@agent-native/core 0.96.0 → 0.97.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 (450) hide show
  1. package/README.md +6 -0
  2. package/corpus/README.md +2 -2
  3. package/corpus/core/CHANGELOG.md +39 -0
  4. package/corpus/core/docs/content/audit-log.mdx +2 -1
  5. package/corpus/core/docs/content/automations.mdx +7 -7
  6. package/corpus/core/docs/content/creating-templates.mdx +1 -1
  7. package/corpus/core/docs/content/internationalization.mdx +2 -1
  8. package/corpus/core/docs/content/locales/ar-SA/audit-log.mdx +2 -1
  9. package/corpus/core/docs/content/locales/ar-SA/automations.mdx +7 -7
  10. package/corpus/core/docs/content/locales/ar-SA/getting-started.mdx +7 -1
  11. package/corpus/core/docs/content/locales/ar-SA/internationalization.mdx +1 -1
  12. package/corpus/core/docs/content/locales/ar-SA/package-lifecycle.mdx +19 -0
  13. package/corpus/core/docs/content/locales/ar-SA/sandbox-adapters.mdx +18 -7
  14. package/corpus/core/docs/content/locales/ar-SA/security.mdx +8 -0
  15. package/corpus/core/docs/content/locales/de-DE/audit-log.mdx +2 -1
  16. package/corpus/core/docs/content/locales/de-DE/automations.mdx +7 -7
  17. package/corpus/core/docs/content/locales/de-DE/getting-started.mdx +7 -1
  18. package/corpus/core/docs/content/locales/de-DE/internationalization.mdx +1 -1
  19. package/corpus/core/docs/content/locales/de-DE/package-lifecycle.mdx +22 -0
  20. package/corpus/core/docs/content/locales/de-DE/sandbox-adapters.mdx +18 -7
  21. package/corpus/core/docs/content/locales/de-DE/security.mdx +8 -0
  22. package/corpus/core/docs/content/locales/es-ES/audit-log.mdx +2 -1
  23. package/corpus/core/docs/content/locales/es-ES/automations.mdx +7 -7
  24. package/corpus/core/docs/content/locales/es-ES/getting-started.mdx +7 -1
  25. package/corpus/core/docs/content/locales/es-ES/internationalization.mdx +1 -1
  26. package/corpus/core/docs/content/locales/es-ES/package-lifecycle.mdx +22 -0
  27. package/corpus/core/docs/content/locales/es-ES/sandbox-adapters.mdx +18 -7
  28. package/corpus/core/docs/content/locales/es-ES/security.mdx +8 -0
  29. package/corpus/core/docs/content/locales/fr-FR/audit-log.mdx +2 -1
  30. package/corpus/core/docs/content/locales/fr-FR/automations.mdx +7 -7
  31. package/corpus/core/docs/content/locales/fr-FR/getting-started.mdx +7 -1
  32. package/corpus/core/docs/content/locales/fr-FR/internationalization.mdx +1 -1
  33. package/corpus/core/docs/content/locales/fr-FR/package-lifecycle.mdx +21 -0
  34. package/corpus/core/docs/content/locales/fr-FR/sandbox-adapters.mdx +19 -8
  35. package/corpus/core/docs/content/locales/fr-FR/security.mdx +8 -0
  36. package/corpus/core/docs/content/locales/hi-IN/audit-log.mdx +2 -1
  37. package/corpus/core/docs/content/locales/hi-IN/automations.mdx +7 -7
  38. package/corpus/core/docs/content/locales/hi-IN/getting-started.mdx +7 -1
  39. package/corpus/core/docs/content/locales/hi-IN/internationalization.mdx +1 -1
  40. package/corpus/core/docs/content/locales/hi-IN/package-lifecycle.mdx +20 -0
  41. package/corpus/core/docs/content/locales/hi-IN/sandbox-adapters.mdx +18 -7
  42. package/corpus/core/docs/content/locales/hi-IN/security.mdx +8 -0
  43. package/corpus/core/docs/content/locales/ja-JP/audit-log.mdx +2 -1
  44. package/corpus/core/docs/content/locales/ja-JP/automations.mdx +7 -7
  45. package/corpus/core/docs/content/locales/ja-JP/getting-started.mdx +7 -1
  46. package/corpus/core/docs/content/locales/ja-JP/internationalization.mdx +1 -1
  47. package/corpus/core/docs/content/locales/ja-JP/package-lifecycle.mdx +21 -0
  48. package/corpus/core/docs/content/locales/ja-JP/sandbox-adapters.mdx +17 -6
  49. package/corpus/core/docs/content/locales/ja-JP/security.mdx +8 -0
  50. package/corpus/core/docs/content/locales/ko-KR/audit-log.mdx +2 -1
  51. package/corpus/core/docs/content/locales/ko-KR/automations.mdx +7 -7
  52. package/corpus/core/docs/content/locales/ko-KR/getting-started.mdx +7 -1
  53. package/corpus/core/docs/content/locales/ko-KR/internationalization.mdx +1 -1
  54. package/corpus/core/docs/content/locales/ko-KR/package-lifecycle.mdx +20 -0
  55. package/corpus/core/docs/content/locales/ko-KR/sandbox-adapters.mdx +17 -6
  56. package/corpus/core/docs/content/locales/ko-KR/security.mdx +8 -0
  57. package/corpus/core/docs/content/locales/pt-BR/audit-log.mdx +2 -1
  58. package/corpus/core/docs/content/locales/pt-BR/automations.mdx +7 -7
  59. package/corpus/core/docs/content/locales/pt-BR/getting-started.mdx +7 -1
  60. package/corpus/core/docs/content/locales/pt-BR/internationalization.mdx +1 -1
  61. package/corpus/core/docs/content/locales/pt-BR/package-lifecycle.mdx +21 -0
  62. package/corpus/core/docs/content/locales/pt-BR/sandbox-adapters.mdx +18 -7
  63. package/corpus/core/docs/content/locales/pt-BR/security.mdx +8 -0
  64. package/corpus/core/docs/content/locales/zh-CN/audit-log.mdx +2 -1
  65. package/corpus/core/docs/content/locales/zh-CN/automations.mdx +7 -7
  66. package/corpus/core/docs/content/locales/zh-CN/getting-started.mdx +6 -4
  67. package/corpus/core/docs/content/locales/zh-CN/internationalization.mdx +1 -1
  68. package/corpus/core/docs/content/locales/zh-CN/package-lifecycle.mdx +19 -0
  69. package/corpus/core/docs/content/locales/zh-CN/sandbox-adapters.mdx +17 -6
  70. package/corpus/core/docs/content/locales/zh-CN/security.mdx +8 -0
  71. package/corpus/core/docs/content/locales/zh-TW/audit-log.mdx +2 -1
  72. package/corpus/core/docs/content/locales/zh-TW/automations.mdx +7 -7
  73. package/corpus/core/docs/content/locales/zh-TW/getting-started.mdx +6 -4
  74. package/corpus/core/docs/content/locales/zh-TW/internationalization.mdx +1 -1
  75. package/corpus/core/docs/content/locales/zh-TW/package-lifecycle.mdx +19 -0
  76. package/corpus/core/docs/content/locales/zh-TW/sandbox-adapters.mdx +18 -7
  77. package/corpus/core/docs/content/locales/zh-TW/security.mdx +8 -0
  78. package/corpus/core/docs/content/package-lifecycle.mdx +51 -0
  79. package/corpus/core/docs/content/sandbox-adapters.mdx +16 -5
  80. package/corpus/core/package.json +9 -2
  81. package/corpus/core/src/a2a/auth-policy.ts +33 -0
  82. package/corpus/core/src/agent/durable-background.ts +15 -7
  83. package/corpus/core/src/agent/run-store.ts +13 -4
  84. package/corpus/core/src/audit/actions/export-audit-events.ts +162 -0
  85. package/corpus/core/src/audit/store.ts +8 -3
  86. package/corpus/core/src/audit/types.ts +3 -0
  87. package/corpus/core/src/cli/doctor.ts +396 -0
  88. package/corpus/core/src/cli/index.ts +56 -0
  89. package/corpus/core/src/cli/info.ts +3 -3
  90. package/corpus/core/src/cli/package-lifecycle.ts +821 -0
  91. package/corpus/core/src/client/agent-chat-adapter.ts +9 -9
  92. package/corpus/core/src/guards/db-tool-scoping.ts +129 -0
  93. package/corpus/core/src/guards/index.ts +23 -0
  94. package/corpus/core/src/guards/no-drizzle-push.ts +116 -0
  95. package/corpus/core/src/guards/no-env-credentials.ts +229 -0
  96. package/corpus/core/src/guards/no-env-mutation.ts +114 -0
  97. package/corpus/core/src/guards/no-localhost-fallback.ts +124 -0
  98. package/corpus/core/src/guards/no-unscoped-credentials.ts +227 -0
  99. package/corpus/core/src/guards/no-unscoped-queries.ts +834 -0
  100. package/corpus/core/src/guards/scan-utils.ts +105 -0
  101. package/corpus/core/src/guards/types.ts +30 -0
  102. package/corpus/core/src/org/accept-pending.ts +9 -1
  103. package/corpus/core/src/org/migrations.ts +41 -0
  104. package/corpus/core/src/package-lifecycle/index.ts +1 -0
  105. package/corpus/core/src/package-lifecycle/manifest.ts +120 -0
  106. package/corpus/core/src/provider-api/custom-registry.ts +56 -0
  107. package/corpus/core/src/provider-api/index.ts +2 -0
  108. package/corpus/core/src/secrets/storage.ts +47 -27
  109. package/corpus/core/src/server/action-discovery.ts +4 -0
  110. package/corpus/core/src/server/agent-chat-plugin.ts +54 -12
  111. package/corpus/core/src/server/core-routes-plugin.ts +30 -14
  112. package/corpus/core/src/server/csrf.ts +24 -5
  113. package/corpus/core/src/server/framework-request-handler.ts +34 -0
  114. package/corpus/core/src/server/google-realtime-session.ts +1 -36
  115. package/corpus/core/src/server/poll.ts +24 -2
  116. package/corpus/core/src/server/realtime-voice.ts +9 -0
  117. package/corpus/core/src/server/request-origin.ts +63 -0
  118. package/corpus/core/src/server/transcribe-voice.ts +1 -50
  119. package/corpus/core/src/templates/default/package.json +2 -2
  120. package/corpus/core/src/templates/headless/package.json +0 -1
  121. package/corpus/core/src/templates/workspace-core/.agents/skills/audit-log/SKILL.md +3 -0
  122. package/corpus/core/src/templates/workspace-core/.agents/skills/automations/SKILL.md +1 -1
  123. package/corpus/core/src/templates/workspace-core/package.json +0 -1
  124. package/corpus/core/src/templates/workspace-root/package.json +0 -1
  125. package/corpus/core/src/triggers/actions.ts +11 -3
  126. package/corpus/core/src/triggers/types.ts +7 -1
  127. package/corpus/templates/analytics/actions/compose-dashboard.ts +65 -37
  128. package/corpus/templates/analytics/actions/mutate-dashboard.ts +73 -24
  129. package/corpus/templates/analytics/actions/reorder-dashboard-panels.ts +16 -13
  130. package/corpus/templates/analytics/actions/update-dashboard.ts +53 -42
  131. package/corpus/templates/analytics/changelog/2026-07-10-dashboard-edits-from-the-agent-and-the-ui-at-the-same-time-n.md +6 -0
  132. package/corpus/templates/analytics/changelog/2026-07-10-timed-out-bigquery-jobs-are-now-cancelled-so-they-stop-consu.md +6 -0
  133. package/corpus/templates/analytics/package.json +1 -2
  134. package/corpus/templates/analytics/server/lib/bigquery.ts +3 -2
  135. package/corpus/templates/analytics/server/lib/dashboards-store.ts +154 -11
  136. package/corpus/templates/assets/package.json +1 -2
  137. package/corpus/templates/brain/package.json +1 -2
  138. package/corpus/templates/calendar/package.json +1 -2
  139. package/corpus/templates/chat/package.json +1 -2
  140. package/corpus/templates/clips/changelog/2026-07-10-atomic-view-tracking.md +6 -0
  141. package/corpus/templates/clips/chrome-extension/package.json +3 -2
  142. package/corpus/templates/clips/desktop/package.json +6 -4
  143. package/corpus/templates/clips/desktop/src/lib/recorder.ts +26 -13
  144. package/corpus/templates/clips/desktop/src/lib/voice-dictation.ts +4 -1
  145. package/corpus/templates/clips/package.json +1 -2
  146. package/corpus/templates/clips/server/db/schema.ts +29 -17
  147. package/corpus/templates/clips/server/plugins/db.ts +8 -0
  148. package/corpus/templates/clips/server/routes/api/view-event.post.ts +260 -105
  149. package/corpus/templates/content/.agents/skills/notion-integration/SKILL.md +16 -0
  150. package/corpus/templates/content/AGENTS.md +72 -62
  151. package/corpus/templates/content/actions/_content-database-source-adapters.ts +84 -0
  152. package/corpus/templates/content/actions/_database-source-utils.ts +206 -96
  153. package/corpus/templates/content/actions/_notion-database-source-adapter.ts +216 -0
  154. package/corpus/templates/content/actions/_position-utils.ts +76 -0
  155. package/corpus/templates/content/actions/_property-utils.ts +31 -20
  156. package/corpus/templates/content/actions/add-database-item.ts +52 -39
  157. package/corpus/templates/content/actions/attach-content-database-source.ts +95 -11
  158. package/corpus/templates/content/actions/change-content-database-source-role.ts +24 -1
  159. package/corpus/templates/content/actions/configure-document-property.ts +36 -27
  160. package/corpus/templates/content/actions/create-content-database.ts +40 -30
  161. package/corpus/templates/content/actions/create-document.ts +39 -32
  162. package/corpus/templates/content/actions/duplicate-document-property.ts +37 -28
  163. package/corpus/templates/content/actions/list-notion-database-sources.ts +80 -0
  164. package/corpus/templates/content/actions/move-document.ts +64 -48
  165. package/corpus/templates/content/actions/refresh-content-database-source.ts +42 -3
  166. package/corpus/templates/content/actions/share-local-file-document.ts +36 -27
  167. package/corpus/templates/content/actions/suggest-source-join-key.ts +39 -16
  168. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +89 -23
  169. package/corpus/templates/content/app/components/editor/database/settings.tsx +1 -1
  170. package/corpus/templates/content/app/hooks/use-content-database.ts +18 -1
  171. package/corpus/templates/content/app/i18n/zh-TW.ts +4 -0
  172. package/corpus/templates/content/app/i18n-data.ts +40 -0
  173. package/corpus/templates/content/changelog/2026-07-10-failed-row-creation-and-source-attach-now-show-an-error-inst.md +6 -0
  174. package/corpus/templates/content/changelog/2026-07-10-items-added-at-the-same-time-no-longer-end-up-with-identical.md +6 -0
  175. package/corpus/templates/content/changelog/2026-07-10-notion-databases-can-add-read-only-details-to-content-tables.md +6 -0
  176. package/corpus/templates/content/package.json +1 -2
  177. package/corpus/templates/content/parity/matrix.md +25 -25
  178. package/corpus/templates/content/parity/matrix.ts +1 -0
  179. package/corpus/templates/content/server/routes/api/documents/[id]/move.patch.ts +43 -26
  180. package/corpus/templates/content/shared/api.ts +16 -1
  181. package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +8 -4
  182. package/corpus/templates/design/AGENTS.md +12 -2
  183. package/corpus/templates/design/DEVELOPING.md +10 -6
  184. package/corpus/templates/design/actions/apply-visual-edit.ts +191 -6
  185. package/corpus/templates/design/actions/duplicate-design.ts +31 -25
  186. package/corpus/templates/design/app/pages/design-editor/pending-edits.ts +5 -1
  187. package/corpus/templates/design/changelog/2026-07-10-duplicating-a-design-can-no-longer-produce-a-copy-with-missi.md +6 -0
  188. package/corpus/templates/design/changelog/2026-07-10-local-visual-edits-can-now-save-safe-leaf-text-class-and.md +6 -0
  189. package/corpus/templates/design/package.json +1 -1
  190. package/corpus/templates/design/shared/local-jsx-visual-edit.ts +388 -0
  191. package/corpus/templates/dispatch/package.json +1 -2
  192. package/corpus/templates/forms/actions/patch-form-fields.ts +82 -44
  193. package/corpus/templates/forms/changelog/2026-07-10-simultaneous-edits-to-different-form-fields-no-longer-overwr.md +6 -0
  194. package/corpus/templates/forms/package.json +1 -2
  195. package/corpus/templates/macros/package.json +1 -2
  196. package/corpus/templates/mail/app/components/email/EmailThread.tsx +3 -1
  197. package/corpus/templates/mail/changelog/2026-07-10-fixed-calendar-rsvp-buttons-in-emails-firing-duplicate-respo.md +6 -0
  198. package/corpus/templates/mail/package.json +1 -2
  199. package/corpus/templates/plan/actions/restore-plan-version.ts +126 -96
  200. package/corpus/templates/plan/changelog/2026-07-10-restoring-a-plan-version-can-no-longer-leave-a-plan-half-res.md +6 -0
  201. package/corpus/templates/plan/package.json +1 -2
  202. package/corpus/templates/plan/server/plans.ts +9 -2
  203. package/corpus/templates/slides/actions/list-decks.ts +28 -0
  204. package/corpus/templates/slides/app/components/deck/MermaidRenderer.tsx +41 -26
  205. package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +4 -8
  206. package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +2 -4
  207. package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +4 -8
  208. package/corpus/templates/slides/app/components/editor/ExportMenu.tsx +5 -12
  209. package/corpus/templates/slides/app/components/editor/HistoryPanel.tsx +3 -6
  210. package/corpus/templates/slides/app/components/editor/ImageDropPromptPopover.tsx +3 -6
  211. package/corpus/templates/slides/app/components/editor/PromptDialog.tsx +2 -5
  212. package/corpus/templates/slides/app/context/DeckContext.tsx +47 -4
  213. package/corpus/templates/slides/app/pages/DeckEditor.tsx +11 -30
  214. package/corpus/templates/slides/app/pages/Index.tsx +2 -3
  215. package/corpus/templates/slides/app/root.tsx +0 -5
  216. package/corpus/templates/slides/changelog/2026-07-10-deck-lists-load-much-faster-and-no-longer-re-download-slide-.md +6 -0
  217. package/corpus/templates/slides/package.json +1 -2
  218. package/dist/a2a/auth-policy.d.ts +19 -0
  219. package/dist/a2a/auth-policy.d.ts.map +1 -1
  220. package/dist/a2a/auth-policy.js +32 -0
  221. package/dist/a2a/auth-policy.js.map +1 -1
  222. package/dist/agent/durable-background.d.ts +8 -5
  223. package/dist/agent/durable-background.d.ts.map +1 -1
  224. package/dist/agent/durable-background.js +15 -8
  225. package/dist/agent/durable-background.js.map +1 -1
  226. package/dist/agent/run-store.d.ts.map +1 -1
  227. package/dist/agent/run-store.js +9 -4
  228. package/dist/agent/run-store.js.map +1 -1
  229. package/dist/audit/actions/export-audit-events.d.ts +27 -0
  230. package/dist/audit/actions/export-audit-events.d.ts.map +1 -0
  231. package/dist/audit/actions/export-audit-events.js +144 -0
  232. package/dist/audit/actions/export-audit-events.js.map +1 -0
  233. package/dist/audit/store.d.ts +1 -0
  234. package/dist/audit/store.d.ts.map +1 -1
  235. package/dist/audit/store.js +8 -3
  236. package/dist/audit/store.js.map +1 -1
  237. package/dist/audit/types.d.ts +3 -0
  238. package/dist/audit/types.d.ts.map +1 -1
  239. package/dist/audit/types.js.map +1 -1
  240. package/dist/cli/doctor.d.ts +83 -0
  241. package/dist/cli/doctor.d.ts.map +1 -0
  242. package/dist/cli/doctor.js +277 -0
  243. package/dist/cli/doctor.js.map +1 -0
  244. package/dist/cli/index.js +50 -0
  245. package/dist/cli/index.js.map +1 -1
  246. package/dist/cli/info.js +3 -3
  247. package/dist/cli/info.js.map +1 -1
  248. package/dist/cli/package-lifecycle.d.ts +50 -0
  249. package/dist/cli/package-lifecycle.d.ts.map +1 -0
  250. package/dist/cli/package-lifecycle.js +560 -0
  251. package/dist/cli/package-lifecycle.js.map +1 -0
  252. package/dist/client/agent-chat-adapter.js +7 -3
  253. package/dist/client/agent-chat-adapter.js.map +1 -1
  254. package/dist/collab/struct-routes.d.ts +1 -1
  255. package/dist/guards/db-tool-scoping.d.ts +38 -0
  256. package/dist/guards/db-tool-scoping.d.ts.map +1 -0
  257. package/dist/guards/db-tool-scoping.js +114 -0
  258. package/dist/guards/db-tool-scoping.js.map +1 -0
  259. package/dist/guards/index.d.ts +23 -0
  260. package/dist/guards/index.d.ts.map +1 -0
  261. package/dist/guards/index.js +19 -0
  262. package/dist/guards/index.js.map +1 -0
  263. package/dist/guards/no-drizzle-push.d.ts +14 -0
  264. package/dist/guards/no-drizzle-push.d.ts.map +1 -0
  265. package/dist/guards/no-drizzle-push.js +97 -0
  266. package/dist/guards/no-drizzle-push.js.map +1 -0
  267. package/dist/guards/no-env-credentials.d.ts +36 -0
  268. package/dist/guards/no-env-credentials.d.ts.map +1 -0
  269. package/dist/guards/no-env-credentials.js +204 -0
  270. package/dist/guards/no-env-credentials.js.map +1 -0
  271. package/dist/guards/no-env-mutation.d.ts +23 -0
  272. package/dist/guards/no-env-mutation.d.ts.map +1 -0
  273. package/dist/guards/no-env-mutation.js +90 -0
  274. package/dist/guards/no-env-mutation.js.map +1 -0
  275. package/dist/guards/no-localhost-fallback.d.ts +30 -0
  276. package/dist/guards/no-localhost-fallback.d.ts.map +1 -0
  277. package/dist/guards/no-localhost-fallback.js +105 -0
  278. package/dist/guards/no-localhost-fallback.js.map +1 -0
  279. package/dist/guards/no-unscoped-credentials.d.ts +28 -0
  280. package/dist/guards/no-unscoped-credentials.d.ts.map +1 -0
  281. package/dist/guards/no-unscoped-credentials.js +199 -0
  282. package/dist/guards/no-unscoped-credentials.js.map +1 -0
  283. package/dist/guards/no-unscoped-queries.d.ts +32 -0
  284. package/dist/guards/no-unscoped-queries.d.ts.map +1 -0
  285. package/dist/guards/no-unscoped-queries.js +720 -0
  286. package/dist/guards/no-unscoped-queries.js.map +1 -0
  287. package/dist/guards/scan-utils.d.ts +28 -0
  288. package/dist/guards/scan-utils.d.ts.map +1 -0
  289. package/dist/guards/scan-utils.js +92 -0
  290. package/dist/guards/scan-utils.js.map +1 -0
  291. package/dist/guards/types.d.ts +28 -0
  292. package/dist/guards/types.d.ts.map +1 -0
  293. package/dist/guards/types.js +11 -0
  294. package/dist/guards/types.js.map +1 -0
  295. package/dist/org/accept-pending.d.ts.map +1 -1
  296. package/dist/org/accept-pending.js +9 -1
  297. package/dist/org/accept-pending.js.map +1 -1
  298. package/dist/org/migrations.d.ts +7 -2
  299. package/dist/org/migrations.d.ts.map +1 -1
  300. package/dist/org/migrations.js +41 -0
  301. package/dist/org/migrations.js.map +1 -1
  302. package/dist/package-lifecycle/index.d.ts +2 -0
  303. package/dist/package-lifecycle/index.d.ts.map +1 -0
  304. package/dist/package-lifecycle/index.js +2 -0
  305. package/dist/package-lifecycle/index.js.map +1 -0
  306. package/dist/package-lifecycle/manifest.d.ts +24 -0
  307. package/dist/package-lifecycle/manifest.d.ts.map +1 -0
  308. package/dist/package-lifecycle/manifest.js +81 -0
  309. package/dist/package-lifecycle/manifest.js.map +1 -0
  310. package/dist/progress/routes.d.ts +1 -1
  311. package/dist/provider-api/custom-registry.d.ts +32 -1
  312. package/dist/provider-api/custom-registry.d.ts.map +1 -1
  313. package/dist/provider-api/custom-registry.js +41 -1
  314. package/dist/provider-api/custom-registry.js.map +1 -1
  315. package/dist/provider-api/index.d.ts +1 -1
  316. package/dist/provider-api/index.d.ts.map +1 -1
  317. package/dist/provider-api/index.js +1 -1
  318. package/dist/provider-api/index.js.map +1 -1
  319. package/dist/secrets/storage.d.ts.map +1 -1
  320. package/dist/secrets/storage.js +45 -27
  321. package/dist/secrets/storage.js.map +1 -1
  322. package/dist/server/action-discovery.d.ts.map +1 -1
  323. package/dist/server/action-discovery.js +4 -0
  324. package/dist/server/action-discovery.js.map +1 -1
  325. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  326. package/dist/server/agent-chat-plugin.js +47 -13
  327. package/dist/server/agent-chat-plugin.js.map +1 -1
  328. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  329. package/dist/server/core-routes-plugin.js +23 -12
  330. package/dist/server/core-routes-plugin.js.map +1 -1
  331. package/dist/server/csrf.d.ts.map +1 -1
  332. package/dist/server/csrf.js +18 -5
  333. package/dist/server/csrf.js.map +1 -1
  334. package/dist/server/framework-request-handler.d.ts.map +1 -1
  335. package/dist/server/framework-request-handler.js +34 -0
  336. package/dist/server/framework-request-handler.js.map +1 -1
  337. package/dist/server/google-realtime-session.d.ts.map +1 -1
  338. package/dist/server/google-realtime-session.js +2 -34
  339. package/dist/server/google-realtime-session.js.map +1 -1
  340. package/dist/server/poll.d.ts.map +1 -1
  341. package/dist/server/poll.js +24 -2
  342. package/dist/server/poll.js.map +1 -1
  343. package/dist/server/realtime-voice.d.ts.map +1 -1
  344. package/dist/server/realtime-voice.js +9 -0
  345. package/dist/server/realtime-voice.js.map +1 -1
  346. package/dist/server/request-origin.d.ts +10 -0
  347. package/dist/server/request-origin.d.ts.map +1 -0
  348. package/dist/server/request-origin.js +60 -0
  349. package/dist/server/request-origin.js.map +1 -0
  350. package/dist/server/transcribe-voice.d.ts.map +1 -1
  351. package/dist/server/transcribe-voice.js +2 -48
  352. package/dist/server/transcribe-voice.js.map +1 -1
  353. package/dist/templates/default/package.json +2 -2
  354. package/dist/templates/headless/package.json +0 -1
  355. package/dist/templates/workspace-core/.agents/skills/audit-log/SKILL.md +3 -0
  356. package/dist/templates/workspace-core/.agents/skills/automations/SKILL.md +1 -1
  357. package/dist/templates/workspace-core/package.json +0 -1
  358. package/dist/templates/workspace-root/package.json +0 -1
  359. package/dist/triggers/actions.d.ts.map +1 -1
  360. package/dist/triggers/actions.js +8 -3
  361. package/dist/triggers/actions.js.map +1 -1
  362. package/dist/triggers/types.d.ts +7 -1
  363. package/dist/triggers/types.d.ts.map +1 -1
  364. package/dist/triggers/types.js.map +1 -1
  365. package/docs/content/audit-log.mdx +2 -1
  366. package/docs/content/automations.mdx +7 -7
  367. package/docs/content/creating-templates.mdx +1 -1
  368. package/docs/content/internationalization.mdx +2 -1
  369. package/docs/content/locales/ar-SA/audit-log.mdx +2 -1
  370. package/docs/content/locales/ar-SA/automations.mdx +7 -7
  371. package/docs/content/locales/ar-SA/getting-started.mdx +7 -1
  372. package/docs/content/locales/ar-SA/internationalization.mdx +1 -1
  373. package/docs/content/locales/ar-SA/package-lifecycle.mdx +19 -0
  374. package/docs/content/locales/ar-SA/sandbox-adapters.mdx +18 -7
  375. package/docs/content/locales/ar-SA/security.mdx +8 -0
  376. package/docs/content/locales/de-DE/audit-log.mdx +2 -1
  377. package/docs/content/locales/de-DE/automations.mdx +7 -7
  378. package/docs/content/locales/de-DE/getting-started.mdx +7 -1
  379. package/docs/content/locales/de-DE/internationalization.mdx +1 -1
  380. package/docs/content/locales/de-DE/package-lifecycle.mdx +22 -0
  381. package/docs/content/locales/de-DE/sandbox-adapters.mdx +18 -7
  382. package/docs/content/locales/de-DE/security.mdx +8 -0
  383. package/docs/content/locales/es-ES/audit-log.mdx +2 -1
  384. package/docs/content/locales/es-ES/automations.mdx +7 -7
  385. package/docs/content/locales/es-ES/getting-started.mdx +7 -1
  386. package/docs/content/locales/es-ES/internationalization.mdx +1 -1
  387. package/docs/content/locales/es-ES/package-lifecycle.mdx +22 -0
  388. package/docs/content/locales/es-ES/sandbox-adapters.mdx +18 -7
  389. package/docs/content/locales/es-ES/security.mdx +8 -0
  390. package/docs/content/locales/fr-FR/audit-log.mdx +2 -1
  391. package/docs/content/locales/fr-FR/automations.mdx +7 -7
  392. package/docs/content/locales/fr-FR/getting-started.mdx +7 -1
  393. package/docs/content/locales/fr-FR/internationalization.mdx +1 -1
  394. package/docs/content/locales/fr-FR/package-lifecycle.mdx +21 -0
  395. package/docs/content/locales/fr-FR/sandbox-adapters.mdx +19 -8
  396. package/docs/content/locales/fr-FR/security.mdx +8 -0
  397. package/docs/content/locales/hi-IN/audit-log.mdx +2 -1
  398. package/docs/content/locales/hi-IN/automations.mdx +7 -7
  399. package/docs/content/locales/hi-IN/getting-started.mdx +7 -1
  400. package/docs/content/locales/hi-IN/internationalization.mdx +1 -1
  401. package/docs/content/locales/hi-IN/package-lifecycle.mdx +20 -0
  402. package/docs/content/locales/hi-IN/sandbox-adapters.mdx +18 -7
  403. package/docs/content/locales/hi-IN/security.mdx +8 -0
  404. package/docs/content/locales/ja-JP/audit-log.mdx +2 -1
  405. package/docs/content/locales/ja-JP/automations.mdx +7 -7
  406. package/docs/content/locales/ja-JP/getting-started.mdx +7 -1
  407. package/docs/content/locales/ja-JP/internationalization.mdx +1 -1
  408. package/docs/content/locales/ja-JP/package-lifecycle.mdx +21 -0
  409. package/docs/content/locales/ja-JP/sandbox-adapters.mdx +17 -6
  410. package/docs/content/locales/ja-JP/security.mdx +8 -0
  411. package/docs/content/locales/ko-KR/audit-log.mdx +2 -1
  412. package/docs/content/locales/ko-KR/automations.mdx +7 -7
  413. package/docs/content/locales/ko-KR/getting-started.mdx +7 -1
  414. package/docs/content/locales/ko-KR/internationalization.mdx +1 -1
  415. package/docs/content/locales/ko-KR/package-lifecycle.mdx +20 -0
  416. package/docs/content/locales/ko-KR/sandbox-adapters.mdx +17 -6
  417. package/docs/content/locales/ko-KR/security.mdx +8 -0
  418. package/docs/content/locales/pt-BR/audit-log.mdx +2 -1
  419. package/docs/content/locales/pt-BR/automations.mdx +7 -7
  420. package/docs/content/locales/pt-BR/getting-started.mdx +7 -1
  421. package/docs/content/locales/pt-BR/internationalization.mdx +1 -1
  422. package/docs/content/locales/pt-BR/package-lifecycle.mdx +21 -0
  423. package/docs/content/locales/pt-BR/sandbox-adapters.mdx +18 -7
  424. package/docs/content/locales/pt-BR/security.mdx +8 -0
  425. package/docs/content/locales/zh-CN/audit-log.mdx +2 -1
  426. package/docs/content/locales/zh-CN/automations.mdx +7 -7
  427. package/docs/content/locales/zh-CN/getting-started.mdx +6 -4
  428. package/docs/content/locales/zh-CN/internationalization.mdx +1 -1
  429. package/docs/content/locales/zh-CN/package-lifecycle.mdx +19 -0
  430. package/docs/content/locales/zh-CN/sandbox-adapters.mdx +17 -6
  431. package/docs/content/locales/zh-CN/security.mdx +8 -0
  432. package/docs/content/locales/zh-TW/audit-log.mdx +2 -1
  433. package/docs/content/locales/zh-TW/automations.mdx +7 -7
  434. package/docs/content/locales/zh-TW/getting-started.mdx +6 -4
  435. package/docs/content/locales/zh-TW/internationalization.mdx +1 -1
  436. package/docs/content/locales/zh-TW/package-lifecycle.mdx +19 -0
  437. package/docs/content/locales/zh-TW/sandbox-adapters.mdx +18 -7
  438. package/docs/content/locales/zh-TW/security.mdx +8 -0
  439. package/docs/content/package-lifecycle.mdx +51 -0
  440. package/docs/content/sandbox-adapters.mdx +16 -5
  441. package/package.json +10 -3
  442. package/src/templates/default/package.json +2 -2
  443. package/src/templates/headless/package.json +0 -1
  444. package/src/templates/workspace-core/.agents/skills/audit-log/SKILL.md +3 -0
  445. package/src/templates/workspace-core/.agents/skills/automations/SKILL.md +1 -1
  446. package/src/templates/workspace-core/package.json +0 -1
  447. package/src/templates/workspace-root/package.json +0 -1
  448. package/corpus/templates/slides/app/components/ui/toast.tsx +0 -1
  449. package/corpus/templates/slides/app/components/ui/toaster.tsx +0 -1
  450. package/corpus/templates/slides/app/hooks/use-toast.ts +0 -1
@@ -42,6 +42,10 @@ import {
42
42
  type DocumentPropertyValue,
43
43
  } from "../shared/properties.js";
44
44
  import { chunks } from "./_batch-utils.js";
45
+ import {
46
+ propertyDefinitionsPositionScope,
47
+ withPositionLock,
48
+ } from "./_position-utils.js";
45
49
 
46
50
  type DocumentRow = InferSelectModel<typeof schema.documents>;
47
51
  type ContentDatabaseRow = InferSelectModel<typeof schema.contentDatabases>;
@@ -1116,27 +1120,34 @@ export async function seedDefaultBlocksField(args: {
1116
1120
  if (database.primaryId) return database.primaryId;
1117
1121
  if (database.blocksSeeded === 1) return null;
1118
1122
 
1119
- const [maxPos] = await db
1120
- .select({ max: sql<number>`COALESCE(MAX(position), -1)` })
1121
- .from(schema.documentPropertyDefinitions)
1122
- .where(eq(schema.documentPropertyDefinitions.databaseId, args.databaseId));
1123
+ await withPositionLock(
1124
+ propertyDefinitionsPositionScope(args.databaseId),
1125
+ async () => {
1126
+ const [maxPos] = await db
1127
+ .select({ max: sql<number>`COALESCE(MAX(position), -1)` })
1128
+ .from(schema.documentPropertyDefinitions)
1129
+ .where(
1130
+ eq(schema.documentPropertyDefinitions.databaseId, args.databaseId),
1131
+ );
1123
1132
 
1124
- await db
1125
- .insert(schema.documentPropertyDefinitions)
1126
- .values({
1127
- id,
1128
- ownerEmail: args.ownerEmail,
1129
- orgId: args.orgId,
1130
- databaseId: args.databaseId,
1131
- name: DEFAULT_BLOCKS_FIELD_NAME,
1132
- type: "blocks",
1133
- visibility: "always_show",
1134
- optionsJson: serializePropertyOptions({ blocks: { primary: true } }),
1135
- position: (maxPos?.max ?? -1) + 1,
1136
- createdAt: args.now,
1137
- updatedAt: args.now,
1138
- })
1139
- .onConflictDoNothing();
1133
+ await db
1134
+ .insert(schema.documentPropertyDefinitions)
1135
+ .values({
1136
+ id,
1137
+ ownerEmail: args.ownerEmail,
1138
+ orgId: args.orgId,
1139
+ databaseId: args.databaseId,
1140
+ name: DEFAULT_BLOCKS_FIELD_NAME,
1141
+ type: "blocks",
1142
+ visibility: "always_show",
1143
+ optionsJson: serializePropertyOptions({ blocks: { primary: true } }),
1144
+ position: (maxPos?.max ?? -1) + 1,
1145
+ createdAt: args.now,
1146
+ updatedAt: args.now,
1147
+ })
1148
+ .onConflictDoNothing();
1149
+ },
1150
+ );
1140
1151
 
1141
1152
  const claim = await db
1142
1153
  .update(schema.contentDatabases)
@@ -11,6 +11,11 @@ import {
11
11
  type DocumentPropertyType,
12
12
  } from "../shared/properties.js";
13
13
  import { getContentDatabaseResponse } from "./_database-utils.js";
14
+ import {
15
+ databaseItemsPositionScope,
16
+ documentsPositionScope,
17
+ withPositionLock,
18
+ } from "./_position-utils.js";
14
19
  import { nanoid, normalizedValueJson } from "./_property-utils.js";
15
20
 
16
21
  export default defineAction({
@@ -44,48 +49,56 @@ export default defineAction({
44
49
  const databaseDocument = access.resource;
45
50
  const now = new Date().toISOString();
46
51
 
47
- const [maxDocPos] = await db
48
- .select({ max: sql<number>`COALESCE(MAX(position), -1)` })
49
- .from(schema.documents)
50
- .where(
51
- and(
52
- eq(schema.documents.ownerEmail, database.ownerEmail),
53
- eq(schema.documents.parentId, database.documentId),
54
- ),
55
- );
56
-
57
- const [maxItemPos] = await db
58
- .select({ max: sql<number>`COALESCE(MAX(position), -1)` })
59
- .from(schema.contentDatabaseItems)
60
- .where(eq(schema.contentDatabaseItems.databaseId, databaseId));
61
-
62
52
  const documentId = nanoid();
63
53
  const itemId = nanoid();
64
- await db.insert(schema.documents).values({
65
- id: documentId,
66
- ownerEmail: database.ownerEmail,
67
- orgId: database.orgId,
68
- parentId: database.documentId,
69
- title: title?.trim() ?? "",
70
- content: "",
71
- icon: null,
72
- position: (maxDocPos?.max ?? -1) + 1,
73
- isFavorite: 0,
74
- hideFromSearch: databaseDocument.hideFromSearch ?? 0,
75
- visibility: databaseDocument.visibility ?? "private",
76
- createdAt: now,
77
- updatedAt: now,
78
- });
79
54
 
80
- await db.insert(schema.contentDatabaseItems).values({
81
- id: itemId,
82
- ownerEmail: database.ownerEmail,
83
- orgId: database.orgId,
84
- databaseId,
85
- documentId,
86
- position: (maxItemPos?.max ?? -1) + 1,
87
- createdAt: now,
88
- updatedAt: now,
55
+ await withPositionLock(
56
+ documentsPositionScope(database.ownerEmail, database.documentId),
57
+ async () => {
58
+ const [maxDocPos] = await db
59
+ .select({ max: sql<number>`COALESCE(MAX(position), -1)` })
60
+ .from(schema.documents)
61
+ .where(
62
+ and(
63
+ eq(schema.documents.ownerEmail, database.ownerEmail),
64
+ eq(schema.documents.parentId, database.documentId),
65
+ ),
66
+ );
67
+
68
+ await db.insert(schema.documents).values({
69
+ id: documentId,
70
+ ownerEmail: database.ownerEmail,
71
+ orgId: database.orgId,
72
+ parentId: database.documentId,
73
+ title: title?.trim() ?? "",
74
+ content: "",
75
+ icon: null,
76
+ position: (maxDocPos?.max ?? -1) + 1,
77
+ isFavorite: 0,
78
+ hideFromSearch: databaseDocument.hideFromSearch ?? 0,
79
+ visibility: databaseDocument.visibility ?? "private",
80
+ createdAt: now,
81
+ updatedAt: now,
82
+ });
83
+ },
84
+ );
85
+
86
+ await withPositionLock(databaseItemsPositionScope(databaseId), async () => {
87
+ const [maxItemPos] = await db
88
+ .select({ max: sql<number>`COALESCE(MAX(position), -1)` })
89
+ .from(schema.contentDatabaseItems)
90
+ .where(eq(schema.contentDatabaseItems.databaseId, databaseId));
91
+
92
+ await db.insert(schema.contentDatabaseItems).values({
93
+ id: itemId,
94
+ ownerEmail: database.ownerEmail,
95
+ orgId: database.orgId,
96
+ databaseId,
97
+ documentId,
98
+ position: (maxItemPos?.max ?? -1) + 1,
99
+ createdAt: now,
100
+ updatedAt: now,
101
+ });
89
102
  });
90
103
 
91
104
  const inheritedShares = await db
@@ -15,6 +15,7 @@ import {
15
15
  type BuilderCmsReadResult,
16
16
  } from "./_builder-cms-read-client.js";
17
17
  import type { BuilderCmsSourceEntry } from "./_builder-cms-source-adapter.js";
18
+ import { getContentDatabaseSourceAdapter } from "./_content-database-source-adapters.js";
18
19
  import {
19
20
  databaseSourceExistsForTable,
20
21
  enqueueBuilderBodyHydrationForItems,
@@ -32,6 +33,7 @@ import {
32
33
  sourceSetupPayload,
33
34
  storeSecondarySourceRows,
34
35
  updateBuilderCmsSourceReadMetadata,
36
+ updateReadOnlySourceMetadata,
35
37
  writeSourceFederation,
36
38
  } from "./_database-source-utils.js";
37
39
  import { getContentDatabaseResponse } from "./_database-utils.js";
@@ -41,7 +43,7 @@ import {
41
43
  } from "./_local-table-source.js";
42
44
 
43
45
  const sourceTypeSchema = z
44
- .enum(["mock-local", "builder-cms", "local-table"])
46
+ .enum(["mock-local", "builder-cms", "local-table", "notion-database"])
45
47
  .default("mock-local");
46
48
  const BUILDER_CMS_ATTACH_INITIAL_PAGES = 1;
47
49
 
@@ -237,14 +239,23 @@ export default defineAction({
237
239
  const now = new Date().toISOString();
238
240
  const sourceType = (args.sourceType ??
239
241
  "mock-local") as ContentDatabaseSourceType;
242
+ if (sourceType === "notion-database" && !args.sourceTable?.trim()) {
243
+ throw new Error(
244
+ "sourceTable must be a Notion data-source ID returned by list-notion-database-sources.",
245
+ );
246
+ }
240
247
  const sourceName =
241
248
  args.sourceName?.trim() ||
242
- (sourceType === "builder-cms" ? "Builder CMS" : "Mock local source");
249
+ (sourceType === "builder-cms"
250
+ ? "Builder CMS"
251
+ : sourceType === "notion-database"
252
+ ? "Notion database"
253
+ : "Mock local source");
243
254
  const sourceTable =
244
255
  args.sourceTable?.trim() ||
245
256
  (sourceType === "builder-cms" ? "blog_article" : "content_items");
246
257
 
247
- const existingSource = await getExistingSource(database.id);
258
+ let existingSource = await getExistingSource(database.id);
248
259
  if (sourceType === "local-table") {
249
260
  if (sourceTable === database.id) {
250
261
  throw new Error("A database can't be added as a source of itself.");
@@ -255,6 +266,41 @@ export default defineAction({
255
266
  const relationshipMode =
256
267
  args.relationshipMode ?? (args.mode === "add" ? "items" : undefined);
257
268
 
269
+ // A normal local Content database has rows but no explicit source record.
270
+ // Bootstrap that local snapshot before attaching a read-only details source
271
+ // so Notion federation works without forcing users to attach Builder first.
272
+ if (
273
+ sourceType === "notion-database" &&
274
+ relationshipMode === "details" &&
275
+ !existingSource
276
+ ) {
277
+ const setup = await sourceSetupPayload(database.id);
278
+ const localSourceId = await replaceSourceMetadata({
279
+ database,
280
+ source: null,
281
+ sourceType: "mock-local",
282
+ sourceName: "Local Content database",
283
+ sourceTable: database.id,
284
+ now,
285
+ });
286
+ await seedMockSourceFields({
287
+ sourceId: localSourceId,
288
+ ownerEmail: database.ownerEmail,
289
+ sourceType: "mock-local",
290
+ properties: setup.properties,
291
+ now,
292
+ });
293
+ await seedMockSourceRows({
294
+ sourceId: localSourceId,
295
+ ownerEmail: database.ownerEmail,
296
+ sourceType: "mock-local",
297
+ sourceTable: database.id,
298
+ items: setup.response.items,
299
+ now,
300
+ });
301
+ existingSource = await getExistingSource(database.id);
302
+ }
303
+
258
304
  // Adding a SECOND source as details: relate it onto the primary on the
259
305
  // canonical key. Read-only overlay — the secondary's entries are NOT
260
306
  // imported as local documents/items.
@@ -265,17 +311,35 @@ export default defineAction({
265
311
  let entries: BuilderCmsSourceEntry[];
266
312
  let modelFields: BuilderCmsModelFieldSummary[];
267
313
  let builderRead: BuilderCmsReadResult | null = null;
268
- if (sourceType === "builder-cms") {
314
+ let adapterMetadata: Record<string, unknown> | undefined;
315
+ let adapterFetchedAt = now;
316
+ let adapterMessage: string | null = null;
317
+ const adapter = getContentDatabaseSourceAdapter(sourceType);
318
+ if (adapter) {
319
+ const read = await adapter.read({
320
+ sourceTable,
321
+ limit: args.limit,
322
+ offset: args.offset,
323
+ });
324
+ entries = read.state === "live" ? read.entries : [];
325
+ modelFields = read.fields;
326
+ adapterMetadata = read.metadata;
327
+ adapterFetchedAt = read.fetchedAt;
328
+ adapterMessage = read.message;
329
+ if (sourceType === "builder-cms") {
330
+ builderRead = {
331
+ state: read.state,
332
+ entries: read.entries,
333
+ fetchedAt: read.fetchedAt,
334
+ message: read.message,
335
+ progress: read.progress!,
336
+ };
337
+ }
338
+ } else if (sourceType === "builder-cms") {
269
339
  const initial = await readInitialBuilderCmsAttachSource(sourceTable);
270
340
  modelFields = initial.modelFields;
271
341
  builderRead = initial.read;
272
342
  entries = builderRead.state === "live" ? builderRead.entries : [];
273
- } else if (sourceType === "local-table") {
274
- // sourceTable carries the target database id for a local-table source.
275
- ({ entries, modelFields } = await readLocalTableEntries(sourceTable, {
276
- limit: args.limit,
277
- offset: args.offset,
278
- }));
279
343
  } else {
280
344
  entries = [];
281
345
  modelFields = [];
@@ -299,6 +363,7 @@ export default defineAction({
299
363
  await seedSecondarySourceFields({
300
364
  sourceId: secondaryId,
301
365
  ownerEmail: database.ownerEmail,
366
+ sourceType,
302
367
  modelFields,
303
368
  sampleEntry: entries[0],
304
369
  now,
@@ -317,6 +382,17 @@ export default defineAction({
317
382
  ...builderCmsAttachReadMetadata(builderRead),
318
383
  });
319
384
  }
385
+ if (sourceType === "notion-database") {
386
+ await updateReadOnlySourceMetadata({
387
+ sourceId: secondaryId,
388
+ sourceType,
389
+ sourceTable,
390
+ fetchedAt: adapterFetchedAt,
391
+ now,
392
+ message: adapterMessage,
393
+ metadata: adapterMetadata,
394
+ });
395
+ }
320
396
  await writeSourceFederation({
321
397
  sourceId: secondaryId,
322
398
  federation: identityFederation(
@@ -458,7 +534,15 @@ export default defineAction({
458
534
  }
459
535
 
460
536
  if (relationshipMode === "items" && existingSource) {
461
- throw new Error("Only Builder sources can add more items right now.");
537
+ throw new Error(
538
+ "Only Builder sources can add more items right now. Notion database sources are read-only detail sources in this pilot.",
539
+ );
540
+ }
541
+
542
+ if (sourceType === "notion-database") {
543
+ throw new Error(
544
+ "Notion database sources are read-only detail sources in this pilot. Attach a local or Builder source first, then add Notion details with a match key.",
545
+ );
462
546
  }
463
547
 
464
548
  const existingSourceRows = existingSource
@@ -16,6 +16,7 @@ import {
16
16
  readBuilderCmsModelFields,
17
17
  } from "./_builder-cms-read-client.js";
18
18
  import type { BuilderCmsSourceEntry } from "./_builder-cms-source-adapter.js";
19
+ import { getContentDatabaseSourceAdapter } from "./_content-database-source-adapters.js";
19
20
  import {
20
21
  enqueueBuilderBodyHydrationForItems,
21
22
  ensureDatabaseSourceProperty,
@@ -109,7 +110,12 @@ function identityFederation(
109
110
  }
110
111
 
111
112
  function sourceType(value: string): ContentDatabaseSourceType {
112
- if (value === "builder-cms" || value === "local-table") return value;
113
+ if (
114
+ value === "builder-cms" ||
115
+ value === "local-table" ||
116
+ value === "notion-database"
117
+ )
118
+ return value;
113
119
  return "mock-local";
114
120
  }
115
121
 
@@ -255,6 +261,22 @@ async function readSourceEntries(args: {
255
261
  message: null,
256
262
  };
257
263
  }
264
+ if (args.sourceType === "notion-database") {
265
+ const read = await getContentDatabaseSourceAdapter("notion-database")!.read(
266
+ {
267
+ sourceTable: args.sourceTable,
268
+ limit: args.limit,
269
+ offset: args.offset,
270
+ },
271
+ );
272
+ return {
273
+ entries: read.entries,
274
+ modelFields: read.fields,
275
+ readState: read.state,
276
+ fetchedAt: read.fetchedAt,
277
+ message: read.message,
278
+ };
279
+ }
258
280
  return {
259
281
  entries: [],
260
282
  modelFields: [],
@@ -330,6 +352,7 @@ export default defineAction({
330
352
  await seedSecondarySourceFields({
331
353
  sourceId: source.id,
332
354
  ownerEmail: database.ownerEmail,
355
+ sourceType: normalizedType,
333
356
  modelFields,
334
357
  sampleEntry: entries[0],
335
358
  now,
@@ -16,6 +16,10 @@ import {
16
16
  normalizePropertyVisibility,
17
17
  type DocumentPropertyType,
18
18
  } from "../shared/properties.js";
19
+ import {
20
+ propertyDefinitionsPositionScope,
21
+ withPositionLock,
22
+ } from "./_position-utils.js";
19
23
  import {
20
24
  listPropertiesForDocument,
21
25
  nanoid,
@@ -168,34 +172,39 @@ export default defineAction({
168
172
  })
169
173
  .where(eq(schema.documentPropertyDefinitions.id, args.id));
170
174
  } else {
171
- const [maxPos] = await db
172
- .select({
173
- max: sql<number>`COALESCE(MAX(position), -1)`,
174
- })
175
- .from(schema.documentPropertyDefinitions)
176
- .where(
177
- and(
178
- eq(
179
- schema.documentPropertyDefinitions.ownerEmail,
180
- document.ownerEmail,
181
- ),
182
- eq(schema.documentPropertyDefinitions.databaseId, database.id),
183
- ),
184
- );
175
+ await withPositionLock(
176
+ propertyDefinitionsPositionScope(database.id),
177
+ async () => {
178
+ const [maxPos] = await db
179
+ .select({
180
+ max: sql<number>`COALESCE(MAX(position), -1)`,
181
+ })
182
+ .from(schema.documentPropertyDefinitions)
183
+ .where(
184
+ and(
185
+ eq(
186
+ schema.documentPropertyDefinitions.ownerEmail,
187
+ document.ownerEmail,
188
+ ),
189
+ eq(schema.documentPropertyDefinitions.databaseId, database.id),
190
+ ),
191
+ );
185
192
 
186
- await db.insert(schema.documentPropertyDefinitions).values({
187
- id: nanoid(),
188
- ownerEmail: document.ownerEmail,
189
- orgId: document.orgId ?? null,
190
- databaseId: database.id,
191
- name,
192
- type,
193
- visibility: normalizePropertyVisibility(args.visibility),
194
- optionsJson,
195
- position: (maxPos?.max ?? -1) + 1,
196
- createdAt: now,
197
- updatedAt: now,
198
- });
193
+ await db.insert(schema.documentPropertyDefinitions).values({
194
+ id: nanoid(),
195
+ ownerEmail: document.ownerEmail,
196
+ orgId: document.orgId ?? null,
197
+ databaseId: database.id,
198
+ name,
199
+ type,
200
+ visibility: normalizePropertyVisibility(args.visibility),
201
+ optionsJson,
202
+ position: (maxPos?.max ?? -1) + 1,
203
+ createdAt: now,
204
+ updatedAt: now,
205
+ });
206
+ },
207
+ );
199
208
  }
200
209
 
201
210
  await writeAppState("refresh-signal", { ts: Date.now() });
@@ -15,6 +15,7 @@ import type {
15
15
  CreateDatabaseRequest,
16
16
  } from "../shared/api.js";
17
17
  import { getContentDatabaseResponse } from "./_database-utils.js";
18
+ import { documentsPositionScope, withPositionLock } from "./_position-utils.js";
18
19
  import { nanoid, seedDefaultBlocksField } from "./_property-utils.js";
19
20
 
20
21
  const createContentDatabaseSchema = z.object({
@@ -132,37 +133,46 @@ export async function createContentDatabaseRecord(
132
133
  .where(eq(schema.documentShares.resourceId, parentId));
133
134
  }
134
135
 
135
- const [maxPos] = await db
136
- .select({ max: sql<number>`COALESCE(MAX(position), -1)` })
137
- .from(schema.documents)
138
- .where(
139
- parentId
140
- ? and(
141
- eq(schema.documents.ownerEmail, ownerEmail),
142
- eq(schema.documents.parentId, parentId),
143
- )
144
- : and(
145
- eq(schema.documents.ownerEmail, ownerEmail),
146
- sql`parent_id IS NULL`,
147
- ),
148
- );
149
-
150
136
  documentId = nanoid();
151
- await db.insert(schema.documents).values({
152
- id: documentId,
153
- ownerEmail,
154
- orgId,
155
- parentId,
156
- title,
157
- content: "",
158
- icon: null,
159
- position: (maxPos?.max ?? -1) + 1,
160
- isFavorite: 0,
161
- hideFromSearch,
162
- visibility,
163
- createdAt: now,
164
- updatedAt: now,
165
- });
137
+ // Snapshot as a const so the closure below keeps TypeScript's
138
+ // non-undefined narrowing from the guard above (`let` bindings lose
139
+ // narrowing across a closure boundary).
140
+ const resolvedOwnerEmail = ownerEmail;
141
+ await withPositionLock(
142
+ documentsPositionScope(resolvedOwnerEmail, parentId),
143
+ async () => {
144
+ const [maxPos] = await db
145
+ .select({ max: sql<number>`COALESCE(MAX(position), -1)` })
146
+ .from(schema.documents)
147
+ .where(
148
+ parentId
149
+ ? and(
150
+ eq(schema.documents.ownerEmail, resolvedOwnerEmail),
151
+ eq(schema.documents.parentId, parentId),
152
+ )
153
+ : and(
154
+ eq(schema.documents.ownerEmail, resolvedOwnerEmail),
155
+ sql`parent_id IS NULL`,
156
+ ),
157
+ );
158
+
159
+ await db.insert(schema.documents).values({
160
+ id: documentId!,
161
+ ownerEmail: resolvedOwnerEmail,
162
+ orgId,
163
+ parentId,
164
+ title,
165
+ content: "",
166
+ icon: null,
167
+ position: (maxPos?.max ?? -1) + 1,
168
+ isFavorite: 0,
169
+ hideFromSearch,
170
+ visibility,
171
+ createdAt: now,
172
+ updatedAt: now,
173
+ });
174
+ },
175
+ );
166
176
 
167
177
  if (inheritedShares.length > 0) {
168
178
  await db.insert(schema.documentShares).values(
@@ -18,6 +18,7 @@ import {
18
18
  createLocalFileDocument,
19
19
  isContentLocalFileMode,
20
20
  } from "./_local-file-documents.js";
21
+ import { documentsPositionScope, withPositionLock } from "./_position-utils.js";
21
22
 
22
23
  function nanoid(size = 12): string {
23
24
  const chars =
@@ -122,41 +123,47 @@ export default defineAction({
122
123
  .where(eq(schema.documentShares.resourceId, parentId));
123
124
  }
124
125
 
125
- // Get max position among siblings
126
- const maxPos = await db
127
- .select({ max: sql<number>`COALESCE(MAX(position), -1)` })
128
- .from(schema.documents)
129
- .where(
130
- parentId
131
- ? and(
132
- eq(schema.documents.ownerEmail, ownerEmail),
133
- eq(schema.documents.parentId, parentId),
134
- )
135
- : and(
136
- eq(schema.documents.ownerEmail, ownerEmail),
137
- sql`parent_id IS NULL`,
138
- ),
139
- );
140
-
141
- const position = (maxPos[0]?.max ?? -1) + 1;
142
126
  const now = new Date().toISOString();
143
127
  const id = args.id || nanoid();
144
128
 
145
- await db.insert(schema.documents).values({
146
- id,
147
- ownerEmail,
148
- orgId,
149
- parentId,
150
- title,
151
- content,
152
- icon,
153
- position,
154
- isFavorite: 0,
155
- hideFromSearch,
156
- visibility,
157
- createdAt: now,
158
- updatedAt: now,
159
- });
129
+ await withPositionLock(
130
+ documentsPositionScope(ownerEmail, parentId),
131
+ async () => {
132
+ // Get max position among siblings
133
+ const maxPos = await db
134
+ .select({ max: sql<number>`COALESCE(MAX(position), -1)` })
135
+ .from(schema.documents)
136
+ .where(
137
+ parentId
138
+ ? and(
139
+ eq(schema.documents.ownerEmail, ownerEmail),
140
+ eq(schema.documents.parentId, parentId),
141
+ )
142
+ : and(
143
+ eq(schema.documents.ownerEmail, ownerEmail),
144
+ sql`parent_id IS NULL`,
145
+ ),
146
+ );
147
+
148
+ const position = (maxPos[0]?.max ?? -1) + 1;
149
+
150
+ await db.insert(schema.documents).values({
151
+ id,
152
+ ownerEmail,
153
+ orgId,
154
+ parentId,
155
+ title,
156
+ content,
157
+ icon,
158
+ position,
159
+ isFavorite: 0,
160
+ hideFromSearch,
161
+ visibility,
162
+ createdAt: now,
163
+ updatedAt: now,
164
+ });
165
+ },
166
+ );
160
167
 
161
168
  if (inheritedShares.length > 0) {
162
169
  await db.insert(schema.documentShares).values(