primitive-admin 1.2.0-alpha.1 → 1.2.0-alpha.11

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 (410) hide show
  1. package/README.md +105 -134
  2. package/assets/skill/skills/primitive-platform/SKILL.md +37 -4
  3. package/dist/bin/primitive.js +30 -35
  4. package/dist/bin/primitive.js.map +1 -1
  5. package/dist/src/commands/agent-sessions.d.ts +133 -0
  6. package/dist/src/commands/agent-sessions.js +792 -0
  7. package/dist/src/commands/agent-sessions.js.map +1 -0
  8. package/dist/src/commands/analytics.js +0 -148
  9. package/dist/src/commands/analytics.js.map +1 -1
  10. package/dist/src/commands/apps-children.d.ts +54 -0
  11. package/dist/src/commands/apps-children.js +631 -0
  12. package/dist/src/commands/apps-children.js.map +1 -0
  13. package/dist/src/commands/apps.d.ts +6 -0
  14. package/dist/src/commands/apps.js +131 -9
  15. package/dist/src/commands/apps.js.map +1 -1
  16. package/dist/src/commands/auth-sessions.d.ts +3 -3
  17. package/dist/src/commands/auth-sessions.js +117 -23
  18. package/dist/src/commands/auth-sessions.js.map +1 -1
  19. package/dist/src/commands/auth.js +460 -36
  20. package/dist/src/commands/auth.js.map +1 -1
  21. package/dist/src/commands/collections.js +316 -256
  22. package/dist/src/commands/collections.js.map +1 -1
  23. package/dist/src/commands/config.d.ts +1 -1
  24. package/dist/src/commands/config.js +60 -28
  25. package/dist/src/commands/config.js.map +1 -1
  26. package/dist/src/commands/connections.js +11 -12
  27. package/dist/src/commands/connections.js.map +1 -1
  28. package/dist/src/commands/database-type-configs.js +2 -76
  29. package/dist/src/commands/database-type-configs.js.map +1 -1
  30. package/dist/src/commands/databases.d.ts +9 -0
  31. package/dist/src/commands/databases.js +221 -457
  32. package/dist/src/commands/databases.js.map +1 -1
  33. package/dist/src/commands/db3-types.d.ts +15 -0
  34. package/dist/src/commands/db3-types.js +157 -0
  35. package/dist/src/commands/db3-types.js.map +1 -0
  36. package/dist/src/commands/db3.d.ts +12 -0
  37. package/dist/src/commands/db3.js +1052 -0
  38. package/dist/src/commands/db3.js.map +1 -0
  39. package/dist/src/commands/documents.d.ts +121 -2
  40. package/dist/src/commands/documents.js +1601 -1251
  41. package/dist/src/commands/documents.js.map +1 -1
  42. package/dist/src/commands/env.d.ts +9 -1
  43. package/dist/src/commands/env.js +164 -49
  44. package/dist/src/commands/env.js.map +1 -1
  45. package/dist/src/commands/function-trigger-commands.d.ts +28 -0
  46. package/dist/src/commands/function-trigger-commands.js +341 -0
  47. package/dist/src/commands/function-trigger-commands.js.map +1 -0
  48. package/dist/src/commands/functions.js +297 -24
  49. package/dist/src/commands/functions.js.map +1 -1
  50. package/dist/src/commands/groups.js +150 -49
  51. package/dist/src/commands/groups.js.map +1 -1
  52. package/dist/src/commands/guides.js +5 -5
  53. package/dist/src/commands/init.d.ts +7 -0
  54. package/dist/src/commands/init.js +23 -5
  55. package/dist/src/commands/init.js.map +1 -1
  56. package/dist/src/commands/integrations.js +14 -8
  57. package/dist/src/commands/integrations.js.map +1 -1
  58. package/dist/src/commands/metadata-category-configs.d.ts +2 -2
  59. package/dist/src/commands/metadata-category-configs.js +2 -2
  60. package/dist/src/commands/prompts.d.ts +7 -0
  61. package/dist/src/commands/prompts.js +48 -5
  62. package/dist/src/commands/prompts.js.map +1 -1
  63. package/dist/src/commands/scripts.d.ts +9 -17
  64. package/dist/src/commands/scripts.js +24 -479
  65. package/dist/src/commands/scripts.js.map +1 -1
  66. package/dist/src/commands/sync-app-settings.d.ts +36 -8
  67. package/dist/src/commands/sync-app-settings.js +109 -23
  68. package/dist/src/commands/sync-app-settings.js.map +1 -1
  69. package/dist/src/commands/sync.d.ts +360 -610
  70. package/dist/src/commands/sync.js +3151 -6697
  71. package/dist/src/commands/sync.js.map +1 -1
  72. package/dist/src/commands/tokens.js +3 -3
  73. package/dist/src/commands/tokens.js.map +1 -1
  74. package/dist/src/commands/users.js +77 -2
  75. package/dist/src/commands/users.js.map +1 -1
  76. package/dist/src/commands/workflows.d.ts +5 -83
  77. package/dist/src/commands/workflows.js +57 -2282
  78. package/dist/src/commands/workflows.js.map +1 -1
  79. package/dist/src/lib/aggregate-output.d.ts +25 -0
  80. package/dist/src/lib/aggregate-output.js +53 -0
  81. package/dist/src/lib/aggregate-output.js.map +1 -0
  82. package/dist/src/lib/api-client.d.ts +681 -551
  83. package/dist/src/lib/api-client.js +880 -814
  84. package/dist/src/lib/api-client.js.map +1 -1
  85. package/dist/src/lib/app-settings-descriptor.d.ts +47 -1
  86. package/dist/src/lib/app-settings-descriptor.js +114 -10
  87. package/dist/src/lib/app-settings-descriptor.js.map +1 -1
  88. package/dist/src/lib/auth-fixtures.d.ts +44 -0
  89. package/dist/src/lib/auth-fixtures.js +61 -0
  90. package/dist/src/lib/auth-fixtures.js.map +1 -0
  91. package/dist/src/lib/auth-flow.d.ts +41 -1
  92. package/dist/src/lib/auth-flow.js +70 -16
  93. package/dist/src/lib/auth-flow.js.map +1 -1
  94. package/dist/src/lib/block-layout.d.ts +12 -23
  95. package/dist/src/lib/block-layout.js +26 -92
  96. package/dist/src/lib/block-layout.js.map +1 -1
  97. package/dist/src/lib/block-selector.d.ts +2 -2
  98. package/dist/src/lib/block-selector.js +2 -2
  99. package/dist/src/lib/child-apps-local.d.ts +164 -0
  100. package/dist/src/lib/child-apps-local.js +258 -0
  101. package/dist/src/lib/child-apps-local.js.map +1 -0
  102. package/dist/src/lib/ci-session-request.d.ts +22 -0
  103. package/dist/src/lib/ci-session-request.js +51 -0
  104. package/dist/src/lib/ci-session-request.js.map +1 -0
  105. package/dist/src/lib/codegen-shared/generatedFiles.d.ts +10 -8
  106. package/dist/src/lib/codegen-shared/generatedFiles.js +21 -15
  107. package/dist/src/lib/codegen-shared/generatedFiles.js.map +1 -1
  108. package/dist/src/lib/codegen-shared/prettierStable.d.ts +1 -1
  109. package/dist/src/lib/codegen-shared/prettierStable.js +1 -1
  110. package/dist/src/lib/codegen-shared/resolveCodegenSourceDir.d.ts +2 -2
  111. package/dist/src/lib/codegen-shared/resolveCodegenSourceDir.js +2 -2
  112. package/dist/src/lib/collection-export.d.ts +76 -15
  113. package/dist/src/lib/collection-export.js +116 -23
  114. package/dist/src/lib/collection-export.js.map +1 -1
  115. package/dist/src/lib/collection-principal.d.ts +22 -0
  116. package/dist/src/lib/collection-principal.js +35 -0
  117. package/dist/src/lib/collection-principal.js.map +1 -0
  118. package/dist/src/lib/config-object-descriptor.d.ts +3 -22
  119. package/dist/src/lib/config-object-descriptor.js +56 -290
  120. package/dist/src/lib/config-object-descriptor.js.map +1 -1
  121. package/dist/src/lib/config-payload.js +2 -3
  122. package/dist/src/lib/config-payload.js.map +1 -1
  123. package/dist/src/lib/config-surface.d.ts +5 -7
  124. package/dist/src/lib/config-surface.js +18 -40
  125. package/dist/src/lib/config-surface.js.map +1 -1
  126. package/dist/src/lib/connections-list.d.ts +10 -0
  127. package/dist/src/lib/connections-list.js +18 -0
  128. package/dist/src/lib/connections-list.js.map +1 -0
  129. package/dist/src/lib/credentials-home.d.ts +58 -0
  130. package/dist/src/lib/credentials-home.js +204 -0
  131. package/dist/src/lib/credentials-home.js.map +1 -0
  132. package/dist/src/lib/credentials-lock.d.ts +88 -0
  133. package/dist/src/lib/credentials-lock.js +302 -0
  134. package/dist/src/lib/credentials-lock.js.map +1 -0
  135. package/dist/src/lib/credentials-store.d.ts +179 -24
  136. package/dist/src/lib/credentials-store.js +712 -77
  137. package/dist/src/lib/credentials-store.js.map +1 -1
  138. package/dist/src/lib/csv.d.ts +8 -9
  139. package/dist/src/lib/csv.js +3 -4
  140. package/dist/src/lib/csv.js.map +1 -1
  141. package/dist/src/lib/custodian.d.ts +8 -0
  142. package/dist/src/lib/custodian.js +18 -0
  143. package/dist/src/lib/custodian.js.map +1 -0
  144. package/dist/src/lib/db-codegen/dbGenerator.js +5 -16
  145. package/dist/src/lib/db-codegen/dbGenerator.js.map +1 -1
  146. package/dist/src/lib/db-codegen/dbNaming.d.ts +5 -13
  147. package/dist/src/lib/db-codegen/dbNaming.js +5 -17
  148. package/dist/src/lib/db-codegen/dbNaming.js.map +1 -1
  149. package/dist/src/lib/db-codegen/dbTemplates.d.ts +7 -56
  150. package/dist/src/lib/db-codegen/dbTemplates.js +25 -125
  151. package/dist/src/lib/db-codegen/dbTemplates.js.map +1 -1
  152. package/dist/src/lib/db-codegen/dbTsTypes.d.ts +2 -2
  153. package/dist/src/lib/db-codegen/dbTsTypes.js +2 -2
  154. package/dist/src/lib/db-codegen/dbTypeIR.d.ts +67 -2
  155. package/dist/src/lib/db-codegen/dbTypeIR.js +13 -2
  156. package/dist/src/lib/db-codegen/dbTypeIR.js.map +1 -1
  157. package/dist/src/lib/db3-export.d.ts +231 -0
  158. package/dist/src/lib/db3-export.js +510 -0
  159. package/dist/src/lib/db3-export.js.map +1 -0
  160. package/dist/src/lib/db3-index-output.d.ts +27 -0
  161. package/dist/src/lib/db3-index-output.js +49 -0
  162. package/dist/src/lib/db3-index-output.js.map +1 -0
  163. package/dist/src/lib/document-export-lookups.d.ts +31 -0
  164. package/dist/src/lib/document-export-lookups.js +53 -0
  165. package/dist/src/lib/document-export-lookups.js.map +1 -0
  166. package/dist/src/lib/document-export-permissions.d.ts +7 -5
  167. package/dist/src/lib/document-export-permissions.js +7 -5
  168. package/dist/src/lib/document-export-permissions.js.map +1 -1
  169. package/dist/src/lib/document-export-record-log.d.ts +57 -0
  170. package/dist/src/lib/document-export-record-log.js +215 -0
  171. package/dist/src/lib/document-export-record-log.js.map +1 -0
  172. package/dist/src/lib/document-ingest-artifact.d.ts +26 -2
  173. package/dist/src/lib/document-ingest-artifact.js +42 -8
  174. package/dist/src/lib/document-ingest-artifact.js.map +1 -1
  175. package/dist/src/lib/document-ingest-format2.d.ts +36 -0
  176. package/dist/src/lib/document-ingest-format2.js +78 -0
  177. package/dist/src/lib/document-ingest-format2.js.map +1 -0
  178. package/dist/src/lib/document-ingest-input.d.ts +9 -0
  179. package/dist/src/lib/document-ingest-input.js +28 -1
  180. package/dist/src/lib/document-ingest-input.js.map +1 -1
  181. package/dist/src/lib/document-ingest-rows.d.ts +16 -0
  182. package/dist/src/lib/document-ingest-rows.js +17 -0
  183. package/dist/src/lib/document-ingest-rows.js.map +1 -1
  184. package/dist/src/lib/document-ingest.d.ts +33 -1
  185. package/dist/src/lib/document-ingest.js +49 -0
  186. package/dist/src/lib/document-ingest.js.map +1 -1
  187. package/dist/src/lib/document-schema-rows.d.ts +42 -0
  188. package/dist/src/lib/document-schema-rows.js +53 -0
  189. package/dist/src/lib/document-schema-rows.js.map +1 -0
  190. package/dist/src/lib/env-resolver-core.d.ts +70 -2
  191. package/dist/src/lib/env-resolver-core.js +137 -20
  192. package/dist/src/lib/env-resolver-core.js.map +1 -1
  193. package/dist/src/lib/env-resolver.d.ts +14 -2
  194. package/dist/src/lib/env-resolver.js +32 -10
  195. package/dist/src/lib/env-resolver.js.map +1 -1
  196. package/dist/src/lib/function-authorize-check.d.ts +142 -0
  197. package/dist/src/lib/function-authorize-check.js +310 -0
  198. package/dist/src/lib/function-authorize-check.js.map +1 -0
  199. package/dist/src/lib/function-authorize-view.d.ts +15 -0
  200. package/dist/src/lib/function-authorize-view.js +50 -0
  201. package/dist/src/lib/function-authorize-view.js.map +1 -0
  202. package/dist/src/lib/function-bundle.d.ts +38 -18
  203. package/dist/src/lib/function-bundle.js +96 -35
  204. package/dist/src/lib/function-bundle.js.map +1 -1
  205. package/dist/src/lib/function-collect.d.ts +75 -12
  206. package/dist/src/lib/function-collect.js +427 -12
  207. package/dist/src/lib/function-collect.js.map +1 -1
  208. package/dist/src/lib/function-db-types.d.ts +29 -0
  209. package/dist/src/lib/function-db-types.js +117 -7
  210. package/dist/src/lib/function-db-types.js.map +1 -1
  211. package/dist/src/lib/function-document-types.d.ts +5 -3
  212. package/dist/src/lib/function-document-types.js +10 -14
  213. package/dist/src/lib/function-document-types.js.map +1 -1
  214. package/dist/src/lib/function-lint.d.ts +34 -0
  215. package/dist/src/lib/function-lint.js +112 -0
  216. package/dist/src/lib/function-lint.js.map +1 -0
  217. package/dist/src/lib/function-log-row.js +21 -2
  218. package/dist/src/lib/function-log-row.js.map +1 -1
  219. package/dist/src/lib/function-run.d.ts +16 -21
  220. package/dist/src/lib/function-run.js +37 -30
  221. package/dist/src/lib/function-run.js.map +1 -1
  222. package/dist/src/lib/function-schema-codegen.d.ts +1 -1
  223. package/dist/src/lib/function-schema-codegen.js +5 -5
  224. package/dist/src/lib/function-schema-codegen.js.map +1 -1
  225. package/dist/src/lib/function-source-roots.d.ts +67 -0
  226. package/dist/src/lib/function-source-roots.js +148 -0
  227. package/dist/src/lib/function-source-roots.js.map +1 -0
  228. package/dist/src/lib/function-sync.d.ts +108 -22
  229. package/dist/src/lib/function-sync.js +127 -39
  230. package/dist/src/lib/function-sync.js.map +1 -1
  231. package/dist/src/lib/function-trigger-listing.d.ts +11 -6
  232. package/dist/src/lib/function-trigger-listing.js +32 -11
  233. package/dist/src/lib/function-trigger-listing.js.map +1 -1
  234. package/dist/src/lib/function-typecheck.d.ts +37 -2
  235. package/dist/src/lib/function-typecheck.js +210 -28
  236. package/dist/src/lib/function-typecheck.js.map +1 -1
  237. package/dist/src/lib/function-versions.d.ts +2 -0
  238. package/dist/src/lib/function-versions.js +1 -0
  239. package/dist/src/lib/function-versions.js.map +1 -1
  240. package/dist/src/lib/generated-allowlist.js +0 -20
  241. package/dist/src/lib/generated-allowlist.js.map +1 -1
  242. package/dist/src/lib/generated-config-surfaces.d.ts +703 -203
  243. package/dist/src/lib/generated-config-surfaces.js +2270 -2014
  244. package/dist/src/lib/generated-config-surfaces.js.map +1 -1
  245. package/dist/src/lib/generated-sdk-types.d.ts +1 -1
  246. package/dist/src/lib/generated-sdk-types.js +1 -1
  247. package/dist/src/lib/generated-sdk-types.js.map +1 -1
  248. package/dist/src/lib/init-adopt.js +12 -3
  249. package/dist/src/lib/init-adopt.js.map +1 -1
  250. package/dist/src/lib/init-login-note.d.ts +13 -0
  251. package/dist/src/lib/init-login-note.js +22 -0
  252. package/dist/src/lib/init-login-note.js.map +1 -0
  253. package/dist/src/lib/json-value.d.ts +6 -0
  254. package/dist/src/lib/json-value.js +13 -0
  255. package/dist/src/lib/json-value.js.map +1 -0
  256. package/dist/src/lib/load-routes.d.ts +33 -0
  257. package/dist/src/lib/load-routes.js +35 -0
  258. package/dist/src/lib/load-routes.js.map +1 -0
  259. package/dist/src/lib/local-state.d.ts +38 -7
  260. package/dist/src/lib/local-state.js +172 -49
  261. package/dist/src/lib/local-state.js.map +1 -1
  262. package/dist/src/lib/local-test-cases.d.ts +5 -2
  263. package/dist/src/lib/local-test-cases.js +7 -4
  264. package/dist/src/lib/local-test-cases.js.map +1 -1
  265. package/dist/src/lib/log-inspection.d.ts +42 -4
  266. package/dist/src/lib/log-inspection.js +37 -5
  267. package/dist/src/lib/log-inspection.js.map +1 -1
  268. package/dist/src/lib/login-exchange-check.d.ts +18 -0
  269. package/dist/src/lib/login-exchange-check.js +27 -0
  270. package/dist/src/lib/login-exchange-check.js.map +1 -0
  271. package/dist/src/lib/login-scope-lines.d.ts +25 -0
  272. package/dist/src/lib/login-scope-lines.js +45 -0
  273. package/dist/src/lib/login-scope-lines.js.map +1 -0
  274. package/dist/src/lib/logout-admin-session.d.ts +2 -1
  275. package/dist/src/lib/logout-admin-session.js +7 -1
  276. package/dist/src/lib/logout-admin-session.js.map +1 -1
  277. package/dist/src/lib/object-status-filter.d.ts +9 -1
  278. package/dist/src/lib/object-status-filter.js +9 -1
  279. package/dist/src/lib/object-status-filter.js.map +1 -1
  280. package/dist/src/lib/output.js +2 -0
  281. package/dist/src/lib/output.js.map +1 -1
  282. package/dist/src/lib/paginate.d.ts +0 -5
  283. package/dist/src/lib/paginate.js +0 -5
  284. package/dist/src/lib/paginate.js.map +1 -1
  285. package/dist/src/lib/pin-refusal-hint.d.ts +12 -0
  286. package/dist/src/lib/pin-refusal-hint.js +35 -0
  287. package/dist/src/lib/pin-refusal-hint.js.map +1 -0
  288. package/dist/src/lib/primitive-env-plugin.d.ts +99 -0
  289. package/dist/src/lib/primitive-env-plugin.js +408 -0
  290. package/dist/src/lib/primitive-env-plugin.js.map +1 -0
  291. package/dist/src/lib/project-config.d.ts +7 -0
  292. package/dist/src/lib/project-config.js +22 -1
  293. package/dist/src/lib/project-config.js.map +1 -1
  294. package/dist/src/lib/project-login-apps.d.ts +8 -0
  295. package/dist/src/lib/project-login-apps.js +27 -0
  296. package/dist/src/lib/project-login-apps.js.map +1 -0
  297. package/dist/src/lib/prompt-schema-codegen.d.ts +10 -3
  298. package/dist/src/lib/prompt-schema-codegen.js +52 -11
  299. package/dist/src/lib/prompt-schema-codegen.js.map +1 -1
  300. package/dist/src/lib/pull-write.d.ts +31 -0
  301. package/dist/src/lib/pull-write.js +49 -0
  302. package/dist/src/lib/pull-write.js.map +1 -0
  303. package/dist/src/lib/push-failure-report.d.ts +45 -0
  304. package/dist/src/lib/push-failure-report.js +57 -0
  305. package/dist/src/lib/push-failure-report.js.map +1 -0
  306. package/dist/src/lib/records-verbs.d.ts +69 -0
  307. package/dist/src/lib/records-verbs.js +40 -0
  308. package/dist/src/lib/records-verbs.js.map +1 -0
  309. package/dist/src/lib/refresh-admin-credentials.d.ts +7 -0
  310. package/dist/src/lib/refresh-admin-credentials.js +16 -4
  311. package/dist/src/lib/refresh-admin-credentials.js.map +1 -1
  312. package/dist/src/lib/root-import-decision.d.ts +65 -0
  313. package/dist/src/lib/root-import-decision.js +109 -0
  314. package/dist/src/lib/root-import-decision.js.map +1 -0
  315. package/dist/src/lib/run-status.d.ts +1 -1
  316. package/dist/src/lib/run-status.generated.d.ts +2 -2
  317. package/dist/src/lib/run-status.generated.js +3 -1
  318. package/dist/src/lib/run-status.generated.js.map +1 -1
  319. package/dist/src/lib/run-status.js +1 -1
  320. package/dist/src/lib/schema-codegen/generated-schema-descriptor.d.ts +129 -0
  321. package/dist/src/lib/schema-codegen/generated-schema-descriptor.js +269 -0
  322. package/dist/src/lib/schema-codegen/generated-schema-descriptor.js.map +1 -0
  323. package/dist/src/lib/schema-codegen/naming.d.ts +35 -0
  324. package/dist/src/lib/schema-codegen/naming.js +83 -0
  325. package/dist/src/lib/schema-codegen/naming.js.map +1 -0
  326. package/dist/src/lib/schema-codegen/schemaToTs.d.ts +82 -0
  327. package/dist/src/lib/schema-codegen/schemaToTs.js +305 -0
  328. package/dist/src/lib/schema-codegen/schemaToTs.js.map +1 -0
  329. package/dist/src/lib/scope-request.d.ts +84 -0
  330. package/dist/src/lib/scope-request.js +235 -0
  331. package/dist/src/lib/scope-request.js.map +1 -0
  332. package/dist/src/lib/session-id.d.ts +9 -0
  333. package/dist/src/lib/session-id.js +28 -0
  334. package/dist/src/lib/session-id.js.map +1 -0
  335. package/dist/src/lib/snapshot-build-rows.d.ts +21 -0
  336. package/dist/src/lib/snapshot-build-rows.js +22 -0
  337. package/dist/src/lib/snapshot-build-rows.js.map +1 -1
  338. package/dist/src/lib/snapshot-build.js +8 -3
  339. package/dist/src/lib/snapshot-build.js.map +1 -1
  340. package/dist/src/lib/snapshots.d.ts +17 -1
  341. package/dist/src/lib/snapshots.js +50 -2
  342. package/dist/src/lib/snapshots.js.map +1 -1
  343. package/dist/src/lib/swift-codegen/agentGenerator.d.ts +6 -2
  344. package/dist/src/lib/swift-codegen/agentGenerator.js +57 -5
  345. package/dist/src/lib/swift-codegen/agentGenerator.js.map +1 -1
  346. package/dist/src/lib/swift-codegen/banners.d.ts +34 -7
  347. package/dist/src/lib/swift-codegen/banners.js +37 -7
  348. package/dist/src/lib/swift-codegen/banners.js.map +1 -1
  349. package/dist/src/lib/swift-codegen/dbGenerator.d.ts +4 -3
  350. package/dist/src/lib/swift-codegen/dbGenerator.js +14 -117
  351. package/dist/src/lib/swift-codegen/dbGenerator.js.map +1 -1
  352. package/dist/src/lib/swift-codegen/functionGenerator.d.ts +3 -3
  353. package/dist/src/lib/swift-codegen/functionGenerator.js +23 -18
  354. package/dist/src/lib/swift-codegen/functionGenerator.js.map +1 -1
  355. package/dist/src/lib/swift-codegen/generator.d.ts +5 -5
  356. package/dist/src/lib/swift-codegen/generator.js +35 -40
  357. package/dist/src/lib/swift-codegen/generator.js.map +1 -1
  358. package/dist/src/lib/swift-codegen/schemaToSwift.d.ts +3 -3
  359. package/dist/src/lib/swift-codegen/schemaToSwift.js +4 -4
  360. package/dist/src/lib/swift-codegen/schemaToSwift.js.map +1 -1
  361. package/dist/src/lib/swift-codegen/swiftKeys.d.ts +19 -0
  362. package/dist/src/lib/swift-codegen/swiftKeys.js +31 -0
  363. package/dist/src/lib/swift-codegen/swiftKeys.js.map +1 -0
  364. package/dist/src/lib/sync-paths.d.ts +35 -0
  365. package/dist/src/lib/sync-paths.js +57 -5
  366. package/dist/src/lib/sync-paths.js.map +1 -1
  367. package/dist/src/lib/sync-resource-types.d.ts +26 -26
  368. package/dist/src/lib/sync-resource-types.js +61 -189
  369. package/dist/src/lib/sync-resource-types.js.map +1 -1
  370. package/dist/src/lib/sync-selectors.d.ts +5 -1
  371. package/dist/src/lib/sync-selectors.js +23 -13
  372. package/dist/src/lib/sync-selectors.js.map +1 -1
  373. package/dist/src/lib/test-case-file-names.d.ts +3 -5
  374. package/dist/src/lib/test-case-file-names.js +3 -5
  375. package/dist/src/lib/test-case-file-names.js.map +1 -1
  376. package/dist/src/lib/toml-database-config.d.ts +15 -75
  377. package/dist/src/lib/toml-database-config.js +17 -306
  378. package/dist/src/lib/toml-database-config.js.map +1 -1
  379. package/dist/src/lib/transient-retry.d.ts +43 -0
  380. package/dist/src/lib/transient-retry.js +94 -0
  381. package/dist/src/lib/transient-retry.js.map +1 -0
  382. package/dist/src/lib/vars-override.d.ts +105 -0
  383. package/dist/src/lib/vars-override.js +143 -0
  384. package/dist/src/lib/vars-override.js.map +1 -0
  385. package/dist/src/lib/webhook-capture.d.ts +43 -0
  386. package/dist/src/lib/webhook-capture.js +91 -0
  387. package/dist/src/lib/webhook-capture.js.map +1 -0
  388. package/dist/src/lib/webhook-deliver.d.ts +18 -20
  389. package/dist/src/lib/webhook-deliver.js +34 -89
  390. package/dist/src/lib/webhook-deliver.js.map +1 -1
  391. package/dist/src/lib/webhook-test-run.d.ts +32 -0
  392. package/dist/src/lib/webhook-test-run.js +108 -0
  393. package/dist/src/lib/webhook-test-run.js.map +1 -0
  394. package/dist/src/lib/workflow-codegen/generator.d.ts +7 -7
  395. package/dist/src/lib/workflow-codegen/generator.js +16 -23
  396. package/dist/src/lib/workflow-codegen/generator.js.map +1 -1
  397. package/dist/src/lib/workflow-codegen/invokerIR.d.ts +6 -12
  398. package/dist/src/lib/workflow-codegen/invokerIR.js +4 -5
  399. package/dist/src/lib/workflow-codegen/invokerIR.js.map +1 -1
  400. package/dist/src/lib/workflow-toml-validator.d.ts +2 -0
  401. package/dist/src/lib/workflow-toml-validator.js +28 -1
  402. package/dist/src/lib/workflow-toml-validator.js.map +1 -1
  403. package/dist/src/types/index.d.ts +30 -37
  404. package/dist/src/validators.d.ts +7 -55
  405. package/dist/src/validators.js +7 -53
  406. package/dist/src/validators.js.map +1 -1
  407. package/dist/src/vite.d.ts +17 -0
  408. package/dist/src/vite.js +18 -0
  409. package/dist/src/vite.js.map +1 -0
  410. package/package.json +20 -12
@@ -2,13 +2,11 @@ import { readFileSync, writeFileSync, appendFileSync, mkdirSync, existsSync, rea
2
2
  import * as path from "path";
3
3
  import { ApiClient } from "../lib/api-client.js";
4
4
  import { getCurrentAppId, resolveAppId } from "../lib/config.js";
5
- import { resolveCodegenSourceDir } from "../lib/codegen-shared/resolveCodegenSourceDir.js";
6
5
  import { resolveSyncDir } from "../lib/sync-paths.js";
7
6
  import { parseCsv, applyColumnMap, buildRows } from "../lib/csv.js";
8
7
  import { chunk, parseBatchSize } from "../lib/batch.js";
9
- import { generateDbTypes, } from "../lib/db-codegen/dbGenerator.js";
10
- import { generateDbSwiftTypes } from "../lib/swift-codegen/dbGenerator.js";
11
8
  import { success, error, info, warn, keyValue, result as printResult, formatTable, formatId, formatDate, json, } from "../lib/output.js";
9
+ import { renderAggregateResult } from "../lib/aggregate-output.js";
12
10
  import { confirmPrompt } from "../lib/confirm-prompt.js";
13
11
  import { parseFilterOptions } from "../lib/record-filter.js";
14
12
  import { parseDataOption } from "../lib/data-input.js";
@@ -52,49 +50,6 @@ function assertDataIdMatches(data, recordId, writtenId, commandPath) {
52
50
  : `Pass the record id as the argument, not inside --data: ${commandPath} ${dataId} --data ...`);
53
51
  process.exit(1);
54
52
  }
55
- /**
56
- * Validate that the named operation is an import-compatible, save-like
57
- * mutation before importing (issue #145, Codex finding (a)).
58
- *
59
- * The importer always builds `params: { modelName, id, data }`, and the batch
60
- * endpoint rejects undeclared params per item. So we require the op to be a
61
- * `mutation` whose declared `params` cover `modelName`, `id`, and `data`. This
62
- * surfaces a clear up-front error instead of letting every row fail
63
- * server-side. Exits non-zero on any mismatch.
64
- */
65
- async function validateImportOperation(client, appId, databaseId, operationName) {
66
- let ops;
67
- try {
68
- ops = await client.listDatabaseOperations(appId, databaseId);
69
- }
70
- catch (err) {
71
- error(`Could not list operations for this database: ${err?.message || err}`);
72
- process.exit(1);
73
- return;
74
- }
75
- const op = (ops || []).find((o) => o?.name === operationName);
76
- if (!op) {
77
- error(`Operation "${operationName}" not found — create a mutation op (e.g. ` +
78
- `\`seed_save\`) on this database type first.`);
79
- process.exit(1);
80
- return;
81
- }
82
- if (op.type !== "mutation") {
83
- error(`Operation "${operationName}" is a "${op.type}" op, not an import-compatible ` +
84
- `mutation. CSV import needs a save-like mutation taking {modelName, id, data}.`);
85
- process.exit(1);
86
- return;
87
- }
88
- const params = op.params || {};
89
- const missing = ["modelName", "id", "data"].filter((p) => !(p in params));
90
- if (missing.length > 0) {
91
- error(`Operation "${operationName}" is not import-compatible: its params are missing ` +
92
- `${missing.join(", ")}. CSV import builds {modelName, id, data} per item, so the ` +
93
- `op must declare those params (like \`seed_save\`).`);
94
- process.exit(1);
95
- return;
96
- }
97
- }
98
53
  /**
99
54
  * The full `databases records bulk` precondition value space, audited in one
100
55
  * pass (issue #2437, Codex cycle 3). A precondition is field-equality only, so
@@ -760,43 +715,18 @@ database-type-config' and the 'database-type-configs' group for inspection:
760
715
  json(result);
761
716
  return;
762
717
  }
763
- const aggregated = result?.result;
764
- // Label the value column after the operation, including the field it
765
- // ran over: `SUM` alone does not say what was summed. The field name is
766
- // reproduced verbatim in both labels — it is a user-supplied
767
- // identifier, and case-folding it produced `avg(lastvalue)` for
768
- // `--field lastValue` (issue #2357).
769
- const valueLabel = options.op === "count"
770
- ? "COUNT"
771
- : `${options.op.toUpperCase()}(${options.field})`;
772
- const scalarLabel = options.op === "count"
773
- ? "count"
774
- : `${options.op.toLowerCase()}(${options.field})`;
775
- if (groupBy.length === 0) {
776
- // Ungrouped: one scalar per operation, keyed by the endpoint's
777
- // operation name (`count`, `sum_<field>`, …). Render it as a
778
- // key/value line — there is no group column to table.
779
- const value = (aggregated ?? {})[options.op === "count" ? "count" : `${options.op}_${options.field}`];
780
- keyValue(scalarLabel, value === null || value === undefined ? "—" : String(value));
781
- return;
782
- }
783
- if (aggregated &&
784
- typeof aggregated === "object" &&
785
- !Array.isArray(aggregated) &&
786
- Object.values(aggregated).every((v) => typeof v !== "object" || v === null)) {
787
- // Flat { group -> value } shape (single operation, single group-by): render a table.
788
- const rows = Object.entries(aggregated).map(([group, value]) => ({
789
- group,
790
- value: value === null || value === undefined ? "—" : String(value),
791
- }));
792
- console.log(formatTable(rows, [
793
- { header: "GROUP", key: "group" },
794
- { header: valueLabel, key: "value" },
795
- ]));
718
+ // The route answers rows (#4265): one key/value line when
719
+ // ungrouped, a table with one column per group key when grouped.
720
+ const rendered = renderAggregateResult(result?.result, {
721
+ groupBy,
722
+ op: options.op,
723
+ field: options.field,
724
+ });
725
+ if (rendered.kind === "scalar") {
726
+ keyValue(rendered.label, rendered.value);
796
727
  }
797
728
  else {
798
- // Grouped/nested or multi-operation shape: print the structured result.
799
- console.log(JSON.stringify(aggregated ?? {}, null, 2));
729
+ console.log(rendered.text);
800
730
  }
801
731
  }
802
732
  catch (err) {
@@ -1182,145 +1112,6 @@ database-type-config' and the 'database-type-configs' group for inspection:
1182
1112
  process.exit(1);
1183
1113
  }
1184
1114
  });
1185
- // ---- Operations subcommand group ----
1186
- const operations = databases
1187
- .command("operations")
1188
- .description("List and execute registered operations on a database");
1189
- // List operations
1190
- operations
1191
- .command("list")
1192
- .description("List registered operations available on a database")
1193
- .argument("<database-id>", "Database ID")
1194
- .option("--app <app-id>", "App ID")
1195
- .option("--json", "Output as JSON")
1196
- .action(async (databaseId, options) => {
1197
- const resolvedAppId = resolveAppId(undefined, options);
1198
- const client = new ApiClient();
1199
- try {
1200
- const result = await client.listDatabaseOperations(resolvedAppId, databaseId);
1201
- const list = Array.isArray(result) ? result : [];
1202
- if (options.json) {
1203
- json(wholeListEnvelope(list));
1204
- return;
1205
- }
1206
- if (list.length === 0) {
1207
- info("No operations found.");
1208
- return;
1209
- }
1210
- console.log(formatTable(list, [
1211
- { header: "NAME", key: "name" },
1212
- { header: "TYPE", key: "type" },
1213
- { header: "MODEL", key: "modelName" },
1214
- { header: "ACCESS", key: "access" },
1215
- ]));
1216
- }
1217
- catch (err) {
1218
- error(err.message);
1219
- process.exit(1);
1220
- }
1221
- });
1222
- // Execute operation
1223
- operations
1224
- .command("execute")
1225
- .description("Execute a registered operation on a database")
1226
- .argument("<database-id>", "Database ID")
1227
- .argument("<operation-name>", "Operation name")
1228
- .option("--params <json>", "Operation parameters as JSON")
1229
- .option("--limit <n>", "Max records to return (for queries)")
1230
- .option("--cursor <cursor>", "Pagination cursor")
1231
- .option("--token <jwt>", "Execute as a specific user (dev/test — JWT visible in process args)")
1232
- .option("--app <app-id>", "App ID")
1233
- .option("--json", "Output as JSON")
1234
- .option("--timing", "Show server-side timing breakdown")
1235
- .action(async (databaseId, operationName, options) => {
1236
- const resolvedAppId = resolveAppId(undefined, options);
1237
- const client = new ApiClient();
1238
- let params;
1239
- if (options.params) {
1240
- try {
1241
- params = JSON.parse(options.params);
1242
- }
1243
- catch {
1244
- error("Invalid --params JSON.");
1245
- process.exit(1);
1246
- return;
1247
- }
1248
- }
1249
- const body = {};
1250
- if (params)
1251
- body.params = params;
1252
- if (options.limit)
1253
- body.limit = parseInt(options.limit, 10);
1254
- if (options.cursor)
1255
- body.cursor = options.cursor;
1256
- try {
1257
- const result = await client.executeDatabaseOperation(resolvedAppId, databaseId, operationName, body, options.token, { timing: !!options.timing });
1258
- if (options.json) {
1259
- json(result);
1260
- return;
1261
- }
1262
- // Smart display based on result shape. `executeDatabaseOperation()`
1263
- // has already normalized a query page to `{ items, hasMore,
1264
- // nextCursor? }` (#2440), so `items` is exactly "this result was a
1265
- // list" — the two branches cannot disagree about it.
1266
- if (Array.isArray(result.items)) {
1267
- if (result.items.length === 0) {
1268
- info("No records found.");
1269
- }
1270
- else {
1271
- const cols = Object.keys(result.items[0]).filter((k) => k !== "type");
1272
- console.log(formatTable(result.items, cols.map((c) => ({
1273
- header: c.toUpperCase(),
1274
- key: c,
1275
- format: (v) => {
1276
- if (v === null || v === undefined)
1277
- return "—";
1278
- if (typeof v === "object") {
1279
- const s = JSON.stringify(v);
1280
- return s.length > 50 ? s.slice(0, 47) + "..." : s;
1281
- }
1282
- const s = String(v);
1283
- return s.length > 50 ? s.slice(0, 47) + "..." : s;
1284
- },
1285
- }))));
1286
- }
1287
- // Gate on the cursor itself, the way `records query` does: `hasMore`
1288
- // without a cursor used to print the literal `undefined` (#2440).
1289
- if (result.nextCursor) {
1290
- info(`More records available. Use --cursor ${result.nextCursor} to continue.`);
1291
- }
1292
- }
1293
- else if (result.count !== undefined) {
1294
- console.log(`Count: ${result.count}`);
1295
- }
1296
- else if (result.result !== undefined) {
1297
- // Aggregate result
1298
- json(result);
1299
- }
1300
- else if (result.results && Array.isArray(result.results)) {
1301
- // Batch/mutation results
1302
- success(`Operation executed (${result.results.length} result${result.results.length === 1 ? "" : "s"}).`);
1303
- }
1304
- else if (result.success !== undefined) {
1305
- success("Operation executed.");
1306
- }
1307
- else {
1308
- json(result);
1309
- }
1310
- // Display timing if present
1311
- if (result._timing) {
1312
- console.log("");
1313
- console.log("Timing:");
1314
- for (const [key, value] of Object.entries(result._timing)) {
1315
- console.log(` ${key}: ${value}ms`);
1316
- }
1317
- }
1318
- }
1319
- catch (err) {
1320
- error(err.message);
1321
- process.exit(1);
1322
- }
1323
- });
1324
1115
  // ---- Indexes subcommand group ----
1325
1116
  const indexes = databases
1326
1117
  .command("indexes")
@@ -1576,6 +1367,11 @@ database-type-config' and the 'database-type-configs' group for inspection:
1576
1367
  info("No databases to import.");
1577
1368
  return;
1578
1369
  }
1370
+ // Check every database's files before writing anything, so a malformed
1371
+ // export fails without leaving a database behind. Each one is read
1372
+ // again as it is imported rather than holding every export's records.
1373
+ for (const dbDir of dbDirs)
1374
+ readDatabaseExport(dbDir);
1579
1375
  const summary = {
1580
1376
  created: 0,
1581
1377
  updated: 0,
@@ -1586,6 +1382,7 @@ database-type-config' and the 'database-type-configs' group for inspection:
1586
1382
  aborted: false,
1587
1383
  indexesRegistered: 0,
1588
1384
  batchErrors: [],
1385
+ databases: [],
1589
1386
  };
1590
1387
  for (const dbDir of dbDirs) {
1591
1388
  await importSingleDatabase(client, resolvedAppId, dbDir, {
@@ -1641,11 +1438,10 @@ database-type-config' and the 'database-type-configs' group for inspection:
1641
1438
  // ============================================
1642
1439
  databases
1643
1440
  .command("import-csv")
1644
- .description("Import rows from a CSV file into a database via a registered batch (bulk) save operation")
1441
+ .description("Import rows from a CSV file into a database: one save per row through records/batch, best-effort (a row the database refuses is counted as failed and the rest are written)")
1645
1442
  .argument("<database-id>", "Database ID")
1646
1443
  .argument("<file>", "Path to the CSV file")
1647
- .requiredOption("--model <name>", "Model name passed in each item's params")
1648
- .option("--operation <op>", "Registered mutation operation to use (must be a {modelName,id,data} save-like op)", "seed_save")
1444
+ .requiredOption("--model <name>", "Model every row is saved into")
1649
1445
  .option("--column-map <json>", 'Map CSV headers to field names, e.g. \'{"CSV Header":"fieldName"}\'')
1650
1446
  .option("--types <json>", 'Coerce fields by type, e.g. \'{"price":"number","active":"boolean"}\'')
1651
1447
  .option("--id-column <col>", "Use this CSV column for record ids (else a ULID is generated)")
@@ -1681,11 +1477,11 @@ database-type-config' and the 'database-type-configs' group for inspection:
1681
1477
  return;
1682
1478
  }
1683
1479
  }
1684
- // The registered-batch (`executeBatch`) path rejects requests over
1685
- // 100000 items server-side; keep chunks under it.
1480
+ // `records/batch` has no fixed server item cap — bound it with the same
1481
+ // conservative client-side ceiling `databases import` uses.
1686
1482
  const parsedBatchSize = parseBatchSize(options.batchSize, {
1687
- max: 100000,
1688
- overMaxMessage: "--batch-size cannot exceed 100000 (the server's per-request cap).",
1483
+ max: IMPORT_BATCH_SIZE_CEILING,
1484
+ overMaxMessage: `--batch-size cannot exceed ${IMPORT_BATCH_SIZE_CEILING} (a conservative client-side limit for batch write requests).`,
1689
1485
  });
1690
1486
  if ("error" in parsedBatchSize) {
1691
1487
  error(parsedBatchSize.error);
@@ -1704,21 +1500,14 @@ database-type-config' and the 'database-type-configs' group for inspection:
1704
1500
  let rows = parseCsv(raw, options.delimiter);
1705
1501
  // 2. Apply column map.
1706
1502
  rows = applyColumnMap(rows, columnMap);
1707
- // 3. Coerce types, assign ids, shape into batch items.
1503
+ // 3. Coerce types, assign ids, shape into records/batch saves.
1708
1504
  const { batch, rowCount } = buildRows(rows, {
1709
1505
  modelName: options.model,
1710
1506
  types,
1711
1507
  idColumn: options.idColumn,
1712
1508
  });
1713
1509
  const chunks = chunk(batch, batchSize);
1714
- // 4. Validate the chosen op is an import-compatible save-like mutation
1715
- // BEFORE writing (op-not-found / incompatible → clear up-front error
1716
- // rather than per-row server-side failure). Skip the round-trip only
1717
- // when there is genuinely nothing to import in a dry run.
1718
- if (!options.dryRun || rowCount > 0) {
1719
- await validateImportOperation(client, resolvedAppId, databaseId, options.operation);
1720
- }
1721
- // 5. Empty / headers-only CSV: no request, report 0/0.
1510
+ // 4. Empty / headers-only CSV: no request, report 0/0.
1722
1511
  if (rowCount === 0) {
1723
1512
  if (options.json) {
1724
1513
  json({ imported: 0, failed: 0, rows: 0, batches: 0, errors: [], dryRun: !!options.dryRun });
@@ -1729,7 +1518,7 @@ database-type-config' and the 'database-type-configs' group for inspection:
1729
1518
  }
1730
1519
  return;
1731
1520
  }
1732
- // 6. Dry run: report counts, no writes.
1521
+ // 5. Dry run: report counts, no writes.
1733
1522
  if (options.dryRun) {
1734
1523
  if (options.json) {
1735
1524
  json({ dryRun: true, rows: rowCount, batches: chunks.length, batchSize });
@@ -1742,32 +1531,60 @@ database-type-config' and the 'database-type-configs' group for inspection:
1742
1531
  }
1743
1532
  return;
1744
1533
  }
1745
- // 7. Import chunk by chunk; accumulate imported/failed + per-chunk errors.
1534
+ // 6. Import chunk by chunk through records/batch, non-atomic (the
1535
+ // route's default): each row's outcome is its own, so a refused row
1536
+ // is counted failed and its siblings commit.
1746
1537
  let imported = 0;
1747
1538
  let failed = 0;
1748
1539
  const errors = [];
1749
1540
  let aborted = false;
1750
1541
  for (let i = 0; i < chunks.length; i++) {
1751
1542
  const piece = chunks[i];
1543
+ let chunkFailed = false;
1752
1544
  try {
1753
- const res = await client.executeBatch(resolvedAppId, databaseId, options.operation, piece);
1754
- imported += res.imported ?? 0;
1755
- failed += res.failed ?? 0;
1545
+ const res = await client.batchDatabaseRecords(resolvedAppId, databaseId, piece);
1546
+ const results = res?.results ?? [];
1547
+ let chunkImported = 0;
1548
+ let chunkRefused = 0;
1549
+ const firstErrors = [];
1550
+ for (let j = 0; j < piece.length; j++) {
1551
+ const r = results[j];
1552
+ if (r && r.success) {
1553
+ chunkImported++;
1554
+ }
1555
+ else {
1556
+ chunkRefused++;
1557
+ if (r?.error && firstErrors.length < 3)
1558
+ firstErrors.push(r.error);
1559
+ }
1560
+ }
1561
+ imported += chunkImported;
1562
+ failed += chunkRefused;
1563
+ if (chunkRefused > 0) {
1564
+ chunkFailed = true;
1565
+ errors.push({
1566
+ batch: i,
1567
+ error: `${chunkRefused} row(s) failed${firstErrors.length ? `: ${firstErrors.join("; ")}` : ""}`,
1568
+ });
1569
+ }
1756
1570
  if (!options.json) {
1757
- info(`Batch ${i + 1}/${chunks.length}: imported ${res.imported ?? 0}, failed ${res.failed ?? 0}`);
1571
+ info(`Batch ${i + 1}/${chunks.length}: imported ${chunkImported}, failed ${chunkRefused}`);
1758
1572
  }
1759
1573
  }
1760
1574
  catch (err) {
1575
+ // A chunk-level failure (a 400 for a malformed op): the whole
1576
+ // chunk was refused, so every row in it counts as failed.
1761
1577
  const msg = err?.message || String(err);
1578
+ chunkFailed = true;
1762
1579
  errors.push({ batch: i, error: msg });
1763
1580
  failed += piece.length;
1764
1581
  if (!options.json) {
1765
1582
  warn(`Batch ${i + 1}/${chunks.length} failed: ${msg}`);
1766
1583
  }
1767
- if (options.stopOnError) {
1768
- aborted = true;
1769
- break;
1770
- }
1584
+ }
1585
+ if (chunkFailed && options.stopOnError) {
1586
+ aborted = true;
1587
+ break;
1771
1588
  }
1772
1589
  }
1773
1590
  if (options.json) {
@@ -1785,7 +1602,7 @@ database-type-config' and the 'database-type-configs' group for inspection:
1785
1602
  }
1786
1603
  }
1787
1604
  }
1788
- // Non-zero exit if any chunk errored.
1605
+ // Non-zero exit if any row or chunk failed.
1789
1606
  if (errors.length > 0) {
1790
1607
  process.exit(1);
1791
1608
  }
@@ -1803,7 +1620,7 @@ database-type-config' and the 'database-type-configs' group for inspection:
1803
1620
  .description("Manage the TOML schema attached to a database type");
1804
1621
  schema
1805
1622
  .command("generate")
1806
- .description("Scaffold a starting TOML schema for <database-type> from existing operations + DO introspection, and insert it into the local database-type-configs/<type>.toml file.")
1623
+ .description("Scaffold a starting TOML schema for <database-type> from the models and fields its databases hold, and append it to the local database-type-configs/<type>.toml file.")
1807
1624
  .argument("<database-type>", "Database type name")
1808
1625
  .option("-f, --force", "Overwrite an existing [models.*] block in the local file")
1809
1626
  .option("--json", "Output the generated TOML as JSON")
@@ -1842,10 +1659,10 @@ database-type-config' and the 'database-type-configs' group for inspection:
1842
1659
  console.log(scaffoldedToml);
1843
1660
  return;
1844
1661
  }
1845
- // 3. For each candidate, splice the scaffolded TOML at a stable
1846
- // anchor (before the first `[[operations]]` block, or at EOF). Per
1847
- // the plan-of-record, textual insertion is deliberate — smol-toml
1848
- // parse/stringify drops comments, so we splice as a raw string.
1662
+ // 3. For each candidate, append the scaffolded TOML at the end of the
1663
+ // file. Per the plan-of-record, textual insertion is deliberate —
1664
+ // smol-toml parse/stringify drops comments, so we splice as a raw
1665
+ // string.
1849
1666
  for (const targetPath of candidateFiles) {
1850
1667
  const original = readFileSync(targetPath, "utf-8");
1851
1668
  // Detect existing [models.*] block. If present, refuse unless --force.
@@ -1854,26 +1671,9 @@ database-type-config' and the 'database-type-configs' group for inspection:
1854
1671
  error(`${targetPath} already has [models.*] blocks. Re-run with --force to overwrite.`);
1855
1672
  process.exit(1);
1856
1673
  }
1857
- // Strip existing [models.*] blocks if --force.
1858
- let cleaned = original;
1859
- if (hasModelsBlock && options.force) {
1860
- cleaned = stripModelsBlocks(original);
1861
- }
1862
- // Splice: insert before the first [[operations]] block, otherwise
1863
- // at the end of file.
1864
- let merged;
1865
- const opsAnchor = cleaned.indexOf("\n[[operations]]");
1866
- if (opsAnchor >= 0) {
1867
- merged =
1868
- cleaned.slice(0, opsAnchor + 1) +
1869
- scaffoldedToml +
1870
- "\n" +
1871
- cleaned.slice(opsAnchor + 1);
1872
- }
1873
- else {
1874
- const sep = cleaned.endsWith("\n") ? "" : "\n";
1875
- merged = cleaned + sep + scaffoldedToml + "\n";
1876
- }
1674
+ const merged = spliceScaffoldedSchema(original, scaffoldedToml, {
1675
+ force: !!options.force,
1676
+ });
1877
1677
  writeFileSync(targetPath, merged);
1878
1678
  success(`Inserted schema into ${targetPath}`);
1879
1679
  }
@@ -1884,137 +1684,18 @@ database-type-config' and the 'database-type-configs' group for inspection:
1884
1684
  process.exit(1);
1885
1685
  }
1886
1686
  });
1887
- // ============================================
1888
- // Codegen command (issue #814)
1889
- // ============================================
1890
- databases
1891
- .command("codegen")
1892
- .description("Generate record + operation types from the local database-type-configs/*.toml schema. TypeScript (default): a <type>.generated.ts per database type (record interfaces, per-op input-params interfaces, per-op result aliases, and a typed <type>Ops factory). Swift (--lang swift): a <type>.generated.swift per database type (record structs, per-op params structs, per-op result typealiases, and a typed <Type>Ops factory).\n\nFormatting: the emitted TypeScript is already formatted the way Prettier's DEFAULT config formats it, so a `codegen` -> `prettier --write` -> `codegen --check` pipeline stays green. If your project uses a NON-default Prettier config (a different printWidth, trailingComma, or quote style), Prettier will reformat the generated files and `--check` will then fail: add the generated directory to `.prettierignore` and commit the raw emission instead.")
1893
- .argument("[database-type]", "Generate for a single database type (defaults to every database-type-configs/*.toml found)")
1894
- .option("-o, --output <dir>", "Output directory for the generated files (defaults to <config-dir>/database-type-configs/generated/)")
1895
- .option("--lang <lang>", "Target language for the generated types: 'ts' (default) or 'swift'.", "ts")
1896
- .option("--check", "Exit non-zero if generated output is out of date (CI guard); does not write. Compares byte-for-byte, so the file on disk must match the emission exactly.")
1897
- .option("--json", "Output the result summary as JSON")
1898
- .action(async (databaseType, options) => {
1899
- try {
1900
- // 0. Validate --lang up front so an unknown value fails clearly rather
1901
- // than silently defaulting to the TS emitter.
1902
- const lang = String(options.lang ?? "ts").toLowerCase();
1903
- if (lang !== "ts" && lang !== "swift") {
1904
- error(`Unknown --lang "${options.lang}". Use "ts" or "swift".`);
1905
- process.exit(1);
1906
- }
1907
- // 1. The single source database-type-configs/ directory: the
1908
- // environment's, and only ever the environment's (#1510, #3154).
1909
- const dbTypesSourceDir = resolveCodegenSourceDir({
1910
- subdir: "database-type-configs",
1911
- });
1912
- // 2. Collect the source .toml files (one per database type), filtered
1913
- // to a single type when an argument is given.
1914
- const inputs = [];
1915
- for (const fileName of readdirSync(dbTypesSourceDir)) {
1916
- if (!fileName.endsWith(".toml"))
1917
- continue;
1918
- const typeName = fileName.slice(0, -".toml".length);
1919
- if (databaseType && typeName !== databaseType)
1920
- continue;
1921
- const tomlPath = path.join(dbTypesSourceDir, fileName);
1922
- inputs.push({
1923
- databaseType: typeName,
1924
- tomlPath,
1925
- tomlContent: readFileSync(tomlPath, "utf-8"),
1926
- });
1927
- }
1928
- if (inputs.length === 0) {
1929
- error(databaseType
1930
- ? `No database-type-configs/${databaseType}.toml found under primitive/<env>/.`
1931
- : "No database-type-configs/*.toml files found to generate from.");
1932
- process.exit(1);
1933
- }
1934
- // 3. Resolve the output directory. Default: a `generated/` subdir of
1935
- // the first source dir (keeps generated output beside the schema).
1936
- const outputDir = options.output
1937
- ? path.resolve(options.output)
1938
- : path.join(path.dirname(inputs[0].tomlPath), "generated");
1939
- // 4. Run codegen (or --check) with the selected emitter. Both the TS
1940
- // and Swift generators return the same WriteOrCheckResult shape, so
1941
- // the reporting below is emitter-agnostic; only the emitter (and the
1942
- // regenerate hint) differs. When a single database-type filter
1943
- // argument is given, the input set is partial — flag it so stale
1944
- // cleanup is scoped to that type and sibling types' generated files
1945
- // are left intact.
1946
- const codegenResult = lang === "swift"
1947
- ? await generateDbSwiftTypes({
1948
- inputs,
1949
- outputDir,
1950
- check: !!options.check,
1951
- singleType: !!databaseType,
1952
- })
1953
- : await generateDbTypes({
1954
- inputs,
1955
- outputDir,
1956
- check: !!options.check,
1957
- singleType: !!databaseType,
1958
- });
1959
- if (options.check) {
1960
- if (codegenResult.mismatches.length > 0) {
1961
- if (options.json) {
1962
- json({ ok: false, mismatches: codegenResult.mismatches });
1963
- }
1964
- else {
1965
- error(`Check failed: ${codegenResult.mismatches.length} file(s) out of date.`);
1966
- for (const m of codegenResult.mismatches) {
1967
- error(` ${m.reason}: ${path.relative(process.cwd(), m.filePath)}`);
1968
- }
1969
- // Echo back the options that decide WHERE and WHAT was
1970
- // checked, the way `workflows codegen` does (#2895). Suggesting
1971
- // a bare `databases codegen` after a `--check -o <dir>` sent
1972
- // people to regenerate into the default
1973
- // <config-dir>/database-type-configs/generated/ instead of the
1974
- // directory that is actually out of date, so the files stayed
1975
- // stale and the next check failed the same way (#2911).
1976
- const regenerate = ["primitive databases codegen"];
1977
- if (databaseType)
1978
- regenerate.push(databaseType);
1979
- if (lang === "swift")
1980
- regenerate.push("--lang swift");
1981
- if (options.output)
1982
- regenerate.push(`-o ${options.output}`);
1983
- info(`Run \`${regenerate.join(" ")}\` to regenerate.`);
1984
- }
1985
- process.exit(1);
1986
- }
1987
- if (options.json) {
1988
- json({ ok: true, checked: codegenResult.writtenFiles.length });
1989
- }
1990
- else {
1991
- success(`Check passed: ${codegenResult.writtenFiles.length} file(s) up to date.`);
1992
- }
1993
- return;
1994
- }
1995
- if (options.json) {
1996
- json({
1997
- written: codegenResult.writtenFiles,
1998
- deleted: codegenResult.deletedFiles,
1999
- });
2000
- return;
2001
- }
2002
- success(`Generated ${codegenResult.writtenFiles.length} file(s)` +
2003
- (codegenResult.deletedFiles.length > 0
2004
- ? `, deleted ${codegenResult.deletedFiles.length} stale file(s).`
2005
- : "."));
2006
- for (const f of codegenResult.writtenFiles) {
2007
- keyValue(" wrote", path.relative(process.cwd(), f));
2008
- }
2009
- for (const f of codegenResult.deletedFiles) {
2010
- keyValue(" deleted", path.relative(process.cwd(), f));
2011
- }
2012
- }
2013
- catch (err) {
2014
- error(err.message);
2015
- process.exit(1);
2016
- }
2017
- });
1687
+ }
1688
+ /**
1689
+ * Append a scaffolded `[models.*]` schema to a database type file's text,
1690
+ * first stripping the file's existing `[models.*]` blocks when `force` is set.
1691
+ * Appended at the end of the file: #3189 retired the `[[operations]]` blocks
1692
+ * the scaffold used to be inserted ahead of.
1693
+ */
1694
+ export function spliceScaffoldedSchema(original, scaffoldedToml, options = {}) {
1695
+ const hasModelsBlock = /\n\[models\./.test("\n" + original);
1696
+ const cleaned = hasModelsBlock && options.force ? stripModelsBlocks(original) : original;
1697
+ const sep = cleaned.endsWith("\n") ? "" : "\n";
1698
+ return cleaned + sep + scaffoldedToml + "\n";
2018
1699
  }
2019
1700
  /** Remove every existing `[models.*]` block from a TOML file body. */
2020
1701
  function stripModelsBlocks(text) {
@@ -2083,8 +1764,9 @@ async function exportSingleDatabase(client, appId, databaseId, outputDir, jsonOu
2083
1764
  hasMore = !!cursor && records.length > 0;
2084
1765
  }
2085
1766
  }
2086
- // 4. Export indexes
2087
- const indexes = await client.listDatabaseIndexes(appId, databaseId);
1767
+ // 4. Export indexes. The route answers `{ indexes: [...] }`; the file holds
1768
+ // the bare list, which every version of `databases import` reads.
1769
+ const indexes = indexList(await client.listDatabaseIndexes(appId, databaseId), "the index listing");
2088
1770
  writeFileSync(path.join(dbDir, "indexes.json"), JSON.stringify(indexes, null, 2));
2089
1771
  // 5. Export unique constraints
2090
1772
  const constraints = await client.listDatabaseUniqueConstraints(appId, databaseId);
@@ -2117,20 +1799,27 @@ async function exportSingleDatabase(client, appId, databaseId, outputDir, jsonOu
2117
1799
  const IMPORT_BATCH_SIZE_CEILING = 25000;
2118
1800
  async function importSingleDatabase(client, appId, dbDir, options) {
2119
1801
  const { overwrite, dryRun, batchSize, stopOnError, json: jsonOutput, summary } = options;
2120
- const metadataPath = path.join(dbDir, "metadata.json");
2121
- if (!existsSync(metadataPath)) {
1802
+ const exported = readDatabaseExport(dbDir);
1803
+ if (!exported) {
2122
1804
  warn(`Skipping ${dbDir}: no metadata.json found`);
2123
1805
  summary.skipped++;
1806
+ summary.databases.push({ sourceDatabaseId: path.basename(dbDir), action: "skipped", reason: "no metadata.json" });
2124
1807
  return;
2125
1808
  }
2126
- const metadata = JSON.parse(readFileSync(metadataPath, "utf-8"));
1809
+ const { metadata, indexes, constraints, ops } = exported;
2127
1810
  const databaseId = metadata.databaseId;
1811
+ const entry = (fields) => ({
1812
+ sourceDatabaseId: databaseId,
1813
+ ...(isNonEmptyString(metadata.title) ? { title: metadata.title } : {}),
1814
+ ...fields,
1815
+ });
2128
1816
  if (dryRun) {
2129
1817
  // Report record/batch counts without writing anything (no DB creation,
2130
1818
  // no index registration, no batch write).
2131
- const recordCount = countRecordLines(dbDir);
1819
+ const recordCount = ops.length;
2132
1820
  const batchCount = chunk(new Array(recordCount), batchSize).length;
2133
1821
  summary.created++;
1822
+ summary.databases.push(entry({ action: "created" }));
2134
1823
  summary.recordsImported += recordCount;
2135
1824
  summary.batches += batchCount;
2136
1825
  info(`[dry-run] Would import database ${databaseId} (${metadata.title || "untitled"}) — ${recordCount} record(s), ${batchCount} batch(es)`);
@@ -2153,6 +1842,7 @@ async function importSingleDatabase(client, appId, dbDir, options) {
2153
1842
  if (exists && !overwrite) {
2154
1843
  warn(`Skipping ${databaseId}: already exists (use --overwrite to replace)`);
2155
1844
  summary.skipped++;
1845
+ summary.databases.push(entry({ action: "skipped", reason: "exists" }));
2156
1846
  return;
2157
1847
  }
2158
1848
  // Create database if it doesn't exist
@@ -2173,59 +1863,38 @@ async function importSingleDatabase(client, appId, dbDir, options) {
2173
1863
  const created = await client.createDatabase(appId, createData);
2174
1864
  targetDatabaseId = created.databaseId || created.id || databaseId;
2175
1865
  summary.created++;
1866
+ summary.databases.push(entry({ action: "created", targetDatabaseId }));
2176
1867
  }
2177
1868
  else {
2178
1869
  summary.updated++;
1870
+ summary.databases.push(entry({ action: "updated", targetDatabaseId }));
2179
1871
  }
2180
1872
  // Register indexes
2181
- const indexesPath = path.join(dbDir, "indexes.json");
2182
- if (existsSync(indexesPath)) {
2183
- const indexes = JSON.parse(readFileSync(indexesPath, "utf-8"));
2184
- for (const idx of indexes) {
2185
- try {
2186
- await client.registerDatabaseIndex(appId, targetDatabaseId, {
2187
- modelName: idx.modelName || idx.model_name,
2188
- fieldName: idx.fieldName || idx.field_name,
2189
- fieldType: idx.fieldType || idx.field_type || "string",
2190
- unique: idx.isUnique || idx.is_unique || false,
2191
- });
2192
- summary.indexesRegistered++;
2193
- }
2194
- catch {
2195
- // Index may already exist
2196
- }
1873
+ for (const idx of indexes) {
1874
+ try {
1875
+ await client.registerDatabaseIndex(appId, targetDatabaseId, {
1876
+ modelName: idx.modelName || idx.model_name,
1877
+ fieldName: idx.fieldName || idx.field_name,
1878
+ fieldType: idx.fieldType || idx.field_type || "string",
1879
+ unique: Boolean(idx.isUnique || idx.is_unique),
1880
+ });
1881
+ summary.indexesRegistered++;
1882
+ }
1883
+ catch {
1884
+ // Index may already exist
2197
1885
  }
2198
1886
  }
2199
1887
  // Register unique constraints
2200
- const constraintsPath = path.join(dbDir, "constraints.json");
2201
- if (existsSync(constraintsPath)) {
2202
- const constraints = JSON.parse(readFileSync(constraintsPath, "utf-8"));
2203
- for (const c of constraints) {
2204
- try {
2205
- await client.registerDatabaseUniqueConstraint(appId, targetDatabaseId, {
2206
- modelName: c.modelName || c.model_name,
2207
- constraintName: c.constraintName || c.constraint_name,
2208
- fields: c.fields ? (typeof c.fields === "string" ? JSON.parse(c.fields) : c.fields) : [],
2209
- });
2210
- }
2211
- catch {
2212
- // Constraint may already exist
2213
- }
1888
+ for (const c of constraints) {
1889
+ try {
1890
+ await client.registerDatabaseUniqueConstraint(appId, targetDatabaseId, c);
1891
+ }
1892
+ catch {
1893
+ // Constraint may already exist
2214
1894
  }
2215
1895
  }
2216
1896
  // Import records via chunked batch writes (was one save per record).
2217
- const recordsPath = path.join(dbDir, "records.jsonl");
2218
- if (existsSync(recordsPath)) {
2219
- const lines = readFileSync(recordsPath, "utf-8").split("\n").filter(Boolean);
2220
- // Map each records.jsonl line to a batch save op. Preserve the explicit
2221
- // `_type`/`_id`; strip the redundant id/type keys out of `_data` (the
2222
- // per-record loop did the same) so they don't duplicate into stored data.
2223
- const ops = lines.map((line) => {
2224
- const record = JSON.parse(line);
2225
- const { _type, _id, _data } = record;
2226
- const { id: _ignoredId, type: _ignoredType, ...data } = _data;
2227
- return { op: "save", modelName: _type, id: _id, data };
2228
- });
1897
+ if (ops.length > 0) {
2229
1898
  const chunks = chunk(ops, batchSize);
2230
1899
  summary.batches += chunks.length;
2231
1900
  for (let i = 0; i < chunks.length; i++) {
@@ -2279,13 +1948,108 @@ async function importSingleDatabase(client, appId, dbDir, options) {
2279
1948
  }
2280
1949
  }
2281
1950
  }
2282
- info(`Imported database ${databaseId} (${metadata.title || "untitled"})`);
1951
+ const as = targetDatabaseId !== databaseId ? ` as ${targetDatabaseId}` : "";
1952
+ info(`Imported database ${databaseId} (${metadata.title || "untitled"})${as}`);
2283
1953
  }
2284
- /** Count non-empty lines in a database export's records.jsonl (0 if absent). */
2285
- function countRecordLines(dbDir) {
1954
+ /**
1955
+ * The index list in the server's `{ indexes: [...] }` answer, or in an
1956
+ * export's indexes.json: exports written before #4490 hold that envelope,
1957
+ * later ones the bare list. `source` names where it came from in the error.
1958
+ */
1959
+ function indexList(parsed, source) {
1960
+ const list = Array.isArray(parsed) ? parsed : parsed?.indexes;
1961
+ if (!Array.isArray(list)) {
1962
+ throw new Error(`${source} is not an index list (expected an array, or an object with an "indexes" array).`);
1963
+ }
1964
+ return list;
1965
+ }
1966
+ /**
1967
+ * Read and check every file in one database's export directory, so an export
1968
+ * that cannot be imported fails before anything is written. Null when the
1969
+ * directory has no metadata.json.
1970
+ */
1971
+ function readDatabaseExport(dbDir) {
1972
+ const metadataPath = path.join(dbDir, "metadata.json");
1973
+ if (!existsSync(metadataPath))
1974
+ return null;
1975
+ const metadata = readExportJson(metadataPath);
1976
+ const indexesPath = path.join(dbDir, "indexes.json");
1977
+ const indexes = existsSync(indexesPath) ? indexList(readExportJson(indexesPath), indexesPath) : [];
1978
+ const constraintsPath = path.join(dbDir, "constraints.json");
1979
+ const constraints = [];
1980
+ if (existsSync(constraintsPath)) {
1981
+ const parsed = readExportJson(constraintsPath);
1982
+ const list = Array.isArray(parsed) ? parsed : parsed?.constraints;
1983
+ if (!Array.isArray(list)) {
1984
+ throw new Error(`${constraintsPath} is not a constraint list (expected an array).`);
1985
+ }
1986
+ list.forEach((c, i) => constraints.push(exportedConstraint(c, `${constraintsPath} entry ${i + 1}`)));
1987
+ }
1988
+ // Map each records.jsonl line to a batch save op. Preserve the explicit
1989
+ // `_type`/`_id`; strip the redundant id/type keys out of `_data` (the
1990
+ // per-record loop did the same) so they don't duplicate into stored data.
2286
1991
  const recordsPath = path.join(dbDir, "records.jsonl");
2287
- if (!existsSync(recordsPath))
2288
- return 0;
2289
- return readFileSync(recordsPath, "utf-8").split("\n").filter(Boolean).length;
1992
+ const ops = [];
1993
+ if (existsSync(recordsPath)) {
1994
+ readFileSync(recordsPath, "utf-8")
1995
+ .split("\n")
1996
+ .forEach((line, i) => {
1997
+ if (!line)
1998
+ return;
1999
+ const where = `${recordsPath} line ${i + 1}`;
2000
+ let record;
2001
+ try {
2002
+ record = JSON.parse(line);
2003
+ }
2004
+ catch (err) {
2005
+ throw new Error(`${where} is not valid JSON: ${err.message}`);
2006
+ }
2007
+ const { _type, _id, _data } = record ?? {};
2008
+ if (!isNonEmptyString(_type) || !isNonEmptyString(_id) || !_data || typeof _data !== "object") {
2009
+ throw new Error(`${where} is not a record (expected "_type", "_id" and "_data").`);
2010
+ }
2011
+ const { id: _ignoredId, type: _ignoredType, ...data } = _data;
2012
+ ops.push({ op: "save", modelName: _type, id: _id, data });
2013
+ });
2014
+ }
2015
+ return { metadata, indexes, constraints, ops };
2016
+ }
2017
+ function isNonEmptyString(value) {
2018
+ return typeof value === "string" && value.length > 0;
2019
+ }
2020
+ /**
2021
+ * One constraints.json entry as the register route takes it. `fields` is the
2022
+ * list the server answers, or the JSON string older exports carry; the route
2023
+ * refuses fewer than two, so such an entry fails here rather than after the
2024
+ * database is created.
2025
+ */
2026
+ function exportedConstraint(c, where) {
2027
+ const modelName = c?.modelName || c?.model_name;
2028
+ const constraintName = c?.constraintName || c?.constraint_name;
2029
+ let fields = c?.fields;
2030
+ if (typeof fields === "string") {
2031
+ try {
2032
+ fields = JSON.parse(fields);
2033
+ }
2034
+ catch (err) {
2035
+ throw new Error(`${where} has fields that are not valid JSON: ${err.message}`);
2036
+ }
2037
+ }
2038
+ if (!isNonEmptyString(modelName) ||
2039
+ !isNonEmptyString(constraintName) ||
2040
+ !Array.isArray(fields) ||
2041
+ fields.length < 2 ||
2042
+ !fields.every(isNonEmptyString)) {
2043
+ throw new Error(`${where} is not a unique constraint (expected "model_name", "constraint_name" and two or more "fields").`);
2044
+ }
2045
+ return { modelName, constraintName, fields };
2046
+ }
2047
+ function readExportJson(file) {
2048
+ try {
2049
+ return JSON.parse(readFileSync(file, "utf-8"));
2050
+ }
2051
+ catch (err) {
2052
+ throw new Error(`${file} is not valid JSON: ${err.message}`);
2053
+ }
2290
2054
  }
2291
2055
  //# sourceMappingURL=databases.js.map