@cosmicdrift/kumiko-framework 0.1.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 (388) hide show
  1. package/README.md +159 -0
  2. package/package.json +91 -0
  3. package/src/__tests__/anonymous-access.integration.ts +325 -0
  4. package/src/__tests__/error-contract.integration.ts +435 -0
  5. package/src/__tests__/field-access.integration.ts +269 -0
  6. package/src/__tests__/full-stack.integration.ts +914 -0
  7. package/src/__tests__/ownership.integration.ts +449 -0
  8. package/src/__tests__/reference-data.integration.ts +198 -0
  9. package/src/__tests__/transition-guard.integration.ts +340 -0
  10. package/src/api/__tests__/api.test.ts +337 -0
  11. package/src/api/__tests__/auth-middleware-transport.test.ts +80 -0
  12. package/src/api/__tests__/auth-routes-cookie.test.ts +179 -0
  13. package/src/api/__tests__/batch.integration.ts +404 -0
  14. package/src/api/__tests__/body-limit.test.ts +88 -0
  15. package/src/api/__tests__/csrf-middleware.test.ts +97 -0
  16. package/src/api/__tests__/dispatcher-live.integration.ts +216 -0
  17. package/src/api/__tests__/metrics-endpoint.test.ts +126 -0
  18. package/src/api/__tests__/nested-write.integration.ts +213 -0
  19. package/src/api/__tests__/readiness.test.ts +76 -0
  20. package/src/api/__tests__/request-id-middleware.test.ts +72 -0
  21. package/src/api/__tests__/sse-broker.test.ts +58 -0
  22. package/src/api/__tests__/sse-route.test.ts +112 -0
  23. package/src/api/anonymous-cookie.ts +60 -0
  24. package/src/api/api-constants.ts +64 -0
  25. package/src/api/auth-middleware.ts +418 -0
  26. package/src/api/auth-routes.ts +982 -0
  27. package/src/api/csrf-middleware.ts +77 -0
  28. package/src/api/index.ts +31 -0
  29. package/src/api/jwt.ts +66 -0
  30. package/src/api/observability-middleware.ts +89 -0
  31. package/src/api/readiness.ts +132 -0
  32. package/src/api/request-context.ts +49 -0
  33. package/src/api/request-id-middleware.ts +50 -0
  34. package/src/api/route-registrars.ts +195 -0
  35. package/src/api/routes.ts +135 -0
  36. package/src/api/server.ts +640 -0
  37. package/src/api/sse-broker.ts +71 -0
  38. package/src/api/sse-route.ts +62 -0
  39. package/src/api/tokens.ts +16 -0
  40. package/src/db/__tests__/apply-entity-event-tenant.integration.ts +159 -0
  41. package/src/db/__tests__/compound-types.test.ts +114 -0
  42. package/src/db/__tests__/connection-options.test.ts +68 -0
  43. package/src/db/__tests__/cursor.test.ts +41 -0
  44. package/src/db/__tests__/db-helpers.test.ts +369 -0
  45. package/src/db/__tests__/dialect-instant.test.ts +50 -0
  46. package/src/db/__tests__/drizzle-helpers.integration.ts +186 -0
  47. package/src/db/__tests__/drizzle-table-types.test.ts +162 -0
  48. package/src/db/__tests__/encryption.test.ts +39 -0
  49. package/src/db/__tests__/event-store-executor-list.integration.ts +313 -0
  50. package/src/db/__tests__/event-store-executor.integration.ts +235 -0
  51. package/src/db/__tests__/implicit-projection-equivalence.integration.ts +304 -0
  52. package/src/db/__tests__/located-timestamp.test.ts +184 -0
  53. package/src/db/__tests__/money.test.ts +199 -0
  54. package/src/db/__tests__/multi-row-insert.integration.ts +76 -0
  55. package/src/db/__tests__/parse-auto-verb.test.ts +70 -0
  56. package/src/db/__tests__/required-not-null-migration-safety.integration.ts +105 -0
  57. package/src/db/__tests__/row-helpers.test.ts +59 -0
  58. package/src/db/__tests__/schema-migration.integration.ts +273 -0
  59. package/src/db/__tests__/table-builder-indexes.test.ts +153 -0
  60. package/src/db/__tests__/table-builder-required.test.ts +216 -0
  61. package/src/db/__tests__/tenant-db.integration.ts +606 -0
  62. package/src/db/__tests__/unique-violation-mapping.integration.ts +166 -0
  63. package/src/db/apply-entity-event.ts +188 -0
  64. package/src/db/assert-exists-in.ts +59 -0
  65. package/src/db/compound-types.ts +47 -0
  66. package/src/db/connection.ts +104 -0
  67. package/src/db/cursor.ts +83 -0
  68. package/src/db/dialect.ts +109 -0
  69. package/src/db/eagerload.ts +174 -0
  70. package/src/db/encryption.ts +39 -0
  71. package/src/db/event-store-executor.ts +906 -0
  72. package/src/db/index.ts +55 -0
  73. package/src/db/located-timestamp.ts +114 -0
  74. package/src/db/money.ts +120 -0
  75. package/src/db/pg-error.ts +46 -0
  76. package/src/db/reference-data.ts +77 -0
  77. package/src/db/row-helpers.ts +53 -0
  78. package/src/db/schema-inspection.ts +25 -0
  79. package/src/db/table-builder.ts +475 -0
  80. package/src/db/tenant-db.ts +434 -0
  81. package/src/engine/__tests__/auth-claims-registrar.test.ts +74 -0
  82. package/src/engine/__tests__/boot-validator-located-timestamps.test.ts +108 -0
  83. package/src/engine/__tests__/boot-validator.test.ts +1865 -0
  84. package/src/engine/__tests__/build-app-schema.test.ts +154 -0
  85. package/src/engine/__tests__/claim-keys.test.ts +274 -0
  86. package/src/engine/__tests__/config-helpers.test.ts +236 -0
  87. package/src/engine/__tests__/effective-features.test.ts +86 -0
  88. package/src/engine/__tests__/engine.test.ts +1461 -0
  89. package/src/engine/__tests__/entity-handlers.test.ts +274 -0
  90. package/src/engine/__tests__/event-helpers.test.ts +68 -0
  91. package/src/engine/__tests__/extends-registrar.test.ts +159 -0
  92. package/src/engine/__tests__/factories-long-text.test.ts +84 -0
  93. package/src/engine/__tests__/factories-time.test.ts +158 -0
  94. package/src/engine/__tests__/field-predicates.test.ts +48 -0
  95. package/src/engine/__tests__/hook-phases.test.ts +132 -0
  96. package/src/engine/__tests__/identifiers.test.ts +35 -0
  97. package/src/engine/__tests__/lifecycle-hooks.test.ts +237 -0
  98. package/src/engine/__tests__/nav.test.ts +267 -0
  99. package/src/engine/__tests__/ownership.test.ts +421 -0
  100. package/src/engine/__tests__/parse-ref-target.test.ts +43 -0
  101. package/src/engine/__tests__/projection-helpers.test.ts +62 -0
  102. package/src/engine/__tests__/projection.test.ts +191 -0
  103. package/src/engine/__tests__/qualified-name.test.ts +264 -0
  104. package/src/engine/__tests__/resolve-config-or-param.test.ts +315 -0
  105. package/src/engine/__tests__/run-in.test.ts +38 -0
  106. package/src/engine/__tests__/schema-builder.test.ts +380 -0
  107. package/src/engine/__tests__/screen.test.ts +408 -0
  108. package/src/engine/__tests__/state-machine.test.ts +148 -0
  109. package/src/engine/__tests__/system-user.test.ts +57 -0
  110. package/src/engine/__tests__/validation-hooks.test.ts +71 -0
  111. package/src/engine/access.ts +23 -0
  112. package/src/engine/boot-validator.ts +1528 -0
  113. package/src/engine/build-app-schema.ts +125 -0
  114. package/src/engine/config-helpers.ts +115 -0
  115. package/src/engine/constants.ts +85 -0
  116. package/src/engine/create-app.ts +98 -0
  117. package/src/engine/define-feature.ts +702 -0
  118. package/src/engine/define-handler.ts +78 -0
  119. package/src/engine/define-roles.ts +19 -0
  120. package/src/engine/effective-features.ts +87 -0
  121. package/src/engine/entity-handlers.ts +364 -0
  122. package/src/engine/event-helpers.ts +73 -0
  123. package/src/engine/factories.ts +328 -0
  124. package/src/engine/feature-ast/__tests__/canonical-form.test.ts +416 -0
  125. package/src/engine/feature-ast/__tests__/parse-happy-path.test.ts +197 -0
  126. package/src/engine/feature-ast/__tests__/parse-real-features.test.ts +128 -0
  127. package/src/engine/feature-ast/__tests__/parse.test.ts +888 -0
  128. package/src/engine/feature-ast/__tests__/patch.test.ts +360 -0
  129. package/src/engine/feature-ast/__tests__/patcher.test.ts +469 -0
  130. package/src/engine/feature-ast/__tests__/render-roundtrip.test.ts +287 -0
  131. package/src/engine/feature-ast/extractors.ts +2562 -0
  132. package/src/engine/feature-ast/index.ts +105 -0
  133. package/src/engine/feature-ast/parse.ts +369 -0
  134. package/src/engine/feature-ast/patch.ts +525 -0
  135. package/src/engine/feature-ast/patcher.ts +518 -0
  136. package/src/engine/feature-ast/patterns.ts +434 -0
  137. package/src/engine/feature-ast/render.ts +602 -0
  138. package/src/engine/feature-ast/source-location.ts +45 -0
  139. package/src/engine/field-access.ts +120 -0
  140. package/src/engine/index.ts +254 -0
  141. package/src/engine/ownership.ts +337 -0
  142. package/src/engine/parse-ref-target.ts +22 -0
  143. package/src/engine/pattern-library/__tests__/library.test.ts +351 -0
  144. package/src/engine/pattern-library/index.ts +24 -0
  145. package/src/engine/pattern-library/library.ts +1117 -0
  146. package/src/engine/pattern-library/types.ts +255 -0
  147. package/src/engine/projection-helpers.ts +85 -0
  148. package/src/engine/qualified-name.ts +122 -0
  149. package/src/engine/read-claim.ts +31 -0
  150. package/src/engine/registry.ts +1325 -0
  151. package/src/engine/resolve-config-or-param.ts +153 -0
  152. package/src/engine/run-in.ts +29 -0
  153. package/src/engine/schema-builder.ts +175 -0
  154. package/src/engine/screen-filter-ops.ts +51 -0
  155. package/src/engine/state-machine.ts +70 -0
  156. package/src/engine/system-user.ts +32 -0
  157. package/src/engine/types/config.ts +306 -0
  158. package/src/engine/types/event-type-map.ts +37 -0
  159. package/src/engine/types/feature.ts +574 -0
  160. package/src/engine/types/fields.ts +422 -0
  161. package/src/engine/types/handlers.ts +742 -0
  162. package/src/engine/types/hooks.ts +142 -0
  163. package/src/engine/types/http-route.ts +54 -0
  164. package/src/engine/types/identifiers.ts +47 -0
  165. package/src/engine/types/index.ts +208 -0
  166. package/src/engine/types/nav.ts +46 -0
  167. package/src/engine/types/projection.ts +132 -0
  168. package/src/engine/types/relations.ts +51 -0
  169. package/src/engine/types/screen.ts +452 -0
  170. package/src/engine/types/workspace.ts +42 -0
  171. package/src/engine/validation.ts +33 -0
  172. package/src/entrypoint/__tests__/entrypoint-job-wiring.integration.ts +173 -0
  173. package/src/entrypoint/__tests__/split-deploy.integration.ts +297 -0
  174. package/src/entrypoint/index.ts +442 -0
  175. package/src/errors/__tests__/classes.test.ts +371 -0
  176. package/src/errors/__tests__/write-failures.test.ts +109 -0
  177. package/src/errors/classes.ts +249 -0
  178. package/src/errors/i18n/de.yaml +83 -0
  179. package/src/errors/i18n/en.yaml +80 -0
  180. package/src/errors/index.ts +41 -0
  181. package/src/errors/kumiko-error.ts +67 -0
  182. package/src/errors/reasons.ts +36 -0
  183. package/src/errors/serialize.ts +136 -0
  184. package/src/errors/transition-details.ts +30 -0
  185. package/src/errors/write-error-info.ts +123 -0
  186. package/src/errors/zod-bridge.ts +49 -0
  187. package/src/event-store/__tests__/admin-api.integration.ts +361 -0
  188. package/src/event-store/__tests__/event-store.integration.ts +584 -0
  189. package/src/event-store/__tests__/get-stream-version-perf.integration.ts +83 -0
  190. package/src/event-store/__tests__/perf.integration.ts +255 -0
  191. package/src/event-store/__tests__/snapshot.integration.ts +267 -0
  192. package/src/event-store/__tests__/upcaster-dead-letter.integration.ts +204 -0
  193. package/src/event-store/__tests__/upcaster.integration.ts +460 -0
  194. package/src/event-store/admin-api.ts +257 -0
  195. package/src/event-store/archive.ts +106 -0
  196. package/src/event-store/errors.ts +35 -0
  197. package/src/event-store/event-store.ts +405 -0
  198. package/src/event-store/events-schema.ts +90 -0
  199. package/src/event-store/index.ts +50 -0
  200. package/src/event-store/snapshot.ts +210 -0
  201. package/src/event-store/upcaster-dead-letter.ts +119 -0
  202. package/src/event-store/upcaster.ts +147 -0
  203. package/src/files/__tests__/content-disposition.test.ts +123 -0
  204. package/src/files/__tests__/file-field-column.integration.ts +103 -0
  205. package/src/files/__tests__/file-field-pipeline.integration.ts +211 -0
  206. package/src/files/__tests__/file-handle.test.ts +122 -0
  207. package/src/files/__tests__/files.integration.ts +830 -0
  208. package/src/files/__tests__/storage-tracking.integration.ts +153 -0
  209. package/src/files/content-disposition.ts +55 -0
  210. package/src/files/file-handle.ts +63 -0
  211. package/src/files/file-ref-table.ts +22 -0
  212. package/src/files/file-routes.ts +353 -0
  213. package/src/files/in-memory-provider.ts +62 -0
  214. package/src/files/index.ts +29 -0
  215. package/src/files/local-provider.ts +35 -0
  216. package/src/files/storage-tracking.ts +60 -0
  217. package/src/files/types.ts +118 -0
  218. package/src/i18n/__tests__/i18n.test.ts +72 -0
  219. package/src/i18n/index.ts +29 -0
  220. package/src/jobs/__tests__/job-event-trigger.integration.ts +172 -0
  221. package/src/jobs/__tests__/job-multi-trigger.integration.ts +144 -0
  222. package/src/jobs/__tests__/jobs.integration.ts +566 -0
  223. package/src/jobs/index.ts +2 -0
  224. package/src/jobs/job-runner.ts +574 -0
  225. package/src/lifecycle/__tests__/create-test-lifecycle.ts +19 -0
  226. package/src/lifecycle/__tests__/lifecycle-server.integration.ts +108 -0
  227. package/src/lifecycle/__tests__/lifecycle.test.ts +212 -0
  228. package/src/lifecycle/__tests__/signal-handlers.test.ts +106 -0
  229. package/src/lifecycle/index.ts +13 -0
  230. package/src/lifecycle/lifecycle.ts +160 -0
  231. package/src/lifecycle/signal-handlers.ts +62 -0
  232. package/src/logging/__tests__/pino-trace-bridge.test.ts +50 -0
  233. package/src/logging/index.ts +3 -0
  234. package/src/logging/pino-logger.ts +64 -0
  235. package/src/logging/types.ts +7 -0
  236. package/src/migrations/__tests__/compare-snapshots.test.ts +150 -0
  237. package/src/migrations/__tests__/detect-drift.integration.ts +320 -0
  238. package/src/migrations/__tests__/detect-projections-to-rebuild.integration.ts +134 -0
  239. package/src/migrations/__tests__/rebuild-marker.test.ts +79 -0
  240. package/src/migrations/index.ts +28 -0
  241. package/src/migrations/projection-detection.ts +149 -0
  242. package/src/migrations/rebuild-marker.ts +64 -0
  243. package/src/migrations/schema-drift.ts +395 -0
  244. package/src/observability/__tests__/console-provider.test.ts +67 -0
  245. package/src/observability/__tests__/metric-validator.test.ts +87 -0
  246. package/src/observability/__tests__/noop-provider.test.ts +82 -0
  247. package/src/observability/__tests__/observability.integration.ts +559 -0
  248. package/src/observability/__tests__/prometheus-meter.test.ts +144 -0
  249. package/src/observability/__tests__/recording-meter.test.ts +101 -0
  250. package/src/observability/__tests__/recording-tracer.test.ts +110 -0
  251. package/src/observability/__tests__/sensitive-filter.test.ts +98 -0
  252. package/src/observability/console-provider.ts +130 -0
  253. package/src/observability/context.ts +26 -0
  254. package/src/observability/fallback.ts +34 -0
  255. package/src/observability/ids.ts +25 -0
  256. package/src/observability/index.ts +79 -0
  257. package/src/observability/metric-validator.ts +86 -0
  258. package/src/observability/metrics-handle.ts +56 -0
  259. package/src/observability/noop-provider.ts +146 -0
  260. package/src/observability/prometheus-meter.ts +284 -0
  261. package/src/observability/recording-meter.ts +156 -0
  262. package/src/observability/recording-tracer.ts +198 -0
  263. package/src/observability/redis-wrapper.ts +132 -0
  264. package/src/observability/sensitive-filter.ts +108 -0
  265. package/src/observability/standard-metrics.ts +213 -0
  266. package/src/observability/types/index.ts +29 -0
  267. package/src/observability/types/metric.ts +56 -0
  268. package/src/observability/types/provider.ts +32 -0
  269. package/src/observability/types/span.ts +64 -0
  270. package/src/pipeline/__tests__/archive-stream.integration.ts +220 -0
  271. package/src/pipeline/__tests__/auth-claims-resolver.test.ts +279 -0
  272. package/src/pipeline/__tests__/cascade-handler.integration.ts +419 -0
  273. package/src/pipeline/__tests__/cascade-handler.test.ts +52 -0
  274. package/src/pipeline/__tests__/causation-chain.integration.ts +206 -0
  275. package/src/pipeline/__tests__/ctx-bridge.integration.ts +234 -0
  276. package/src/pipeline/__tests__/dispatcher.test.ts +379 -0
  277. package/src/pipeline/__tests__/distributed-lock.integration.ts +67 -0
  278. package/src/pipeline/__tests__/domain-events-projections.integration.ts +323 -0
  279. package/src/pipeline/__tests__/event-dedup.integration.ts +153 -0
  280. package/src/pipeline/__tests__/event-define-event-strict.integration.ts +202 -0
  281. package/src/pipeline/__tests__/event-dispatcher-lifecycle.integration.ts +220 -0
  282. package/src/pipeline/__tests__/event-dispatcher-multi-instance.integration.ts +423 -0
  283. package/src/pipeline/__tests__/event-dispatcher-pg-listen.integration.ts +123 -0
  284. package/src/pipeline/__tests__/event-dispatcher-recovery.integration.ts +202 -0
  285. package/src/pipeline/__tests__/event-dispatcher-second-audit.integration.ts +290 -0
  286. package/src/pipeline/__tests__/event-dispatcher-strict.test.ts +65 -0
  287. package/src/pipeline/__tests__/event-dispatcher.integration.ts +287 -0
  288. package/src/pipeline/__tests__/event-retention.integration.ts +239 -0
  289. package/src/pipeline/__tests__/fetch-for-writing.integration.ts +281 -0
  290. package/src/pipeline/__tests__/lifecycle-pipeline.test.ts +430 -0
  291. package/src/pipeline/__tests__/load-aggregate-query.integration.ts +266 -0
  292. package/src/pipeline/__tests__/msp-error-mode.integration.ts +149 -0
  293. package/src/pipeline/__tests__/msp-multi-hop.integration.ts +228 -0
  294. package/src/pipeline/__tests__/msp-rebuild.integration.ts +368 -0
  295. package/src/pipeline/__tests__/multi-stream-projection.integration.ts +341 -0
  296. package/src/pipeline/__tests__/perf-rebuild.integration.ts +147 -0
  297. package/src/pipeline/__tests__/projection-rebuild.integration.ts +551 -0
  298. package/src/pipeline/__tests__/query-projection.integration.ts +201 -0
  299. package/src/pipeline/__tests__/redis-pipeline.integration.ts +306 -0
  300. package/src/pipeline/append-event-core.ts +117 -0
  301. package/src/pipeline/auth-claims-resolver.ts +103 -0
  302. package/src/pipeline/cascade-handler.ts +113 -0
  303. package/src/pipeline/dispatcher.ts +1585 -0
  304. package/src/pipeline/distributed-lock.ts +37 -0
  305. package/src/pipeline/entity-cache.ts +113 -0
  306. package/src/pipeline/event-consumer-state.ts +108 -0
  307. package/src/pipeline/event-dedup.ts +23 -0
  308. package/src/pipeline/event-dispatcher.ts +1016 -0
  309. package/src/pipeline/event-retention.ts +154 -0
  310. package/src/pipeline/idempotency.ts +76 -0
  311. package/src/pipeline/index.ts +66 -0
  312. package/src/pipeline/lifecycle-pipeline.ts +409 -0
  313. package/src/pipeline/msp-rebuild.ts +242 -0
  314. package/src/pipeline/multi-stream-apply-context.ts +115 -0
  315. package/src/pipeline/projection-rebuild.ts +334 -0
  316. package/src/pipeline/projection-state.ts +72 -0
  317. package/src/pipeline/projections-runner.ts +56 -0
  318. package/src/pipeline/redis-keys.ts +11 -0
  319. package/src/pipeline/system-hooks.ts +190 -0
  320. package/src/random/__tests__/generate.test.ts +149 -0
  321. package/src/random/generate.ts +141 -0
  322. package/src/random/index.ts +8 -0
  323. package/src/random/words.ts +392 -0
  324. package/src/rate-limit/__tests__/dispatcher-l3.integration.ts +111 -0
  325. package/src/rate-limit/__tests__/middleware.integration.ts +189 -0
  326. package/src/rate-limit/__tests__/resolver.integration.ts +189 -0
  327. package/src/rate-limit/bucket.ts +36 -0
  328. package/src/rate-limit/index.ts +14 -0
  329. package/src/rate-limit/middleware.ts +152 -0
  330. package/src/rate-limit/resolver.ts +267 -0
  331. package/src/redis/__tests__/redis-options.test.ts +54 -0
  332. package/src/redis/index.ts +74 -0
  333. package/src/search/__tests__/meilisearch-adapter.integration.ts +236 -0
  334. package/src/search/__tests__/search-adapter.test.ts +256 -0
  335. package/src/search/in-memory-adapter.ts +123 -0
  336. package/src/search/index.ts +12 -0
  337. package/src/search/meilisearch-adapter.ts +106 -0
  338. package/src/search/types.ts +39 -0
  339. package/src/secrets/__tests__/dek-cache.test.ts +213 -0
  340. package/src/secrets/__tests__/env-master-key-provider.test.ts +119 -0
  341. package/src/secrets/__tests__/envelope.test.ts +74 -0
  342. package/src/secrets/__tests__/leak-guard.test.ts +92 -0
  343. package/src/secrets/__tests__/rotation.test.ts +149 -0
  344. package/src/secrets/dek-cache.ts +116 -0
  345. package/src/secrets/env-master-key-provider.ts +162 -0
  346. package/src/secrets/envelope.ts +55 -0
  347. package/src/secrets/index.ts +19 -0
  348. package/src/secrets/leak-guard.ts +87 -0
  349. package/src/secrets/rotation.ts +34 -0
  350. package/src/secrets/types.ts +107 -0
  351. package/src/stack/db.ts +104 -0
  352. package/src/stack/event-collector.ts +23 -0
  353. package/src/stack/index.ts +32 -0
  354. package/src/stack/redis.ts +44 -0
  355. package/src/stack/request-helper.ts +168 -0
  356. package/src/stack/table-helpers.ts +104 -0
  357. package/src/stack/test-stack.ts +357 -0
  358. package/src/stack/test-users.ts +37 -0
  359. package/src/testing/__tests__/e2e-generator.test.ts +230 -0
  360. package/src/testing/__tests__/ensure-entity-table.integration.ts +54 -0
  361. package/src/testing/access-assertions.ts +15 -0
  362. package/src/testing/assertions.ts +35 -0
  363. package/src/testing/e2e-generator.ts +465 -0
  364. package/src/testing/expect-error.ts +25 -0
  365. package/src/testing/handler-context.ts +125 -0
  366. package/src/testing/http-cookies.ts +52 -0
  367. package/src/testing/index.ts +41 -0
  368. package/src/testing/late-bound.ts +39 -0
  369. package/src/testing/mutable-master-key-provider.ts +31 -0
  370. package/src/testing/observability-recorder.ts +54 -0
  371. package/src/testing/shared-entities.ts +49 -0
  372. package/src/testing/utils.ts +1 -0
  373. package/src/testing/wait-for.ts +31 -0
  374. package/src/time/__tests__/polyfill.test.ts +73 -0
  375. package/src/time/__tests__/tz-context.test.ts +121 -0
  376. package/src/time/index.ts +21 -0
  377. package/src/time/polyfill.ts +70 -0
  378. package/src/time/tz-context.ts +107 -0
  379. package/src/ui-types/app-schema.ts +57 -0
  380. package/src/ui-types/index.ts +65 -0
  381. package/src/utils/__tests__/assert.test.ts +17 -0
  382. package/src/utils/__tests__/env-parse.test.ts +54 -0
  383. package/src/utils/assert.ts +18 -0
  384. package/src/utils/env-parse.ts +16 -0
  385. package/src/utils/ids.ts +16 -0
  386. package/src/utils/index.ts +5 -0
  387. package/src/utils/safe-json.ts +30 -0
  388. package/src/utils/serialization.ts +7 -0
@@ -0,0 +1,405 @@
1
+ import { and, asc, eq, gt, lte, max, sql } from "drizzle-orm";
2
+ import type { DbRunner } from "../db";
3
+ import { isUniqueViolation } from "../db/pg-error";
4
+ import type { TenantId } from "../engine/types";
5
+ import { isStreamArchived } from "./archive";
6
+ import { VersionConflictError } from "./errors";
7
+ import { eventsTable } from "./events-schema";
8
+
9
+ export type EventMetadata = {
10
+ readonly userId: string;
11
+ readonly requestId?: string;
12
+ // End-to-end business-operation id. Root HTTP requests get it from the
13
+ // x-correlation-id header (default: requestId). MSP-applies inherit it
14
+ // from the triggering event. Lets you trace "which user click caused
15
+ // this email 3 streams later?".
16
+ readonly correlationId?: string;
17
+ // Stored event id that triggered this write. Null for root commands;
18
+ // set to event.id when an MSP-apply runs ctx.appendEvent. Together with
19
+ // correlationId forms a causation DAG across aggregate streams.
20
+ readonly causationId?: string;
21
+ // Marten-conform free key/value space for app-specific metadata that
22
+ // doesn't deserve its own EventMetadata field. Examples: A/B-test bucket,
23
+ // feature-flag snapshot, geo-region, client SDK version. Persisted into
24
+ // events.metadata jsonb (no schema change — it's already a free-form
25
+ // jsonb column), survives upcasters untouched, available on every
26
+ // StoredEvent.metadata.headers. Framework does not interpret values; the
27
+ // app reads them when filtering/auditing. Keep values JSON-primitive
28
+ // (string|number|boolean) so JSON serialization stays bulletproof.
29
+ readonly headers?: Readonly<Record<string, string | number | boolean>>;
30
+ };
31
+
32
+ export type EventToAppend = {
33
+ readonly aggregateId: string;
34
+ readonly aggregateType: string;
35
+ readonly tenantId: TenantId;
36
+ // Predecessor version. 0 for a brand-new aggregate — framework writes version 1.
37
+ readonly expectedVersion: number;
38
+ readonly type: string;
39
+ readonly eventVersion?: number;
40
+ readonly payload: Record<string, unknown>;
41
+ readonly metadata: EventMetadata;
42
+ };
43
+
44
+ // Generic über payload-shape. Default = Record<string, unknown> macht
45
+ // alle existierenden Konsumenten backwards-compatible. Konkrete Apply-
46
+ // Handler / Tests können `StoredEvent<MyEventPayload>` annotieren um
47
+ // payload typed zu lesen. Type-Propagation kommt durch r.defineEvent +
48
+ // SingleStreamApplyFn<T> in apply-Maps.
49
+ export type StoredEvent<TPayload = Record<string, unknown>> = {
50
+ readonly id: string;
51
+ readonly aggregateId: string;
52
+ readonly aggregateType: string;
53
+ readonly tenantId: TenantId;
54
+ readonly version: number;
55
+ readonly type: string;
56
+ readonly eventVersion: number;
57
+ readonly payload: TPayload;
58
+ readonly metadata: EventMetadata;
59
+ readonly createdAt: Temporal.Instant;
60
+ readonly createdBy: string;
61
+ };
62
+
63
+ type SelectedEvent = typeof eventsTable.$inferSelect;
64
+
65
+ // Append one event atomically. Two guarantees combined:
66
+ //
67
+ // 1. UNIQUE (tenant_id, aggregate_id, version) serializes concurrent writers
68
+ // within a tenant — a second writer racing the same expectedVersion
69
+ // receives a PG unique violation (SQLSTATE 23505) → VersionConflictError.
70
+ // Cross-tenant aggregate_id collisions are not conflicts by definition:
71
+ // two tenants owning a row with the same UUID is just isolation, not a
72
+ // race.
73
+ //
74
+ // 2. For updates (expectedVersion > 0), INSERT … SELECT … WHERE EXISTS
75
+ // requires the predecessor event to exist within the same tenant — i.e.
76
+ // "you can't append v6 to a stream whose v5 was never written." The
77
+ // tenant filter inside the EXISTS is belt-and-suspenders now that the
78
+ // unique index carries tenant_id; we keep it so the predecessor check
79
+ // stays semantically obvious when read in isolation.
80
+ //
81
+ // Creates (expectedVersion === 0) skip the predecessor check — no predecessor
82
+ // exists yet. Colliding creates fall out via UNIQUE (tenant_id, aggregate_id, version=1).
83
+ // Channel name used by append() → NOTIFY and the event-dispatcher → LISTEN
84
+ // (Sprint E.4). The event-dispatcher subscribes to this channel on start and
85
+ // fires a runOnce immediately on each commit, so delivery latency is bounded
86
+ // by TCP round-trip instead of pollIntervalMs.
87
+ export const EVENTS_PUBSUB_CHANNEL = "kumiko_events_new";
88
+
89
+ export async function append(db: DbRunner, event: EventToAppend): Promise<StoredEvent> {
90
+ const newVersion = event.expectedVersion + 1;
91
+ const eventVersion = event.eventVersion ?? 1;
92
+
93
+ try {
94
+ const row =
95
+ event.expectedVersion === 0
96
+ ? await insertFirstEvent(db, event, newVersion, eventVersion)
97
+ : await insertSubsequentEvent(db, event, newVersion, eventVersion);
98
+
99
+ // NOTIFY fires on commit (PG buffers NOTIFY per TX), so subscribers never
100
+ // see a wake-up for an event that later rolled back. Harmless no-op when
101
+ // no LISTENer is attached.
102
+ await db.execute(sql`SELECT pg_notify(${EVENTS_PUBSUB_CHANNEL}, '')`);
103
+
104
+ return buildStoredEvent(event, newVersion, eventVersion, row);
105
+ } catch (e) {
106
+ if (isUniqueViolation(e)) {
107
+ // Only constraint left on the events table: events_aggregate_version_uq
108
+ // on (tenant_id, aggregate_id, version). A unique violation here always
109
+ // means a concurrent writer in the same tenant won the race to the
110
+ // next version — retry-able conflict.
111
+ throw new VersionConflictError(event.aggregateId, event.expectedVersion);
112
+ }
113
+ throw e;
114
+ }
115
+ }
116
+
117
+ type InsertReturn = { id: bigint; createdAt: Temporal.Instant };
118
+
119
+ async function insertFirstEvent(
120
+ db: DbRunner,
121
+ event: EventToAppend,
122
+ newVersion: number,
123
+ eventVersion: number,
124
+ ): Promise<InsertReturn> {
125
+ const [row] = await db
126
+ .insert(eventsTable)
127
+ .values({
128
+ aggregateId: event.aggregateId,
129
+ aggregateType: event.aggregateType,
130
+ tenantId: event.tenantId,
131
+ version: newVersion,
132
+ type: event.type,
133
+ eventVersion,
134
+ payload: event.payload,
135
+ metadata: event.metadata,
136
+ createdBy: event.metadata.userId,
137
+ })
138
+ .returning({ id: eventsTable.id, createdAt: eventsTable.createdAt });
139
+ if (!row) throw new Error("insertFirstEvent: INSERT RETURNING produced no row");
140
+ return row;
141
+ }
142
+
143
+ // Subsequent event — predecessor must exist AND belong to the same tenant.
144
+ // INSERT … SELECT … WHERE EXISTS is awkward in the typed builder, so this
145
+ // one stays raw. Uses ${eventsTable} for the table reference so renames
146
+ // don't silently break the statement.
147
+ async function insertSubsequentEvent(
148
+ db: DbRunner,
149
+ event: EventToAppend,
150
+ newVersion: number,
151
+ eventVersion: number,
152
+ ): Promise<InsertReturn> {
153
+ const payloadJson = JSON.stringify(event.payload);
154
+ const metadataJson = JSON.stringify(event.metadata);
155
+ const rows = await db.execute<{ id: string; created_at: Date | string }>(sql`
156
+ INSERT INTO ${eventsTable} (
157
+ aggregate_id, aggregate_type, tenant_id, version,
158
+ type, event_version, payload, metadata, created_by
159
+ )
160
+ SELECT ${event.aggregateId}::uuid, ${event.aggregateType}, ${event.tenantId}::uuid, ${newVersion},
161
+ ${event.type}, ${eventVersion}, ${payloadJson}::jsonb,
162
+ ${metadataJson}::jsonb, ${event.metadata.userId}
163
+ WHERE EXISTS (
164
+ SELECT 1 FROM ${eventsTable}
165
+ WHERE aggregate_id = ${event.aggregateId}::uuid
166
+ AND version = ${event.expectedVersion}
167
+ AND tenant_id = ${event.tenantId}::uuid
168
+ )
169
+ RETURNING id, created_at;
170
+ `);
171
+ const row = rows[0];
172
+ if (!row) throw new VersionConflictError(event.aggregateId, event.expectedVersion);
173
+ return {
174
+ id: BigInt(row.id),
175
+ // Raw SQL bypasses Drizzle's customType — postgres-js returns Date or
176
+ // string depending on driver-config. Normalize through Temporal.Instant
177
+ // so the InsertReturn shape matches the typed-builder path.
178
+ createdAt:
179
+ row.created_at instanceof Date
180
+ ? Temporal.Instant.fromEpochMilliseconds(row.created_at.getTime())
181
+ : Temporal.Instant.from(row.created_at),
182
+ };
183
+ }
184
+
185
+ function buildStoredEvent(
186
+ event: EventToAppend,
187
+ newVersion: number,
188
+ eventVersion: number,
189
+ row: InsertReturn,
190
+ ): StoredEvent {
191
+ return {
192
+ id: String(row.id),
193
+ aggregateId: event.aggregateId,
194
+ aggregateType: event.aggregateType,
195
+ tenantId: event.tenantId,
196
+ version: newVersion,
197
+ type: event.type,
198
+ eventVersion,
199
+ payload: event.payload,
200
+ metadata: event.metadata,
201
+ createdAt: row.createdAt,
202
+ createdBy: event.metadata.userId,
203
+ };
204
+ }
205
+
206
+ // Load all events for an aggregate, ordered by version. Tenant check is
207
+ // belt + suspenders: even if a caller passes a correct aggregate_id by
208
+ // mistake, the tenant filter prevents cross-tenant reads.
209
+ //
210
+ // Archived streams return an empty slice by default. Pass
211
+ // { includeArchived: true } for ops tools / audit that must see the tail
212
+ // of an archived aggregate. The archive check is a single indexed lookup —
213
+ // negligible on the hot path.
214
+ export async function loadAggregate(
215
+ db: DbRunner,
216
+ aggregateId: string,
217
+ tenantId: TenantId,
218
+ options?: { readonly includeArchived?: boolean },
219
+ ): Promise<readonly StoredEvent[]> {
220
+ if (!options?.includeArchived) {
221
+ const archived = await isStreamArchived(db, tenantId, aggregateId);
222
+ if (archived) return [];
223
+ }
224
+ const rows = await db
225
+ .select()
226
+ .from(eventsTable)
227
+ .where(and(eq(eventsTable.aggregateId, aggregateId), eq(eventsTable.tenantId, tenantId)))
228
+ .orderBy(asc(eventsTable.version));
229
+ return rows.map(toStoredEvent);
230
+ }
231
+
232
+ // Load events up to a point in time. Used for asOf queries that reconstruct
233
+ // historical state. Includes events whose created_at is <= asOf. Same
234
+ // archive semantics as loadAggregate.
235
+ export async function loadAggregateAsOf(
236
+ db: DbRunner,
237
+ aggregateId: string,
238
+ tenantId: TenantId,
239
+ asOf: Temporal.Instant,
240
+ options?: { readonly includeArchived?: boolean },
241
+ ): Promise<readonly StoredEvent[]> {
242
+ if (!options?.includeArchived) {
243
+ const archived = await isStreamArchived(db, tenantId, aggregateId);
244
+ if (archived) return [];
245
+ }
246
+ const rows = await db
247
+ .select()
248
+ .from(eventsTable)
249
+ .where(
250
+ and(
251
+ eq(eventsTable.aggregateId, aggregateId),
252
+ eq(eventsTable.tenantId, tenantId),
253
+ lte(eventsTable.createdAt, asOf),
254
+ ),
255
+ )
256
+ .orderBy(asc(eventsTable.version));
257
+ return rows.map(toStoredEvent);
258
+ }
259
+
260
+ // Cheapest possible read of "what's the latest version on this stream?". The
261
+ // CRUD executor uses this as expectedVersion for its append, so a domain
262
+ // event appended via ctx.appendEvent between two CRUD writes doesn't cause
263
+ // the next CRUD write to fail with version_conflict. Indexed lookup on the
264
+ // existing (aggregate_id, version) unique index. Returns 0 for empty/unknown
265
+ // streams (matches create()'s expectedVersion=0 convention).
266
+ export async function getStreamVersion(
267
+ db: DbRunner,
268
+ aggregateId: string,
269
+ tenantId: TenantId,
270
+ ): Promise<number> {
271
+ const [row] = await db
272
+ .select({ v: max(eventsTable.version) })
273
+ .from(eventsTable)
274
+ .where(and(eq(eventsTable.aggregateId, aggregateId), eq(eventsTable.tenantId, tenantId)));
275
+ return row?.v ?? 0;
276
+ }
277
+
278
+ // Global high-water-mark = MAX(events.id). Marten/Wolverine standard for
279
+ // projection/consumer lag math: lag = HWM - cursor. Single-row aggregate over
280
+ // the bigserial PK index — sub-millisecond cost. Returns 0n on an empty log
281
+ // (boot, fresh tenant, post-archive).
282
+ export async function getEventsHighWaterMark(db: DbRunner): Promise<bigint> {
283
+ const [row] = await db.select({ max: max(eventsTable.id) }).from(eventsTable);
284
+ return row?.max ?? 0n;
285
+ }
286
+
287
+ // Load events strictly newer than a given version. Used by snapshot-aware
288
+ // reads: snapshot provides state up to version N, apply events v > N to
289
+ // catch up to current.
290
+ export async function loadEventsAfterVersion(
291
+ db: DbRunner,
292
+ aggregateId: string,
293
+ tenantId: TenantId,
294
+ afterVersion: number,
295
+ ): Promise<readonly StoredEvent[]> {
296
+ const rows = await db
297
+ .select()
298
+ .from(eventsTable)
299
+ .where(
300
+ and(
301
+ eq(eventsTable.aggregateId, aggregateId),
302
+ eq(eventsTable.tenantId, tenantId),
303
+ gt(eventsTable.version, afterVersion),
304
+ ),
305
+ )
306
+ .orderBy(asc(eventsTable.version));
307
+ return rows.map(toStoredEvent);
308
+ }
309
+
310
+ // Load every event for an aggregate_type across all tenants. Ordered by
311
+ // (created_at, id) — chronological replay order for projection rebuilds.
312
+ //
313
+ // CAUTION — buffers ALL matching events in memory. Safe for smaller
314
+ // aggregate-types (≤ 100k events), a memory cliff for large stores.
315
+ // For >100k events use `streamAllEventsByType` (yields batchwise).
316
+ // Mostly called from tests today — production rebuild goes through
317
+ // projection-rebuild's own streaming path.
318
+ export async function loadAllEventsByType(
319
+ db: DbRunner,
320
+ aggregateType: string,
321
+ ): Promise<readonly StoredEvent[]> {
322
+ const rows = await db
323
+ .select()
324
+ .from(eventsTable)
325
+ .where(eq(eventsTable.aggregateType, aggregateType))
326
+ .orderBy(asc(eventsTable.createdAt), asc(eventsTable.id));
327
+ return rows.map(toStoredEvent);
328
+ }
329
+
330
+ // Stream every event for an aggregate_type across all tenants, batchwise
331
+ // instead of buffered. Memory-bounded: never more than `batchSize` rows
332
+ // resident. Cursor walks `events.id` (bigserial monotonic — concurrent
333
+ // inserts get distinct ids in commit order, so no duplicates and no skips
334
+ // past the cursor).
335
+ //
336
+ // Use case: projection-rebuild on a large event log (>100k events per
337
+ // aggregate-type). loadAllEventsByType would OOM; this iterator yields
338
+ // in batches and the caller accumulates only what it needs.
339
+ //
340
+ // Default batchSize 1000 — trade-off between DB round-trips (smaller =
341
+ // more queries) and memory (larger = more resident).
342
+ //
343
+ // The caller may pause / do async work between yields; the next batch is
344
+ // only fetched when consumed.
345
+ //
346
+ // Cancellation: pass `signal` (typically `ctx.signal` from a handler) to
347
+ // abort iteration. Checked both at batch boundaries (before the next
348
+ // fetch) AND between yields (so abort lands within one event regardless
349
+ // of batch size). Throws AbortError on the first check after abort;
350
+ // in-flight queries are not actively cancelled (postgres-js connection-
351
+ // cancel is a separate, riskier concern handled per-query at the TenantDb
352
+ // boundary).
353
+ export async function* streamAllEventsByType(
354
+ db: DbRunner,
355
+ aggregateType: string,
356
+ batchSize = 1000,
357
+ signal?: AbortSignal,
358
+ ): AsyncIterable<StoredEvent> {
359
+ let cursorId = 0n;
360
+ while (true) {
361
+ signal?.throwIfAborted();
362
+ const rows = await db
363
+ .select()
364
+ .from(eventsTable)
365
+ .where(and(eq(eventsTable.aggregateType, aggregateType), gt(eventsTable.id, cursorId)))
366
+ .orderBy(asc(eventsTable.id))
367
+ .limit(batchSize);
368
+
369
+ if (rows.length === 0) {
370
+ // skip: end of stream — generator exit is the natural termination.
371
+ return;
372
+ }
373
+
374
+ // Track the highest id seen in this batch as we yield. Avoids both the
375
+ // non-null assertion and a redundant array index — the cursor falls out
376
+ // of the same loop that produces the events.
377
+ let nextCursor = cursorId;
378
+ for (const row of rows) {
379
+ // Per-yield abort check. Cheap (one boolean read), keeps cancel
380
+ // semantics independent of the batchSize knob — at batchSize=1000
381
+ // a batch-boundary-only check would still yield 1000 events after
382
+ // an abort which isn't what callers expect.
383
+ signal?.throwIfAborted();
384
+ yield toStoredEvent(row);
385
+ nextCursor = row.id;
386
+ }
387
+ cursorId = nextCursor;
388
+ }
389
+ }
390
+
391
+ function toStoredEvent(row: SelectedEvent): StoredEvent {
392
+ return {
393
+ id: String(row.id),
394
+ aggregateId: row.aggregateId,
395
+ aggregateType: row.aggregateType,
396
+ tenantId: row.tenantId,
397
+ version: row.version,
398
+ type: row.type,
399
+ eventVersion: row.eventVersion,
400
+ payload: row.payload,
401
+ metadata: row.metadata,
402
+ createdAt: row.createdAt,
403
+ createdBy: row.createdBy,
404
+ };
405
+ }
@@ -0,0 +1,90 @@
1
+ import { sql } from "drizzle-orm";
2
+ import { type DbConnection, tableExists } from "../db";
3
+ import {
4
+ bigserial,
5
+ index,
6
+ instant,
7
+ integer,
8
+ jsonb,
9
+ table as pgTable,
10
+ text,
11
+ uniqueIndex,
12
+ uuid,
13
+ } from "../db/dialect";
14
+ import { pushTables } from "../stack";
15
+ import { createArchivedStreamsTable } from "./archive";
16
+ import { createSnapshotsTable } from "./snapshot";
17
+
18
+ // Event-store schema as a Drizzle table. The typed select/insert path handles
19
+ // most operations; append() for subsequent versions uses raw SQL because
20
+ // INSERT ... SELECT ... WHERE EXISTS isn't ergonomic in the typed builder.
21
+ //
22
+ // HTTP-level retry idempotency is handled by pipeline/idempotency.ts
23
+ // (Redis-backed check + cached-response replay). The event-store itself
24
+ // imposes no idempotency index — a single HTTP request may write N events
25
+ // freely, metadata.requestId is purely a trace marker.
26
+ export type EventMetadata = {
27
+ readonly userId: string;
28
+ readonly requestId?: string;
29
+ readonly correlationId?: string;
30
+ readonly causationId?: string;
31
+ // App-specific free key/value (Marten "headers"). Mirror of the canonical
32
+ // type in event-store.ts — kept duplicate because events-schema must stay
33
+ // import-cycle-free vs the event-store module.
34
+ readonly headers?: Readonly<Record<string, string | number | boolean>>;
35
+ };
36
+
37
+ export const eventsTable = pgTable(
38
+ "kumiko_events",
39
+ {
40
+ // bigserial PK: global chronological ordering cheap to index, safe past
41
+ // 2^53 as long as we stay < ~9e15 events. Returned to JS as BigInt.
42
+ id: bigserial("id", { mode: "bigint" }).primaryKey(),
43
+ aggregateId: uuid("aggregate_id").notNull(),
44
+ aggregateType: text("aggregate_type").notNull(),
45
+ tenantId: uuid("tenant_id").notNull(),
46
+ version: integer("version").notNull(),
47
+ type: text("type").notNull(),
48
+ eventVersion: integer("event_version").notNull().default(1),
49
+ payload: jsonb("payload").$type<Record<string, unknown>>().notNull(),
50
+ metadata: jsonb("metadata").$type<EventMetadata>().notNull(),
51
+ // Millisecond precision: matches what asOf-queries can compare reliably.
52
+ // Sprint F: instant() = Temporal.Instant round-trip via dialect.ts customType.
53
+ createdAt: instant("created_at", { precision: 3 }).notNull().default(sql`now()`),
54
+ // Text rather than uuid: the framework's SessionUser.id is a number
55
+ // (serial) by default. Stringified here so both integer- and UUID-shaped
56
+ // user ids round-trip cleanly. Aggregate-IDs stay uuid because events are
57
+ // aggregated by UUID end-to-end.
58
+ createdBy: text("created_by").notNull(),
59
+ },
60
+ (t) => ({
61
+ // Tenant-scoped unique: two tenants that happen to pick the same
62
+ // aggregate_id (deterministic IDs, replay, restores) don't collide, and
63
+ // insertFirstEvent needs no extra tenant check for cross-tenant safety —
64
+ // the constraint itself guarantees it. For expectedVersion > 0 the raw
65
+ // INSERT … SELECT … WHERE EXISTS still pairs the predecessor with the
66
+ // same tenant, which is now just predecessor-existence and no longer
67
+ // doing double duty as an anti-hijack check.
68
+ aggregateVersionUq: uniqueIndex("events_aggregate_version_uq").on(
69
+ t.tenantId,
70
+ t.aggregateId,
71
+ t.version,
72
+ ),
73
+ loadIdx: index("events_load_idx").on(t.aggregateId, t.version),
74
+ tenantTypeIdx: index("events_tenant_type_idx").on(t.tenantId, t.aggregateType, t.createdAt),
75
+ }),
76
+ );
77
+
78
+ // Convenience used by framework integration tests. Creates the table via
79
+ // drizzle-kit diffing. Also materializes kumiko_archived_streams and
80
+ // kumiko_snapshots — loadAggregate / appendEvent / loadAggregateWithSnapshot
81
+ // consult them on the hot path, so the three tables must come up together.
82
+ export async function createEventsTable(db: DbConnection): Promise<void> {
83
+ // skip: events table already exists — createEventsTable is called from both
84
+ // setupTestStack and explicit test-setups, the guard keeps it idempotent.
85
+ if (!(await tableExists(db, "public.kumiko_events"))) {
86
+ await pushTables(db, { kumikoEvents: eventsTable });
87
+ }
88
+ await createArchivedStreamsTable(db);
89
+ await createSnapshotsTable(db);
90
+ }
@@ -0,0 +1,50 @@
1
+ export {
2
+ type ArchiveStreamArgs,
3
+ archivedStreamsTable,
4
+ archiveStream,
5
+ createArchivedStreamsTable,
6
+ isStreamArchived,
7
+ restoreStream,
8
+ } from "./archive";
9
+ export { ArchivedStreamError, VersionConflictError } from "./errors";
10
+ export {
11
+ append,
12
+ EVENTS_PUBSUB_CHANNEL,
13
+ type EventMetadata,
14
+ type EventToAppend,
15
+ getEventsHighWaterMark,
16
+ getStreamVersion,
17
+ loadAggregate,
18
+ loadAggregateAsOf,
19
+ loadAllEventsByType,
20
+ loadEventsAfterVersion,
21
+ type StoredEvent,
22
+ streamAllEventsByType,
23
+ } from "./event-store";
24
+ export { createEventsTable, eventsTable } from "./events-schema";
25
+ export {
26
+ createSnapshotsTable,
27
+ type LoadAggregateWithSnapshotResult,
28
+ loadAggregateWithSnapshot,
29
+ loadLatestSnapshot,
30
+ type SaveSnapshotArgs,
31
+ type Snapshot,
32
+ type SnapshotReducer,
33
+ saveSnapshot,
34
+ snapshotsTable,
35
+ } from "./snapshot";
36
+ export {
37
+ type EventUpcasters,
38
+ makeUpcastCtx,
39
+ type UpcasterErrorPolicy,
40
+ type UpcastOptions,
41
+ upcastStoredEvent,
42
+ upcastStoredEvents,
43
+ } from "./upcaster";
44
+ export {
45
+ createUpcasterDeadLetterTable,
46
+ type DeadLetterRow,
47
+ listDeadLetters,
48
+ recordUpcasterDeadLetter,
49
+ upcasterDeadLetterTable,
50
+ } from "./upcaster-dead-letter";