@agent-native/core 0.124.3 → 0.124.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +10 -0
- package/corpus/core/docs/content/cloneable-saas.mdx +9 -9
- package/corpus/core/docs/content/creating-templates.mdx +2 -2
- package/corpus/core/docs/content/deployment.mdx +23 -0
- package/corpus/core/docs/content/faq.mdx +4 -4
- package/corpus/core/docs/content/key-concepts.mdx +1 -1
- package/corpus/core/docs/content/multi-app-workspace.mdx +1 -1
- package/corpus/core/docs/content/syncing-template-changes.mdx +1 -1
- package/corpus/core/docs/content/template-analytics-developers.mdx +2 -2
- package/corpus/core/docs/content/template-analytics.mdx +2 -2
- package/corpus/core/docs/content/template-assets-developers.mdx +3 -3
- package/corpus/core/docs/content/template-assets.mdx +2 -2
- package/corpus/core/docs/content/template-brain-developers.mdx +2 -2
- package/corpus/core/docs/content/template-brain.mdx +1 -1
- package/corpus/core/docs/content/template-calendar-developers.mdx +1 -1
- package/corpus/core/docs/content/template-calendar.mdx +1 -1
- package/corpus/core/docs/content/template-chat.mdx +1 -1
- package/corpus/core/docs/content/template-clips-developers.mdx +4 -4
- package/corpus/core/docs/content/template-clips.mdx +2 -2
- package/corpus/core/docs/content/template-content-developers.mdx +2 -2
- package/corpus/core/docs/content/template-content.mdx +1 -1
- package/corpus/core/docs/content/template-design-brand-and-figma.mdx +1 -1
- package/corpus/core/docs/content/template-design-developers.mdx +2 -2
- package/corpus/core/docs/content/template-design.mdx +2 -2
- package/corpus/core/docs/content/template-dispatch-developers.mdx +5 -5
- package/corpus/core/docs/content/template-forms-developers.mdx +1 -1
- package/corpus/core/docs/content/template-forms.mdx +1 -1
- package/corpus/core/docs/content/template-mail-developers.mdx +2 -2
- package/corpus/core/docs/content/template-mail.mdx +2 -2
- package/corpus/core/docs/content/template-plan-developers.mdx +3 -3
- package/corpus/core/docs/content/template-plan.mdx +3 -3
- package/corpus/core/docs/content/template-slides-developers.mdx +4 -4
- package/corpus/core/docs/content/template-slides.mdx +1 -1
- package/corpus/core/docs/content/what-is-agent-native.mdx +5 -5
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/a2a/auth-policy.ts +1 -1
- package/corpus/core/src/agent/production-agent.ts +14 -1
- package/corpus/core/src/agent/run-manager.ts +6 -13
- package/corpus/core/src/cli/index.ts +11 -1
- package/corpus/core/src/client/route-chunk-recovery.ts +18 -7
- package/corpus/core/src/db/client.ts +7 -6
- package/corpus/core/src/db/migrations.ts +2 -1
- package/corpus/core/src/deploy/build.ts +290 -4
- package/corpus/core/src/deploy/nitro-preset.ts +50 -0
- package/corpus/core/src/integrations/pending-tasks-retry-job.ts +2 -1
- package/corpus/core/src/scripts/call-agent.ts +4 -2
- package/corpus/core/src/server/agent-discovery.ts +1 -0
- package/corpus/core/src/server/agent-run-context.ts +13 -3
- package/corpus/core/src/server/request-context.ts +2 -0
- package/corpus/core/src/shared/cloudflare-globals.d.ts +2 -1
- package/corpus/core/src/shared/runtime.ts +2 -0
- package/corpus/core/src/templates/default/.agents/skills/secrets/SKILL.md +29 -0
- package/corpus/core/src/templates/default/app/i18n/ar-SA.ts +6 -6
- package/corpus/core/src/templates/default/app/i18n/de-DE.ts +6 -6
- package/corpus/core/src/templates/default/app/i18n/en-US.ts +6 -6
- package/corpus/core/src/templates/default/app/i18n/es-ES.ts +6 -6
- package/corpus/core/src/templates/default/app/i18n/fr-FR.ts +6 -6
- package/corpus/core/src/templates/default/app/i18n/hi-IN.ts +6 -6
- package/corpus/core/src/templates/default/app/i18n/ja-JP.ts +6 -6
- package/corpus/core/src/templates/default/app/i18n/ko-KR.ts +6 -6
- package/corpus/core/src/templates/default/app/i18n/pt-BR.ts +6 -6
- package/corpus/core/src/templates/default/app/i18n/zh-CN.ts +6 -6
- package/corpus/core/src/templates/default/app/i18n/zh-TW.ts +6 -6
- package/corpus/core/src/templates/headless/.agents/skills/secrets/SKILL.md +29 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +29 -0
- package/corpus/core/src/vite/client.ts +20 -1
- package/corpus/templates/analytics/actions/restore-dashboard-revision.ts +9 -2
- package/corpus/templates/analytics/app/components/dashboard/DashboardHistoryPanel.tsx +3 -0
- package/corpus/templates/analytics/app/components/dashboard/DashboardPanelSkeleton.tsx +1 -1
- package/corpus/templates/analytics/app/global.css +10 -9
- package/corpus/templates/analytics/app/hooks/use-chart-tooltip-portal.ts +59 -18
- package/corpus/templates/analytics/app/hooks/use-dashboard-revisions.ts +14 -2
- package/corpus/templates/analytics/app/i18n-data.ts +102 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +232 -2
- package/corpus/templates/analytics/changelog/2026-07-27-chart-tooltips-stay-beside-the-cursor-when-they-extend-beyon.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-27-chat-no-longer-claims-a-data-source-is-disconnected-when-it-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-27-dashboard-changes-can-be-undone-with-cmd-z-and-actions-menu.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-27-dashboard-redo-with-cmd-shift-z-and-actions-menu.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-27-dashboard-skeletons-are-subtler-and-smoother.md +6 -0
- package/corpus/templates/analytics/server/lib/dashboards-store.ts +61 -20
- package/corpus/templates/analytics/server/lib/real-data-actions.ts +1 -0
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +7 -3
- package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +7 -32
- package/corpus/templates/calendar/changelog/2026-07-27-calendar-s-sidebar-now-uses-a-cleaner-layout-with-fewer-util.md +6 -0
- package/corpus/templates/content/app/components/editor/database/sidebar.tsx +14 -6
- package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +32 -37
- package/corpus/templates/content/changelog/2026-07-27-content-sidebar-page-lists-now-load-with-quiet-skeletons-and.md +6 -0
- package/corpus/templates/design/app/components/layout/Sidebar.tsx +16 -18
- package/corpus/templates/design/changelog/2026-07-27-collapsed-sidebar-keeps-the-agent-native-logo.md +6 -0
- package/corpus/templates/dispatch/AGENTS.md +7 -2
- package/corpus/templates/dispatch/actions/view-screen.ts +3 -2
- package/corpus/templates/dispatch/changelog/2026-07-17-curated-template-remixes.md +1 -1
- package/corpus/templates/dispatch/changelog/2026-07-27-creating-an-app-from-a-curated-template-now-uses-clearer-mor.md +6 -0
- package/corpus/templates/dispatch/changelog/2026-07-27-thread-debug-accepts-request-run-ids.md +6 -0
- package/corpus/templates/slides/actions/create-design-system.ts +10 -2
- package/corpus/templates/slides/actions/import-file.ts +173 -1
- package/corpus/templates/slides/actions/list-slide-comments.ts +16 -1
- package/corpus/templates/slides/actions/update-design-system.ts +13 -2
- package/corpus/templates/slides/app/components/editor/AssetLibraryPanel.tsx +35 -12
- package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +36 -0
- package/corpus/templates/slides/app/i18n/en-US.ts +3 -0
- package/corpus/templates/slides/app/lib/dynamic-import.ts +63 -0
- package/corpus/templates/slides/app/lib/export-pdf-client.ts +3 -2
- package/corpus/templates/slides/app/lib/export-pptx-client.ts +5 -2
- package/corpus/templates/slides/app/pages/DesignSystems.tsx +9 -1
- package/corpus/templates/slides/server/db/schema.ts +11 -0
- package/corpus/templates/slides/server/handlers/assets.ts +64 -19
- package/corpus/templates/slides/server/handlers/import/html-converter.ts +38 -0
- package/corpus/templates/slides/server/plugins/db.ts +20 -0
- package/corpus/templates/slides/shared/design-system-validation.ts +62 -0
- package/dist/a2a/auth-policy.js +1 -1
- package/dist/a2a/auth-policy.js.map +1 -1
- package/dist/agent/production-agent.d.ts +1 -0
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +12 -1
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-manager.d.ts +2 -0
- package/dist/agent/run-manager.d.ts.map +1 -1
- package/dist/agent/run-manager.js +4 -10
- package/dist/agent/run-manager.js.map +1 -1
- package/dist/cli/index.js +8 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/client/route-chunk-recovery.d.ts.map +1 -1
- package/dist/client/route-chunk-recovery.js +16 -7
- package/dist/client/route-chunk-recovery.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +4 -2
- package/dist/db/client.js.map +1 -1
- package/dist/db/migrations.d.ts.map +1 -1
- package/dist/db/migrations.js +2 -1
- package/dist/db/migrations.js.map +1 -1
- package/dist/deploy/build.d.ts +25 -0
- package/dist/deploy/build.d.ts.map +1 -1
- package/dist/deploy/build.js +227 -4
- package/dist/deploy/build.js.map +1 -1
- package/dist/deploy/nitro-preset.d.ts +8 -0
- package/dist/deploy/nitro-preset.d.ts.map +1 -0
- package/dist/deploy/nitro-preset.js +36 -0
- package/dist/deploy/nitro-preset.js.map +1 -0
- package/dist/integrations/pending-tasks-retry-job.d.ts.map +1 -1
- package/dist/integrations/pending-tasks-retry-job.js +2 -1
- package/dist/integrations/pending-tasks-retry-job.js.map +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/observability/routes.d.ts +3 -3
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +11 -11
- package/dist/provider-api/actions/provider-api.d.ts +11 -11
- package/dist/scripts/call-agent.d.ts.map +1 -1
- package/dist/scripts/call-agent.js +4 -2
- package/dist/scripts/call-agent.js.map +1 -1
- package/dist/secrets/routes.d.ts +3 -3
- package/dist/server/agent-discovery.d.ts.map +1 -1
- package/dist/server/agent-discovery.js +1 -0
- package/dist/server/agent-discovery.js.map +1 -1
- package/dist/server/agent-run-context.d.ts.map +1 -1
- package/dist/server/agent-run-context.js +10 -3
- package/dist/server/agent-run-context.js.map +1 -1
- package/dist/server/request-context.d.ts +2 -0
- package/dist/server/request-context.d.ts.map +1 -1
- package/dist/server/request-context.js.map +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/shared/runtime.d.ts.map +1 -1
- package/dist/shared/runtime.js +2 -0
- package/dist/shared/runtime.js.map +1 -1
- package/dist/templates/default/.agents/skills/secrets/SKILL.md +29 -0
- package/dist/templates/default/app/i18n/ar-SA.ts +6 -6
- package/dist/templates/default/app/i18n/de-DE.ts +6 -6
- package/dist/templates/default/app/i18n/en-US.ts +6 -6
- package/dist/templates/default/app/i18n/es-ES.ts +6 -6
- package/dist/templates/default/app/i18n/fr-FR.ts +6 -6
- package/dist/templates/default/app/i18n/hi-IN.ts +6 -6
- package/dist/templates/default/app/i18n/ja-JP.ts +6 -6
- package/dist/templates/default/app/i18n/ko-KR.ts +6 -6
- package/dist/templates/default/app/i18n/pt-BR.ts +6 -6
- package/dist/templates/default/app/i18n/zh-CN.ts +6 -6
- package/dist/templates/default/app/i18n/zh-TW.ts +6 -6
- package/dist/templates/headless/.agents/skills/secrets/SKILL.md +29 -0
- package/dist/templates/workspace-core/.agents/skills/secrets/SKILL.md +29 -0
- package/dist/vite/client.d.ts +1 -1
- package/dist/vite/client.d.ts.map +1 -1
- package/dist/vite/client.js +16 -0
- package/dist/vite/client.js.map +1 -1
- package/docs/content/cloneable-saas.mdx +9 -9
- package/docs/content/creating-templates.mdx +2 -2
- package/docs/content/deployment.mdx +23 -0
- package/docs/content/faq.mdx +4 -4
- package/docs/content/key-concepts.mdx +1 -1
- package/docs/content/multi-app-workspace.mdx +1 -1
- package/docs/content/syncing-template-changes.mdx +1 -1
- package/docs/content/template-analytics-developers.mdx +2 -2
- package/docs/content/template-analytics.mdx +2 -2
- package/docs/content/template-assets-developers.mdx +3 -3
- package/docs/content/template-assets.mdx +2 -2
- package/docs/content/template-brain-developers.mdx +2 -2
- package/docs/content/template-brain.mdx +1 -1
- package/docs/content/template-calendar-developers.mdx +1 -1
- package/docs/content/template-calendar.mdx +1 -1
- package/docs/content/template-chat.mdx +1 -1
- package/docs/content/template-clips-developers.mdx +4 -4
- package/docs/content/template-clips.mdx +2 -2
- package/docs/content/template-content-developers.mdx +2 -2
- package/docs/content/template-content.mdx +1 -1
- package/docs/content/template-design-brand-and-figma.mdx +1 -1
- package/docs/content/template-design-developers.mdx +2 -2
- package/docs/content/template-design.mdx +2 -2
- package/docs/content/template-dispatch-developers.mdx +5 -5
- package/docs/content/template-forms-developers.mdx +1 -1
- package/docs/content/template-forms.mdx +1 -1
- package/docs/content/template-mail-developers.mdx +2 -2
- package/docs/content/template-mail.mdx +2 -2
- package/docs/content/template-plan-developers.mdx +3 -3
- package/docs/content/template-plan.mdx +3 -3
- package/docs/content/template-slides-developers.mdx +4 -4
- package/docs/content/template-slides.mdx +1 -1
- package/docs/content/what-is-agent-native.mdx +5 -5
- package/package.json +1 -1
- package/src/a2a/auth-policy.ts +1 -1
- package/src/agent/production-agent.ts +14 -1
- package/src/agent/run-manager.ts +6 -13
- package/src/cli/index.ts +11 -1
- package/src/client/route-chunk-recovery.ts +18 -7
- package/src/db/client.ts +7 -6
- package/src/db/migrations.ts +2 -1
- package/src/deploy/build.ts +290 -4
- package/src/deploy/nitro-preset.ts +50 -0
- package/src/integrations/pending-tasks-retry-job.ts +2 -1
- package/src/scripts/call-agent.ts +4 -2
- package/src/server/agent-discovery.ts +1 -0
- package/src/server/agent-run-context.ts +13 -3
- package/src/server/request-context.ts +2 -0
- package/src/shared/cloudflare-globals.d.ts +2 -1
- package/src/shared/runtime.ts +2 -0
- package/src/templates/default/.agents/skills/secrets/SKILL.md +29 -0
- package/src/templates/default/app/i18n/ar-SA.ts +6 -6
- package/src/templates/default/app/i18n/de-DE.ts +6 -6
- package/src/templates/default/app/i18n/en-US.ts +6 -6
- package/src/templates/default/app/i18n/es-ES.ts +6 -6
- package/src/templates/default/app/i18n/fr-FR.ts +6 -6
- package/src/templates/default/app/i18n/hi-IN.ts +6 -6
- package/src/templates/default/app/i18n/ja-JP.ts +6 -6
- package/src/templates/default/app/i18n/ko-KR.ts +6 -6
- package/src/templates/default/app/i18n/pt-BR.ts +6 -6
- package/src/templates/default/app/i18n/zh-CN.ts +6 -6
- package/src/templates/default/app/i18n/zh-TW.ts +6 -6
- package/src/templates/headless/.agents/skills/secrets/SKILL.md +29 -0
- package/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +29 -0
- package/src/vite/client.ts +20 -1
- /package/corpus/templates/slides/server/routes/api/assets/{[filename].delete.ts → [id].delete.ts} +0 -0
package/dist/db/migrations.js
CHANGED
|
@@ -534,7 +534,8 @@ export function runMigrations(migrations, options) {
|
|
|
534
534
|
const isServerless = !!globalThis.process?.env?.NETLIFY ||
|
|
535
535
|
!!globalThis.process?.env?.AWS_LAMBDA_FUNCTION_NAME ||
|
|
536
536
|
!!globalThis.process?.env?.VERCEL ||
|
|
537
|
-
"__cf_env" in globalThis
|
|
537
|
+
"__cf_env" in globalThis ||
|
|
538
|
+
"__env__" in globalThis;
|
|
538
539
|
if (typeof globalThis.process?.exit === "function" && !isServerless) {
|
|
539
540
|
process.exit(1);
|
|
540
541
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrations.js","sourceRoot":"","sources":["../../src/db/migrations.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n getDbExec,\n createDbExec,\n isPostgres,\n getDialect,\n getMigrationDatabaseUrl,\n getCloudflareD1Binding,\n retrySqliteBusy,\n type DbExec,\n} from \"./client.js\";\n\ninterface D1PreparedStatementLike {\n bind(...values: unknown[]): D1PreparedStatementLike;\n all(): Promise<{ results: Record<string, unknown>[] }>;\n first<T = Record<string, unknown>>(): Promise<T | null>;\n run(): Promise<unknown>;\n}\n\ninterface D1DatabaseLike {\n prepare(query: string): D1PreparedStatementLike;\n batch(statements: D1PreparedStatementLike[]): Promise<unknown>;\n}\n\n// ---------------------------------------------------------------------------\n// Shared direct-endpoint exec across concurrent migration runners per boot.\n//\n// On each serverless cold start THREE plugins call runMigrations (core,\n// org, context-xray). Without coordination each would open an independent\n// direct-endpoint Neon connection AND leave it idle for ~10 s after\n// migrations finish. We avoid that by sharing a single direct exec for\n// the duration of the migration window: the first caller opens it,\n// subsequent callers reuse the same promise, and the last caller closes it\n// via reference-counting. The exec is nulled out after the window so a\n// second cold start (e.g. after a Lambda thaw) gets a fresh connection.\n// ---------------------------------------------------------------------------\n\nlet _migrationExecPromise: Promise<DbExec> | null = null;\nlet _migrationExecRefCount = 0;\n\nasync function acquireMigrationExec(): Promise<DbExec> {\n if (!_migrationExecPromise) {\n const opened = createDbExec({ url: getMigrationDatabaseUrl() });\n _migrationExecPromise = opened;\n opened.catch(() => {\n // Opening the connection failed. Reset the shared state so the next\n // caller retries with a fresh connection instead of awaiting this\n // permanently rejected promise — and zero the ref count, because none\n // of the awaiters that failed here will ever call release.\n if (_migrationExecPromise === opened) {\n _migrationExecPromise = null;\n _migrationExecRefCount = 0;\n }\n });\n }\n _migrationExecRefCount++;\n return _migrationExecPromise;\n}\n\nasync function releaseMigrationExec(): Promise<void> {\n _migrationExecRefCount--;\n if (_migrationExecRefCount > 0) return;\n // Last caller — close and reset so next boot gets a fresh connection.\n const execPromise = _migrationExecPromise;\n _migrationExecPromise = null;\n _migrationExecRefCount = 0;\n if (!execPromise) return;\n try {\n const exec = await execPromise;\n await exec.close?.();\n } catch {\n // Swallow close errors — the migrations themselves already succeeded or\n // failed; a cleanup error should not surface as a boot crash.\n }\n}\n\ntype NitroPluginDef = (nitroApp: any) => void | Promise<void>;\n\n/**\n * Rewrite SQLite-specific SQL to Postgres-compatible equivalents.\n * Handles: datetime('now') → CURRENT_TIMESTAMP, AUTOINCREMENT → GENERATED, etc.\n */\nfunction adaptSqlForPostgres(sql: string): string {\n return sql\n .replace(/datetime\\s*\\(\\s*'now'\\s*\\)/gi, \"CURRENT_TIMESTAMP\")\n .replace(/\\bAUTOINCREMENT\\b/gi, \"\")\n .replace(/\\bINTEGER\\b/gi, \"BIGINT\");\n}\n\nconst IF_NOT_EXISTS_ADD_COLUMN_RE = /ADD\\s+COLUMN\\s+IF\\s+NOT\\s+EXISTS/i;\n\n/**\n * Strip Postgres-only syntax that SQLite doesn't support.\n * Handles: ALTER TABLE ... ADD COLUMN IF NOT EXISTS → ADD COLUMN\n *\n * Note: SQLite does not have a native equivalent, so the idempotent\n * semantic is emulated at the executor level by swallowing the\n * \"duplicate column name\" error for statements that originally carried\n * the clause. See `hadIfNotExists` tracking in the run loop.\n */\nfunction adaptSqlForSqlite(sql: string): string {\n return sql.replace(/ADD\\s+COLUMN\\s+IF\\s+NOT\\s+EXISTS/gi, \"ADD COLUMN\");\n}\n\n/**\n * True when an error from `ALTER TABLE ... ADD COLUMN` indicates the\n * column already existed. Recognizes both SQLite (\"duplicate column\n * name\") and Postgres (\"column ... already exists\" — exact text varies\n * by error code 42701, but the substring is stable). Exported so other\n * idempotent column-upgrade loops in the codebase don't reinvent this\n * regex with subtly different shapes.\n */\nexport function isDuplicateColumnError(err: unknown): boolean {\n const msg = (err as Error | undefined)?.message ?? \"\";\n return (\n /duplicate column name/i.test(msg) || /column .* already exists/i.test(msg)\n );\n}\n\n/**\n * True when a migration statement failed because the connected DB ROLE lacks\n * privilege — e.g. a permission-limited dev/replica role that doesn't own the\n * table. Postgres raises SQLSTATE 42501 (\"insufficient_privilege\", routine\n * aclcheck_error, message \"must be owner of table …\"). We treat these as\n * NON-FATAL so a perms-limited database can't crash-loop the whole server: the\n * migration is skipped (left unrecorded) and a properly-privileged role applies\n * it later. Production, where the role owns its tables, never hits this path.\n */\nexport function isPermissionError(err: unknown): boolean {\n const e = err as { code?: string; message?: string } | undefined;\n if (e?.code === \"42501\") return true;\n const msg = e?.message ?? \"\";\n return (\n /must be owner of/i.test(msg) ||\n /permission denied/i.test(msg) ||\n /insufficient privilege/i.test(msg)\n );\n}\n\n/**\n * Split a multi-statement SQL blob into individual statements.\n *\n * libsql's `execute(sql)` only runs the first statement in a multi-statement\n * string. This splitter is intentionally simple: it respects single-quoted\n * string literals (with `''` escaping) and `--` line comments, and splits on\n * top-level `;`. It does NOT attempt to parse `$$`-quoted Postgres function\n * bodies — migrations that define functions/triggers with `;` inside bodies\n * should pass a single-statement migration per entry instead.\n */\nfunction splitSqlStatements(sql: string): string[] {\n const out: string[] = [];\n let buf = \"\";\n let i = 0;\n let inSingle = false;\n while (i < sql.length) {\n const ch = sql[i];\n const next = sql[i + 1];\n if (!inSingle && ch === \"-\" && next === \"-\") {\n // Skip to end of line\n while (i < sql.length && sql[i] !== \"\\n\") i++;\n continue;\n }\n if (ch === \"'\") {\n buf += ch;\n if (inSingle && next === \"'\") {\n buf += next;\n i += 2;\n continue;\n }\n inSingle = !inSingle;\n i++;\n continue;\n }\n if (ch === \";\" && !inSingle) {\n const trimmed = buf.trim();\n if (trimmed) out.push(trimmed);\n buf = \"\";\n i++;\n continue;\n }\n buf += ch;\n i++;\n }\n const tail = buf.trim();\n if (tail) out.push(tail);\n return out;\n}\n\nexport interface RunMigrationsOptions {\n /**\n * Name of the migrations bookkeeping table. REQUIRED — there is intentionally\n * no default. Two templates that share a database (e.g. via the same Neon URL)\n * each have their own version space starting at v1, and a single shared\n * `_migrations` table will silently skip the second template's migrations if\n * the first has already advanced past those version numbers. This caused the\n * design template's migrations to be skipped entirely on a Neon DB that\n * slides had already populated up to v15 (PR #320 era).\n *\n * Use one bookkeeping table per template, e.g. `slides_migrations`. Core\n * feature plugins (e.g. the org module) follow the same convention with\n * their own prefix, e.g. `_org_migrations`.\n */\n table: string;\n}\n\n/**\n * A single migration entry.\n *\n * `sql` can be a string (runs on every dialect) or an object with dialect\n * keys for dialect-gated SQL. Useful when Postgres needs an ALTER that\n * SQLite can't parse.\n *\n * { version: 14, sql: { postgres: \"ALTER TABLE …\" } } // no-op on sqlite\n * { version: 15, sql: { sqlite: \"…\", postgres: \"…\" } } // both dialects\n *\n * `name` is an optional stable, unique slug that opts a migration into\n * **name-based tracking** instead of the legacy version-number gate. See the\n * \"Name-based tracking\" section on `runMigrations` for why this exists and\n * exactly how the two gating strategies interact.\n */\nexport type MigrationSql = string | { postgres?: string; sqlite?: string };\n\nexport interface MigrationEntry {\n version: number;\n sql: MigrationSql;\n /**\n * Stable, unique slug for this migration (e.g. `\"analytics-alert-rules-table\"`).\n * When present, this migration is tracked by NAME instead of by version\n * number — see the `runMigrations` doc comment for the full rationale and\n * gating rules. Must be unique across the migration list; a duplicate name\n * throws at startup (programmer error, not a runtime data problem).\n */\n name?: string;\n}\n\nfunction resolveMigrationSql(sql: MigrationSql, pg: boolean): string | null {\n if (typeof sql === \"string\") return sql;\n const raw = pg ? sql.postgres : sql.sqlite;\n return raw ?? null;\n}\n\n/**\n * Runs a list of migrations against the configured database, gated by a\n * per-table bookkeeping row (`options.table`) so repeated boots only apply\n * new migrations.\n *\n * ## Name-based tracking (why it exists)\n *\n * The legacy gate is purely numeric: `SELECT MAX(version)` from the\n * bookkeeping table, then apply every entry whose `version` is greater. That\n * scheme silently breaks down when **two independent branches each extend the\n * same migration list with different DDL under the same version numbers** —\n * exactly what happened to the analytics template's v75-v83 range. Branch A\n * shipped alert-rule tables as v75-v78; branch B shipped unrelated DDL as its\n * own v75-v83. Whichever branch deployed first recorded \"v75..v83 applied\"\n * in the bookkeeping table. When the other branch merged and deployed, its\n * migrations at those same version numbers were never applied — `MAX(version)`\n * was already ≥ their version, so the gate treated them as done even though\n * their actual DDL had never run. The result: `analytics_migrations` showed\n * rows for 1..83 with no gaps, yet `analytics_alert_rules`,\n * `analytics_alert_incidents`, and `session_recordings.network_error_count`\n * did not exist in production. Version numbers are not a stable identity —\n * they're just sequence position, and sequence position collides across\n * branches.\n *\n * Name-based tracking fixes this by keying application on a stable, unique\n * **string slug** instead of a position in a shared integer sequence:\n *\n * - Entries with a `name` are recorded in a companion table,\n * `${table}_named` (`name TEXT PRIMARY KEY`), and APPLY IFF their name is\n * absent from that table — completely independent of version numbers or\n * the legacy `MAX(version)` gate. Two branches can both ship a migration\n * named `\"analytics-alert-rules-table\"` at version 75, or one at version 75\n * and the other at version 90 after a rebase — either way it applies\n * exactly once per database, keyed on the name.\n * - Entries WITHOUT a `name` keep the exact legacy behavior\n * (`version > MAX(recorded version)`), so nothing changes for existing\n * unnamed migrations.\n * - Named migrations still execute in list order, interleaved with unnamed\n * ones exactly as written.\n * - When a named migration's DDL runs, we record BOTH the named row (always)\n * and — if its `version` is greater than the current legacy max — the\n * legacy version row too, in the SAME atomic batch/transaction as the DDL.\n * This keeps the legacy `MAX(version)` gate monotonically advancing for\n * any unnamed migrations that come after it in the list, while ensuring a\n * named migration is never \"double recorded\" in a way that would let it\n * re-apply.\n * - A duplicate `name` across the migration list throws at startup — that's\n * a programmer error (copy-paste or merge mistake), not a runtime data\n * problem, and failing loud beats silently tracking the wrong row.\n *\n * New migrations should always set a `name`. Legacy unnamed migrations don't\n * need to be renamed retroactively — the two gating strategies coexist in the\n * same list — but if a table is EVER at risk of being shared across parallel\n * branches (any template's own migrations qualify, since branches routinely\n * extend the same list concurrently), giving new entries a name is what makes\n * them immune to the collision class described above.\n */\nexport function runMigrations(\n migrations: Array<MigrationEntry>,\n options: RunMigrationsOptions,\n): NitroPluginDef {\n const table = options?.table;\n if (\n !table ||\n typeof table !== \"string\" ||\n !/^[A-Za-z_][A-Za-z0-9_]*$/.test(table)\n ) {\n throw new Error(\n \"runMigrations: `table` option is required and must be a valid SQL identifier \" +\n '(e.g. `{ table: \"slides_migrations\" }`). See packages/core/src/db/migrations.ts ' +\n \"for why this is required (shared-DB version-collision bug).\",\n );\n }\n\n // Duplicate-name detection — programmer error, fail loud at startup rather\n // than silently tracking the wrong migration's applied state.\n {\n const seenNames = new Set<string>();\n for (const m of migrations) {\n if (!m.name) continue;\n if (seenNames.has(m.name)) {\n throw new Error(\n `runMigrations: duplicate migration name \"${m.name}\" in the migration list for table \"${table}\". ` +\n \"Migration names must be unique — pick a different stable slug.\",\n );\n }\n seenNames.add(m.name);\n }\n }\n\n const namedTable = `${table}_named`;\n\n return async () => {\n try {\n // Check for Cloudflare D1 binding (only if DATABASE_URL not set)\n const d1 =\n getDialect() === \"d1\"\n ? (getCloudflareD1Binding() as D1DatabaseLike | undefined)\n : null;\n if (d1) {\n await d1\n .prepare(\n `CREATE TABLE IF NOT EXISTS ${table} (version INTEGER PRIMARY KEY)`,\n )\n .run();\n await d1\n .prepare(\n `CREATE TABLE IF NOT EXISTS ${namedTable} (name TEXT PRIMARY KEY, version INTEGER, applied_at TEXT NOT NULL DEFAULT (datetime('now')))`,\n )\n .run();\n const firstRow = await d1\n .prepare(`SELECT MAX(version) as v FROM ${table}`)\n .first<{ v?: number }>();\n const current = (firstRow?.v as number) ?? 0;\n\n const appliedNamesRows = await d1\n .prepare(`SELECT name FROM ${namedTable}`)\n .all();\n const appliedNames = new Set(\n (appliedNamesRows?.results ?? []).map((r) => String(r.name)),\n );\n\n const pending = migrations.filter((m) =>\n m.name ? !appliedNames.has(m.name) : m.version > current,\n );\n\n for (const m of pending) {\n try {\n // D1 is SQLite-compatible\n const raw = resolveMigrationSql(m.sql, false);\n const recordStatements = [\n m.name\n ? d1\n .prepare(\n `INSERT OR IGNORE INTO ${namedTable} (name, version) VALUES (?, ?)`,\n )\n .bind(m.name, m.version)\n : null,\n m.version > current\n ? d1\n .prepare(`INSERT OR IGNORE INTO ${table} VALUES (?)`)\n .bind(m.version)\n : null,\n ].filter((s): s is NonNullable<typeof s> => s != null);\n\n if (raw == null) {\n // Dialect-gated migration with no SQL for this dialect; still\n // record it so we don't retry forever.\n for (const stmt of recordStatements) await stmt.run();\n continue;\n }\n const originalStatements = splitSqlStatements(raw);\n const statements = originalStatements.map((orig) => ({\n sql: adaptSqlForSqlite(orig),\n hadIfNotExists: IF_NOT_EXISTS_ADD_COLUMN_RE.test(orig),\n }));\n const hasIfNotExists = statements.some((s) => s.hadIfNotExists);\n if (hasIfNotExists) {\n // Per-statement path: we need to swallow \"duplicate column\"\n // errors for statements that originally carried\n // `ADD COLUMN IF NOT EXISTS`, which a batch() can't express.\n // Loses atomicity, but the idempotent-ADD-COLUMN semantic\n // means a partial re-run resolves cleanly on retry.\n for (const { sql: stmt, hadIfNotExists } of statements) {\n try {\n await d1.prepare(stmt).run();\n } catch (err) {\n if (hadIfNotExists && isDuplicateColumnError(err)) continue;\n throw err;\n }\n }\n for (const stmt of recordStatements) await stmt.run();\n } else {\n // Atomic batch: all statements + bookkeeping inserts land in\n // the same transaction. A failing statement rolls the whole\n // migration back, so we never record a half-applied migration.\n await d1.batch([\n ...statements.map((s) => d1.prepare(s.sql)),\n ...recordStatements,\n ]);\n }\n console.log(\n `[db] Applied migration ${m.name ? `\"${m.name}\" ` : \"\"}v${m.version} (${statements.length} statement${statements.length === 1 ? \"\" : \"s\"})`,\n );\n } catch (err) {\n console.error(\n `[db] Migration ${m.name ? `\"${m.name}\" ` : \"\"}v${m.version} FAILED:`,\n (err as Error).message,\n \"\\nSQL:\",\n JSON.stringify(m.sql),\n );\n throw err;\n }\n }\n return;\n }\n\n // Generic path — works for libsql and Postgres\n const pg = isPostgres();\n\n // ---------------------------------------------------------------------------\n // Fast-path: read migration state through the regular pooled singleton before\n // opening the direct-endpoint connection.\n //\n // On Postgres every cold start previously opened a fresh direct-endpoint Neon\n // connection (bypassing PgBouncer, which is needed only for DDL), ran\n // CREATE TABLE IF NOT EXISTS + SELECT MAX(version) even with zero pending\n // migrations, and never closed the pool — it idled for ~10 s. Three runners\n // (core, org, context-xray) did this independently per boot.\n //\n // Now: use the pooled singleton (getDbExec) for the bookkeeping SELECT. If\n // the migrations table does not yet exist we treat it as \"all migrations\n // pending\" (current = -1). Only when there are pending migrations do we open\n // the direct-endpoint exec (DDL is the only thing Neon's PgBouncer blocks —\n // documented at getMigrationDatabaseUrl). The direct exec is shared across\n // concurrent runners via acquireMigrationExec() and closed after the last\n // caller via releaseMigrationExec().\n // ---------------------------------------------------------------------------\n\n let current = -1; // sentinel: \"table missing\" → treat all as pending\n let namedRowsMissing = false; // sentinel: \"named table missing\" → no names applied yet\n\n // Any migration with a `name` is a candidate regardless of version, so\n // the fast-path \"anything pending?\" check must also account for names.\n const hasNamedMigrations = migrations.some((m) => m.name);\n let appliedNames = new Set<string>();\n\n if (pg) {\n try {\n const { rows } = await getDbExec().execute(\n `SELECT MAX(version) as v FROM ${table}`,\n );\n current = (rows[0]?.v as number) ?? 0;\n } catch {\n // Table doesn't exist yet — leave current = -1 so all migrations apply.\n }\n if (hasNamedMigrations) {\n try {\n const { rows } = await getDbExec().execute(\n `SELECT name FROM ${namedTable}`,\n );\n appliedNames = new Set(rows.map((r) => String(r.name)));\n } catch {\n // Named table doesn't exist yet — leave appliedNames empty so all\n // named migrations apply.\n namedRowsMissing = true;\n }\n }\n }\n\n // For SQLite we still use getDbExec() as exec throughout (no pooler concern).\n // For Postgres we only open the direct exec when there are pending migrations.\n const pendingFast = pg\n ? migrations.filter((m) =>\n m.name ? !appliedNames.has(m.name) : m.version > current,\n )\n : null; // SQLite: compute after table creation below\n\n // Short-circuit: Postgres with nothing to do — skip the direct connection entirely.\n if (pg && pendingFast !== null && pendingFast.length === 0) {\n return;\n }\n\n // Acquire the exec appropriate for the dialect.\n // For Postgres: the shared direct-endpoint exec (DDL-safe, closed on release).\n // For SQLite/libsql: the singleton pooled exec (no pooler concern).\n const exec = pg ? await acquireMigrationExec() : getDbExec();\n\n try {\n // Retry initial table creation — SQLITE_BUSY_RECOVERY can occur on HMR\n // restarts when WAL files from the previous process haven't been released yet.\n await retrySqliteBusy(\n () =>\n exec.execute(\n `CREATE TABLE IF NOT EXISTS ${table} (version INTEGER PRIMARY KEY)`,\n ),\n { maxAttempts: 6, baseDelayMs: 1000, rethrow: true },\n );\n // Companion name-keyed bookkeeping table — never alters the existing\n // `${table}`'s PRIMARY KEY, so legacy version rows keep working exactly\n // as before. See the `runMigrations` doc comment for why this exists.\n await retrySqliteBusy(\n () =>\n exec.execute(\n `CREATE TABLE IF NOT EXISTS ${namedTable} (name TEXT PRIMARY KEY, version INTEGER, applied_at ${pg ? \"TIMESTAMP NOT NULL DEFAULT now()\" : \"TEXT NOT NULL DEFAULT (datetime('now'))\"})`,\n ),\n { maxAttempts: 6, baseDelayMs: 1000, rethrow: true },\n );\n\n // For Postgres, current was already set by the fast-path SELECT above.\n // For SQLite we run the SELECT now (via the same exec, which is the singleton).\n if (!pg) {\n const { rows } = await exec.execute(\n `SELECT MAX(version) as v FROM ${table}`,\n );\n current = (rows[0]?.v as number) ?? 0;\n if (hasNamedMigrations) {\n const { rows: nameRows } = await exec.execute(\n `SELECT name FROM ${namedTable}`,\n );\n appliedNames = new Set(nameRows.map((r) => String(r.name)));\n }\n } else if (current === -1 || (hasNamedMigrations && namedRowsMissing)) {\n // Fast-path read failed (table was absent on the pooler): re-read via the\n // direct exec now that CREATE TABLE IF NOT EXISTS has ensured it exists.\n if (current === -1) {\n const { rows } = await exec.execute(\n `SELECT MAX(version) as v FROM ${table}`,\n );\n current = (rows[0]?.v as number) ?? 0;\n }\n if (hasNamedMigrations && namedRowsMissing) {\n const { rows: nameRows } = await exec.execute(\n `SELECT name FROM ${namedTable}`,\n );\n appliedNames = new Set(nameRows.map((r) => String(r.name)));\n }\n }\n\n const insertVersionSql = pg\n ? `INSERT INTO ${table} VALUES (?) ON CONFLICT DO NOTHING`\n : `INSERT OR IGNORE INTO ${table} VALUES (?)`;\n const insertNamedSql = pg\n ? `INSERT INTO ${namedTable} (name, version) VALUES (?, ?) ON CONFLICT DO NOTHING`\n : `INSERT OR IGNORE INTO ${namedTable} (name, version) VALUES (?, ?)`;\n\n const pending = migrations.filter((m) =>\n m.name ? !appliedNames.has(m.name) : m.version > current,\n );\n if (pending.length > 0) {\n console.log(\n `[db] Applying ${pending.length} migration(s) on ${pg ? \"Postgres\" : \"SQLite/libsql\"}…`,\n );\n }\n\n for (const m of pending) {\n const raw = resolveMigrationSql(m.sql, pg);\n const label = m.name\n ? `\"${m.name}\" (v${m.version})`\n : `v${m.version}`;\n\n // Record BOTH the named row (always, when named) and the legacy\n // version row (only if this migration actually advances the legacy\n // MAX) — atomically with the DDL below. This keeps the legacy gate\n // monotonic for any unnamed migrations later in the list, while a\n // named migration is tracked by name regardless of version.\n const recordSql: Array<{ sql: string; args: unknown[] }> = [];\n if (m.name) {\n recordSql.push({\n sql: insertNamedSql,\n args: [m.name, m.version],\n });\n }\n if (m.version > current) {\n recordSql.push({ sql: insertVersionSql, args: [m.version] });\n }\n\n if (raw == null) {\n // Dialect-gated migration with no SQL for this dialect; still mark\n // as applied so we don't retry forever.\n for (const stmt of recordSql) await exec.execute(stmt);\n if (m.version > current) current = m.version;\n if (m.name) appliedNames.add(m.name);\n continue;\n }\n // Split BEFORE adapting so we can remember which original statements\n // carried `ADD COLUMN IF NOT EXISTS` — SQLite drops the clause, so we\n // emulate the idempotent semantic by swallowing duplicate-column\n // errors only for those statements.\n const originalStatements = splitSqlStatements(raw);\n const statements = originalStatements.map((orig) => ({\n sql: pg ? adaptSqlForPostgres(orig) : adaptSqlForSqlite(orig),\n hadIfNotExists: IF_NOT_EXISTS_ADD_COLUMN_RE.test(orig),\n }));\n let currentStmt = \"\";\n try {\n for (const { sql: stmt, hadIfNotExists } of statements) {\n currentStmt = stmt;\n try {\n await exec.execute(stmt);\n } catch (err) {\n if (!pg && hadIfNotExists && isDuplicateColumnError(err)) {\n // IF NOT EXISTS semantic: column already present, skip.\n continue;\n }\n throw err;\n }\n }\n for (const stmt of recordSql) await exec.execute(stmt);\n if (m.version > current) current = m.version;\n if (m.name) appliedNames.add(m.name);\n console.log(\n `[db] Applied migration ${label} (${statements.length} statement${statements.length === 1 ? \"\" : \"s\"})`,\n );\n } catch (err) {\n if (pg && isPermissionError(err)) {\n // The connected role lacks privilege for this migration (e.g. a\n // permission-limited dev/replica role that doesn't own the table).\n // Don't crash-loop the whole server over it — warn and STOP here.\n // We must NOT continue to later migrations: unnamed pending work is\n // computed as `version > MAX(recorded version)`, so applying a later\n // unnamed migration would advance MAX past this unrecorded one and\n // orphan it forever. Stopping leaves MAX at the last recorded\n // version, so a properly-privileged role resumes from this exact\n // migration, in order. (A named migration skipped here simply\n // isn't recorded by name either, so it's retried next boot same as\n // the legacy gate — no orphaning risk from name-based tracking.)\n console.warn(\n `[db] Migration ${label} skipped — insufficient privilege: ${(err as Error).message}. ` +\n `Apply it with a DB role that owns the table. ` +\n `Halting further migrations so this one isn't orphaned. ` +\n `Set <APP_NAME>_DATABASE_URL (e.g. PLAN_DATABASE_URL) to a database this app owns — a file: URL uses local SQLite.`,\n \"\\nStatement:\",\n currentStmt,\n );\n break;\n }\n console.error(\n `[db] Migration ${label} FAILED:`,\n (err as Error).message,\n \"\\nStatement:\",\n currentStmt,\n );\n throw err;\n }\n }\n } finally {\n // Release the direct-endpoint exec (Postgres only). For SQLite getDbExec()\n // returns the process-lifetime singleton, so releaseMigrationExec is a no-op\n // (refCount never incremented for SQLite path, guard in releaseMigrationExec).\n if (pg) await releaseMigrationExec();\n }\n } catch (err) {\n console.error(\"[db] Migration failed:\", (err as Error).message);\n // In local dev, hard-fail so the developer catches errors immediately.\n // On serverless runtimes (Netlify Functions, Vercel, CF Workers) we\n // keep the process alive — the app will return 500s for routes that\n // depend on the missing tables, but at least other routes still work.\n // Note: Node.js 21+ defines globalThis.navigator, so we check for\n // serverless env vars instead of navigator presence.\n const isServerless =\n !!globalThis.process?.env?.NETLIFY ||\n !!globalThis.process?.env?.AWS_LAMBDA_FUNCTION_NAME ||\n !!globalThis.process?.env?.VERCEL ||\n \"__cf_env\" in globalThis;\n if (typeof globalThis.process?.exit === \"function\" && !isServerless) {\n process.exit(1);\n }\n }\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"migrations.js","sourceRoot":"","sources":["../../src/db/migrations.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n getDbExec,\n createDbExec,\n isPostgres,\n getDialect,\n getMigrationDatabaseUrl,\n getCloudflareD1Binding,\n retrySqliteBusy,\n type DbExec,\n} from \"./client.js\";\n\ninterface D1PreparedStatementLike {\n bind(...values: unknown[]): D1PreparedStatementLike;\n all(): Promise<{ results: Record<string, unknown>[] }>;\n first<T = Record<string, unknown>>(): Promise<T | null>;\n run(): Promise<unknown>;\n}\n\ninterface D1DatabaseLike {\n prepare(query: string): D1PreparedStatementLike;\n batch(statements: D1PreparedStatementLike[]): Promise<unknown>;\n}\n\n// ---------------------------------------------------------------------------\n// Shared direct-endpoint exec across concurrent migration runners per boot.\n//\n// On each serverless cold start THREE plugins call runMigrations (core,\n// org, context-xray). Without coordination each would open an independent\n// direct-endpoint Neon connection AND leave it idle for ~10 s after\n// migrations finish. We avoid that by sharing a single direct exec for\n// the duration of the migration window: the first caller opens it,\n// subsequent callers reuse the same promise, and the last caller closes it\n// via reference-counting. The exec is nulled out after the window so a\n// second cold start (e.g. after a Lambda thaw) gets a fresh connection.\n// ---------------------------------------------------------------------------\n\nlet _migrationExecPromise: Promise<DbExec> | null = null;\nlet _migrationExecRefCount = 0;\n\nasync function acquireMigrationExec(): Promise<DbExec> {\n if (!_migrationExecPromise) {\n const opened = createDbExec({ url: getMigrationDatabaseUrl() });\n _migrationExecPromise = opened;\n opened.catch(() => {\n // Opening the connection failed. Reset the shared state so the next\n // caller retries with a fresh connection instead of awaiting this\n // permanently rejected promise — and zero the ref count, because none\n // of the awaiters that failed here will ever call release.\n if (_migrationExecPromise === opened) {\n _migrationExecPromise = null;\n _migrationExecRefCount = 0;\n }\n });\n }\n _migrationExecRefCount++;\n return _migrationExecPromise;\n}\n\nasync function releaseMigrationExec(): Promise<void> {\n _migrationExecRefCount--;\n if (_migrationExecRefCount > 0) return;\n // Last caller — close and reset so next boot gets a fresh connection.\n const execPromise = _migrationExecPromise;\n _migrationExecPromise = null;\n _migrationExecRefCount = 0;\n if (!execPromise) return;\n try {\n const exec = await execPromise;\n await exec.close?.();\n } catch {\n // Swallow close errors — the migrations themselves already succeeded or\n // failed; a cleanup error should not surface as a boot crash.\n }\n}\n\ntype NitroPluginDef = (nitroApp: any) => void | Promise<void>;\n\n/**\n * Rewrite SQLite-specific SQL to Postgres-compatible equivalents.\n * Handles: datetime('now') → CURRENT_TIMESTAMP, AUTOINCREMENT → GENERATED, etc.\n */\nfunction adaptSqlForPostgres(sql: string): string {\n return sql\n .replace(/datetime\\s*\\(\\s*'now'\\s*\\)/gi, \"CURRENT_TIMESTAMP\")\n .replace(/\\bAUTOINCREMENT\\b/gi, \"\")\n .replace(/\\bINTEGER\\b/gi, \"BIGINT\");\n}\n\nconst IF_NOT_EXISTS_ADD_COLUMN_RE = /ADD\\s+COLUMN\\s+IF\\s+NOT\\s+EXISTS/i;\n\n/**\n * Strip Postgres-only syntax that SQLite doesn't support.\n * Handles: ALTER TABLE ... ADD COLUMN IF NOT EXISTS → ADD COLUMN\n *\n * Note: SQLite does not have a native equivalent, so the idempotent\n * semantic is emulated at the executor level by swallowing the\n * \"duplicate column name\" error for statements that originally carried\n * the clause. See `hadIfNotExists` tracking in the run loop.\n */\nfunction adaptSqlForSqlite(sql: string): string {\n return sql.replace(/ADD\\s+COLUMN\\s+IF\\s+NOT\\s+EXISTS/gi, \"ADD COLUMN\");\n}\n\n/**\n * True when an error from `ALTER TABLE ... ADD COLUMN` indicates the\n * column already existed. Recognizes both SQLite (\"duplicate column\n * name\") and Postgres (\"column ... already exists\" — exact text varies\n * by error code 42701, but the substring is stable). Exported so other\n * idempotent column-upgrade loops in the codebase don't reinvent this\n * regex with subtly different shapes.\n */\nexport function isDuplicateColumnError(err: unknown): boolean {\n const msg = (err as Error | undefined)?.message ?? \"\";\n return (\n /duplicate column name/i.test(msg) || /column .* already exists/i.test(msg)\n );\n}\n\n/**\n * True when a migration statement failed because the connected DB ROLE lacks\n * privilege — e.g. a permission-limited dev/replica role that doesn't own the\n * table. Postgres raises SQLSTATE 42501 (\"insufficient_privilege\", routine\n * aclcheck_error, message \"must be owner of table …\"). We treat these as\n * NON-FATAL so a perms-limited database can't crash-loop the whole server: the\n * migration is skipped (left unrecorded) and a properly-privileged role applies\n * it later. Production, where the role owns its tables, never hits this path.\n */\nexport function isPermissionError(err: unknown): boolean {\n const e = err as { code?: string; message?: string } | undefined;\n if (e?.code === \"42501\") return true;\n const msg = e?.message ?? \"\";\n return (\n /must be owner of/i.test(msg) ||\n /permission denied/i.test(msg) ||\n /insufficient privilege/i.test(msg)\n );\n}\n\n/**\n * Split a multi-statement SQL blob into individual statements.\n *\n * libsql's `execute(sql)` only runs the first statement in a multi-statement\n * string. This splitter is intentionally simple: it respects single-quoted\n * string literals (with `''` escaping) and `--` line comments, and splits on\n * top-level `;`. It does NOT attempt to parse `$$`-quoted Postgres function\n * bodies — migrations that define functions/triggers with `;` inside bodies\n * should pass a single-statement migration per entry instead.\n */\nfunction splitSqlStatements(sql: string): string[] {\n const out: string[] = [];\n let buf = \"\";\n let i = 0;\n let inSingle = false;\n while (i < sql.length) {\n const ch = sql[i];\n const next = sql[i + 1];\n if (!inSingle && ch === \"-\" && next === \"-\") {\n // Skip to end of line\n while (i < sql.length && sql[i] !== \"\\n\") i++;\n continue;\n }\n if (ch === \"'\") {\n buf += ch;\n if (inSingle && next === \"'\") {\n buf += next;\n i += 2;\n continue;\n }\n inSingle = !inSingle;\n i++;\n continue;\n }\n if (ch === \";\" && !inSingle) {\n const trimmed = buf.trim();\n if (trimmed) out.push(trimmed);\n buf = \"\";\n i++;\n continue;\n }\n buf += ch;\n i++;\n }\n const tail = buf.trim();\n if (tail) out.push(tail);\n return out;\n}\n\nexport interface RunMigrationsOptions {\n /**\n * Name of the migrations bookkeeping table. REQUIRED — there is intentionally\n * no default. Two templates that share a database (e.g. via the same Neon URL)\n * each have their own version space starting at v1, and a single shared\n * `_migrations` table will silently skip the second template's migrations if\n * the first has already advanced past those version numbers. This caused the\n * design template's migrations to be skipped entirely on a Neon DB that\n * slides had already populated up to v15 (PR #320 era).\n *\n * Use one bookkeeping table per template, e.g. `slides_migrations`. Core\n * feature plugins (e.g. the org module) follow the same convention with\n * their own prefix, e.g. `_org_migrations`.\n */\n table: string;\n}\n\n/**\n * A single migration entry.\n *\n * `sql` can be a string (runs on every dialect) or an object with dialect\n * keys for dialect-gated SQL. Useful when Postgres needs an ALTER that\n * SQLite can't parse.\n *\n * { version: 14, sql: { postgres: \"ALTER TABLE …\" } } // no-op on sqlite\n * { version: 15, sql: { sqlite: \"…\", postgres: \"…\" } } // both dialects\n *\n * `name` is an optional stable, unique slug that opts a migration into\n * **name-based tracking** instead of the legacy version-number gate. See the\n * \"Name-based tracking\" section on `runMigrations` for why this exists and\n * exactly how the two gating strategies interact.\n */\nexport type MigrationSql = string | { postgres?: string; sqlite?: string };\n\nexport interface MigrationEntry {\n version: number;\n sql: MigrationSql;\n /**\n * Stable, unique slug for this migration (e.g. `\"analytics-alert-rules-table\"`).\n * When present, this migration is tracked by NAME instead of by version\n * number — see the `runMigrations` doc comment for the full rationale and\n * gating rules. Must be unique across the migration list; a duplicate name\n * throws at startup (programmer error, not a runtime data problem).\n */\n name?: string;\n}\n\nfunction resolveMigrationSql(sql: MigrationSql, pg: boolean): string | null {\n if (typeof sql === \"string\") return sql;\n const raw = pg ? sql.postgres : sql.sqlite;\n return raw ?? null;\n}\n\n/**\n * Runs a list of migrations against the configured database, gated by a\n * per-table bookkeeping row (`options.table`) so repeated boots only apply\n * new migrations.\n *\n * ## Name-based tracking (why it exists)\n *\n * The legacy gate is purely numeric: `SELECT MAX(version)` from the\n * bookkeeping table, then apply every entry whose `version` is greater. That\n * scheme silently breaks down when **two independent branches each extend the\n * same migration list with different DDL under the same version numbers** —\n * exactly what happened to the analytics template's v75-v83 range. Branch A\n * shipped alert-rule tables as v75-v78; branch B shipped unrelated DDL as its\n * own v75-v83. Whichever branch deployed first recorded \"v75..v83 applied\"\n * in the bookkeeping table. When the other branch merged and deployed, its\n * migrations at those same version numbers were never applied — `MAX(version)`\n * was already ≥ their version, so the gate treated them as done even though\n * their actual DDL had never run. The result: `analytics_migrations` showed\n * rows for 1..83 with no gaps, yet `analytics_alert_rules`,\n * `analytics_alert_incidents`, and `session_recordings.network_error_count`\n * did not exist in production. Version numbers are not a stable identity —\n * they're just sequence position, and sequence position collides across\n * branches.\n *\n * Name-based tracking fixes this by keying application on a stable, unique\n * **string slug** instead of a position in a shared integer sequence:\n *\n * - Entries with a `name` are recorded in a companion table,\n * `${table}_named` (`name TEXT PRIMARY KEY`), and APPLY IFF their name is\n * absent from that table — completely independent of version numbers or\n * the legacy `MAX(version)` gate. Two branches can both ship a migration\n * named `\"analytics-alert-rules-table\"` at version 75, or one at version 75\n * and the other at version 90 after a rebase — either way it applies\n * exactly once per database, keyed on the name.\n * - Entries WITHOUT a `name` keep the exact legacy behavior\n * (`version > MAX(recorded version)`), so nothing changes for existing\n * unnamed migrations.\n * - Named migrations still execute in list order, interleaved with unnamed\n * ones exactly as written.\n * - When a named migration's DDL runs, we record BOTH the named row (always)\n * and — if its `version` is greater than the current legacy max — the\n * legacy version row too, in the SAME atomic batch/transaction as the DDL.\n * This keeps the legacy `MAX(version)` gate monotonically advancing for\n * any unnamed migrations that come after it in the list, while ensuring a\n * named migration is never \"double recorded\" in a way that would let it\n * re-apply.\n * - A duplicate `name` across the migration list throws at startup — that's\n * a programmer error (copy-paste or merge mistake), not a runtime data\n * problem, and failing loud beats silently tracking the wrong row.\n *\n * New migrations should always set a `name`. Legacy unnamed migrations don't\n * need to be renamed retroactively — the two gating strategies coexist in the\n * same list — but if a table is EVER at risk of being shared across parallel\n * branches (any template's own migrations qualify, since branches routinely\n * extend the same list concurrently), giving new entries a name is what makes\n * them immune to the collision class described above.\n */\nexport function runMigrations(\n migrations: Array<MigrationEntry>,\n options: RunMigrationsOptions,\n): NitroPluginDef {\n const table = options?.table;\n if (\n !table ||\n typeof table !== \"string\" ||\n !/^[A-Za-z_][A-Za-z0-9_]*$/.test(table)\n ) {\n throw new Error(\n \"runMigrations: `table` option is required and must be a valid SQL identifier \" +\n '(e.g. `{ table: \"slides_migrations\" }`). See packages/core/src/db/migrations.ts ' +\n \"for why this is required (shared-DB version-collision bug).\",\n );\n }\n\n // Duplicate-name detection — programmer error, fail loud at startup rather\n // than silently tracking the wrong migration's applied state.\n {\n const seenNames = new Set<string>();\n for (const m of migrations) {\n if (!m.name) continue;\n if (seenNames.has(m.name)) {\n throw new Error(\n `runMigrations: duplicate migration name \"${m.name}\" in the migration list for table \"${table}\". ` +\n \"Migration names must be unique — pick a different stable slug.\",\n );\n }\n seenNames.add(m.name);\n }\n }\n\n const namedTable = `${table}_named`;\n\n return async () => {\n try {\n // Check for Cloudflare D1 binding (only if DATABASE_URL not set)\n const d1 =\n getDialect() === \"d1\"\n ? (getCloudflareD1Binding() as D1DatabaseLike | undefined)\n : null;\n if (d1) {\n await d1\n .prepare(\n `CREATE TABLE IF NOT EXISTS ${table} (version INTEGER PRIMARY KEY)`,\n )\n .run();\n await d1\n .prepare(\n `CREATE TABLE IF NOT EXISTS ${namedTable} (name TEXT PRIMARY KEY, version INTEGER, applied_at TEXT NOT NULL DEFAULT (datetime('now')))`,\n )\n .run();\n const firstRow = await d1\n .prepare(`SELECT MAX(version) as v FROM ${table}`)\n .first<{ v?: number }>();\n const current = (firstRow?.v as number) ?? 0;\n\n const appliedNamesRows = await d1\n .prepare(`SELECT name FROM ${namedTable}`)\n .all();\n const appliedNames = new Set(\n (appliedNamesRows?.results ?? []).map((r) => String(r.name)),\n );\n\n const pending = migrations.filter((m) =>\n m.name ? !appliedNames.has(m.name) : m.version > current,\n );\n\n for (const m of pending) {\n try {\n // D1 is SQLite-compatible\n const raw = resolveMigrationSql(m.sql, false);\n const recordStatements = [\n m.name\n ? d1\n .prepare(\n `INSERT OR IGNORE INTO ${namedTable} (name, version) VALUES (?, ?)`,\n )\n .bind(m.name, m.version)\n : null,\n m.version > current\n ? d1\n .prepare(`INSERT OR IGNORE INTO ${table} VALUES (?)`)\n .bind(m.version)\n : null,\n ].filter((s): s is NonNullable<typeof s> => s != null);\n\n if (raw == null) {\n // Dialect-gated migration with no SQL for this dialect; still\n // record it so we don't retry forever.\n for (const stmt of recordStatements) await stmt.run();\n continue;\n }\n const originalStatements = splitSqlStatements(raw);\n const statements = originalStatements.map((orig) => ({\n sql: adaptSqlForSqlite(orig),\n hadIfNotExists: IF_NOT_EXISTS_ADD_COLUMN_RE.test(orig),\n }));\n const hasIfNotExists = statements.some((s) => s.hadIfNotExists);\n if (hasIfNotExists) {\n // Per-statement path: we need to swallow \"duplicate column\"\n // errors for statements that originally carried\n // `ADD COLUMN IF NOT EXISTS`, which a batch() can't express.\n // Loses atomicity, but the idempotent-ADD-COLUMN semantic\n // means a partial re-run resolves cleanly on retry.\n for (const { sql: stmt, hadIfNotExists } of statements) {\n try {\n await d1.prepare(stmt).run();\n } catch (err) {\n if (hadIfNotExists && isDuplicateColumnError(err)) continue;\n throw err;\n }\n }\n for (const stmt of recordStatements) await stmt.run();\n } else {\n // Atomic batch: all statements + bookkeeping inserts land in\n // the same transaction. A failing statement rolls the whole\n // migration back, so we never record a half-applied migration.\n await d1.batch([\n ...statements.map((s) => d1.prepare(s.sql)),\n ...recordStatements,\n ]);\n }\n console.log(\n `[db] Applied migration ${m.name ? `\"${m.name}\" ` : \"\"}v${m.version} (${statements.length} statement${statements.length === 1 ? \"\" : \"s\"})`,\n );\n } catch (err) {\n console.error(\n `[db] Migration ${m.name ? `\"${m.name}\" ` : \"\"}v${m.version} FAILED:`,\n (err as Error).message,\n \"\\nSQL:\",\n JSON.stringify(m.sql),\n );\n throw err;\n }\n }\n return;\n }\n\n // Generic path — works for libsql and Postgres\n const pg = isPostgres();\n\n // ---------------------------------------------------------------------------\n // Fast-path: read migration state through the regular pooled singleton before\n // opening the direct-endpoint connection.\n //\n // On Postgres every cold start previously opened a fresh direct-endpoint Neon\n // connection (bypassing PgBouncer, which is needed only for DDL), ran\n // CREATE TABLE IF NOT EXISTS + SELECT MAX(version) even with zero pending\n // migrations, and never closed the pool — it idled for ~10 s. Three runners\n // (core, org, context-xray) did this independently per boot.\n //\n // Now: use the pooled singleton (getDbExec) for the bookkeeping SELECT. If\n // the migrations table does not yet exist we treat it as \"all migrations\n // pending\" (current = -1). Only when there are pending migrations do we open\n // the direct-endpoint exec (DDL is the only thing Neon's PgBouncer blocks —\n // documented at getMigrationDatabaseUrl). The direct exec is shared across\n // concurrent runners via acquireMigrationExec() and closed after the last\n // caller via releaseMigrationExec().\n // ---------------------------------------------------------------------------\n\n let current = -1; // sentinel: \"table missing\" → treat all as pending\n let namedRowsMissing = false; // sentinel: \"named table missing\" → no names applied yet\n\n // Any migration with a `name` is a candidate regardless of version, so\n // the fast-path \"anything pending?\" check must also account for names.\n const hasNamedMigrations = migrations.some((m) => m.name);\n let appliedNames = new Set<string>();\n\n if (pg) {\n try {\n const { rows } = await getDbExec().execute(\n `SELECT MAX(version) as v FROM ${table}`,\n );\n current = (rows[0]?.v as number) ?? 0;\n } catch {\n // Table doesn't exist yet — leave current = -1 so all migrations apply.\n }\n if (hasNamedMigrations) {\n try {\n const { rows } = await getDbExec().execute(\n `SELECT name FROM ${namedTable}`,\n );\n appliedNames = new Set(rows.map((r) => String(r.name)));\n } catch {\n // Named table doesn't exist yet — leave appliedNames empty so all\n // named migrations apply.\n namedRowsMissing = true;\n }\n }\n }\n\n // For SQLite we still use getDbExec() as exec throughout (no pooler concern).\n // For Postgres we only open the direct exec when there are pending migrations.\n const pendingFast = pg\n ? migrations.filter((m) =>\n m.name ? !appliedNames.has(m.name) : m.version > current,\n )\n : null; // SQLite: compute after table creation below\n\n // Short-circuit: Postgres with nothing to do — skip the direct connection entirely.\n if (pg && pendingFast !== null && pendingFast.length === 0) {\n return;\n }\n\n // Acquire the exec appropriate for the dialect.\n // For Postgres: the shared direct-endpoint exec (DDL-safe, closed on release).\n // For SQLite/libsql: the singleton pooled exec (no pooler concern).\n const exec = pg ? await acquireMigrationExec() : getDbExec();\n\n try {\n // Retry initial table creation — SQLITE_BUSY_RECOVERY can occur on HMR\n // restarts when WAL files from the previous process haven't been released yet.\n await retrySqliteBusy(\n () =>\n exec.execute(\n `CREATE TABLE IF NOT EXISTS ${table} (version INTEGER PRIMARY KEY)`,\n ),\n { maxAttempts: 6, baseDelayMs: 1000, rethrow: true },\n );\n // Companion name-keyed bookkeeping table — never alters the existing\n // `${table}`'s PRIMARY KEY, so legacy version rows keep working exactly\n // as before. See the `runMigrations` doc comment for why this exists.\n await retrySqliteBusy(\n () =>\n exec.execute(\n `CREATE TABLE IF NOT EXISTS ${namedTable} (name TEXT PRIMARY KEY, version INTEGER, applied_at ${pg ? \"TIMESTAMP NOT NULL DEFAULT now()\" : \"TEXT NOT NULL DEFAULT (datetime('now'))\"})`,\n ),\n { maxAttempts: 6, baseDelayMs: 1000, rethrow: true },\n );\n\n // For Postgres, current was already set by the fast-path SELECT above.\n // For SQLite we run the SELECT now (via the same exec, which is the singleton).\n if (!pg) {\n const { rows } = await exec.execute(\n `SELECT MAX(version) as v FROM ${table}`,\n );\n current = (rows[0]?.v as number) ?? 0;\n if (hasNamedMigrations) {\n const { rows: nameRows } = await exec.execute(\n `SELECT name FROM ${namedTable}`,\n );\n appliedNames = new Set(nameRows.map((r) => String(r.name)));\n }\n } else if (current === -1 || (hasNamedMigrations && namedRowsMissing)) {\n // Fast-path read failed (table was absent on the pooler): re-read via the\n // direct exec now that CREATE TABLE IF NOT EXISTS has ensured it exists.\n if (current === -1) {\n const { rows } = await exec.execute(\n `SELECT MAX(version) as v FROM ${table}`,\n );\n current = (rows[0]?.v as number) ?? 0;\n }\n if (hasNamedMigrations && namedRowsMissing) {\n const { rows: nameRows } = await exec.execute(\n `SELECT name FROM ${namedTable}`,\n );\n appliedNames = new Set(nameRows.map((r) => String(r.name)));\n }\n }\n\n const insertVersionSql = pg\n ? `INSERT INTO ${table} VALUES (?) ON CONFLICT DO NOTHING`\n : `INSERT OR IGNORE INTO ${table} VALUES (?)`;\n const insertNamedSql = pg\n ? `INSERT INTO ${namedTable} (name, version) VALUES (?, ?) ON CONFLICT DO NOTHING`\n : `INSERT OR IGNORE INTO ${namedTable} (name, version) VALUES (?, ?)`;\n\n const pending = migrations.filter((m) =>\n m.name ? !appliedNames.has(m.name) : m.version > current,\n );\n if (pending.length > 0) {\n console.log(\n `[db] Applying ${pending.length} migration(s) on ${pg ? \"Postgres\" : \"SQLite/libsql\"}…`,\n );\n }\n\n for (const m of pending) {\n const raw = resolveMigrationSql(m.sql, pg);\n const label = m.name\n ? `\"${m.name}\" (v${m.version})`\n : `v${m.version}`;\n\n // Record BOTH the named row (always, when named) and the legacy\n // version row (only if this migration actually advances the legacy\n // MAX) — atomically with the DDL below. This keeps the legacy gate\n // monotonic for any unnamed migrations later in the list, while a\n // named migration is tracked by name regardless of version.\n const recordSql: Array<{ sql: string; args: unknown[] }> = [];\n if (m.name) {\n recordSql.push({\n sql: insertNamedSql,\n args: [m.name, m.version],\n });\n }\n if (m.version > current) {\n recordSql.push({ sql: insertVersionSql, args: [m.version] });\n }\n\n if (raw == null) {\n // Dialect-gated migration with no SQL for this dialect; still mark\n // as applied so we don't retry forever.\n for (const stmt of recordSql) await exec.execute(stmt);\n if (m.version > current) current = m.version;\n if (m.name) appliedNames.add(m.name);\n continue;\n }\n // Split BEFORE adapting so we can remember which original statements\n // carried `ADD COLUMN IF NOT EXISTS` — SQLite drops the clause, so we\n // emulate the idempotent semantic by swallowing duplicate-column\n // errors only for those statements.\n const originalStatements = splitSqlStatements(raw);\n const statements = originalStatements.map((orig) => ({\n sql: pg ? adaptSqlForPostgres(orig) : adaptSqlForSqlite(orig),\n hadIfNotExists: IF_NOT_EXISTS_ADD_COLUMN_RE.test(orig),\n }));\n let currentStmt = \"\";\n try {\n for (const { sql: stmt, hadIfNotExists } of statements) {\n currentStmt = stmt;\n try {\n await exec.execute(stmt);\n } catch (err) {\n if (!pg && hadIfNotExists && isDuplicateColumnError(err)) {\n // IF NOT EXISTS semantic: column already present, skip.\n continue;\n }\n throw err;\n }\n }\n for (const stmt of recordSql) await exec.execute(stmt);\n if (m.version > current) current = m.version;\n if (m.name) appliedNames.add(m.name);\n console.log(\n `[db] Applied migration ${label} (${statements.length} statement${statements.length === 1 ? \"\" : \"s\"})`,\n );\n } catch (err) {\n if (pg && isPermissionError(err)) {\n // The connected role lacks privilege for this migration (e.g. a\n // permission-limited dev/replica role that doesn't own the table).\n // Don't crash-loop the whole server over it — warn and STOP here.\n // We must NOT continue to later migrations: unnamed pending work is\n // computed as `version > MAX(recorded version)`, so applying a later\n // unnamed migration would advance MAX past this unrecorded one and\n // orphan it forever. Stopping leaves MAX at the last recorded\n // version, so a properly-privileged role resumes from this exact\n // migration, in order. (A named migration skipped here simply\n // isn't recorded by name either, so it's retried next boot same as\n // the legacy gate — no orphaning risk from name-based tracking.)\n console.warn(\n `[db] Migration ${label} skipped — insufficient privilege: ${(err as Error).message}. ` +\n `Apply it with a DB role that owns the table. ` +\n `Halting further migrations so this one isn't orphaned. ` +\n `Set <APP_NAME>_DATABASE_URL (e.g. PLAN_DATABASE_URL) to a database this app owns — a file: URL uses local SQLite.`,\n \"\\nStatement:\",\n currentStmt,\n );\n break;\n }\n console.error(\n `[db] Migration ${label} FAILED:`,\n (err as Error).message,\n \"\\nStatement:\",\n currentStmt,\n );\n throw err;\n }\n }\n } finally {\n // Release the direct-endpoint exec (Postgres only). For SQLite getDbExec()\n // returns the process-lifetime singleton, so releaseMigrationExec is a no-op\n // (refCount never incremented for SQLite path, guard in releaseMigrationExec).\n if (pg) await releaseMigrationExec();\n }\n } catch (err) {\n console.error(\"[db] Migration failed:\", (err as Error).message);\n // In local dev, hard-fail so the developer catches errors immediately.\n // On serverless runtimes (Netlify Functions, Vercel, CF Workers) we\n // keep the process alive — the app will return 500s for routes that\n // depend on the missing tables, but at least other routes still work.\n // Note: Node.js 21+ defines globalThis.navigator, so we check for\n // serverless env vars instead of navigator presence.\n const isServerless =\n !!globalThis.process?.env?.NETLIFY ||\n !!globalThis.process?.env?.AWS_LAMBDA_FUNCTION_NAME ||\n !!globalThis.process?.env?.VERCEL ||\n \"__cf_env\" in globalThis ||\n \"__env__\" in globalThis;\n if (typeof globalThis.process?.exit === \"function\" && !isServerless) {\n process.exit(1);\n }\n }\n };\n}\n"]}
|
package/dist/deploy/build.d.ts
CHANGED
|
@@ -9,11 +9,18 @@
|
|
|
9
9
|
*
|
|
10
10
|
* Supported presets:
|
|
11
11
|
* - cloudflare_pages: Outputs dist/ with _worker.js for Cloudflare Pages
|
|
12
|
+
* - cloudflare_module: Outputs a native Cloudflare Worker under .output/server
|
|
12
13
|
*
|
|
13
14
|
* Usage: node deploy/build.js (called automatically by `agent-native build`)
|
|
14
15
|
*/
|
|
15
16
|
import { type DiscoveredRoute, type DiscoveredAction } from "./route-discovery.js";
|
|
16
17
|
import { type WorkspaceCoreExports } from "./workspace-core.js";
|
|
18
|
+
export declare const CLOUDFLARE_MODULE_PRESETS: readonly ["cloudflare_module", "cloudflare-module"];
|
|
19
|
+
export declare function isCloudflareModulePreset(targetPreset: string): boolean;
|
|
20
|
+
export declare const CLOUDFLARE_MODULE_WORKER_ENTRY = "worker.mjs";
|
|
21
|
+
export declare function generateCloudflareModuleWorkerEntry(): string;
|
|
22
|
+
export declare function patchCloudflareModuleNitroEntry(code: string): string;
|
|
23
|
+
export declare function configureCloudflareModuleWorkerOutput(serverDir: string): void;
|
|
17
24
|
export declare const NITRO_RUNTIME_IGNORE_PATTERNS: string[];
|
|
18
25
|
export declare const CLOUDFLARE_WORKER_ESBUILD_EXTERNALS: string[];
|
|
19
26
|
export declare const CLOUDFLARE_WORKER_STUB_MODULES: Record<string, string>;
|
|
@@ -228,6 +235,24 @@ export interface NitroBuildPipelineOptions {
|
|
|
228
235
|
* anything with a file extension.
|
|
229
236
|
*/
|
|
230
237
|
export declare function runNitroBuildPipeline(opts: NitroBuildPipelineOptions): Promise<void>;
|
|
238
|
+
/**
|
|
239
|
+
* Packages that Nitro can discover through the shared server graph but that
|
|
240
|
+
* cannot be evaluated in a Cloudflare Worker. Keep the network-capable SDKs
|
|
241
|
+
* real; these are limited to Node/native/browser-runtime packages whose
|
|
242
|
+
* server-side paths already fail closed when the capability is unavailable.
|
|
243
|
+
*/
|
|
244
|
+
export declare const CLOUDFLARE_MODULE_STUB_MODULES: readonly ["@napi-rs/canvas", "@resvg/resvg-js", "@sentry/node", "@sparticuz/chromium-min", "better-sqlite3", "chartjs-node-canvas", "chokidar", "fsevents", "node-pty", "playwright", "playwright-core"];
|
|
245
|
+
/**
|
|
246
|
+
* Mirror the fail-closed package stubs used by the Pages bundler in Nitro's
|
|
247
|
+
* Rolldown graph. Without this, the native module preset emits a valid module
|
|
248
|
+
* graph that still crashes at Worker cold start when a Node-only optional
|
|
249
|
+
* dependency is evaluated.
|
|
250
|
+
*/
|
|
251
|
+
export declare function createCloudflareModuleStubPlugin(): {
|
|
252
|
+
name: string;
|
|
253
|
+
resolveId(id: string): string;
|
|
254
|
+
load(id: string): string;
|
|
255
|
+
};
|
|
231
256
|
/**
|
|
232
257
|
* Dependencies Nitro itself must bundle outside the controlled serverless
|
|
233
258
|
* output pass. Netlify, Vercel, and Lambda keep Yjs external through Nitro;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/deploy/build.ts"],"names":[],"mappings":";AAEA
|
|
1
|
+
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/deploy/build.ts"],"names":[],"mappings":"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"}
|
package/dist/deploy/build.js
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
*
|
|
10
10
|
* Supported presets:
|
|
11
11
|
* - cloudflare_pages: Outputs dist/ with _worker.js for Cloudflare Pages
|
|
12
|
+
* - cloudflare_module: Outputs a native Cloudflare Worker under .output/server
|
|
12
13
|
*
|
|
13
14
|
* Usage: node deploy/build.js (called automatically by `agent-native build`)
|
|
14
15
|
*/
|
|
@@ -29,6 +30,113 @@ import { discoverApiRoutes, discoverPlugins, discoverActionFiles, getMissingDefa
|
|
|
29
30
|
import { getWorkspaceCoreExports, } from "./workspace-core.js";
|
|
30
31
|
const cwd = process.cwd();
|
|
31
32
|
const preset = process.env.NITRO_PRESET || "node";
|
|
33
|
+
export const CLOUDFLARE_MODULE_PRESETS = [
|
|
34
|
+
"cloudflare_module",
|
|
35
|
+
"cloudflare-module",
|
|
36
|
+
];
|
|
37
|
+
export function isCloudflareModulePreset(targetPreset) {
|
|
38
|
+
return CLOUDFLARE_MODULE_PRESETS.includes(targetPreset);
|
|
39
|
+
}
|
|
40
|
+
export const CLOUDFLARE_MODULE_WORKER_ENTRY = "worker.mjs";
|
|
41
|
+
export function generateCloudflareModuleWorkerEntry() {
|
|
42
|
+
return `let handler;
|
|
43
|
+
|
|
44
|
+
export * from "./index.mjs";
|
|
45
|
+
|
|
46
|
+
async function loadHandler() {
|
|
47
|
+
handler ??= (await import("./index.mjs")).default;
|
|
48
|
+
return handler;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function initializeBindings(env) {
|
|
52
|
+
if (!env) return;
|
|
53
|
+
globalThis.__cf_env = env;
|
|
54
|
+
globalThis.__env__ = env;
|
|
55
|
+
globalThis.process = globalThis.process || { env: {} };
|
|
56
|
+
globalThis.process.env = globalThis.process.env || {};
|
|
57
|
+
for (const [key, value] of Object.entries(env)) {
|
|
58
|
+
if (typeof value === "string") globalThis.process.env[key] = value;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export default {
|
|
63
|
+
async fetch(request, env, ctx) {
|
|
64
|
+
if (typeof ctx?.waitUntil === "function") {
|
|
65
|
+
request.waitUntil = ctx.waitUntil.bind(ctx);
|
|
66
|
+
}
|
|
67
|
+
initializeBindings(env);
|
|
68
|
+
return (await loadHandler()).fetch(request, env, ctx);
|
|
69
|
+
},
|
|
70
|
+
async scheduled(controller, env, ctx) {
|
|
71
|
+
initializeBindings(env);
|
|
72
|
+
return (await loadHandler()).scheduled?.(controller, env, ctx);
|
|
73
|
+
},
|
|
74
|
+
async email(message, env, ctx) {
|
|
75
|
+
initializeBindings(env);
|
|
76
|
+
return (await loadHandler()).email?.(message, env, ctx);
|
|
77
|
+
},
|
|
78
|
+
async queue(batch, env, ctx) {
|
|
79
|
+
initializeBindings(env);
|
|
80
|
+
return (await loadHandler()).queue?.(batch, env, ctx);
|
|
81
|
+
},
|
|
82
|
+
async tail(traces, env, ctx) {
|
|
83
|
+
initializeBindings(env);
|
|
84
|
+
return (await loadHandler()).tail?.(traces, env, ctx);
|
|
85
|
+
},
|
|
86
|
+
async trace(traces, env, ctx) {
|
|
87
|
+
initializeBindings(env);
|
|
88
|
+
return (await loadHandler()).trace?.(traces, env, ctx);
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
`;
|
|
92
|
+
}
|
|
93
|
+
export function patchCloudflareModuleNitroEntry(code) {
|
|
94
|
+
const factoryMatch = code.match(/function ([A-Za-z_$][\w$]*)\(e\)\{let ([A-Za-z_$][\w$]*)=([A-Za-z_$][\w$]*)\(\),([A-Za-z_$][\w$]*)=([A-Za-z_$][\w$]*)\(\);return\{async fetch\(([A-Za-z_$][\w$]*),([A-Za-z_$][\w$]*),([A-Za-z_$][\w$]*)\)\{/);
|
|
95
|
+
if (!factoryMatch) {
|
|
96
|
+
throw new Error("[deploy] Could not find Nitro's Cloudflare module handler factory");
|
|
97
|
+
}
|
|
98
|
+
const [, factoryName, handlerName, handlerFactoryName, hooksName, hooksFactoryName, requestName, envName, contextName,] = factoryMatch;
|
|
99
|
+
const eagerInitialization = `let ${handlerName}=${handlerFactoryName}(),${hooksName}=${hooksFactoryName}();`;
|
|
100
|
+
if (!code.includes(eagerInitialization)) {
|
|
101
|
+
throw new Error(`[deploy] Nitro's ${factoryName} handler changed its initialization shape`);
|
|
102
|
+
}
|
|
103
|
+
const bindingMatch = code.match(new RegExp(`globalThis\\.__env__=${envName},([A-Za-z_$][\\w$]*)\\(${requestName},\\{env:${envName},context:${contextName}\\}\\);?`));
|
|
104
|
+
if (!bindingMatch) {
|
|
105
|
+
throw new Error(`[deploy] Nitro's ${factoryName} handler does not initialize Cloudflare bindings as expected`);
|
|
106
|
+
}
|
|
107
|
+
const bindingInitialization = bindingMatch[0];
|
|
108
|
+
let patched = code.replace(eagerInitialization, `let ${handlerName},${hooksName};`);
|
|
109
|
+
patched = patched.replace(bindingInitialization, `${bindingInitialization}${handlerName}??=${handlerFactoryName}();`);
|
|
110
|
+
const hookCall = `${hooksName}.callHook(`;
|
|
111
|
+
if (!patched.includes(hookCall)) {
|
|
112
|
+
throw new Error(`[deploy] Nitro's ${factoryName} handler has no Cloudflare lifecycle hooks`);
|
|
113
|
+
}
|
|
114
|
+
patched = patched
|
|
115
|
+
.split(hookCall)
|
|
116
|
+
.join(`(${hooksName}??=${hooksFactoryName}()).callHook(`);
|
|
117
|
+
return patched;
|
|
118
|
+
}
|
|
119
|
+
export function configureCloudflareModuleWorkerOutput(serverDir) {
|
|
120
|
+
const configPath = path.join(serverDir, "wrangler.json");
|
|
121
|
+
if (!fs.existsSync(configPath)) {
|
|
122
|
+
throw new Error(`[deploy] Nitro did not generate ${configPath} for cloudflare_module`);
|
|
123
|
+
}
|
|
124
|
+
const nitroEntryPath = path.join(serverDir, "index.mjs");
|
|
125
|
+
if (!fs.existsSync(nitroEntryPath)) {
|
|
126
|
+
throw new Error(`[deploy] Nitro did not generate ${nitroEntryPath} for cloudflare_module`);
|
|
127
|
+
}
|
|
128
|
+
const config = JSON.parse(fs.readFileSync(configPath, "utf8"));
|
|
129
|
+
config.main = CLOUDFLARE_MODULE_WORKER_ENTRY;
|
|
130
|
+
const compatibilityFlags = Array.isArray(config.compatibility_flags)
|
|
131
|
+
? config.compatibility_flags.filter((flag) => typeof flag === "string")
|
|
132
|
+
: [];
|
|
133
|
+
config.compatibility_flags = [
|
|
134
|
+
...new Set([...compatibilityFlags, "nodejs_compat"]),
|
|
135
|
+
];
|
|
136
|
+
fs.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`);
|
|
137
|
+
fs.writeFileSync(nitroEntryPath, patchCloudflareModuleNitroEntry(fs.readFileSync(nitroEntryPath, "utf8")));
|
|
138
|
+
fs.writeFileSync(path.join(serverDir, CLOUDFLARE_MODULE_WORKER_ENTRY), generateCloudflareModuleWorkerEntry());
|
|
139
|
+
}
|
|
32
140
|
export const NITRO_RUNTIME_IGNORE_PATTERNS = [
|
|
33
141
|
"**/*.spec.ts",
|
|
34
142
|
"**/*.spec.tsx",
|
|
@@ -707,7 +815,9 @@ function requestWithMountedApiPrefixStripped(request) {
|
|
|
707
815
|
return request;
|
|
708
816
|
}
|
|
709
817
|
url.pathname = strippedPathname;
|
|
710
|
-
|
|
818
|
+
const rewritten = new Request(url, request);
|
|
819
|
+
rewritten.waitUntil = request.waitUntil;
|
|
820
|
+
return rewritten;
|
|
711
821
|
}
|
|
712
822
|
|
|
713
823
|
function prefixMountedPath(path, basePath) {
|
|
@@ -1145,8 +1255,10 @@ ${includeReactRouterSsr
|
|
|
1145
1255
|
|
|
1146
1256
|
export default {
|
|
1147
1257
|
async fetch(request, env, ctx) {
|
|
1148
|
-
//
|
|
1149
|
-
if (ctx
|
|
1258
|
+
// Attach the request-scoped continuation hook before any URL rewrite.
|
|
1259
|
+
if (typeof ctx?.waitUntil === "function") {
|
|
1260
|
+
request.waitUntil = ctx.waitUntil.bind(ctx);
|
|
1261
|
+
}
|
|
1150
1262
|
if (env) {
|
|
1151
1263
|
globalThis.process = globalThis.process || { env: {} };
|
|
1152
1264
|
globalThis.process.env = globalThis.process.env || {};
|
|
@@ -2440,6 +2552,19 @@ export function bundleYjsRuntimeForServerlessOutput(serverDir, projectCwd) {
|
|
|
2440
2552
|
const source = fs.readFileSync(filePath, "utf-8");
|
|
2441
2553
|
fs.writeFileSync(filePath, source.replace(/(\b(?:from\s*|import\s*\(\s*|import\s*))(["'])yjs\2/g, (_match, importPrefix, quote) => `${importPrefix}${quote}${relativeBundledImport}${quote}`));
|
|
2442
2554
|
}
|
|
2555
|
+
walkServerJavaScriptFiles(serverDir, (filePath) => {
|
|
2556
|
+
const bundledImport = path
|
|
2557
|
+
.relative(path.dirname(filePath), bundledYjsPath)
|
|
2558
|
+
.split(path.sep)
|
|
2559
|
+
.join("/");
|
|
2560
|
+
const relativeBundledImport = bundledImport.startsWith(".")
|
|
2561
|
+
? bundledImport
|
|
2562
|
+
: `./${bundledImport}`;
|
|
2563
|
+
const source = fs.readFileSync(filePath, "utf-8");
|
|
2564
|
+
const rewritten = source.replace(/(\b(?:from\s*|import\s*\(\s*|import\s*))(["'])\.\.?\/(?:\.\.\/)*_libs\/yjs\.mjs\2/g, (_match, importPrefix, quote) => `${importPrefix}${quote}${relativeBundledImport}${quote}`);
|
|
2565
|
+
if (rewritten !== source)
|
|
2566
|
+
fs.writeFileSync(filePath, rewritten);
|
|
2567
|
+
});
|
|
2443
2568
|
return bareImports;
|
|
2444
2569
|
}
|
|
2445
2570
|
export function assertSingleTemplateNetlifyBuildOutput(projectCwd) {
|
|
@@ -2916,6 +3041,52 @@ const BROWSER_ONLY_SERVER_LIBS = [
|
|
|
2916
3041
|
"@excalidraw/mermaid-to-excalidraw",
|
|
2917
3042
|
"mermaid",
|
|
2918
3043
|
];
|
|
3044
|
+
/**
|
|
3045
|
+
* Packages that Nitro can discover through the shared server graph but that
|
|
3046
|
+
* cannot be evaluated in a Cloudflare Worker. Keep the network-capable SDKs
|
|
3047
|
+
* real; these are limited to Node/native/browser-runtime packages whose
|
|
3048
|
+
* server-side paths already fail closed when the capability is unavailable.
|
|
3049
|
+
*/
|
|
3050
|
+
export const CLOUDFLARE_MODULE_STUB_MODULES = [
|
|
3051
|
+
"@napi-rs/canvas",
|
|
3052
|
+
"@resvg/resvg-js",
|
|
3053
|
+
"@sentry/node",
|
|
3054
|
+
"@sparticuz/chromium-min",
|
|
3055
|
+
"better-sqlite3",
|
|
3056
|
+
"chartjs-node-canvas",
|
|
3057
|
+
"chokidar",
|
|
3058
|
+
"fsevents",
|
|
3059
|
+
"node-pty",
|
|
3060
|
+
"playwright",
|
|
3061
|
+
"playwright-core",
|
|
3062
|
+
];
|
|
3063
|
+
/**
|
|
3064
|
+
* Mirror the fail-closed package stubs used by the Pages bundler in Nitro's
|
|
3065
|
+
* Rolldown graph. Without this, the native module preset emits a valid module
|
|
3066
|
+
* graph that still crashes at Worker cold start when a Node-only optional
|
|
3067
|
+
* dependency is evaluated.
|
|
3068
|
+
*/
|
|
3069
|
+
export function createCloudflareModuleStubPlugin() {
|
|
3070
|
+
const stubbed = new Set(CLOUDFLARE_MODULE_STUB_MODULES);
|
|
3071
|
+
const stubIdPrefix = "\0agent-native-cloudflare-module-stub:";
|
|
3072
|
+
return {
|
|
3073
|
+
name: "agent-native-cloudflare-module-stub",
|
|
3074
|
+
resolveId(id) {
|
|
3075
|
+
const packageName = id.startsWith("@")
|
|
3076
|
+
? id.split("/").slice(0, 2).join("/")
|
|
3077
|
+
: id.split("/")[0];
|
|
3078
|
+
if (!stubbed.has(packageName) || id !== packageName)
|
|
3079
|
+
return null;
|
|
3080
|
+
return `${stubIdPrefix}${packageName}`;
|
|
3081
|
+
},
|
|
3082
|
+
load(id) {
|
|
3083
|
+
if (!id.startsWith(stubIdPrefix))
|
|
3084
|
+
return null;
|
|
3085
|
+
const packageName = id.slice(stubIdPrefix.length);
|
|
3086
|
+
return CLOUDFLARE_WORKER_STUB_MODULES[packageName] ?? null;
|
|
3087
|
+
},
|
|
3088
|
+
};
|
|
3089
|
+
}
|
|
2919
3090
|
/**
|
|
2920
3091
|
* Dependencies Nitro itself must bundle outside the controlled serverless
|
|
2921
3092
|
* output pass. Netlify, Vercel, and Lambda keep Yjs external through Nitro;
|
|
@@ -3100,7 +3271,12 @@ export default bundle;
|
|
|
3100
3271
|
...(preset === "netlify" || preset === "vercel" || preset === "aws-lambda"
|
|
3101
3272
|
? { external: ["yjs"] }
|
|
3102
3273
|
: {}),
|
|
3103
|
-
plugins: [
|
|
3274
|
+
plugins: [
|
|
3275
|
+
...(preset.startsWith("cloudflare")
|
|
3276
|
+
? [createCloudflareModuleStubPlugin()]
|
|
3277
|
+
: []),
|
|
3278
|
+
createBrowserOnlyServerStubPlugin(),
|
|
3279
|
+
],
|
|
3104
3280
|
},
|
|
3105
3281
|
...(providedPluginsNitroPlugin
|
|
3106
3282
|
? { plugins: [providedPluginsNitroPlugin] }
|
|
@@ -3120,6 +3296,9 @@ export default bundle;
|
|
|
3120
3296
|
appBasePath,
|
|
3121
3297
|
cwd,
|
|
3122
3298
|
});
|
|
3299
|
+
if (isCloudflareModulePreset(preset)) {
|
|
3300
|
+
configureCloudflareModuleWorkerOutput(nitro.options.output.serverDir);
|
|
3301
|
+
}
|
|
3123
3302
|
if (preset === "netlify" || preset === "vercel" || preset === "aws-lambda") {
|
|
3124
3303
|
copyInstalledLibsqlNativePackages(nitro.options.output.serverDir);
|
|
3125
3304
|
copyInstalledResvgPackages(nitro.options.output.serverDir);
|
|
@@ -3127,6 +3306,9 @@ export default bundle;
|
|
|
3127
3306
|
sanitizeServerlessFunctionPackageManifest(nitro.options.output.serverDir);
|
|
3128
3307
|
bundleYjsRuntimeForServerlessOutput(nitro.options.output.serverDir, cwd);
|
|
3129
3308
|
}
|
|
3309
|
+
if (isCloudflareModulePreset(preset)) {
|
|
3310
|
+
bundleYjsRuntimeForServerlessOutput(nitro.options.output.serverDir, cwd);
|
|
3311
|
+
}
|
|
3130
3312
|
if (preset === "netlify") {
|
|
3131
3313
|
emitSingleTemplateNetlifyKeepWarmFunction(cwd);
|
|
3132
3314
|
// Durable background agent runs (default-OFF / opt-in; enable with a truthy
|
|
@@ -3231,8 +3413,45 @@ export default bundle;
|
|
|
3231
3413
|
if (bareImports.size > 0) {
|
|
3232
3414
|
const libsDir = path.join(outputDir, "_libs");
|
|
3233
3415
|
fs.mkdirSync(libsDir, { recursive: true });
|
|
3416
|
+
function rewriteExternalImports(mod, outFile) {
|
|
3417
|
+
function rewriteImports(dir) {
|
|
3418
|
+
if (!fs.existsSync(dir))
|
|
3419
|
+
return;
|
|
3420
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
3421
|
+
const p = path.join(dir, entry.name);
|
|
3422
|
+
if (entry.isDirectory()) {
|
|
3423
|
+
rewriteImports(p);
|
|
3424
|
+
continue;
|
|
3425
|
+
}
|
|
3426
|
+
if (!entry.name.endsWith(".mjs") && !entry.name.endsWith(".js"))
|
|
3427
|
+
continue;
|
|
3428
|
+
const code = fs.readFileSync(p, "utf8");
|
|
3429
|
+
const relPath = path
|
|
3430
|
+
.relative(path.dirname(p), outFile)
|
|
3431
|
+
.replace(/\\/g, "/");
|
|
3432
|
+
const importPath = relPath.startsWith(".")
|
|
3433
|
+
? relPath
|
|
3434
|
+
: "./" + relPath;
|
|
3435
|
+
const escaped = mod.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3436
|
+
const re = new RegExp(`from["']${escaped}["']`, "g");
|
|
3437
|
+
const rewritten = code.replace(re, `from"${importPath}"`);
|
|
3438
|
+
if (rewritten !== code)
|
|
3439
|
+
fs.writeFileSync(p, rewritten);
|
|
3440
|
+
}
|
|
3441
|
+
}
|
|
3442
|
+
rewriteImports(outputDir);
|
|
3443
|
+
}
|
|
3234
3444
|
for (const mod of bareImports) {
|
|
3235
3445
|
const outFile = path.join(libsDir, `${mod.replace(/[/@]/g, "_")}.mjs`);
|
|
3446
|
+
// Nitro may already have emitted a correctly minified module wrapper
|
|
3447
|
+
// for this dependency. Replacing that wrapper with an esbuild CJS
|
|
3448
|
+
// adapter loses its public export aliases and makes otherwise valid
|
|
3449
|
+
// sibling chunks fail during Worker module linking.
|
|
3450
|
+
if (fs.existsSync(outFile)) {
|
|
3451
|
+
console.log(`[deploy] Retaining Nitro external: ${mod}`);
|
|
3452
|
+
rewriteExternalImports(mod, outFile);
|
|
3453
|
+
continue;
|
|
3454
|
+
}
|
|
3236
3455
|
try {
|
|
3237
3456
|
// Resolve the module — check workspace node_modules and pnpm store
|
|
3238
3457
|
let resolvedMod = mod;
|
|
@@ -3491,6 +3710,10 @@ async function main() {
|
|
|
3491
3710
|
// as multi-module Workers. Use the custom esbuild-based bundler.
|
|
3492
3711
|
await buildCloudflarePages();
|
|
3493
3712
|
break;
|
|
3713
|
+
case "cloudflare_module":
|
|
3714
|
+
case "cloudflare-module":
|
|
3715
|
+
await buildWithNitro();
|
|
3716
|
+
break;
|
|
3494
3717
|
default:
|
|
3495
3718
|
// All other presets (netlify, vercel, deno_deploy, aws-lambda, etc.)
|
|
3496
3719
|
// are handled natively by Nitro's build API.
|