build: Bundle server.ts into a single CJS file (#6736)

* build: Bundle server.ts into a single CJS file

* feat: Add providerSandboxId to sandbox metadata and updates

* feat: Add environment variable to toggle skill server entrypoint

* refactor: Remove providerStatus from sandbox schemas and logic
This commit is contained in:
Jon
2026-04-13 10:55:30 +08:00
committed by GitHub
parent 3df8908851
commit 6253f2240b
8 changed files with 25 additions and 25 deletions
-1
View File
@@ -192,7 +192,6 @@ export const SandboxInstanceDetailSchema = z.object({
skillIds: z.array(z.string()).optional(),
provider: z.string(),
image: SandboxImageConfigSchema,
providerStatus: SandboxProviderStatusSchema,
providerCreatedAt: z.date(),
endpoint: SkillSandboxEndpointSchema.optional(),
storage: SandboxStorageSchema.optional(),
@@ -161,6 +161,7 @@ export async function createEditDebugSandbox(
);
const endpointInfo = await getProviderSandboxEndpoint(client.provider, defaults.targetPort);
const sandboxInfo = await client.provider.getInfo();
// Wait for the HTTP service inside the container to bind its port before
// sending the ready SSE event — prevents ECONNREFUSED in the client iframe.
@@ -171,7 +172,7 @@ export async function createEditDebugSandbox(
{ _id: existingInstance._id },
{
'metadata.endpoint': endpointInfo,
'metadata.providerStatus': { state: 'Running' }
...(sandboxInfo?.id && { 'metadata.providerSandboxId': sandboxInfo.id })
}
);
@@ -311,13 +312,10 @@ export async function createEditDebugSandbox(
teamId,
tmbId,
skillId,
sessionId,
providerSandboxId: sandboxInfo.id, // real sandbox ID for save-deploy connection
provider: providerConfig.provider,
image: sandboxInfo.image,
providerStatus: {
state: sandboxInfo.status.state,
message: sandboxInfo.status.message,
reason: sandboxInfo.status.reason
},
providerCreatedAt: sandboxInfo.createdAt,
endpoint: endpointInfo,
storage: {
@@ -351,7 +349,7 @@ export async function createEditDebugSandbox(
return {
sandboxId: newSandboxDoc._id.toString(),
providerSandboxId: sandboxInfo.id,
providerSandboxId: sessionId,
endpoint: endpointInfo,
status: {
state: sandboxInfo.status.state,
@@ -544,6 +542,9 @@ export async function packageSkillInSandbox(params: {
size: files[0].content.length
});
// Clean up the zip file after reading to free sandbox storage
await newSandbox.execute(`rm -f "${zipFilePath}"`);
const content = files[0].content;
return Buffer.from(content instanceof Uint8Array ? content : Buffer.from(content, 'utf-8'));
} catch (error) {
+1
View File
@@ -48,6 +48,7 @@ export const SandboxMetadataSchema = z.object({
skillId: z.string().optional(),
sessionId: z.string().optional(),
providerSandboxId: z.string().optional(), // real provider sandbox ID (different from sessionId)
skillIds: z.array(z.string()).optional(),
image: SandboxImageSchema,
endpoint: SandboxEndpointSchema.optional()
@@ -338,11 +338,6 @@ export async function createAgentSandbox(
skillIds: hasSkills ? deployableSkills.map((s) => s._id) : [],
provider: providerConfig.provider,
image: sandboxInfo.image,
providerStatus: {
state: sandboxInfo.status.state,
message: sandboxInfo.status.message,
reason: sandboxInfo.status.reason
},
providerCreatedAt: sandboxInfo.createdAt
}
}
+15 -3
View File
@@ -45,6 +45,17 @@ ENV NODE_OPTIONS="--max-old-space-size=4096"
ENV NEXT_PUBLIC_BASE_URL=$base_url
RUN pnpm --filter=app build
# Bundle server.ts into a single CJS file; only 'next' is kept external (already in standalone output)
# Banner: mirrors what standalone server.js does — chdir to __dirname and load pre-serialized
# Next.js config so that next() skips webpack (config-utils) during startup.
RUN cd projects/app && ./node_modules/.bin/esbuild server.ts \
--bundle \
--platform=node \
--format=cjs \
--outfile=server-proxy.js \
--external:next \
'--banner:js=process.chdir(__dirname);try{const d=require("./.next/required-server-files.json");process.env.__NEXT_PRIVATE_STANDALONE_CONFIG=JSON.stringify(d.config);}catch(e){}'
# Remove build-time-only packages from standalone output before copying to runner.
# These are traced into standalone by mistake (rspack bindings, gnu platform binaries, etc.)
RUN rm -rf projects/app/.next/standalone/node_modules/.pnpm/@next+rspack-binding-*/ \
@@ -60,6 +71,8 @@ WORKDIR /app
ARG proxy
ARG base_url
ARG SHOW_SKILL=false
ENV SHOW_SKILL=$SHOW_SKILL
# create user and use it
RUN addgroup --system --gid 1001 nodejs
@@ -78,6 +91,7 @@ COPY --from=builder --chown=nextjs:nodejs /app/projects/app/.next/static /app/pr
COPY --from=builder --chown=nextjs:nodejs /app/projects/app/.next/server/chunks /app/projects/app/.next/server/chunks
# copy worker
COPY --from=builder --chown=nextjs:nodejs /app/projects/app/worker /app/projects/app/worker
COPY --from=builder --chown=nextjs:nodejs /app/projects/app/server-proxy.js /app/projects/app/server-proxy.js
# copy standload packages
COPY --from=maindeps /app/node_modules/tiktoken ./node_modules/tiktoken
@@ -100,6 +114,4 @@ EXPOSE 3000
USER nextjs
ENV serverPath=./projects/app/server.js
ENTRYPOINT ["sh","-c","node --max-old-space-size=4096 ${serverPath}"]
ENTRYPOINT ["sh","-c","if [ \"$SHOW_SKILL\" = \"true\" ]; then node --max-old-space-size=4096 ./projects/app/server-proxy.js; else node --max-old-space-size=4096 ./projects/app/server.js; fi"]
@@ -76,7 +76,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
let packageBuffer: Buffer;
try {
packageBuffer = await packageSkillInSandbox({
providerSandboxId: sandboxInfo.sandboxId
providerSandboxId: sandboxInfo.metadata?.providerSandboxId ?? sandboxInfo.sandboxId
});
} catch (error: any) {
return jsonRes(res, {
@@ -318,7 +318,6 @@ describe('debugChat handler — parameter validation', () => {
skillId,
provider: 'opensandbox',
image: { repository: 'test-image', tag: 'latest' },
providerStatus: { state: 'running' },
providerCreatedAt: new Date()
}
});
@@ -24,9 +24,6 @@ describe('SandboxInstance Schema', () => {
repository: 'node',
tag: '18-alpine'
},
providerStatus: {
state: 'Running'
},
providerCreatedAt: new Date()
}
};
@@ -54,7 +51,6 @@ describe('SandboxInstance Schema', () => {
tmbId: '507f1f77bcf86cd799439013',
provider: 'opensandbox',
image: { repository: 'node', tag: 'latest' },
providerStatus: { state: 'Pending' },
providerCreatedAt: new Date()
}
});
@@ -79,7 +75,6 @@ describe('SandboxInstance Schema', () => {
tmbId: '507f1f77bcf86cd799439013',
provider: 'opensandbox',
image: { repository: 'node' },
providerStatus: { state: 'Running' },
providerCreatedAt: new Date()
}
});
@@ -122,7 +117,6 @@ describe('SandboxInstance Schema', () => {
tmbId: '507f1f77bcf86cd799439013',
provider: 'opensandbox',
image: { repository: 'node' },
providerStatus: { state: 'Running' },
providerCreatedAt: new Date(),
endpoint: {
host: 'localhost',
@@ -158,7 +152,6 @@ describe('SandboxInstance Schema', () => {
tmbId: '507f1f77bcf86cd799439013',
provider: 'opensandbox',
image: { repository: 'node' },
providerStatus: { state: 'Succeeded' },
providerCreatedAt: new Date(),
skillIds: ['507f1f77bcf86cd799439014', '507f1f77bcf86cd799439015']
}