Commit 6253f224 by Jon Committed by GitHub

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
parent 3df89088
...@@ -192,7 +192,6 @@ export const SandboxInstanceDetailSchema = z.object({ ...@@ -192,7 +192,6 @@ export const SandboxInstanceDetailSchema = z.object({
skillIds: z.array(z.string()).optional(), skillIds: z.array(z.string()).optional(),
provider: z.string(), provider: z.string(),
image: SandboxImageConfigSchema, image: SandboxImageConfigSchema,
providerStatus: SandboxProviderStatusSchema,
providerCreatedAt: z.date(), providerCreatedAt: z.date(),
endpoint: SkillSandboxEndpointSchema.optional(), endpoint: SkillSandboxEndpointSchema.optional(),
storage: SandboxStorageSchema.optional(), storage: SandboxStorageSchema.optional(),
......
...@@ -161,6 +161,7 @@ export async function createEditDebugSandbox( ...@@ -161,6 +161,7 @@ export async function createEditDebugSandbox(
); );
const endpointInfo = await getProviderSandboxEndpoint(client.provider, defaults.targetPort); 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 // Wait for the HTTP service inside the container to bind its port before
// sending the ready SSE event — prevents ECONNREFUSED in the client iframe. // sending the ready SSE event — prevents ECONNREFUSED in the client iframe.
...@@ -171,7 +172,7 @@ export async function createEditDebugSandbox( ...@@ -171,7 +172,7 @@ export async function createEditDebugSandbox(
{ _id: existingInstance._id }, { _id: existingInstance._id },
{ {
'metadata.endpoint': endpointInfo, 'metadata.endpoint': endpointInfo,
'metadata.providerStatus': { state: 'Running' } ...(sandboxInfo?.id && { 'metadata.providerSandboxId': sandboxInfo.id })
} }
); );
...@@ -311,13 +312,10 @@ export async function createEditDebugSandbox( ...@@ -311,13 +312,10 @@ export async function createEditDebugSandbox(
teamId, teamId,
tmbId, tmbId,
skillId, skillId,
sessionId,
providerSandboxId: sandboxInfo.id, // real sandbox ID for save-deploy connection
provider: providerConfig.provider, provider: providerConfig.provider,
image: sandboxInfo.image, image: sandboxInfo.image,
providerStatus: {
state: sandboxInfo.status.state,
message: sandboxInfo.status.message,
reason: sandboxInfo.status.reason
},
providerCreatedAt: sandboxInfo.createdAt, providerCreatedAt: sandboxInfo.createdAt,
endpoint: endpointInfo, endpoint: endpointInfo,
storage: { storage: {
...@@ -351,7 +349,7 @@ export async function createEditDebugSandbox( ...@@ -351,7 +349,7 @@ export async function createEditDebugSandbox(
return { return {
sandboxId: newSandboxDoc._id.toString(), sandboxId: newSandboxDoc._id.toString(),
providerSandboxId: sandboxInfo.id, providerSandboxId: sessionId,
endpoint: endpointInfo, endpoint: endpointInfo,
status: { status: {
state: sandboxInfo.status.state, state: sandboxInfo.status.state,
...@@ -544,6 +542,9 @@ export async function packageSkillInSandbox(params: { ...@@ -544,6 +542,9 @@ export async function packageSkillInSandbox(params: {
size: files[0].content.length 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; const content = files[0].content;
return Buffer.from(content instanceof Uint8Array ? content : Buffer.from(content, 'utf-8')); return Buffer.from(content instanceof Uint8Array ? content : Buffer.from(content, 'utf-8'));
} catch (error) { } catch (error) {
......
...@@ -48,6 +48,7 @@ export const SandboxMetadataSchema = z.object({ ...@@ -48,6 +48,7 @@ export const SandboxMetadataSchema = z.object({
skillId: z.string().optional(), skillId: z.string().optional(),
sessionId: z.string().optional(), sessionId: z.string().optional(),
providerSandboxId: z.string().optional(), // real provider sandbox ID (different from sessionId)
skillIds: z.array(z.string()).optional(), skillIds: z.array(z.string()).optional(),
image: SandboxImageSchema, image: SandboxImageSchema,
endpoint: SandboxEndpointSchema.optional() endpoint: SandboxEndpointSchema.optional()
......
...@@ -338,11 +338,6 @@ export async function createAgentSandbox( ...@@ -338,11 +338,6 @@ export async function createAgentSandbox(
skillIds: hasSkills ? deployableSkills.map((s) => s._id) : [], skillIds: hasSkills ? deployableSkills.map((s) => s._id) : [],
provider: providerConfig.provider, provider: providerConfig.provider,
image: sandboxInfo.image, image: sandboxInfo.image,
providerStatus: {
state: sandboxInfo.status.state,
message: sandboxInfo.status.message,
reason: sandboxInfo.status.reason
},
providerCreatedAt: sandboxInfo.createdAt providerCreatedAt: sandboxInfo.createdAt
} }
} }
......
...@@ -45,6 +45,17 @@ ENV NODE_OPTIONS="--max-old-space-size=4096" ...@@ -45,6 +45,17 @@ ENV NODE_OPTIONS="--max-old-space-size=4096"
ENV NEXT_PUBLIC_BASE_URL=$base_url ENV NEXT_PUBLIC_BASE_URL=$base_url
RUN pnpm --filter=app build 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. # 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.) # 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-*/ \ RUN rm -rf projects/app/.next/standalone/node_modules/.pnpm/@next+rspack-binding-*/ \
...@@ -60,6 +71,8 @@ WORKDIR /app ...@@ -60,6 +71,8 @@ WORKDIR /app
ARG proxy ARG proxy
ARG base_url ARG base_url
ARG SHOW_SKILL=false
ENV SHOW_SKILL=$SHOW_SKILL
# create user and use it # create user and use it
RUN addgroup --system --gid 1001 nodejs RUN addgroup --system --gid 1001 nodejs
...@@ -78,6 +91,7 @@ COPY --from=builder --chown=nextjs:nodejs /app/projects/app/.next/static /app/pr ...@@ -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 --from=builder --chown=nextjs:nodejs /app/projects/app/.next/server/chunks /app/projects/app/.next/server/chunks
# copy worker # 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/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 standload packages
COPY --from=maindeps /app/node_modules/tiktoken ./node_modules/tiktoken COPY --from=maindeps /app/node_modules/tiktoken ./node_modules/tiktoken
...@@ -100,6 +114,4 @@ EXPOSE 3000 ...@@ -100,6 +114,4 @@ EXPOSE 3000
USER nextjs USER nextjs
ENV serverPath=./projects/app/server.js 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"]
ENTRYPOINT ["sh","-c","node --max-old-space-size=4096 ${serverPath}"]
...@@ -76,7 +76,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) ...@@ -76,7 +76,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
let packageBuffer: Buffer; let packageBuffer: Buffer;
try { try {
packageBuffer = await packageSkillInSandbox({ packageBuffer = await packageSkillInSandbox({
providerSandboxId: sandboxInfo.sandboxId providerSandboxId: sandboxInfo.metadata?.providerSandboxId ?? sandboxInfo.sandboxId
}); });
} catch (error: any) { } catch (error: any) {
return jsonRes(res, { return jsonRes(res, {
......
...@@ -318,7 +318,6 @@ describe('debugChat handler — parameter validation', () => { ...@@ -318,7 +318,6 @@ describe('debugChat handler — parameter validation', () => {
skillId, skillId,
provider: 'opensandbox', provider: 'opensandbox',
image: { repository: 'test-image', tag: 'latest' }, image: { repository: 'test-image', tag: 'latest' },
providerStatus: { state: 'running' },
providerCreatedAt: new Date() providerCreatedAt: new Date()
} }
}); });
......
...@@ -24,9 +24,6 @@ describe('SandboxInstance Schema', () => { ...@@ -24,9 +24,6 @@ describe('SandboxInstance Schema', () => {
repository: 'node', repository: 'node',
tag: '18-alpine' tag: '18-alpine'
}, },
providerStatus: {
state: 'Running'
},
providerCreatedAt: new Date() providerCreatedAt: new Date()
} }
}; };
...@@ -54,7 +51,6 @@ describe('SandboxInstance Schema', () => { ...@@ -54,7 +51,6 @@ describe('SandboxInstance Schema', () => {
tmbId: '507f1f77bcf86cd799439013', tmbId: '507f1f77bcf86cd799439013',
provider: 'opensandbox', provider: 'opensandbox',
image: { repository: 'node', tag: 'latest' }, image: { repository: 'node', tag: 'latest' },
providerStatus: { state: 'Pending' },
providerCreatedAt: new Date() providerCreatedAt: new Date()
} }
}); });
...@@ -79,7 +75,6 @@ describe('SandboxInstance Schema', () => { ...@@ -79,7 +75,6 @@ describe('SandboxInstance Schema', () => {
tmbId: '507f1f77bcf86cd799439013', tmbId: '507f1f77bcf86cd799439013',
provider: 'opensandbox', provider: 'opensandbox',
image: { repository: 'node' }, image: { repository: 'node' },
providerStatus: { state: 'Running' },
providerCreatedAt: new Date() providerCreatedAt: new Date()
} }
}); });
...@@ -122,7 +117,6 @@ describe('SandboxInstance Schema', () => { ...@@ -122,7 +117,6 @@ describe('SandboxInstance Schema', () => {
tmbId: '507f1f77bcf86cd799439013', tmbId: '507f1f77bcf86cd799439013',
provider: 'opensandbox', provider: 'opensandbox',
image: { repository: 'node' }, image: { repository: 'node' },
providerStatus: { state: 'Running' },
providerCreatedAt: new Date(), providerCreatedAt: new Date(),
endpoint: { endpoint: {
host: 'localhost', host: 'localhost',
...@@ -158,7 +152,6 @@ describe('SandboxInstance Schema', () => { ...@@ -158,7 +152,6 @@ describe('SandboxInstance Schema', () => {
tmbId: '507f1f77bcf86cd799439013', tmbId: '507f1f77bcf86cd799439013',
provider: 'opensandbox', provider: 'opensandbox',
image: { repository: 'node' }, image: { repository: 'node' },
providerStatus: { state: 'Succeeded' },
providerCreatedAt: new Date(), providerCreatedAt: new Date(),
skillIds: ['507f1f77bcf86cd799439014', '507f1f77bcf86cd799439015'] skillIds: ['507f1f77bcf86cd799439014', '507f1f77bcf86cd799439015']
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment