@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
@@ -86,6 +86,7 @@ import {
86
86
  type ExistingBuilderSourceRowIdentity,
87
87
  } from "./_builder-cms-source-adapter.js";
88
88
  import { mergeBuilderCmsWriteSettingsIntoJson } from "./_builder-cms-write-settings.js";
89
+ import { lockContentDatabaseMutation } from "./_content-database-mutation-lock.js";
89
90
  import { ensureDocumentsFilesMembership } from "./_content-files.js";
90
91
  import {
91
92
  organizationContentSpaceId,
@@ -7018,26 +7019,42 @@ export async function replaceSourceMetadata(args: {
7018
7019
  })
7019
7020
  .where(eq(schema.contentDatabaseSources.id, args.source.id));
7020
7021
  } else {
7021
- await db.insert(schema.contentDatabaseSources).values({
7022
- id: sourceId,
7023
- ownerEmail: args.database.ownerEmail,
7024
- orgId: args.database.orgId,
7025
- databaseId: args.database.id,
7026
- sourceType: args.sourceType,
7027
- sourceName: args.sourceName,
7028
- sourceTable: args.sourceTable,
7029
- syncState: "linked",
7030
- freshness: "fresh",
7031
- capabilitiesJson: sourceCapabilitiesForType(args.sourceType),
7032
- metadataJson: serializeSourceMetadataRecord({
7022
+ await db.transaction(async (tx) => {
7023
+ await lockContentDatabaseMutation(
7024
+ tx as unknown as ReturnType<typeof getDb>,
7025
+ args.database.id,
7026
+ );
7027
+ const [existing] = await tx
7028
+ .select({ id: schema.contentDatabaseSources.id })
7029
+ .from(schema.contentDatabaseSources)
7030
+ .where(eq(schema.contentDatabaseSources.databaseId, args.database.id))
7031
+ .limit(1);
7032
+ if (existing) {
7033
+ throw new Error(
7034
+ "Database source state changed before attachment completed.",
7035
+ );
7036
+ }
7037
+ await tx.insert(schema.contentDatabaseSources).values({
7038
+ id: sourceId,
7039
+ ownerEmail: args.database.ownerEmail,
7040
+ orgId: args.database.orgId,
7041
+ databaseId: args.database.id,
7033
7042
  sourceType: args.sourceType,
7043
+ sourceName: args.sourceName,
7034
7044
  sourceTable: args.sourceTable,
7035
- }),
7036
- lastRefreshedAt: args.now,
7037
- lastSourceUpdatedAt: args.now,
7038
- lastError: null,
7039
- createdAt: args.now,
7040
- updatedAt: args.now,
7045
+ syncState: "linked",
7046
+ freshness: "fresh",
7047
+ capabilitiesJson: sourceCapabilitiesForType(args.sourceType),
7048
+ metadataJson: serializeSourceMetadataRecord({
7049
+ sourceType: args.sourceType,
7050
+ sourceTable: args.sourceTable,
7051
+ }),
7052
+ lastRefreshedAt: args.now,
7053
+ lastSourceUpdatedAt: args.now,
7054
+ lastError: null,
7055
+ createdAt: args.now,
7056
+ updatedAt: args.now,
7057
+ });
7041
7058
  });
7042
7059
  }
7043
7060
 
@@ -7050,6 +7067,7 @@ export async function replaceSourceMetadata(args: {
7050
7067
  */
7051
7068
  export async function insertSecondarySource(args: {
7052
7069
  database: ContentDatabaseRow;
7070
+ expectedPrimarySourceId: string;
7053
7071
  sourceType: ContentDatabaseSourceType;
7054
7072
  sourceName: string;
7055
7073
  sourceTable: string;
@@ -7057,26 +7075,54 @@ export async function insertSecondarySource(args: {
7057
7075
  }): Promise<string> {
7058
7076
  const db = getDb();
7059
7077
  const sourceId = crypto.randomUUID();
7060
- await db.insert(schema.contentDatabaseSources).values({
7061
- id: sourceId,
7062
- ownerEmail: args.database.ownerEmail,
7063
- orgId: args.database.orgId,
7064
- databaseId: args.database.id,
7065
- sourceType: args.sourceType,
7066
- sourceName: args.sourceName,
7067
- sourceTable: args.sourceTable,
7068
- syncState: "linked",
7069
- freshness: "fresh",
7070
- capabilitiesJson: sourceCapabilitiesForType(args.sourceType),
7071
- metadataJson: serializeSourceMetadataRecord({
7078
+ await db.transaction(async (tx) => {
7079
+ await lockContentDatabaseMutation(
7080
+ tx as unknown as ReturnType<typeof getDb>,
7081
+ args.database.id,
7082
+ );
7083
+ const sources = await tx
7084
+ .select({
7085
+ id: schema.contentDatabaseSources.id,
7086
+ sourceType: schema.contentDatabaseSources.sourceType,
7087
+ sourceTable: schema.contentDatabaseSources.sourceTable,
7088
+ })
7089
+ .from(schema.contentDatabaseSources)
7090
+ .where(eq(schema.contentDatabaseSources.databaseId, args.database.id));
7091
+ if (!sources.some((source) => source.id === args.expectedPrimarySourceId)) {
7092
+ throw new Error(
7093
+ "Database source state changed before attachment completed.",
7094
+ );
7095
+ }
7096
+ if (
7097
+ sources.some(
7098
+ (source) =>
7099
+ source.sourceType === args.sourceType &&
7100
+ source.sourceTable === args.sourceTable,
7101
+ )
7102
+ ) {
7103
+ throw new Error(`"${args.sourceTable}" is already attached as a source.`);
7104
+ }
7105
+ await tx.insert(schema.contentDatabaseSources).values({
7106
+ id: sourceId,
7107
+ ownerEmail: args.database.ownerEmail,
7108
+ orgId: args.database.orgId,
7109
+ databaseId: args.database.id,
7072
7110
  sourceType: args.sourceType,
7111
+ sourceName: args.sourceName,
7073
7112
  sourceTable: args.sourceTable,
7074
- }),
7075
- lastRefreshedAt: args.now,
7076
- lastSourceUpdatedAt: args.now,
7077
- lastError: null,
7078
- createdAt: args.now,
7079
- updatedAt: args.now,
7113
+ syncState: "linked",
7114
+ freshness: "fresh",
7115
+ capabilitiesJson: sourceCapabilitiesForType(args.sourceType),
7116
+ metadataJson: serializeSourceMetadataRecord({
7117
+ sourceType: args.sourceType,
7118
+ sourceTable: args.sourceTable,
7119
+ }),
7120
+ lastRefreshedAt: args.now,
7121
+ lastSourceUpdatedAt: args.now,
7122
+ lastError: null,
7123
+ createdAt: args.now,
7124
+ updatedAt: args.now,
7125
+ });
7080
7126
  });
7081
7127
  return sourceId;
7082
7128
  }
@@ -1448,6 +1448,11 @@ export async function deleteDatabaseDataForDocument(
1448
1448
  await db
1449
1449
  .delete(schema.contentDatabaseSources)
1450
1450
  .where(eq(schema.contentDatabaseSources.databaseId, database.id));
1451
+ await db
1452
+ .delete(schema.contentDatabaseMigrationReceipts)
1453
+ .where(
1454
+ eq(schema.contentDatabaseMigrationReceipts.databaseId, database.id),
1455
+ );
1451
1456
  await db
1452
1457
  .delete(schema.documentPropertyDefinitions)
1453
1458
  .where(eq(schema.documentPropertyDefinitions.databaseId, database.id));
@@ -2,11 +2,15 @@ import { and, eq } from "drizzle-orm";
2
2
 
3
3
  import { getDb, schema } from "../server/db/index.js";
4
4
  import { resolveContentSpaceAccess } from "./_content-space-access.js";
5
- import { deleteDocumentRecursive } from "./delete-document.js";
5
+ import {
6
+ deleteDocumentRootsRecursive,
7
+ PermanentDeleteScopeChangedError,
8
+ } from "./delete-document.js";
6
9
 
7
10
  type Db = ReturnType<typeof getDb>;
11
+ const MAX_DELETE_SCOPE_ATTEMPTS = 3;
8
12
 
9
- export async function deleteUserContentSpace(db: Db, spaceId: string) {
13
+ async function deleteUserContentSpaceOnce(db: Db, spaceId: string) {
10
14
  return db.transaction(async (tx) => {
11
15
  const scopedDb = tx as unknown as Db;
12
16
  const access = await resolveContentSpaceAccess(spaceId, "editor", {
@@ -45,14 +49,9 @@ export async function deleteUserContentSpace(db: Db, spaceId: string) {
45
49
  await scopedDb
46
50
  .delete(schema.contentSpaceCatalogItems)
47
51
  .where(eq(schema.contentSpaceCatalogItems.id, mapping.id));
48
- const deletedCatalogDocuments = await deleteDocumentRecursive(
49
- scopedDb,
50
- mapping.documentId,
51
- access.space.ownerEmail,
52
- );
53
- const deletedWorkspaceDocuments = await deleteDocumentRecursive(
52
+ const deletedDocuments = await deleteDocumentRootsRecursive(
54
53
  scopedDb,
55
- filesDatabase.documentId,
54
+ [mapping.documentId, filesDatabase.documentId],
56
55
  access.space.ownerEmail,
57
56
  );
58
57
 
@@ -77,8 +76,23 @@ export async function deleteUserContentSpace(db: Db, spaceId: string) {
77
76
 
78
77
  return {
79
78
  spaceId,
80
- deletedDocuments:
81
- deletedCatalogDocuments.length + deletedWorkspaceDocuments.length,
79
+ deletedDocuments: deletedDocuments.length,
82
80
  };
83
81
  });
84
82
  }
83
+
84
+ export async function deleteUserContentSpace(db: Db, spaceId: string) {
85
+ for (let attempt = 1; attempt <= MAX_DELETE_SCOPE_ATTEMPTS; attempt += 1) {
86
+ try {
87
+ return await deleteUserContentSpaceOnce(db, spaceId);
88
+ } catch (error) {
89
+ if (
90
+ !(error instanceof PermanentDeleteScopeChangedError) ||
91
+ attempt === MAX_DELETE_SCOPE_ATTEMPTS
92
+ ) {
93
+ throw error;
94
+ }
95
+ }
96
+ }
97
+ throw new Error("Workspace deletion did not complete.");
98
+ }
@@ -10,6 +10,10 @@ import {
10
10
  isComputedPropertyType,
11
11
  type DocumentPropertyType,
12
12
  } from "../shared/properties.js";
13
+ import {
14
+ lockContentDatabaseMutation,
15
+ touchContentDatabase,
16
+ } from "./_content-database-mutation-lock.js";
13
17
  import { ensureDocumentFilesMembership } from "./_content-files.js";
14
18
  import { getContentDatabaseResponse } from "./_database-utils.js";
15
19
  import {
@@ -97,54 +101,68 @@ export default defineAction({
97
101
  .where(eq(schema.documentShares.resourceId, database.documentId));
98
102
 
99
103
  const initialValues = Object.entries(propertyValues ?? {});
100
- const propertyValueRows: Array<
101
- typeof schema.documentPropertyValues.$inferInsert
102
- > = [];
103
- if (initialValues.length > 0) {
104
- const requestedPropertyIds = initialValues.map(
105
- ([propertyId]) => propertyId,
106
- );
107
- const definitions = await db
108
- .select()
109
- .from(schema.documentPropertyDefinitions)
110
- .where(
111
- and(
112
- eq(
113
- schema.documentPropertyDefinitions.ownerEmail,
114
- database.ownerEmail,
115
- ),
116
- eq(schema.documentPropertyDefinitions.databaseId, databaseId),
117
- inArray(
118
- schema.documentPropertyDefinitions.id,
119
- requestedPropertyIds,
120
- ),
121
- ),
122
- );
123
- const definitionById = new Map(
124
- definitions.map((definition) => [definition.id, definition]),
125
- );
126
-
127
- for (const [propertyId, value] of initialValues) {
128
- const definition = definitionById.get(propertyId);
129
- const type = definition?.type as DocumentPropertyType | undefined;
130
- if (!definition || !type || isComputedPropertyType(type)) continue;
131
- propertyValueRows.push({
132
- id: nanoid(),
133
- ownerEmail: database.ownerEmail,
134
- documentId,
135
- propertyId,
136
- valueJson: normalizedValueJson(type, value),
137
- createdAt: now,
138
- updatedAt: now,
139
- });
140
- }
141
- }
142
104
 
143
105
  await withPositionLock(
144
106
  documentsPositionScope(database.ownerEmail, database.documentId),
145
107
  () =>
146
108
  withPositionLock(databaseItemsPositionScope(databaseId), async () => {
147
109
  await db.transaction(async (tx) => {
110
+ await lockContentDatabaseMutation(
111
+ tx as unknown as ReturnType<typeof getDb>,
112
+ databaseId,
113
+ );
114
+ await touchContentDatabase(
115
+ tx as unknown as ReturnType<typeof getDb>,
116
+ databaseId,
117
+ now,
118
+ );
119
+ const propertyValueRows: Array<
120
+ typeof schema.documentPropertyValues.$inferInsert
121
+ > = [];
122
+ if (initialValues.length > 0) {
123
+ const requestedPropertyIds = initialValues.map(
124
+ ([propertyId]) => propertyId,
125
+ );
126
+ const definitions = await tx
127
+ .select()
128
+ .from(schema.documentPropertyDefinitions)
129
+ .where(
130
+ and(
131
+ eq(
132
+ schema.documentPropertyDefinitions.ownerEmail,
133
+ database.ownerEmail,
134
+ ),
135
+ eq(
136
+ schema.documentPropertyDefinitions.databaseId,
137
+ databaseId,
138
+ ),
139
+ inArray(
140
+ schema.documentPropertyDefinitions.id,
141
+ requestedPropertyIds,
142
+ ),
143
+ ),
144
+ );
145
+ const definitionById = new Map(
146
+ definitions.map((definition) => [definition.id, definition]),
147
+ );
148
+ for (const [propertyId, value] of initialValues) {
149
+ const definition = definitionById.get(propertyId);
150
+ const type = definition?.type as
151
+ | DocumentPropertyType
152
+ | undefined;
153
+ if (!definition || !type || isComputedPropertyType(type))
154
+ continue;
155
+ propertyValueRows.push({
156
+ id: nanoid(),
157
+ ownerEmail: database.ownerEmail,
158
+ documentId,
159
+ propertyId,
160
+ valueJson: normalizedValueJson(type, value),
161
+ createdAt: now,
162
+ updatedAt: now,
163
+ });
164
+ }
165
+ }
148
166
  const [maxDocPos] = await tx
149
167
  .select({ max: sql<number>`COALESCE(MAX(position), -1)` })
150
168
  .from(schema.documents)
@@ -398,6 +398,7 @@ export default defineAction({
398
398
 
399
399
  const secondaryId = await insertSecondarySource({
400
400
  database,
401
+ expectedPrimarySourceId: existingSource.id,
401
402
  sourceType,
402
403
  sourceName,
403
404
  sourceTable,
@@ -491,6 +492,7 @@ export default defineAction({
491
492
  additionalRead.state === "live" ? additionalRead.entries : [];
492
493
  const additionalSourceId = await insertSecondarySource({
493
494
  database,
495
+ expectedPrimarySourceId: existingSource.id,
494
496
  sourceType,
495
497
  sourceName,
496
498
  sourceTable,
@@ -1,7 +1,7 @@
1
1
  import { defineAction } from "@agent-native/core";
2
2
  import { writeAppState } from "@agent-native/core/application-state";
3
3
  import { assertAccess } from "@agent-native/core/sharing";
4
- import { and, eq, isNull, sql } from "drizzle-orm";
4
+ import { and, eq, sql } from "drizzle-orm";
5
5
  import { z } from "zod";
6
6
 
7
7
  import { getDb, schema } from "../server/db/index.js";
@@ -16,6 +16,8 @@ import {
16
16
  normalizePropertyVisibility,
17
17
  type DocumentPropertyType,
18
18
  } from "../shared/properties.js";
19
+ import { lockContentDatabaseMutation } from "./_content-database-mutation-lock.js";
20
+ import { lockDatabaseMemberships } from "./_database-membership-lock.js";
19
21
  import {
20
22
  propertyDefinitionsPositionScope,
21
23
  withPositionLock,
@@ -101,7 +103,7 @@ export default defineAction({
101
103
  const now = new Date().toISOString();
102
104
  const name = args.name.trim();
103
105
  const type = args.type as DocumentPropertyType;
104
- let optionsJson = optionsForNewProperty(type, args.options as any);
106
+ const optionsJson = optionsForNewProperty(type, args.options as any);
105
107
  const database = await resolvePropertyDatabaseForDocument(
106
108
  document,
107
109
  args.databaseId,
@@ -114,13 +116,12 @@ export default defineAction({
114
116
  }
115
117
 
116
118
  if (args.id) {
117
- const propertyId = args.id;
118
119
  const [existing] = await db
119
120
  .select()
120
121
  .from(schema.documentPropertyDefinitions)
121
122
  .where(
122
123
  and(
123
- eq(schema.documentPropertyDefinitions.id, propertyId),
124
+ eq(schema.documentPropertyDefinitions.id, args.id),
124
125
  eq(
125
126
  schema.documentPropertyDefinitions.ownerEmail,
126
127
  document.ownerEmail,
@@ -128,95 +129,79 @@ export default defineAction({
128
129
  eq(schema.documentPropertyDefinitions.databaseId, database.id),
129
130
  ),
130
131
  );
131
- if (!existing) throw new Error(`Property "${propertyId}" not found`);
132
- if (existing.systemRole) {
133
- throw new Error("System properties cannot be changed.");
134
- }
135
- if (
136
- isComputedPropertyType(existing.type as DocumentPropertyType) &&
137
- existing.type !== type
138
- ) {
139
- throw new Error("Computed property types cannot be changed.");
140
- }
141
-
142
- const existingOptions = parsePropertyOptions(existing.optionsJson);
143
- const existingIsPrimaryBlocks =
144
- isBlocksPropertyType(existing.type as DocumentPropertyType) &&
145
- isPrimaryBlocksField(existingOptions);
146
-
147
- // The primary "Content" Blocks field backs the document body — it can be
148
- // renamed/hidden but not retyped (delete it from the database view to
149
- // remove the body). Block the type switch defensively.
150
- if (existingIsPrimaryBlocks && existing.type !== type) {
151
- throw new Error(
152
- "The primary Content (Blocks) field cannot change type. Delete it from the database view to remove the body.",
153
- );
154
- }
155
-
156
- // Preserve the primary flag when re-saving the primary Blocks field (a
157
- // rename or visibility change must NOT demote it to a normal Blocks field).
158
- if (existingIsPrimaryBlocks && isBlocksPropertyType(type)) {
159
- optionsJson = serializePropertyOptions({ blocks: { primary: true } });
160
- }
161
-
132
+ if (!existing) throw new Error(`Property "${args.id}" not found`);
162
133
  await db.transaction(async (tx) => {
163
- const [lockedDatabase] = await tx
164
- .update(schema.contentDatabases)
165
- .set({ updatedAt: sql`${schema.contentDatabases.updatedAt}` })
166
- .where(
167
- and(
168
- eq(schema.contentDatabases.id, database.id),
169
- eq(schema.contentDatabases.documentId, database.documentId),
170
- eq(schema.contentDatabases.ownerEmail, document.ownerEmail),
171
- isNull(schema.contentDatabases.deletedAt),
172
- ),
173
- )
174
- .returning({ id: schema.contentDatabases.id });
175
- if (!lockedDatabase) throw new Error("Database is no longer active.");
176
- const [lockedExisting] = await tx
177
- .update(schema.documentPropertyDefinitions)
178
- .set({
179
- updatedAt: sql`${schema.documentPropertyDefinitions.updatedAt}`,
180
- })
134
+ await lockContentDatabaseMutation(
135
+ tx as unknown as ReturnType<typeof getDb>,
136
+ database.id,
137
+ );
138
+ let [lockedDefinition] = await tx
139
+ .select()
140
+ .from(schema.documentPropertyDefinitions)
181
141
  .where(
182
142
  and(
183
- eq(schema.documentPropertyDefinitions.id, propertyId),
143
+ eq(schema.documentPropertyDefinitions.id, args.id!),
184
144
  eq(
185
145
  schema.documentPropertyDefinitions.ownerEmail,
186
146
  document.ownerEmail,
187
147
  ),
188
148
  eq(schema.documentPropertyDefinitions.databaseId, database.id),
189
149
  ),
190
- )
191
- .returning();
192
- if (!lockedExisting)
193
- throw new Error(`Property "${propertyId}" not found`);
194
- if (lockedExisting.systemRole)
150
+ );
151
+ if (!lockedDefinition)
152
+ throw new Error(`Property "${args.id}" not found`);
153
+ if (lockedDefinition.systemRole) {
195
154
  throw new Error("System properties cannot be changed.");
155
+ }
196
156
  if (
197
- isComputedPropertyType(lockedExisting.type as DocumentPropertyType) &&
198
- lockedExisting.type !== type
157
+ isComputedPropertyType(
158
+ lockedDefinition.type as DocumentPropertyType,
159
+ ) &&
160
+ lockedDefinition.type !== type
199
161
  ) {
200
162
  throw new Error("Computed property types cannot be changed.");
201
163
  }
164
+
165
+ const lockedOptions = parsePropertyOptions(
166
+ lockedDefinition.optionsJson,
167
+ );
202
168
  const lockedIsPrimaryBlocks =
203
- isBlocksPropertyType(lockedExisting.type as DocumentPropertyType) &&
204
- isPrimaryBlocksField(
205
- parsePropertyOptions(lockedExisting.optionsJson),
206
- );
207
- if (lockedIsPrimaryBlocks && lockedExisting.type !== type) {
169
+ isBlocksPropertyType(lockedDefinition.type as DocumentPropertyType) &&
170
+ isPrimaryBlocksField(lockedOptions);
171
+ if (lockedIsPrimaryBlocks && lockedDefinition.type !== type) {
208
172
  throw new Error(
209
173
  "The primary Content (Blocks) field cannot change type. Delete it from the database view to remove the body.",
210
174
  );
211
175
  }
212
-
213
- if (lockedExisting.type !== type) {
176
+ if (lockedDefinition.type !== type) {
177
+ const memberships = await tx
178
+ .select({ id: schema.contentDatabaseItems.id })
179
+ .from(schema.contentDatabaseItems)
180
+ .where(eq(schema.contentDatabaseItems.databaseId, database.id));
181
+ await lockDatabaseMemberships(
182
+ tx,
183
+ memberships.map((membership) => membership.id),
184
+ );
185
+ [lockedDefinition] = await tx
186
+ .select()
187
+ .from(schema.documentPropertyDefinitions)
188
+ .where(
189
+ and(
190
+ eq(schema.documentPropertyDefinitions.id, args.id!),
191
+ eq(
192
+ schema.documentPropertyDefinitions.ownerEmail,
193
+ document.ownerEmail,
194
+ ),
195
+ eq(schema.documentPropertyDefinitions.databaseId, database.id),
196
+ ),
197
+ );
198
+ if (!lockedDefinition) {
199
+ throw new Error(`Property "${args.id}" not found`);
200
+ }
214
201
  const [mappedSourceField] = await tx
215
202
  .select({ id: schema.contentDatabaseSourceFields.id })
216
203
  .from(schema.contentDatabaseSourceFields)
217
- .where(
218
- eq(schema.contentDatabaseSourceFields.propertyId, propertyId),
219
- )
204
+ .where(eq(schema.contentDatabaseSourceFields.propertyId, args.id!))
220
205
  .limit(1);
221
206
  if (mappedSourceField) {
222
207
  throw new Error(
@@ -227,7 +212,7 @@ export default defineAction({
227
212
  .delete(schema.documentPropertyValues)
228
213
  .where(
229
214
  and(
230
- eq(schema.documentPropertyValues.propertyId, propertyId),
215
+ eq(schema.documentPropertyValues.propertyId, args.id!),
231
216
  eq(
232
217
  schema.documentPropertyValues.ownerEmail,
233
218
  document.ownerEmail,
@@ -239,18 +224,19 @@ export default defineAction({
239
224
  .where(
240
225
  and(
241
226
  eq(schema.contentDatabaseItemKeyClaims.databaseId, database.id),
242
- eq(schema.contentDatabaseItemKeyClaims.propertyId, propertyId),
227
+ eq(schema.contentDatabaseItemKeyClaims.propertyId, args.id!),
243
228
  ),
244
229
  );
245
- // Switching a Blocks field to another type drops its independent content.
246
230
  if (
247
- isBlocksPropertyType(lockedExisting.type as DocumentPropertyType) &&
231
+ isBlocksPropertyType(
232
+ lockedDefinition.type as DocumentPropertyType,
233
+ ) &&
248
234
  !isBlocksPropertyType(type)
249
235
  ) {
250
236
  await tx
251
237
  .delete(schema.documentBlockFieldContents)
252
238
  .where(
253
- eq(schema.documentBlockFieldContents.propertyId, propertyId),
239
+ eq(schema.documentBlockFieldContents.propertyId, args.id!),
254
240
  );
255
241
  }
256
242
  }
@@ -265,7 +251,7 @@ export default defineAction({
265
251
  type,
266
252
  visibility:
267
253
  args.visibility === undefined
268
- ? normalizePropertyVisibility(lockedExisting.visibility)
254
+ ? normalizePropertyVisibility(lockedDefinition.visibility)
269
255
  : normalizePropertyVisibility(args.visibility),
270
256
  optionsJson:
271
257
  lockedIsPrimaryBlocks && isBlocksPropertyType(type)
@@ -273,40 +259,49 @@ export default defineAction({
273
259
  : optionsJson,
274
260
  updatedAt: now,
275
261
  })
276
- .where(eq(schema.documentPropertyDefinitions.id, propertyId));
262
+ .where(eq(schema.documentPropertyDefinitions.id, args.id!));
277
263
  });
278
264
  } else {
279
265
  await withPositionLock(
280
266
  propertyDefinitionsPositionScope(database.id),
281
267
  async () => {
282
- const [maxPos] = await db
283
- .select({
284
- max: sql<number>`COALESCE(MAX(position), -1)`,
285
- })
286
- .from(schema.documentPropertyDefinitions)
287
- .where(
288
- and(
289
- eq(
290
- schema.documentPropertyDefinitions.ownerEmail,
291
- document.ownerEmail,
292
- ),
293
- eq(schema.documentPropertyDefinitions.databaseId, database.id),
294
- ),
268
+ await db.transaction(async (tx) => {
269
+ await lockContentDatabaseMutation(
270
+ tx as unknown as ReturnType<typeof getDb>,
271
+ database.id,
295
272
  );
273
+ const [maxPos] = await tx
274
+ .select({
275
+ max: sql<number>`COALESCE(MAX(position), -1)`,
276
+ })
277
+ .from(schema.documentPropertyDefinitions)
278
+ .where(
279
+ and(
280
+ eq(
281
+ schema.documentPropertyDefinitions.ownerEmail,
282
+ document.ownerEmail,
283
+ ),
284
+ eq(
285
+ schema.documentPropertyDefinitions.databaseId,
286
+ database.id,
287
+ ),
288
+ ),
289
+ );
296
290
 
297
- await db.insert(schema.documentPropertyDefinitions).values({
298
- id: nanoid(),
299
- ownerEmail: document.ownerEmail,
300
- orgId: document.orgId ?? null,
301
- databaseId: database.id,
302
- name,
303
- description: args.description?.trim() ?? "",
304
- type,
305
- visibility: normalizePropertyVisibility(args.visibility),
306
- optionsJson,
307
- position: (maxPos?.max ?? -1) + 1,
308
- createdAt: now,
309
- updatedAt: now,
291
+ await tx.insert(schema.documentPropertyDefinitions).values({
292
+ id: nanoid(),
293
+ ownerEmail: document.ownerEmail,
294
+ orgId: document.orgId ?? null,
295
+ databaseId: database.id,
296
+ name,
297
+ description: args.description?.trim() ?? "",
298
+ type,
299
+ visibility: normalizePropertyVisibility(args.visibility),
300
+ optionsJson,
301
+ position: (maxPos?.max ?? -1) + 1,
302
+ createdAt: now,
303
+ updatedAt: now,
304
+ });
310
305
  });
311
306
  },
312
307
  );