@agent-native/core 0.79.11 → 0.79.15
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/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +25 -0
- package/corpus/core/docs/content/locales/zh-TW/a2a-protocol.md +68 -68
- package/corpus/core/docs/content/locales/zh-TW/actions.md +82 -82
- package/corpus/core/docs/content/locales/zh-TW/agent-mentions.md +22 -22
- package/corpus/core/docs/content/locales/zh-TW/agent-surfaces.md +82 -82
- package/corpus/core/docs/content/locales/zh-TW/agent-teams.md +29 -29
- package/corpus/core/docs/content/locales/zh-TW/agent-web-surfaces.md +11 -11
- package/corpus/core/docs/content/locales/zh-TW/audit-log.md +16 -16
- package/corpus/core/docs/content/locales/zh-TW/authentication.md +32 -32
- package/corpus/core/docs/content/locales/zh-TW/automations.md +32 -32
- package/corpus/core/docs/content/locales/zh-TW/blueprint-installer.md +19 -19
- package/corpus/core/docs/content/locales/zh-TW/cli-adapters.md +17 -17
- package/corpus/core/docs/content/locales/zh-TW/client.md +62 -62
- package/corpus/core/docs/content/locales/zh-TW/cloneable-saas.md +32 -32
- package/corpus/core/docs/content/locales/zh-TW/code-agents-ui.md +91 -91
- package/corpus/core/docs/content/locales/zh-TW/components.md +51 -51
- package/corpus/core/docs/content/locales/zh-TW/context-awareness.md +66 -66
- package/corpus/core/docs/content/locales/zh-TW/creating-templates.md +39 -39
- package/corpus/core/docs/content/locales/zh-TW/cross-app-sso.md +29 -29
- package/corpus/core/docs/content/locales/zh-TW/database.md +21 -21
- package/corpus/core/docs/content/locales/zh-TW/deployment.md +37 -37
- package/corpus/core/docs/content/locales/zh-TW/dispatch.md +43 -43
- package/corpus/core/docs/content/locales/zh-TW/drop-in-agent.md +34 -34
- package/corpus/core/docs/content/locales/zh-TW/durable-resume.md +18 -18
- package/corpus/core/docs/content/locales/zh-TW/embedding-sdk.md +73 -73
- package/corpus/core/docs/content/locales/zh-TW/evals.md +16 -16
- package/corpus/core/docs/content/locales/zh-TW/extensions.md +81 -81
- package/corpus/core/docs/content/locales/zh-TW/external-agents.md +146 -146
- package/corpus/core/docs/content/locales/zh-TW/faq.md +43 -43
- package/corpus/core/docs/content/locales/zh-TW/file-uploads.md +11 -11
- package/corpus/core/docs/content/locales/zh-TW/frames.md +33 -33
- package/corpus/core/docs/content/locales/zh-TW/getting-started.md +28 -28
- package/corpus/core/docs/content/locales/zh-TW/harness-agents.md +78 -78
- package/corpus/core/docs/content/locales/zh-TW/human-approval.md +27 -27
- package/corpus/core/docs/content/locales/zh-TW/internationalization.md +19 -19
- package/corpus/core/docs/content/locales/zh-TW/key-concepts.md +68 -68
- package/corpus/core/docs/content/locales/zh-TW/local-file-mode.md +50 -50
- package/corpus/core/docs/content/locales/zh-TW/mcp-apps.md +38 -38
- package/corpus/core/docs/content/locales/zh-TW/mcp-clients.md +67 -67
- package/corpus/core/docs/content/locales/zh-TW/mcp-protocol.md +50 -50
- package/corpus/core/docs/content/locales/zh-TW/messaging.md +99 -99
- package/corpus/core/docs/content/locales/zh-TW/migration-workbench.md +6 -6
- package/corpus/core/docs/content/locales/zh-TW/multi-app-workspace.md +39 -39
- package/corpus/core/docs/content/locales/zh-TW/multi-tenancy.md +7 -7
- package/corpus/core/docs/content/locales/zh-TW/native-chat-ui.md +38 -38
- package/corpus/core/docs/content/locales/zh-TW/notifications.md +23 -23
- package/corpus/core/docs/content/locales/zh-TW/observability.md +49 -49
- package/corpus/core/docs/content/locales/zh-TW/observational-memory.md +23 -23
- package/corpus/core/docs/content/locales/zh-TW/onboarding.md +40 -40
- package/corpus/core/docs/content/locales/zh-TW/plan-plugin.md +37 -37
- package/corpus/core/docs/content/locales/zh-TW/pr-visual-recap.md +72 -72
- package/corpus/core/docs/content/locales/zh-TW/processors.md +17 -17
- package/corpus/core/docs/content/locales/zh-TW/progress.md +15 -15
- package/corpus/core/docs/content/locales/zh-TW/pure-agent-apps.md +10 -10
- package/corpus/core/docs/content/locales/zh-TW/real-time-collaboration.md +103 -103
- package/corpus/core/docs/content/locales/zh-TW/recurring-jobs.md +19 -19
- package/corpus/core/docs/content/locales/zh-TW/routing.md +9 -9
- package/corpus/core/docs/content/locales/zh-TW/sandbox-adapters.md +48 -48
- package/corpus/core/docs/content/locales/zh-TW/security.md +49 -49
- package/corpus/core/docs/content/locales/zh-TW/server.md +47 -47
- package/corpus/core/docs/content/locales/zh-TW/sharing.md +22 -22
- package/corpus/core/docs/content/locales/zh-TW/skills-guide.md +46 -46
- package/corpus/core/docs/content/locales/zh-TW/template-analytics.md +40 -40
- package/corpus/core/docs/content/locales/zh-TW/template-assets.md +69 -69
- package/corpus/core/docs/content/locales/zh-TW/template-brain.md +81 -81
- package/corpus/core/docs/content/locales/zh-TW/template-calendar.md +40 -40
- package/corpus/core/docs/content/locales/zh-TW/template-chat.md +27 -27
- package/corpus/core/docs/content/locales/zh-TW/template-clips.md +85 -85
- package/corpus/core/docs/content/locales/zh-TW/template-content.md +65 -66
- package/corpus/core/docs/content/locales/zh-TW/template-design.md +29 -29
- package/corpus/core/docs/content/locales/zh-TW/template-dispatch.md +51 -51
- package/corpus/core/docs/content/locales/zh-TW/template-forms.md +25 -25
- package/corpus/core/docs/content/locales/zh-TW/template-mail.md +71 -71
- package/corpus/core/docs/content/locales/zh-TW/template-plan.md +92 -92
- package/corpus/core/docs/content/locales/zh-TW/template-slides.md +52 -52
- package/corpus/core/docs/content/locales/zh-TW/template-videos.md +30 -30
- package/corpus/core/docs/content/locales/zh-TW/tracking.md +29 -29
- package/corpus/core/docs/content/locales/zh-TW/using-your-agent.md +18 -18
- package/corpus/core/docs/content/locales/zh-TW/voice-input.md +19 -19
- package/corpus/core/docs/content/locales/zh-TW/what-is-agent-native.md +61 -61
- package/corpus/core/docs/content/locales/zh-TW/workspace-connections.md +41 -41
- package/corpus/core/docs/content/locales/zh-TW/workspace-management.md +27 -27
- package/corpus/core/docs/content/locales/zh-TW/workspace.md +58 -58
- package/corpus/core/docs/content/locales/zh-TW/writing-agent-instructions.md +41 -41
- package/corpus/core/docs/content/template-clips.md +48 -2
- package/corpus/core/package.json +2 -1
- package/corpus/core/src/client/AgentPanel.tsx +27 -3
- package/corpus/core/src/deploy/build.ts +738 -57
- package/corpus/core/src/deploy/route-discovery.ts +1 -1
- package/corpus/core/src/server/edge.ts +50 -0
- package/corpus/core/src/styles/agent-native.css +93 -0
- package/corpus/core/src/templates/default/app/i18n/zh-TW.ts +44 -44
- package/corpus/core/src/vite/client.ts +1 -0
- package/corpus/templates/analytics/app/components/layout/Layout.tsx +5 -3
- package/corpus/templates/analytics/app/i18n/zh-TW.ts +69 -70
- package/corpus/templates/analytics/changelog/2026-06-27-traditional-chinese-copy-uses-taiwan-terminology.md +6 -0
- package/corpus/templates/assets/app/components/layout/Layout.tsx +3 -3
- package/corpus/templates/assets/app/i18n/zh-TW.ts +82 -82
- package/corpus/templates/assets/changelog/2026-06-27-traditional-chinese-copy-uses-taiwan-terminology.md +6 -0
- package/corpus/templates/brain/app/components/layout/Layout.tsx +6 -4
- package/corpus/templates/brain/app/i18n/zh-TW.ts +90 -90
- package/corpus/templates/brain/changelog/2026-06-27-traditional-chinese-copy-uses-taiwan-terminology.md +6 -0
- package/corpus/templates/calendar/app/components/layout/AppLayout.tsx +1 -1
- package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +1 -1
- package/corpus/templates/calendar/app/i18n/zh-TW.ts +57 -57
- package/corpus/templates/calendar/changelog/2026-06-27-traditional-chinese-copy-uses-taiwan-terminology.md +6 -0
- package/corpus/templates/calendar/server/lib/booking-og-fonts.ts +20 -6
- package/corpus/templates/calendar/server/lib/booking-og-image.ts +17 -9
- package/corpus/templates/chat/app/components/layout/Layout.tsx +5 -3
- package/corpus/templates/chat/app/i18n/zh-TW.ts +3 -3
- package/corpus/templates/chat/changelog/2026-06-27-traditional-chinese-copy-uses-taiwan-terminology.md +6 -0
- package/corpus/templates/clips/AGENTS.md +6 -0
- package/corpus/templates/clips/actions/delete-recording-permanent.ts +7 -1
- package/corpus/templates/clips/actions/get-recording-player-data.ts +44 -2
- package/corpus/templates/clips/actions/navigate.ts +2 -0
- package/corpus/templates/clips/actions/save-bug-report-context.ts +173 -0
- package/corpus/templates/clips/actions/view-screen.ts +58 -7
- package/corpus/templates/clips/app/components/recorder/storage-setup-card.tsx +9 -3
- package/corpus/templates/clips/app/hooks/use-navigation-state.ts +17 -0
- package/corpus/templates/clips/app/i18n/ar-SA.ts +31 -0
- package/corpus/templates/clips/app/i18n/de-DE.ts +32 -0
- package/corpus/templates/clips/app/i18n/en-US.ts +32 -0
- package/corpus/templates/clips/app/i18n/es-ES.ts +32 -0
- package/corpus/templates/clips/app/i18n/fr-FR.ts +32 -0
- package/corpus/templates/clips/app/i18n/hi-IN.ts +32 -0
- package/corpus/templates/clips/app/i18n/ja-JP.ts +31 -0
- package/corpus/templates/clips/app/i18n/ko-KR.ts +32 -0
- package/corpus/templates/clips/app/i18n/pt-BR.ts +32 -0
- package/corpus/templates/clips/app/i18n/zh-CN.ts +30 -0
- package/corpus/templates/clips/app/i18n/zh-TW.ts +461 -451
- package/corpus/templates/clips/app/routes/bug-report.done.tsx +126 -0
- package/corpus/templates/clips/app/routes/bug-report.tsx +222 -0
- package/corpus/templates/clips/app/routes/record.tsx +104 -12
- package/corpus/templates/clips/changelog/2026-06-26-brief-network-blips-no-longer-block-recording-or-wrongly-pro.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-26-bug-report-recordings-can-keep-redacted-host-app-context-wit.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-26-bug-report-widgets-can-launch-clips-recordings-from-embedded.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-26-desktop-recording-keeps-connected-users-out-of-the-storage-s.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-26-if-a-recording-can-t-be-uploaded-the-chrome-extension-now-sa.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-27-traditional-chinese-copy-uses-taiwan-terminology.md +6 -0
- package/corpus/templates/clips/chrome-extension/public/manifest.json +9 -2
- package/corpus/templates/clips/chrome-extension/src/background.ts +43 -0
- package/corpus/templates/clips/chrome-extension/src/offscreen.ts +111 -6
- package/corpus/templates/clips/chrome-extension/src/popup.ts +18 -7
- package/corpus/templates/clips/desktop/src/app.tsx +53 -19
- package/corpus/templates/clips/server/db/schema.ts +26 -0
- package/corpus/templates/clips/server/lib/public-agent-context.ts +51 -0
- package/corpus/templates/clips/server/plugins/auth.ts +1 -0
- package/corpus/templates/clips/server/plugins/db.ts +28 -0
- package/corpus/templates/clips/server/routes/api/agent-context.json.get.ts +4 -1
- package/corpus/templates/clips/shared/bug-report.ts +161 -0
- package/corpus/templates/content/app/components/layout/Layout.tsx +10 -8
- package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +1 -1
- package/corpus/templates/content/app/i18n/zh-TW.ts +67 -66
- package/corpus/templates/content/changelog/2026-06-27-traditional-chinese-copy-uses-taiwan-terminology.md +6 -0
- package/corpus/templates/design/app/components/layout/Layout.tsx +3 -3
- package/corpus/templates/design/app/i18n/zh-TW.ts +44 -44
- package/corpus/templates/design/changelog/2026-06-27-traditional-chinese-copy-uses-taiwan-terminology.md +6 -0
- package/corpus/templates/dispatch/app/i18n/zh-TW.ts +5 -4
- package/corpus/templates/dispatch/changelog/2026-06-27-traditional-chinese-copy-uses-taiwan-terminology.md +6 -0
- package/corpus/templates/forms/app/components/layout/Layout.tsx +4 -2
- package/corpus/templates/forms/app/components/layout/Sidebar.tsx +1 -1
- package/corpus/templates/forms/app/i18n/zh-TW.ts +48 -48
- package/corpus/templates/forms/changelog/2026-06-27-traditional-chinese-copy-uses-taiwan-terminology.md +6 -0
- package/corpus/templates/macros/app/components/layout/AppLayout.tsx +3 -3
- package/corpus/templates/macros/app/i18n/zh-TW.ts +5 -5
- package/corpus/templates/macros/changelog/2026-06-27-traditional-chinese-copy-uses-taiwan-terminology.md +6 -0
- package/corpus/templates/mail/app/i18n/zh-TW.ts +83 -83
- package/corpus/templates/mail/changelog/2026-06-27-traditional-chinese-copy-uses-taiwan-terminology.md +6 -0
- package/corpus/templates/plan/app/components/layout/Layout.tsx +5 -3
- package/corpus/templates/plan/app/i18n/zh-TW.ts +69 -69
- package/corpus/templates/plan/changelog/2026-06-27-traditional-chinese-copy-uses-taiwan-terminology.md +6 -0
- package/corpus/templates/slides/app/components/layout/Layout.tsx +3 -3
- package/corpus/templates/slides/app/i18n/zh-TW.ts +64 -64
- package/corpus/templates/slides/changelog/2026-06-27-traditional-chinese-copy-uses-taiwan-terminology.md +6 -0
- package/corpus/templates/videos/app/components/layout/Layout.tsx +2 -2
- package/corpus/templates/videos/app/i18n/zh-TW.ts +54 -54
- package/corpus/templates/videos/changelog/2026-06-27-traditional-chinese-copy-uses-taiwan-terminology.md +6 -0
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +14 -4
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/deploy/build.d.ts +29 -2
- package/dist/deploy/build.d.ts.map +1 -1
- package/dist/deploy/build.js +587 -51
- package/dist/deploy/build.js.map +1 -1
- package/dist/deploy/route-discovery.d.ts +1 -1
- package/dist/deploy/route-discovery.js +1 -1
- package/dist/deploy/route-discovery.js.map +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +2 -2
- package/dist/notifications/routes.d.ts +2 -2
- package/dist/observability/routes.d.ts +7 -7
- package/dist/resources/handlers.d.ts +2 -2
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/edge.d.ts +11 -0
- package/dist/server/edge.d.ts.map +1 -0
- package/dist/server/edge.js +11 -0
- package/dist/server/edge.js.map +1 -0
- package/dist/styles/agent-native.css +93 -0
- package/dist/templates/default/app/i18n/zh-TW.ts +44 -44
- package/dist/vite/client.d.ts.map +1 -1
- package/dist/vite/client.js +1 -0
- package/dist/vite/client.js.map +1 -1
- package/docs/content/locales/zh-TW/a2a-protocol.md +68 -68
- package/docs/content/locales/zh-TW/actions.md +82 -82
- package/docs/content/locales/zh-TW/agent-mentions.md +22 -22
- package/docs/content/locales/zh-TW/agent-surfaces.md +82 -82
- package/docs/content/locales/zh-TW/agent-teams.md +29 -29
- package/docs/content/locales/zh-TW/agent-web-surfaces.md +11 -11
- package/docs/content/locales/zh-TW/audit-log.md +16 -16
- package/docs/content/locales/zh-TW/authentication.md +32 -32
- package/docs/content/locales/zh-TW/automations.md +32 -32
- package/docs/content/locales/zh-TW/blueprint-installer.md +19 -19
- package/docs/content/locales/zh-TW/cli-adapters.md +17 -17
- package/docs/content/locales/zh-TW/client.md +62 -62
- package/docs/content/locales/zh-TW/cloneable-saas.md +32 -32
- package/docs/content/locales/zh-TW/code-agents-ui.md +91 -91
- package/docs/content/locales/zh-TW/components.md +51 -51
- package/docs/content/locales/zh-TW/context-awareness.md +66 -66
- package/docs/content/locales/zh-TW/creating-templates.md +39 -39
- package/docs/content/locales/zh-TW/cross-app-sso.md +29 -29
- package/docs/content/locales/zh-TW/database.md +21 -21
- package/docs/content/locales/zh-TW/deployment.md +37 -37
- package/docs/content/locales/zh-TW/dispatch.md +43 -43
- package/docs/content/locales/zh-TW/drop-in-agent.md +34 -34
- package/docs/content/locales/zh-TW/durable-resume.md +18 -18
- package/docs/content/locales/zh-TW/embedding-sdk.md +73 -73
- package/docs/content/locales/zh-TW/evals.md +16 -16
- package/docs/content/locales/zh-TW/extensions.md +81 -81
- package/docs/content/locales/zh-TW/external-agents.md +146 -146
- package/docs/content/locales/zh-TW/faq.md +43 -43
- package/docs/content/locales/zh-TW/file-uploads.md +11 -11
- package/docs/content/locales/zh-TW/frames.md +33 -33
- package/docs/content/locales/zh-TW/getting-started.md +28 -28
- package/docs/content/locales/zh-TW/harness-agents.md +78 -78
- package/docs/content/locales/zh-TW/human-approval.md +27 -27
- package/docs/content/locales/zh-TW/internationalization.md +19 -19
- package/docs/content/locales/zh-TW/key-concepts.md +68 -68
- package/docs/content/locales/zh-TW/local-file-mode.md +50 -50
- package/docs/content/locales/zh-TW/mcp-apps.md +38 -38
- package/docs/content/locales/zh-TW/mcp-clients.md +67 -67
- package/docs/content/locales/zh-TW/mcp-protocol.md +50 -50
- package/docs/content/locales/zh-TW/messaging.md +99 -99
- package/docs/content/locales/zh-TW/migration-workbench.md +6 -6
- package/docs/content/locales/zh-TW/multi-app-workspace.md +39 -39
- package/docs/content/locales/zh-TW/multi-tenancy.md +7 -7
- package/docs/content/locales/zh-TW/native-chat-ui.md +38 -38
- package/docs/content/locales/zh-TW/notifications.md +23 -23
- package/docs/content/locales/zh-TW/observability.md +49 -49
- package/docs/content/locales/zh-TW/observational-memory.md +23 -23
- package/docs/content/locales/zh-TW/onboarding.md +40 -40
- package/docs/content/locales/zh-TW/plan-plugin.md +37 -37
- package/docs/content/locales/zh-TW/pr-visual-recap.md +72 -72
- package/docs/content/locales/zh-TW/processors.md +17 -17
- package/docs/content/locales/zh-TW/progress.md +15 -15
- package/docs/content/locales/zh-TW/pure-agent-apps.md +10 -10
- package/docs/content/locales/zh-TW/real-time-collaboration.md +103 -103
- package/docs/content/locales/zh-TW/recurring-jobs.md +19 -19
- package/docs/content/locales/zh-TW/routing.md +9 -9
- package/docs/content/locales/zh-TW/sandbox-adapters.md +48 -48
- package/docs/content/locales/zh-TW/security.md +49 -49
- package/docs/content/locales/zh-TW/server.md +47 -47
- package/docs/content/locales/zh-TW/sharing.md +22 -22
- package/docs/content/locales/zh-TW/skills-guide.md +46 -46
- package/docs/content/locales/zh-TW/template-analytics.md +40 -40
- package/docs/content/locales/zh-TW/template-assets.md +69 -69
- package/docs/content/locales/zh-TW/template-brain.md +81 -81
- package/docs/content/locales/zh-TW/template-calendar.md +40 -40
- package/docs/content/locales/zh-TW/template-chat.md +27 -27
- package/docs/content/locales/zh-TW/template-clips.md +85 -85
- package/docs/content/locales/zh-TW/template-content.md +65 -66
- package/docs/content/locales/zh-TW/template-design.md +29 -29
- package/docs/content/locales/zh-TW/template-dispatch.md +51 -51
- package/docs/content/locales/zh-TW/template-forms.md +25 -25
- package/docs/content/locales/zh-TW/template-mail.md +71 -71
- package/docs/content/locales/zh-TW/template-plan.md +92 -92
- package/docs/content/locales/zh-TW/template-slides.md +52 -52
- package/docs/content/locales/zh-TW/template-videos.md +30 -30
- package/docs/content/locales/zh-TW/tracking.md +29 -29
- package/docs/content/locales/zh-TW/using-your-agent.md +18 -18
- package/docs/content/locales/zh-TW/voice-input.md +19 -19
- package/docs/content/locales/zh-TW/what-is-agent-native.md +61 -61
- package/docs/content/locales/zh-TW/workspace-connections.md +41 -41
- package/docs/content/locales/zh-TW/workspace-management.md +27 -27
- package/docs/content/locales/zh-TW/workspace.md +58 -58
- package/docs/content/locales/zh-TW/writing-agent-instructions.md +41 -41
- package/docs/content/template-clips.md +48 -2
- package/package.json +2 -1
- package/src/templates/default/app/i18n/zh-TW.ts +44 -44
|
@@ -100,6 +100,391 @@ export const CLOUDFLARE_WORKER_ESBUILD_EXTERNALS = [
|
|
|
100
100
|
"@sparticuz/chromium-min",
|
|
101
101
|
"fsevents",
|
|
102
102
|
];
|
|
103
|
+
export const CLOUDFLARE_WORKER_STUB_MODULES: Record<string, string> = {
|
|
104
|
+
"better-sqlite3":
|
|
105
|
+
"export default {}; export const Database = class {}; export const watch = () => ({ close() {} });\n",
|
|
106
|
+
"node-pty":
|
|
107
|
+
"export default {}; export const watch = () => ({ close() {} });\n",
|
|
108
|
+
chokidar: "export default {}; export const watch = () => ({ close() {} });\n",
|
|
109
|
+
fsevents: "export default {}; export const watch = () => ({ close() {} });\n",
|
|
110
|
+
dotenv: "export default {}; export const config = () => ({ parsed: {} });\n",
|
|
111
|
+
"@anthropic-ai/sdk": "export default class Anthropic {}\n",
|
|
112
|
+
"@anthropic-ai/tokenizer":
|
|
113
|
+
"export default {}; export const countTokens = undefined;\n",
|
|
114
|
+
"@sentry/node": [
|
|
115
|
+
"export const init = () => {};",
|
|
116
|
+
"const scope = {",
|
|
117
|
+
" setUser() {},",
|
|
118
|
+
" setTag() {},",
|
|
119
|
+
" setExtra() {},",
|
|
120
|
+
" setContext() {},",
|
|
121
|
+
" setLevel() {},",
|
|
122
|
+
" getScopeData() { return {}; },",
|
|
123
|
+
"};",
|
|
124
|
+
"export const getIsolationScope = () => scope;",
|
|
125
|
+
"export const withScope = (fn) => fn(scope);",
|
|
126
|
+
"export const captureException = () => undefined;",
|
|
127
|
+
"export default { init, getIsolationScope, withScope, captureException };",
|
|
128
|
+
"",
|
|
129
|
+
].join("\n"),
|
|
130
|
+
"@resvg/resvg-js": [
|
|
131
|
+
"export class Resvg {",
|
|
132
|
+
' constructor() { throw new Error("@resvg/resvg-js unavailable in Cloudflare Pages worker"); }',
|
|
133
|
+
"}",
|
|
134
|
+
"export default { Resvg };",
|
|
135
|
+
"",
|
|
136
|
+
].join("\n"),
|
|
137
|
+
"playwright-core": [
|
|
138
|
+
"const unavailable = async () => { throw new Error('playwright-core unavailable in Cloudflare Pages worker'); };",
|
|
139
|
+
"export const chromium = { launch: unavailable };",
|
|
140
|
+
"export const firefox = { launch: unavailable };",
|
|
141
|
+
"export const webkit = { launch: unavailable };",
|
|
142
|
+
"export default { chromium, firefox, webkit };",
|
|
143
|
+
"",
|
|
144
|
+
].join("\n"),
|
|
145
|
+
"@sparticuz/chromium-min": [
|
|
146
|
+
"const chromium = {",
|
|
147
|
+
" args: [],",
|
|
148
|
+
" setGraphicsMode: false,",
|
|
149
|
+
" executablePath: async () => { throw new Error('@sparticuz/chromium-min unavailable in Cloudflare Pages worker'); },",
|
|
150
|
+
"};",
|
|
151
|
+
"export default chromium;",
|
|
152
|
+
"",
|
|
153
|
+
].join("\n"),
|
|
154
|
+
"@google/genai": [
|
|
155
|
+
"export class GoogleGenAI {",
|
|
156
|
+
" constructor() { throw new Error('@google/genai unavailable in Cloudflare Pages worker'); }",
|
|
157
|
+
"}",
|
|
158
|
+
"export default { GoogleGenAI };",
|
|
159
|
+
"",
|
|
160
|
+
].join("\n"),
|
|
161
|
+
"pdf-parse": [
|
|
162
|
+
"export class PDFParse {",
|
|
163
|
+
" constructor() { throw new Error('pdf-parse unavailable in Cloudflare Pages worker'); }",
|
|
164
|
+
"}",
|
|
165
|
+
"export default { PDFParse };",
|
|
166
|
+
"",
|
|
167
|
+
].join("\n"),
|
|
168
|
+
"pdfjs-dist":
|
|
169
|
+
"export default {}; export const getDocument = () => { throw new Error('pdfjs-dist unavailable in Cloudflare Pages worker'); };\n",
|
|
170
|
+
"chartjs-node-canvas": [
|
|
171
|
+
"export class ChartJSNodeCanvas {",
|
|
172
|
+
" constructor() { throw new Error('chartjs-node-canvas unavailable in Cloudflare Pages worker'); }",
|
|
173
|
+
"}",
|
|
174
|
+
"export default { ChartJSNodeCanvas };",
|
|
175
|
+
"",
|
|
176
|
+
].join("\n"),
|
|
177
|
+
"@napi-rs/canvas":
|
|
178
|
+
"export default {}; export const createCanvas = () => { throw new Error('@napi-rs/canvas unavailable in Cloudflare Pages worker'); };\n",
|
|
179
|
+
mermaid: "export default {}; export const mermaidAPI = {};\n",
|
|
180
|
+
"@excalidraw/excalidraw":
|
|
181
|
+
"export default {}; export const MainMenu = {}; export const WelcomeScreen = {};\n",
|
|
182
|
+
"@excalidraw/mermaid-to-excalidraw":
|
|
183
|
+
"export default async () => ({ elements: [], files: {} });\n",
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
function cloudflareNodeBuiltinStubSource(
|
|
187
|
+
moduleName: string,
|
|
188
|
+
namedExports: string[],
|
|
189
|
+
overrides: string[] = [],
|
|
190
|
+
): string {
|
|
191
|
+
const overridden = new Set(
|
|
192
|
+
overrides.flatMap((source) =>
|
|
193
|
+
Array.from(source.matchAll(/\bexport const ([A-Za-z_$][\w$]*)/g)).map(
|
|
194
|
+
(match) => match[1],
|
|
195
|
+
),
|
|
196
|
+
),
|
|
197
|
+
);
|
|
198
|
+
const exports = Array.from(new Set(namedExports))
|
|
199
|
+
.filter((name) => !overridden.has(name))
|
|
200
|
+
.sort();
|
|
201
|
+
return [
|
|
202
|
+
`const unavailable = (name) => (..._args) => { throw new Error(name + " is unavailable in Cloudflare Pages workers"); };`,
|
|
203
|
+
`const proxy = new Proxy({}, { get(_target, prop) { return unavailable("${moduleName}." + String(prop)); } });`,
|
|
204
|
+
...overrides,
|
|
205
|
+
...exports.map(
|
|
206
|
+
(name) => `export const ${name} = unavailable("${moduleName}.${name}");`,
|
|
207
|
+
),
|
|
208
|
+
"export default proxy;",
|
|
209
|
+
"",
|
|
210
|
+
].join("\n");
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export const CLOUDFLARE_WORKER_NODE_BUILTIN_STUB_MODULES: Record<
|
|
214
|
+
string,
|
|
215
|
+
string
|
|
216
|
+
> = {
|
|
217
|
+
child_process: cloudflareNodeBuiltinStubSource("child_process", [
|
|
218
|
+
"exec",
|
|
219
|
+
"execFile",
|
|
220
|
+
"execFileSync",
|
|
221
|
+
"execSync",
|
|
222
|
+
"fork",
|
|
223
|
+
"spawn",
|
|
224
|
+
"spawnSync",
|
|
225
|
+
]),
|
|
226
|
+
cluster: cloudflareNodeBuiltinStubSource("cluster", [
|
|
227
|
+
"disconnect",
|
|
228
|
+
"fork",
|
|
229
|
+
"isMaster",
|
|
230
|
+
"isPrimary",
|
|
231
|
+
"isWorker",
|
|
232
|
+
"setupMaster",
|
|
233
|
+
"setupPrimary",
|
|
234
|
+
"worker",
|
|
235
|
+
"workers",
|
|
236
|
+
]),
|
|
237
|
+
dgram: cloudflareNodeBuiltinStubSource("dgram", ["createSocket"]),
|
|
238
|
+
dns: cloudflareNodeBuiltinStubSource("dns", [
|
|
239
|
+
"lookup",
|
|
240
|
+
"promises",
|
|
241
|
+
"resolve",
|
|
242
|
+
"resolve4",
|
|
243
|
+
"resolve6",
|
|
244
|
+
]),
|
|
245
|
+
"dns/promises": cloudflareNodeBuiltinStubSource("dns/promises", [
|
|
246
|
+
"lookup",
|
|
247
|
+
"resolve",
|
|
248
|
+
"resolve4",
|
|
249
|
+
"resolve6",
|
|
250
|
+
]),
|
|
251
|
+
domain: cloudflareNodeBuiltinStubSource("domain", ["create"]),
|
|
252
|
+
fs: cloudflareNodeBuiltinStubSource(
|
|
253
|
+
"fs",
|
|
254
|
+
[
|
|
255
|
+
"access",
|
|
256
|
+
"accessSync",
|
|
257
|
+
"appendFile",
|
|
258
|
+
"appendFileSync",
|
|
259
|
+
"chmod",
|
|
260
|
+
"chmodSync",
|
|
261
|
+
"close",
|
|
262
|
+
"closeSync",
|
|
263
|
+
"copyFile",
|
|
264
|
+
"copyFileSync",
|
|
265
|
+
"cp",
|
|
266
|
+
"cpSync",
|
|
267
|
+
"createReadStream",
|
|
268
|
+
"createWriteStream",
|
|
269
|
+
"existsSync",
|
|
270
|
+
"lstat",
|
|
271
|
+
"lstatSync",
|
|
272
|
+
"mkdir",
|
|
273
|
+
"mkdirSync",
|
|
274
|
+
"open",
|
|
275
|
+
"openSync",
|
|
276
|
+
"readFile",
|
|
277
|
+
"readFileSync",
|
|
278
|
+
"readdir",
|
|
279
|
+
"readdirSync",
|
|
280
|
+
"readlink",
|
|
281
|
+
"readlinkSync",
|
|
282
|
+
"realpath",
|
|
283
|
+
"realpathSync",
|
|
284
|
+
"rename",
|
|
285
|
+
"renameSync",
|
|
286
|
+
"rm",
|
|
287
|
+
"rmSync",
|
|
288
|
+
"stat",
|
|
289
|
+
"statSync",
|
|
290
|
+
"symlink",
|
|
291
|
+
"symlinkSync",
|
|
292
|
+
"unlink",
|
|
293
|
+
"unlinkSync",
|
|
294
|
+
"watch",
|
|
295
|
+
"writeFile",
|
|
296
|
+
"writeFileSync",
|
|
297
|
+
],
|
|
298
|
+
[
|
|
299
|
+
"export const constants = {};",
|
|
300
|
+
"export const promises = {};",
|
|
301
|
+
"export const existsSync = () => false;",
|
|
302
|
+
"export const readdirSync = () => [];",
|
|
303
|
+
"export const realpathSync = (value) => value;",
|
|
304
|
+
"export const mkdirSync = () => undefined;",
|
|
305
|
+
"export const rmSync = () => undefined;",
|
|
306
|
+
],
|
|
307
|
+
),
|
|
308
|
+
"fs/promises": cloudflareNodeBuiltinStubSource("fs/promises", [
|
|
309
|
+
"access",
|
|
310
|
+
"appendFile",
|
|
311
|
+
"chmod",
|
|
312
|
+
"copyFile",
|
|
313
|
+
"cp",
|
|
314
|
+
"lstat",
|
|
315
|
+
"mkdir",
|
|
316
|
+
"readFile",
|
|
317
|
+
"readdir",
|
|
318
|
+
"readlink",
|
|
319
|
+
"realpath",
|
|
320
|
+
"rename",
|
|
321
|
+
"rm",
|
|
322
|
+
"stat",
|
|
323
|
+
"symlink",
|
|
324
|
+
"unlink",
|
|
325
|
+
"writeFile",
|
|
326
|
+
]),
|
|
327
|
+
http: cloudflareNodeBuiltinStubSource("http", [
|
|
328
|
+
"Agent",
|
|
329
|
+
"ClientRequest",
|
|
330
|
+
"IncomingMessage",
|
|
331
|
+
"ServerResponse",
|
|
332
|
+
"createServer",
|
|
333
|
+
"get",
|
|
334
|
+
"request",
|
|
335
|
+
]),
|
|
336
|
+
http2: cloudflareNodeBuiltinStubSource("http2", [
|
|
337
|
+
"Http2ServerRequest",
|
|
338
|
+
"Http2ServerResponse",
|
|
339
|
+
"constants",
|
|
340
|
+
"connect",
|
|
341
|
+
"createSecureServer",
|
|
342
|
+
"createServer",
|
|
343
|
+
]),
|
|
344
|
+
https: cloudflareNodeBuiltinStubSource("https", [
|
|
345
|
+
"Agent",
|
|
346
|
+
"createServer",
|
|
347
|
+
"get",
|
|
348
|
+
"request",
|
|
349
|
+
]),
|
|
350
|
+
inspector: cloudflareNodeBuiltinStubSource("inspector", [
|
|
351
|
+
"Session",
|
|
352
|
+
"close",
|
|
353
|
+
"open",
|
|
354
|
+
"url",
|
|
355
|
+
"waitForDebugger",
|
|
356
|
+
]),
|
|
357
|
+
module: cloudflareNodeBuiltinStubSource(
|
|
358
|
+
"module",
|
|
359
|
+
["Module", "builtinModules", "createRequire", "syncBuiltinESMExports"],
|
|
360
|
+
[
|
|
361
|
+
"export const builtinModules = [];",
|
|
362
|
+
"export const createRequire = () => globalThis.require ?? ((specifier) => { throw new Error('Cannot require: ' + specifier); });",
|
|
363
|
+
],
|
|
364
|
+
),
|
|
365
|
+
net: cloudflareNodeBuiltinStubSource("net", [
|
|
366
|
+
"Socket",
|
|
367
|
+
"connect",
|
|
368
|
+
"createConnection",
|
|
369
|
+
"createServer",
|
|
370
|
+
]),
|
|
371
|
+
os: cloudflareNodeBuiltinStubSource(
|
|
372
|
+
"os",
|
|
373
|
+
[
|
|
374
|
+
"arch",
|
|
375
|
+
"cpus",
|
|
376
|
+
"endianness",
|
|
377
|
+
"freemem",
|
|
378
|
+
"homedir",
|
|
379
|
+
"hostname",
|
|
380
|
+
"networkInterfaces",
|
|
381
|
+
"platform",
|
|
382
|
+
"release",
|
|
383
|
+
"tmpdir",
|
|
384
|
+
"totalmem",
|
|
385
|
+
"type",
|
|
386
|
+
"userInfo",
|
|
387
|
+
],
|
|
388
|
+
[
|
|
389
|
+
'export const EOL = "\\n";',
|
|
390
|
+
'export const arch = () => "x64";',
|
|
391
|
+
"export const cpus = () => [];",
|
|
392
|
+
'export const endianness = () => "LE";',
|
|
393
|
+
"export const freemem = () => 0;",
|
|
394
|
+
'export const homedir = () => "/tmp";',
|
|
395
|
+
'export const hostname = () => "cloudflare-worker";',
|
|
396
|
+
"export const networkInterfaces = () => ({});",
|
|
397
|
+
'export const platform = () => "linux";',
|
|
398
|
+
'export const release = () => "";',
|
|
399
|
+
'export const tmpdir = () => "/tmp";',
|
|
400
|
+
"export const totalmem = () => 0;",
|
|
401
|
+
'export const type = () => "Worker";',
|
|
402
|
+
"export const userInfo = () => ({ username: 'worker', homedir: '/tmp' });",
|
|
403
|
+
],
|
|
404
|
+
),
|
|
405
|
+
readline: cloudflareNodeBuiltinStubSource("readline", [
|
|
406
|
+
"Interface",
|
|
407
|
+
"clearLine",
|
|
408
|
+
"clearScreenDown",
|
|
409
|
+
"createInterface",
|
|
410
|
+
"cursorTo",
|
|
411
|
+
"emitKeypressEvents",
|
|
412
|
+
"moveCursor",
|
|
413
|
+
]),
|
|
414
|
+
repl: cloudflareNodeBuiltinStubSource("repl", ["start"]),
|
|
415
|
+
sqlite: cloudflareNodeBuiltinStubSource("sqlite", ["DatabaseSync"]),
|
|
416
|
+
sys: cloudflareNodeBuiltinStubSource("sys", [
|
|
417
|
+
"debug",
|
|
418
|
+
"deprecate",
|
|
419
|
+
"error",
|
|
420
|
+
"inspect",
|
|
421
|
+
"log",
|
|
422
|
+
"print",
|
|
423
|
+
"puts",
|
|
424
|
+
]),
|
|
425
|
+
tls: cloudflareNodeBuiltinStubSource("tls", [
|
|
426
|
+
"TLSSocket",
|
|
427
|
+
"connect",
|
|
428
|
+
"createSecureContext",
|
|
429
|
+
"createServer",
|
|
430
|
+
]),
|
|
431
|
+
trace_events: cloudflareNodeBuiltinStubSource("trace_events", [
|
|
432
|
+
"createTracing",
|
|
433
|
+
"getEnabledCategories",
|
|
434
|
+
]),
|
|
435
|
+
tty: cloudflareNodeBuiltinStubSource("tty", [
|
|
436
|
+
"ReadStream",
|
|
437
|
+
"WriteStream",
|
|
438
|
+
"isatty",
|
|
439
|
+
]),
|
|
440
|
+
v8: cloudflareNodeBuiltinStubSource("v8", [
|
|
441
|
+
"deserialize",
|
|
442
|
+
"getHeapStatistics",
|
|
443
|
+
"serialize",
|
|
444
|
+
]),
|
|
445
|
+
vm: cloudflareNodeBuiltinStubSource("vm", [
|
|
446
|
+
"Script",
|
|
447
|
+
"compileFunction",
|
|
448
|
+
"createContext",
|
|
449
|
+
"runInContext",
|
|
450
|
+
"runInNewContext",
|
|
451
|
+
"runInThisContext",
|
|
452
|
+
]),
|
|
453
|
+
wasi: cloudflareNodeBuiltinStubSource("wasi", ["WASI"]),
|
|
454
|
+
worker_threads: cloudflareNodeBuiltinStubSource(
|
|
455
|
+
"worker_threads",
|
|
456
|
+
["MessageChannel", "MessagePort", "Worker", "isMainThread", "parentPort"],
|
|
457
|
+
["export const isMainThread = true;", "export const parentPort = null;"],
|
|
458
|
+
),
|
|
459
|
+
};
|
|
460
|
+
|
|
461
|
+
export interface GenerateWorkerEntryOptions {
|
|
462
|
+
includeReactRouterSsr?: boolean;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
interface ReactRouterAssetManifest {
|
|
466
|
+
entry: ReactRouterAssetManifestEntry;
|
|
467
|
+
routes: Record<string, ReactRouterAssetManifestRoute>;
|
|
468
|
+
url: string;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
interface ReactRouterAssetManifestEntry {
|
|
472
|
+
module: string;
|
|
473
|
+
imports?: string[];
|
|
474
|
+
css?: string[];
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
interface ReactRouterAssetManifestRoute {
|
|
478
|
+
id: string;
|
|
479
|
+
module: string;
|
|
480
|
+
imports?: string[];
|
|
481
|
+
css?: string[];
|
|
482
|
+
hasLoader?: boolean;
|
|
483
|
+
clientActionModule?: string;
|
|
484
|
+
clientLoaderModule?: string;
|
|
485
|
+
clientMiddlewareModule?: string;
|
|
486
|
+
hydrateFallbackModule?: string;
|
|
487
|
+
}
|
|
103
488
|
|
|
104
489
|
function normalizeConfiguredAppBasePath(): string {
|
|
105
490
|
return normalizeAppBasePath(
|
|
@@ -116,6 +501,7 @@ const NODE_ONLY_PLUGINS = new Set([
|
|
|
116
501
|
// observability there; the framework default is the Node SDK.
|
|
117
502
|
"sentry",
|
|
118
503
|
]);
|
|
504
|
+
const EDGE_SERVER_ENTRYPOINT = "@agent-native/core/server/edge";
|
|
119
505
|
|
|
120
506
|
function isNodeOnlyPlugin(filePath: string): boolean {
|
|
121
507
|
const basename = path.basename(filePath, path.extname(filePath));
|
|
@@ -127,7 +513,7 @@ export function generateProvidedPluginsNitroPluginSource(
|
|
|
127
513
|
): string {
|
|
128
514
|
const stems = [...new Set(pluginStems.filter(Boolean))].sort();
|
|
129
515
|
return `// AUTO-GENERATED by @agent-native/core deploy build
|
|
130
|
-
import { markDefaultPluginProvided } from "
|
|
516
|
+
import { markDefaultPluginProvided } from "${EDGE_SERVER_ENTRYPOINT}";
|
|
131
517
|
|
|
132
518
|
const pluginStems = ${JSON.stringify(stems)};
|
|
133
519
|
|
|
@@ -189,7 +575,7 @@ export function addImmutableAssetRouteRulesForClientBuild(
|
|
|
189
575
|
* If a workspace core is present (monorepo with `agent-native.workspaceCore`
|
|
190
576
|
* configured and the named package resolves), any plugin slot that the
|
|
191
577
|
* workspace core exports is imported from there instead of from
|
|
192
|
-
* `@agent-native/core/server`. This is the middle layer of the three-layer
|
|
578
|
+
* `@agent-native/core/server/edge`. This is the middle layer of the three-layer
|
|
193
579
|
* inheritance model: app local > workspace core > framework default.
|
|
194
580
|
*/
|
|
195
581
|
export function generateWorkerEntry(
|
|
@@ -200,7 +586,9 @@ export function generateWorkerEntry(
|
|
|
200
586
|
workspaceCore: WorkspaceCoreExports | null = null,
|
|
201
587
|
immutableAssetPaths: string[] = [],
|
|
202
588
|
builtAppBasePath = normalizeConfiguredAppBasePath(),
|
|
589
|
+
options: GenerateWorkerEntryOptions = {},
|
|
203
590
|
): string {
|
|
591
|
+
const includeReactRouterSsr = options.includeReactRouterSsr ?? true;
|
|
204
592
|
const routeImports: string[] = [];
|
|
205
593
|
const routeRegistrations: string[] = [];
|
|
206
594
|
|
|
@@ -293,11 +681,11 @@ export function generateWorkerEntry(
|
|
|
293
681
|
)};`,
|
|
294
682
|
);
|
|
295
683
|
} else {
|
|
296
|
-
// Fall back to the framework default from
|
|
684
|
+
// Fall back to the framework default from the edge-safe core entrypoint.
|
|
297
685
|
const defaultExportName = DEFAULT_PLUGIN_REGISTRY[stem];
|
|
298
686
|
if (!defaultExportName) continue;
|
|
299
687
|
pluginImports.push(
|
|
300
|
-
`import { ${defaultExportName} as ${varName} } from "
|
|
688
|
+
`import { ${defaultExportName} as ${varName} } from "${EDGE_SERVER_ENTRYPOINT}";`,
|
|
301
689
|
);
|
|
302
690
|
}
|
|
303
691
|
pluginCalls.push(` if (typeof ${varName} === "function") {
|
|
@@ -315,15 +703,15 @@ export function generateWorkerEntry(
|
|
|
315
703
|
: [];
|
|
316
704
|
if (generatedPluginMarks.length > 0) {
|
|
317
705
|
pluginImports.unshift(
|
|
318
|
-
`import { markDefaultPluginProvided as markGeneratedPluginProvided } from "
|
|
706
|
+
`import { markDefaultPluginProvided as markGeneratedPluginProvided } from "${EDGE_SERVER_ENTRYPOINT}";`,
|
|
319
707
|
);
|
|
320
708
|
}
|
|
321
709
|
|
|
322
710
|
return `
|
|
323
711
|
// Auto-generated worker entry point for ${preset}
|
|
324
712
|
import { H3, defineEventHandler, readBody, toResponse } from "h3";
|
|
325
|
-
import { createRequestHandler } from "react-router";
|
|
326
|
-
import * as serverBuild from "./server-build.js";
|
|
713
|
+
${includeReactRouterSsr ? 'import { createRequestHandler } from "react-router";' : ""}
|
|
714
|
+
${includeReactRouterSsr ? 'import * as serverBuild from "./server-build.js";' : ""}
|
|
327
715
|
|
|
328
716
|
function normalizeAppBasePath(value) {
|
|
329
717
|
if (!value || value === "/") return "";
|
|
@@ -653,6 +1041,52 @@ function requestWithPathname(request, pathname) {
|
|
|
653
1041
|
return new Request(url, request);
|
|
654
1042
|
}
|
|
655
1043
|
|
|
1044
|
+
function isStaticAppShellRequest(request) {
|
|
1045
|
+
if (request.method !== "GET" && request.method !== "HEAD") return false;
|
|
1046
|
+
const p = stripAppBasePath(new URL(request.url).pathname);
|
|
1047
|
+
if (
|
|
1048
|
+
p.startsWith("/.well-known/") ||
|
|
1049
|
+
p.startsWith("/_agent-native/") ||
|
|
1050
|
+
isApiPath(p) ||
|
|
1051
|
+
p === "/favicon.ico" ||
|
|
1052
|
+
p === "/favicon.png" ||
|
|
1053
|
+
/\\.\\w+$/.test(p)
|
|
1054
|
+
) {
|
|
1055
|
+
return false;
|
|
1056
|
+
}
|
|
1057
|
+
return true;
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
async function fetchStaticAppShell(request, env) {
|
|
1061
|
+
if (!env?.ASSETS || !isStaticAppShellRequest(request)) return null;
|
|
1062
|
+
const basePath = getAppBasePath();
|
|
1063
|
+
const p = stripAppBasePath(new URL(request.url).pathname);
|
|
1064
|
+
const shellRequest = requestWithPathname(
|
|
1065
|
+
requestWithMethod(request, "GET"),
|
|
1066
|
+
"/index.html",
|
|
1067
|
+
);
|
|
1068
|
+
let response;
|
|
1069
|
+
try {
|
|
1070
|
+
response = await env.ASSETS.fetch(shellRequest);
|
|
1071
|
+
} catch {
|
|
1072
|
+
return null;
|
|
1073
|
+
}
|
|
1074
|
+
if (response.status === 404) return null;
|
|
1075
|
+
if (request.method === "HEAD") {
|
|
1076
|
+
return rewriteMountedResponse(
|
|
1077
|
+
new Response(null, {
|
|
1078
|
+
status: response.status,
|
|
1079
|
+
statusText: response.statusText,
|
|
1080
|
+
headers: response.headers,
|
|
1081
|
+
}),
|
|
1082
|
+
basePath,
|
|
1083
|
+
p,
|
|
1084
|
+
request,
|
|
1085
|
+
);
|
|
1086
|
+
}
|
|
1087
|
+
return rewriteMountedResponse(response, basePath, p, request);
|
|
1088
|
+
}
|
|
1089
|
+
|
|
656
1090
|
// API route handlers
|
|
657
1091
|
${routeImports.join("\n")}
|
|
658
1092
|
|
|
@@ -708,7 +1142,9 @@ ${routeRegistrations.join("\n")}
|
|
|
708
1142
|
// Register action routes (/_agent-native/actions/*)
|
|
709
1143
|
${actionRegistrations.join("\n")}
|
|
710
1144
|
|
|
711
|
-
|
|
1145
|
+
${
|
|
1146
|
+
includeReactRouterSsr
|
|
1147
|
+
? ` // SSR catch-all for React Router
|
|
712
1148
|
const rrHandler = createRequestHandler(() => serverBuild);
|
|
713
1149
|
app.all("/**", defineEventHandler(async (event) => {
|
|
714
1150
|
const basePath = getAppBasePath();
|
|
@@ -739,7 +1175,9 @@ ${actionRegistrations.join("\n")}
|
|
|
739
1175
|
);
|
|
740
1176
|
}
|
|
741
1177
|
return rewriteMountedResponse(await rrHandler(request), basePath, p, request);
|
|
742
|
-
}))
|
|
1178
|
+
}));`
|
|
1179
|
+
: ""
|
|
1180
|
+
}
|
|
743
1181
|
|
|
744
1182
|
_handler = app.fetch.bind(app);
|
|
745
1183
|
return _handler;
|
|
@@ -778,12 +1216,227 @@ export default {
|
|
|
778
1216
|
}
|
|
779
1217
|
|
|
780
1218
|
const handler = await getHandler();
|
|
781
|
-
|
|
1219
|
+
const response = await handler(requestWithMountedApiPrefixStripped(request));
|
|
1220
|
+
${
|
|
1221
|
+
includeReactRouterSsr
|
|
1222
|
+
? " return response;"
|
|
1223
|
+
: ` if (response.status === 404) {
|
|
1224
|
+
const shellResponse = await fetchStaticAppShell(request, env);
|
|
1225
|
+
if (shellResponse) return shellResponse;
|
|
1226
|
+
}
|
|
1227
|
+
return response;`
|
|
1228
|
+
}
|
|
782
1229
|
}
|
|
783
1230
|
};
|
|
784
1231
|
`;
|
|
785
1232
|
}
|
|
786
1233
|
|
|
1234
|
+
function escapeHtmlAttribute(value: string): string {
|
|
1235
|
+
return value
|
|
1236
|
+
.replaceAll("&", "&")
|
|
1237
|
+
.replaceAll('"', """)
|
|
1238
|
+
.replaceAll("<", "<")
|
|
1239
|
+
.replaceAll(">", ">");
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
function findReactRouterManifest(distDir: string): ReactRouterAssetManifest {
|
|
1243
|
+
const assetsDir = path.join(distDir, "assets");
|
|
1244
|
+
const manifestFile = fs
|
|
1245
|
+
.readdirSync(assetsDir)
|
|
1246
|
+
.find((file) => /^manifest-[\w-]+\.js$/.test(file));
|
|
1247
|
+
if (!manifestFile) {
|
|
1248
|
+
throw new Error(`React Router client manifest not found in ${assetsDir}`);
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
const source = fs.readFileSync(path.join(assetsDir, manifestFile), "utf8");
|
|
1252
|
+
const match = source.match(/^window\.__reactRouterManifest=(.*);?\s*$/);
|
|
1253
|
+
if (!match) {
|
|
1254
|
+
throw new Error(`Could not parse React Router manifest ${manifestFile}`);
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
return JSON.parse(match[1].replace(/;$/, "")) as ReactRouterAssetManifest;
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
function collectModulePreloads(
|
|
1261
|
+
manifest: ReactRouterAssetManifest,
|
|
1262
|
+
route: ReactRouterAssetManifestRoute,
|
|
1263
|
+
): string[] {
|
|
1264
|
+
const paths = new Set<string>();
|
|
1265
|
+
const add = (value: string | undefined) => {
|
|
1266
|
+
if (value) paths.add(value);
|
|
1267
|
+
};
|
|
1268
|
+
add(manifest.url);
|
|
1269
|
+
add(manifest.entry.module);
|
|
1270
|
+
manifest.entry.imports?.forEach(add);
|
|
1271
|
+
add(route.module);
|
|
1272
|
+
route.imports?.forEach(add);
|
|
1273
|
+
add(route.clientActionModule);
|
|
1274
|
+
add(route.clientLoaderModule);
|
|
1275
|
+
add(route.clientMiddlewareModule);
|
|
1276
|
+
add(route.hydrateFallbackModule);
|
|
1277
|
+
return [...paths];
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
function collectStylesheetLinks(
|
|
1281
|
+
manifest: ReactRouterAssetManifest,
|
|
1282
|
+
route: ReactRouterAssetManifestRoute,
|
|
1283
|
+
): string[] {
|
|
1284
|
+
return [...new Set([...(manifest.entry.css ?? []), ...(route.css ?? [])])];
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
function generateRouteModuleImportScript(
|
|
1288
|
+
manifest: ReactRouterAssetManifest,
|
|
1289
|
+
route: ReactRouterAssetManifestRoute,
|
|
1290
|
+
): string {
|
|
1291
|
+
const modules = [
|
|
1292
|
+
["route0", route.module],
|
|
1293
|
+
["route0_clientAction", route.clientActionModule],
|
|
1294
|
+
["route0_clientLoader", route.clientLoaderModule],
|
|
1295
|
+
["route0_clientMiddleware", route.clientMiddlewareModule],
|
|
1296
|
+
["route0_hydrateFallback", route.hydrateFallbackModule],
|
|
1297
|
+
] as const;
|
|
1298
|
+
const imports = modules
|
|
1299
|
+
.filter(([, modulePath]) => modulePath)
|
|
1300
|
+
.map(
|
|
1301
|
+
([name, modulePath]) =>
|
|
1302
|
+
`import * as ${name} from ${JSON.stringify(modulePath)};`,
|
|
1303
|
+
);
|
|
1304
|
+
const parts = modules
|
|
1305
|
+
.filter(([, modulePath]) => modulePath)
|
|
1306
|
+
.map(([name]) => `...${name}`);
|
|
1307
|
+
|
|
1308
|
+
return [
|
|
1309
|
+
`import ${JSON.stringify(manifest.url)};`,
|
|
1310
|
+
...imports,
|
|
1311
|
+
`window.__reactRouterRouteModules = {${JSON.stringify(route.id)}:{${parts.join(",")}}};`,
|
|
1312
|
+
`import(${JSON.stringify(manifest.entry.module)});`,
|
|
1313
|
+
].join("\n");
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
const EMPTY_REACT_ROUTER_TURBO_STREAM =
|
|
1317
|
+
'[{"_1":2,"_3":-5,"_4":-5},"loaderData",{},"actionData","errors"]\n';
|
|
1318
|
+
|
|
1319
|
+
// Manifest fallbacks cannot execute server loaders, so root loaders get the
|
|
1320
|
+
// framework's default locale shape to keep hydration from reading undefined.
|
|
1321
|
+
const DEFAULT_ROOT_LOADER_REACT_ROUTER_TURBO_STREAM =
|
|
1322
|
+
'[{"_1":2,"_3":-5,"_4":-5},"loaderData",{"_5":6},"actionData","errors","root",{"_7":8,"_9":10,"_11":12,"_13":14},"locale","en-US","preference",{"_7":15},"dir","ltr","messages",{},"system"]\n';
|
|
1323
|
+
|
|
1324
|
+
export function generateCloudflarePagesStaticShellFromManifest(
|
|
1325
|
+
manifest: ReactRouterAssetManifest,
|
|
1326
|
+
basePath = normalizeConfiguredAppBasePath(),
|
|
1327
|
+
): string {
|
|
1328
|
+
const rootRoute = manifest.routes.root;
|
|
1329
|
+
if (!rootRoute) {
|
|
1330
|
+
throw new Error("React Router manifest is missing the root route");
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
const modulePreloads = collectModulePreloads(manifest, rootRoute)
|
|
1334
|
+
.map(
|
|
1335
|
+
(href) =>
|
|
1336
|
+
`<link rel="modulepreload" href="${escapeHtmlAttribute(href)}"/>`,
|
|
1337
|
+
)
|
|
1338
|
+
.join("");
|
|
1339
|
+
const stylesheets = collectStylesheetLinks(manifest, rootRoute)
|
|
1340
|
+
.map(
|
|
1341
|
+
(href) => `<link rel="stylesheet" href="${escapeHtmlAttribute(href)}"/>`,
|
|
1342
|
+
)
|
|
1343
|
+
.join("");
|
|
1344
|
+
const routeModuleScript = generateRouteModuleImportScript(
|
|
1345
|
+
manifest,
|
|
1346
|
+
rootRoute,
|
|
1347
|
+
);
|
|
1348
|
+
const context = {
|
|
1349
|
+
basename: basePath || "/",
|
|
1350
|
+
future: { unstable_optimizeDeps: false },
|
|
1351
|
+
routeDiscovery: { mode: "initial" },
|
|
1352
|
+
ssr: true,
|
|
1353
|
+
isSpaMode: true,
|
|
1354
|
+
};
|
|
1355
|
+
const encodedInitialState = rootRoute.hasLoader
|
|
1356
|
+
? DEFAULT_ROOT_LOADER_REACT_ROUTER_TURBO_STREAM
|
|
1357
|
+
: EMPTY_REACT_ROUTER_TURBO_STREAM;
|
|
1358
|
+
|
|
1359
|
+
return `<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"/><link rel="manifest" href="/manifest.json"/><link rel="icon" type="image/svg+xml" href="/favicon.svg"/>${modulePreloads}${stylesheets}</head><body><div style="display:flex;align-items:center;justify-content:center;height:100vh;width:100%"><svg role="status" aria-label="Loading" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="animation:an-spin 1s linear infinite;opacity:0.7"><path d="M21 12a9 9 0 1 1-6.219-8.56"></path></svg><style>@keyframes an-spin { to { transform: rotate(360deg) } } @media (prefers-color-scheme: dark) { html { background: #09090b; color: #fafafa } }</style></div><script>window.__reactRouterContext = ${JSON.stringify(context)};window.__reactRouterContext.stream = new ReadableStream({start(controller){window.__reactRouterContext.streamController = controller;}}).pipeThrough(new TextEncoderStream());</script><script type="module" async="">${routeModuleScript}</script><!--$--><script>window.__reactRouterContext.streamController.enqueue(${JSON.stringify(encodedInitialState)});</script><!--$--><script>window.__reactRouterContext.streamController.close();</script><!--/$--><!--/$--></body></html>`;
|
|
1360
|
+
}
|
|
1361
|
+
|
|
1362
|
+
function writeCloudflarePagesStaticShell({
|
|
1363
|
+
serverDir,
|
|
1364
|
+
distDir,
|
|
1365
|
+
tmpDir,
|
|
1366
|
+
}: {
|
|
1367
|
+
serverDir: string;
|
|
1368
|
+
distDir: string;
|
|
1369
|
+
tmpDir: string;
|
|
1370
|
+
}): void {
|
|
1371
|
+
const serverEntry = path.join(serverDir, "index.js");
|
|
1372
|
+
if (!fs.existsSync(serverEntry)) {
|
|
1373
|
+
throw new Error(`React Router server build not found at ${serverEntry}`);
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
const outFile = path.join(distDir, "index.html");
|
|
1377
|
+
const renderScript = path.join(tmpDir, "render-cloudflare-static-shell.mjs");
|
|
1378
|
+
const basePath = normalizeConfiguredAppBasePath();
|
|
1379
|
+
fs.writeFileSync(
|
|
1380
|
+
renderScript,
|
|
1381
|
+
`
|
|
1382
|
+
import fs from "node:fs";
|
|
1383
|
+
import { createRequire } from "node:module";
|
|
1384
|
+
import { pathToFileURL } from "node:url";
|
|
1385
|
+
|
|
1386
|
+
const cwd = ${JSON.stringify(cwd)};
|
|
1387
|
+
const serverEntry = ${JSON.stringify(serverEntry)};
|
|
1388
|
+
const outFile = ${JSON.stringify(outFile)};
|
|
1389
|
+
const basePath = ${JSON.stringify(basePath)};
|
|
1390
|
+
|
|
1391
|
+
const requireFromApp = createRequire(cwd + "/package.json");
|
|
1392
|
+
const reactRouterEntry = requireFromApp.resolve("react-router");
|
|
1393
|
+
const { createRequestHandler } = await import(pathToFileURL(reactRouterEntry).href);
|
|
1394
|
+
const serverBuild = await import(pathToFileURL(serverEntry).href);
|
|
1395
|
+
const handler = createRequestHandler(serverBuild, "production");
|
|
1396
|
+
const pathname = basePath ? basePath + "/" : "/";
|
|
1397
|
+
const response = await handler(
|
|
1398
|
+
new Request(new URL(pathname, "https://agent-native.local"), {
|
|
1399
|
+
headers: { "X-React-Router-SPA-Mode": "yes" },
|
|
1400
|
+
}),
|
|
1401
|
+
);
|
|
1402
|
+
const html = await response.text();
|
|
1403
|
+
|
|
1404
|
+
if (!html || !html.includes("__reactRouterContext") || !html.includes("entry.client")) {
|
|
1405
|
+
throw new Error("React Router did not render a usable Cloudflare Pages static shell");
|
|
1406
|
+
}
|
|
1407
|
+
|
|
1408
|
+
fs.writeFileSync(outFile, html);
|
|
1409
|
+
process.exit(0);
|
|
1410
|
+
`,
|
|
1411
|
+
);
|
|
1412
|
+
|
|
1413
|
+
try {
|
|
1414
|
+
execFileSync(process.execPath, [renderScript], {
|
|
1415
|
+
cwd,
|
|
1416
|
+
env: {
|
|
1417
|
+
...process.env,
|
|
1418
|
+
NODE_ENV: process.env.NODE_ENV || "production",
|
|
1419
|
+
IS_RR_BUILD_REQUEST: "yes",
|
|
1420
|
+
},
|
|
1421
|
+
stdio: "inherit",
|
|
1422
|
+
});
|
|
1423
|
+
console.log("[deploy] Wrote Cloudflare Pages static app shell.");
|
|
1424
|
+
} catch (error) {
|
|
1425
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1426
|
+
console.warn(
|
|
1427
|
+
`[deploy] React Router static shell render failed; using manifest fallback. ${message}`,
|
|
1428
|
+
);
|
|
1429
|
+
fs.writeFileSync(
|
|
1430
|
+
outFile,
|
|
1431
|
+
generateCloudflarePagesStaticShellFromManifest(
|
|
1432
|
+
findReactRouterManifest(distDir),
|
|
1433
|
+
basePath,
|
|
1434
|
+
),
|
|
1435
|
+
);
|
|
1436
|
+
console.log("[deploy] Wrote Cloudflare Pages static app shell fallback.");
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1439
|
+
|
|
787
1440
|
/**
|
|
788
1441
|
* Build for Cloudflare Pages.
|
|
789
1442
|
* Output structure:
|
|
@@ -816,11 +1469,15 @@ async function buildCloudflarePages() {
|
|
|
816
1469
|
// Copy client assets to dist/
|
|
817
1470
|
copyDir(clientDir, distDir);
|
|
818
1471
|
|
|
1472
|
+
const tmpDir = path.join(cwd, ".deploy-tmp");
|
|
1473
|
+
fs.mkdirSync(tmpDir, { recursive: true });
|
|
1474
|
+
writeCloudflarePagesStaticShell({ serverDir, distDir, tmpDir });
|
|
1475
|
+
|
|
819
1476
|
// Exclude _worker.js from being served as a public asset
|
|
820
1477
|
fs.writeFileSync(path.join(distDir, ".assetsignore"), "_worker.js\n");
|
|
821
1478
|
|
|
822
|
-
// Write
|
|
823
|
-
//
|
|
1479
|
+
// Write package metadata inside _worker.js/ for the ES module worker that
|
|
1480
|
+
// Wrangler compiles and uploads for Cloudflare Pages.
|
|
824
1481
|
fs.mkdirSync(path.join(distDir, "_worker.js"), { recursive: true });
|
|
825
1482
|
fs.writeFileSync(
|
|
826
1483
|
path.join(distDir, "_worker.js", "package.json"),
|
|
@@ -841,6 +1498,7 @@ async function buildCloudflarePages() {
|
|
|
841
1498
|
const actions = await discoverActionFiles(cwd);
|
|
842
1499
|
const missingDefaults = await getMissingDefaultPlugins(cwd);
|
|
843
1500
|
const workspaceCore = await getWorkspaceCoreExports(cwd);
|
|
1501
|
+
const includeReactRouterSsr = false;
|
|
844
1502
|
|
|
845
1503
|
const workspaceSlotCount = workspaceCore
|
|
846
1504
|
? Object.keys(workspaceCore.plugins).length
|
|
@@ -858,6 +1516,8 @@ async function buildCloudflarePages() {
|
|
|
858
1516
|
actions,
|
|
859
1517
|
workspaceCore,
|
|
860
1518
|
immutableAssetPaths,
|
|
1519
|
+
normalizeConfiguredAppBasePath(),
|
|
1520
|
+
{ includeReactRouterSsr },
|
|
861
1521
|
);
|
|
862
1522
|
|
|
863
1523
|
// Create _worker.js output directory
|
|
@@ -867,23 +1527,27 @@ async function buildCloudflarePages() {
|
|
|
867
1527
|
// Write the worker entry
|
|
868
1528
|
const entryFile = path.join(workerOutDir, "index.js");
|
|
869
1529
|
|
|
870
|
-
// Rewrite the server-build import to point at the copied files
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
1530
|
+
// Rewrite the server-build import to point at the copied files when this
|
|
1531
|
+
// worker intentionally includes React Router SSR.
|
|
1532
|
+
const adjustedEntry = includeReactRouterSsr
|
|
1533
|
+
? entrySource.replace(
|
|
1534
|
+
`import * as serverBuild from "./server-build.js";`,
|
|
1535
|
+
`import * as serverBuild from "./server/index.js";`,
|
|
1536
|
+
)
|
|
1537
|
+
: entrySource;
|
|
875
1538
|
|
|
876
1539
|
// Write a temp file for esbuild to bundle everything into a single worker entry.
|
|
877
|
-
//
|
|
878
|
-
|
|
879
|
-
|
|
1540
|
+
// When React Router SSR is enabled, the server build is copied to tmp so
|
|
1541
|
+
// esbuild can resolve it. Cloudflare Pages currently uses a static app shell
|
|
1542
|
+
// instead so the worker stays under the platform bundle size limit.
|
|
880
1543
|
// Name the entry "index.js" so esbuild outputs index.js in the outdir,
|
|
881
1544
|
// matching the _worker.js/index.js entry point that Cloudflare Pages expects.
|
|
882
1545
|
const tmpEntry = path.join(tmpDir, "index.js");
|
|
883
1546
|
fs.writeFileSync(tmpEntry, adjustedEntry);
|
|
884
1547
|
|
|
885
|
-
|
|
886
|
-
|
|
1548
|
+
if (includeReactRouterSsr) {
|
|
1549
|
+
copyDir(serverDir, path.join(tmpDir, "server"));
|
|
1550
|
+
}
|
|
887
1551
|
|
|
888
1552
|
// Create a require shim so CJS require("fs") calls resolve via ESM imports.
|
|
889
1553
|
// This is injected via esbuild --inject to replace its broken __require shim.
|
|
@@ -915,27 +1579,35 @@ async function buildCloudflarePages() {
|
|
|
915
1579
|
// Create stub modules for native/Node-only deps that can't run on Workers.
|
|
916
1580
|
// These get resolved by esbuild instead of the real modules, avoiding bundling
|
|
917
1581
|
// native code that would fail on the Workers runtime.
|
|
918
|
-
const stubModules = [
|
|
919
|
-
"better-sqlite3",
|
|
920
|
-
"node-pty",
|
|
921
|
-
"chokidar",
|
|
922
|
-
"fsevents",
|
|
923
|
-
"dotenv",
|
|
924
|
-
"@anthropic-ai/sdk",
|
|
925
|
-
];
|
|
926
1582
|
const stubDir = path.join(tmpDir, "node_modules");
|
|
927
|
-
for (const mod of
|
|
1583
|
+
for (const [mod, source] of Object.entries(CLOUDFLARE_WORKER_STUB_MODULES)) {
|
|
928
1584
|
const modDir = path.join(stubDir, mod);
|
|
929
1585
|
fs.mkdirSync(modDir, { recursive: true });
|
|
930
|
-
fs.writeFileSync(
|
|
931
|
-
path.join(modDir, "index.js"),
|
|
932
|
-
`export default {}; export const watch = () => ({ close() {} });`,
|
|
933
|
-
);
|
|
1586
|
+
fs.writeFileSync(path.join(modDir, "index.js"), source);
|
|
934
1587
|
fs.writeFileSync(
|
|
935
1588
|
path.join(modDir, "package.json"),
|
|
936
1589
|
JSON.stringify({ name: mod, main: "index.js", type: "module" }),
|
|
937
1590
|
);
|
|
938
1591
|
}
|
|
1592
|
+
const stubAliases = Object.keys(CLOUDFLARE_WORKER_STUB_MODULES).map(
|
|
1593
|
+
(mod) => `--alias:${mod}=${path.join(stubDir, mod, "index.js")}`,
|
|
1594
|
+
);
|
|
1595
|
+
const nodeBuiltinStubDir = path.join(tmpDir, "node-builtin-stubs");
|
|
1596
|
+
fs.mkdirSync(nodeBuiltinStubDir, { recursive: true });
|
|
1597
|
+
const nodeBuiltinStubAliases: string[] = [];
|
|
1598
|
+
for (const [mod, source] of Object.entries(
|
|
1599
|
+
CLOUDFLARE_WORKER_NODE_BUILTIN_STUB_MODULES,
|
|
1600
|
+
).sort(([a], [b]) => b.length - a.length)) {
|
|
1601
|
+
const stubFile = path.join(
|
|
1602
|
+
nodeBuiltinStubDir,
|
|
1603
|
+
`${mod.replace(/\W+/g, "_")}.js`,
|
|
1604
|
+
);
|
|
1605
|
+
fs.writeFileSync(stubFile, source);
|
|
1606
|
+
nodeBuiltinStubAliases.push(
|
|
1607
|
+
`--alias:${mod}=${stubFile}`,
|
|
1608
|
+
`--alias:node:${mod}=${stubFile}`,
|
|
1609
|
+
);
|
|
1610
|
+
}
|
|
939
1611
|
|
|
940
1612
|
const esbuildBin = findEsbuild();
|
|
941
1613
|
|
|
@@ -951,8 +1623,17 @@ async function buildCloudflarePages() {
|
|
|
951
1623
|
// Only externalize bare names. node:* externals would otherwise pin
|
|
952
1624
|
// the prefix in output; instead we alias node:* → bare so anything that
|
|
953
1625
|
// resolves past alias land as bare externals.
|
|
954
|
-
const
|
|
955
|
-
|
|
1626
|
+
const nodeBuiltinStubs = new Set(
|
|
1627
|
+
Object.keys(CLOUDFLARE_WORKER_NODE_BUILTIN_STUB_MODULES),
|
|
1628
|
+
);
|
|
1629
|
+
const nodeExternals = builtinNames
|
|
1630
|
+
.filter((n) => !nodeBuiltinStubs.has(n))
|
|
1631
|
+
.sort((a, b) => b.length - a.length)
|
|
1632
|
+
.map((n) => `--external:${n}`);
|
|
1633
|
+
const nodeAliases = builtinNames
|
|
1634
|
+
.filter((n) => !nodeBuiltinStubs.has(n))
|
|
1635
|
+
.sort((a, b) => b.length - a.length)
|
|
1636
|
+
.map((n) => `--alias:node:${n}=${n}`);
|
|
956
1637
|
|
|
957
1638
|
// Hard externalize large client-only / node-only libraries so they don't
|
|
958
1639
|
// bloat the edge worker. These are never executed in the CF Pages runtime
|
|
@@ -965,9 +1646,9 @@ async function buildCloudflarePages() {
|
|
|
965
1646
|
// files. Both import sites degrade gracefully when the runtime import
|
|
966
1647
|
// fails: context-xray token counts fall back to char/4 estimates and the
|
|
967
1648
|
// OG image route falls back to SVG.
|
|
968
|
-
const heavyClientExternals = CLOUDFLARE_WORKER_ESBUILD_EXTERNALS.
|
|
969
|
-
(p) =>
|
|
970
|
-
);
|
|
1649
|
+
const heavyClientExternals = CLOUDFLARE_WORKER_ESBUILD_EXTERNALS.filter(
|
|
1650
|
+
(p) => !Object.hasOwn(CLOUDFLARE_WORKER_STUB_MODULES, p),
|
|
1651
|
+
).map((p) => `--external:${p}`);
|
|
971
1652
|
|
|
972
1653
|
execFileSync(
|
|
973
1654
|
esbuildBin,
|
|
@@ -996,6 +1677,8 @@ async function buildCloudflarePages() {
|
|
|
996
1677
|
// Externalize node: builtins — CF Workers runtime provides them
|
|
997
1678
|
...nodeExternals,
|
|
998
1679
|
...heavyClientExternals,
|
|
1680
|
+
...stubAliases,
|
|
1681
|
+
...nodeBuiltinStubAliases,
|
|
999
1682
|
// Rewrite node:* -> bare names so chunks never contain node: imports
|
|
1000
1683
|
...nodeAliases,
|
|
1001
1684
|
],
|
|
@@ -1114,6 +1797,7 @@ const NODE_BUILTINS = [
|
|
|
1114
1797
|
"dgram",
|
|
1115
1798
|
"diagnostics_channel",
|
|
1116
1799
|
"dns",
|
|
1800
|
+
"dns/promises",
|
|
1117
1801
|
"domain",
|
|
1118
1802
|
"events",
|
|
1119
1803
|
"fs",
|
|
@@ -1159,22 +1843,14 @@ export function getNodeBuiltinNames(): string[] {
|
|
|
1159
1843
|
* Injected via esbuild --inject so CJS deps work on Workers runtime.
|
|
1160
1844
|
*/
|
|
1161
1845
|
function generateRequireShim(): string {
|
|
1162
|
-
// Shim
|
|
1163
|
-
//
|
|
1164
|
-
//
|
|
1165
|
-
//
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
// the runtime provides; failures only surface when callers actually USE
|
|
1171
|
-
// the unsupported APIs at request time, which is the same as if the
|
|
1172
|
-
// shim wasn't there.
|
|
1173
|
-
//
|
|
1174
|
-
// `sqlite` is excluded because it's Node 22+ only and Workers'
|
|
1175
|
-
// nodejs_compat doesn't expose it yet — importing it makes the whole
|
|
1176
|
-
// bundle fail to load.
|
|
1177
|
-
const shimmed = NODE_BUILTINS.filter((name) => name !== "sqlite");
|
|
1846
|
+
// Shim Node builtins that Cloudflare Pages can import, and return lazy
|
|
1847
|
+
// unavailable proxies for builtins that Pages Functions reject at upload
|
|
1848
|
+
// time (child_process, fs, net, etc.). This lets optional Node-only code stay
|
|
1849
|
+
// present in the shared bundle without making worker initialization fail.
|
|
1850
|
+
const stubbed = new Set(
|
|
1851
|
+
Object.keys(CLOUDFLARE_WORKER_NODE_BUILTIN_STUB_MODULES),
|
|
1852
|
+
);
|
|
1853
|
+
const shimmed = NODE_BUILTINS.filter((name) => !stubbed.has(name));
|
|
1178
1854
|
|
|
1179
1855
|
// Bare module names — CF Pages Functions runs under nodejs_compat v1,
|
|
1180
1856
|
// which rejects "node:fs" and only accepts "fs". The post-build pass in
|
|
@@ -1192,9 +1868,14 @@ function generateRequireShim(): string {
|
|
|
1192
1868
|
const entries = shimmed
|
|
1193
1869
|
.map((m) => `"${m}":__${m.replace("/", "_")}`)
|
|
1194
1870
|
.join(",");
|
|
1871
|
+
const stubEntries = Array.from(stubbed)
|
|
1872
|
+
.sort()
|
|
1873
|
+
.map((m) => `"${m}":__unavailable("${m}")`)
|
|
1874
|
+
.join(",");
|
|
1875
|
+
const allEntries = [entries, stubEntries].filter(Boolean).join(",");
|
|
1195
1876
|
|
|
1196
1877
|
const messageChannelPolyfill = `if(typeof MessageChannel==="undefined"){globalThis.MessageChannel=class{constructor(){const a={onmessage:null},b={onmessage:null};a.postMessage=d=>{if(b.onmessage)setTimeout(()=>b.onmessage({data:d}),0)};b.postMessage=d=>{if(a.onmessage)setTimeout(()=>a.onmessage({data:d}),0)};this.port1=a;this.port2=b}}}`;
|
|
1197
|
-
return `${imports}\n${messageChannelPolyfill}\nconst __mods={${
|
|
1878
|
+
return `${imports}\n${messageChannelPolyfill}\nconst __unavailable=(m)=>new Proxy({}, { get(_target, prop) { return (..._args) => { throw new Error(m + "." + String(prop) + " is unavailable in Cloudflare Pages workers"); }; } });\nconst __mods={${allEntries}};export var require=globalThis.require||function(m){const r=__mods[m];if(r!==undefined)return r;throw new Error("Cannot require: "+m)};\n`;
|
|
1198
1879
|
}
|
|
1199
1880
|
|
|
1200
1881
|
function findEsbuild(): string {
|