@cosmicdrift/kumiko-framework 0.388.0 → 0.390.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 (711) hide show
  1. package/AGENTS.md +12 -4
  2. package/README.md +1 -1
  3. package/agents/examples/apex-surface-auth.md +2 -3
  4. package/agents/examples/api-worker-split.md +9 -2
  5. package/agents/examples/auth-claims.md +1 -1
  6. package/agents/examples/cross-feature-events.md +12 -12
  7. package/agents/examples/crypto-shredding-hr.md +2 -2
  8. package/agents/examples/encrypted-tenant-config.md +1 -1
  9. package/agents/examples/error-contract.md +12 -7
  10. package/agents/examples/event-sourcing.md +29 -29
  11. package/agents/examples/files-post-processing.md +10 -8
  12. package/agents/examples/golden-path.md +13 -1
  13. package/agents/examples/inbound-mail-triage.md +1 -0
  14. package/agents/examples/lane-routing.md +2 -1
  15. package/agents/examples/legal-pages.md +2 -2
  16. package/agents/examples/lifecycle-hooks.md +55 -2
  17. package/agents/examples/list-table-options.md +466 -0
  18. package/agents/examples/managed-config.md +4 -4
  19. package/agents/examples/managed-pages.md +1 -1
  20. package/agents/examples/pdf-audit-export.md +4 -2
  21. package/agents/examples/relations.md +19 -4
  22. package/agents/examples/search.md +4 -4
  23. package/agents/examples/secrets-demo.md +9 -6
  24. package/agents/examples/state-machine.md +5 -4
  25. package/agents/examples/tenant-isolation.md +73 -1
  26. package/agents/examples/tenant-settings.md +1 -1
  27. package/agents/examples/user-data-rights.md +3 -6
  28. package/agents/examples/workflow-engine.md +53 -47
  29. package/agents/examples.md +5 -4
  30. package/agents/features.md +1 -1
  31. package/agents/widgets.md +1 -0
  32. package/dist/api/api-constants.d.ts +1 -0
  33. package/dist/api/api-constants.js +2 -0
  34. package/dist/api/auth-middleware.js +1 -1
  35. package/dist/api/auth-routes-invite.js +2 -1
  36. package/dist/api/auth-routes-shared.d.ts +2 -0
  37. package/dist/api/auth-routes-shared.js +5 -0
  38. package/dist/api/client-error-route.js +2 -3
  39. package/dist/api/entity-read-access.d.ts +4 -1
  40. package/dist/api/entity-read-access.js +14 -0
  41. package/dist/api/export/export-cells-reference.d.ts +9 -0
  42. package/dist/api/export/export-cells-reference.js +21 -0
  43. package/dist/api/export/export-cells.d.ts +11 -0
  44. package/dist/api/export/export-cells.js +136 -0
  45. package/dist/api/export/export-ciphertext-guard.d.ts +2 -0
  46. package/dist/api/export/export-ciphertext-guard.js +27 -0
  47. package/dist/api/export/export-columns.d.ts +31 -0
  48. package/dist/api/export/export-columns.js +85 -0
  49. package/dist/api/export/export-errors.d.ts +4 -0
  50. package/dist/api/export/export-errors.js +14 -0
  51. package/dist/api/export/export-route.d.ts +4 -0
  52. package/dist/api/export/export-route.js +75 -0
  53. package/dist/api/export/export-rows.d.ts +13 -0
  54. package/dist/api/export/export-rows.js +62 -0
  55. package/dist/api/export/export-screen.d.ts +13 -0
  56. package/dist/api/export/export-screen.js +47 -0
  57. package/dist/api/export/export-xlsx-writer.d.ts +4 -0
  58. package/dist/api/export/export-xlsx-writer.js +21 -0
  59. package/dist/api/extra-route.d.ts +7 -1
  60. package/dist/api/index.d.ts +23 -27
  61. package/dist/api/index.js +13 -15
  62. package/dist/api/jwt.js +1 -1
  63. package/dist/api/observability-middleware.d.ts +1 -1
  64. package/dist/api/observability-middleware.js +2 -1
  65. package/dist/api/pii-leak-guard.d.ts +3 -0
  66. package/dist/api/pii-leak-guard.js +3 -2
  67. package/dist/api/request-context-internals.d.ts +31 -0
  68. package/dist/api/request-context-internals.js +11 -0
  69. package/dist/api/request-context-scopes.d.ts +14 -0
  70. package/dist/api/request-context-scopes.js +69 -0
  71. package/dist/api/request-context.d.ts +1 -40
  72. package/dist/api/request-context.js +22 -51
  73. package/dist/api/request-id-middleware.d.ts +1 -1
  74. package/dist/api/route-registrars.d.ts +2 -1
  75. package/dist/api/route-registrars.js +1 -1
  76. package/dist/api/routes.d.ts +16 -0
  77. package/dist/api/routes.js +9 -5
  78. package/dist/api/server-boot-checks.d.ts +1 -1
  79. package/dist/api/server-boot-checks.js +2 -2
  80. package/dist/api/server-event-dispatcher.d.ts +6 -1
  81. package/dist/api/server-event-dispatcher.js +3 -4
  82. package/dist/api/server-extra-routes.d.ts +1 -1
  83. package/dist/api/server-extra-routes.js +5 -1
  84. package/dist/api/server-middleware.js +3 -1
  85. package/dist/api/server-routes.d.ts +3 -2
  86. package/dist/api/server-routes.js +8 -2
  87. package/dist/api/server-wiring.js +8 -4
  88. package/dist/api/server.d.ts +2 -1
  89. package/dist/api/sse-route.d.ts +3 -1
  90. package/dist/api/sse-route.js +11 -1
  91. package/dist/api/tenant-scoped-secrets.d.ts +2 -0
  92. package/dist/api/tenant-scoped-secrets.js +13 -0
  93. package/dist/api/websocket-route.d.ts +1 -1
  94. package/dist/auth/index.d.ts +0 -1
  95. package/dist/auth/roles.d.ts +0 -5
  96. package/dist/compliance/duration-spec.d.ts +0 -1
  97. package/dist/compliance/duration-spec.js +0 -5
  98. package/dist/compliance/index.d.ts +4 -4
  99. package/dist/compliance/index.js +2 -2
  100. package/dist/compliance/profiles.d.ts +0 -15
  101. package/dist/compliance/profiles.js +0 -23
  102. package/dist/config/index.d.ts +11 -9
  103. package/dist/config/index.js +13 -1
  104. package/dist/config/internals.d.ts +9 -0
  105. package/dist/config/internals.js +1 -0
  106. package/dist/consumer-cli-internals.d.ts +4 -0
  107. package/dist/consumer-cli-internals.js +1 -0
  108. package/dist/consumer-cli.d.ts +1 -4
  109. package/dist/consumer-cli.js +5 -1
  110. package/dist/crypto/event-pii.js +1 -1
  111. package/dist/crypto/index.d.ts +8 -9
  112. package/dist/crypto/index.js +7 -8
  113. package/dist/crypto/pg-kms-adapter.d.ts +1 -0
  114. package/dist/crypto/pg-kms-adapter.js +17 -18
  115. package/dist/db/aggregate-sql.d.ts +2 -0
  116. package/dist/db/aggregate-sql.js +10 -0
  117. package/dist/db/apply-entity-event.d.ts +1 -1
  118. package/dist/db/apply-entity-event.js +15 -47
  119. package/dist/db/blind-index-cleanup.js +91 -77
  120. package/dist/db/closed-connection.js +12 -19
  121. package/dist/db/collect-table-metas.js +1 -1
  122. package/dist/db/compound-types.d.ts +1 -1
  123. package/dist/db/compound-types.js +0 -7
  124. package/dist/db/config-seed.d.ts +2 -1
  125. package/dist/db/config-seed.js +6 -1
  126. package/dist/db/connection.d.ts +7 -6
  127. package/dist/db/connection.js +43 -24
  128. package/dist/db/cross-tenant-reads.d.ts +1 -1
  129. package/dist/db/cross-tenant-reads.js +1 -1
  130. package/dist/db/dialect.d.ts +0 -5
  131. package/dist/db/dialect.js +0 -3
  132. package/dist/db/driver-row-coercion.js +4 -4
  133. package/dist/db/driver-value-preparation.js +6 -4
  134. package/dist/db/eagerload.d.ts +2 -1
  135. package/dist/db/entity-field-encryption.d.ts +1 -1
  136. package/dist/db/entity-table-meta.d.ts +1 -1
  137. package/dist/db/event-store-executor-context.d.ts +3 -1
  138. package/dist/db/event-store-executor-context.js +4 -3
  139. package/dist/db/event-store-executor-read-aggregate-currencies.d.ts +17 -0
  140. package/dist/db/event-store-executor-read-aggregate-currencies.js +40 -0
  141. package/dist/db/event-store-executor-read-aggregate.js +36 -5
  142. package/dist/db/event-store-executor-read-filter.d.ts +1 -1
  143. package/dist/db/event-store-executor-read-filter.js +6 -3
  144. package/dist/db/event-store-executor-read-rows.d.ts +2 -1
  145. package/dist/db/event-store-executor-read-search.d.ts +2 -1
  146. package/dist/db/event-store-executor-read-sort.d.ts +2 -1
  147. package/dist/db/event-store-executor-read.js +2 -2
  148. package/dist/db/event-store-executor-write-atomic.d.ts +4 -0
  149. package/dist/db/event-store-executor-write-atomic.js +42 -0
  150. package/dist/db/event-store-executor-write-steps.d.ts +3 -5
  151. package/dist/db/event-store-executor-write-steps.js +0 -5
  152. package/dist/db/event-store-executor-write.js +22 -19
  153. package/dist/db/event-store-executor.d.ts +1 -1
  154. package/dist/db/event-store-executor.js +2 -1
  155. package/dist/db/executor-managed-tables.d.ts +7 -1
  156. package/dist/db/executor-managed-tables.js +12 -3
  157. package/dist/db/index.d.ts +29 -28
  158. package/dist/db/index.js +22 -20
  159. package/dist/db/known-table-names.d.ts +6 -0
  160. package/dist/db/known-table-names.js +21 -0
  161. package/dist/db/list-aggregate-labels.d.ts +1 -1
  162. package/dist/db/located-timestamp.d.ts +1 -1
  163. package/dist/db/located-timestamp.js +0 -5
  164. package/dist/db/migrate-generator.d.ts +17 -1
  165. package/dist/db/migrate-generator.js +50 -20
  166. package/dist/db/migrate-primary-key.d.ts +12 -0
  167. package/dist/db/migrate-primary-key.js +45 -0
  168. package/dist/db/migrate-rls-diff.d.ts +20 -0
  169. package/dist/db/migrate-rls-diff.js +61 -0
  170. package/dist/db/migrate-runner.js +7 -3
  171. package/dist/db/money.d.ts +1 -1
  172. package/dist/db/money.js +1 -1
  173. package/dist/db/parent-ref-clause.d.ts +2 -1
  174. package/dist/db/pg-error.d.ts +2 -0
  175. package/dist/db/pg-error.js +37 -21
  176. package/dist/db/queries/backfill-pii.js +3 -6
  177. package/dist/db/queries/database-now.js +2 -1
  178. package/dist/db/queries/ddl.d.ts +3 -0
  179. package/dist/db/queries/ddl.js +34 -1
  180. package/dist/db/queries/event-store.js +4 -2
  181. package/dist/db/queries/event-tenants.d.ts +2 -0
  182. package/dist/db/queries/event-tenants.js +17 -0
  183. package/dist/db/queries/rebuild-rls-guard.d.ts +2 -0
  184. package/dist/db/queries/rebuild-rls-guard.js +29 -0
  185. package/dist/db/queries/rls-boot-catalog.d.ts +16 -0
  186. package/dist/db/queries/rls-boot-catalog.js +39 -0
  187. package/dist/db/queries/rls-catalog.d.ts +6 -0
  188. package/dist/db/queries/rls-catalog.js +82 -0
  189. package/dist/db/queries/rls-scope.d.ts +3 -0
  190. package/dist/db/queries/rls-scope.js +17 -0
  191. package/dist/db/queries/rls-shape.d.ts +10 -0
  192. package/dist/db/queries/rls-shape.js +42 -0
  193. package/dist/db/queries/session-advisory-lock.d.ts +2 -0
  194. package/dist/db/queries/session-advisory-lock.js +23 -0
  195. package/dist/db/queries/shadow-swap.d.ts +1 -2
  196. package/dist/db/queries/shadow-swap.js +11 -28
  197. package/dist/db/queries/test-stack.d.ts +4 -1
  198. package/dist/db/queries/test-stack.js +83 -2
  199. package/dist/db/query.d.ts +14 -0
  200. package/dist/db/query.js +77 -48
  201. package/dist/db/reference-data.d.ts +1 -1
  202. package/dist/db/reference-data.js +20 -3
  203. package/dist/db/render-ddl.d.ts +6 -2
  204. package/dist/db/render-ddl.js +7 -7
  205. package/dist/db/render-rls-ddl.d.ts +35 -0
  206. package/dist/db/render-rls-ddl.js +127 -0
  207. package/dist/db/replay-migration-sql.d.ts +3 -1
  208. package/dist/db/replay-migration-sql.js +22 -5
  209. package/dist/db/replay-rls.d.ts +25 -0
  210. package/dist/db/replay-rls.js +156 -0
  211. package/dist/db/row-level-security-boot-check.d.ts +5 -0
  212. package/dist/db/row-level-security-boot-check.js +85 -0
  213. package/dist/db/row-level-security-connection.d.ts +3 -0
  214. package/dist/db/row-level-security-connection.js +213 -0
  215. package/dist/db/row-level-security-scope.d.ts +33 -0
  216. package/dist/db/row-level-security-scope.js +127 -0
  217. package/dist/db/scope-tenant-db-to-tenant.d.ts +3 -0
  218. package/dist/db/scope-tenant-db-to-tenant.js +14 -0
  219. package/dist/db/sql-identifier.d.ts +1 -0
  220. package/dist/db/sql-identifier.js +3 -0
  221. package/dist/db/statement-timeout.js +2 -1
  222. package/dist/db/table-builder.d.ts +2 -1
  223. package/dist/db/table-builder.js +1 -1
  224. package/dist/db/table-info.js +1 -1
  225. package/dist/db/table-push.d.ts +11 -2
  226. package/dist/db/table-push.js +15 -2
  227. package/dist/db/tenant-db-runner.d.ts +3 -1
  228. package/dist/db/tenant-db-runner.js +4 -3
  229. package/dist/db/tenant-db-scoped-rebind.d.ts +10 -0
  230. package/dist/db/tenant-db-scoped-rebind.js +33 -0
  231. package/dist/db/tenant-db-statement-runner.d.ts +13 -0
  232. package/dist/db/tenant-db-statement-runner.js +48 -0
  233. package/dist/db/tenant-db-upsert.d.ts +5 -0
  234. package/dist/db/tenant-db-upsert.js +91 -0
  235. package/dist/db/tenant-db.d.ts +17 -12
  236. package/dist/db/tenant-db.js +60 -121
  237. package/dist/db/tenant-id-filter.d.ts +3 -0
  238. package/dist/db/tenant-id-filter.js +30 -0
  239. package/dist/db/transaction-serialization.d.ts +6 -0
  240. package/dist/db/transaction-serialization.js +60 -0
  241. package/dist/derivatives/delete-stored-file.js +1 -1
  242. package/dist/derivatives/index.d.ts +2 -5
  243. package/dist/derivatives/index.js +2 -3
  244. package/dist/engine/access.d.ts +2 -1
  245. package/dist/engine/access.js +1 -1
  246. package/dist/engine/boot-validator/bundled-lists-table.d.ts +2 -0
  247. package/dist/engine/boot-validator/bundled-lists-table.js +36 -0
  248. package/dist/engine/boot-validator/entity-handler.d.ts +2 -1
  249. package/dist/engine/boot-validator/entity-handler.js +1 -1
  250. package/dist/engine/boot-validator/entity-list-aggregate-options.d.ts +3 -0
  251. package/dist/engine/boot-validator/entity-list-aggregate-options.js +23 -0
  252. package/dist/engine/boot-validator/list-bulk-actions.d.ts +3 -0
  253. package/dist/engine/boot-validator/list-bulk-actions.js +49 -0
  254. package/dist/engine/boot-validator/list-column-layout.d.ts +8 -0
  255. package/dist/engine/boot-validator/list-column-layout.js +41 -0
  256. package/dist/engine/boot-validator/list-table-aggregate-options.d.ts +24 -0
  257. package/dist/engine/boot-validator/list-table-aggregate-options.js +145 -0
  258. package/dist/engine/boot-validator/list-table-aggregate-query.d.ts +11 -0
  259. package/dist/engine/boot-validator/list-table-aggregate-query.js +31 -0
  260. package/dist/engine/boot-validator/list-table-export-options.d.ts +1 -0
  261. package/dist/engine/boot-validator/list-table-export-options.js +27 -0
  262. package/dist/engine/boot-validator/list-table-options.d.ts +3 -0
  263. package/dist/engine/boot-validator/list-table-options.js +77 -0
  264. package/dist/engine/boot-validator/list-table-reject-unknown-keys.d.ts +1 -0
  265. package/dist/engine/boot-validator/list-table-reject-unknown-keys.js +7 -0
  266. package/dist/engine/boot-validator/nav.d.ts +3 -1
  267. package/dist/engine/boot-validator/nav.js +1 -1
  268. package/dist/engine/boot-validator/ownership.d.ts +2 -1
  269. package/dist/engine/boot-validator/parent-ref.d.ts +2 -1
  270. package/dist/engine/boot-validator/projection-list-screens.d.ts +2 -1
  271. package/dist/engine/boot-validator/projection-list-screens.js +3 -13
  272. package/dist/engine/boot-validator/query-refs.d.ts +2 -1
  273. package/dist/engine/boot-validator/related-list-table-rules.d.ts +4 -0
  274. package/dist/engine/boot-validator/related-list-table-rules.js +42 -0
  275. package/dist/engine/boot-validator/screens-forms.d.ts +2 -1
  276. package/dist/engine/boot-validator/screens-kind-entity-list.js +7 -0
  277. package/dist/engine/boot-validator/screens-kind-projection-list.js +4 -0
  278. package/dist/engine/boot-validator/screens-kind-shared.d.ts +3 -1
  279. package/dist/engine/boot-validator/screens-lists.js +12 -2
  280. package/dist/engine/boot-validator/screens.d.ts +2 -1
  281. package/dist/engine/boot-validator/workspaces.d.ts +3 -1
  282. package/dist/engine/bridge-stub.d.ts +5 -2
  283. package/dist/engine/bridge-stub.js +39 -24
  284. package/dist/engine/build-app-schema.d.ts +2 -1
  285. package/dist/engine/build-app-schema.js +9 -1
  286. package/dist/engine/build-config-feature-schema.js +6 -1
  287. package/dist/engine/config-helpers.d.ts +2 -2
  288. package/dist/engine/config-helpers.js +0 -9
  289. package/dist/engine/constants.d.ts +0 -10
  290. package/dist/engine/constants.js +0 -8
  291. package/dist/engine/create-app.js +1 -1
  292. package/dist/engine/define-feature.d.ts +2 -1
  293. package/dist/engine/define-feature.js +5 -2
  294. package/dist/engine/define-handler.d.ts +1 -1
  295. package/dist/engine/define-step.d.ts +0 -1
  296. package/dist/engine/define-step.js +0 -3
  297. package/dist/engine/embedded-derived.d.ts +1 -1
  298. package/dist/engine/entity-handlers.d.ts +2 -1
  299. package/dist/engine/entity-handlers.js +7 -7
  300. package/dist/engine/entity-list-runtime-options.js +3 -1
  301. package/dist/engine/entity-list-searchability.d.ts +2 -1
  302. package/dist/engine/event-def.d.ts +2 -1
  303. package/dist/engine/event-helpers.d.ts +3 -1
  304. package/dist/engine/event-helpers.js +3 -3
  305. package/dist/engine/extension-names.d.ts +2 -8
  306. package/dist/engine/extension-names.js +2 -2
  307. package/dist/engine/extension-selector-plugins.d.ts +1 -1
  308. package/dist/engine/extensions/storage-provider.d.ts +1 -2
  309. package/dist/engine/extensions/user-data.d.ts +0 -8
  310. package/dist/engine/factories.d.ts +2 -1
  311. package/dist/engine/feature-builder-state.d.ts +9 -1
  312. package/dist/engine/feature-builder-state.js +1 -0
  313. package/dist/engine/feature-changelog.d.ts +1 -1
  314. package/dist/engine/feature-config-events-jobs.d.ts +4 -1
  315. package/dist/engine/feature-entity-handlers.d.ts +5 -1
  316. package/dist/engine/feature-manifest.d.ts +1 -0
  317. package/dist/engine/feature-manifest.js +2 -1
  318. package/dist/engine/feature-ui-extensions.d.ts +7 -1
  319. package/dist/engine/feature-ui-extensions.js +6 -4
  320. package/dist/engine/field-access.d.ts +3 -1
  321. package/dist/engine/field-access.js +12 -0
  322. package/dist/engine/handler-field-references.d.ts +0 -4
  323. package/dist/engine/index.d.ts +58 -55
  324. package/dist/engine/index.js +23 -28
  325. package/dist/engine/instruction-fields.d.ts +1 -1
  326. package/dist/engine/personal-data-fields.d.ts +1 -1
  327. package/dist/engine/qualified-name.d.ts +0 -1
  328. package/dist/engine/read-claim.d.ts +2 -1
  329. package/dist/engine/registry-facade.js +0 -3
  330. package/dist/engine/registry-ingest.d.ts +2 -1
  331. package/dist/engine/registry-ingest.js +1 -2
  332. package/dist/engine/registry-state.d.ts +12 -2
  333. package/dist/engine/registry-state.js +2 -3
  334. package/dist/engine/registry-validate.d.ts +3 -1
  335. package/dist/engine/registry-validate.js +7 -7
  336. package/dist/engine/run-in.d.ts +1 -1
  337. package/dist/engine/run-in.js +0 -1
  338. package/dist/engine/schema-builder.d.ts +1 -1
  339. package/dist/engine/schema-builder.js +1 -1
  340. package/dist/engine/screen-filter-ops.d.ts +2 -1
  341. package/dist/engine/screen-filter-ops.js +2 -5
  342. package/dist/engine/soft-delete-cleanup.d.ts +1 -1
  343. package/dist/engine/soft-delete-cleanup.js +4 -4
  344. package/dist/engine/state-machine.js +2 -1
  345. package/dist/engine/steps/_read-source.js +1 -1
  346. package/dist/engine/steps/aggregate-append-event.js +2 -2
  347. package/dist/engine/steps/call-feature.js +2 -2
  348. package/dist/engine/steps/mail-send.js +1 -1
  349. package/dist/engine/steps/retry.js +1 -1
  350. package/dist/engine/steps/wait-for-event.js +1 -1
  351. package/dist/engine/steps/wait.js +1 -1
  352. package/dist/engine/steps/webhook-send.js +1 -1
  353. package/dist/engine/strip-disabled-features-from-app-schema.js +7 -3
  354. package/dist/engine/template-variables.d.ts +2 -1
  355. package/dist/engine/transfer-adjacency.d.ts +1 -1
  356. package/dist/engine/types/feature.d.ts +1 -0
  357. package/dist/engine/types/index.d.ts +8 -30
  358. package/dist/engine/types/index.js +2 -10
  359. package/dist/engine/types/screen.d.ts +1 -1
  360. package/dist/engine/types/screen.js +1 -1
  361. package/dist/engine/validation.d.ts +2 -1
  362. package/dist/entrypoint/index.d.ts +9 -35
  363. package/dist/entrypoint/index.js +10 -1
  364. package/dist/entrypoint/internals.d.ts +40 -0
  365. package/dist/entrypoint/internals.js +1 -0
  366. package/dist/entrypoint/row-level-security-mode-check.d.ts +3 -0
  367. package/dist/entrypoint/row-level-security-mode-check.js +19 -0
  368. package/dist/env/dry-run-internals.d.ts +10 -0
  369. package/dist/env/dry-run-internals.js +1 -0
  370. package/dist/env/dry-run.d.ts +1 -10
  371. package/dist/env/dry-run.js +2 -1
  372. package/dist/env/index.d.ts +1 -85
  373. package/dist/env/index.js +6 -50
  374. package/dist/env/internals.d.ts +87 -0
  375. package/dist/env/internals.js +53 -0
  376. package/dist/errors/classes.js +2 -2
  377. package/dist/errors/index.d.ts +5 -14
  378. package/dist/errors/index.js +4 -9
  379. package/dist/errors/member-resolution.js +1 -1
  380. package/dist/errors/reasons.d.ts +0 -1
  381. package/dist/errors/reasons.js +7 -7
  382. package/dist/errors/serialize.d.ts +0 -18
  383. package/dist/errors/serialize.js +0 -27
  384. package/dist/es-ops/index.d.ts +4 -4
  385. package/dist/es-ops/index.js +2 -2
  386. package/dist/es-ops/operations-schema.d.ts +1 -1
  387. package/dist/es-ops/types.d.ts +4 -5
  388. package/dist/event-store/admin-api-internals.d.ts +14 -0
  389. package/dist/event-store/admin-api-internals.js +1 -0
  390. package/dist/event-store/admin-api.d.ts +1 -14
  391. package/dist/event-store/admin-api.js +11 -6
  392. package/dist/event-store/archive.js +4 -2
  393. package/dist/event-store/errors.js +2 -2
  394. package/dist/event-store/event-store.d.ts +1 -0
  395. package/dist/event-store/event-store.js +42 -32
  396. package/dist/event-store/events-schema.js +4 -1
  397. package/dist/event-store/index.d.ts +11 -13
  398. package/dist/event-store/index.js +7 -9
  399. package/dist/event-store/provenance-append.js +1 -1
  400. package/dist/event-store/rebuild-dead-letter.js +4 -2
  401. package/dist/event-store/snapshot.js +4 -3
  402. package/dist/event-store/stream-scope.d.ts +2 -0
  403. package/dist/event-store/stream-scope.js +6 -0
  404. package/dist/event-store/upcaster-dead-letter.js +4 -2
  405. package/dist/event-store/upcaster.d.ts +2 -1
  406. package/dist/files/action-form-upload.d.ts +2 -1
  407. package/dist/files/action-form-upload.js +1 -1
  408. package/dist/files/assert-file-refs-belong-to-tenant.d.ts +2 -1
  409. package/dist/files/assert-file-refs-belong-to-tenant.js +1 -1
  410. package/dist/files/bind-pending-file-refs.d.ts +2 -1
  411. package/dist/files/bind-pending-file-refs.js +2 -1
  412. package/dist/files/bind-referenced-files.write.js +1 -1
  413. package/dist/files/create-file-ref-from-bytes.d.ts +6 -3
  414. package/dist/files/create-file-ref-from-bytes.js +6 -3
  415. package/dist/files/create-file-ref.d.ts +6 -2
  416. package/dist/files/create-file-ref.js +13 -4
  417. package/dist/files/dispose-removed-file-refs.d.ts +2 -1
  418. package/dist/files/dispose-removed-file-refs.js +1 -1
  419. package/dist/files/feature.js +2 -2
  420. package/dist/files/file-handle.js +1 -1
  421. package/dist/files/file-routes.d.ts +3 -1
  422. package/dist/files/file-routes.js +41 -4
  423. package/dist/files/index.d.ts +11 -13
  424. package/dist/files/index.js +5 -7
  425. package/dist/files/load-save-file-refs.d.ts +2 -1
  426. package/dist/files/load-save-file-refs.js +1 -1
  427. package/dist/files/provider-resolver.d.ts +6 -4
  428. package/dist/files/provider-resolver.js +5 -5
  429. package/dist/files/record-write-check.d.ts +6 -0
  430. package/dist/files/record-write-check.js +13 -0
  431. package/dist/files/storage-tracking.js +4 -2
  432. package/dist/files/sweep-orphaned-uploads.d.ts +1 -1
  433. package/dist/files/sweep-orphaned-uploads.js +1 -1
  434. package/dist/files/upload-ledger.d.ts +2 -2
  435. package/dist/files/upload-ledger.js +4 -4
  436. package/dist/i18n/index.d.ts +2 -8
  437. package/dist/i18n/index.js +1 -1
  438. package/dist/i18n/internals.d.ts +7 -0
  439. package/dist/i18n/internals.js +1 -0
  440. package/dist/i18n/required-surface-keys.d.ts +4 -1
  441. package/dist/i18n/required-surface-keys.js +7 -2
  442. package/dist/internal/row-level-security.d.ts +3 -0
  443. package/dist/internal/row-level-security.js +3 -0
  444. package/dist/internal/stack-support.d.ts +1 -1
  445. package/dist/internal/stack-support.js +1 -1
  446. package/dist/internal/testing.d.ts +1 -0
  447. package/dist/internal/testing.js +10 -6
  448. package/dist/jobs/index.d.ts +1 -1
  449. package/dist/jobs/job-append-event.d.ts +12 -0
  450. package/dist/jobs/job-append-event.js +30 -0
  451. package/dist/jobs/job-runner-context.d.ts +2 -2
  452. package/dist/jobs/job-runner-context.js +46 -16
  453. package/dist/jobs/job-runner-execution.d.ts +1 -1
  454. package/dist/jobs/job-runner-execution.js +6 -4
  455. package/dist/jobs/job-runner-gates.d.ts +1 -1
  456. package/dist/jobs/job-runner-gates.js +0 -1
  457. package/dist/jobs/job-runner-helpers.d.ts +11 -4
  458. package/dist/jobs/job-runner-helpers.js +10 -1
  459. package/dist/jobs/job-runner-scope.d.ts +5 -2
  460. package/dist/jobs/job-runner-scope.js +6 -6
  461. package/dist/jobs/job-runner-types.d.ts +2 -1
  462. package/dist/jobs/job-runner.js +22 -6
  463. package/dist/jobs/max-per-tenant.d.ts +1 -1
  464. package/dist/logging/index.d.ts +1 -2
  465. package/dist/logging/index.js +1 -1
  466. package/dist/logging/pino-logger.js +1 -1
  467. package/dist/logging/utils.d.ts +1 -0
  468. package/dist/logging/utils.js +6 -0
  469. package/dist/migrations/index.d.ts +3 -3
  470. package/dist/migrations/index.js +3 -3
  471. package/dist/migrations/pending-rebuilds.d.ts +1 -1
  472. package/dist/migrations/pending-rebuilds.js +1 -1
  473. package/dist/migrations/pii-event-backfill.js +4 -1
  474. package/dist/observability/escape-hatch-report.d.ts +2 -1
  475. package/dist/observability/escape-hatch-report.js +9 -2
  476. package/dist/observability/index.d.ts +7 -15
  477. package/dist/observability/index.js +4 -12
  478. package/dist/observability/metric-validator.js +1 -1
  479. package/dist/observability/metrics-handle.d.ts +0 -1
  480. package/dist/observability/metrics-handle.js +2 -15
  481. package/dist/observability/recording-tracer.d.ts +1 -2
  482. package/dist/observability/recording-tracer.js +0 -6
  483. package/dist/observability/sensitive-filter.d.ts +0 -2
  484. package/dist/observability/sensitive-filter.js +0 -29
  485. package/dist/pipeline/active-membership.d.ts +2 -1
  486. package/dist/pipeline/active-membership.js +6 -2
  487. package/dist/pipeline/after-rollback-sink.d.ts +6 -0
  488. package/dist/pipeline/after-rollback-sink.js +32 -0
  489. package/dist/pipeline/append-event-core.d.ts +2 -1
  490. package/dist/pipeline/append-event-core.js +2 -2
  491. package/dist/pipeline/attach-outside-transaction.d.ts +3 -0
  492. package/dist/pipeline/attach-outside-transaction.js +13 -0
  493. package/dist/pipeline/auth-claims-resolver.d.ts +2 -1
  494. package/dist/pipeline/cascade-handler.d.ts +2 -1
  495. package/dist/pipeline/cascade-handler.js +3 -2
  496. package/dist/pipeline/config-accessor-factory.d.ts +1 -1
  497. package/dist/pipeline/config-accessor-factory.js +1 -1
  498. package/dist/pipeline/context-services.d.ts +56 -0
  499. package/dist/pipeline/context-services.js +73 -0
  500. package/dist/pipeline/dispatch-batch.d.ts +2 -1
  501. package/dist/pipeline/dispatch-batch.js +39 -19
  502. package/dist/pipeline/dispatch-query.js +5 -4
  503. package/dist/pipeline/dispatch-scope.d.ts +6 -0
  504. package/dist/pipeline/dispatch-scope.js +27 -0
  505. package/dist/pipeline/dispatch-shared.d.ts +13 -9
  506. package/dist/pipeline/dispatch-shared.js +75 -194
  507. package/dist/pipeline/dispatch-stream.js +8 -4
  508. package/dist/pipeline/dispatch-write.d.ts +2 -1
  509. package/dist/pipeline/dispatch-write.js +10 -8
  510. package/dist/pipeline/dispatcher-utils.d.ts +3 -1
  511. package/dist/pipeline/dispatcher-utils.js +8 -2
  512. package/dist/pipeline/dispatcher.d.ts +3 -2
  513. package/dist/pipeline/dispatcher.js +4 -3
  514. package/dist/pipeline/event-consumer-state.d.ts +0 -1
  515. package/dist/pipeline/event-dispatcher-delivery.d.ts +1 -1
  516. package/dist/pipeline/event-dispatcher-delivery.js +7 -3
  517. package/dist/pipeline/event-dispatcher.d.ts +3 -2
  518. package/dist/pipeline/event-dispatcher.js +13 -12
  519. package/dist/pipeline/event-retention.js +59 -56
  520. package/dist/pipeline/handler-access-error.js +2 -1
  521. package/dist/pipeline/handler-context-auth.d.ts +5 -6
  522. package/dist/pipeline/handler-context-auth.js +7 -4
  523. package/dist/pipeline/handler-context-config.d.ts +2 -5
  524. package/dist/pipeline/handler-context-config.js +2 -2
  525. package/dist/pipeline/handler-context-db.d.ts +32 -7
  526. package/dist/pipeline/handler-context-db.js +26 -17
  527. package/dist/pipeline/handler-context-dispatch.d.ts +14 -6
  528. package/dist/pipeline/handler-context-dispatch.js +18 -5
  529. package/dist/pipeline/handler-context-events.d.ts +22 -38
  530. package/dist/pipeline/handler-context-events.js +42 -35
  531. package/dist/pipeline/handler-context-member-resolution.d.ts +2 -0
  532. package/dist/pipeline/handler-context-member-resolution.js +110 -0
  533. package/dist/pipeline/handler-context-notify.d.ts +3 -2
  534. package/dist/pipeline/handler-context-notify.js +1 -1
  535. package/dist/pipeline/handler-context-observability.d.ts +2 -4
  536. package/dist/pipeline/handler-context-observability.js +7 -5
  537. package/dist/pipeline/handler-context-phase-denials.d.ts +11 -0
  538. package/dist/pipeline/handler-context-phase-denials.js +98 -0
  539. package/dist/pipeline/handler-context-scope.d.ts +7 -10
  540. package/dist/pipeline/handler-context-scope.js +18 -20
  541. package/dist/pipeline/index.d.ts +9 -21
  542. package/dist/pipeline/index.js +5 -7
  543. package/dist/pipeline/irreversible-operation-gate.d.ts +1 -1
  544. package/dist/pipeline/irreversible-operation-gate.js +2 -2
  545. package/dist/pipeline/lifecycle-pipeline.d.ts +8 -7
  546. package/dist/pipeline/lifecycle-pipeline.js +9 -15
  547. package/dist/pipeline/member-read-only-transaction.js +11 -3
  548. package/dist/pipeline/member-reader.d.ts +1 -1
  549. package/dist/pipeline/member-reader.js +2 -2
  550. package/dist/pipeline/msp-rebuild.js +5 -3
  551. package/dist/pipeline/multi-stream-apply-context.js +3 -2
  552. package/dist/pipeline/notify-scope.d.ts +2 -1
  553. package/dist/pipeline/pre-handler-gates.d.ts +2 -1
  554. package/dist/pipeline/pre-transaction-reservations.d.ts +3 -3
  555. package/dist/pipeline/pre-transaction-reservations.js +9 -7
  556. package/dist/pipeline/projection-rebuild.js +12 -5
  557. package/dist/pipeline/projection-state.d.ts +0 -6
  558. package/dist/pipeline/projection-state.js +0 -5
  559. package/dist/pipeline/projections-runner.d.ts +2 -1
  560. package/dist/pipeline/projections-runner.js +10 -6
  561. package/dist/pipeline/system-hooks.d.ts +6 -2
  562. package/dist/pipeline/system-hooks.js +61 -10
  563. package/dist/pipeline/system-identity-switch.d.ts +4 -2
  564. package/dist/pipeline/system-identity-switch.js +51 -36
  565. package/dist/pipeline/typed-append-event.d.ts +2 -0
  566. package/dist/pipeline/typed-append-event.js +4 -0
  567. package/dist/pipeline/write-origin.js +2 -2
  568. package/dist/pipeline/write-result-masking.d.ts +1 -1
  569. package/dist/pipeline/write-result-masking.js +13 -10
  570. package/dist/random/index.d.ts +1 -2
  571. package/dist/random/index.js +1 -2
  572. package/dist/rate-limit/bucket.d.ts +2 -1
  573. package/dist/rate-limit/middleware.js +2 -1
  574. package/dist/redis/index.d.ts +3 -4
  575. package/dist/redis/index.js +2 -2
  576. package/dist/schema-cli/apply-command.js +5 -2
  577. package/dist/schema-cli/baseline-command.js +7 -2
  578. package/dist/schema-cli/generate-command.js +7 -9
  579. package/dist/schema-cli/shared.d.ts +4 -0
  580. package/dist/schema-cli/shared.js +21 -2
  581. package/dist/schema-cli/status-command.js +8 -2
  582. package/dist/schema-cli/validate-command.js +52 -4
  583. package/dist/schema-cli.d.ts +0 -1
  584. package/dist/search/configure-tenant-index.d.ts +1 -3
  585. package/dist/search/configure-tenant-index.js +0 -4
  586. package/dist/search/index.d.ts +1 -4
  587. package/dist/search/index.js +0 -2
  588. package/dist/search/meilisearch-adapter-internals.d.ts +8 -0
  589. package/dist/search/meilisearch-adapter-internals.js +9 -0
  590. package/dist/search/meilisearch-adapter.d.ts +1 -8
  591. package/dist/search/meilisearch-adapter.js +6 -7
  592. package/dist/search/meilisearch-peer.d.ts +2 -0
  593. package/dist/search/meilisearch-peer.js +5 -0
  594. package/dist/search/reindex-entity.js +107 -91
  595. package/dist/secrets/index.d.ts +3 -4
  596. package/dist/secrets/index.js +2 -3
  597. package/dist/seeding/index.d.ts +2 -2
  598. package/dist/seeding/index.js +1 -2
  599. package/dist/time/index.d.ts +2 -2
  600. package/dist/time/index.js +1 -1
  601. package/dist/time/tz-context.d.ts +0 -5
  602. package/dist/time/tz-context.js +0 -9
  603. package/dist/ui-types/index.d.ts +8 -11
  604. package/dist/ui-types/index.js +3 -3
  605. package/dist/upgrade-changelog.d.ts +3 -0
  606. package/dist/upgrade-changelog.js +18 -0
  607. package/dist/upgrade-cli-internals.d.ts +8 -0
  608. package/dist/upgrade-cli-internals.js +63 -0
  609. package/dist/upgrade-cli.d.ts +1 -18
  610. package/dist/upgrade-cli.js +29 -137
  611. package/dist/upgrade-marker-parse.d.ts +32 -0
  612. package/dist/upgrade-marker-parse.js +73 -0
  613. package/dist/utils/import-optional-peer.d.ts +6 -0
  614. package/dist/utils/import-optional-peer.js +19 -0
  615. package/dist/utils/index.d.ts +1 -4
  616. package/dist/utils/index.js +1 -4
  617. package/package.json +27 -20
  618. package/src/changes.json +451 -0
  619. package/dist/crypto/request-kms-cache.d.ts +0 -8
  620. package/dist/crypto/request-kms-cache.js +0 -21
  621. package/dist/engine/codemod/index.d.ts +0 -2
  622. package/dist/engine/codemod/index.js +0 -1
  623. package/dist/engine/codemod/pipeline-codemod.d.ts +0 -50
  624. package/dist/engine/codemod/pipeline-codemod.js +0 -536
  625. package/dist/engine/feature-ast/entity-field-types.d.ts +0 -13
  626. package/dist/engine/feature-ast/entity-field-types.js +0 -35
  627. package/dist/engine/feature-ast/extractors/ai-steps.d.ts +0 -6
  628. package/dist/engine/feature-ast/extractors/ai-steps.js +0 -254
  629. package/dist/engine/feature-ast/extractors/events.d.ts +0 -5
  630. package/dist/engine/feature-ast/extractors/events.js +0 -275
  631. package/dist/engine/feature-ast/extractors/handlers.d.ts +0 -24
  632. package/dist/engine/feature-ast/extractors/handlers.js +0 -358
  633. package/dist/engine/feature-ast/extractors/hooks.d.ts +0 -24
  634. package/dist/engine/feature-ast/extractors/hooks.js +0 -248
  635. package/dist/engine/feature-ast/extractors/index.d.ts +0 -14
  636. package/dist/engine/feature-ast/extractors/index.js +0 -13
  637. package/dist/engine/feature-ast/extractors/jobs-routes.d.ts +0 -7
  638. package/dist/engine/feature-ast/extractors/jobs-routes.js +0 -145
  639. package/dist/engine/feature-ast/extractors/projections-screens.d.ts +0 -10
  640. package/dist/engine/feature-ast/extractors/projections-screens.js +0 -195
  641. package/dist/engine/feature-ast/extractors/resolve-import.d.ts +0 -21
  642. package/dist/engine/feature-ast/extractors/resolve-import.js +0 -180
  643. package/dist/engine/feature-ast/extractors/round1.d.ts +0 -10
  644. package/dist/engine/feature-ast/extractors/round1.js +0 -81
  645. package/dist/engine/feature-ast/extractors/round2.d.ts +0 -7
  646. package/dist/engine/feature-ast/extractors/round2.js +0 -191
  647. package/dist/engine/feature-ast/extractors/round3.d.ts +0 -23
  648. package/dist/engine/feature-ast/extractors/round3.js +0 -292
  649. package/dist/engine/feature-ast/extractors/round5.d.ts +0 -9
  650. package/dist/engine/feature-ast/extractors/round5.js +0 -68
  651. package/dist/engine/feature-ast/extractors/round6.d.ts +0 -4
  652. package/dist/engine/feature-ast/extractors/round6.js +0 -17
  653. package/dist/engine/feature-ast/extractors/shared.d.ts +0 -94
  654. package/dist/engine/feature-ast/extractors/shared.js +0 -343
  655. package/dist/engine/feature-ast/index.d.ts +0 -16
  656. package/dist/engine/feature-ast/index.js +0 -10
  657. package/dist/engine/feature-ast/parse.d.ts +0 -31
  658. package/dist/engine/feature-ast/parse.js +0 -483
  659. package/dist/engine/feature-ast/patch.d.ts +0 -210
  660. package/dist/engine/feature-ast/patch.js +0 -610
  661. package/dist/engine/feature-ast/patcher.d.ts +0 -217
  662. package/dist/engine/feature-ast/patcher.js +0 -281
  663. package/dist/engine/feature-ast/pattern-change-schema.d.ts +0 -1476
  664. package/dist/engine/feature-ast/pattern-change-schema.js +0 -1226
  665. package/dist/engine/feature-ast/pattern-id-matchers.d.ts +0 -7
  666. package/dist/engine/feature-ast/pattern-id-matchers.js +0 -210
  667. package/dist/engine/feature-ast/patterns.d.ts +0 -318
  668. package/dist/engine/feature-ast/patterns.js +0 -106
  669. package/dist/engine/feature-ast/render.d.ts +0 -47
  670. package/dist/engine/feature-ast/render.js +0 -662
  671. package/dist/engine/feature-ast/source-location.d.ts +0 -17
  672. package/dist/engine/feature-ast/source-location.js +0 -27
  673. package/dist/engine/pattern-library/index.d.ts +0 -2
  674. package/dist/engine/pattern-library/index.js +0 -3
  675. package/dist/engine/pattern-library/library.d.ts +0 -14
  676. package/dist/engine/pattern-library/library.js +0 -93
  677. package/dist/engine/pattern-library/mixed-schemas.d.ts +0 -16
  678. package/dist/engine/pattern-library/mixed-schemas.js +0 -559
  679. package/dist/engine/pattern-library/opaque-schemas.d.ts +0 -7
  680. package/dist/engine/pattern-library/opaque-schemas.js +0 -115
  681. package/dist/engine/pattern-library/shared-fields.d.ts +0 -122
  682. package/dist/engine/pattern-library/shared-fields.js +0 -88
  683. package/dist/engine/pattern-library/static-schemas.d.ts +0 -20
  684. package/dist/engine/pattern-library/static-schemas.js +0 -478
  685. package/dist/engine/pattern-library/types.d.ts +0 -158
  686. package/dist/engine/pattern-library/types.js +0 -36
  687. package/dist/engine/provider-plugin-context.d.ts +0 -3
  688. package/dist/engine/provider-plugin-context.js +0 -28
  689. package/dist/engine/resolve-config-or-param.d.ts +0 -18
  690. package/dist/engine/resolve-config-or-param.js +0 -76
  691. package/src/scripts/codemod/README.md +0 -187
  692. package/src/scripts/codemod/codemod-support.ts +0 -334
  693. package/src/scripts/codemod/collect-source-files.ts +0 -48
  694. package/src/scripts/codemod/crypto-shredding-testing-move.ts +0 -119
  695. package/src/scripts/codemod/db-factory.ts +0 -810
  696. package/src/scripts/codemod/feature-factory.ts +0 -429
  697. package/src/scripts/codemod/feature-layout.ts +0 -424
  698. package/src/scripts/codemod/import-extensions.ts +0 -118
  699. package/src/scripts/codemod/migrate-cross-tenant.ts +0 -328
  700. package/src/scripts/codemod/migrate-db-raw.ts +0 -401
  701. package/src/scripts/codemod/migrate-open-to-all.ts +0 -235
  702. package/src/scripts/codemod/object-form.ts +0 -746
  703. package/src/scripts/codemod/package-merge.ts +0 -299
  704. package/src/scripts/codemod/pii-personal-migration.ts +0 -816
  705. package/src/scripts/codemod/remove-engine-payload-casts.ts +0 -318
  706. package/src/scripts/codemod/s3-imports.ts +0 -236
  707. package/src/scripts/codemod/tenant-db-options.ts +0 -454
  708. package/src/scripts/codemod/testing-injection.ts +0 -215
  709. package/src/scripts/codemod/testing-move-targets.ts +0 -161
  710. package/src/scripts/codemod/testing-move.ts +0 -542
  711. package/src/scripts/codemod/unprocessable-error-details-reason.ts +0 -411
@@ -0,0 +1,136 @@
1
+ import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
2
+ import { referenceCell } from "./export-cells-reference.js";
3
+ const DATE_FORMAT = "yyyy-mm-dd";
4
+ const TIMESTAMP_FORMAT = "yyyy-mm-dd hh:mm";
5
+ const PLAIN_MONEY_FORMAT = "#,##0.00";
6
+ const ISO_DATE = /^\d{4}-\d{2}-\d{2}$/;
7
+ const CURRENCY_CODE = /^[A-Z]{3}$/;
8
+ function isNullish(value) {
9
+ return value === null || value === undefined;
10
+ }
11
+ function textCell(value) {
12
+ return { value, type: String };
13
+ }
14
+ function numberCell(value, format) {
15
+ return { value, type: Number, ...(format !== undefined && { format }) };
16
+ }
17
+ function toFiniteNumber(value) {
18
+ const n = typeof value === "number" ? value : typeof value === "string" ? Number(value) : NaN;
19
+ return value !== "" && Number.isFinite(n) ? n : undefined;
20
+ }
21
+ function stringify(value) {
22
+ if (typeof value === "string")
23
+ return value;
24
+ if (typeof value === "object" && value !== null) {
25
+ // Temporal values stringify to ISO via toString; plain data goes through JSON.
26
+ const text = String(value);
27
+ return text === "[object Object]" ? JSON.stringify(value) : text;
28
+ }
29
+ return String(value);
30
+ }
31
+ function fromEpochMillis(value) {
32
+ if (value instanceof Date)
33
+ return Number.isNaN(value.getTime()) ? undefined : value;
34
+ if (typeof value === "object" && value !== null && "epochMilliseconds" in value) {
35
+ return fromEpochMillis(new Date(Number(value.epochMilliseconds)));
36
+ }
37
+ if (typeof value === "string" || typeof value === "number") {
38
+ return fromEpochMillis(new Date(value));
39
+ }
40
+ return undefined;
41
+ }
42
+ // Date-only values are anchored at UTC midnight, never parsed through the local zone.
43
+ function toUtcDate(value) {
44
+ const text = typeof value === "string" ? value : isNullish(value) ? "" : stringify(value);
45
+ if (ISO_DATE.test(text))
46
+ return fromEpochMillis(new Date(`${text}T00:00:00Z`));
47
+ return undefined;
48
+ }
49
+ function dateCell(value) {
50
+ const date = toUtcDate(value) ?? fromEpochMillis(value);
51
+ return date === undefined
52
+ ? textCell(stringify(value))
53
+ : { value: date, type: Date, format: DATE_FORMAT };
54
+ }
55
+ // The sheet has no time zone, so the instant is shifted to the wall clock of `timeZone` and
56
+ // stored as if that wall clock were UTC.
57
+ function timestampCell(value, timeZone) {
58
+ const date = fromEpochMillis(value);
59
+ if (date === undefined)
60
+ return textCell(stringify(value));
61
+ const wall = Temporal.Instant.fromEpochMilliseconds(date.getTime()).toZonedDateTimeISO(timeZone);
62
+ const shifted = new Date(Date.UTC(wall.year, wall.month - 1, wall.day, wall.hour, wall.minute, wall.second));
63
+ return { value: shifted, type: Date, format: TIMESTAMP_FORMAT };
64
+ }
65
+ // `at` is the wall clock in the record's own zone without offset; reading it as UTC keeps the
66
+ // digits the user saw in the list.
67
+ function locatedTimestampCell(value) {
68
+ const at = typeof value === "object" && value !== null && "at" in value ? String(value.at) : undefined;
69
+ const date = at === undefined ? undefined : fromEpochMillis(new Date(`${at}Z`));
70
+ return date === undefined
71
+ ? textCell(stringify(value))
72
+ : { value: date, type: Date, format: TIMESTAMP_FORMAT };
73
+ }
74
+ function moneyCell(value) {
75
+ if (typeof value !== "object" || value === null || !("amount" in value)) {
76
+ const n = toFiniteNumber(value);
77
+ return n === undefined ? textCell(stringify(value)) : numberCell(n, PLAIN_MONEY_FORMAT);
78
+ }
79
+ const amount = toFiniteNumber(value.amount);
80
+ if (amount === undefined)
81
+ return textCell(stringify(value.amount));
82
+ const currency = "currency" in value ? String(value.currency) : "";
83
+ const format = CURRENCY_CODE.test(currency)
84
+ ? `${PLAIN_MONEY_FORMAT} "${currency}"`
85
+ : PLAIN_MONEY_FORMAT;
86
+ return numberCell(amount, format);
87
+ }
88
+ function integerCell(value, kind) {
89
+ const n = toFiniteNumber(value);
90
+ if (n === undefined)
91
+ return textCell(stringify(value));
92
+ // A bigInt beyond 2^53 would lose digits as a spreadsheet number.
93
+ if (kind === "bigInt" && !Number.isSafeInteger(n))
94
+ return textCell(stringify(value));
95
+ return numberCell(n);
96
+ }
97
+ function optionLabel(prefix, raw, translate) {
98
+ const text = String(raw);
99
+ const label = translate(`${prefix}${text}`);
100
+ return label === `${prefix}${text}` ? text : label;
101
+ }
102
+ function autoCell(value) {
103
+ if (typeof value === "number" && Number.isFinite(value))
104
+ return numberCell(value);
105
+ if (typeof value === "boolean")
106
+ return { value, type: Boolean };
107
+ return textCell(stringify(value));
108
+ }
109
+ function optionCell(cell, value, translate) {
110
+ const values = cell.kind === "multiSelect" && Array.isArray(value) ? value : [value];
111
+ return textCell(values.map((v) => optionLabel(cell.optionLabelKeyPrefix, v, translate)).join(", "));
112
+ }
113
+ const SIMPLE_CELL_BUILDERS = {
114
+ number: (value) => integerCell(value, "number"),
115
+ decimal: (value) => integerCell(value, "decimal"),
116
+ bigInt: (value) => integerCell(value, "bigInt"),
117
+ money: (value) => moneyCell(value),
118
+ date: (value) => dateCell(value),
119
+ timestamp: timestampCell,
120
+ locatedTimestamp: (value) => locatedTimestampCell(value),
121
+ boolean: (value) => typeof value === "boolean" ? { value, type: Boolean } : textCell(stringify(value)),
122
+ auto: (value) => autoCell(value),
123
+ text: (value) => textCell(stringify(value)),
124
+ };
125
+ /** Never emits a formula cell and never reinterprets strings: text always stays text. */
126
+ export function toExportCell(column, context) {
127
+ const { cell, field } = column;
128
+ const value = context.row[field];
129
+ if (isNullish(value))
130
+ return null;
131
+ if (cell.kind === "reference")
132
+ return referenceCell(cell, field, context.row);
133
+ if ("optionLabelKeyPrefix" in cell)
134
+ return optionCell(cell, value, context.translate);
135
+ return SIMPLE_CELL_BUILDERS[cell.kind](value, context.timeZone);
136
+ }
@@ -0,0 +1,2 @@
1
+ import type { SheetData } from "write-excel-file/node";
2
+ export declare function guardSheetAgainstCiphertext(sheet: SheetData, isProduction?: boolean): SheetData;
@@ -0,0 +1,27 @@
1
+ import { InternalError } from "../../errors/index.js";
2
+ import { createFallbackLogger } from "../../logging/utils.js";
3
+ import { CIPHERTEXT_RE, CIPHERTEXT_REDACT_RE, CIPHERTEXT_REDACTION } from "../pii-leak-guard.js";
4
+ const log = createFallbackLogger("kumiko:export-xlsx");
5
+ // The response guard only scans JSON, so a workbook needs its own check: a ciphertext in a cell
6
+ // means a raw DB read reached the export. Same policy as the guard: loud outside production,
7
+ // redacted and logged in production.
8
+ function guardText(text, isProduction) {
9
+ if (!CIPHERTEXT_RE.test(text))
10
+ return text;
11
+ const detail = "XLSX export contains a PII ciphertext — a raw DB read leaked into the sheet. " +
12
+ "Decrypt before returning (decryptStoredPii / executor read path).";
13
+ if (!isProduction)
14
+ throw new InternalError({ message: detail });
15
+ log.error(detail);
16
+ return text.replace(CIPHERTEXT_REDACT_RE, CIPHERTEXT_REDACTION);
17
+ }
18
+ function guardCell(cell, isProduction) {
19
+ if (typeof cell !== "object" || cell === null || !("value" in cell))
20
+ return cell;
21
+ if (typeof cell.value !== "string")
22
+ return cell;
23
+ return { ...cell, value: guardText(cell.value, isProduction) };
24
+ }
25
+ export function guardSheetAgainstCiphertext(sheet, isProduction = process.env["NODE_ENV"] === "production") {
26
+ return sheet.map((row) => row.map((cell) => guardCell(cell, isProduction)));
27
+ }
@@ -0,0 +1,31 @@
1
+ import type { EntityDefinition } from "@cosmicdrift/kumiko-types/fields";
2
+ import type { ListColumnSpec } from "@cosmicdrift/kumiko-types/screen";
3
+ import type { SessionUser } from "../../engine/types/index.ts";
4
+ import type { ReferenceCellKind } from "./export-cells-reference.ts";
5
+ export type SimpleCellKind = "text" | "number" | "decimal" | "bigInt" | "money" | "date" | "timestamp" | "locatedTimestamp" | "boolean" | "auto";
6
+ export type ExportCellKind = {
7
+ readonly kind: SimpleCellKind;
8
+ } | ReferenceCellKind | {
9
+ readonly kind: "select" | "multiSelect";
10
+ /** `<feature>:entity:<entity>:field:<field>:option:` — the option value is appended. */
11
+ readonly optionLabelKeyPrefix: string;
12
+ };
13
+ export type ExportColumn = {
14
+ readonly field: string;
15
+ readonly headerKey: string;
16
+ readonly headerFallback: string;
17
+ readonly cell: ExportCellKind;
18
+ };
19
+ export type ExportColumnSource = {
20
+ readonly featureName: string;
21
+ readonly columns: readonly ListColumnSpec[];
22
+ readonly entity: EntityDefinition | undefined;
23
+ readonly entityName: string | undefined;
24
+ readonly user: Pick<SessionUser, "roles">;
25
+ };
26
+ /**
27
+ * Resolves the requested column ids against the screen's declared columns, in client order.
28
+ * Virtual columns and, on an entityList, encrypted/sensitive fields are dropped without error:
29
+ * the zip response bypasses the PII-leak guard, so this is the only place that keeps them out.
30
+ */
31
+ export declare function resolveExportColumns(source: ExportColumnSource, requested: readonly string[]): ExportColumn[];
@@ -0,0 +1,85 @@
1
+ import { holdsCiphertextOrSecret } from "../../db/entity-field-encryption.js";
2
+ import { userMayReadFieldInBulk } from "../../engine/field-access.js";
3
+ import { normalizeListColumn } from "../../engine/screen-helpers.js";
4
+ import { exportRejection } from "./export-errors.js";
5
+ const PROJECTION_PSEUDO_ENTITY = "__projection__";
6
+ const FIELD_KIND_BY_TYPE = {
7
+ number: "number",
8
+ decimal: "decimal",
9
+ bigInt: "bigInt",
10
+ money: "money",
11
+ date: "date",
12
+ timestamp: "timestamp",
13
+ locatedTimestamp: "locatedTimestamp",
14
+ boolean: "boolean",
15
+ };
16
+ function fieldLabelKey(featureName, entityName, field) {
17
+ return `${featureName}:entity:${entityName}:field:${field}`;
18
+ }
19
+ function entityCellKind(source, entity, field) {
20
+ const def = entity.fields[field];
21
+ if (def?.type === "reference") {
22
+ return {
23
+ kind: "reference",
24
+ labelField: def.labelField ?? "id",
25
+ multiple: def.multiple === true,
26
+ };
27
+ }
28
+ const type = def?.type ?? "text";
29
+ if (type === "select" || type === "multiSelect") {
30
+ return {
31
+ kind: type,
32
+ optionLabelKeyPrefix: `${fieldLabelKey(source.featureName, source.entityName ?? "", field)}:option:`,
33
+ };
34
+ }
35
+ return { kind: FIELD_KIND_BY_TYPE[type] ?? "text" };
36
+ }
37
+ function projectionCellKind(valueType) {
38
+ if (valueType === "number" || valueType === "decimal" || valueType === "bigInt") {
39
+ return { kind: valueType };
40
+ }
41
+ return { kind: valueType === "money" ? "money" : "auto" };
42
+ }
43
+ function isExportableOnEntity(source, entity, field, virtual) {
44
+ if (virtual || !userMayReadFieldInBulk(entity, field, source.user))
45
+ return false;
46
+ return !holdsCiphertextOrSecret(entity, field);
47
+ }
48
+ /**
49
+ * Resolves the requested column ids against the screen's declared columns, in client order.
50
+ * Virtual columns and, on an entityList, encrypted/sensitive fields are dropped without error:
51
+ * the zip response bypasses the PII-leak guard, so this is the only place that keeps them out.
52
+ */
53
+ export function resolveExportColumns(source, requested) {
54
+ const declared = new Map(source.columns.map((spec) => normalizeListColumn(spec)).map((c) => [c.field, c]));
55
+ const seen = new Set();
56
+ const resolved = [];
57
+ for (const field of requested) {
58
+ const column = declared.get(field);
59
+ if (column === undefined) {
60
+ throw exportRejection("export_unknown_column", "columns", { column: field });
61
+ }
62
+ if (seen.has(field))
63
+ continue;
64
+ seen.add(field);
65
+ const virtual = column.virtual === true;
66
+ const { entity } = source;
67
+ if (entity !== undefined && !isExportableOnEntity(source, entity, field, virtual))
68
+ continue;
69
+ if (entity === undefined && virtual)
70
+ continue;
71
+ const cell = entity !== undefined
72
+ ? entityCellKind(source, entity, field)
73
+ : projectionCellKind(column.valueType);
74
+ const headerEntity = source.entityName ?? PROJECTION_PSEUDO_ENTITY;
75
+ resolved.push({
76
+ field,
77
+ headerKey: column.label ?? fieldLabelKey(source.featureName, headerEntity, field),
78
+ headerFallback: column.label ?? field,
79
+ cell,
80
+ });
81
+ }
82
+ if (resolved.length === 0)
83
+ throw exportRejection("export_no_columns", "columns");
84
+ return resolved;
85
+ }
@@ -0,0 +1,4 @@
1
+ import { ValidationError } from "../../errors/index.ts";
2
+ export declare const EXPORT_TOO_MANY_I18N_KEY = "kumiko.list.export-too-many";
3
+ export type ExportRejectReason = "export_invalid_request" | "export_unknown_screen" | "export_not_enabled" | "export_unknown_column" | "export_no_columns";
4
+ export declare function exportRejection(reason: ExportRejectReason, path: string, params?: Readonly<Record<string, unknown>>): ValidationError;
@@ -0,0 +1,14 @@
1
+ import { ValidationError } from "../../errors/index.js";
2
+ export const EXPORT_TOO_MANY_I18N_KEY = "kumiko.list.export-too-many";
3
+ export function exportRejection(reason, path, params) {
4
+ return new ValidationError({
5
+ fields: [
6
+ {
7
+ path,
8
+ code: reason,
9
+ i18nKey: `kumiko.list.${reason.replace(/_/g, "-")}`,
10
+ ...(params !== undefined && { params }),
11
+ },
12
+ ],
13
+ });
14
+ }
@@ -0,0 +1,4 @@
1
+ import { Hono } from "hono";
2
+ import type { Registry } from "../../engine/types/index.ts";
3
+ import type { Dispatcher } from "../../pipeline/dispatcher.ts";
4
+ export declare function createExportRoutes(dispatcher: Dispatcher, registry: Registry): Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
@@ -0,0 +1,75 @@
1
+ import { Hono } from "hono";
2
+ import * as z from "zod";
3
+ import { toKumikoError } from "../../errors/to-kumiko-error.js";
4
+ import { createI18n } from "../../i18n/index.js";
5
+ import { DEFAULT_LOCALE } from "../../i18n/request-locale.js";
6
+ import { isValidIanaTimeZone } from "../../time/index.js";
7
+ import { Routes } from "../api-constants.js";
8
+ import { getUser } from "../auth-middleware.js";
9
+ import { requestContext } from "../request-context.js";
10
+ import { assertPayloadDepthAllowed, queryErrorResponse } from "../routes.js";
11
+ import { EXPORT_TOO_MANY_I18N_KEY, exportRejection } from "./export-errors.js";
12
+ import { readExportRows } from "./export-rows.js";
13
+ import { resolveExportPlan } from "./export-screen.js";
14
+ import { writeExportWorkbook } from "./export-xlsx-writer.js";
15
+ const XLSX_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
16
+ const MAX_ID_LENGTH = 200;
17
+ const exportBodySchema = z.object({
18
+ screen: z.string().max(MAX_ID_LENGTH),
19
+ payload: z.record(z.string(), z.unknown()).default({}),
20
+ columns: z.array(z.string().max(MAX_ID_LENGTH)).min(1).max(MAX_ID_LENGTH),
21
+ timeZone: z.string().max(64).optional(),
22
+ });
23
+ // Browser zone first (what the user saw in the list), then the profile zone, else UTC.
24
+ function exportTimeZone(requested, profile) {
25
+ for (const candidate of [requested, profile]) {
26
+ if (candidate !== undefined && isValidIanaTimeZone(candidate))
27
+ return candidate;
28
+ }
29
+ return "UTC";
30
+ }
31
+ function downloadFileName(screenShortId, now) {
32
+ const safeId = screenShortId.replace(/[^A-Za-z0-9_-]/g, "_");
33
+ return `${safeId}-${now.toISOString().slice(0, 10)}.xlsx`;
34
+ }
35
+ export function createExportRoutes(dispatcher, registry) {
36
+ const api = new Hono();
37
+ const i18n = createI18n(registry, { defaultLocale: DEFAULT_LOCALE });
38
+ api.post(Routes.exportXlsx, async (c) => {
39
+ const user = getUser(c);
40
+ try {
41
+ const parsed = exportBodySchema.safeParse(await c.req.json().catch(() => undefined));
42
+ if (!parsed.success)
43
+ throw exportRejection("export_invalid_request", "body");
44
+ const body = parsed.data;
45
+ assertPayloadDepthAllowed(body.payload);
46
+ const plan = resolveExportPlan(registry, body.screen, body.columns, user);
47
+ const result = await readExportRows(dispatcher, plan, body.payload, user);
48
+ if (result.tooMany) {
49
+ return c.json({
50
+ error: {
51
+ code: "export_too_many_rows",
52
+ httpStatus: 413,
53
+ message: `export exceeds the limit of ${plan.maxRows} rows; narrow the filter`,
54
+ i18nKey: EXPORT_TOO_MANY_I18N_KEY,
55
+ details: { maxRows: plan.maxRows },
56
+ },
57
+ }, 413);
58
+ }
59
+ const locale = requestContext.get()?.locale ?? DEFAULT_LOCALE;
60
+ const bytes = await writeExportWorkbook(plan.columns, result.rows, (key) => i18n.t(key, locale), exportTimeZone(body.timeZone, user.timezone));
61
+ return new Response(bytes, {
62
+ status: 200,
63
+ headers: {
64
+ "Content-Type": XLSX_CONTENT_TYPE,
65
+ "Cache-Control": "no-store",
66
+ "Content-Disposition": `attachment; filename="${downloadFileName(plan.screenShortId, new Date())}"`,
67
+ },
68
+ });
69
+ }
70
+ catch (e) {
71
+ return queryErrorResponse(c, toKumikoError(e), Routes.exportXlsx);
72
+ }
73
+ });
74
+ return api;
75
+ }
@@ -0,0 +1,13 @@
1
+ import type { SessionUser } from "../../engine/types/index.ts";
2
+ import type { Dispatcher } from "../../pipeline/dispatcher.ts";
3
+ import type { ExportPlan } from "./export-screen.ts";
4
+ export type ExportRow = Readonly<Record<string, unknown>>;
5
+ export type ExportRowsResult = {
6
+ readonly tooMany: false;
7
+ readonly rows: readonly ExportRow[];
8
+ } | {
9
+ readonly tooMany: true;
10
+ };
11
+ export declare function sanitizeExportPayload(clientPayload: Readonly<Record<string, unknown>>, plan: Pick<ExportPlan, "screenFilter">): Record<string, unknown>;
12
+ /** Reads the whole filtered list page by page; gives up as soon as more than `maxRows` exist. */
13
+ export declare function readExportRows(dispatcher: Pick<Dispatcher, "query">, plan: ExportPlan, clientPayload: Readonly<Record<string, unknown>>, user: SessionUser): Promise<ExportRowsResult>;
@@ -0,0 +1,62 @@
1
+ import { MAX_LIST_LIMIT } from "../../engine/entity-handlers.js";
2
+ import { InternalError } from "../../errors/index.js";
3
+ import { isPlainObject } from "../../utils/is-plain-object.js";
4
+ // Paging, sizing and aggregation belong to the server here; `filter` is replaced from the screen
5
+ // below, so a client can neither widen the fixed screen filter nor smuggle another one in.
6
+ const CLIENT_CONTROLLED_PAGING_KEYS = [
7
+ "limit",
8
+ "offset",
9
+ "cursor",
10
+ "totalCount",
11
+ "aggregate",
12
+ "includeDeleted",
13
+ "filter",
14
+ ];
15
+ export function sanitizeExportPayload(clientPayload, plan) {
16
+ const payload = { ...clientPayload };
17
+ for (const key of CLIENT_CONTROLLED_PAGING_KEYS)
18
+ delete payload[key];
19
+ if (plan.screenFilter !== undefined)
20
+ payload["filter"] = plan.screenFilter;
21
+ return payload;
22
+ }
23
+ function parsePage(result, queryType) {
24
+ if (!isPlainObject(result) || !Array.isArray(result["rows"])) {
25
+ throw new InternalError({
26
+ message: `export: query ${queryType} did not return a { rows } envelope`,
27
+ });
28
+ }
29
+ const nextCursor = result["nextCursor"];
30
+ return {
31
+ rows: result["rows"].filter(isPlainObject),
32
+ nextCursor: typeof nextCursor === "string" && nextCursor !== "" ? nextCursor : undefined,
33
+ };
34
+ }
35
+ /** Reads the whole filtered list page by page; gives up as soon as more than `maxRows` exist. */
36
+ export async function readExportRows(dispatcher, plan, clientPayload, user) {
37
+ const base = sanitizeExportPayload(clientPayload, plan);
38
+ const rows = [];
39
+ const seenCursors = new Set();
40
+ let cursor;
41
+ for (;;) {
42
+ const limit = Math.min(MAX_LIST_LIMIT, plan.maxRows + 1 - rows.length);
43
+ const pagingPayload = cursor !== undefined
44
+ ? { ...base, limit, cursor }
45
+ : rows.length > 0
46
+ ? { ...base, limit, offset: rows.length }
47
+ : { ...base, limit };
48
+ const page = parsePage(await dispatcher.query(plan.queryType, pagingPayload, user), plan.queryType);
49
+ rows.push(...page.rows);
50
+ if (rows.length > plan.maxRows)
51
+ return { tooMany: true };
52
+ // A short or empty page is the end of the list; a repeated cursor would loop forever.
53
+ if (page.rows.length < limit || page.rows.length === 0)
54
+ return { tooMany: false, rows };
55
+ if (page.nextCursor !== undefined) {
56
+ if (seenCursors.has(page.nextCursor))
57
+ return { tooMany: false, rows };
58
+ seenCursors.add(page.nextCursor);
59
+ }
60
+ cursor = page.nextCursor;
61
+ }
62
+ }
@@ -0,0 +1,13 @@
1
+ import type { ScreenFilter } from "@cosmicdrift/kumiko-types/screen";
2
+ import type { Registry, SessionUser } from "../../engine/types/index.ts";
3
+ import { type ExportColumn } from "./export-columns.ts";
4
+ export type ExportPlan = {
5
+ readonly screenShortId: string;
6
+ readonly queryType: string;
7
+ readonly screenFilter: ScreenFilter | undefined;
8
+ readonly columns: readonly ExportColumn[];
9
+ readonly maxRows: number;
10
+ };
11
+ type ExportScreenRegistry = Pick<Registry, "getScreen" | "getScreenFeature" | "getEntity">;
12
+ export declare function resolveExportPlan(registry: ExportScreenRegistry, screenQn: string, requestedColumns: readonly string[], user: Pick<SessionUser, "roles">): ExportPlan;
13
+ export {};
@@ -0,0 +1,47 @@
1
+ import { hasAccess } from "../../engine/access.js";
2
+ import { toKebab } from "../../engine/qualified-name.js";
3
+ import { DEFAULT_EXPORT_MAX_ROWS } from "../../engine/types/screen.js";
4
+ import { AccessDeniedError } from "../../errors/index.js";
5
+ import { resolveExportColumns } from "./export-columns.js";
6
+ import { exportRejection } from "./export-errors.js";
7
+ const SCREEN_QN = /^[A-Za-z0-9_-]+:screen:[A-Za-z0-9_-]+$/;
8
+ function findExportScreen(registry, screenQn) {
9
+ // The client sends the feature name as authored (camelCase allowed); the registry keys are kebab.
10
+ const registryQn = toKebab(screenQn);
11
+ const screen = SCREEN_QN.test(screenQn) ? registry.getScreen(registryQn) : undefined;
12
+ if (screen === undefined || (screen.type !== "entityList" && screen.type !== "projectionList")) {
13
+ throw exportRejection("export_unknown_screen", "screen");
14
+ }
15
+ return { registryQn, screen };
16
+ }
17
+ export function resolveExportPlan(registry, screenQn, requestedColumns, user) {
18
+ const { registryQn, screen } = findExportScreen(registry, screenQn);
19
+ if (screen.table?.export?.xlsx !== true)
20
+ throw exportRejection("export_not_enabled", "screen");
21
+ if (screen.access !== undefined && !hasAccess(user, screen.access)) {
22
+ throw new AccessDeniedError({ details: { screen: screenQn } });
23
+ }
24
+ // Label keys use the feature name as authored, query types the kebab form.
25
+ const featureName = registry.getScreenFeature(registryQn) ?? "";
26
+ const screenShortId = registryQn.split(":")[2] ?? "";
27
+ const maxRows = screen.table.export.maxRows ?? DEFAULT_EXPORT_MAX_ROWS;
28
+ if (screen.type === "projectionList") {
29
+ return {
30
+ screenShortId,
31
+ queryType: screen.query,
32
+ screenFilter: screen.filter,
33
+ columns: resolveExportColumns({ featureName, columns: screen.columns, entity: undefined, entityName: undefined, user }, requestedColumns),
34
+ maxRows,
35
+ };
36
+ }
37
+ const entity = registry.getEntity(screen.entity);
38
+ if (entity === undefined)
39
+ throw exportRejection("export_unknown_screen", "screen");
40
+ return {
41
+ screenShortId,
42
+ queryType: `${toKebab(featureName)}:query:${toKebab(screen.entity)}:list`,
43
+ screenFilter: screen.filter,
44
+ columns: resolveExportColumns({ featureName, columns: screen.columns, entity, entityName: screen.entity, user }, requestedColumns),
45
+ maxRows,
46
+ };
47
+ }
@@ -0,0 +1,4 @@
1
+ import { type Translate } from "./export-cells.ts";
2
+ import type { ExportColumn } from "./export-columns.ts";
3
+ import type { ExportRow } from "./export-rows.ts";
4
+ export declare function writeExportWorkbook(columns: readonly ExportColumn[], rows: readonly ExportRow[], translate: Translate, timeZone: string): Promise<Uint8Array<ArrayBuffer>>;
@@ -0,0 +1,21 @@
1
+ import writeXlsxFile, {} from "write-excel-file/node";
2
+ import { toExportCell } from "./export-cells.js";
3
+ import { guardSheetAgainstCiphertext } from "./export-ciphertext-guard.js";
4
+ function headerLabel(column, translate) {
5
+ const translated = translate(column.headerKey);
6
+ return translated === column.headerKey ? column.headerFallback : translated;
7
+ }
8
+ export async function writeExportWorkbook(columns, rows, translate, timeZone) {
9
+ const header = columns.map((column) => ({
10
+ value: headerLabel(column, translate),
11
+ type: String,
12
+ fontWeight: "bold",
13
+ }));
14
+ const body = rows.map((row) => columns.map((column) => toExportCell(column, { row, translate, timeZone })));
15
+ const sheetData = guardSheetAgainstCiphertext([header, ...body]);
16
+ const buffer = await writeXlsxFile(sheetData, {}).toBuffer();
17
+ // Buffer is typed over ArrayBufferLike; a plain copy gives Response a BodyInit-compatible view.
18
+ const bytes = new Uint8Array(buffer.byteLength);
19
+ bytes.set(buffer);
20
+ return bytes;
21
+ }
@@ -1,5 +1,7 @@
1
+ import type { WriteResult } from "@cosmicdrift/kumiko-types/handlers";
2
+ import type { HttpRouteMethod } from "@cosmicdrift/kumiko-types/http-route";
1
3
  import type { Context, Hono } from "hono";
2
- import type { HttpRouteMethod, Registry, SessionUser, TenantId, WriteResult } from "../engine/types/index.ts";
4
+ import type { Registry, SessionUser, TenantId } from "../engine/types/index.ts";
3
5
  import type { SecretsContext } from "../secrets/index.ts";
4
6
  export declare const ExtraRouteEntries: {
5
7
  readonly anonymous: "anonymous";
@@ -70,6 +72,10 @@ export type SignatureExtraRouteDeps = {
70
72
  * caller's authenticity (signature, HMAC state, etc.). */
71
73
  readonly dispatchSystemWrite: (args: SystemDispatchArgs) => Promise<WriteResult>;
72
74
  readonly dispatchSystemQuery: (args: SystemDispatchArgs) => Promise<unknown>;
75
+ /** Same trust as dispatchSystemWrite, but runs as the tenant's system user
76
+ * with the "system" role plus exactly `roles` (no SystemAdmin), so the write
77
+ * passes app-role access checks. */
78
+ readonly dispatchWriteAs: (args: RoleDispatchArgs) => Promise<WriteResult>;
73
79
  };
74
80
  export type SignatureExtraRoute<TVerified> = {
75
81
  readonly method: HttpRouteMethod;
@@ -1,40 +1,36 @@
1
1
  export { DEFAULT_GLOBAL_RATE_LIMIT } from "../rate-limit/middleware.ts";
2
- export type { SetTenantCookieOptions } from "./anonymous-cookie.ts";
3
- export { deleteTenantCookie, setTenantCookie } from "./anonymous-cookie.ts";
2
+ export { setTenantCookie } from "./anonymous-cookie.ts";
4
3
  export { collectAnonymousLiveEntities } from "./anonymous-live-entities.ts";
5
4
  export { LOCALE_HEADER_NAME, NO_ROUTE_MATCH_HEADER_NAME } from "./api-constants.ts";
6
- export type { AnonymousAccessConfig, AnonymousAccessResolved, AuthMiddlewareOptions, AuthSessionChecker, AuthSessionCheckResult, AuthSessionStatus, TenantExists, TenantLifecycleStatusResolver, TenantResolver, TokenVerifier, } from "./auth-middleware.ts";
7
- export { authMiddleware, CSRF_HEADER_NAME, getUser, PAT_TOKEN_PREFIX, sessionCheckStatus, } from "./auth-middleware.ts";
5
+ export type { AnonymousAccessConfig, AnonymousAccessResolved, AuthSessionCheckResult, TokenVerifier, } from "./auth-middleware.ts";
6
+ export { CSRF_HEADER_NAME, PAT_TOKEN_PREFIX, } from "./auth-middleware.ts";
8
7
  export type { AuthRoutesConfig, LoginRateLimiter, SessionChecker, SessionCreator, SessionMassRevoker, SessionMetadata, SessionRevoker, } from "./auth-routes.ts";
9
- export { createAuthRoutes, createInMemoryLoginRateLimiter, createRedisLoginRateLimiter, } from "./auth-routes.ts";
10
- export type { ClientIpHeaderSource, ClientIpResolver } from "./client-ip.ts";
11
- export { assertValidTrustedProxyHops, clientIpSourceFromHonoContext, createClientIpResolver, extractSocketAddress, parseTrustedProxyHopsEnv, TRUSTED_PROXY_HOPS_ENV, UNKNOWN_CLIENT_IP, } from "./client-ip.ts";
12
- export type { AnonymousExtraRoute, AnonymousExtraRouteDeps, ExtraRouteDefinition, ExtraRouteEntry, ExtraRouteRejectionOptions, ExtraRouteRejectionStatus, RoleDispatchArgs, SignatureExtraRoute, SignatureExtraRouteDeps, SignatureExtraRouteVerifyDeps, SignatureExtraRouteVerifyRequest, SystemDispatchArgs, UserExtraRoute, UserExtraRouteDeps, } from "./extra-route.ts";
13
- export { ExtraRouteEntries, ExtraRouteRejection, signatureRoute } from "./extra-route.ts";
14
- export type { CachedResponseInit, CachePolicy } from "./http-cache.ts";
15
- export { cacheControlHeader, cachedResponse, computeRevisionEtag, computeStrongEtag, computeWeakEtag, etagMatches, parseIfNoneMatch, } from "./http-cache.ts";
16
- export type { JwtHelper, JwtKeyring, JwtPayload } from "./jwt.ts";
17
- export { createJwtHelper, loadJwtSecretOrKeyring } from "./jwt.ts";
8
+ export { createInMemoryLoginRateLimiter, createRedisLoginRateLimiter, } from "./auth-routes.ts";
9
+ export type { ClientIpResolver } from "./client-ip.ts";
10
+ export { createClientIpResolver, parseTrustedProxyHopsEnv, TRUSTED_PROXY_HOPS_ENV, UNKNOWN_CLIENT_IP, } from "./client-ip.ts";
11
+ export type { AnonymousExtraRoute, AnonymousExtraRouteDeps, ExtraRouteDefinition, RoleDispatchArgs, SignatureExtraRouteDeps, SignatureExtraRouteVerifyRequest, SystemDispatchArgs, UserExtraRouteDeps, } from "./extra-route.ts";
12
+ export { ExtraRouteRejection, signatureRoute } from "./extra-route.ts";
13
+ export type { CachePolicy } from "./http-cache.ts";
14
+ export { cacheControlHeader, cachedResponse, computeRevisionEtag, computeStrongEtag, computeWeakEtag, etagMatches, } from "./http-cache.ts";
15
+ export type { JwtHelper } from "./jwt.ts";
16
+ export { loadJwtSecretOrKeyring } from "./jwt.ts";
18
17
  export { publicOriginOf } from "./origin-middleware.ts";
19
- export { patAllows, qnMatches } from "./pat-scope.ts";
20
- export type { PostAuthLandingArgs, PostAuthLandingFlow, PostAuthLandingResolver, } from "./post-auth-landing.ts";
21
- export { isSafeLandingPath } from "./post-auth-landing.ts";
22
- export type { RedisSseBroker, RedisSseBrokerOptions } from "./redis-sse-broker.ts";
18
+ export type { PostAuthLandingArgs, PostAuthLandingResolver, } from "./post-auth-landing.ts";
19
+ export type { RedisSseBroker } from "./redis-sse-broker.ts";
23
20
  export { createDefaultSseBroker, createRedisSseBroker, isRedisSseBroker, } from "./redis-sse-broker.ts";
24
- export { type RequestContextData, readonlyRequestContext as requestContext, } from "./request-context.ts";
25
- export { buildRequestContextDataFromRequest, requestIdMiddleware, } from "./request-id-middleware.ts";
21
+ export { readonlyRequestContext as requestContext } from "./request-context-scopes.ts";
22
+ export { buildRequestContextDataFromRequest } from "./request-id-middleware.ts";
26
23
  export type { MetricsRouteOptions } from "./route-registrars.ts";
27
24
  export { createMetricsApp, DEFAULT_MAX_REQUEST_BYTES, isPrometheusMeter, } from "./route-registrars.ts";
28
- export { createApiRoutes } from "./routes.ts";
29
- export type { KumikoServer, ServerOptions } from "./server.ts";
25
+ export type { ServerOptions } from "./server.ts";
30
26
  export { buildServer } from "./server.ts";
27
+ export { resolveBaseDbAndSearchAdapter } from "./server-event-dispatcher.ts";
31
28
  export { makeDispatchSystemQuery, makeDispatchSystemWrite, makeDispatchWriteAs, } from "./server-extra-routes.ts";
32
29
  export { withFileProviderResolver } from "./server-wiring.ts";
33
- export type { ResolvedSessionCookies, SessionCookieBase, SessionCookieNames, } from "./session-cookies.ts";
34
- export { AUTH_COOKIE_BASE, CSRF_COOKIE_BASE, getSessionCookies, HOST_COOKIE_PREFIX, isHostPrefixedCookieName, resolveSessionCookieNames, resolveSessionCookies, sessionCookieName, sessionCookiesMiddleware, TENANT_COOKIE_BASE, } from "./session-cookies.ts";
35
- export type { SseBroker, SseClient, SseEvent } from "./sse-broker.ts";
30
+ export { AUTH_COOKIE_BASE, CSRF_COOKIE_BASE, getSessionCookies, sessionCookieName, } from "./session-cookies.ts";
31
+ export type { SseBroker, SseEvent } from "./sse-broker.ts";
36
32
  export { createSseBroker } from "./sse-broker.ts";
37
- export { createSseRoute, SSE_HEARTBEAT_INTERVAL_MS, type SseRouteOptions } from "./sse-route.ts";
33
+ export { SSE_HEARTBEAT_INTERVAL_MS } from "./sse-route.ts";
38
34
  export { generateToken } from "./tokens.ts";
39
- export type { KumikoServeEnv, KumikoServerWebSocket, KumikoWebSocketData, WebSocketUpgradeServer, } from "./websocket-route.ts";
40
- export { createKumikoWebSocketHandler, isWebSocketUpgradeRequest, kumikoWebSocketHandler, WEBSOCKET_BACKPRESSURE_LIMIT_BYTES, WEBSOCKET_DEFAULT_MAX_CONNECTIONS_PER_USER, WEBSOCKET_HEARTBEAT_INTERVAL_MS, WEBSOCKET_MAX_PAYLOAD_BYTES, WEBSOCKET_PENDING_BUFFER_LIMIT_BYTES, WEBSOCKET_REVALIDATION_FAILURE_LIMIT, WEBSOCKET_ROUTE_PATH_PREFIX, } from "./websocket-route.ts";
35
+ export type { KumikoServeEnv, KumikoWebSocketData, } from "./websocket-route.ts";
36
+ export { createKumikoWebSocketHandler, isWebSocketUpgradeRequest, WEBSOCKET_BACKPRESSURE_LIMIT_BYTES, WEBSOCKET_HEARTBEAT_INTERVAL_MS, WEBSOCKET_MAX_PAYLOAD_BYTES, WEBSOCKET_PENDING_BUFFER_LIMIT_BYTES, WEBSOCKET_ROUTE_PATH_PREFIX, } from "./websocket-route.ts";