@cosmicdrift/kumiko-framework 0.367.0 → 0.369.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 (240) hide show
  1. package/AGENTS.md +1 -7
  2. package/README.md +1 -1
  3. package/agents/examples/access-control.md +2 -2
  4. package/agents/examples/anonymous-access-multitenant.md +2 -2
  5. package/agents/examples/anonymous-access.md +3 -3
  6. package/agents/examples/apex-landing.md +1 -1
  7. package/agents/examples/apex-surface-auth.md +6 -7
  8. package/agents/examples/api-worker-split.md +7 -8
  9. package/agents/examples/auth-claims.md +2 -1
  10. package/agents/examples/auth-foundation-providers.md +3 -3
  11. package/agents/examples/auth-mfa.md +3 -4
  12. package/agents/examples/basic-entity.md +3 -4
  13. package/agents/examples/chat-channels.md +4 -4
  14. package/agents/examples/compliance-profiles-demo.md +2 -3
  15. package/agents/examples/cross-feature-events.md +4 -4
  16. package/agents/examples/crypto-shredding-hr.md +14 -9
  17. package/agents/examples/currencies-global.md +3 -4
  18. package/agents/examples/currencies-per-tenant.md +3 -4
  19. package/agents/examples/custom-fields-basic.md +2 -3
  20. package/agents/examples/custom-handlers.md +3 -5
  21. package/agents/examples/dashboard-stats.md +2 -3
  22. package/agents/examples/delivery-notifications.md +5 -6
  23. package/agents/examples/e2e-generator.md +1 -1
  24. package/agents/examples/embedded-entity-form.md +2 -3
  25. package/agents/examples/embedded.md +2 -3
  26. package/agents/examples/encrypted-tenant-config.md +5 -6
  27. package/agents/examples/error-contract.md +3 -4
  28. package/agents/examples/event-sourcing.md +19 -23
  29. package/agents/examples/feature-toggles.md +4 -4
  30. package/agents/examples/field-access.md +3 -4
  31. package/agents/examples/files-post-processing.md +12 -13
  32. package/agents/examples/golden-path.md +208 -0
  33. package/agents/examples/idempotency.md +2 -2
  34. package/agents/examples/inbound-mail-triage.md +7 -7
  35. package/agents/examples/lane-routing.md +3 -3
  36. package/agents/examples/ledger-banking.md +2 -3
  37. package/agents/examples/ledger-invoicing.md +2 -3
  38. package/agents/examples/legal-pages.md +1 -1
  39. package/agents/examples/lifecycle-hooks.md +3 -3
  40. package/agents/examples/managed-config.md +3 -4
  41. package/agents/examples/managed-pages.md +2 -2
  42. package/agents/examples/notes-history-basic.md +4 -5
  43. package/agents/examples/ownership.md +3 -5
  44. package/agents/examples/pdf-audit-export.md +2 -3
  45. package/agents/examples/pipeline-basics.md +2 -2
  46. package/agents/examples/public-share-token.md +3 -3
  47. package/agents/examples/rate-limiting.md +2 -1
  48. package/agents/examples/realtime-sse.md +2 -3
  49. package/agents/examples/record-detail-layout.md +1 -1
  50. package/agents/examples/reference-data.md +3 -3
  51. package/agents/examples/relations.md +2 -2
  52. package/agents/examples/screens-nav.md +1 -1
  53. package/agents/examples/search.md +2 -2
  54. package/agents/examples/secrets-demo.md +8 -8
  55. package/agents/examples/security-baseline.md +2 -2
  56. package/agents/examples/session-revocation.md +7 -8
  57. package/agents/examples/state-machine.md +181 -165
  58. package/agents/examples/tags-basic.md +2 -3
  59. package/agents/examples/tenant-isolation.md +2 -3
  60. package/agents/examples/tenant-settings.md +2 -2
  61. package/agents/examples/tier-admin.md +3 -4
  62. package/agents/examples/timezones.md +3 -3
  63. package/agents/examples/user-data-rights.md +12 -8
  64. package/agents/examples/user-profile.md +3 -3
  65. package/agents/examples/webhook-step.md +2 -3
  66. package/agents/examples/wizard-form.md +4 -5
  67. package/agents/examples/workflow-engine.md +7 -3
  68. package/agents/examples/writeform-section.md +1 -1
  69. package/agents/examples.md +1 -0
  70. package/agents/features.md +4 -4
  71. package/dist/consumer-cli.js +2 -3
  72. package/dist/crypto/index.d.ts +1 -1
  73. package/dist/crypto/index.js +1 -1
  74. package/dist/crypto/owner-transition-rekey.js +2 -0
  75. package/dist/crypto/pg-kms-adapter.js +1 -1
  76. package/dist/crypto/subject-resolver.d.ts +2 -0
  77. package/dist/crypto/subject-resolver.js +30 -15
  78. package/dist/db/bun-db-deprecated.d.ts +10 -0
  79. package/dist/{bun-db/index.js → db/bun-db-deprecated.js} +4 -3
  80. package/dist/db/config-seed.js +1 -1
  81. package/dist/db/connection.d.ts +23 -5
  82. package/dist/db/connection.js +10 -5
  83. package/dist/db/dialect.js +1 -1
  84. package/dist/db/entity-field-encryption.d.ts +5 -0
  85. package/dist/db/entity-field-encryption.js +29 -0
  86. package/dist/db/entity-table-meta.js +6 -5
  87. package/dist/db/event-store-executor-read.js +26 -5
  88. package/dist/db/index.d.ts +4 -4
  89. package/dist/db/index.js +1 -1
  90. package/dist/db/migrate-runner.js +1 -1
  91. package/dist/db/queries/backfill-pii.js +16 -9
  92. package/dist/db/queries/ddl.js +1 -1
  93. package/dist/db/queries/event-store.d.ts +2 -0
  94. package/dist/db/queries/event-store.js +26 -0
  95. package/dist/db/queries/test-stack.js +1 -1
  96. package/dist/db/query.d.ts +105 -1
  97. package/dist/db/query.js +1450 -3
  98. package/dist/{stack/table-helpers.d.ts → db/table-push.d.ts} +5 -15
  99. package/dist/{stack/table-helpers.js → db/table-push.js} +6 -46
  100. package/dist/db/tenant-db.d.ts +11 -0
  101. package/dist/db/tenant-db.js +51 -12
  102. package/dist/derivatives/derivatives-context.d.ts +1 -1
  103. package/dist/derivatives/derivatives-context.js +1 -1
  104. package/dist/engine/boot-validator/gdpr-storage.js +3 -3
  105. package/dist/engine/boot-validator/pii-retention.js +3 -3
  106. package/dist/engine/boot-validator/record-owned.js +3 -3
  107. package/dist/engine/boot-validator/screens.js +37 -1
  108. package/dist/engine/bridge-stub.d.ts +4 -0
  109. package/dist/engine/bridge-stub.js +62 -0
  110. package/dist/engine/build-config-feature-schema.js +197 -65
  111. package/dist/engine/event-helpers.d.ts +2 -1
  112. package/dist/engine/event-helpers.js +1 -0
  113. package/dist/engine/extension-selector-plugins.d.ts +3 -0
  114. package/dist/engine/extension-selector-plugins.js +14 -0
  115. package/dist/engine/feature-config-events-jobs.d.ts +2 -0
  116. package/dist/engine/feature-config-events-jobs.js +3 -2
  117. package/dist/engine/index.d.ts +1 -0
  118. package/dist/engine/index.js +1 -0
  119. package/dist/es-ops/operations-schema.js +1 -1
  120. package/dist/event-store/admin-api.js +1 -1
  121. package/dist/event-store/archive.js +1 -1
  122. package/dist/event-store/errors.d.ts +2 -1
  123. package/dist/event-store/errors.js +6 -2
  124. package/dist/event-store/event-store.js +17 -9
  125. package/dist/event-store/events-schema.js +1 -1
  126. package/dist/event-store/rebuild-dead-letter.js +3 -3
  127. package/dist/event-store/snapshot.js +1 -1
  128. package/dist/event-store/upcaster-dead-letter.js +3 -3
  129. package/dist/files/create-file-ref-from-bytes.js +1 -1
  130. package/dist/files/file-routes.js +1 -1
  131. package/dist/i18n/settings-hub-keys.js +1 -2
  132. package/dist/internal/stack-support.d.ts +12 -0
  133. package/dist/internal/stack-support.js +12 -0
  134. package/dist/internal/testing.d.ts +4 -0
  135. package/dist/internal/testing.js +5 -0
  136. package/dist/jobs/job-runner.js +23 -11
  137. package/dist/migrations/pending-rebuilds.js +1 -1
  138. package/dist/migrations/pii-event-backfill.js +2 -2
  139. package/dist/pipeline/dispatch-shared.js +43 -23
  140. package/dist/pipeline/dispatch-write.js +6 -2
  141. package/dist/pipeline/dispatcher-utils.js +6 -2
  142. package/dist/pipeline/event-consumer-state.js +1 -1
  143. package/dist/pipeline/projection-rebuild.d.ts +1 -0
  144. package/dist/pipeline/projection-rebuild.js +1 -1
  145. package/dist/pipeline/projection-state.js +1 -1
  146. package/dist/pipeline/system-hooks.js +1 -1
  147. package/dist/schema-cli.js +3 -3
  148. package/dist/search/purge-subject.js +20 -10
  149. package/dist/seeding/index.d.ts +1 -0
  150. package/dist/seeding/index.js +1 -0
  151. package/dist/stack/index.d.ts +10 -9
  152. package/dist/stack/index.js +11 -19
  153. package/dist/testing/e2e-generator.d.ts +5 -49
  154. package/dist/testing/e2e-generator.js +5 -382
  155. package/dist/testing/handler-context.d.ts +5 -4
  156. package/dist/testing/handler-context.js +5 -69
  157. package/dist/testing/index.d.ts +10 -26
  158. package/dist/testing/index.js +10 -34
  159. package/dist/testing/real-providers.d.ts +5 -3
  160. package/dist/testing/real-providers.js +5 -21
  161. package/dist/upgrade-cli.js +6 -4
  162. package/package.json +37 -9
  163. package/src/changes.json +64 -0
  164. package/src/scripts/codemod/README.md +43 -0
  165. package/src/scripts/codemod/codemod-support.ts +276 -0
  166. package/src/scripts/codemod/db-factory.ts +810 -0
  167. package/src/scripts/codemod/feature-factory.ts +429 -0
  168. package/src/scripts/codemod/s3-imports.ts +274 -0
  169. package/src/scripts/codemod/tenant-db-options.ts +454 -0
  170. package/src/scripts/codemod/testing-move-targets.ts +161 -0
  171. package/src/scripts/codemod/testing-move.ts +520 -0
  172. package/dist/bun-db/connection.d.ts +0 -17
  173. package/dist/bun-db/connection.js +0 -40
  174. package/dist/bun-db/index.d.ts +0 -4
  175. package/dist/bun-db/query.d.ts +0 -106
  176. package/dist/bun-db/query.js +0 -1457
  177. package/dist/db/api.d.ts +0 -19
  178. package/dist/db/api.js +0 -23
  179. package/dist/db/bun-provider.d.ts +0 -2
  180. package/dist/db/bun-provider.js +0 -28
  181. package/dist/db/postgres-provider.d.ts +0 -2
  182. package/dist/db/postgres-provider.js +0 -21
  183. package/dist/db/query-api.d.ts +0 -2
  184. package/dist/db/query-api.js +0 -6
  185. package/dist/stack/db.d.ts +0 -22
  186. package/dist/stack/db.js +0 -67
  187. package/dist/stack/drain-event-consumers.d.ts +0 -4
  188. package/dist/stack/drain-event-consumers.js +0 -51
  189. package/dist/stack/drain-jobs.d.ts +0 -22
  190. package/dist/stack/drain-jobs.js +0 -141
  191. package/dist/stack/event-collector.d.ts +0 -9
  192. package/dist/stack/event-collector.js +0 -12
  193. package/dist/stack/push-entity-projection-tables.d.ts +0 -24
  194. package/dist/stack/push-entity-projection-tables.js +0 -74
  195. package/dist/stack/redis.d.ts +0 -17
  196. package/dist/stack/redis.js +0 -52
  197. package/dist/stack/request-helper.d.ts +0 -35
  198. package/dist/stack/request-helper.js +0 -144
  199. package/dist/stack/test-stack.d.ts +0 -192
  200. package/dist/stack/test-stack.js +0 -429
  201. package/dist/testing/access-assertions.d.ts +0 -2
  202. package/dist/testing/access-assertions.js +0 -13
  203. package/dist/testing/assertions.d.ts +0 -10
  204. package/dist/testing/assertions.js +0 -22
  205. package/dist/testing/boot-validator-fixture.d.ts +0 -3
  206. package/dist/testing/boot-validator-fixture.js +0 -101
  207. package/dist/testing/closed-connection-error.d.ts +0 -7
  208. package/dist/testing/closed-connection-error.js +0 -46
  209. package/dist/testing/db-cleanup.d.ts +0 -9
  210. package/dist/testing/db-cleanup.js +0 -31
  211. package/dist/testing/expect-error.d.ts +0 -2
  212. package/dist/testing/expect-error.js +0 -22
  213. package/dist/testing/file-provider-contract.d.ts +0 -2
  214. package/dist/testing/file-provider-contract.js +0 -102
  215. package/dist/testing/http-cookies.d.ts +0 -7
  216. package/dist/testing/http-cookies.js +0 -47
  217. package/dist/testing/late-bound.d.ts +0 -9
  218. package/dist/testing/late-bound.js +0 -31
  219. package/dist/testing/manual-clock.d.ts +0 -14
  220. package/dist/testing/manual-clock.js +0 -12
  221. package/dist/testing/multipart-helper.d.ts +0 -22
  222. package/dist/testing/multipart-helper.js +0 -77
  223. package/dist/testing/mutable-master-key-provider.d.ts +0 -7
  224. package/dist/testing/mutable-master-key-provider.js +0 -35
  225. package/dist/testing/observability-recorder.d.ts +0 -9
  226. package/dist/testing/observability-recorder.js +0 -29
  227. package/dist/testing/seed.d.ts +0 -9
  228. package/dist/testing/seed.js +0 -21
  229. package/dist/testing/shared-entities.d.ts +0 -286
  230. package/dist/testing/shared-entities.js +0 -56
  231. package/dist/testing/utils.d.ts +0 -1
  232. package/dist/testing/utils.js +0 -1
  233. package/dist/testing/wait-for.d.ts +0 -20
  234. package/dist/testing/wait-for.js +0 -47
  235. package/dist/testing/without-ambient-temporal.d.ts +0 -5
  236. package/dist/testing/without-ambient-temporal.js +0 -17
  237. package/dist/testing/zip-fixture.d.ts +0 -1
  238. package/dist/testing/zip-fixture.js +0 -33
  239. /package/dist/{stack/test-users.d.ts → seeding/seed-users.d.ts} +0 -0
  240. /package/dist/{stack/test-users.js → seeding/seed-users.js} +0 -0
@@ -35,8 +35,8 @@
35
35
  // 2. projection ({@link PiiBackfillOptions.resolveOwnerFromProjection}) —
36
36
  // pre-owner-field-addition events don't carry it; read it from the
37
37
  // entity's current projection row instead.
38
- // 2b. whenAbsent — the payload again, now falling back to the tenant key for
39
- // fields that declare it.
38
+ // 2b. whenAbsent — the payload again, now falling back to the tenant key (or
39
+ // the row's own record key for whenAbsent: "self") for fields that declare it.
40
40
  // 3. erase ({@link PiiBackfillOptions.eraseUnresolvableSubjects}) — still
41
41
  // unresolvable (hard-deleted aggregate, no projection) → PII_ERASED_SENTINEL.
42
42
  // Stages 2 and 3 are opt-in and off by default; without them an
@@ -48,13 +48,16 @@
48
48
  // owner change made before owner transitions re-keyed the value). An owner
49
49
  // cleared again (owner → none) is not recoverable from the projection: such
50
50
  // values stay tenant-keyed, unlike the live path that keeps the last owner.
51
+ // For whenAbsent: "self" fields the same stage moves tenant-keyed ciphertext
52
+ // of a still-ownerless row under its record key (written before the field
53
+ // declared "self"); a later owner assignment keeps the created event
54
+ // record-keyed, like the tenant-keyed case.
51
55
  //
52
56
  // Snapshots of touched aggregates are dropped per batch (they may cache
53
57
  // plaintext); the next snapshotting load recreates them. AFTER a run, rebuild the
54
58
  // affected projections — applyEntityEvent materializes ciphertext AND the
55
59
  // blind-index columns, which keeps equality lookups (login by email) alive.
56
60
  import { isOneOf } from "@cosmicdrift/kumiko-types/type-guards";
57
- import { asRawClient } from "../../bun-db/index.js";
58
61
  import { quoteIdent } from "../../crypto/ciphertext-pattern.js";
59
62
  import { configuredEventPiiCatalog } from "../../crypto/event-pii.js";
60
63
  import { isLocalKeyKmsAdapter, KeyErasedError, KeyNotFoundError, } from "../../crypto/kms-adapter.js";
@@ -62,6 +65,7 @@ import { isPlainUserOwnedField } from "../../crypto/owner-transition-rekey.js";
62
65
  import { configuredPiiSubjectKms, decryptPiiValueForSubject, encryptPiiValueForSubject, isPiiCiphertext, PII_ERASED_SENTINEL, piiCiphertextSubject, } from "../../crypto/pii-field-encryption.js";
63
66
  import { collectPiiEncryptedFields, nonEmptyString, resolveEventSubject, resolveSubjectForField, SubjectResolutionError, } from "../../crypto/subject-resolver.js";
64
67
  import { resolveTableName } from "../entity-table-meta.js";
68
+ import { asRawClient } from "../query.js";
65
69
  import { tableExists } from "../schema-inspection.js";
66
70
  import { toSnakeCase } from "../table-builder.js";
67
71
  import { toPostgresArrayLiteral } from "./postgres-array-literal.js";
@@ -479,7 +483,7 @@ async function rekeyTenantKeyedValue(deps, target) {
479
483
  return { kind: "unchanged" };
480
484
  const keyedUnder = ciphertextSubjectOrNull(ciphertext);
481
485
  const userSubject = keyedUnder?.kind === "tenant" && keyedUnder.tenantId === target.tenantId
482
- ? ownerOfTenantKeyedValue(target)
486
+ ? rekeyTargetOfTenantKeyedValue(target)
483
487
  : keyedUnder?.kind === "user"
484
488
  ? currentProjectionOwnerIfOther(target, keyedUnder.userId)
485
489
  : null;
@@ -505,12 +509,15 @@ async function rekeyTenantKeyedValue(deps, target) {
505
509
  throw e;
506
510
  }
507
511
  }
508
- // Strict chain (payload, then projection), never whenAbsent.
509
- function ownerOfTenantKeyedValue(target) {
512
+ // Strict chain (payload, then projection) names the owner; an ownerless row of a
513
+ // whenAbsent: "self" field falls through to its record key. A whenAbsent: "tenant"
514
+ // result is the key the value already sits under — nothing to move.
515
+ function rekeyTargetOfTenantKeyedValue(target) {
510
516
  const resolution = resolveOwnerSubject(target.entity, target.field, target.subjectSource, target.ownerFallback, target.projectionOwnerRow, target.tenantId, target.aggregateType);
511
- return resolution.kind === "resolved" && resolution.subject.kind === "user"
512
- ? resolution.subject
513
- : null;
517
+ if (resolution.kind !== "resolved")
518
+ return null;
519
+ const { subject } = resolution;
520
+ return subject.kind === "user" || subject.kind === "record" ? subject : null;
514
521
  }
515
522
  // A value keyed under a previous owner moves to the owner the row has now. The
516
523
  // projection of the event's own tenant is authoritative here: the payload of
@@ -1,6 +1,6 @@
1
1
  import { asRawClient } from "../query.js";
2
2
  import { quoteTableIdent } from "./table-ops.js";
3
- // Generic DDL helpers used on the prod-boot path (stack/table-helpers.ts's
3
+ // Generic DDL helpers used on the prod-boot path (db/table-push.ts's
4
4
  // unsafePushTables, event-consumer-state.ts's multi-instance backfill) —
5
5
  // split out of queries/test-stack.ts so a prod-boot import doesn't point at
6
6
  // a module named for test-only concerns (truncate/create/drop-database).
@@ -24,6 +24,8 @@ export type SubsequentEventInsertRow = {
24
24
  readonly id: string | bigint;
25
25
  readonly created_at: Date | string;
26
26
  };
27
+ export type FirstEventInsertParams = Omit<SubsequentEventInsertParams, "expectedVersion">;
28
+ export declare function insertFirstEventRow(db: AnyDb, params: FirstEventInsertParams): Promise<SubsequentEventInsertRow | undefined>;
27
29
  /** INSERT … SELECT … WHERE EXISTS predecessor — stays raw (typed builder can't express this). */
28
30
  export declare function insertSubsequentEventRow(db: AnyDb, params: SubsequentEventInsertParams): Promise<SubsequentEventInsertRow | undefined>;
29
31
  export declare function selectStreamMaxVersion(db: AnyDb, aggregateId: string, tenantId: string): Promise<number>;
@@ -135,6 +135,31 @@ function duplicateIdempotencyKeyErrorOr(e) {
135
135
  }
136
136
  return e;
137
137
  }
138
+ // ON CONFLICT on the version index only: a lost race returns no row instead of
139
+ // a 23505, which would abort the caller's transaction (25P02) and make the
140
+ // current stream version unreadable. The idempotency index still raises 23505.
141
+ export async function insertFirstEventRow(db, params) {
142
+ const rows = await asRawClient(db).unsafe(`INSERT INTO "kumiko_events" (
143
+ aggregate_id, aggregate_type, tenant_id, version,
144
+ type, event_version, payload, metadata, created_by, created_at
145
+ )
146
+ VALUES ($1::uuid, $2, $3::uuid, $4, $5, $6, $7::jsonb, $8::jsonb, $9,
147
+ COALESCE($10::timestamptz, now()))
148
+ ON CONFLICT (tenant_id, aggregate_id, version) DO NOTHING
149
+ RETURNING id, created_at`, [
150
+ params.aggregateId,
151
+ params.aggregateType,
152
+ params.tenantId,
153
+ params.newVersion,
154
+ params.type,
155
+ params.eventVersion,
156
+ params.payload,
157
+ params.metadata,
158
+ params.createdBy,
159
+ params.createdAt ?? null,
160
+ ]);
161
+ return rows[0];
162
+ }
138
163
  /** INSERT … SELECT … WHERE EXISTS predecessor — stays raw (typed builder can't express this). */
139
164
  export async function insertSubsequentEventRow(db, params) {
140
165
  const rows = await asRawClient(db).unsafe(`INSERT INTO "kumiko_events" (
@@ -150,6 +175,7 @@ export async function insertSubsequentEventRow(db, params) {
150
175
  AND version = $10
151
176
  AND tenant_id = $3::uuid
152
177
  )
178
+ ON CONFLICT (tenant_id, aggregate_id, version) DO NOTHING
153
179
  RETURNING id, created_at`, [
154
180
  params.aggregateId,
155
181
  params.aggregateType,
@@ -1,7 +1,7 @@
1
1
  import { asRawClient } from "../query.js";
2
2
  import { quoteTableIdent } from "./table-ops.js";
3
3
  // Re-exported for back-compat — the generic DDL helpers moved to ./ddl so
4
- // the prod-boot path (stack/table-helpers.ts, pipeline/event-consumer-state.ts)
4
+ // the prod-boot path (db/table-push.ts, pipeline/event-consumer-state.ts)
5
5
  // doesn't import from a module named for test-only concerns.
6
6
  export { alterTableAddColumn, createIndexIfNotExists, executeDdlStatement } from "./ddl.js";
7
7
  export async function truncateTablesRestartIdentity(db, tableNames) {
@@ -1 +1,105 @@
1
- export { type AnyDb, aggregateWhere, asEntityTableMeta, asRawClient, coerceRow, countWhere, type DeleteManyBatchedOptions, type DeleteManyBatchedResult, deleteMany, deleteManyBatched, extractTableInfo, fetchOne, type IncrementCounterOptions, incrementCounter, insertMany, insertOne, type JsonTextMatch, type OrderByClause, runInNewTransaction, runInSavepoint, runInSavepointIfSupported, runnerCanBeginTransaction, type SelectOptions, selectMany, type TableInfo, transaction, type UpsertOnConflictOptions, unsafeReadRetrying, updateMany, upsertByPk, upsertOnConflict, type WhereObject, type WhereOperator, type WhereValue, } from "../bun-db/query.js";
1
+ import type { AggregateRow, AggregateSpec } from "@cosmicdrift/kumiko-types/aggregate-types";
2
+ import type { DbRunner, DbTx } from "@cosmicdrift/kumiko-types/db-connection";
3
+ import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
4
+ import type { SelectOptions, WhereObject } from "@cosmicdrift/kumiko-types/where-clause-types";
5
+ import type { EntityTableMeta } from "./entity-table-meta.js";
6
+ import { type NotExecutorOnly } from "./table-builder.js";
7
+ import { asEntityTableMeta, requireEntityTableMeta } from "./table-introspection.js";
8
+ export { asEntityTableMeta, requireEntityTableMeta };
9
+ export type ReservedClient = {
10
+ unsafe: RawClient["unsafe"];
11
+ release: () => unknown;
12
+ };
13
+ export type RawClient = {
14
+ unsafe: <TRow = unknown>(sql: string, params?: readonly unknown[]) => Promise<readonly TRow[]>;
15
+ begin?: <T>(fn: (tx: DbTx) => Promise<T>) => Promise<T>;
16
+ savepoint?: <T>(fn: (sp: unknown) => Promise<T>) => Promise<T>;
17
+ release?: unknown;
18
+ reserve?: () => Promise<ReservedClient>;
19
+ };
20
+ export type RawClientWithBegin = RawClient & {
21
+ begin: NonNullable<RawClient["begin"]>;
22
+ };
23
+ export declare function hasBegin(client: RawClient): client is RawClientWithBegin;
24
+ export declare function asRawClient(db: unknown): RawClient;
25
+ export declare function runnerCanBeginTransaction(db: unknown): boolean;
26
+ export declare function runInSavepoint<T>(tx: unknown, fn: (sp: unknown) => Promise<T>): Promise<T>;
27
+ export declare function runInSavepointIfSupported<T>(db: unknown, fn: (sp: DbRunner) => Promise<T>): Promise<T>;
28
+ export type AnyDb = DbRunner | unknown;
29
+ export type { JsonTextMatch, OrderByClause, SelectOptions, WhereObject, WhereOperator, WhereValue, } from "@cosmicdrift/kumiko-types/where-clause-types";
30
+ type TableLike = EntityTableMeta | any;
31
+ type WritableTable = EntityTableMeta & NotExecutorOnly;
32
+ export type TableInfo = {
33
+ readonly name: string;
34
+ readonly columnOf: (field: string) => string;
35
+ readonly pgTypeOf: (column: string) => string | undefined;
36
+ readonly bigintJsModeOf: (column: string) => "number" | "bigint" | undefined;
37
+ readonly fieldOf: (column: string) => string;
38
+ readonly hasColumn: (fieldOrColumn: string) => boolean;
39
+ };
40
+ export declare function extractTableInfo(table: TableLike): TableInfo;
41
+ export declare function coerceRow<TOut = Record<string, unknown>>(row: Record<string, unknown>, info: TableInfo): TOut;
42
+ export declare function instantToTimestamptzParam(instant: Temporal.Instant): string;
43
+ export declare function isClosedConnectionError(err: unknown): boolean;
44
+ export declare function describeClosedConnectionFailure(raw: unknown, err: unknown, attempts: number): Record<string, unknown> | undefined;
45
+ export declare function unsafeReadRetrying<TRow>(db: AnyDb, sqlText: string, params: readonly unknown[]): Promise<readonly TRow[]>;
46
+ export declare function selectMany<TRow = any>(db: AnyDb, table: TableLike, where?: WhereObject, options?: SelectOptions): Promise<readonly TRow[]>;
47
+ export declare function fetchOne<TRow = any>(db: AnyDb, table: TableLike, where: WhereObject): Promise<TRow | undefined>;
48
+ export type JoinColumnPair = {
49
+ readonly left: string;
50
+ readonly right: string;
51
+ };
52
+ export type InnerJoinSpec = {
53
+ readonly left: TableLike;
54
+ readonly right: TableLike;
55
+ readonly on: readonly [JoinColumnPair, ...JoinColumnPair[]];
56
+ readonly leftWhere?: WhereObject;
57
+ readonly rightWhere?: WhereObject;
58
+ /** Fields to return per side; default: all columns of `left`, none of `right`. */
59
+ readonly leftFields?: readonly string[];
60
+ readonly rightFields?: readonly string[];
61
+ readonly limit?: number;
62
+ };
63
+ export type InnerJoinRow<TLeft, TRight> = {
64
+ readonly left: TLeft;
65
+ readonly right: TRight;
66
+ };
67
+ export declare function selectInnerJoin<TLeft = Record<string, unknown>, TRight = Record<string, unknown>>(db: AnyDb, spec: InnerJoinSpec): Promise<readonly InnerJoinRow<TLeft, TRight>[]>;
68
+ export declare function insertMany<TRow = any>(db: AnyDb, table: WritableTable, rows: ReadonlyArray<Record<string, unknown>>): Promise<readonly TRow[]>;
69
+ export declare function insertOne<TRow = any>(db: AnyDb, table: WritableTable, values: Record<string, unknown>): Promise<TRow | undefined>;
70
+ export declare function updateMany<TRow = any>(db: AnyDb, table: WritableTable, set: Record<string, unknown>, where: WhereObject): Promise<readonly TRow[]>;
71
+ export declare function deleteMany(db: AnyDb, table: WritableTable, where: WhereObject): Promise<void>;
72
+ export declare function resolveConflictColumns(table: TableLike, info: TableInfo, conflictKeys: readonly string[] | undefined): readonly string[];
73
+ export type UpsertOnConflictOptions = {
74
+ readonly conflictKeys: readonly string[];
75
+ /** Columns to set on conflict. Default: EXCLUDED for every inserted non-key column. */
76
+ readonly update?: Record<string, unknown>;
77
+ };
78
+ export type DeleteManyBatchedOptions = {
79
+ readonly limit: number;
80
+ readonly maxBatches?: number;
81
+ /** Row id field for the LIMIT subquery. Default `id`. */
82
+ readonly idColumn?: string;
83
+ };
84
+ export type DeleteManyBatchedResult = {
85
+ readonly deleted: number;
86
+ readonly batches: number;
87
+ };
88
+ export declare function countWhere(db: AnyDb, table: TableLike, where?: WhereObject): Promise<number>;
89
+ export declare function isTimestamptzType(pgType: string | undefined): boolean;
90
+ export declare function aggregateWhere(db: AnyDb, table: TableLike, spec: AggregateSpec, where?: WhereObject): Promise<readonly AggregateRow[]>;
91
+ export declare function upsertOnConflict<TRow = any>(db: AnyDb, table: WritableTable, values: Record<string, unknown>, options: UpsertOnConflictOptions): Promise<TRow | undefined>;
92
+ export declare function upsertByPk<TRow = any>(db: AnyDb, table: WritableTable, values: Record<string, unknown>, updateOnConflict?: Record<string, unknown>): Promise<TRow | undefined>;
93
+ export type InsertOnConflictDoNothingOptions = {
94
+ readonly conflictKeys?: readonly string[];
95
+ };
96
+ export declare function insertOnConflictDoNothing<TRow = any>(db: AnyDb, table: WritableTable, values: Record<string, unknown>, options?: InsertOnConflictDoNothingOptions): Promise<TRow | undefined>;
97
+ export type IncrementCounterOptions = {
98
+ readonly conflictKeys?: readonly string[];
99
+ /** Extra SET clauses on conflict (e.g. lastUpdatedAt: sql\`NOW()\`). */
100
+ readonly set?: Record<string, unknown>;
101
+ };
102
+ export declare function incrementCounter<TRow = any>(db: AnyDb, table: WritableTable, values: Record<string, unknown>, increments: Record<string, number>, options?: IncrementCounterOptions): Promise<TRow | undefined>;
103
+ export declare function deleteManyBatched(db: AnyDb, table: WritableTable, where: WhereObject, options: DeleteManyBatchedOptions): Promise<DeleteManyBatchedResult>;
104
+ export declare function transaction<T>(db: AnyDb, fn: (tx: DbTx) => Promise<T>): Promise<T>;
105
+ export declare function runInNewTransaction<T>(db: unknown, fn: (tx: DbRunner) => Promise<T>): Promise<T>;