From d3a61fd2ddca31e293cdecefd3176c37e9a3fcad Mon Sep 17 00:00:00 2001 From: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com> Date: Fri, 5 Jun 2026 17:00:35 +0800 Subject: [PATCH] perf(build): gate .d.ts emission on OS_SKIP_DTS; fix optional AI plugin skip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Part 1 — OS_SKIP_DTS build-time gating (default behavior unchanged): - 12 tsup configs: dts: true → dts: !process.env.OS_SKIP_DTS - packages/spec/package.json: skip the separate BUILD_DTS=true tsup pass when OS_SKIP_DTS is set (the ~80–90s DTS pass) - packages/cli/package.json: when OS_SKIP_DTS is set, deps have no .d.ts, so build with --noCheck --declaration false to still emit runnable JS (full typecheck preserved by default) - turbo.json: declare OS_SKIP_DTS in globalEnv (Turbo 2.x strict env mode otherwise filters it out; also part of the cache key) Image build (OS_SKIP_DTS=1): framework turbo run build ~5m03s → ~1m12s. Part 2 — fix optional AI plugin "failed to start" false alarm: serve.ts loads @objectstack/service-ai and optional @objectstack/service-ai-studio via importFromHost() and is meant to silently skip when absent. ESM throws "Cannot find package '...'" (code on err.code, not in message), which the old guard didn't match, so control-plane hosts logged a scary error on every boot. Detect missing module via err.code === 'ERR_MODULE_NOT_FOUND' and also match "Cannot find package". Applied to both the AIService and AIStudio guards. Refs objectstack-ai/cloud#107 Co-Authored-By: Claude Opus 4.8 --- packages/cli/package.json | 2 +- packages/cli/src/commands/serve.ts | 12 ++++++++++-- packages/cli/tsup.config.ts | 2 +- packages/core/tsup.config.ts | 2 +- packages/metadata-core/tsup.config.ts | 2 +- packages/metadata-fs/tsup.config.ts | 2 +- packages/metadata/tsup.config.ts | 2 +- packages/platform-objects/tsup.config.ts | 2 +- packages/plugins/plugin-webhooks/tsup.config.ts | 2 +- packages/runtime/tsup.config.ts | 2 +- .../services/service-cluster-redis/tsup.config.ts | 2 +- packages/services/service-cluster/tsup.config.ts | 2 +- packages/services/service-datasource/tsup.config.ts | 2 +- packages/spec/package.json | 2 +- tsup.config.ts | 2 +- turbo.json | 1 + 16 files changed, 25 insertions(+), 16 deletions(-) diff --git a/packages/cli/package.json b/packages/cli/package.json index 5e4de30525..22980aa3f5 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -9,7 +9,7 @@ "os": "./bin/run.js" }, "scripts": { - "build": "tsc -p tsconfig.build.json", + "build": "if [ -n \"$OS_SKIP_DTS\" ]; then tsc -p tsconfig.build.json --noCheck --declaration false --declarationMap false; else tsc -p tsconfig.build.json; fi", "dev": "tsc -p tsconfig.build.json --watch", "test": "vitest run", "lint": "eslint src" diff --git a/packages/cli/src/commands/serve.ts b/packages/cli/src/commands/serve.ts index e5f98a011c..7a75c97d8b 100644 --- a/packages/cli/src/commands/serve.ts +++ b/packages/cli/src/commands/serve.ts @@ -1377,7 +1377,11 @@ export default class Serve extends Command { trackPlugin('AIService'); } catch (err: unknown) { const msg = err instanceof Error ? err.message : String(err); - if (!msg.includes('Cannot find module') && !msg.includes('ERR_MODULE_NOT_FOUND')) { + const code = (err as { code?: string })?.code; + const missing = code === 'ERR_MODULE_NOT_FOUND' + || msg.includes('Cannot find module') + || msg.includes('Cannot find package'); + if (!missing) { console.error('[AI] AIServicePlugin failed to start:', msg); } // @objectstack/service-ai not installed — AI features unavailable @@ -1401,7 +1405,11 @@ export default class Serve extends Command { trackPlugin('AIStudio'); } catch (err: unknown) { const msg = err instanceof Error ? err.message : String(err); - if (!msg.includes('Cannot find module') && !msg.includes('ERR_MODULE_NOT_FOUND')) { + const code = (err as { code?: string })?.code; + const missing = code === 'ERR_MODULE_NOT_FOUND' + || msg.includes('Cannot find module') + || msg.includes('Cannot find package'); + if (!missing) { console.error('[AI Studio] AIStudioPlugin failed to start:', msg); } // @objectstack/service-ai-studio not installed — AI authoring unavailable diff --git a/packages/cli/tsup.config.ts b/packages/cli/tsup.config.ts index e3c4898f83..a26047d4ff 100644 --- a/packages/cli/tsup.config.ts +++ b/packages/cli/tsup.config.ts @@ -17,7 +17,7 @@ export default defineConfig([ { entry: ['src/index.ts'], format: ['esm'], - dts: true, + dts: !process.env.OS_SKIP_DTS, shims: true, }, ]); diff --git a/packages/core/tsup.config.ts b/packages/core/tsup.config.ts index ba2a9673c4..365b76b31f 100644 --- a/packages/core/tsup.config.ts +++ b/packages/core/tsup.config.ts @@ -13,7 +13,7 @@ export default defineConfig({ splitting: false, sourcemap: true, clean: true, - dts: true, + dts: !process.env.OS_SKIP_DTS, format: ['esm', 'cjs'], target: 'es2020', }); diff --git a/packages/metadata-core/tsup.config.ts b/packages/metadata-core/tsup.config.ts index be6392f3de..a9fe160868 100644 --- a/packages/metadata-core/tsup.config.ts +++ b/packages/metadata-core/tsup.config.ts @@ -7,7 +7,7 @@ export default defineConfig({ splitting: true, sourcemap: true, clean: true, - dts: true, + dts: !process.env.OS_SKIP_DTS, format: ['esm', 'cjs'], target: 'es2020', external: ['vitest'], diff --git a/packages/metadata-fs/tsup.config.ts b/packages/metadata-fs/tsup.config.ts index 5a1f5ef5a9..88826a7e6b 100644 --- a/packages/metadata-fs/tsup.config.ts +++ b/packages/metadata-fs/tsup.config.ts @@ -7,7 +7,7 @@ export default defineConfig({ splitting: false, sourcemap: true, clean: true, - dts: true, + dts: !process.env.OS_SKIP_DTS, format: ['esm', 'cjs'], target: 'es2020', external: ['chokidar', '@objectstack/metadata-core'], diff --git a/packages/metadata/tsup.config.ts b/packages/metadata/tsup.config.ts index 665d2b419e..a6d6f382fb 100644 --- a/packages/metadata/tsup.config.ts +++ b/packages/metadata/tsup.config.ts @@ -11,7 +11,7 @@ export default defineConfig({ splitting: false, sourcemap: true, clean: true, - dts: true, + dts: !process.env.OS_SKIP_DTS, format: ['esm', 'cjs'], target: 'es2020', }); diff --git a/packages/platform-objects/tsup.config.ts b/packages/platform-objects/tsup.config.ts index 8dc68c40c6..f147ec30fd 100644 --- a/packages/platform-objects/tsup.config.ts +++ b/packages/platform-objects/tsup.config.ts @@ -17,7 +17,7 @@ export default defineConfig({ plugin: 'src/plugin.ts', }, format: ['cjs', 'esm'], - dts: true, + dts: !process.env.OS_SKIP_DTS, clean: true, sourcemap: true, splitting: false, diff --git a/packages/plugins/plugin-webhooks/tsup.config.ts b/packages/plugins/plugin-webhooks/tsup.config.ts index 983062dbef..37429d0932 100644 --- a/packages/plugins/plugin-webhooks/tsup.config.ts +++ b/packages/plugins/plugin-webhooks/tsup.config.ts @@ -7,7 +7,7 @@ export default defineConfig({ splitting: true, sourcemap: true, clean: true, - dts: true, + dts: !process.env.OS_SKIP_DTS, format: ['esm', 'cjs'], target: 'es2020', external: ['vitest'], diff --git a/packages/runtime/tsup.config.ts b/packages/runtime/tsup.config.ts index 3b7de514f4..0e3f256726 100644 --- a/packages/runtime/tsup.config.ts +++ b/packages/runtime/tsup.config.ts @@ -7,7 +7,7 @@ export default defineConfig({ splitting: false, sourcemap: true, clean: true, - dts: true, + dts: !process.env.OS_SKIP_DTS, format: ['esm', 'cjs'], target: 'es2020', // Mark driver packages as external so they are resolved at runtime, not bundled diff --git a/packages/services/service-cluster-redis/tsup.config.ts b/packages/services/service-cluster-redis/tsup.config.ts index e99e286398..c1773045fb 100644 --- a/packages/services/service-cluster-redis/tsup.config.ts +++ b/packages/services/service-cluster-redis/tsup.config.ts @@ -7,7 +7,7 @@ export default defineConfig({ splitting: true, sourcemap: true, clean: true, - dts: true, + dts: !process.env.OS_SKIP_DTS, format: ['esm', 'cjs'], target: 'es2020', external: ['vitest', 'ioredis'], diff --git a/packages/services/service-cluster/tsup.config.ts b/packages/services/service-cluster/tsup.config.ts index 53dfb458c5..31546183ca 100644 --- a/packages/services/service-cluster/tsup.config.ts +++ b/packages/services/service-cluster/tsup.config.ts @@ -7,7 +7,7 @@ export default defineConfig({ splitting: true, sourcemap: true, clean: true, - dts: true, + dts: !process.env.OS_SKIP_DTS, format: ['esm', 'cjs'], target: 'es2020', external: ['vitest'], diff --git a/packages/services/service-datasource/tsup.config.ts b/packages/services/service-datasource/tsup.config.ts index 6659899115..d54f0e0b9a 100644 --- a/packages/services/service-datasource/tsup.config.ts +++ b/packages/services/service-datasource/tsup.config.ts @@ -7,7 +7,7 @@ export default defineConfig({ splitting: true, sourcemap: true, clean: true, - dts: true, + dts: !process.env.OS_SKIP_DTS, format: ['esm', 'cjs'], target: 'es2020', // Driver packages are loaded via optional, lazy `await import('@objectstack/driver-*')` diff --git a/packages/spec/package.json b/packages/spec/package.json index 9dedfdc30d..4d72f2a444 100644 --- a/packages/spec/package.json +++ b/packages/spec/package.json @@ -178,7 +178,7 @@ "src/**/*.zod.ts" ], "scripts": { - "build": "pnpm gen:schema && pnpm gen:openapi && tsup && NODE_OPTIONS=\"--max-old-space-size=4096\" BUILD_DTS=true tsup", + "build": "pnpm gen:schema && pnpm gen:openapi && tsup && if [ -z \"$OS_SKIP_DTS\" ]; then NODE_OPTIONS=\"--max-old-space-size=4096\" BUILD_DTS=true tsup; fi", "dev": "tsc --watch", "clean": "rm -rf dist", "gen:schema": "OS_EAGER_SCHEMAS=1 tsx scripts/build-schemas.ts", diff --git a/tsup.config.ts b/tsup.config.ts index 533062fa6e..ffa32ebd48 100644 --- a/tsup.config.ts +++ b/tsup.config.ts @@ -5,7 +5,7 @@ export default defineConfig({ splitting: false, sourcemap: true, clean: true, - dts: true, + dts: !process.env.OS_SKIP_DTS, format: ['esm', 'cjs'], target: 'es2020', }); diff --git a/turbo.json b/turbo.json index 624a57bcfc..6b670ca659 100644 --- a/turbo.json +++ b/turbo.json @@ -1,6 +1,7 @@ { "$schema": "https://turbo.build/schema.json", "globalDependencies": ["tsconfig.json", "tsup.config.ts"], + "globalEnv": ["OS_SKIP_DTS"], "tasks": { "build": { "dependsOn": ["^build"],