@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.
Files changed (254) hide show
  1. package/README.md +1 -1
  2. package/corpus/README.md +2 -2
  3. package/corpus/core/CHANGELOG.md +10 -0
  4. package/corpus/core/docs/content/cloneable-saas.mdx +9 -9
  5. package/corpus/core/docs/content/creating-templates.mdx +2 -2
  6. package/corpus/core/docs/content/deployment.mdx +23 -0
  7. package/corpus/core/docs/content/faq.mdx +4 -4
  8. package/corpus/core/docs/content/key-concepts.mdx +1 -1
  9. package/corpus/core/docs/content/multi-app-workspace.mdx +1 -1
  10. package/corpus/core/docs/content/syncing-template-changes.mdx +1 -1
  11. package/corpus/core/docs/content/template-analytics-developers.mdx +2 -2
  12. package/corpus/core/docs/content/template-analytics.mdx +2 -2
  13. package/corpus/core/docs/content/template-assets-developers.mdx +3 -3
  14. package/corpus/core/docs/content/template-assets.mdx +2 -2
  15. package/corpus/core/docs/content/template-brain-developers.mdx +2 -2
  16. package/corpus/core/docs/content/template-brain.mdx +1 -1
  17. package/corpus/core/docs/content/template-calendar-developers.mdx +1 -1
  18. package/corpus/core/docs/content/template-calendar.mdx +1 -1
  19. package/corpus/core/docs/content/template-chat.mdx +1 -1
  20. package/corpus/core/docs/content/template-clips-developers.mdx +4 -4
  21. package/corpus/core/docs/content/template-clips.mdx +2 -2
  22. package/corpus/core/docs/content/template-content-developers.mdx +2 -2
  23. package/corpus/core/docs/content/template-content.mdx +1 -1
  24. package/corpus/core/docs/content/template-design-brand-and-figma.mdx +1 -1
  25. package/corpus/core/docs/content/template-design-developers.mdx +2 -2
  26. package/corpus/core/docs/content/template-design.mdx +2 -2
  27. package/corpus/core/docs/content/template-dispatch-developers.mdx +5 -5
  28. package/corpus/core/docs/content/template-forms-developers.mdx +1 -1
  29. package/corpus/core/docs/content/template-forms.mdx +1 -1
  30. package/corpus/core/docs/content/template-mail-developers.mdx +2 -2
  31. package/corpus/core/docs/content/template-mail.mdx +2 -2
  32. package/corpus/core/docs/content/template-plan-developers.mdx +3 -3
  33. package/corpus/core/docs/content/template-plan.mdx +3 -3
  34. package/corpus/core/docs/content/template-slides-developers.mdx +4 -4
  35. package/corpus/core/docs/content/template-slides.mdx +1 -1
  36. package/corpus/core/docs/content/what-is-agent-native.mdx +5 -5
  37. package/corpus/core/package.json +1 -1
  38. package/corpus/core/src/a2a/auth-policy.ts +1 -1
  39. package/corpus/core/src/agent/production-agent.ts +14 -1
  40. package/corpus/core/src/agent/run-manager.ts +6 -13
  41. package/corpus/core/src/cli/index.ts +11 -1
  42. package/corpus/core/src/client/route-chunk-recovery.ts +18 -7
  43. package/corpus/core/src/db/client.ts +7 -6
  44. package/corpus/core/src/db/migrations.ts +2 -1
  45. package/corpus/core/src/deploy/build.ts +290 -4
  46. package/corpus/core/src/deploy/nitro-preset.ts +50 -0
  47. package/corpus/core/src/integrations/pending-tasks-retry-job.ts +2 -1
  48. package/corpus/core/src/scripts/call-agent.ts +4 -2
  49. package/corpus/core/src/server/agent-discovery.ts +1 -0
  50. package/corpus/core/src/server/agent-run-context.ts +13 -3
  51. package/corpus/core/src/server/request-context.ts +2 -0
  52. package/corpus/core/src/shared/cloudflare-globals.d.ts +2 -1
  53. package/corpus/core/src/shared/runtime.ts +2 -0
  54. package/corpus/core/src/templates/default/.agents/skills/secrets/SKILL.md +29 -0
  55. package/corpus/core/src/templates/default/app/i18n/ar-SA.ts +6 -6
  56. package/corpus/core/src/templates/default/app/i18n/de-DE.ts +6 -6
  57. package/corpus/core/src/templates/default/app/i18n/en-US.ts +6 -6
  58. package/corpus/core/src/templates/default/app/i18n/es-ES.ts +6 -6
  59. package/corpus/core/src/templates/default/app/i18n/fr-FR.ts +6 -6
  60. package/corpus/core/src/templates/default/app/i18n/hi-IN.ts +6 -6
  61. package/corpus/core/src/templates/default/app/i18n/ja-JP.ts +6 -6
  62. package/corpus/core/src/templates/default/app/i18n/ko-KR.ts +6 -6
  63. package/corpus/core/src/templates/default/app/i18n/pt-BR.ts +6 -6
  64. package/corpus/core/src/templates/default/app/i18n/zh-CN.ts +6 -6
  65. package/corpus/core/src/templates/default/app/i18n/zh-TW.ts +6 -6
  66. package/corpus/core/src/templates/headless/.agents/skills/secrets/SKILL.md +29 -0
  67. package/corpus/core/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +29 -0
  68. package/corpus/core/src/vite/client.ts +20 -1
  69. package/corpus/templates/analytics/actions/restore-dashboard-revision.ts +9 -2
  70. package/corpus/templates/analytics/app/components/dashboard/DashboardHistoryPanel.tsx +3 -0
  71. package/corpus/templates/analytics/app/components/dashboard/DashboardPanelSkeleton.tsx +1 -1
  72. package/corpus/templates/analytics/app/global.css +10 -9
  73. package/corpus/templates/analytics/app/hooks/use-chart-tooltip-portal.ts +59 -18
  74. package/corpus/templates/analytics/app/hooks/use-dashboard-revisions.ts +14 -2
  75. package/corpus/templates/analytics/app/i18n-data.ts +102 -0
  76. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +232 -2
  77. package/corpus/templates/analytics/changelog/2026-07-27-chart-tooltips-stay-beside-the-cursor-when-they-extend-beyon.md +6 -0
  78. package/corpus/templates/analytics/changelog/2026-07-27-chat-no-longer-claims-a-data-source-is-disconnected-when-it-.md +6 -0
  79. package/corpus/templates/analytics/changelog/2026-07-27-dashboard-changes-can-be-undone-with-cmd-z-and-actions-menu.md +6 -0
  80. package/corpus/templates/analytics/changelog/2026-07-27-dashboard-redo-with-cmd-shift-z-and-actions-menu.md +6 -0
  81. package/corpus/templates/analytics/changelog/2026-07-27-dashboard-skeletons-are-subtler-and-smoother.md +6 -0
  82. package/corpus/templates/analytics/server/lib/dashboards-store.ts +61 -20
  83. package/corpus/templates/analytics/server/lib/real-data-actions.ts +1 -0
  84. package/corpus/templates/analytics/server/plugins/agent-chat.ts +7 -3
  85. package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +7 -32
  86. package/corpus/templates/calendar/changelog/2026-07-27-calendar-s-sidebar-now-uses-a-cleaner-layout-with-fewer-util.md +6 -0
  87. package/corpus/templates/content/app/components/editor/database/sidebar.tsx +14 -6
  88. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +32 -37
  89. package/corpus/templates/content/changelog/2026-07-27-content-sidebar-page-lists-now-load-with-quiet-skeletons-and.md +6 -0
  90. package/corpus/templates/design/app/components/layout/Sidebar.tsx +16 -18
  91. package/corpus/templates/design/changelog/2026-07-27-collapsed-sidebar-keeps-the-agent-native-logo.md +6 -0
  92. package/corpus/templates/dispatch/AGENTS.md +7 -2
  93. package/corpus/templates/dispatch/actions/view-screen.ts +3 -2
  94. package/corpus/templates/dispatch/changelog/2026-07-17-curated-template-remixes.md +1 -1
  95. package/corpus/templates/dispatch/changelog/2026-07-27-creating-an-app-from-a-curated-template-now-uses-clearer-mor.md +6 -0
  96. package/corpus/templates/dispatch/changelog/2026-07-27-thread-debug-accepts-request-run-ids.md +6 -0
  97. package/corpus/templates/slides/actions/create-design-system.ts +10 -2
  98. package/corpus/templates/slides/actions/import-file.ts +173 -1
  99. package/corpus/templates/slides/actions/list-slide-comments.ts +16 -1
  100. package/corpus/templates/slides/actions/update-design-system.ts +13 -2
  101. package/corpus/templates/slides/app/components/editor/AssetLibraryPanel.tsx +35 -12
  102. package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +36 -0
  103. package/corpus/templates/slides/app/i18n/en-US.ts +3 -0
  104. package/corpus/templates/slides/app/lib/dynamic-import.ts +63 -0
  105. package/corpus/templates/slides/app/lib/export-pdf-client.ts +3 -2
  106. package/corpus/templates/slides/app/lib/export-pptx-client.ts +5 -2
  107. package/corpus/templates/slides/app/pages/DesignSystems.tsx +9 -1
  108. package/corpus/templates/slides/server/db/schema.ts +11 -0
  109. package/corpus/templates/slides/server/handlers/assets.ts +64 -19
  110. package/corpus/templates/slides/server/handlers/import/html-converter.ts +38 -0
  111. package/corpus/templates/slides/server/plugins/db.ts +20 -0
  112. package/corpus/templates/slides/shared/design-system-validation.ts +62 -0
  113. package/dist/a2a/auth-policy.js +1 -1
  114. package/dist/a2a/auth-policy.js.map +1 -1
  115. package/dist/agent/production-agent.d.ts +1 -0
  116. package/dist/agent/production-agent.d.ts.map +1 -1
  117. package/dist/agent/production-agent.js +12 -1
  118. package/dist/agent/production-agent.js.map +1 -1
  119. package/dist/agent/run-manager.d.ts +2 -0
  120. package/dist/agent/run-manager.d.ts.map +1 -1
  121. package/dist/agent/run-manager.js +4 -10
  122. package/dist/agent/run-manager.js.map +1 -1
  123. package/dist/cli/index.js +8 -1
  124. package/dist/cli/index.js.map +1 -1
  125. package/dist/client/route-chunk-recovery.d.ts.map +1 -1
  126. package/dist/client/route-chunk-recovery.js +16 -7
  127. package/dist/client/route-chunk-recovery.js.map +1 -1
  128. package/dist/collab/awareness.d.ts +2 -2
  129. package/dist/collab/awareness.d.ts.map +1 -1
  130. package/dist/collab/routes.d.ts +1 -1
  131. package/dist/collab/struct-routes.d.ts +1 -1
  132. package/dist/db/client.d.ts.map +1 -1
  133. package/dist/db/client.js +4 -2
  134. package/dist/db/client.js.map +1 -1
  135. package/dist/db/migrations.d.ts.map +1 -1
  136. package/dist/db/migrations.js +2 -1
  137. package/dist/db/migrations.js.map +1 -1
  138. package/dist/deploy/build.d.ts +25 -0
  139. package/dist/deploy/build.d.ts.map +1 -1
  140. package/dist/deploy/build.js +227 -4
  141. package/dist/deploy/build.js.map +1 -1
  142. package/dist/deploy/nitro-preset.d.ts +8 -0
  143. package/dist/deploy/nitro-preset.d.ts.map +1 -0
  144. package/dist/deploy/nitro-preset.js +36 -0
  145. package/dist/deploy/nitro-preset.js.map +1 -0
  146. package/dist/integrations/pending-tasks-retry-job.d.ts.map +1 -1
  147. package/dist/integrations/pending-tasks-retry-job.js +2 -1
  148. package/dist/integrations/pending-tasks-retry-job.js.map +1 -1
  149. package/dist/notifications/routes.d.ts +3 -3
  150. package/dist/observability/routes.d.ts +3 -3
  151. package/dist/progress/routes.d.ts +1 -1
  152. package/dist/provider-api/actions/custom-provider-registration.d.ts +11 -11
  153. package/dist/provider-api/actions/provider-api.d.ts +11 -11
  154. package/dist/scripts/call-agent.d.ts.map +1 -1
  155. package/dist/scripts/call-agent.js +4 -2
  156. package/dist/scripts/call-agent.js.map +1 -1
  157. package/dist/secrets/routes.d.ts +3 -3
  158. package/dist/server/agent-discovery.d.ts.map +1 -1
  159. package/dist/server/agent-discovery.js +1 -0
  160. package/dist/server/agent-discovery.js.map +1 -1
  161. package/dist/server/agent-run-context.d.ts.map +1 -1
  162. package/dist/server/agent-run-context.js +10 -3
  163. package/dist/server/agent-run-context.js.map +1 -1
  164. package/dist/server/request-context.d.ts +2 -0
  165. package/dist/server/request-context.d.ts.map +1 -1
  166. package/dist/server/request-context.js.map +1 -1
  167. package/dist/server/transcribe-voice.d.ts +1 -1
  168. package/dist/shared/runtime.d.ts.map +1 -1
  169. package/dist/shared/runtime.js +2 -0
  170. package/dist/shared/runtime.js.map +1 -1
  171. package/dist/templates/default/.agents/skills/secrets/SKILL.md +29 -0
  172. package/dist/templates/default/app/i18n/ar-SA.ts +6 -6
  173. package/dist/templates/default/app/i18n/de-DE.ts +6 -6
  174. package/dist/templates/default/app/i18n/en-US.ts +6 -6
  175. package/dist/templates/default/app/i18n/es-ES.ts +6 -6
  176. package/dist/templates/default/app/i18n/fr-FR.ts +6 -6
  177. package/dist/templates/default/app/i18n/hi-IN.ts +6 -6
  178. package/dist/templates/default/app/i18n/ja-JP.ts +6 -6
  179. package/dist/templates/default/app/i18n/ko-KR.ts +6 -6
  180. package/dist/templates/default/app/i18n/pt-BR.ts +6 -6
  181. package/dist/templates/default/app/i18n/zh-CN.ts +6 -6
  182. package/dist/templates/default/app/i18n/zh-TW.ts +6 -6
  183. package/dist/templates/headless/.agents/skills/secrets/SKILL.md +29 -0
  184. package/dist/templates/workspace-core/.agents/skills/secrets/SKILL.md +29 -0
  185. package/dist/vite/client.d.ts +1 -1
  186. package/dist/vite/client.d.ts.map +1 -1
  187. package/dist/vite/client.js +16 -0
  188. package/dist/vite/client.js.map +1 -1
  189. package/docs/content/cloneable-saas.mdx +9 -9
  190. package/docs/content/creating-templates.mdx +2 -2
  191. package/docs/content/deployment.mdx +23 -0
  192. package/docs/content/faq.mdx +4 -4
  193. package/docs/content/key-concepts.mdx +1 -1
  194. package/docs/content/multi-app-workspace.mdx +1 -1
  195. package/docs/content/syncing-template-changes.mdx +1 -1
  196. package/docs/content/template-analytics-developers.mdx +2 -2
  197. package/docs/content/template-analytics.mdx +2 -2
  198. package/docs/content/template-assets-developers.mdx +3 -3
  199. package/docs/content/template-assets.mdx +2 -2
  200. package/docs/content/template-brain-developers.mdx +2 -2
  201. package/docs/content/template-brain.mdx +1 -1
  202. package/docs/content/template-calendar-developers.mdx +1 -1
  203. package/docs/content/template-calendar.mdx +1 -1
  204. package/docs/content/template-chat.mdx +1 -1
  205. package/docs/content/template-clips-developers.mdx +4 -4
  206. package/docs/content/template-clips.mdx +2 -2
  207. package/docs/content/template-content-developers.mdx +2 -2
  208. package/docs/content/template-content.mdx +1 -1
  209. package/docs/content/template-design-brand-and-figma.mdx +1 -1
  210. package/docs/content/template-design-developers.mdx +2 -2
  211. package/docs/content/template-design.mdx +2 -2
  212. package/docs/content/template-dispatch-developers.mdx +5 -5
  213. package/docs/content/template-forms-developers.mdx +1 -1
  214. package/docs/content/template-forms.mdx +1 -1
  215. package/docs/content/template-mail-developers.mdx +2 -2
  216. package/docs/content/template-mail.mdx +2 -2
  217. package/docs/content/template-plan-developers.mdx +3 -3
  218. package/docs/content/template-plan.mdx +3 -3
  219. package/docs/content/template-slides-developers.mdx +4 -4
  220. package/docs/content/template-slides.mdx +1 -1
  221. package/docs/content/what-is-agent-native.mdx +5 -5
  222. package/package.json +1 -1
  223. package/src/a2a/auth-policy.ts +1 -1
  224. package/src/agent/production-agent.ts +14 -1
  225. package/src/agent/run-manager.ts +6 -13
  226. package/src/cli/index.ts +11 -1
  227. package/src/client/route-chunk-recovery.ts +18 -7
  228. package/src/db/client.ts +7 -6
  229. package/src/db/migrations.ts +2 -1
  230. package/src/deploy/build.ts +290 -4
  231. package/src/deploy/nitro-preset.ts +50 -0
  232. package/src/integrations/pending-tasks-retry-job.ts +2 -1
  233. package/src/scripts/call-agent.ts +4 -2
  234. package/src/server/agent-discovery.ts +1 -0
  235. package/src/server/agent-run-context.ts +13 -3
  236. package/src/server/request-context.ts +2 -0
  237. package/src/shared/cloudflare-globals.d.ts +2 -1
  238. package/src/shared/runtime.ts +2 -0
  239. package/src/templates/default/.agents/skills/secrets/SKILL.md +29 -0
  240. package/src/templates/default/app/i18n/ar-SA.ts +6 -6
  241. package/src/templates/default/app/i18n/de-DE.ts +6 -6
  242. package/src/templates/default/app/i18n/en-US.ts +6 -6
  243. package/src/templates/default/app/i18n/es-ES.ts +6 -6
  244. package/src/templates/default/app/i18n/fr-FR.ts +6 -6
  245. package/src/templates/default/app/i18n/hi-IN.ts +6 -6
  246. package/src/templates/default/app/i18n/ja-JP.ts +6 -6
  247. package/src/templates/default/app/i18n/ko-KR.ts +6 -6
  248. package/src/templates/default/app/i18n/pt-BR.ts +6 -6
  249. package/src/templates/default/app/i18n/zh-CN.ts +6 -6
  250. package/src/templates/default/app/i18n/zh-TW.ts +6 -6
  251. package/src/templates/headless/.agents/skills/secrets/SKILL.md +29 -0
  252. package/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +29 -0
  253. package/src/vite/client.ts +20 -1
  254. /package/corpus/templates/slides/server/routes/api/assets/{[filename].delete.ts → [id].delete.ts} +0 -0
@@ -1,11 +1,11 @@
1
1
  ---
2
2
  title: "Slides: Developer Guide"
3
- description: "The Slides data model, persistence model, full action inventory, routes, and where to make common changes when forking or extending the template."
3
+ description: "The Slides data model, persistence model, full action inventory, routes, and where to make common changes when customizing or extending the template."
4
4
  ---
5
5
 
6
6
  # Developer Guide
7
7
 
8
- This page is for anyone forking the Slides template or extending it: the SQL data model, how concurrent writers are kept safe, every agent-callable action, the route map, and where to make common changes.
8
+ This page is for anyone customizing the Slides template or extending it: the SQL data model, how concurrent writers are kept safe, every agent-callable action, the route map, and where to make common changes.
9
9
 
10
10
  ## Quick start
11
11
 
@@ -313,7 +313,7 @@ Each slide inside `decks.data` is:
313
313
 
314
314
  - `create-design-system`, `update-design-system`, `get-design-system`, `list-design-systems`, `set-default-design-system`, `apply-design-system` (link one to a deck)
315
315
  - `analyze-brand-assets`, `import-document`, `import-from-url` — gather raw brand signals (website CSS/fonts, uploaded document metadata) for a **local**, agent-drafted design system
316
- - `index-design-system-with-builder`, `import-design-project` — the Builder-indexed path for Figma files, connected code/GitHub repos, and `design.md`; `import-design-project` forks from an existing design system rather than a raw source
316
+ - `index-design-system-with-builder`, `import-design-project` — the Builder-indexed path for Figma files, connected code/GitHub repos, and `design.md`; `import-design-project` starts from an existing design system rather than a raw source
317
317
 
318
318
  ### Creative Context
319
319
 
@@ -347,7 +347,7 @@ Each slide inside `decks.data` is:
347
347
 
348
348
  ## Customizing it
349
349
 
350
- The Slides template is fully forkable. Key places to look when extending it:
350
+ The Slides template is fully customizable. Key places to look when extending it:
351
351
 
352
352
  #### Actions — `templates/slides/actions/`
353
353
 
@@ -115,7 +115,7 @@ See [Getting started](/docs/getting-started) for the rest of the setup (`cd`, `p
115
115
  - [**Design Systems & Media**](/docs/template-slides-design-and-media) — brand tokens, Figma/GitHub indexing, images, and import/export
116
116
  - [**Talking to the Agent & Creative Context**](/docs/template-slides-agent) — what the agent sees, prompts by task, and the reuse ladder
117
117
  - [**Developer Guide**](/docs/template-slides-developers) — data model, action inventory, routes, and how to extend the template
118
- - [**Templates**](/docs/cloneable-saas) — the clone-and-own model, and every other domain template to start from
118
+ - [**Templates**](/docs/cloneable-saas) — the Cloneable SaaS model, and every other domain template to start from
119
119
  - [**Getting Started**](/docs/getting-started) — the framework fundamentals: actions, application state, and live sync
120
120
  - [**Real-Time Collaboration**](/docs/real-time-collaboration) — the Yjs pipeline decks share with other collaborative surfaces
121
121
  - [**Sharing**](/docs/sharing) — the share-grant model decks and design systems build on
@@ -322,19 +322,19 @@ Agent-native isn't just for developers. Because the agent can edit the app's own
322
322
 
323
323
  The vision: fewer handoffs, one person doing the work of a small team.
324
324
 
325
- ## Fork and customize {#fork-and-customize}
325
+ ## Start from a template and customize {#fork-and-customize}
326
326
 
327
- Agent-native apps follow a fork-and-customize model. You start from a **template** — Calendar, Content, Slides, Analytics, Mail, Clips, Design, Forms, Dispatch — and make it yours. Each one is a complete, working SaaS product you fork wholesale, not a blank scaffold:
327
+ Agent-native apps follow a start-from-a-working-app model. You start from a **template** — Calendar, Content, Slides, Analytics, Mail, Clips, Design, Forms, Dispatch — and make it yours. Each one is a complete, working SaaS product, not a blank scaffold:
328
328
 
329
329
  1. Pick a template on [agent-native.com/templates](/templates)
330
330
  2. Use it immediately as a hosted app (e.g. mail.agent-native.com)
331
- 3. Fork it when you want to customize — "connect our Stripe account," "add a cohort chart"
331
+ 3. Create your own app from the template when you want to customize — "connect our Stripe account," "add a cohort chart"
332
332
  4. The agent modifies the code to match your needs
333
- 5. Deploy your fork to your own domain — or stay on agent-native.com
333
+ 5. Deploy your app to your own domain — or stay on agent-native.com
334
334
 
335
335
  Because it's _your_ app, not shared infrastructure, the agent can safely evolve the code. Your app keeps improving as you use it. See [Templates](/docs/cloneable-saas) for the full story.
336
336
 
337
- Not ready to fork a whole template? You can also try agent-native by adding a **skill** to a coding agent you already use — install the Plans skill with `npx @agent-native/core@latest skills add visual-plan`. See the [Skills Guide](/docs/skills-guide#app-backed-skills).
337
+ Not ready to start from a whole template? You can also try agent-native by adding a **skill** to a coding agent you already use — install the Plans skill with `npx @agent-native/core@latest skills add visual-plan`. See the [Skills Guide](/docs/skills-guide#app-backed-skills).
338
338
 
339
339
  ## Composable agents {#composable-agents}
340
340
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/core",
3
- "version": "0.124.3",
3
+ "version": "0.124.4",
4
4
  "description": "Framework for agent-native application development — where AI agents and UI share SQL state, actions, and context",
5
5
  "homepage": "https://github.com/BuilderIO/agent-native#readme",
6
6
  "bugs": {
@@ -16,7 +16,7 @@ export function isA2AProductionRuntime(): boolean {
16
16
  return true;
17
17
  }
18
18
  if (process.env.CF_PAGES === "1") return true;
19
- if ("__cf_env" in globalThis) return true;
19
+ if ("__cf_env" in globalThis || "__env__" in globalThis) return true;
20
20
  if (process.env.VERCEL || process.env.VERCEL_ENV) return true;
21
21
  if (process.env.RENDER || process.env.FLY_APP_NAME || process.env.K_SERVICE) {
22
22
  return true;
@@ -2088,6 +2088,13 @@ function collectTextParts(parts: EngineContentPart[]): string {
2088
2088
  .join("");
2089
2089
  }
2090
2090
 
2091
+ // Guard retries are pushed as `role: "user"` because engines have no other
2092
+ // mid-turn channel. Unlabeled, a corrective instruction ("say the source is
2093
+ // not connected and include this link") reads exactly like an injected user
2094
+ // turn, and an aligned model refuses it *to the user* instead of following it.
2095
+ export const AGENT_INTERNAL_GUARD_PROMPT =
2096
+ "Automated quality check on the draft answer you just produced. This is a directive from this application's own response guard, not a message from the user and not content from a tool result or web page. Follow it and revise your answer. Do not quote it, describe it, or treat it as an injection attempt. If it contradicts what you observed this turn, state what you actually observed instead of asserting the guard's premise.";
2097
+
2091
2098
  export const AGENT_INTERNAL_CONTINUE_PROMPT =
2092
2099
  "Continue from where you left off and finish the user's original request. Do not repeat completed work, do not mention internal reconnects, time limits, or step limits, and continue as if this is the same uninterrupted run.";
2093
2100
 
@@ -4588,7 +4595,12 @@ export async function runAgentLoop(opts: {
4588
4595
  send({ type: "clear" });
4589
4596
  messages.push({
4590
4597
  role: "user",
4591
- content: [{ type: "text", text: retryMessage }],
4598
+ content: [
4599
+ {
4600
+ type: "text",
4601
+ text: `${AGENT_INTERNAL_GUARD_PROMPT}\n\n<response-guard>\n${retryMessage}\n</response-guard>`,
4602
+ },
4603
+ ],
4592
4604
  });
4593
4605
  continue;
4594
4606
  }
@@ -8966,6 +8978,7 @@ export function createProductionAgentHandler(
8966
8978
  // assistant message. Falls back to the runId (turn == run) when the
8967
8979
  // client doesn't supply a turnId.
8968
8980
  turnId: effectiveTurnId,
8981
+ waitUntil: getRequestRunContext()?.waitUntil,
8969
8982
  dispatchMode: foregroundSelfChainEligible
8970
8983
  ? "foreground-self-chain"
8971
8984
  : "foreground",
@@ -348,6 +348,8 @@ function shouldCaptureRunError(err: unknown): boolean {
348
348
  }
349
349
 
350
350
  export interface StartRunOptions {
351
+ /** Keep a request-scoped serverless invocation alive for this run. */
352
+ waitUntil?: (promise: Promise<unknown>) => void;
351
353
  /** Optional internal run chunk budget. When reached, the framework emits an
352
354
  * auto-continuation signal instead of a user-facing timeout. Leave unset for
353
355
  * no framework-imposed run timeout. */
@@ -1344,19 +1346,10 @@ export function startRun(
1344
1346
  });
1345
1347
  runPromise.then(resolveFinalized, rejectFinalized);
1346
1348
 
1347
- // On Cloudflare Workers, keep the isolate alive for this run
1348
- try {
1349
- const cfCtx = (
1350
- globalThis as typeof globalThis & {
1351
- __cf_ctx?: { waitUntil(promise: Promise<unknown>): void };
1352
- }
1353
- ).__cf_ctx;
1354
- if (cfCtx?.waitUntil) {
1355
- cfCtx.waitUntil(runPromise);
1356
- }
1357
- } catch {
1358
- // Not on Workers — ignore
1359
- }
1349
+ // Keep the originating request alive when its runtime supports background
1350
+ // work. The callback is passed through request context so concurrent Worker
1351
+ // requests cannot overwrite one another through a global binding.
1352
+ options?.waitUntil?.(runPromise);
1360
1353
 
1361
1354
  return run;
1362
1355
  }
@@ -8,6 +8,10 @@ import { fileURLToPath } from "url";
8
8
 
9
9
  import * as Sentry from "@sentry/node";
10
10
 
11
+ import {
12
+ clearAgentNativeNitroPresetMarker,
13
+ resolveAgentNativeNitroPreset,
14
+ } from "../deploy/nitro-preset.js";
11
15
  import { resolveDeployPostBuildInvocation } from "./deploy-build.js";
12
16
  import { shouldTrackCliRun } from "./telemetry-routing.js";
13
17
  import { createCliTelemetry } from "./telemetry.js";
@@ -696,6 +700,7 @@ switch (command) {
696
700
  }
697
701
 
698
702
  if (isReactRouterFramework()) {
703
+ clearAgentNativeNitroPresetMarker();
699
704
  validateReactRouterBuildDependencies();
700
705
  const rr = findReactRouterBin();
701
706
  console.log("Building (React Router framework mode)...");
@@ -709,15 +714,20 @@ switch (command) {
709
714
  // Post-build: framework-mode apps also need a Nitro server bundle for
710
715
  // `agent-native start` and for serverless presets.
711
716
  if (isReactRouterFramework()) {
717
+ const configuredNitroPreset = resolveAgentNativeNitroPreset();
718
+ const deployEnv = configuredNitroPreset
719
+ ? { ...process.env, NITRO_PRESET: configuredNitroPreset }
720
+ : process.env;
712
721
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
713
722
  const deployBuild = resolveDeployPostBuildInvocation({
714
723
  cliDir: __dirname,
724
+ env: deployEnv,
715
725
  findTsxBin,
716
726
  });
717
727
  if (deployBuild) {
718
728
  await runBuildStep(deployBuild.command, deployBuild.args, {
719
729
  label: "deploy-build",
720
- env: process.env,
730
+ env: deployEnv,
721
731
  });
722
732
  } else {
723
733
  console.warn(
@@ -190,16 +190,27 @@ function recoverToIntendedNavigation(
190
190
  state: RouteChunkRecoveryState,
191
191
  ): boolean {
192
192
  const target = getFreshIntendedNavigation(state, win.location.href);
193
- if (!target) return false;
193
+ const sameCurrentTarget =
194
+ !target &&
195
+ state.intendedHref === win.location.href &&
196
+ Date.now() - state.intendedAt <= INTENDED_NAV_MAX_AGE_MS
197
+ ? state.intendedHref
198
+ : null;
199
+ const recoveryTarget = target ?? sameCurrentTarget;
200
+ if (!recoveryTarget) return false;
194
201
  state.recovering = true;
195
- state.recoveryHref = target;
196
- // Desktop webviews stay open across many deploys; a forced navigation here
197
- // reads as a random tab reload. Leave the current view alive instead.
198
- if (isAgentNativeDesktop(win)) return true;
202
+ state.recoveryHref = recoveryTarget;
203
+ // Keep the desktop shell mounted, but replace only the route that failed to
204
+ // load. A current-page reload remains suppressed below when there is no
205
+ // intended cross-route destination to recover.
206
+ if (isAgentNativeDesktop(win)) {
207
+ hardNavigate(win, recoveryTarget);
208
+ return true;
209
+ }
199
210
  try {
200
- win.history.replaceState(win.history.state, "", target);
211
+ win.history.replaceState(win.history.state, "", recoveryTarget);
201
212
  } catch {}
202
- hardNavigate(win, target);
213
+ hardNavigate(win, recoveryTarget);
203
214
  return true;
204
215
  }
205
216
 
@@ -65,11 +65,11 @@ export interface DbExecConfig {
65
65
  /** Read the request-scoped Cloudflare binding without requiring every
66
66
  * consuming app's TypeScript program to include core's ambient Worker globals. */
67
67
  export function getCloudflareD1Binding(): unknown {
68
- return (
69
- globalThis as typeof globalThis & {
70
- __cf_env?: { DB?: unknown };
71
- }
72
- ).__cf_env?.DB;
68
+ const runtime = globalThis as typeof globalThis & {
69
+ __cf_env?: { DB?: unknown };
70
+ __env__?: { DB?: unknown };
71
+ };
72
+ return runtime.__cf_env?.DB ?? runtime.__env__?.DB;
73
73
  }
74
74
 
75
75
  // ---------------------------------------------------------------------------
@@ -451,7 +451,8 @@ export function getDialect(): Dialect {
451
451
  return _dialect;
452
452
  }
453
453
 
454
- // Don't cache the fallthrough — on CF Workers, env bindings (__cf_env) aren't
454
+ // Don't cache the fallthrough — on CF Workers, env bindings (__cf_env/__env__)
455
+ // aren't
455
456
  // available at import time. If we cache "sqlite" here, D1 will never be
456
457
  // detected once the bindings are set in the fetch handler.
457
458
  return "sqlite";
@@ -682,7 +682,8 @@ export function runMigrations(
682
682
  !!globalThis.process?.env?.NETLIFY ||
683
683
  !!globalThis.process?.env?.AWS_LAMBDA_FUNCTION_NAME ||
684
684
  !!globalThis.process?.env?.VERCEL ||
685
- "__cf_env" in globalThis;
685
+ "__cf_env" in globalThis ||
686
+ "__env__" in globalThis;
686
687
  if (typeof globalThis.process?.exit === "function" && !isServerless) {
687
688
  process.exit(1);
688
689
  }
@@ -10,6 +10,7 @@
10
10
  *
11
11
  * Supported presets:
12
12
  * - cloudflare_pages: Outputs dist/ with _worker.js for Cloudflare Pages
13
+ * - cloudflare_module: Outputs a native Cloudflare Worker under .output/server
13
14
  *
14
15
  * Usage: node deploy/build.js (called automatically by `agent-native build`)
15
16
  */
@@ -73,6 +74,171 @@ import {
73
74
 
74
75
  const cwd = process.cwd();
75
76
  const preset = process.env.NITRO_PRESET || "node";
77
+ export const CLOUDFLARE_MODULE_PRESETS = [
78
+ "cloudflare_module",
79
+ "cloudflare-module",
80
+ ] as const;
81
+
82
+ export function isCloudflareModulePreset(targetPreset: string): boolean {
83
+ return (CLOUDFLARE_MODULE_PRESETS as readonly string[]).includes(
84
+ targetPreset,
85
+ );
86
+ }
87
+
88
+ export const CLOUDFLARE_MODULE_WORKER_ENTRY = "worker.mjs";
89
+
90
+ export function generateCloudflareModuleWorkerEntry(): string {
91
+ return `let handler;
92
+
93
+ export * from "./index.mjs";
94
+
95
+ async function loadHandler() {
96
+ handler ??= (await import("./index.mjs")).default;
97
+ return handler;
98
+ }
99
+
100
+ function initializeBindings(env) {
101
+ if (!env) return;
102
+ globalThis.__cf_env = env;
103
+ globalThis.__env__ = env;
104
+ globalThis.process = globalThis.process || { env: {} };
105
+ globalThis.process.env = globalThis.process.env || {};
106
+ for (const [key, value] of Object.entries(env)) {
107
+ if (typeof value === "string") globalThis.process.env[key] = value;
108
+ }
109
+ }
110
+
111
+ export default {
112
+ async fetch(request, env, ctx) {
113
+ if (typeof ctx?.waitUntil === "function") {
114
+ request.waitUntil = ctx.waitUntil.bind(ctx);
115
+ }
116
+ initializeBindings(env);
117
+ return (await loadHandler()).fetch(request, env, ctx);
118
+ },
119
+ async scheduled(controller, env, ctx) {
120
+ initializeBindings(env);
121
+ return (await loadHandler()).scheduled?.(controller, env, ctx);
122
+ },
123
+ async email(message, env, ctx) {
124
+ initializeBindings(env);
125
+ return (await loadHandler()).email?.(message, env, ctx);
126
+ },
127
+ async queue(batch, env, ctx) {
128
+ initializeBindings(env);
129
+ return (await loadHandler()).queue?.(batch, env, ctx);
130
+ },
131
+ async tail(traces, env, ctx) {
132
+ initializeBindings(env);
133
+ return (await loadHandler()).tail?.(traces, env, ctx);
134
+ },
135
+ async trace(traces, env, ctx) {
136
+ initializeBindings(env);
137
+ return (await loadHandler()).trace?.(traces, env, ctx);
138
+ },
139
+ };
140
+ `;
141
+ }
142
+
143
+ export function patchCloudflareModuleNitroEntry(code: string): string {
144
+ const factoryMatch = code.match(
145
+ /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$]*)\)\{/,
146
+ );
147
+ if (!factoryMatch) {
148
+ throw new Error(
149
+ "[deploy] Could not find Nitro's Cloudflare module handler factory",
150
+ );
151
+ }
152
+
153
+ const [
154
+ ,
155
+ factoryName,
156
+ handlerName,
157
+ handlerFactoryName,
158
+ hooksName,
159
+ hooksFactoryName,
160
+ requestName,
161
+ envName,
162
+ contextName,
163
+ ] = factoryMatch;
164
+ const eagerInitialization = `let ${handlerName}=${handlerFactoryName}(),${hooksName}=${hooksFactoryName}();`;
165
+ if (!code.includes(eagerInitialization)) {
166
+ throw new Error(
167
+ `[deploy] Nitro's ${factoryName} handler changed its initialization shape`,
168
+ );
169
+ }
170
+
171
+ const bindingMatch = code.match(
172
+ new RegExp(
173
+ `globalThis\\.__env__=${envName},([A-Za-z_$][\\w$]*)\\(${requestName},\\{env:${envName},context:${contextName}\\}\\);?`,
174
+ ),
175
+ );
176
+ if (!bindingMatch) {
177
+ throw new Error(
178
+ `[deploy] Nitro's ${factoryName} handler does not initialize Cloudflare bindings as expected`,
179
+ );
180
+ }
181
+ const bindingInitialization = bindingMatch[0];
182
+
183
+ let patched = code.replace(
184
+ eagerInitialization,
185
+ `let ${handlerName},${hooksName};`,
186
+ );
187
+ patched = patched.replace(
188
+ bindingInitialization,
189
+ `${bindingInitialization}${handlerName}??=${handlerFactoryName}();`,
190
+ );
191
+ const hookCall = `${hooksName}.callHook(`;
192
+ if (!patched.includes(hookCall)) {
193
+ throw new Error(
194
+ `[deploy] Nitro's ${factoryName} handler has no Cloudflare lifecycle hooks`,
195
+ );
196
+ }
197
+ patched = patched
198
+ .split(hookCall)
199
+ .join(`(${hooksName}??=${hooksFactoryName}()).callHook(`);
200
+
201
+ return patched;
202
+ }
203
+
204
+ export function configureCloudflareModuleWorkerOutput(serverDir: string): void {
205
+ const configPath = path.join(serverDir, "wrangler.json");
206
+ if (!fs.existsSync(configPath)) {
207
+ throw new Error(
208
+ `[deploy] Nitro did not generate ${configPath} for cloudflare_module`,
209
+ );
210
+ }
211
+ const nitroEntryPath = path.join(serverDir, "index.mjs");
212
+ if (!fs.existsSync(nitroEntryPath)) {
213
+ throw new Error(
214
+ `[deploy] Nitro did not generate ${nitroEntryPath} for cloudflare_module`,
215
+ );
216
+ }
217
+
218
+ const config = JSON.parse(fs.readFileSync(configPath, "utf8")) as {
219
+ main?: string;
220
+ compatibility_flags?: unknown;
221
+ [key: string]: unknown;
222
+ };
223
+ config.main = CLOUDFLARE_MODULE_WORKER_ENTRY;
224
+ const compatibilityFlags = Array.isArray(config.compatibility_flags)
225
+ ? config.compatibility_flags.filter(
226
+ (flag): flag is string => typeof flag === "string",
227
+ )
228
+ : [];
229
+ config.compatibility_flags = [
230
+ ...new Set([...compatibilityFlags, "nodejs_compat"]),
231
+ ];
232
+ fs.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`);
233
+ fs.writeFileSync(
234
+ nitroEntryPath,
235
+ patchCloudflareModuleNitroEntry(fs.readFileSync(nitroEntryPath, "utf8")),
236
+ );
237
+ fs.writeFileSync(
238
+ path.join(serverDir, CLOUDFLARE_MODULE_WORKER_ENTRY),
239
+ generateCloudflareModuleWorkerEntry(),
240
+ );
241
+ }
76
242
  export const NITRO_RUNTIME_IGNORE_PATTERNS = [
77
243
  "**/*.spec.ts",
78
244
  "**/*.spec.tsx",
@@ -893,7 +1059,9 @@ function requestWithMountedApiPrefixStripped(request) {
893
1059
  return request;
894
1060
  }
895
1061
  url.pathname = strippedPathname;
896
- return new Request(url, request);
1062
+ const rewritten = new Request(url, request);
1063
+ rewritten.waitUntil = request.waitUntil;
1064
+ return rewritten;
897
1065
  }
898
1066
 
899
1067
  function prefixMountedPath(path, basePath) {
@@ -1347,8 +1515,10 @@ ${
1347
1515
 
1348
1516
  export default {
1349
1517
  async fetch(request, env, ctx) {
1350
- // Expose env and ctx bindings globally for compatibility
1351
- if (ctx) globalThis.__cf_ctx = ctx;
1518
+ // Attach the request-scoped continuation hook before any URL rewrite.
1519
+ if (typeof ctx?.waitUntil === "function") {
1520
+ request.waitUntil = ctx.waitUntil.bind(ctx);
1521
+ }
1352
1522
  if (env) {
1353
1523
  globalThis.process = globalThis.process || { env: {} };
1354
1524
  globalThis.process.env = globalThis.process.env || {};
@@ -2959,6 +3129,23 @@ export function bundleYjsRuntimeForServerlessOutput(
2959
3129
  );
2960
3130
  }
2961
3131
 
3132
+ walkServerJavaScriptFiles(serverDir, (filePath) => {
3133
+ const bundledImport = path
3134
+ .relative(path.dirname(filePath), bundledYjsPath)
3135
+ .split(path.sep)
3136
+ .join("/");
3137
+ const relativeBundledImport = bundledImport.startsWith(".")
3138
+ ? bundledImport
3139
+ : `./${bundledImport}`;
3140
+ const source = fs.readFileSync(filePath, "utf-8");
3141
+ const rewritten = source.replace(
3142
+ /(\b(?:from\s*|import\s*\(\s*|import\s*))(["'])\.\.?\/(?:\.\.\/)*_libs\/yjs\.mjs\2/g,
3143
+ (_match, importPrefix: string, quote: string) =>
3144
+ `${importPrefix}${quote}${relativeBundledImport}${quote}`,
3145
+ );
3146
+ if (rewritten !== source) fs.writeFileSync(filePath, rewritten);
3147
+ });
3148
+
2962
3149
  return bareImports;
2963
3150
  }
2964
3151
 
@@ -3601,6 +3788,53 @@ const BROWSER_ONLY_SERVER_LIBS = [
3601
3788
  "mermaid",
3602
3789
  ];
3603
3790
 
3791
+ /**
3792
+ * Packages that Nitro can discover through the shared server graph but that
3793
+ * cannot be evaluated in a Cloudflare Worker. Keep the network-capable SDKs
3794
+ * real; these are limited to Node/native/browser-runtime packages whose
3795
+ * server-side paths already fail closed when the capability is unavailable.
3796
+ */
3797
+ export const CLOUDFLARE_MODULE_STUB_MODULES = [
3798
+ "@napi-rs/canvas",
3799
+ "@resvg/resvg-js",
3800
+ "@sentry/node",
3801
+ "@sparticuz/chromium-min",
3802
+ "better-sqlite3",
3803
+ "chartjs-node-canvas",
3804
+ "chokidar",
3805
+ "fsevents",
3806
+ "node-pty",
3807
+ "playwright",
3808
+ "playwright-core",
3809
+ ] as const;
3810
+
3811
+ /**
3812
+ * Mirror the fail-closed package stubs used by the Pages bundler in Nitro's
3813
+ * Rolldown graph. Without this, the native module preset emits a valid module
3814
+ * graph that still crashes at Worker cold start when a Node-only optional
3815
+ * dependency is evaluated.
3816
+ */
3817
+ export function createCloudflareModuleStubPlugin() {
3818
+ const stubbed = new Set<string>(CLOUDFLARE_MODULE_STUB_MODULES);
3819
+ const stubIdPrefix = "\0agent-native-cloudflare-module-stub:";
3820
+
3821
+ return {
3822
+ name: "agent-native-cloudflare-module-stub",
3823
+ resolveId(id: string) {
3824
+ const packageName = id.startsWith("@")
3825
+ ? id.split("/").slice(0, 2).join("/")
3826
+ : id.split("/")[0];
3827
+ if (!stubbed.has(packageName) || id !== packageName) return null;
3828
+ return `${stubIdPrefix}${packageName}`;
3829
+ },
3830
+ load(id: string) {
3831
+ if (!id.startsWith(stubIdPrefix)) return null;
3832
+ const packageName = id.slice(stubIdPrefix.length);
3833
+ return CLOUDFLARE_WORKER_STUB_MODULES[packageName] ?? null;
3834
+ },
3835
+ };
3836
+ }
3837
+
3604
3838
  /**
3605
3839
  * Dependencies Nitro itself must bundle outside the controlled serverless
3606
3840
  * output pass. Netlify, Vercel, and Lambda keep Yjs external through Nitro;
@@ -3811,7 +4045,12 @@ export default bundle;
3811
4045
  ...(preset === "netlify" || preset === "vercel" || preset === "aws-lambda"
3812
4046
  ? { external: ["yjs"] }
3813
4047
  : {}),
3814
- plugins: [createBrowserOnlyServerStubPlugin()],
4048
+ plugins: [
4049
+ ...(preset.startsWith("cloudflare")
4050
+ ? [createCloudflareModuleStubPlugin()]
4051
+ : []),
4052
+ createBrowserOnlyServerStubPlugin(),
4053
+ ],
3815
4054
  },
3816
4055
  ...(providedPluginsNitroPlugin
3817
4056
  ? { plugins: [providedPluginsNitroPlugin] }
@@ -3833,6 +4072,10 @@ export default bundle;
3833
4072
  cwd,
3834
4073
  });
3835
4074
 
4075
+ if (isCloudflareModulePreset(preset)) {
4076
+ configureCloudflareModuleWorkerOutput(nitro.options.output.serverDir);
4077
+ }
4078
+
3836
4079
  if (preset === "netlify" || preset === "vercel" || preset === "aws-lambda") {
3837
4080
  copyInstalledLibsqlNativePackages(nitro.options.output.serverDir);
3838
4081
  copyInstalledResvgPackages(nitro.options.output.serverDir);
@@ -3841,6 +4084,10 @@ export default bundle;
3841
4084
  bundleYjsRuntimeForServerlessOutput(nitro.options.output.serverDir, cwd);
3842
4085
  }
3843
4086
 
4087
+ if (isCloudflareModulePreset(preset)) {
4088
+ bundleYjsRuntimeForServerlessOutput(nitro.options.output.serverDir, cwd);
4089
+ }
4090
+
3844
4091
  if (preset === "netlify") {
3845
4092
  emitSingleTemplateNetlifyKeepWarmFunction(cwd);
3846
4093
 
@@ -3949,8 +4196,43 @@ export default bundle;
3949
4196
  if (bareImports.size > 0) {
3950
4197
  const libsDir = path.join(outputDir, "_libs");
3951
4198
  fs.mkdirSync(libsDir, { recursive: true });
4199
+ function rewriteExternalImports(mod: string, outFile: string) {
4200
+ function rewriteImports(dir: string) {
4201
+ if (!fs.existsSync(dir)) return;
4202
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
4203
+ const p = path.join(dir, entry.name);
4204
+ if (entry.isDirectory()) {
4205
+ rewriteImports(p);
4206
+ continue;
4207
+ }
4208
+ if (!entry.name.endsWith(".mjs") && !entry.name.endsWith(".js"))
4209
+ continue;
4210
+ const code = fs.readFileSync(p, "utf8");
4211
+ const relPath = path
4212
+ .relative(path.dirname(p), outFile)
4213
+ .replace(/\\/g, "/");
4214
+ const importPath = relPath.startsWith(".")
4215
+ ? relPath
4216
+ : "./" + relPath;
4217
+ const escaped = mod.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
4218
+ const re = new RegExp(`from["']${escaped}["']`, "g");
4219
+ const rewritten = code.replace(re, `from"${importPath}"`);
4220
+ if (rewritten !== code) fs.writeFileSync(p, rewritten);
4221
+ }
4222
+ }
4223
+ rewriteImports(outputDir);
4224
+ }
3952
4225
  for (const mod of bareImports) {
3953
4226
  const outFile = path.join(libsDir, `${mod.replace(/[/@]/g, "_")}.mjs`);
4227
+ // Nitro may already have emitted a correctly minified module wrapper
4228
+ // for this dependency. Replacing that wrapper with an esbuild CJS
4229
+ // adapter loses its public export aliases and makes otherwise valid
4230
+ // sibling chunks fail during Worker module linking.
4231
+ if (fs.existsSync(outFile)) {
4232
+ console.log(`[deploy] Retaining Nitro external: ${mod}`);
4233
+ rewriteExternalImports(mod, outFile);
4234
+ continue;
4235
+ }
3954
4236
  try {
3955
4237
  // Resolve the module — check workspace node_modules and pnpm store
3956
4238
  let resolvedMod = mod;
@@ -4244,6 +4526,10 @@ async function main() {
4244
4526
  // as multi-module Workers. Use the custom esbuild-based bundler.
4245
4527
  await buildCloudflarePages();
4246
4528
  break;
4529
+ case "cloudflare_module":
4530
+ case "cloudflare-module":
4531
+ await buildWithNitro();
4532
+ break;
4247
4533
  default:
4248
4534
  // All other presets (netlify, vercel, deno_deploy, aws-lambda, etc.)
4249
4535
  // are handled natively by Nitro's build API.