@agent-native/core 0.137.7 → 0.138.0

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 (446) hide show
  1. package/agent-native.eject.json +2 -0
  2. package/corpus/README.md +1 -1
  3. package/corpus/templates/analytics/.agents/skills/agent-native-docs/SKILL.md +23 -3
  4. package/corpus/templates/analytics/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  5. package/corpus/templates/analytics/.agents/skills/data-querying/SKILL.md +15 -0
  6. package/corpus/templates/analytics/.agents/skills/frontend-design/SKILL.md +23 -2
  7. package/corpus/templates/analytics/.agents/skills/frontend-design/references/visual-direction.md +99 -0
  8. package/corpus/templates/analytics/AGENTS.md +2 -2
  9. package/corpus/templates/analytics/actions/get-first-party-analytics-health.ts +65 -0
  10. package/corpus/templates/analytics/actions/provider-api-catalog.ts +3 -6
  11. package/corpus/templates/analytics/actions/provider-api-docs.ts +3 -6
  12. package/corpus/templates/analytics/actions/provider-api-request.ts +3 -6
  13. package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +3 -3
  14. package/corpus/templates/analytics/agent-native.json +12 -0
  15. package/corpus/templates/analytics/app/i18n-data.ts +162 -0
  16. package/corpus/templates/analytics/app/pages/DataSources.tsx +126 -1
  17. package/corpus/templates/analytics/changelog/2026-08-05-analytics-now-flags-neon-pressure-and-guides-high-volume-tra.md +6 -0
  18. package/corpus/templates/analytics/changelog/2026-08-05-first-party-analytics-uses-compact-rollups-for-faster-usage-.md +6 -0
  19. package/corpus/templates/analytics/server/db/schema.ts +52 -0
  20. package/corpus/templates/analytics/server/lib/credential-keys.ts +3 -0
  21. package/corpus/templates/analytics/server/lib/first-party-analytics-health.ts +397 -0
  22. package/corpus/templates/analytics/server/lib/first-party-analytics-rollups.ts +182 -0
  23. package/corpus/templates/analytics/server/lib/first-party-analytics.ts +86 -15
  24. package/corpus/templates/analytics/server/lib/provider-api.ts +20 -1
  25. package/corpus/templates/analytics/server/lib/replay-storage.ts +1 -1
  26. package/corpus/templates/analytics/server/plugins/agent-chat.ts +1 -0
  27. package/corpus/templates/analytics/server/plugins/db.ts +60 -0
  28. package/corpus/templates/assets/.agents/skills/agent-native-docs/SKILL.md +23 -3
  29. package/corpus/templates/assets/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  30. package/corpus/templates/assets/.agents/skills/frontend-design/SKILL.md +23 -2
  31. package/corpus/templates/assets/.agents/skills/frontend-design/references/visual-direction.md +99 -0
  32. package/corpus/templates/assets/agent-native.json +12 -0
  33. package/corpus/templates/assets/server/lib/generation.ts +8 -8
  34. package/corpus/templates/assets/server/lib/storage.ts +1 -1
  35. package/corpus/templates/assets/server/plugins/onboarding.ts +1 -1
  36. package/corpus/templates/brain/.agents/skills/agent-native-docs/SKILL.md +23 -3
  37. package/corpus/templates/brain/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  38. package/corpus/templates/brain/.agents/skills/frontend-design/SKILL.md +23 -2
  39. package/corpus/templates/brain/.agents/skills/frontend-design/references/visual-direction.md +99 -0
  40. package/corpus/templates/brain/agent-native.json +12 -0
  41. package/corpus/templates/calendar/.agents/skills/agent-native-docs/SKILL.md +23 -3
  42. package/corpus/templates/calendar/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  43. package/corpus/templates/calendar/.agents/skills/frontend-design/SKILL.md +23 -2
  44. package/corpus/templates/calendar/.agents/skills/frontend-design/references/visual-direction.md +99 -0
  45. package/corpus/templates/calendar/agent-native.json +12 -0
  46. package/corpus/templates/chat/.agents/skills/agent-native-docs/SKILL.md +23 -3
  47. package/corpus/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  48. package/corpus/templates/chat/.agents/skills/frontend-design/SKILL.md +23 -2
  49. package/corpus/templates/chat/.agents/skills/frontend-design/references/visual-direction.md +99 -0
  50. package/corpus/templates/chat/AGENTS.md +3 -0
  51. package/corpus/templates/chat/DESIGN.md +28 -0
  52. package/corpus/templates/chat/agent-native.json +12 -0
  53. package/corpus/templates/clips/.agents/skills/agent-native-docs/SKILL.md +23 -3
  54. package/corpus/templates/clips/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  55. package/corpus/templates/clips/.agents/skills/frontend-design/SKILL.md +23 -2
  56. package/corpus/templates/clips/.agents/skills/frontend-design/references/visual-direction.md +99 -0
  57. package/corpus/templates/clips/actions/cleanup-transcript.ts +2 -2
  58. package/corpus/templates/clips/actions/delete-recording-permanent.ts +3 -0
  59. package/corpus/templates/clips/actions/get-playback-position.ts +68 -0
  60. package/corpus/templates/clips/actions/import-loom-recording.ts +2 -2
  61. package/corpus/templates/clips/actions/save-playback-position.ts +80 -0
  62. package/corpus/templates/clips/actions/set-thumbnail.ts +1 -1
  63. package/corpus/templates/clips/agent-native.json +12 -0
  64. package/corpus/templates/clips/app/components/player/video-player.tsx +54 -5
  65. package/corpus/templates/clips/app/components/recorder/pre-record-panel.tsx +65 -18
  66. package/corpus/templates/clips/app/hooks/use-playback-position.ts +188 -0
  67. package/corpus/templates/clips/app/hooks/use-view-tracking.ts +6 -24
  68. package/corpus/templates/clips/app/i18n/en-US.ts +4 -0
  69. package/corpus/templates/clips/app/lib/playback-position.ts +99 -0
  70. package/corpus/templates/clips/app/lib/viewer-session.ts +29 -0
  71. package/corpus/templates/clips/changelog/2026-08-05-clip-buffering-now-uses-buffering-copy-after-playback.md +6 -0
  72. package/corpus/templates/clips/changelog/2026-08-05-clips-remembers-your-playback-position-when-you-reopen-a-cli.md +6 -0
  73. package/corpus/templates/clips/desktop/package.json +1 -0
  74. package/corpus/templates/clips/desktop/src/app.tsx +70 -6
  75. package/corpus/templates/clips/desktop/src/components/AlertDialog.tsx +131 -0
  76. package/corpus/templates/clips/desktop/src/styles.css +129 -0
  77. package/corpus/templates/clips/learnings.defaults.md +1 -1
  78. package/corpus/templates/clips/server/db/schema.ts +18 -0
  79. package/corpus/templates/clips/server/lib/public-agent-context.ts +1 -1
  80. package/corpus/templates/clips/server/lib/video-storage.ts +1 -1
  81. package/corpus/templates/clips/server/plugins/db.ts +15 -0
  82. package/corpus/templates/clips/server/routes/api/media/index.post.ts +1 -1
  83. package/corpus/templates/content/.agents/skills/agent-native-docs/SKILL.md +23 -3
  84. package/corpus/templates/content/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  85. package/corpus/templates/content/.agents/skills/document-editing/references/databases.md +13 -0
  86. package/corpus/templates/content/.agents/skills/frontend-design/SKILL.md +23 -2
  87. package/corpus/templates/content/.agents/skills/frontend-design/references/visual-direction.md +99 -0
  88. package/corpus/templates/content/AGENTS.md +1 -0
  89. package/corpus/templates/content/actions/_content-database-mutation-lock.ts +41 -0
  90. package/corpus/templates/content/actions/_content-database-row-migration.ts +569 -0
  91. package/corpus/templates/content/actions/_database-source-utils.ts +82 -36
  92. package/corpus/templates/content/actions/_database-utils.ts +5 -0
  93. package/corpus/templates/content/actions/_delete-content-space.ts +25 -11
  94. package/corpus/templates/content/actions/add-database-item.ts +60 -42
  95. package/corpus/templates/content/actions/attach-content-database-source.ts +2 -0
  96. package/corpus/templates/content/actions/configure-document-property.ts +99 -104
  97. package/corpus/templates/content/actions/delete-content-database.ts +19 -7
  98. package/corpus/templates/content/actions/delete-document-property.ts +47 -58
  99. package/corpus/templates/content/actions/delete-document.ts +390 -167
  100. package/corpus/templates/content/actions/disconnect-content-database-source.ts +41 -24
  101. package/corpus/templates/content/actions/duplicate-database-item.ts +63 -31
  102. package/corpus/templates/content/actions/duplicate-database-items.ts +86 -43
  103. package/corpus/templates/content/actions/duplicate-document-property.ts +37 -14
  104. package/corpus/templates/content/actions/migrate-content-database-rows.ts +830 -0
  105. package/corpus/templates/content/actions/move-database-item.ts +14 -0
  106. package/corpus/templates/content/actions/permanently-delete-document.ts +27 -6
  107. package/corpus/templates/content/actions/remove-database-items.ts +13 -0
  108. package/corpus/templates/content/actions/reorder-document-property.ts +45 -46
  109. package/corpus/templates/content/actions/set-document-property.ts +68 -28
  110. package/corpus/templates/content/actions/submit-content-database-form.ts +49 -0
  111. package/corpus/templates/content/actions/transcribe-media.ts +1 -1
  112. package/corpus/templates/content/agent-native.json +12 -0
  113. package/corpus/templates/content/app/components/editor/image-upload.ts +2 -2
  114. package/corpus/templates/content/app/i18n-data.ts +1 -1
  115. package/corpus/templates/content/changelog/2026-08-01-content-can-reorganize-every-row-in-an-existing-database-as-.md +6 -0
  116. package/corpus/templates/content/parity/matrix.md +1 -1
  117. package/corpus/templates/content/parity/matrix.ts +4 -2
  118. package/corpus/templates/content/server/db/schema.ts +30 -0
  119. package/corpus/templates/content/server/plugins/db.ts +24 -0
  120. package/corpus/templates/content/server/plugins/onboarding.ts +2 -2
  121. package/corpus/templates/crm/.agents/skills/agent-native-docs/SKILL.md +23 -3
  122. package/corpus/templates/crm/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  123. package/corpus/templates/crm/agent-native.json +12 -0
  124. package/corpus/templates/design/.agents/skills/agent-native-docs/SKILL.md +23 -3
  125. package/corpus/templates/design/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  126. package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +2 -0
  127. package/corpus/templates/design/.agents/skills/frontend-design/SKILL.md +23 -2
  128. package/corpus/templates/design/.agents/skills/frontend-design/references/visual-direction.md +99 -0
  129. package/corpus/templates/design/CODE_NATIVE_DESIGN_STUDIO_IMPLEMENTATION_PLAN.md +2 -2
  130. package/corpus/templates/design/DESIGN-STUDIO-PLAN.md +2 -2
  131. package/corpus/templates/design/actions/apply-design-token-edit.ts +1 -1
  132. package/corpus/templates/design/actions/capture-design-state.ts +1 -1
  133. package/corpus/templates/design/actions/connect-builder-app.ts +2 -2
  134. package/corpus/templates/design/actions/create-design-branch.ts +1 -1
  135. package/corpus/templates/design/actions/create-fusion-app.ts +3 -3
  136. package/corpus/templates/design/actions/deploy-design-preview.ts +1 -1
  137. package/corpus/templates/design/actions/generate-design.ts +3 -2
  138. package/corpus/templates/design/actions/get-component-details.ts +1 -1
  139. package/corpus/templates/design/actions/get-design-branch-diff.ts +1 -1
  140. package/corpus/templates/design/actions/index-components.ts +3 -3
  141. package/corpus/templates/design/actions/index-design-system-with-builder.ts +1 -1
  142. package/corpus/templates/design/actions/migrate-inline-design-to-app.ts +3 -3
  143. package/corpus/templates/design/actions/open-component-source.ts +1 -1
  144. package/corpus/templates/design/actions/update-design.ts +96 -14
  145. package/corpus/templates/design/agent-native.json +12 -0
  146. package/corpus/templates/design/app/components/design/DesignImportPanel.tsx +7 -2
  147. package/corpus/templates/design/app/components/design/FigmaHydrationDialog.tsx +11 -2
  148. package/corpus/templates/design/app/components/design/edit-panel/component-section.tsx +1 -1
  149. package/corpus/templates/design/app/components/editor/PromptDialog.tsx +8 -1
  150. package/corpus/templates/design/app/i18n-data.ts +53 -22
  151. package/corpus/templates/design/app/lib/design-file-upload.ts +2 -3
  152. package/corpus/templates/design/app/lib/upload-limits.ts +4 -0
  153. package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +1 -1
  154. package/corpus/templates/design/changelog/2026-08-05-chat-attachments-now-warn-before-upload-when-they-exceed-the.md +6 -0
  155. package/corpus/templates/design/changelog/2026-08-05-figma-fig-uploads-now-show-a-clear-4-mb-limit-up-front-inste.md +6 -0
  156. package/corpus/templates/design/scripts/qa-figma-stress-import.ts +1 -1
  157. package/corpus/templates/design/server/handlers/import-design-file.ts +9 -5
  158. package/corpus/templates/design/server/handlers/uploads.ts +13 -9
  159. package/corpus/templates/design/server/lib/fig-file-limits.ts +2 -1
  160. package/corpus/templates/design/server/lib/figma-image-hydration.ts +1 -1
  161. package/corpus/templates/design/server/lib/figma-node-import.ts +1 -1
  162. package/corpus/templates/design/server/lib/request-body-limits.ts +11 -0
  163. package/corpus/templates/design/shared/canvas-frames.ts +81 -0
  164. package/corpus/templates/design/shared/design-source-capabilities.ts +25 -9
  165. package/corpus/templates/dispatch/.agents/skills/agent-native-docs/SKILL.md +23 -3
  166. package/corpus/templates/dispatch/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  167. package/corpus/templates/dispatch/.agents/skills/frontend-design/SKILL.md +23 -2
  168. package/corpus/templates/dispatch/.agents/skills/frontend-design/references/visual-direction.md +99 -0
  169. package/corpus/templates/dispatch/agent-native.json +12 -0
  170. package/corpus/templates/factory/.agents/skills/agent-native-docs/SKILL.md +23 -3
  171. package/corpus/templates/factory/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  172. package/corpus/templates/factory/.agents/skills/frontend-design/SKILL.md +23 -2
  173. package/corpus/templates/factory/.agents/skills/frontend-design/references/visual-direction.md +99 -0
  174. package/corpus/templates/factory/agent-native.json +12 -0
  175. package/corpus/templates/forms/.agents/skills/agent-native-docs/SKILL.md +23 -3
  176. package/corpus/templates/forms/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  177. package/corpus/templates/forms/.agents/skills/frontend-design/SKILL.md +23 -2
  178. package/corpus/templates/forms/.agents/skills/frontend-design/references/visual-direction.md +99 -0
  179. package/corpus/templates/forms/actions/export-responses.ts +1 -1
  180. package/corpus/templates/forms/agent-native.json +12 -0
  181. package/corpus/templates/macros/.agents/skills/agent-native-docs/SKILL.md +23 -3
  182. package/corpus/templates/macros/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  183. package/corpus/templates/macros/.agents/skills/frontend-design/SKILL.md +23 -2
  184. package/corpus/templates/macros/.agents/skills/frontend-design/references/visual-direction.md +99 -0
  185. package/corpus/templates/macros/agent-native.json +12 -0
  186. package/corpus/templates/mail/.agents/skills/agent-native-docs/SKILL.md +23 -3
  187. package/corpus/templates/mail/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  188. package/corpus/templates/mail/.agents/skills/frontend-design/SKILL.md +23 -2
  189. package/corpus/templates/mail/.agents/skills/frontend-design/references/visual-direction.md +99 -0
  190. package/corpus/templates/mail/agent-native.json +12 -0
  191. package/corpus/templates/mail/app/i18n/en-US.ts +1 -1
  192. package/corpus/templates/mail/server/lib/media-upload.ts +1 -1
  193. package/corpus/templates/plan/.agents/skills/agent-native-docs/SKILL.md +23 -3
  194. package/corpus/templates/plan/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  195. package/corpus/templates/plan/.agents/skills/frontend-design/SKILL.md +23 -2
  196. package/corpus/templates/plan/.agents/skills/frontend-design/references/visual-direction.md +99 -0
  197. package/corpus/templates/plan/agent-native.json +12 -0
  198. package/corpus/templates/plan/server/lib/plan-assets.ts +1 -1
  199. package/corpus/templates/slides/.agents/skills/agent-native-docs/SKILL.md +23 -3
  200. package/corpus/templates/slides/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  201. package/corpus/templates/slides/.agents/skills/frontend-design/SKILL.md +23 -2
  202. package/corpus/templates/slides/.agents/skills/frontend-design/references/visual-direction.md +99 -0
  203. package/corpus/templates/slides/actions/generate-image-api.ts +1 -1
  204. package/corpus/templates/slides/actions/generate-slides-ai.ts +1 -1
  205. package/corpus/templates/slides/actions/import-file.ts +2 -2
  206. package/corpus/templates/slides/actions/index-design-system-with-builder.ts +1 -1
  207. package/corpus/templates/slides/agent-native.json +12 -0
  208. package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +1 -1
  209. package/corpus/templates/slides/app/i18n/en-US.ts +2 -2
  210. package/corpus/templates/slides/app/lib/deck-sorting.ts +19 -0
  211. package/corpus/templates/slides/app/lib/image-drop-to-agent.ts +1 -1
  212. package/corpus/templates/slides/app/pages/Index.tsx +7 -2
  213. package/corpus/templates/slides/changelog/2026-08-05-decks-are-now-sorted-by-most-recently-updated.md +6 -0
  214. package/corpus/templates/slides/server/handlers/assets.ts +1 -1
  215. package/corpus/templates/slides/server/handlers/uploads.ts +1 -1
  216. package/corpus/templates/tasks/.agents/skills/agent-native-docs/SKILL.md +23 -3
  217. package/corpus/templates/tasks/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  218. package/corpus/templates/tasks/.agents/skills/frontend-design/SKILL.md +23 -2
  219. package/corpus/templates/tasks/.agents/skills/frontend-design/references/visual-direction.md +99 -0
  220. package/corpus/templates/tasks/agent-native.json +12 -0
  221. package/dist/action.d.ts +6 -0
  222. package/dist/agent/engine/builder-engine.js +2 -2
  223. package/dist/agent/engine/credential-errors.d.ts +1 -1
  224. package/dist/agent/engine/credential-errors.js +2 -2
  225. package/dist/agent/production-agent.js +3 -2
  226. package/dist/brand-kit/fig/index.js +1 -1
  227. package/dist/cli/agent.js +45 -3
  228. package/dist/cli/code-agent-executor.js +2 -1
  229. package/dist/cli/create.d.ts +9 -1
  230. package/dist/cli/create.js +94 -1
  231. package/dist/cli/doctor.d.ts +8 -11
  232. package/dist/cli/doctor.js +92 -24
  233. package/dist/cli/index.js +6 -5
  234. package/dist/client/AgentAskPopover.d.ts +3 -1
  235. package/dist/client/AgentAskPopover.js +2 -2
  236. package/dist/client/AgentPanel.js +9 -3
  237. package/dist/client/AssistantChat.js +54 -33
  238. package/dist/client/MultiTabAssistantChat.js +1 -1
  239. package/dist/client/RouteTransitionIndicator.d.ts +7 -0
  240. package/dist/client/RouteTransitionIndicator.js +31 -0
  241. package/dist/client/agent-engine-key.js +1 -1
  242. package/dist/client/app-providers.js +11 -2
  243. package/dist/client/chat/message-components.js +1 -1
  244. package/dist/client/chat/run-recovery.js +1 -1
  245. package/dist/client/chat/tool-call-display.d.ts +3 -1
  246. package/dist/client/chat/tool-call-display.js +4 -3
  247. package/dist/client/chat-model-groups.d.ts +6 -0
  248. package/dist/client/chat-model-groups.js +11 -0
  249. package/dist/client/error-format.js +1 -1
  250. package/dist/client/i18n.js +1 -1
  251. package/dist/client/onboarding/FirstRunOnboarding.d.ts +5 -1
  252. package/dist/client/onboarding/FirstRunOnboarding.js +29 -13
  253. package/dist/client/onboarding/first-run-enabled.d.ts +6 -1
  254. package/dist/client/onboarding/first-run-enabled.js +33 -3
  255. package/dist/client/onboarding/use-onboarding.js +16 -11
  256. package/dist/client/require-session.js +13 -4
  257. package/dist/client/resources/mcp-integration-catalog.js +26 -0
  258. package/dist/client/resources/mcp-integration-logos.js +4 -0
  259. package/dist/client/route-warmup.js +56 -10
  260. package/dist/client/settings/AccountSettingsCard.js +78 -3
  261. package/dist/client/settings/SettingsPanel.js +1 -1
  262. package/dist/client/settings/VoiceTranscriptionSection.js +2 -2
  263. package/dist/client/settings/useBuilderStatus.js +1 -1
  264. package/dist/client/setup-connections/useBuilderConnectCardController.js +1 -1
  265. package/dist/client/ui/index.d.ts +1 -0
  266. package/dist/client/ui/index.js +1 -0
  267. package/dist/client/uploads/upload-editor-image.js +1 -1
  268. package/dist/client/use-chat-threads.js +3 -0
  269. package/dist/client/use-session.d.ts +11 -0
  270. package/dist/client/use-session.js +34 -6
  271. package/dist/collab/routes.d.ts +2 -2
  272. package/dist/config.d.ts +48 -0
  273. package/dist/config.js +111 -0
  274. package/dist/db/migrations.js +5 -0
  275. package/dist/eject/provider-api-definitions.d.ts +1 -1
  276. package/dist/eject/provider-api-definitions.js +1 -0
  277. package/dist/eject/remote-mcp-presets.js +1 -0
  278. package/dist/extensions/web-search-tool.js +2 -2
  279. package/dist/file-upload/actions/upload-image.js +1 -1
  280. package/dist/file-upload/registry.js +1 -1
  281. package/dist/guards/index.d.ts +3 -0
  282. package/dist/guards/index.js +2 -0
  283. package/dist/guards/no-empty-migrations.d.ts +14 -0
  284. package/dist/guards/no-empty-migrations.js +126 -0
  285. package/dist/index.browser.d.ts +1 -0
  286. package/dist/index.browser.js +3 -0
  287. package/dist/index.d.ts +1 -0
  288. package/dist/index.js +1 -0
  289. package/dist/localization/default-messages.d.ts +24 -0
  290. package/dist/localization/default-messages.js +26 -2
  291. package/dist/notifications/routes.d.ts +6 -6
  292. package/dist/onboarding/app-profile.js +1 -1
  293. package/dist/onboarding/plugin.d.ts +2 -0
  294. package/dist/onboarding/plugin.js +29 -2
  295. package/dist/progress/routes.d.ts +1 -1
  296. package/dist/provider-api/actions/custom-provider-registration.d.ts +16 -16
  297. package/dist/provider-api/actions/provider-api.d.ts +13 -13
  298. package/dist/provider-api/index.d.ts +4 -4
  299. package/dist/provider-api/index.js +35 -0
  300. package/dist/resources/handlers.d.ts +1 -1
  301. package/dist/resources/handlers.js +1 -1
  302. package/dist/scripts/docs/framework-search.d.ts +9 -0
  303. package/dist/scripts/docs/framework-search.js +239 -0
  304. package/dist/scripts/docs/index.js +1 -0
  305. package/dist/scripts/docs/search.d.ts +10 -0
  306. package/dist/scripts/docs/search.js +1 -1
  307. package/dist/scripts/docs/source-search.d.ts +10 -2
  308. package/dist/scripts/docs/source-search.js +108 -41
  309. package/dist/search-utils/index.d.ts +11 -0
  310. package/dist/search-utils/index.js +72 -0
  311. package/dist/server/action-change.d.ts +6 -0
  312. package/dist/server/action-change.js +28 -14
  313. package/dist/server/action-discovery.js +9 -0
  314. package/dist/server/action-routes.js +1 -0
  315. package/dist/server/agent-chat/browser-team-tools.js +1 -1
  316. package/dist/server/agent-chat/script-entries.js +43 -2
  317. package/dist/server/auth-login-mode.d.ts +8 -0
  318. package/dist/server/auth-login-mode.js +17 -0
  319. package/dist/server/auth.js +100 -15
  320. package/dist/server/better-auth-instance.d.ts +36 -0
  321. package/dist/server/better-auth-instance.js +25 -3
  322. package/dist/server/builder-design-systems.js +1 -1
  323. package/dist/server/core-routes-plugin.js +17 -14
  324. package/dist/server/credential-provider.js +3 -3
  325. package/dist/server/email-templates.d.ts +7 -0
  326. package/dist/server/email-templates.js +24 -0
  327. package/dist/server/email.d.ts +17 -0
  328. package/dist/server/email.js +22 -1
  329. package/dist/server/framework-request-handler.js +6 -0
  330. package/dist/server/onboarding-html.d.ts +2 -0
  331. package/dist/server/onboarding-html.js +169 -8
  332. package/dist/server/realtime-token.d.ts +1 -1
  333. package/dist/server/realtime-voice.js +1 -1
  334. package/dist/server/sentry.d.ts +1 -1
  335. package/dist/server/transcribe-voice.js +3 -3
  336. package/dist/shared/first-run-onboarding.d.ts +1 -0
  337. package/dist/shared/first-run-onboarding.js +1 -0
  338. package/dist/templates/chat/.agents/skills/agent-native-docs/SKILL.md +23 -3
  339. package/dist/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  340. package/dist/templates/chat/.agents/skills/frontend-design/SKILL.md +23 -2
  341. package/dist/templates/chat/.agents/skills/frontend-design/references/visual-direction.md +99 -0
  342. package/dist/templates/chat/AGENTS.md +3 -0
  343. package/dist/templates/chat/DESIGN.md +28 -0
  344. package/dist/templates/chat/agent-native.json +12 -0
  345. package/dist/templates/default/.agents/skills/agent-native-docs/SKILL.md +23 -3
  346. package/dist/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  347. package/dist/templates/default/.agents/skills/frontend-design/SKILL.md +23 -2
  348. package/dist/templates/default/.agents/skills/frontend-design/references/visual-direction.md +99 -0
  349. package/dist/templates/default/AGENTS.md +4 -0
  350. package/dist/templates/default/DESIGN.md +30 -0
  351. package/dist/templates/default/agent-native.json +9 -0
  352. package/dist/templates/default/app/i18n/ar-SA.ts +2 -2
  353. package/dist/templates/default/app/i18n/de-DE.ts +2 -2
  354. package/dist/templates/default/app/i18n/en-US.ts +2 -2
  355. package/dist/templates/default/app/i18n/es-ES.ts +2 -2
  356. package/dist/templates/default/app/i18n/fr-FR.ts +2 -2
  357. package/dist/templates/default/app/i18n/hi-IN.ts +2 -2
  358. package/dist/templates/default/app/i18n/ja-JP.ts +2 -2
  359. package/dist/templates/default/app/i18n/ko-KR.ts +2 -2
  360. package/dist/templates/default/app/i18n/pt-BR.ts +2 -2
  361. package/dist/templates/default/app/i18n/zh-CN.ts +2 -2
  362. package/dist/templates/default/app/i18n/zh-TW.ts +1 -1
  363. package/dist/templates/default/package.json +1 -0
  364. package/dist/templates/headless/.agents/skills/agent-native-docs/SKILL.md +23 -3
  365. package/dist/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  366. package/dist/templates/headless/agent-native.json +9 -0
  367. package/dist/templates/headless/package.json +2 -0
  368. package/dist/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +23 -3
  369. package/dist/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  370. package/dist/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +23 -2
  371. package/dist/templates/workspace-core/.agents/skills/frontend-design/references/visual-direction.md +99 -0
  372. package/dist/templates/workspace-core/AGENTS.md +3 -0
  373. package/dist/templates/workspace-core/DESIGN.md +35 -0
  374. package/dist/templates/workspace-root/AGENTS.md +3 -0
  375. package/dist/templates/workspace-root/DESIGN.md +35 -0
  376. package/dist/templates/workspace-root/agent-native.json +9 -0
  377. package/dist/templates/workspace-root/package.json +3 -0
  378. package/dist/transcription/builder-transcription.js +1 -1
  379. package/dist/user-profile/actions/change-password.d.ts +8 -0
  380. package/dist/user-profile/actions/change-password.js +24 -0
  381. package/dist/user-profile/actions/get-auth-methods.d.ts +6 -0
  382. package/dist/user-profile/actions/get-auth-methods.js +23 -0
  383. package/dist/user-profile/actions/set-password.d.ts +7 -0
  384. package/dist/user-profile/actions/set-password.js +23 -0
  385. package/dist/vite/client.d.ts +8 -1
  386. package/dist/vite/client.js +63 -12
  387. package/dist/vite/index.d.ts +1 -0
  388. package/dist/vite/index.js +1 -0
  389. package/docs/AGENTS.md +7 -2
  390. package/docs/SKILL.md +7 -5
  391. package/docs/content/agent-native-config.mdx +165 -0
  392. package/docs/content/agent-native-toolkit.mdx +1 -1
  393. package/docs/content/deployment.mdx +7 -2
  394. package/docs/content/doctor.mdx +21 -13
  395. package/docs/content/environment-variables.mdx +158 -0
  396. package/docs/content/file-uploads.mdx +1 -1
  397. package/docs/content/getting-started.mdx +1 -1
  398. package/docs/content/key-concepts.mdx +1 -1
  399. package/docs/content/multi-app-workspace.mdx +1 -1
  400. package/docs/content/template-clips-ai-and-editing.mdx +6 -6
  401. package/docs/content/template-clips-developers.mdx +3 -3
  402. package/docs/content/toolkit-settings.mdx +1 -1
  403. package/docs/content/voice-input.mdx +4 -4
  404. package/package.json +6 -2
  405. package/src/eject/provider-api-definitions.ts +1 -0
  406. package/src/eject/remote-mcp-presets.ts +1 -0
  407. package/src/templates/chat/.agents/skills/agent-native-docs/SKILL.md +23 -3
  408. package/src/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  409. package/src/templates/chat/.agents/skills/frontend-design/SKILL.md +23 -2
  410. package/src/templates/chat/.agents/skills/frontend-design/references/visual-direction.md +99 -0
  411. package/src/templates/chat/AGENTS.md +3 -0
  412. package/src/templates/chat/DESIGN.md +28 -0
  413. package/src/templates/chat/agent-native.json +12 -0
  414. package/src/templates/default/.agents/skills/agent-native-docs/SKILL.md +23 -3
  415. package/src/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  416. package/src/templates/default/.agents/skills/frontend-design/SKILL.md +23 -2
  417. package/src/templates/default/.agents/skills/frontend-design/references/visual-direction.md +99 -0
  418. package/src/templates/default/AGENTS.md +4 -0
  419. package/src/templates/default/DESIGN.md +30 -0
  420. package/src/templates/default/agent-native.json +9 -0
  421. package/src/templates/default/app/i18n/ar-SA.ts +2 -2
  422. package/src/templates/default/app/i18n/de-DE.ts +2 -2
  423. package/src/templates/default/app/i18n/en-US.ts +2 -2
  424. package/src/templates/default/app/i18n/es-ES.ts +2 -2
  425. package/src/templates/default/app/i18n/fr-FR.ts +2 -2
  426. package/src/templates/default/app/i18n/hi-IN.ts +2 -2
  427. package/src/templates/default/app/i18n/ja-JP.ts +2 -2
  428. package/src/templates/default/app/i18n/ko-KR.ts +2 -2
  429. package/src/templates/default/app/i18n/pt-BR.ts +2 -2
  430. package/src/templates/default/app/i18n/zh-CN.ts +2 -2
  431. package/src/templates/default/app/i18n/zh-TW.ts +1 -1
  432. package/src/templates/default/package.json +1 -0
  433. package/src/templates/headless/.agents/skills/agent-native-docs/SKILL.md +23 -3
  434. package/src/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  435. package/src/templates/headless/agent-native.json +9 -0
  436. package/src/templates/headless/package.json +2 -0
  437. package/src/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +23 -3
  438. package/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
  439. package/src/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +23 -2
  440. package/src/templates/workspace-core/.agents/skills/frontend-design/references/visual-direction.md +99 -0
  441. package/src/templates/workspace-core/AGENTS.md +3 -0
  442. package/src/templates/workspace-core/DESIGN.md +35 -0
  443. package/src/templates/workspace-root/AGENTS.md +3 -0
  444. package/src/templates/workspace-root/DESIGN.md +35 -0
  445. package/src/templates/workspace-root/agent-native.json +9 -0
  446. package/src/templates/workspace-root/package.json +3 -0
@@ -0,0 +1,830 @@
1
+ import { defineAction } from "@agent-native/core";
2
+ import { writeAppState } from "@agent-native/core/application-state";
3
+ import { isLocalDatabase, isPostgres } from "@agent-native/core/db";
4
+ import { assertAccess } from "@agent-native/core/sharing";
5
+ import { and, eq, inArray } from "drizzle-orm";
6
+ import { z } from "zod";
7
+
8
+ import { getDb, schema } from "../server/db/index.js";
9
+ import {
10
+ lockContentDatabaseMutation,
11
+ touchContentDatabase,
12
+ withContentDatabaseMutationLock,
13
+ } from "./_content-database-mutation-lock.js";
14
+ import {
15
+ applyMigration,
16
+ deterministicId,
17
+ digest,
18
+ migrationPlanSchema,
19
+ snapshotDigest,
20
+ snapshotMigration,
21
+ serializeMigrationValue,
22
+ validatePlan,
23
+ } from "./_content-database-row-migration.js";
24
+ import { lockDatabaseMemberships } from "./_database-membership-lock.js";
25
+ import { flushOpenDocumentEditorToSql } from "./_document-flush.js";
26
+
27
+ const operationalSchema = z.discriminatedUnion("phase", [
28
+ z.object({ phase: z.literal("validate"), plan: migrationPlanSchema }),
29
+ z.object({ phase: z.literal("apply"), plan: migrationPlanSchema }),
30
+ z.object({
31
+ phase: z.literal("verify"),
32
+ databaseId: z.string().min(1),
33
+ idempotencyKey: z.string().min(1),
34
+ expectedPostDigest: z.string().min(1),
35
+ }),
36
+ z.object({
37
+ phase: z.literal("rollback"),
38
+ databaseId: z.string().min(1),
39
+ idempotencyKey: z.string().min(1),
40
+ expectedPostDigest: z.string().min(1),
41
+ }),
42
+ z.object({
43
+ phase: z.literal("finalize"),
44
+ databaseId: z.string().min(1),
45
+ idempotencyKey: z.string().min(1),
46
+ expectedPostDigest: z.string().min(1),
47
+ }),
48
+ ]);
49
+
50
+ function parseJson(text: string) {
51
+ try {
52
+ return JSON.parse(text) as any;
53
+ } catch {
54
+ throw new Error("Migration receipt is corrupt.");
55
+ }
56
+ }
57
+ function receiptResult(receipt: any, replayed: boolean) {
58
+ const {
59
+ plan: _plan,
60
+ transitionExpectedPostDigest: _transitionExpectedPostDigest,
61
+ ...result
62
+ } = parseJson(receipt.resultJson);
63
+ return {
64
+ ...result,
65
+ receiptId: receipt.id,
66
+ state: receipt.state,
67
+ preDigest: receipt.preDigest,
68
+ postDigest: receipt.postDigest,
69
+ replayed,
70
+ verified: result.verified === true,
71
+ };
72
+ }
73
+
74
+ async function lockCurrentDatabaseMemberships(tx: any, databaseId: string) {
75
+ const memberships = await tx
76
+ .select({ id: schema.contentDatabaseItems.id })
77
+ .from(schema.contentDatabaseItems)
78
+ .where(eq(schema.contentDatabaseItems.databaseId, databaseId));
79
+ await lockDatabaseMemberships(
80
+ tx,
81
+ memberships.map((membership: { id: string }) => membership.id),
82
+ );
83
+ }
84
+
85
+ async function flushMigrationDocuments(rows: Array<{ documentId: string }>) {
86
+ const accesses = await Promise.all(
87
+ rows.map((row) => assertAccess("document", row.documentId, "editor")),
88
+ );
89
+ const flushes = await Promise.allSettled(
90
+ rows.map((row, index) =>
91
+ flushOpenDocumentEditorToSql({
92
+ documentId: row.documentId,
93
+ ownerEmail: accesses[index]?.resource.ownerEmail,
94
+ }),
95
+ ),
96
+ );
97
+ const failed = flushes.find(
98
+ (flush): flush is PromiseRejectedResult => flush.status === "rejected",
99
+ );
100
+ if (failed) throw failed.reason;
101
+ }
102
+
103
+ export default defineAction({
104
+ description:
105
+ "Atomically migrate every active row in one ordinary Content database without attached Sources: validates an exact bounded plan, snapshots bodies, writes only new safe properties, and supports guarded rollback or legacy-property finalization.",
106
+ schema: operationalSchema,
107
+ audit: {
108
+ recordInputs: false,
109
+ target: (args) => ({
110
+ type: "content-database",
111
+ id:
112
+ args.phase === "apply" || args.phase === "validate"
113
+ ? args.plan.databaseId
114
+ : args.databaseId,
115
+ visibility: "private",
116
+ }),
117
+ },
118
+ needsApproval: (args) =>
119
+ args.phase === "rollback" || args.phase === "finalize",
120
+ run: async (args) => {
121
+ const db = getDb();
122
+ const databaseId =
123
+ args.phase === "apply" || args.phase === "validate"
124
+ ? args.plan.databaseId
125
+ : args.databaseId;
126
+ const localDatabase = isLocalDatabase();
127
+ const flushUnderDurableLock = isPostgres() && !localDatabase;
128
+ return withContentDatabaseMutationLock(databaseId, async () => {
129
+ const [database] = await db
130
+ .select()
131
+ .from(schema.contentDatabases)
132
+ .where(eq(schema.contentDatabases.id, databaseId));
133
+ if (!database) throw new Error("Database not found.");
134
+ await assertAccess("document", database.documentId, "admin");
135
+ if (args.phase === "apply") {
136
+ const replay = await db.transaction(async (tx) => {
137
+ const [existing] = await tx
138
+ .select()
139
+ .from(schema.contentDatabaseMigrationReceipts)
140
+ .where(
141
+ and(
142
+ eq(
143
+ schema.contentDatabaseMigrationReceipts.databaseId,
144
+ args.plan.databaseId,
145
+ ),
146
+ eq(
147
+ schema.contentDatabaseMigrationReceipts.idempotencyKey,
148
+ args.plan.idempotencyKey,
149
+ ),
150
+ ),
151
+ );
152
+ const planHash = digest(args.plan);
153
+ if (existing) {
154
+ if (existing.planHash !== planHash)
155
+ throw new Error(
156
+ "Idempotency key was already used with a different migration plan.",
157
+ );
158
+ if (existing.state !== "applied" && existing.state !== "verified")
159
+ throw new Error(
160
+ `Migration receipt is already ${existing.state}.`,
161
+ );
162
+ if (
163
+ snapshotDigest(
164
+ await snapshotMigration(tx, args.plan.databaseId),
165
+ ) !== existing.postDigest
166
+ )
167
+ throw new Error(
168
+ "Applied migration has drifted; replay is refused.",
169
+ );
170
+ return receiptResult(existing, true);
171
+ }
172
+ validatePlan(
173
+ args.plan,
174
+ await snapshotMigration(tx, args.plan.databaseId),
175
+ );
176
+ return null;
177
+ });
178
+ if (replay) return replay;
179
+ if (!localDatabase && !flushUnderDurableLock) {
180
+ throw new Error(
181
+ "Database row migration requires PostgreSQL or a local SQLite/PGlite database so live editor saves can be serialized safely.",
182
+ );
183
+ }
184
+ if (!flushUnderDurableLock) {
185
+ await flushMigrationDocuments(args.plan.rows);
186
+ }
187
+ }
188
+ if (args.phase === "rollback") {
189
+ const preflight = await db.transaction(async (tx) => {
190
+ const [receipt] = await tx
191
+ .select()
192
+ .from(schema.contentDatabaseMigrationReceipts)
193
+ .where(
194
+ and(
195
+ eq(
196
+ schema.contentDatabaseMigrationReceipts.databaseId,
197
+ args.databaseId,
198
+ ),
199
+ eq(
200
+ schema.contentDatabaseMigrationReceipts.idempotencyKey,
201
+ args.idempotencyKey,
202
+ ),
203
+ ),
204
+ );
205
+ if (!receipt) throw new Error("Migration receipt not found.");
206
+ const result = parseJson(receipt.resultJson);
207
+ const current = await snapshotMigration(tx, args.databaseId);
208
+ if (receipt.state === "rolled_back") {
209
+ if (
210
+ result.transitionExpectedPostDigest !== args.expectedPostDigest ||
211
+ snapshotDigest(current) !== receipt.postDigest
212
+ )
213
+ throw new Error(
214
+ "Terminal migration result has drifted; replay is refused.",
215
+ );
216
+ return { replay: receiptResult(receipt, true), versions: [] };
217
+ }
218
+ if (receipt.state !== "applied" && receipt.state !== "verified")
219
+ throw new Error(`Migration receipt is already ${receipt.state}.`);
220
+ if (
221
+ receipt.postDigest !== args.expectedPostDigest ||
222
+ snapshotDigest(current) !== receipt.postDigest
223
+ )
224
+ throw new Error(
225
+ "Migration has drifted; guarded operation is refused.",
226
+ );
227
+ return {
228
+ replay: null,
229
+ versions: parseJson(receipt.rollbackJson).versions ?? [],
230
+ };
231
+ });
232
+ if (preflight.replay) return preflight.replay;
233
+ if (!localDatabase && !flushUnderDurableLock) {
234
+ throw new Error(
235
+ "Database row migration requires PostgreSQL or a local SQLite/PGlite database so live editor saves can be serialized safely.",
236
+ );
237
+ }
238
+ if (!flushUnderDurableLock) {
239
+ await flushMigrationDocuments(preflight.versions);
240
+ }
241
+ }
242
+ if (args.phase === "verify" || args.phase === "finalize") {
243
+ const [receipt] = await db
244
+ .select()
245
+ .from(schema.contentDatabaseMigrationReceipts)
246
+ .where(
247
+ and(
248
+ eq(
249
+ schema.contentDatabaseMigrationReceipts.databaseId,
250
+ args.databaseId,
251
+ ),
252
+ eq(
253
+ schema.contentDatabaseMigrationReceipts.idempotencyKey,
254
+ args.idempotencyKey,
255
+ ),
256
+ ),
257
+ );
258
+ if (!receipt) throw new Error("Migration receipt not found.");
259
+ if (receipt.state === "applied" || receipt.state === "verified") {
260
+ const plan = parseJson(receipt.resultJson).plan;
261
+ if (!plan)
262
+ throw new Error("Migration receipt lacks its verification plan.");
263
+ for (const row of plan.rows)
264
+ await assertAccess(
265
+ "document",
266
+ row.documentId,
267
+ args.phase === "finalize" ? "editor" : "viewer",
268
+ );
269
+ }
270
+ }
271
+ if (args.phase === "verify" || args.phase === "finalize") {
272
+ const replay = await db.transaction(async (tx) => {
273
+ const [receipt] = await tx
274
+ .select()
275
+ .from(schema.contentDatabaseMigrationReceipts)
276
+ .where(
277
+ and(
278
+ eq(
279
+ schema.contentDatabaseMigrationReceipts.databaseId,
280
+ args.databaseId,
281
+ ),
282
+ eq(
283
+ schema.contentDatabaseMigrationReceipts.idempotencyKey,
284
+ args.idempotencyKey,
285
+ ),
286
+ ),
287
+ );
288
+ if (!receipt) throw new Error("Migration receipt not found.");
289
+ const storedResult = parseJson(receipt.resultJson);
290
+ const isTerminalReplay =
291
+ (args.phase === "verify" && receipt.state === "verified") ||
292
+ (args.phase === "finalize" && receipt.state === "finalized");
293
+ if (!isTerminalReplay) return null;
294
+ const expectedDigest =
295
+ args.phase === "verify"
296
+ ? receipt.postDigest
297
+ : storedResult.transitionExpectedPostDigest;
298
+ if (expectedDigest !== args.expectedPostDigest)
299
+ throw new Error(
300
+ "Expected post-migration digest does not match receipt.",
301
+ );
302
+ if (
303
+ snapshotDigest(await snapshotMigration(tx, args.databaseId)) !==
304
+ receipt.postDigest
305
+ )
306
+ throw new Error(
307
+ args.phase === "verify"
308
+ ? "Migration has drifted; verification is refused."
309
+ : "Terminal migration result has drifted; replay is refused.",
310
+ );
311
+ return receiptResult(receipt, true);
312
+ });
313
+ if (replay) return replay;
314
+ }
315
+ let mutated = false;
316
+ const result = await db.transaction(async (tx) => {
317
+ if (args.phase !== "validate") {
318
+ await lockContentDatabaseMutation(
319
+ tx as unknown as ReturnType<typeof getDb>,
320
+ databaseId,
321
+ );
322
+ await lockCurrentDatabaseMemberships(tx, databaseId);
323
+ }
324
+ if (args.phase === "validate" || args.phase === "apply") {
325
+ const planHash = digest(args.plan);
326
+ if (args.phase === "apply") {
327
+ const [existing] = await tx
328
+ .select()
329
+ .from(schema.contentDatabaseMigrationReceipts)
330
+ .where(
331
+ and(
332
+ eq(
333
+ schema.contentDatabaseMigrationReceipts.databaseId,
334
+ args.plan.databaseId,
335
+ ),
336
+ eq(
337
+ schema.contentDatabaseMigrationReceipts.idempotencyKey,
338
+ args.plan.idempotencyKey,
339
+ ),
340
+ ),
341
+ );
342
+ if (existing) {
343
+ if (existing.planHash !== planHash)
344
+ throw new Error(
345
+ "Idempotency key was already used with a different migration plan.",
346
+ );
347
+ if (existing.state !== "applied" && existing.state !== "verified")
348
+ throw new Error(
349
+ `Migration receipt is already ${existing.state}.`,
350
+ );
351
+ const current = await snapshotMigration(tx, args.plan.databaseId);
352
+ if (snapshotDigest(current) !== existing.postDigest)
353
+ throw new Error(
354
+ "Applied migration has drifted; replay is refused.",
355
+ );
356
+ return receiptResult(existing, true);
357
+ }
358
+ // A separate server can run the same migration while an editor is
359
+ // saving. Keep the durable database lock across the flush so that
360
+ // save is part of the state reloaded and validated by this writer.
361
+ if (flushUnderDurableLock) {
362
+ validatePlan(
363
+ args.plan,
364
+ await snapshotMigration(tx, args.plan.databaseId),
365
+ );
366
+ await flushMigrationDocuments(args.plan.rows);
367
+ }
368
+ }
369
+ const snapshot = await snapshotMigration(tx, args.plan.databaseId);
370
+ validatePlan(args.plan, snapshot);
371
+ const preDigest = snapshotDigest(snapshot);
372
+ const orderedIds = snapshot.rows.map((row: any) => ({
373
+ itemId: row.item.id,
374
+ documentId: row.document.id,
375
+ }));
376
+ if (args.phase === "validate")
377
+ return {
378
+ phase: "validate",
379
+ planHash,
380
+ preDigest,
381
+ counts: {
382
+ rows: snapshot.rows.length,
383
+ properties: args.plan.propertyDefinitions.length,
384
+ },
385
+ orderedIds,
386
+ written: 0,
387
+ replayed: false,
388
+ verified: false,
389
+ };
390
+ const receiptId = deterministicId(
391
+ "migration_receipt",
392
+ args.plan.databaseId,
393
+ args.plan.idempotencyKey,
394
+ );
395
+ const now = new Date().toISOString();
396
+ await tx.insert(schema.contentDatabaseMigrationReceipts).values({
397
+ id: receiptId,
398
+ ownerEmail: snapshot.database.ownerEmail,
399
+ orgId: snapshot.database.orgId,
400
+ databaseId: args.plan.databaseId,
401
+ databaseDocumentId: args.plan.databaseDocumentId,
402
+ idempotencyKey: args.plan.idempotencyKey,
403
+ planHash,
404
+ state: "applying",
405
+ preDigest,
406
+ postDigest: preDigest,
407
+ rollbackJson: "{}",
408
+ resultJson: JSON.stringify({ phase: "apply", plan: args.plan }),
409
+ createdAt: now,
410
+ updatedAt: now,
411
+ });
412
+ const rollback = await applyMigration(
413
+ tx,
414
+ args.plan,
415
+ snapshot,
416
+ receiptId,
417
+ now,
418
+ );
419
+ const current = await snapshotMigration(tx, args.plan.databaseId);
420
+ const postDigest = snapshotDigest(current);
421
+ const resultJson = {
422
+ phase: "apply",
423
+ planHash,
424
+ legacyPropertyIds: args.plan.legacyPropertyIds,
425
+ counts: {
426
+ rows: args.plan.rows.length,
427
+ properties: args.plan.propertyDefinitions.length,
428
+ },
429
+ orderedIds,
430
+ written: args.plan.rows.length,
431
+ verified: false,
432
+ plan: args.plan,
433
+ };
434
+ const claimed = await tx
435
+ .update(schema.contentDatabaseMigrationReceipts)
436
+ .set({
437
+ state: "applied",
438
+ postDigest,
439
+ rollbackJson: JSON.stringify(rollback),
440
+ resultJson: JSON.stringify(resultJson),
441
+ updatedAt: now,
442
+ })
443
+ .where(
444
+ and(
445
+ eq(schema.contentDatabaseMigrationReceipts.id, receiptId),
446
+ eq(schema.contentDatabaseMigrationReceipts.state, "applying"),
447
+ ),
448
+ )
449
+ .returning({ id: schema.contentDatabaseMigrationReceipts.id });
450
+ if (claimed.length !== 1)
451
+ throw new Error("Migration receipt claim was lost.");
452
+ mutated = true;
453
+ return {
454
+ phase: "apply",
455
+ planHash,
456
+ legacyPropertyIds: args.plan.legacyPropertyIds,
457
+ counts: resultJson.counts,
458
+ orderedIds,
459
+ written: args.plan.rows.length,
460
+ verified: false,
461
+ receiptId,
462
+ state: "applied",
463
+ preDigest,
464
+ postDigest,
465
+ replayed: false,
466
+ };
467
+ }
468
+ const [receipt] = await tx
469
+ .select()
470
+ .from(schema.contentDatabaseMigrationReceipts)
471
+ .where(
472
+ and(
473
+ eq(
474
+ schema.contentDatabaseMigrationReceipts.databaseId,
475
+ args.databaseId,
476
+ ),
477
+ eq(
478
+ schema.contentDatabaseMigrationReceipts.idempotencyKey,
479
+ args.idempotencyKey,
480
+ ),
481
+ ),
482
+ );
483
+ if (!receipt) throw new Error("Migration receipt not found.");
484
+ const storedResult = parseJson(receipt.resultJson);
485
+ if (args.phase === "verify" && receipt.state === "verified") {
486
+ if (receipt.postDigest !== args.expectedPostDigest)
487
+ throw new Error(
488
+ "Expected post-migration digest does not match receipt.",
489
+ );
490
+ if (
491
+ snapshotDigest(await snapshotMigration(tx, args.databaseId)) !==
492
+ receipt.postDigest
493
+ )
494
+ throw new Error("Migration has drifted; verification is refused.");
495
+ return receiptResult(receipt, true);
496
+ }
497
+ if (
498
+ (args.phase === "rollback" && receipt.state === "rolled_back") ||
499
+ (args.phase === "finalize" && receipt.state === "finalized")
500
+ ) {
501
+ if (
502
+ storedResult.transitionExpectedPostDigest !==
503
+ args.expectedPostDigest
504
+ )
505
+ throw new Error(
506
+ "Expected post-migration digest does not match receipt.",
507
+ );
508
+ if (
509
+ snapshotDigest(await snapshotMigration(tx, args.databaseId)) !==
510
+ receipt.postDigest
511
+ )
512
+ throw new Error(
513
+ "Terminal migration result has drifted; replay is refused.",
514
+ );
515
+ return receiptResult(receipt, true);
516
+ }
517
+ if (args.phase === "verify") {
518
+ if (receipt.state !== "applied" && receipt.state !== "verified")
519
+ throw new Error(`Migration receipt is already ${receipt.state}.`);
520
+ if (receipt.postDigest !== args.expectedPostDigest)
521
+ throw new Error(
522
+ "Expected post-migration digest does not match receipt.",
523
+ );
524
+ const current = await snapshotMigration(tx, args.databaseId);
525
+ if (snapshotDigest(current) !== receipt.postDigest)
526
+ throw new Error("Migration has drifted; verification is refused.");
527
+ const plan = parseJson(receipt.resultJson).plan;
528
+ if (!plan)
529
+ throw new Error("Migration receipt lacks its verification plan.");
530
+ const newDefinitions = new Map(
531
+ plan.propertyDefinitions.map((definition: any) => [
532
+ definition.id,
533
+ definition,
534
+ ]),
535
+ );
536
+ if (
537
+ current.definitions.filter((definition: any) =>
538
+ newDefinitions.has(definition.id),
539
+ ).length !== plan.propertyDefinitions.length
540
+ )
541
+ throw new Error(
542
+ "Migration verification found a property definition count mismatch.",
543
+ );
544
+ for (const definition of plan.propertyDefinitions) {
545
+ const actual = current.definitions.find(
546
+ (candidate: any) => candidate.id === definition.id,
547
+ );
548
+ const optionsJson = JSON.stringify(
549
+ definition.type === "multi_select"
550
+ ? { options: definition.options }
551
+ : {},
552
+ );
553
+ if (
554
+ !actual ||
555
+ actual.name !== definition.name.trim() ||
556
+ actual.type !== definition.type ||
557
+ actual.visibility !== definition.visibility ||
558
+ actual.optionsJson !== optionsJson
559
+ )
560
+ throw new Error(
561
+ "Migration verification found a property definition mismatch.",
562
+ );
563
+ }
564
+ for (const row of plan.rows) {
565
+ const persisted = current.rows.find(
566
+ (candidate: any) =>
567
+ candidate.item.id === row.itemId &&
568
+ candidate.document.id === row.documentId,
569
+ );
570
+ if (!persisted || persisted.document.content !== row.content)
571
+ throw new Error(
572
+ "Migration verification found a row body mismatch.",
573
+ );
574
+ for (const value of row.propertyValues) {
575
+ const actual = current.values.find(
576
+ (candidate: any) =>
577
+ candidate.documentId === row.documentId &&
578
+ candidate.propertyId === value.propertyId,
579
+ )?.valueJson;
580
+ if (
581
+ actual !==
582
+ serializeMigrationValue(
583
+ newDefinitions.get(value.propertyId) as any,
584
+ value.value,
585
+ )
586
+ )
587
+ throw new Error(
588
+ "Migration verification found a new property mismatch.",
589
+ );
590
+ }
591
+ for (const protectedValue of row.protectedPropertyValues) {
592
+ const actual =
593
+ current.values.find(
594
+ (candidate: any) =>
595
+ candidate.documentId === row.documentId &&
596
+ candidate.propertyId === protectedValue.propertyId,
597
+ )?.valueJson ?? "null";
598
+ if (actual !== protectedValue.valueJson)
599
+ throw new Error(
600
+ "Migration verification found a protected property mismatch.",
601
+ );
602
+ }
603
+ }
604
+ const now = new Date().toISOString();
605
+ const resultJson = {
606
+ ...parseJson(receipt.resultJson),
607
+ phase: "verify",
608
+ verified: true,
609
+ };
610
+ const transitioned = await tx
611
+ .update(schema.contentDatabaseMigrationReceipts)
612
+ .set({
613
+ state: "verified",
614
+ resultJson: JSON.stringify(resultJson),
615
+ updatedAt: now,
616
+ })
617
+ .where(
618
+ and(
619
+ eq(schema.contentDatabaseMigrationReceipts.id, receipt.id),
620
+ eq(schema.contentDatabaseMigrationReceipts.state, "applied"),
621
+ ),
622
+ )
623
+ .returning({ id: schema.contentDatabaseMigrationReceipts.id });
624
+ if (transitioned.length !== 1)
625
+ throw new Error("Migration receipt state changed during verify.");
626
+ mutated = true;
627
+ return {
628
+ receiptId: receipt.id,
629
+ state: "verified",
630
+ preDigest: receipt.preDigest,
631
+ postDigest: receipt.postDigest,
632
+ replayed: false,
633
+ verified: true,
634
+ };
635
+ }
636
+ if (args.phase === "finalize" && receipt.state !== "verified")
637
+ throw new Error(
638
+ "Migration receipt must be verified before finalization.",
639
+ );
640
+ if (
641
+ args.phase === "rollback" &&
642
+ receipt.state !== "applied" &&
643
+ receipt.state !== "verified"
644
+ )
645
+ throw new Error(`Migration receipt is already ${receipt.state}.`);
646
+ if (receipt.postDigest !== args.expectedPostDigest)
647
+ throw new Error(
648
+ "Expected post-migration digest does not match receipt.",
649
+ );
650
+ if (args.phase === "rollback" && flushUnderDurableLock) {
651
+ await flushMigrationDocuments(
652
+ parseJson(receipt.rollbackJson).versions ?? [],
653
+ );
654
+ }
655
+ const current = await snapshotMigration(tx, args.databaseId);
656
+ if (snapshotDigest(current) !== receipt.postDigest)
657
+ throw new Error(
658
+ "Migration has drifted; guarded operation is refused.",
659
+ );
660
+ const rollback = parseJson(receipt.rollbackJson);
661
+ const now = new Date().toISOString();
662
+ if (args.phase === "rollback") {
663
+ for (const prior of rollback.versions ?? []) {
664
+ const [version] = await tx
665
+ .select()
666
+ .from(schema.documentVersions)
667
+ .where(eq(schema.documentVersions.id, prior.versionId));
668
+ if (!version) throw new Error("Rollback snapshot is missing.");
669
+ const restoredRows = await tx
670
+ .update(schema.documents)
671
+ .set({
672
+ title: version.title,
673
+ content: version.content,
674
+ updatedAt: now,
675
+ })
676
+ .where(
677
+ and(
678
+ eq(schema.documents.id, prior.documentId),
679
+ eq(schema.documents.updatedAt, prior.appliedUpdatedAt),
680
+ ),
681
+ )
682
+ .returning({ id: schema.documents.id });
683
+ if (restoredRows.length !== 1)
684
+ throw new Error(
685
+ `Rollback row ${prior.documentId} changed concurrently.`,
686
+ );
687
+ }
688
+ const ids = rollback.createdPropertyIds ?? [];
689
+ if (ids.length) {
690
+ await tx
691
+ .delete(schema.documentPropertyValues)
692
+ .where(inArray(schema.documentPropertyValues.propertyId, ids));
693
+ await tx
694
+ .delete(schema.documentPropertyDefinitions)
695
+ .where(inArray(schema.documentPropertyDefinitions.id, ids));
696
+ }
697
+ await tx
698
+ .update(schema.contentDatabases)
699
+ .set({ updatedAt: now })
700
+ .where(eq(schema.contentDatabases.id, args.databaseId));
701
+ const restored = await snapshotMigration(tx, args.databaseId);
702
+ const postDigest = snapshotDigest(restored);
703
+ if (postDigest !== receipt.preDigest)
704
+ throw new Error("Rollback verification failed.");
705
+ const resultJson = {
706
+ phase: "rollback",
707
+ transitionExpectedPostDigest: receipt.postDigest,
708
+ counts: {
709
+ rows: (rollback.versions ?? []).length,
710
+ properties: ids.length,
711
+ },
712
+ verified: true,
713
+ };
714
+ const transitioned = await tx
715
+ .update(schema.contentDatabaseMigrationReceipts)
716
+ .set({
717
+ state: "rolled_back",
718
+ postDigest,
719
+ resultJson: JSON.stringify(resultJson),
720
+ updatedAt: now,
721
+ })
722
+ .where(
723
+ and(
724
+ eq(schema.contentDatabaseMigrationReceipts.id, receipt.id),
725
+ inArray(schema.contentDatabaseMigrationReceipts.state, [
726
+ "applied",
727
+ "verified",
728
+ ]),
729
+ ),
730
+ )
731
+ .returning({ id: schema.contentDatabaseMigrationReceipts.id });
732
+ if (transitioned.length !== 1)
733
+ throw new Error("Migration receipt state changed during rollback.");
734
+ mutated = true;
735
+ return {
736
+ receiptId: receipt.id,
737
+ state: "rolled_back",
738
+ preDigest: receipt.preDigest,
739
+ postDigest,
740
+ counts: {
741
+ rows: (rollback.versions ?? []).length,
742
+ properties: ids.length,
743
+ },
744
+ replayed: false,
745
+ verified: true,
746
+ };
747
+ }
748
+ const planResult = parseJson(receipt.resultJson);
749
+ // Legacy ids are deliberately copied into the receipt result only after apply validation.
750
+ const legacyIds: string[] = planResult.legacyPropertyIds ?? [];
751
+ const legacy = current.definitions.filter((definition: any) =>
752
+ legacyIds.includes(definition.id),
753
+ );
754
+ if (
755
+ legacy.length !== legacyIds.length ||
756
+ legacy.some(
757
+ (definition: any) =>
758
+ definition.systemRole || definition.type === "blocks",
759
+ )
760
+ )
761
+ throw new Error("Legacy property is missing or unsafe to finalize.");
762
+ if (legacyIds.length) {
763
+ await tx
764
+ .delete(schema.documentPropertyValues)
765
+ .where(
766
+ inArray(schema.documentPropertyValues.propertyId, legacyIds),
767
+ );
768
+ await tx
769
+ .delete(schema.documentPropertyDefinitions)
770
+ .where(inArray(schema.documentPropertyDefinitions.id, legacyIds));
771
+ }
772
+ await touchContentDatabase(
773
+ tx as unknown as ReturnType<typeof getDb>,
774
+ args.databaseId,
775
+ now,
776
+ );
777
+ const finalized = await snapshotMigration(tx, args.databaseId);
778
+ if (
779
+ finalized.definitions.some((definition: any) =>
780
+ legacyIds.includes(definition.id),
781
+ ) ||
782
+ finalized.values.some((value: any) =>
783
+ legacyIds.includes(value.propertyId),
784
+ )
785
+ )
786
+ throw new Error("Legacy property finalization verification failed.");
787
+ const postDigest = snapshotDigest(finalized);
788
+ const resultJson = {
789
+ phase: "finalize",
790
+ transitionExpectedPostDigest: receipt.postDigest,
791
+ counts: { rows: 0, properties: legacyIds.length },
792
+ verified: true,
793
+ };
794
+ const transitioned = await tx
795
+ .update(schema.contentDatabaseMigrationReceipts)
796
+ .set({
797
+ state: "finalized",
798
+ postDigest,
799
+ resultJson: JSON.stringify(resultJson),
800
+ updatedAt: now,
801
+ })
802
+ .where(
803
+ and(
804
+ eq(schema.contentDatabaseMigrationReceipts.id, receipt.id),
805
+ eq(schema.contentDatabaseMigrationReceipts.state, "verified"),
806
+ ),
807
+ )
808
+ .returning({ id: schema.contentDatabaseMigrationReceipts.id });
809
+ if (transitioned.length !== 1)
810
+ throw new Error("Migration receipt state changed during finalize.");
811
+ mutated = true;
812
+ return {
813
+ receiptId: receipt.id,
814
+ state: "finalized",
815
+ preDigest: receipt.preDigest,
816
+ postDigest,
817
+ counts: { rows: 0, properties: legacyIds.length },
818
+ replayed: false,
819
+ verified: true,
820
+ };
821
+ });
822
+ if (mutated)
823
+ await writeAppState("refresh-signal", { ts: Date.now() }).catch(() => {
824
+ // The receipt is already committed; polling reconciles this optional
825
+ // UI hint when a concurrent SQLite writer briefly holds the database.
826
+ });
827
+ return result;
828
+ });
829
+ },
830
+ });