@domainkit/capsuledb 0.18.0 → 0.20.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.
package/README.md CHANGED
@@ -73,6 +73,37 @@ Assert mode applies nothing and fails unless the database already matches the ca
73
73
  migration is a boot failure rather than a runtime surprise. `capsuledb check` compares an emitted
74
74
  folder against the current capsule in CI.
75
75
 
76
+ ## Or prepare at deploy time
77
+
78
+ A serverless host prepares the database in its deploy and boots without touching the schema.
79
+ `PgStorage.manifest()` yields the manifest of exactly the capsule `PgStorage.layer()` installs, so a
80
+ stack using `capsuledb/alchemy` prepares what the function asserts:
81
+
82
+ ```ts
83
+ import { PgStorage } from "@domainkit/capsuledb";
84
+ import * as CapsuleDB from "capsuledb/alchemy";
85
+
86
+ const manifest = yield * PgStorage.manifest();
87
+ const registry =
88
+ yield *
89
+ CapsuleDB.Registry("domainkit-storage", {
90
+ url,
91
+ provider: "Postgres",
92
+ manifest,
93
+ });
94
+ // Pass registry.fingerprint into the function's version-scoped environment.
95
+ ```
96
+
97
+ The function boots with `readiness: "first-use"`:
98
+
99
+ ```ts
100
+ PgStorage.layer({ mode: "assert", readiness: "first-use" });
101
+ ```
102
+
103
+ The layer builds without a statement; the first Storage query runs one cached check. A failed check
104
+ surfaces as a `SqlError` on that query and is retried on the next. Pass the same `prefix` and
105
+ `registryPrefix` to `manifest` and `layer`.
106
+
76
107
  ## Tables
77
108
 
78
109
  | Table | Key | Holds |
package/dist/index.d.mts CHANGED
@@ -1,9 +1,10 @@
1
- import { Capsule, Registry, Schema } from "capsuledb";
1
+ import { Capsule, Manifest, Registry, Schema } from "capsuledb";
2
2
  import { Storage } from "domainkit";
3
- import * as SqlClient from "effect/unstable/sql/SqlClient";
3
+ import * as SqlClient from "effect/sql/SqlClient";
4
+ import * as Effect from "effect/Effect";
4
5
  import * as Layer from "effect/Layer";
5
6
  declare namespace PgStorage_d_exports {
6
- export { Options, layer };
7
+ export { Options, layer, manifest };
7
8
  }
8
9
  interface Options {
9
10
  /** Table prefix. Default `domainkit`. Part of the physical layout; immutable after first deploy. */
@@ -15,8 +16,23 @@ interface Options {
15
16
  * host already uses for other capsules, and pass the same value to `capsuledb emit --prefix`.
16
17
  */
17
18
  readonly registryPrefix?: string;
19
+ /**
20
+ * When the registry is checked. `boot` (default) prepares or asserts while the layer builds.
21
+ * `first-use` builds with no statement and runs one cached check before the first Storage query,
22
+ * so a cold start that never touches Storage does no registry work; a failed check surfaces as a
23
+ * `SqlError` on that query and is retried on the next. Pair it with `mode: "assert"` on a host
24
+ * whose database was prepared at deploy time.
25
+ */
26
+ readonly readiness?: "boot" | "first-use";
18
27
  }
19
28
  declare const layer: (options?: Options) => Layer.Layer<Storage.Service, Registry.RegistryRuntimeError, SqlClient.SqlClient>;
29
+ /**
30
+ * The CapsuleDB manifest for exactly what `layer(options)` installs, computed without touching a
31
+ * database. A deploy stack passes it to `CapsuleDB.Registry` from `capsuledb/alchemy`, so the
32
+ * schema it prepares is the schema the runtime asserts. Only `prefix` and `registryPrefix` affect
33
+ * it; `mode` and `readiness` are runtime choices.
34
+ */
35
+ declare const manifest: (options?: Pick<Options, "prefix" | "registryPrefix">) => Effect.Effect<Manifest.Manifest, Registry.RegistryError>;
20
36
  //#endregion
21
37
  //#region src/capsule.d.ts
22
38
  /** The capsule under the default `domainkit` prefix. `capsuledb emit --export capsule` reads this. */
package/dist/index.mjs CHANGED
@@ -2,9 +2,9 @@ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
2
  import { Capsule, Migration, Pg, Registry, Schema } from "capsuledb";
3
3
  import { DomainKit, Principal, Reason, Storage } from "domainkit";
4
4
  import { DateTime, Effect, Layer, Option, Schema as Schema$1 } from "effect";
5
- import * as SqlClient from "effect/unstable/sql/SqlClient";
5
+ import * as SqlClient from "effect/sql/SqlClient";
6
6
  //#region package.json
7
- var version = "0.18.0";
7
+ var version = "0.20.0";
8
8
  //#endregion
9
9
  //#region src/internal/storage.ts
10
10
  /**
@@ -1233,15 +1233,35 @@ const capsule = make();
1233
1233
  * applies `capsuledb emit` output instead and boots with `mode: "assert"`, which touches no schema
1234
1234
  * and fails unless the database already matches the capsule.
1235
1235
  *
1236
+ * A serverless host prepares at deploy time instead: `manifest()` yields the manifest of exactly the
1237
+ * capsule `layer()` installs, a deploy stack hands it to `capsuledb/alchemy`, and the function boots
1238
+ * with `mode: "assert"` and `readiness: "first-use"`, which builds without a statement and checks the
1239
+ * database once, on the first Storage query.
1240
+ *
1236
1241
  * The layer requires only `SqlClient`: credentials arrive sealed, so Storage never needs `Custody`.
1237
1242
  */
1238
- var PgStorage_exports = /* @__PURE__ */ __exportAll({ layer: () => layer });
1239
- const layer = (options = {}) => Registry.layer({
1243
+ var PgStorage_exports = /* @__PURE__ */ __exportAll({
1244
+ layer: () => layer,
1245
+ manifest: () => manifest
1246
+ });
1247
+ /** The capsule and registry prefix `layer` and `manifest` both derive from one set of options. */
1248
+ const selection = (options) => ({
1240
1249
  provider: Pg.profile,
1241
1250
  capsules: [options.prefix === void 0 || options.prefix === "domainkit" ? capsule : make(options.prefix)],
1242
- ...options.mode === void 0 ? {} : { mode: options.mode },
1243
1251
  ...options.registryPrefix === void 0 ? {} : { prefix: options.registryPrefix }
1244
1252
  });
1253
+ const layer = (options = {}) => Registry.layer({
1254
+ ...selection(options),
1255
+ ...options.mode === void 0 ? {} : { mode: options.mode },
1256
+ ...options.readiness === void 0 ? {} : { readiness: options.readiness }
1257
+ });
1258
+ /**
1259
+ * The CapsuleDB manifest for exactly what `layer(options)` installs, computed without touching a
1260
+ * database. A deploy stack passes it to `CapsuleDB.Registry` from `capsuledb/alchemy`, so the
1261
+ * schema it prepares is the schema the runtime asserts. Only `prefix` and `registryPrefix` affect
1262
+ * it; `mode` and `readiness` are runtime choices.
1263
+ */
1264
+ const manifest = (options = {}) => Registry.manifest(selection(options));
1245
1265
  //#endregion
1246
1266
  //#region src/index.ts
1247
1267
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["Schema","make","make","makeTables","makeService","packageJson.version"],"sources":["../package.json","../src/internal/storage.ts","../src/internal/tables.ts","../src/capsule.ts","../src/PgStorage.ts","../src/index.ts"],"sourcesContent":["","/**\n * `Storage.Interface` on PostgreSQL.\n *\n * Every method reads `Principal` and filters by `owner_id`, so a row belonging to another tenant\n * is indistinguishable from a row that does not exist. Aggregate transitions run inside one\n * transaction over a `FOR UPDATE` row, single-flight guards use a session-level advisory lock on a\n * reserved connection, and revocation is two-phase: mark `pending`, call the provider outside any\n * transaction, then delete.\n *\n * `Connect` seals provider secret material through `Custody` before it reaches authorization\n * `upsert` or `rotate`. Continuation payloads, including PKCE verifiers, are stored as unsealed JSON.\n */\nimport { type Approval, DomainKit, type Plan, Principal, Reason, Storage } from \"domainkit\";\nimport { DateTime, Effect, Option, Schema } from \"effect\";\nimport * as SqlClient from \"effect/unstable/sql/SqlClient\";\nimport * as SqlError from \"effect/unstable/sql/SqlError\";\n\nimport type { Tables } from \"./tables.ts\";\n\ntype Fail = DomainKit.Error;\n\n// ---------------------------------------------------------------------------------------------\n// Errors\n// ---------------------------------------------------------------------------------------------\n\nconst fail = (reason: Reason.Model) => Effect.fail(new DomainKit.Error({ reason }));\n\nconst notFound = (entity: Reason.NotFound[\"entity\"], id: string) =>\n fail(new Reason.NotFound({ entity, id }));\n\nconst invalid = (message: string, field?: string) =>\n fail(new Reason.InvalidInput({ message, ...(field === undefined ? {} : { field }) }));\n\nconst busy = (key: string) => fail(new Reason.Busy({ key }));\n\nconst storageFailed = (operation: string, message: string) =>\n new DomainKit.Error({\n reason: new Reason.StorageFailed({ operation, message }),\n });\n\nconst sqlMessage = (error: SqlError.SqlError): string =>\n error.reason.cause instanceof Error\n ? `${error.reason._tag}: ${error.reason.cause.message}`\n : `${error.reason._tag}: ${String(error.reason.cause)}`;\n\n/**\n * Collapse the SQL error channel into `DomainKit.Error`.\n *\n * A `DomainKit.Error` raised by the body is the deliberate outcome of an invariant and passes\n * through unchanged; anything else is a driver failure and becomes `StorageFailed`.\n */\nconst guard =\n (operation: string) =>\n <A, R>(effect: Effect.Effect<A, SqlError.SqlError | Fail, R>): Effect.Effect<A, Fail, R> =>\n Effect.catch(effect, (error) =>\n Effect.fail(DomainKit.isError(error) ? error : storageFailed(operation, sqlMessage(error))),\n );\n\n// ---------------------------------------------------------------------------------------------\n// Row codecs\n// ---------------------------------------------------------------------------------------------\n\n/**\n * A row is stored as its schema's encoded form spread over columns, so the core schema stays the\n * only description of a row's shape. Reading reassembles the encoded object and decodes it.\n */\nconst codec = <S extends Schema.ConstraintCodec<unknown, unknown>>(schema: S, subject: string) => {\n const decode = Schema.decodeUnknownEffect(schema);\n const encode = Schema.encodeUnknownEffect(schema);\n return {\n read: (input: unknown): Effect.Effect<S[\"Type\"], Fail, S[\"DecodingServices\"]> =>\n decode(input).pipe(\n Effect.mapError((error) =>\n storageFailed(`${subject}.decode`, `stored ${subject} is invalid: ${error.message}`),\n ),\n ),\n write: (value: S[\"Type\"]): Effect.Effect<S[\"Encoded\"], Fail, S[\"EncodingServices\"]> =>\n encode(value).pipe(\n Effect.mapError((error) =>\n storageFailed(`${subject}.encode`, `${subject} cannot be stored: ${error.message}`),\n ),\n ),\n };\n};\n\nconst authorizationCodec = codec(Storage.Authorization, \"authorization\");\nconst connectionCodec = codec(Storage.Connection, \"connection\");\nconst attachmentCodec = codec(Storage.Attachment, \"attachment\");\nconst continuationCodec = codec(Storage.Continuation, \"continuation\");\nconst continuationHeaderCodec = codec(Storage.ContinuationHeader, \"continuation header\");\nconst attemptCodec = codec(Storage.Attempt, \"attempt\");\nconst batchCodec = codec(Storage.Batch, \"batch\");\nconst batchItemCodec = codec(Storage.BatchItem, \"batch item\");\nconst readinessCodec = codec(Storage.Readiness, \"readiness\");\nconst credentialCodec = codec(Storage.Credential, \"credential\");\n\n// ---------------------------------------------------------------------------------------------\n// Column conversions\n// ---------------------------------------------------------------------------------------------\n\n/** A `TIMESTAMPTZ` column as the ISO string every DomainKit timestamp schema encodes to. */\nconst iso = (value: unknown): string => {\n if (value instanceof Date) return value.toISOString();\n if (DateTime.isDateTime(value)) return DateTime.toDateUtc(value).toISOString();\n if (typeof value === \"number\") return new Date(value).toISOString();\n if (typeof value === \"string\") {\n const date = new Date(value);\n if (!Number.isNaN(date.getTime())) return date.toISOString();\n }\n return String(value);\n};\n\nconst isoOrNull = (value: unknown): string | null => (value === null ? null : iso(value));\n\n/** An ISO string from a schema's encoded form as the `Date` the driver binds to `TIMESTAMPTZ`. */\nconst at = (value: string): Date => new Date(value);\n\nconst atOrNull = (value: string | null): Date | null => (value === null ? null : at(value));\n\nconst now = Effect.map(DateTime.now, DateTime.toDateUtc);\n\n/**\n * A `JSONB` column as a plain value.\n *\n * Drivers disagree about whether they parse JSON columns, so accept both and normalize here\n * rather than depending on a host's client configuration.\n */\nconst fromJson = (value: unknown): unknown =>\n typeof value === \"string\" ? (JSON.parse(value) as unknown) : value;\n\nconst fromJsonOrNull = (value: unknown): unknown => (value === null ? null : fromJson(value));\n\n/** Bind a value to a `JSONB` column as text; PostgreSQL coerces the untyped parameter. */\nconst toJson = (value: unknown): string => JSON.stringify(value ?? null);\n\nconst toJsonOrNull = (value: unknown): string | null =>\n value === null || value === undefined ? null : toJson(value);\n\n// ---------------------------------------------------------------------------------------------\n// Row shapes\n// ---------------------------------------------------------------------------------------------\n\ninterface AuthorizationRow {\n readonly id: string;\n readonly owner_id: string;\n readonly provider: string;\n readonly method: string;\n readonly capabilities: unknown;\n readonly context: unknown;\n readonly label: string | null;\n readonly revocation: string;\n readonly created_by: string;\n readonly created_at: unknown;\n readonly credential_ciphertext: string;\n readonly credential_expires_at: unknown;\n readonly credential_rotated_at: unknown;\n}\n\ninterface ConnectionRow {\n readonly id: string;\n readonly owner_id: string;\n readonly authorization_id: string;\n readonly created_at: unknown;\n}\n\ninterface AttachmentRow {\n readonly id: string;\n readonly owner_id: string;\n readonly connection_id: string;\n readonly domain: string;\n readonly zone: string;\n readonly label: string;\n readonly target: unknown;\n readonly created_at: unknown;\n}\n\ninterface ContinuationRow {\n readonly id: string;\n readonly owner_id: string;\n readonly actor_id: string;\n readonly provider: string;\n readonly payload: unknown;\n readonly return_to: string | null;\n readonly expires_at: unknown;\n}\n\ninterface AttemptRow {\n readonly id: string;\n readonly owner_id: string;\n readonly attachment_id: string;\n readonly kind: string;\n readonly status: string;\n readonly plan: unknown;\n readonly approval: unknown;\n readonly receipt: unknown;\n readonly rejection: unknown;\n readonly source_receipt_id: string | null;\n readonly lease_expires_at: unknown;\n readonly failure: string | null;\n readonly updated_at: unknown;\n}\n\ninterface BatchRow {\n readonly id: string;\n readonly owner_id: string;\n readonly kind: string;\n readonly status: string;\n readonly digest: string | null;\n readonly approval: unknown;\n readonly rejection: unknown;\n readonly idempotency_key: string;\n readonly created_by: string;\n readonly created_at: unknown;\n readonly updated_at: unknown;\n readonly completed_at: unknown;\n}\n\ninterface BatchItemRow {\n readonly batch_id: string;\n readonly attachment_id: string;\n readonly position: number;\n readonly attempt_id: string | null;\n readonly plan_failure: string | null;\n}\n\n/** An item row with its attempt's status joined in; null while the item carries no plan. */\ninterface BatchItemStatusRow extends BatchItemRow {\n readonly attempt_status: string | null;\n}\n\ninterface ReadinessRow {\n readonly owner_id: string;\n readonly domain: string;\n readonly attachment_id: string | null;\n readonly overall: string;\n readonly requirements: unknown;\n readonly host: unknown;\n readonly pending_since: unknown;\n readonly checked_at: unknown;\n readonly next_check_at: unknown;\n}\n\nconst authorizationOf = (row: AuthorizationRow) =>\n authorizationCodec.read({\n id: row.id,\n ownerId: row.owner_id,\n provider: row.provider,\n method: row.method,\n capabilities: fromJson(row.capabilities),\n context: fromJson(row.context),\n label: row.label,\n revocation: row.revocation,\n createdBy: row.created_by,\n createdAt: iso(row.created_at),\n });\n\nconst credentialOf = (row: AuthorizationRow) =>\n credentialCodec.read({\n ciphertext: row.credential_ciphertext,\n expiresAt: isoOrNull(row.credential_expires_at),\n rotatedAt: iso(row.credential_rotated_at),\n });\n\nconst connectionOf = (row: ConnectionRow) =>\n connectionCodec.read({\n id: row.id,\n ownerId: row.owner_id,\n authorizationId: row.authorization_id,\n createdAt: iso(row.created_at),\n });\n\nconst attachmentOf = (row: AttachmentRow) =>\n attachmentCodec.read({\n id: row.id,\n ownerId: row.owner_id,\n connectionId: row.connection_id,\n domain: row.domain,\n zone: row.zone,\n label: row.label,\n target: fromJson(row.target),\n createdAt: iso(row.created_at),\n });\n\nconst continuationOf = (row: ContinuationRow) =>\n continuationCodec.read({\n id: row.id,\n ownerId: row.owner_id,\n actorId: row.actor_id,\n provider: row.provider,\n payload: fromJson(row.payload),\n returnTo: row.return_to,\n expiresAt: iso(row.expires_at),\n });\n\ntype ContinuationHeaderRow = Pick<\n ContinuationRow,\n \"owner_id\" | \"actor_id\" | \"provider\" | \"expires_at\"\n>;\n\nconst continuationHeaderOf = (row: ContinuationHeaderRow) =>\n continuationHeaderCodec.read({\n ownerId: row.owner_id,\n actorId: row.actor_id,\n provider: row.provider,\n expiresAt: iso(row.expires_at),\n });\n\nconst attemptOf = (row: AttemptRow) =>\n attemptCodec.read({\n id: row.id,\n ownerId: row.owner_id,\n attachmentId: row.attachment_id,\n kind: row.kind,\n status: row.status,\n plan: fromJson(row.plan),\n approval: fromJsonOrNull(row.approval),\n receipt: fromJsonOrNull(row.receipt),\n rejection: fromJsonOrNull(row.rejection),\n sourceReceiptId: row.source_receipt_id,\n leaseExpiresAt: isoOrNull(row.lease_expires_at),\n failure: row.failure,\n updatedAt: iso(row.updated_at),\n });\n\nconst batchOf = (row: BatchRow) =>\n batchCodec.read({\n id: row.id,\n ownerId: row.owner_id,\n kind: row.kind,\n status: row.status,\n digest: row.digest,\n approval: fromJsonOrNull(row.approval),\n rejection: fromJsonOrNull(row.rejection),\n idempotencyKey: row.idempotency_key,\n createdBy: row.created_by,\n createdAt: iso(row.created_at),\n updatedAt: iso(row.updated_at),\n completedAt: isoOrNull(row.completed_at),\n });\n\nconst batchItemOf = (row: BatchItemRow) =>\n batchItemCodec.read({\n batchId: row.batch_id,\n attachmentId: row.attachment_id,\n position: row.position,\n attemptId: row.attempt_id,\n planFailure: row.plan_failure,\n });\n\nconst readinessOf = (row: ReadinessRow) =>\n readinessCodec.read({\n domain: row.domain,\n attachmentId: row.attachment_id,\n ownerId: row.owner_id,\n overall: row.overall,\n requirements: fromJson(row.requirements),\n host: fromJson(row.host),\n pendingSince: isoOrNull(row.pending_since),\n checkedAt: iso(row.checked_at),\n nextCheckAt: isoOrNull(row.next_check_at),\n });\n\nconst stale = (attempt: Storage.Attempt) =>\n fail(new Reason.Stale({ planId: attempt.id, digest: attempt.plan.digest }));\n\nconst batchStale = (batch: Storage.Batch) =>\n fail(new Reason.BatchStale({ batchId: batch.id, status: batch.status, digest: batch.digest }));\n\n/** `prefix_<uuid>`, the same identifier shape the memory implementation mints. */\nconst fresh = (prefix: string) => Effect.sync(() => `${prefix}_${crypto.randomUUID()}`);\n\n// ---------------------------------------------------------------------------------------------\n// Service\n// ---------------------------------------------------------------------------------------------\n\nexport const make = (\n tables: Tables,\n): Effect.Effect<Storage.Interface, never, SqlClient.SqlClient> =>\n Effect.gen(function* () {\n const client = yield* SqlClient.SqlClient;\n // A host may configure result-name transforms for its own tables; these queries read the exact\n // snake_case columns the capsule declared.\n const sql = client.withoutTransforms();\n\n const authorizations = sql(tables.authorizations.name);\n const connections = sql(tables.connections.name);\n const attachments = sql(tables.attachments.name);\n const continuations = sql(tables.continuations.name);\n const attempts = sql(tables.attempts.name);\n const readiness = sql(tables.readiness.name);\n const batches = sql(tables.batches.name);\n const batchItems = sql(tables.batchItems.name);\n\n /** The row this principal owns, locked for the rest of the transaction. */\n const lockedAuthorization = (owner: string, id: string) =>\n sql<AuthorizationRow>`\n SELECT * FROM ${authorizations} WHERE id = ${id} AND owner_id = ${owner} FOR UPDATE\n `.pipe(\n Effect.flatMap((rows) =>\n rows[0] === undefined ? notFound(\"authorization\", id) : Effect.succeed(rows[0]),\n ),\n );\n\n const lockedAttempt = (owner: string, id: string) =>\n sql<AttemptRow>`\n SELECT * FROM ${attempts} WHERE id = ${id} AND owner_id = ${owner} FOR UPDATE\n `.pipe(\n Effect.flatMap((rows) =>\n rows[0] === undefined ? notFound(\"plan\", id) : Effect.succeed(rows[0]),\n ),\n Effect.flatMap(attemptOf),\n );\n\n const requireConnection = (owner: string, id: string) =>\n sql<ConnectionRow>`\n SELECT * FROM ${connections} WHERE id = ${id} AND owner_id = ${owner}\n `.pipe(\n Effect.flatMap((rows) =>\n rows[0] === undefined ? notFound(\"connection\", id) : Effect.succeed(rows[0]),\n ),\n );\n\n const requireAttachment = (owner: string, id: string) =>\n sql<AttachmentRow>`\n SELECT * FROM ${attachments} WHERE id = ${id} AND owner_id = ${owner}\n `.pipe(\n Effect.flatMap((rows) =>\n rows[0] === undefined ? notFound(\"attachment\", id) : Effect.succeed(rows[0]),\n ),\n );\n\n const writeAuthorization = (\n authorization: Storage.Authorization,\n credential: Storage.Credential,\n ) =>\n Effect.all({\n row: authorizationCodec.write(authorization),\n secret: credentialCodec.write(credential),\n });\n\n /**\n * Phase one of revocation: mark the row `pending` so a crash between the provider call and the\n * delete is recoverable. Idempotent, and it never widens the row's state.\n *\n * Returns the ciphertext the caller is about to have revoked, which phase two checks.\n */\n const prepareRevocation = (owner: string, id: string) =>\n sql.withTransaction(\n Effect.gen(function* () {\n const row = yield* lockedAuthorization(owner, id);\n yield* sql`\n UPDATE ${authorizations} SET revocation = 'pending', updated_at = ${yield* now}\n WHERE id = ${id} AND owner_id = ${owner}\n `;\n return row.credential_ciphertext;\n }),\n );\n\n /**\n * Phase two: delete the row, but only while it still holds the credential the provider was\n * asked to revoke.\n *\n * A credential refresh runs concurrently with revocation and rotates the row after the provider\n * call selected the old ciphertext. Deleting unconditionally would drop the row while the newly\n * issued credential is still live at the provider, with no local state left to revoke it from.\n * Leaving the row `pending` instead hands it to `recoverRevocations`, which revokes what the\n * row now holds. Every ciphertext is AES-GCM with a fresh IV, so equality here is exact.\n */\n const completeRevocation = (owner: string, id: string, ciphertext: string) =>\n sql`\n DELETE FROM ${authorizations}\n WHERE id = ${id} AND owner_id = ${owner} AND credential_ciphertext = ${ciphertext}\n `;\n\n const requireBatch = (owner: string, id: string) =>\n sql<BatchRow>`\n SELECT * FROM ${batches} WHERE id = ${id} AND owner_id = ${owner}\n `.pipe(\n Effect.flatMap((rows) =>\n rows[0] === undefined ? notFound(\"batch\", id) : Effect.succeed(rows[0]),\n ),\n Effect.flatMap(batchOf),\n );\n\n /** The batch this principal owns, locked for the rest of the transaction. */\n const lockedBatch = (owner: string, id: string) =>\n sql<BatchRow>`\n SELECT * FROM ${batches} WHERE id = ${id} AND owner_id = ${owner} FOR UPDATE\n `.pipe(\n Effect.flatMap((rows) =>\n rows[0] === undefined ? notFound(\"batch\", id) : Effect.succeed(rows[0]),\n ),\n Effect.flatMap(batchOf),\n );\n\n const requireAttempt = (owner: string, id: string) =>\n sql<AttemptRow>`\n SELECT * FROM ${attempts} WHERE id = ${id} AND owner_id = ${owner}\n `.pipe(\n Effect.flatMap((rows) =>\n rows[0] === undefined ? notFound(\"plan\", id) : Effect.succeed(rows[0]),\n ),\n );\n\n /**\n * A batch's items in `position` order, each with its attempt's status, which is what the\n * aggregate's own status is recomputed from. The batch was already read under its owner, and\n * the join carries the same filter so an item can only ever reach that owner's attempts.\n */\n const itemRows = (owner: string, batchId: string) =>\n sql<BatchItemStatusRow>`\n SELECT item.batch_id, item.attachment_id, item.\"position\", item.attempt_id,\n item.plan_failure, attempt.status AS attempt_status\n FROM ${batchItems} AS item\n LEFT JOIN ${attempts} AS attempt\n ON attempt.id = item.attempt_id AND attempt.owner_id = ${owner}\n WHERE item.batch_id = ${batchId}\n ORDER BY item.\"position\" ASC\n `;\n\n const aggregateOf = (\n owner: string,\n batch: Storage.Batch,\n ): Effect.Effect<Storage.BatchAggregate, Fail | SqlError.SqlError> =>\n itemRows(owner, batch.id).pipe(\n Effect.flatMap((rows) => Effect.forEach(rows, batchItemOf)),\n Effect.map((items) => ({ batch, items })),\n );\n\n /**\n * Write `batch` with its status recomputed from the items' attempts.\n *\n * Every transition ends here, inside the transaction that locked the row, so the stored status\n * and the owner-scoped unfinished index never disagree with the attempts they summarize.\n */\n const settled = (\n owner: string,\n batch: Storage.Batch,\n ): Effect.Effect<Storage.BatchAggregate, Fail | SqlError.SqlError> =>\n Effect.gen(function* () {\n const rows = yield* itemRows(owner, batch.id);\n const items = yield* Effect.forEach(rows, batchItemOf);\n const status = Storage.batchStatusOf({\n approved: batch.approval !== null,\n rejected: batch.rejection !== null,\n items: rows.map((row) =>\n row.attempt_id === null ? null : (row.attempt_status as Storage.AttemptStatus | null),\n ),\n });\n const instant = yield* DateTime.now;\n const next = new Storage.Batch({\n ...batch,\n status,\n completedAt: status === \"complete\" || status === \"rejected\" ? instant : null,\n updatedAt: instant,\n });\n const encoded = yield* batchCodec.write(next);\n yield* sql`\n UPDATE ${batches} SET\n status = ${encoded.status},\n digest = ${encoded.digest},\n approval = ${toJsonOrNull(encoded.approval)},\n rejection = ${toJsonOrNull(encoded.rejection)},\n completed_at = ${atOrNull(encoded.completedAt)},\n updated_at = ${at(encoded.updatedAt)}\n WHERE id = ${batch.id} AND owner_id = ${owner}\n `;\n return { batch: next, items };\n });\n\n const service: Storage.Interface = {\n authorizations: {\n upsert: ({ authorization, credential, expectedId }) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n Effect.gen(function* () {\n if (authorization.ownerId !== ownerId) {\n return yield* invalid(\n \"Authorization owner does not match the principal\",\n \"ownerId\",\n );\n }\n const { row, secret } = yield* writeAuthorization(authorization, credential);\n const stamp = yield* now;\n return yield* sql.withTransaction(\n Effect.gen(function* () {\n if (expectedId !== undefined) {\n const current = yield* lockedAuthorization(ownerId, expectedId);\n if (current.revocation !== \"active\") {\n return yield* busy(`authorization:${expectedId}`);\n }\n if (authorization.id !== expectedId) {\n return yield* invalid(\"Authorization id must match expectedId\", \"id\");\n }\n // A replace overwrites every column the caller supplied, including `created_at`:\n // the row it returns has to be the row a later `get` reads back.\n yield* sql`\n UPDATE ${authorizations} SET\n provider = ${row.provider},\n method = ${row.method},\n capabilities = ${toJson(row.capabilities)},\n context = ${toJson(row.context)},\n label = ${row.label},\n revocation = ${row.revocation},\n created_by = ${row.createdBy},\n created_at = ${at(row.createdAt)},\n credential_ciphertext = ${secret.ciphertext},\n credential_expires_at = ${atOrNull(secret.expiresAt)},\n credential_rotated_at = ${at(secret.rotatedAt)},\n updated_at = ${stamp}\n WHERE id = ${expectedId} AND owner_id = ${ownerId}\n `;\n return authorization;\n }\n // An id already taken by any tenant is a caller defect, not a missing row, so the\n // insert claims it atomically instead of racing a prior existence check.\n const inserted = yield* sql<{ readonly id: string }>`\n INSERT INTO ${authorizations} (\n id, owner_id, provider, method, capabilities, context, label, revocation,\n created_by, created_at, credential_ciphertext, credential_expires_at,\n credential_rotated_at, updated_at\n ) VALUES (\n ${row.id}, ${row.ownerId}, ${row.provider}, ${row.method},\n ${toJson(row.capabilities)}, ${toJson(row.context)}, ${row.label},\n ${row.revocation},\n ${row.createdBy}, ${at(row.createdAt)}, ${secret.ciphertext},\n ${atOrNull(secret.expiresAt)}, ${at(secret.rotatedAt)}, ${stamp}\n ) ON CONFLICT (id) DO NOTHING RETURNING id\n `;\n return inserted[0] === undefined\n ? yield* invalid(`Authorization ${authorization.id} already exists`, \"id\")\n : authorization;\n }),\n );\n }),\n ).pipe(guard(\"authorizations.upsert\")),\n get: (id) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n sql<AuthorizationRow>`\n SELECT * FROM ${authorizations} WHERE id = ${id} AND owner_id = ${ownerId}\n `.pipe(\n Effect.flatMap((rows) =>\n rows[0] === undefined ? notFound(\"authorization\", id) : authorizationOf(rows[0]),\n ),\n ),\n ).pipe(guard(\"authorizations.get\")),\n credential: (id) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n sql<AuthorizationRow>`\n SELECT * FROM ${authorizations} WHERE id = ${id} AND owner_id = ${ownerId}\n `.pipe(\n Effect.flatMap((rows) =>\n rows[0] === undefined ? notFound(\"authorization\", id) : credentialOf(rows[0]),\n ),\n ),\n ).pipe(guard(\"authorizations.credential\")),\n rotate: (id, credential) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n Effect.gen(function* () {\n const secret = yield* credentialCodec.write(credential);\n const updated = yield* sql<{ readonly id: string }>`\n UPDATE ${authorizations} SET\n credential_ciphertext = ${secret.ciphertext},\n credential_expires_at = ${atOrNull(secret.expiresAt)},\n credential_rotated_at = ${at(secret.rotatedAt)},\n updated_at = ${yield* now}\n WHERE id = ${id} AND owner_id = ${ownerId} RETURNING id\n `;\n if (updated[0] === undefined) return yield* notFound(\"authorization\", id);\n }),\n ).pipe(guard(\"authorizations.rotate\")),\n promoteCapabilities: (id, capabilities) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n sql.withTransaction(\n Effect.gen(function* () {\n const current = yield* authorizationOf(yield* lockedAuthorization(ownerId, id));\n const merged = [...new Set([...current.capabilities, ...capabilities])];\n yield* sql`\n UPDATE ${authorizations}\n SET capabilities = ${toJson(merged)}, updated_at = ${yield* now}\n WHERE id = ${id} AND owner_id = ${ownerId}\n `;\n }),\n ),\n ).pipe(guard(\"authorizations.promoteCapabilities\")),\n revoke: (id, revoke) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n Effect.gen(function* () {\n const ciphertext = yield* prepareRevocation(ownerId, id).pipe(\n guard(\"authorizations.revoke\"),\n );\n yield* revoke;\n yield* completeRevocation(ownerId, id, ciphertext).pipe(\n guard(\"authorizations.completeRevocation\"),\n );\n }),\n ),\n recoverRevocations: (revoke) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n Effect.gen(function* () {\n const rows = yield* sql<AuthorizationRow>`\n SELECT * FROM ${authorizations}\n WHERE owner_id = ${ownerId} AND revocation = 'pending'\n ORDER BY created_at\n `.pipe(guard(\"authorizations.pendingRevocations\"));\n yield* Effect.forEach(rows, (row) =>\n Effect.gen(function* () {\n yield* revoke(yield* authorizationOf(row));\n yield* completeRevocation(ownerId, row.id, row.credential_ciphertext).pipe(\n guard(\"authorizations.completeRevocation\"),\n );\n }),\n );\n return rows.length;\n }),\n ),\n },\n connections: {\n create: (authorizationId) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n sql.withTransaction(\n Effect.gen(function* () {\n yield* lockedAuthorization(ownerId, authorizationId);\n const row = new Storage.Connection({\n id: yield* fresh(\"conn\"),\n ownerId,\n authorizationId,\n createdAt: yield* DateTime.now,\n });\n const encoded = yield* connectionCodec.write(row);\n yield* sql`\n INSERT INTO ${connections} (id, owner_id, authorization_id, created_at)\n VALUES (${encoded.id}, ${encoded.ownerId}, ${encoded.authorizationId},\n ${at(encoded.createdAt)})\n `;\n return row;\n }),\n ),\n ).pipe(guard(\"connections.create\")),\n get: (id) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n Effect.flatMap(requireConnection(ownerId, id), connectionOf),\n ).pipe(guard(\"connections.get\")),\n list: (filter) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n Effect.flatMap(\n filter?.provider === undefined\n ? sql<ConnectionRow>`\n SELECT * FROM ${connections} WHERE owner_id = ${ownerId} ORDER BY created_at\n `\n : sql<ConnectionRow>`\n SELECT c.* FROM ${connections} AS c\n JOIN ${authorizations} AS a ON a.id = c.authorization_id\n WHERE c.owner_id = ${ownerId} AND a.provider = ${filter.provider}\n ORDER BY c.created_at\n `,\n (rows) => Effect.forEach(rows, connectionOf),\n ),\n ).pipe(guard(\"connections.list\")),\n remove: (id) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n sql.withTransaction(\n Effect.gen(function* () {\n const rows = yield* sql<ConnectionRow>`\n SELECT * FROM ${connections}\n WHERE id = ${id} AND owner_id = ${ownerId} FOR UPDATE\n `;\n if (rows[0] === undefined) return yield* notFound(\"connection\", id);\n const held = yield* sql<{ readonly id: string }>`\n SELECT id FROM ${attachments}\n WHERE connection_id = ${id} AND owner_id = ${ownerId} LIMIT 1\n `;\n if (held[0] !== undefined) {\n return yield* invalid(`Connection ${id} still has attachments`, \"connectionId\");\n }\n yield* sql`DELETE FROM ${connections} WHERE id = ${id} AND owner_id = ${ownerId}`;\n }),\n ),\n ).pipe(guard(\"connections.remove\")),\n },\n attachments: {\n create: (input) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n sql.withTransaction(\n Effect.gen(function* () {\n yield* requireConnection(ownerId, input.connectionId);\n const row = new Storage.Attachment({\n id: yield* fresh(\"att\"),\n ownerId,\n connectionId: input.connectionId,\n domain: input.domain,\n zone: input.zone,\n label: input.label,\n target: input.target,\n createdAt: yield* DateTime.now,\n });\n const encoded = yield* attachmentCodec.write(row);\n // The unique (owner_id, domain) constraint decides the duplicate, so two concurrent\n // attaches cannot both win.\n const inserted = yield* sql<{ readonly id: string }>`\n INSERT INTO ${attachments} (\n id, owner_id, connection_id, domain, zone, label, target, created_at\n ) VALUES (\n ${encoded.id}, ${encoded.ownerId}, ${encoded.connectionId}, ${encoded.domain},\n ${encoded.zone}, ${encoded.label}, ${toJson(encoded.target)},\n ${at(encoded.createdAt)}\n ) ON CONFLICT (owner_id, domain) DO NOTHING RETURNING id\n `;\n return inserted[0] === undefined\n ? yield* invalid(`${input.domain} is already attached`, \"domain\")\n : row;\n }),\n ),\n ).pipe(guard(\"attachments.create\")),\n get: (id) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n Effect.flatMap(requireAttachment(ownerId, id), attachmentOf),\n ).pipe(guard(\"attachments.get\")),\n byDomain: (domain) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n sql<AttachmentRow>`\n SELECT * FROM ${attachments} WHERE owner_id = ${ownerId} AND domain = ${domain}\n `.pipe(\n Effect.flatMap((rows) =>\n rows[0] === undefined\n ? Effect.succeedNone\n : Effect.map(attachmentOf(rows[0]), Option.some),\n ),\n ),\n ).pipe(guard(\"attachments.byDomain\")),\n list: (connectionId) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n Effect.gen(function* () {\n yield* requireConnection(ownerId, connectionId);\n const rows = yield* sql<AttachmentRow>`\n SELECT * FROM ${attachments}\n WHERE owner_id = ${ownerId} AND connection_id = ${connectionId}\n ORDER BY created_at\n `;\n return yield* Effect.forEach(rows, attachmentOf);\n }),\n ).pipe(guard(\"attachments.list\")),\n remove: (id) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n sql.withTransaction(\n Effect.gen(function* () {\n yield* requireAttachment(ownerId, id);\n // Readiness is keyed by domain and outlives the attachment, so clear the link\n // rather than the row: what was observed about the domain is still true, and a\n // dangling attachment id would fail the next `readiness.put`.\n yield* sql`\n UPDATE ${readiness} SET attachment_id = NULL\n WHERE attachment_id = ${id} AND owner_id = ${ownerId}\n `;\n yield* sql`DELETE FROM ${attachments} WHERE id = ${id} AND owner_id = ${ownerId}`;\n }),\n ),\n ).pipe(guard(\"attachments.remove\")),\n },\n continuations: {\n put: (continuation) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n Effect.gen(function* () {\n if (continuation.ownerId !== ownerId) {\n return yield* invalid(\"Continuation owner does not match the principal\", \"ownerId\");\n }\n const encoded = yield* continuationCodec.write(continuation);\n yield* sql`\n INSERT INTO ${continuations} (\n id, owner_id, actor_id, provider, payload, return_to, expires_at\n ) VALUES (\n ${encoded.id}, ${encoded.ownerId}, ${encoded.actorId}, ${encoded.provider},\n ${toJson(encoded.payload)}, ${encoded.returnTo}, ${at(encoded.expiresAt)}\n ) ON CONFLICT (id) DO UPDATE SET\n owner_id = EXCLUDED.owner_id,\n actor_id = EXCLUDED.actor_id,\n provider = EXCLUDED.provider,\n payload = EXCLUDED.payload,\n return_to = EXCLUDED.return_to,\n expires_at = EXCLUDED.expires_at\n `;\n }),\n ).pipe(guard(\"continuations.put\")),\n get: (id) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n Effect.gen(function* () {\n // A read, not a claim: the row survives so `consume` can still spend it.\n const rows = yield* sql<ContinuationRow>`\n SELECT * FROM ${continuations} WHERE id = ${id} AND owner_id = ${ownerId}\n `;\n if (rows[0] === undefined) return yield* notFound(\"continuation\", id);\n const continuation = yield* continuationOf(rows[0]);\n const instant = yield* DateTime.now;\n return DateTime.toEpochMillis(continuation.expiresAt) <=\n DateTime.toEpochMillis(instant)\n ? yield* fail(new Reason.Expired({ entity: \"continuation\", id }))\n : continuation;\n }),\n ).pipe(guard(\"continuations.get\")),\n header: (id) =>\n Effect.gen(function* () {\n // No owner filter, unlike everything else in this module: the provider callback has to\n // learn whose flow it is finishing before it can resolve a principal to scope by. The\n // projection is the enforcement — `payload` is never selected, so the PKCE verifier\n // stays behind the owner-scoped `get`.\n const rows = yield* sql<ContinuationHeaderRow>`\n SELECT owner_id, actor_id, provider, expires_at\n FROM ${continuations} WHERE id = ${id}\n `;\n if (rows[0] === undefined) return yield* notFound(\"continuation\", id);\n const header = yield* continuationHeaderOf(rows[0]);\n const instant = yield* DateTime.now;\n return DateTime.toEpochMillis(header.expiresAt) <= DateTime.toEpochMillis(instant)\n ? yield* fail(new Reason.Expired({ entity: \"continuation\", id }))\n : header;\n }).pipe(guard(\"continuations.header\")),\n consume: (id) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n Effect.gen(function* () {\n // The delete is the claim: a second consume finds nothing, expired or not.\n const rows = yield* sql<ContinuationRow>`\n DELETE FROM ${continuations}\n WHERE id = ${id} AND owner_id = ${ownerId} RETURNING *\n `;\n if (rows[0] === undefined) return yield* notFound(\"continuation\", id);\n const continuation = yield* continuationOf(rows[0]);\n const instant = yield* DateTime.now;\n return DateTime.toEpochMillis(continuation.expiresAt) <=\n DateTime.toEpochMillis(instant)\n ? yield* fail(new Reason.Expired({ entity: \"continuation\", id }))\n : continuation;\n }),\n ).pipe(guard(\"continuations.consume\")),\n },\n attempts: {\n create: (attempt) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n Effect.gen(function* () {\n if (attempt.ownerId !== ownerId) {\n return yield* invalid(\"Attempt owner does not match the principal\", \"ownerId\");\n }\n const encoded = yield* attemptCodec.write(attempt);\n const inserted = yield* sql<{ readonly id: string }>`\n INSERT INTO ${attempts} (\n id, owner_id, attachment_id, kind, status, plan, approval, approval_id,\n receipt, receipt_id, rejection, source_receipt_id, lease_expires_at, failure,\n plan_created_at, updated_at\n ) VALUES (\n ${encoded.id}, ${encoded.ownerId}, ${encoded.attachmentId}, ${encoded.kind},\n ${encoded.status}, ${toJson(encoded.plan)}, ${toJsonOrNull(encoded.approval)},\n ${attempt.approval?.id ?? null}, ${toJsonOrNull(encoded.receipt)},\n ${attempt.receipt?.id ?? null}, ${toJsonOrNull(encoded.rejection)},\n ${encoded.sourceReceiptId},\n ${atOrNull(encoded.leaseExpiresAt)}, ${encoded.failure},\n ${at(encoded.plan.createdAt)}, ${at(encoded.updatedAt)}\n ) ON CONFLICT (id) DO NOTHING RETURNING id\n `;\n return inserted[0] === undefined\n ? yield* invalid(`Plan ${attempt.id} already exists`, \"id\")\n : attempt;\n }),\n ).pipe(guard(\"attempts.create\")),\n get: (id) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n sql<AttemptRow>`\n SELECT * FROM ${attempts} WHERE id = ${id} AND owner_id = ${ownerId}\n `.pipe(\n Effect.flatMap((rows) =>\n rows[0] === undefined ? notFound(\"plan\", id) : attemptOf(rows[0]),\n ),\n ),\n ).pipe(guard(\"attempts.get\")),\n byApproval: (id) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n sql<AttemptRow>`\n SELECT * FROM ${attempts} WHERE approval_id = ${id} AND owner_id = ${ownerId}\n `.pipe(\n Effect.flatMap((rows) =>\n rows[0] === undefined ? notFound(\"approval\", id) : attemptOf(rows[0]),\n ),\n ),\n ).pipe(guard(\"attempts.byApproval\")),\n byReceipt: (id) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n sql<AttemptRow>`\n SELECT * FROM ${attempts} WHERE receipt_id = ${id} AND owner_id = ${ownerId}\n `.pipe(\n Effect.flatMap((rows) =>\n rows[0] === undefined ? notFound(\"receipt\", id) : attemptOf(rows[0]),\n ),\n ),\n ).pipe(guard(\"attempts.byReceipt\")),\n latest: (attachmentId, kind) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n sql<AttemptRow>`\n SELECT * FROM ${attempts}\n WHERE owner_id = ${ownerId} AND attachment_id = ${attachmentId} AND kind = ${kind}\n ORDER BY plan_created_at DESC, updated_at DESC LIMIT 1\n `.pipe(\n Effect.flatMap((rows) =>\n rows[0] === undefined\n ? Effect.succeedNone\n : Effect.map(attemptOf(rows[0]), Option.some),\n ),\n ),\n ).pipe(guard(\"attempts.latest\")),\n approve: (id, approval) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n sql.withTransaction(\n Effect.gen(function* () {\n const current = yield* lockedAttempt(ownerId, id);\n // Replaying the same approval is how a retried request stays safe.\n if (current.approval?.id === approval.id) return current;\n if (current.status !== \"planned\") return yield* stale(current);\n const next = new Storage.Attempt({\n ...current,\n status: \"approved\",\n approval,\n updatedAt: yield* DateTime.now,\n });\n const encoded = yield* attemptCodec.write(next);\n yield* sql`\n UPDATE ${attempts} SET\n status = ${encoded.status},\n approval = ${toJsonOrNull(encoded.approval)},\n approval_id = ${approval.id},\n updated_at = ${at(encoded.updatedAt)}\n WHERE id = ${id} AND owner_id = ${ownerId}\n `;\n return next;\n }),\n ),\n ).pipe(guard(\"attempts.approve\")),\n reject: (id, input) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n sql.withTransaction(\n Effect.gen(function* () {\n const current = yield* lockedAttempt(ownerId, id);\n // Terminal: a second rejection is the same outcome, so it returns the first one.\n if (current.status === \"rejected\") return current;\n if (current.status === \"expired\") {\n return yield* fail(new Reason.Expired({ entity: \"plan\", id }));\n }\n // A digest mismatch means the reviewer declined a plan that is no longer current.\n if (current.status !== \"planned\" || current.plan.digest !== input.digest) {\n return yield* stale(current);\n }\n const instant = yield* DateTime.now;\n const next = new Storage.Attempt({\n ...current,\n status: \"rejected\",\n rejection: { actorId: input.actorId, reason: input.reason, at: instant },\n updatedAt: instant,\n });\n const encoded = yield* attemptCodec.write(next);\n yield* sql`\n UPDATE ${attempts} SET\n status = ${encoded.status},\n rejection = ${toJsonOrNull(encoded.rejection)},\n updated_at = ${at(encoded.updatedAt)}\n WHERE id = ${id} AND owner_id = ${ownerId}\n `;\n return next;\n }),\n ),\n ).pipe(guard(\"attempts.reject\")),\n claim: (id, lease) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n sql.withTransaction(\n Effect.gen(function* () {\n const current = yield* lockedAttempt(ownerId, id);\n const instant = yield* DateTime.now;\n if (current.status === \"applying\") {\n const held =\n current.leaseExpiresAt !== null &&\n DateTime.toEpochMillis(current.leaseExpiresAt) >\n DateTime.toEpochMillis(instant);\n if (held) return yield* busy(`apply:${id}`);\n } else if (current.status !== \"approved\" && current.status !== \"failed\") {\n return yield* stale(current);\n }\n const next = new Storage.Attempt({\n ...current,\n status: \"applying\",\n leaseExpiresAt: lease,\n failure: null,\n updatedAt: instant,\n });\n const encoded = yield* attemptCodec.write(next);\n yield* sql`\n UPDATE ${attempts} SET\n status = ${encoded.status},\n lease_expires_at = ${atOrNull(encoded.leaseExpiresAt)},\n failure = NULL,\n updated_at = ${at(encoded.updatedAt)}\n WHERE id = ${id} AND owner_id = ${ownerId}\n `;\n return next;\n }),\n ),\n ).pipe(guard(\"attempts.claim\")),\n complete: (id, receipt) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n sql.withTransaction(\n Effect.gen(function* () {\n const current = yield* lockedAttempt(ownerId, id);\n if (current.status !== \"applying\") return yield* stale(current);\n const next = new Storage.Attempt({\n ...current,\n status: receipt.status,\n receipt,\n leaseExpiresAt: null,\n updatedAt: yield* DateTime.now,\n });\n const encoded = yield* attemptCodec.write(next);\n yield* sql`\n UPDATE ${attempts} SET\n status = ${encoded.status},\n receipt = ${toJsonOrNull(encoded.receipt)},\n receipt_id = ${receipt.id},\n lease_expires_at = NULL,\n updated_at = ${at(encoded.updatedAt)}\n WHERE id = ${id} AND owner_id = ${ownerId}\n `;\n return next;\n }),\n ),\n ).pipe(guard(\"attempts.complete\")),\n fail: (id, message) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n sql.withTransaction(\n Effect.gen(function* () {\n const current = yield* lockedAttempt(ownerId, id);\n if (current.status !== \"applying\") return yield* stale(current);\n const next = new Storage.Attempt({\n ...current,\n status: \"failed\",\n failure: message,\n leaseExpiresAt: null,\n updatedAt: yield* DateTime.now,\n });\n const encoded = yield* attemptCodec.write(next);\n yield* sql`\n UPDATE ${attempts} SET\n status = ${encoded.status},\n failure = ${message},\n lease_expires_at = NULL,\n updated_at = ${at(encoded.updatedAt)}\n WHERE id = ${id} AND owner_id = ${ownerId}\n `;\n return next;\n }),\n ),\n ).pipe(guard(\"attempts.fail\")),\n },\n batches: {\n create: (input) =>\n Effect.flatMap(Principal.Service, ({ actorId, ownerId }) =>\n sql.withTransaction(\n Effect.gen(function* () {\n const replayed = (row: BatchRow) =>\n Effect.flatMap(batchOf(row), (batch) => aggregateOf(ownerId, batch));\n const existing = yield* sql<BatchRow>`\n SELECT * FROM ${batches}\n WHERE owner_id = ${ownerId} AND idempotency_key = ${input.idempotencyKey}\n `;\n // A retried create is the same batch, whatever the second call asks for.\n if (existing[0] !== undefined) return yield* replayed(existing[0]);\n if (input.attachmentIds.length === 0) {\n return yield* invalid(\"A batch needs at least one attachment\", \"attachmentIds\");\n }\n if (new Set(input.attachmentIds).size !== input.attachmentIds.length) {\n return yield* invalid(\"A batch holds one item per attachment\", \"attachmentIds\");\n }\n for (const attachmentId of input.attachmentIds) {\n yield* requireAttachment(ownerId, attachmentId);\n }\n const instant = yield* DateTime.now;\n const batch = new Storage.Batch({\n id: Storage.BatchId.make(yield* fresh(\"batch\")),\n ownerId,\n kind: input.kind,\n status: \"planning\",\n digest: null,\n approval: null,\n rejection: null,\n idempotencyKey: input.idempotencyKey,\n createdBy: actorId,\n createdAt: instant,\n updatedAt: instant,\n completedAt: null,\n });\n const encoded = yield* batchCodec.write(batch);\n // The unique key decides the race rather than the read above: a concurrent create\n // under the same key loses the insert and reads the batch it lost to.\n const inserted = yield* sql<{ readonly id: string }>`\n INSERT INTO ${batches} (\n id, owner_id, kind, status, digest, approval, rejection, idempotency_key,\n created_by, created_at, updated_at, completed_at\n ) VALUES (\n ${encoded.id}, ${encoded.ownerId}, ${encoded.kind}, ${encoded.status},\n ${encoded.digest}, ${toJsonOrNull(encoded.approval)},\n ${toJsonOrNull(encoded.rejection)}, ${encoded.idempotencyKey},\n ${encoded.createdBy}, ${at(encoded.createdAt)}, ${at(encoded.updatedAt)},\n ${atOrNull(encoded.completedAt)}\n ) ON CONFLICT (owner_id, idempotency_key) DO NOTHING RETURNING id\n `;\n if (inserted[0] === undefined) {\n const winner = yield* sql<BatchRow>`\n SELECT * FROM ${batches}\n WHERE owner_id = ${ownerId} AND idempotency_key = ${input.idempotencyKey}\n `;\n return winner[0] === undefined\n ? yield* notFound(\"batch\", input.idempotencyKey)\n : yield* replayed(winner[0]);\n }\n const items = input.attachmentIds.map(\n (attachmentId, position) =>\n new Storage.BatchItem({\n batchId: batch.id,\n attachmentId,\n position,\n attemptId: null,\n planFailure: null,\n }),\n );\n for (const item of items) {\n yield* sql`\n INSERT INTO ${batchItems} (\n batch_id, attachment_id, \"position\", attempt_id, plan_failure\n ) VALUES (\n ${item.batchId}, ${item.attachmentId}, ${item.position}, ${item.attemptId},\n ${item.planFailure}\n )\n `;\n }\n return { batch, items };\n }),\n ),\n ).pipe(guard(\"batches.create\")),\n get: (id) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n Effect.flatMap(requireBatch(ownerId, id), (batch) => aggregateOf(ownerId, batch)),\n ).pipe(guard(\"batches.get\")),\n byIdempotencyKey: (key) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n sql<BatchRow>`\n SELECT * FROM ${batches}\n WHERE owner_id = ${ownerId} AND idempotency_key = ${key}\n `.pipe(\n Effect.flatMap((rows) =>\n rows[0] === undefined\n ? Effect.succeedNone\n : Effect.flatMap(batchOf(rows[0]), (batch) =>\n Effect.map(aggregateOf(ownerId, batch), Option.some),\n ),\n ),\n ),\n ).pipe(guard(\"batches.byIdempotencyKey\")),\n listUnfinished: () =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n Effect.gen(function* () {\n const rows = yield* sql<BatchRow>`\n SELECT * FROM ${batches}\n WHERE owner_id = ${ownerId} AND status NOT IN ('complete', 'rejected')\n ORDER BY updated_at DESC\n `;\n if (rows.length === 0) return [];\n const list = yield* Effect.forEach(rows, batchOf);\n // Items are pointers, so the whole index is two queries: no attempt is read here.\n const itemsRows = yield* sql<BatchItemRow>`\n SELECT batch_id, attachment_id, \"position\", attempt_id, plan_failure\n FROM ${batchItems}\n WHERE ${sql.in(\n \"batch_id\",\n list.map(({ id }) => id),\n )}\n ORDER BY \"position\" ASC\n `;\n const items = yield* Effect.forEach(itemsRows, batchItemOf);\n return list.map((batch) => ({\n batch,\n items: items.filter((item) => item.batchId === batch.id),\n }));\n }),\n ).pipe(guard(\"batches.listUnfinished\")),\n recordItemPlan: (id, attachmentId, attemptId) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n sql.withTransaction(\n Effect.gen(function* () {\n const batch = yield* lockedBatch(ownerId, id);\n // The fence: a planning pass still in flight must not land state on a batch the\n // principal declined, or on one already bound to an approved digest.\n if (batch.status !== \"planning\" && batch.status !== \"planned\") {\n return yield* batchStale(batch);\n }\n const attempt = yield* requireAttempt(ownerId, attemptId);\n if (attempt.attachment_id !== attachmentId || attempt.kind !== batch.kind) {\n return yield* invalid(\n `Plan ${attemptId} does not belong to attachment ${attachmentId} in this batch`,\n \"attemptId\",\n );\n }\n const updated = yield* sql<{ readonly attachment_id: string }>`\n UPDATE ${batchItems} SET attempt_id = ${attemptId}, plan_failure = NULL\n WHERE batch_id = ${id} AND attachment_id = ${attachmentId}\n RETURNING attachment_id\n `;\n return updated[0] === undefined\n ? yield* notFound(\"attachment\", attachmentId)\n : yield* settled(ownerId, batch);\n }),\n ),\n ).pipe(guard(\"batches.recordItemPlan\")),\n recordItemPlanFailure: (id, attachmentId, message) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n sql.withTransaction(\n Effect.gen(function* () {\n const batch = yield* lockedBatch(ownerId, id);\n if (batch.status !== \"planning\" && batch.status !== \"planned\") {\n return yield* batchStale(batch);\n }\n const updated = yield* sql<{ readonly attachment_id: string }>`\n UPDATE ${batchItems} SET attempt_id = NULL, plan_failure = ${message}\n WHERE batch_id = ${id} AND attachment_id = ${attachmentId}\n RETURNING attachment_id\n `;\n return updated[0] === undefined\n ? yield* notFound(\"attachment\", attachmentId)\n : yield* settled(ownerId, batch);\n }),\n ),\n ).pipe(guard(\"batches.recordItemPlanFailure\")),\n approve: (id, input) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n sql.withTransaction(\n Effect.gen(function* () {\n const batch = yield* lockedBatch(ownerId, id);\n // Replaying the same approval is how a retried request stays safe.\n if (batch.approval !== null) {\n return batch.digest === input.digest\n ? yield* aggregateOf(ownerId, batch)\n : yield* batchStale(batch);\n }\n if (batch.status !== \"planned\") return yield* batchStale(batch);\n const items = yield* Effect.forEach(yield* itemRows(ownerId, id), batchItemOf);\n const pairs: Array<{\n readonly attemptId: Plan.PlanId;\n readonly approval: Approval.Model;\n }> = [];\n for (const item of items) {\n const supplied = input.approvals.find(\n (entry) => entry.attachmentId === item.attachmentId,\n );\n if (supplied === undefined) {\n return yield* invalid(\n `Batch ${id} has no approval for attachment ${item.attachmentId}`,\n \"approvals\",\n );\n }\n // The item has to still point at the attempt this approval names: anything else\n // means the batch was re-planned after the principal reviewed it.\n if (item.attemptId === null || item.attemptId !== supplied.approval.planId) {\n return yield* batchStale(batch);\n }\n pairs.push({ attemptId: item.attemptId, approval: supplied.approval });\n }\n const instant = yield* DateTime.now;\n // The per-attempt approvals and the batch's own are one transaction: a batch is\n // never approved without the approvals `attempts.apply` takes.\n for (const pair of pairs) {\n const current = yield* lockedAttempt(ownerId, pair.attemptId);\n if (current.approval?.id === pair.approval.id) continue;\n if (current.status !== \"planned\") return yield* stale(current);\n const next = new Storage.Attempt({\n ...current,\n status: \"approved\",\n approval: pair.approval,\n updatedAt: instant,\n });\n const encoded = yield* attemptCodec.write(next);\n yield* sql`\n UPDATE ${attempts} SET\n status = ${encoded.status},\n approval = ${toJsonOrNull(encoded.approval)},\n approval_id = ${pair.approval.id},\n updated_at = ${at(encoded.updatedAt)}\n WHERE id = ${pair.attemptId} AND owner_id = ${ownerId}\n `;\n }\n return yield* settled(\n ownerId,\n new Storage.Batch({\n ...batch,\n digest: input.digest,\n approval: { actorId: input.actorId, at: instant },\n }),\n );\n }),\n ),\n ).pipe(guard(\"batches.approve\")),\n reject: (id, input) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n sql.withTransaction(\n Effect.gen(function* () {\n const batch = yield* lockedBatch(ownerId, id);\n // Terminal: a second rejection is the same outcome, so it returns the first one.\n if (batch.rejection !== null) return yield* aggregateOf(ownerId, batch);\n if (batch.status !== \"planning\" && batch.status !== \"planned\") {\n return yield* batchStale(batch);\n }\n const rows = yield* itemRows(ownerId, id);\n const instant = yield* DateTime.now;\n const rejection = {\n actorId: input.actorId,\n reason: input.reason,\n at: instant,\n };\n for (const row of rows) {\n if (row.attempt_id === null || row.attempt_status !== \"planned\") continue;\n const current = yield* lockedAttempt(ownerId, row.attempt_id);\n if (current.status !== \"planned\") continue;\n const next = new Storage.Attempt({\n ...current,\n status: \"rejected\",\n rejection,\n updatedAt: instant,\n });\n const encoded = yield* attemptCodec.write(next);\n yield* sql`\n UPDATE ${attempts} SET\n status = ${encoded.status},\n rejection = ${toJsonOrNull(encoded.rejection)},\n updated_at = ${at(encoded.updatedAt)}\n WHERE id = ${row.attempt_id} AND owner_id = ${ownerId}\n `;\n }\n return yield* settled(ownerId, new Storage.Batch({ ...batch, rejection }));\n }),\n ),\n ).pipe(guard(\"batches.reject\")),\n refresh: (id) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n sql.withTransaction(\n Effect.flatMap(lockedBatch(ownerId, id), (batch) => settled(ownerId, batch)),\n ),\n ).pipe(guard(\"batches.refresh\")),\n },\n readiness: {\n put: (row) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n Effect.gen(function* () {\n if (row.ownerId !== ownerId) {\n return yield* invalid(\"Readiness owner does not match the principal\", \"ownerId\");\n }\n // A linked attachment has to exist for this owner; observe-only readiness has none.\n if (row.attachmentId !== null) yield* requireAttachment(ownerId, row.attachmentId);\n const encoded = yield* readinessCodec.write(row);\n yield* sql`\n INSERT INTO ${readiness} (\n owner_id, domain, attachment_id, overall, requirements, host, pending_since,\n checked_at, next_check_at\n ) VALUES (\n ${encoded.ownerId}, ${encoded.domain}, ${encoded.attachmentId},\n ${encoded.overall}, ${toJson(encoded.requirements)}, ${toJson(encoded.host)},\n ${atOrNull(encoded.pendingSince)}, ${at(encoded.checkedAt)},\n ${atOrNull(encoded.nextCheckAt)}\n ) ON CONFLICT (owner_id, domain) DO UPDATE SET\n attachment_id = EXCLUDED.attachment_id,\n overall = EXCLUDED.overall,\n requirements = EXCLUDED.requirements,\n host = EXCLUDED.host,\n pending_since = EXCLUDED.pending_since,\n checked_at = EXCLUDED.checked_at,\n next_check_at = EXCLUDED.next_check_at\n `;\n }),\n ).pipe(guard(\"readiness.put\")),\n get: (domain) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n sql<ReadinessRow>`\n SELECT * FROM ${readiness}\n WHERE owner_id = ${ownerId} AND domain = ${domain}\n `.pipe(\n Effect.flatMap((rows) =>\n rows[0] === undefined\n ? Effect.succeedNone\n : Effect.map(readinessOf(rows[0]), Option.some),\n ),\n ),\n ).pipe(guard(\"readiness.get\")),\n },\n withLock: (key, effect) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n Effect.scoped(\n Effect.gen(function* () {\n // A session lock, not a transaction lock: the guarded effect refreshes a credential\n // against the provider, and no transaction should stay open across an HTTP call.\n // `reserve` pins one pooled connection so the unlock runs on the session that took\n // the lock, and registering it after the connection makes it run first on release.\n const connection = yield* Effect.mapError(sql.reserve, (error) =>\n storageFailed(\"withLock\", sqlMessage(error)),\n );\n const scoped = `${ownerId}:${key}`;\n yield* Effect.acquireRelease(\n connection\n .execute(\n \"SELECT pg_try_advisory_lock(hashtextextended($1, 0)) AS acquired\",\n [scoped],\n undefined,\n )\n .pipe(\n Effect.mapError((error: SqlError.SqlError) =>\n storageFailed(\"withLock\", sqlMessage(error)),\n ),\n Effect.flatMap((rows: ReadonlyArray<{ readonly acquired: boolean }>) =>\n rows[0]?.acquired === true ? Effect.void : busy(key),\n ),\n ),\n () =>\n connection\n .execute(\n \"SELECT pg_advisory_unlock(hashtextextended($1, 0))\",\n [scoped],\n undefined,\n )\n .pipe(Effect.ignore),\n );\n return yield* effect;\n }),\n ),\n ),\n };\n\n return service;\n });\n","/**\n * The eight tables DomainKit owns, declared once and rendered per dialect by CapsuleDB.\n *\n * Every table carries `owner_id` and every query filters by it: tenancy is a column, not a schema.\n * There are no foreign keys to host tables, and none between DomainKit's own tables either, so a\n * host can add its own in the emitted migration without fighting a constraint the package owns.\n */\nimport { Schema } from \"capsuledb\";\n\nexport interface Tables {\n readonly authorizations: Schema.Table;\n readonly connections: Schema.Table;\n readonly attachments: Schema.Table;\n readonly continuations: Schema.Table;\n readonly attempts: Schema.Table;\n readonly readiness: Schema.Table;\n readonly batches: Schema.Table;\n readonly batchItems: Schema.Table;\n}\n\n/** Default table prefix. Part of the physical layout, so it is immutable after the first deploy. */\nexport const DEFAULT_PREFIX = \"domainkit\";\n\n/**\n * Declare the eight tables under `prefix`.\n *\n * `Schema.table` validates every identifier it will quote, so an invalid prefix throws\n * `CapsuleDefinitionError` here rather than reaching a renderer.\n */\nexport const make = (prefix: string): Tables => ({\n authorizations: Schema.table(`${prefix}_authorizations`, {\n columns: {\n id: Schema.text(),\n owner_id: Schema.text(),\n provider: Schema.text(),\n method: Schema.text(),\n capabilities: Schema.json(),\n context: Schema.json(),\n /**\n * What the provider called the account when the credential was issued, so a UI names the\n * connection offline. Null names no account, which is also what rows written before the\n * column existed carry.\n */\n label: Schema.text({ nullable: true }),\n revocation: Schema.text(),\n created_by: Schema.text(),\n created_at: Schema.timestamp(),\n credential_ciphertext: Schema.text(),\n credential_expires_at: Schema.timestamp({ nullable: true }),\n credential_rotated_at: Schema.timestamp(),\n updated_at: Schema.timestamp(),\n },\n primaryKey: [\"id\"],\n indexes: [{ columns: [\"owner_id\", \"revocation\"] }, { columns: [\"owner_id\", \"provider\"] }],\n }),\n connections: Schema.table(`${prefix}_connections`, {\n columns: {\n id: Schema.text(),\n owner_id: Schema.text(),\n authorization_id: Schema.text(),\n created_at: Schema.timestamp(),\n },\n primaryKey: [\"id\"],\n indexes: [{ columns: [\"owner_id\"] }, { columns: [\"authorization_id\"] }],\n }),\n attachments: Schema.table(`${prefix}_attachments`, {\n columns: {\n id: Schema.text(),\n owner_id: Schema.text(),\n connection_id: Schema.text(),\n domain: Schema.text(),\n zone: Schema.text(),\n /**\n * The provider's label for the zone at attach time, so a UI names the account offline. The\n * default is what fills the rows an installation attached before the column existed.\n */\n label: Schema.text({ default: \"\" }),\n target: Schema.json(),\n created_at: Schema.timestamp(),\n },\n primaryKey: [\"id\"],\n // One attachment per domain per tenant; `attachments.create` reads the conflict as InvalidInput.\n uniques: [[\"owner_id\", \"domain\"]],\n indexes: [{ columns: [\"owner_id\", \"connection_id\"] }],\n }),\n continuations: Schema.table(`${prefix}_continuations`, {\n columns: {\n id: Schema.text(),\n owner_id: Schema.text(),\n actor_id: Schema.text(),\n provider: Schema.text(),\n payload: Schema.json(),\n return_to: Schema.text({ nullable: true }),\n expires_at: Schema.timestamp(),\n },\n primaryKey: [\"id\"],\n // Hosts sweep expired rows on this index; consume deletes the row it returns.\n indexes: [{ columns: [\"expires_at\"] }],\n }),\n attempts: Schema.table(`${prefix}_attempts`, {\n columns: {\n id: Schema.text(),\n owner_id: Schema.text(),\n attachment_id: Schema.text(),\n kind: Schema.text(),\n status: Schema.text(),\n plan: Schema.json(),\n approval: Schema.json({ nullable: true }),\n /** Denormalized from `approval` so `byApproval` is an index lookup. */\n approval_id: Schema.text({ nullable: true }),\n receipt: Schema.json({ nullable: true }),\n /** Denormalized from `receipt` so `byReceipt` is an index lookup. */\n receipt_id: Schema.text({ nullable: true }),\n /** Who declined the plan, why, and when; set when an attempt reaches `rejected`. */\n rejection: Schema.json({ nullable: true }),\n source_receipt_id: Schema.text({ nullable: true }),\n lease_expires_at: Schema.timestamp({ nullable: true }),\n failure: Schema.text({ nullable: true }),\n /** The plan's own `createdAt`; `latest` orders by it. */\n plan_created_at: Schema.timestamp(),\n updated_at: Schema.timestamp(),\n },\n primaryKey: [\"id\"],\n indexes: [\n { columns: [\"owner_id\", \"attachment_id\", \"kind\"] },\n { columns: [\"owner_id\", \"approval_id\"] },\n { columns: [\"owner_id\", \"receipt_id\"] },\n ],\n }),\n readiness: Schema.table(`${prefix}_readiness`, {\n columns: {\n owner_id: Schema.text(),\n domain: Schema.text(),\n /** Set while an attachment covers the domain; observe-only readiness leaves it null. */\n attachment_id: Schema.text({ nullable: true }),\n overall: Schema.text(),\n requirements: Schema.json(),\n host: Schema.json(),\n pending_since: Schema.timestamp({ nullable: true }),\n checked_at: Schema.timestamp(),\n next_check_at: Schema.timestamp({ nullable: true }),\n },\n // Keyed by domain, not by attachment, so a host observing public DNS alone gets the same row.\n primaryKey: [\"owner_id\", \"domain\"],\n // The sweep index drives the backoff ladder; the attachment index is for clearing the link.\n indexes: [{ columns: [\"owner_id\", \"next_check_at\"] }, { columns: [\"attachment_id\"] }],\n }),\n batches: Schema.table(`${prefix}_batches`, {\n columns: {\n id: Schema.text(),\n owner_id: Schema.text(),\n kind: Schema.text(),\n status: Schema.text(),\n /** SHA-256 over the items' `attachmentId:planDigest` pairs; set when the batch is approved. */\n digest: Schema.text({ nullable: true }),\n /** Who bound the digest, and when; the per-attempt approvals live on the attempts. */\n approval: Schema.json({ nullable: true }),\n rejection: Schema.json({ nullable: true }),\n idempotency_key: Schema.text(),\n created_by: Schema.text(),\n created_at: Schema.timestamp(),\n updated_at: Schema.timestamp(),\n /** When the batch reached `complete` or `rejected`; null while it still owes a move. */\n completed_at: Schema.timestamp({ nullable: true }),\n },\n primaryKey: [\"id\"],\n // One batch per key per tenant; `batches.create` reads the conflict as a replay.\n uniques: [[\"owner_id\", \"idempotency_key\"]],\n // The owner-scoped unfinished index, newest first.\n indexes: [{ columns: [\"owner_id\", \"status\", \"updated_at\"] }],\n }),\n batchItems: Schema.table(`${prefix}_batch_items`, {\n columns: {\n batch_id: Schema.text(),\n attachment_id: Schema.text(),\n /** The item's place in the batch, as `batches.create` received it. */\n position: Schema.integer(),\n /** The attempt carrying this item's plan; null until one lands. */\n attempt_id: Schema.text({ nullable: true }),\n /** Why the last planning pass stopped here; cleared when a plan lands. */\n plan_failure: Schema.text({ nullable: true }),\n },\n // One item per attachment per batch, which is what makes a replayed plan write idempotent.\n primaryKey: [\"batch_id\", \"attachment_id\"],\n indexes: [{ columns: [\"attempt_id\"] }],\n }),\n});\n\n/**\n * The authorizations table as the first migration created it, before `label`.\n *\n * Frozen for the same reason as `attachmentsV1`: migration 1 renders this shape, and the migration\n * that adds the column carries the difference.\n */\nexport const authorizationsV1 = (prefix: string): Schema.Table =>\n Schema.table(`${prefix}_authorizations`, {\n columns: {\n id: Schema.text(),\n owner_id: Schema.text(),\n provider: Schema.text(),\n method: Schema.text(),\n capabilities: Schema.json(),\n context: Schema.json(),\n revocation: Schema.text(),\n created_by: Schema.text(),\n created_at: Schema.timestamp(),\n credential_ciphertext: Schema.text(),\n credential_expires_at: Schema.timestamp({ nullable: true }),\n credential_rotated_at: Schema.timestamp(),\n updated_at: Schema.timestamp(),\n },\n primaryKey: [\"id\"],\n indexes: [{ columns: [\"owner_id\", \"revocation\"] }, { columns: [\"owner_id\", \"provider\"] }],\n });\n\n/**\n * The attachments table as the first migration created it, before `label`.\n *\n * A migration is history: what it renders must not move, or an installation that already ran it\n * sees a different checksum for work it has done. The declaration above is the current shape, and\n * the migration that adds the column carries the difference.\n */\nexport const attachmentsV1 = (prefix: string): Schema.Table =>\n Schema.table(`${prefix}_attachments`, {\n columns: {\n id: Schema.text(),\n owner_id: Schema.text(),\n connection_id: Schema.text(),\n domain: Schema.text(),\n zone: Schema.text(),\n target: Schema.json(),\n created_at: Schema.timestamp(),\n },\n primaryKey: [\"id\"],\n uniques: [[\"owner_id\", \"domain\"]],\n indexes: [{ columns: [\"owner_id\", \"connection_id\"] }],\n });\n\nexport const list = (tables: Tables): ReadonlyArray<Schema.Table> => [\n ...initial(tables),\n tables.batches,\n tables.batchItems,\n];\n\n/**\n * The tables the first migration creates.\n *\n * A migration is history: what it renders must not move, so a table added later is declared above\n * and created by its own migration rather than joining this list.\n */\nexport const initial = (tables: Tables): ReadonlyArray<Schema.Table> => [\n tables.authorizations,\n tables.connections,\n tables.attachments,\n tables.continuations,\n tables.attempts,\n tables.readiness,\n];\n","/**\n * DomainKit's CapsuleDB capsule: eight tables and one `Storage.Service` implementation.\n *\n * The capsule is a plain value, so a host imports it, points `capsuledb emit` at it, or hands it\n * to `Registry.layer` without running an Effect first.\n */\nimport { Capsule, Migration } from \"capsuledb\";\nimport { Storage } from \"domainkit\";\nimport { Layer } from \"effect\";\nimport type * as SqlClient from \"effect/unstable/sql/SqlClient\";\n\nimport { make as makeService } from \"./internal/storage.ts\";\nimport {\n attachmentsV1,\n authorizationsV1,\n DEFAULT_PREFIX,\n initial,\n list,\n make as makeTables,\n} from \"./internal/tables.ts\";\n\nexport { DEFAULT_PREFIX };\n\n/**\n * Build the capsule for a table prefix.\n *\n * The prefix is part of the physical layout: it changes the rendered DDL and therefore the\n * migration checksums, so a deployed registry must keep the prefix it was created with.\n */\nexport const make = (\n prefix: string = DEFAULT_PREFIX,\n): Capsule.Capsule<Storage.Service, never, SqlClient.SqlClient> => {\n const tables = makeTables(prefix);\n return Capsule.make({\n id: \"domainkit.storage\",\n tables: list(tables),\n migrations: [\n Migration.make({\n id: 1,\n name: \"create-storage\",\n risk: \"additive\",\n steps: initial(tables).map((table) =>\n Migration.createTable(\n table.name === tables.attachments.name\n ? attachmentsV1(prefix)\n : table.name === tables.authorizations.name\n ? authorizationsV1(prefix)\n : table,\n ),\n ),\n }),\n // An installation that attached domains before the column existed keeps those rows: the\n // default fills them, and the backfill names each one after the zone it is attached to,\n // which is what the provider's label is built from.\n Migration.make({\n id: 2,\n name: \"attachment-label\",\n risk: \"additive\",\n steps: [\n Migration.addColumn(tables.attachments.name, \"label\", { type: \"text\", default: \"\" }),\n Migration.sql(\n Object.fromEntries(\n ([\"postgres\", \"sqlite\"] as const).map((dialect) => [\n dialect,\n [`UPDATE ${tables.attachments.name} SET label = zone WHERE label = ''`],\n ]),\n ),\n ),\n ],\n }),\n // An installation that connected accounts before the column existed keeps those rows\n // unnamed: the provider named the account at connect time, and nothing here can name it\n // after the fact without a credential.\n Migration.make({\n id: 3,\n name: \"authorization-label\",\n risk: \"additive\",\n steps: [\n Migration.addColumn(tables.authorizations.name, \"label\", {\n type: \"text\",\n nullable: true,\n }),\n ],\n }),\n // The batch aggregate: many attempts planned together and approved once. Both tables are\n // new, so an installation that ran migrations 1 to 3 gains them without touching a row it\n // already holds.\n Migration.make({\n id: 4,\n name: \"batches\",\n risk: \"additive\",\n steps: [Migration.createTable(tables.batches), Migration.createTable(tables.batchItems)],\n }),\n ],\n layer: Layer.effect(Storage.Service)(makeService(tables)),\n });\n};\n\n/** The capsule under the default `domainkit` prefix. `capsuledb emit --export capsule` reads this. */\nexport const capsule: Capsule.Capsule<Storage.Service, never, SqlClient.SqlClient> = make();\n","/**\n * The layer a host installs: DomainKit's `Storage` on the host's own PostgreSQL client.\n *\n * `layer()` runs the capsule through CapsuleDB's registry, which creates the ledger, applies\n * pending migrations, and only then provides `Storage`. A host that owns its migration pipeline\n * applies `capsuledb emit` output instead and boots with `mode: \"assert\"`, which touches no schema\n * and fails unless the database already matches the capsule.\n *\n * The layer requires only `SqlClient`: credentials arrive sealed, so Storage never needs `Custody`.\n */\nimport { Pg, type Registry as RegistryTypes, Registry } from \"capsuledb\";\nimport type { Storage } from \"domainkit\";\nimport type * as Layer from \"effect/Layer\";\nimport type * as SqlClient from \"effect/unstable/sql/SqlClient\";\n\nimport { capsule, DEFAULT_PREFIX, make } from \"./capsule.ts\";\n\nexport interface Options {\n /** Table prefix. Default `domainkit`. Part of the physical layout; immutable after first deploy. */\n readonly prefix?: string;\n /** `prepare` (default) migrates at boot; `assert` expects the host applied `capsuledb emit` output. */\n readonly mode?: \"prepare\" | \"assert\";\n /**\n * Prefix for CapsuleDB's own ledger tables; default `capsuledb`. Set it only to match a prefix a\n * host already uses for other capsules, and pass the same value to `capsuledb emit --prefix`.\n */\n readonly registryPrefix?: string;\n}\n\nexport const layer = (\n options: Options = {},\n): Layer.Layer<Storage.Service, RegistryTypes.RegistryRuntimeError, SqlClient.SqlClient> =>\n Registry.layer({\n provider: Pg.profile,\n capsules: [\n options.prefix === undefined || options.prefix === DEFAULT_PREFIX\n ? capsule\n : make(options.prefix),\n ],\n ...(options.mode === undefined ? {} : { mode: options.mode }),\n ...(options.registryPrefix === undefined ? {} : { prefix: options.registryPrefix }),\n });\n","/**\n * DomainKit's `Storage` on PostgreSQL, as one declarative CapsuleDB capsule.\n *\n * Hosts install `PgStorage.layer()` under `DomainKit.layer` and supply their own `SqlClient`. The\n * `capsule` value is the same declaration `capsuledb emit` reads to write SQL for a host-owned\n * migration pipeline.\n */\nimport packageJson from \"../package.json\" with { type: \"json\" };\n\nexport const VERSION = packageJson.version;\n\nexport * as PgStorage from \"./PgStorage.ts\";\nexport { capsule } from \"./capsule.ts\";\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["Schema","make","make","makeTables","makeService","packageJson.version"],"sources":["../package.json","../src/internal/storage.ts","../src/internal/tables.ts","../src/capsule.ts","../src/PgStorage.ts","../src/index.ts"],"sourcesContent":["","/**\n * `Storage.Interface` on PostgreSQL.\n *\n * Every method reads `Principal` and filters by `owner_id`, so a row belonging to another tenant\n * is indistinguishable from a row that does not exist. Aggregate transitions run inside one\n * transaction over a `FOR UPDATE` row, single-flight guards use a session-level advisory lock on a\n * reserved connection, and revocation is two-phase: mark `pending`, call the provider outside any\n * transaction, then delete.\n *\n * `Connect` seals provider secret material through `Custody` before it reaches authorization\n * `upsert` or `rotate`. Continuation payloads, including PKCE verifiers, are stored as unsealed JSON.\n */\nimport { type Approval, DomainKit, type Plan, Principal, Reason, Storage } from \"domainkit\";\nimport { DateTime, Effect, Option, Schema } from \"effect\";\nimport * as SqlClient from \"effect/sql/SqlClient\";\nimport * as SqlError from \"effect/sql/SqlError\";\n\nimport type { Tables } from \"./tables.ts\";\n\ntype Fail = DomainKit.Error;\n\n// ---------------------------------------------------------------------------------------------\n// Errors\n// ---------------------------------------------------------------------------------------------\n\nconst fail = (reason: Reason.Model) => Effect.fail(new DomainKit.Error({ reason }));\n\nconst notFound = (entity: Reason.NotFound[\"entity\"], id: string) =>\n fail(new Reason.NotFound({ entity, id }));\n\nconst invalid = (message: string, field?: string) =>\n fail(new Reason.InvalidInput({ message, ...(field === undefined ? {} : { field }) }));\n\nconst busy = (key: string) => fail(new Reason.Busy({ key }));\n\nconst storageFailed = (operation: string, message: string) =>\n new DomainKit.Error({\n reason: new Reason.StorageFailed({ operation, message }),\n });\n\nconst sqlMessage = (error: SqlError.SqlError): string =>\n error.reason.cause instanceof Error\n ? `${error.reason._tag}: ${error.reason.cause.message}`\n : `${error.reason._tag}: ${String(error.reason.cause)}`;\n\n/**\n * Collapse the SQL error channel into `DomainKit.Error`.\n *\n * A `DomainKit.Error` raised by the body is the deliberate outcome of an invariant and passes\n * through unchanged; anything else is a driver failure and becomes `StorageFailed`.\n */\nconst guard =\n (operation: string) =>\n <A, R>(effect: Effect.Effect<A, SqlError.SqlError | Fail, R>): Effect.Effect<A, Fail, R> =>\n Effect.catch(effect, (error) =>\n Effect.fail(DomainKit.isError(error) ? error : storageFailed(operation, sqlMessage(error))),\n );\n\n// ---------------------------------------------------------------------------------------------\n// Row codecs\n// ---------------------------------------------------------------------------------------------\n\n/**\n * A row is stored as its schema's encoded form spread over columns, so the core schema stays the\n * only description of a row's shape. Reading reassembles the encoded object and decodes it.\n */\nconst codec = <S extends Schema.ConstraintCodec<unknown, unknown>>(schema: S, subject: string) => {\n const decode = Schema.decodeUnknownEffect(schema);\n const encode = Schema.encodeUnknownEffect(schema);\n return {\n read: (input: unknown): Effect.Effect<S[\"Type\"], Fail, S[\"DecodingServices\"]> =>\n decode(input).pipe(\n Effect.mapError((error) =>\n storageFailed(`${subject}.decode`, `stored ${subject} is invalid: ${error.message}`),\n ),\n ),\n write: (value: S[\"Type\"]): Effect.Effect<S[\"Encoded\"], Fail, S[\"EncodingServices\"]> =>\n encode(value).pipe(\n Effect.mapError((error) =>\n storageFailed(`${subject}.encode`, `${subject} cannot be stored: ${error.message}`),\n ),\n ),\n };\n};\n\nconst authorizationCodec = codec(Storage.Authorization, \"authorization\");\nconst connectionCodec = codec(Storage.Connection, \"connection\");\nconst attachmentCodec = codec(Storage.Attachment, \"attachment\");\nconst continuationCodec = codec(Storage.Continuation, \"continuation\");\nconst continuationHeaderCodec = codec(Storage.ContinuationHeader, \"continuation header\");\nconst attemptCodec = codec(Storage.Attempt, \"attempt\");\nconst batchCodec = codec(Storage.Batch, \"batch\");\nconst batchItemCodec = codec(Storage.BatchItem, \"batch item\");\nconst readinessCodec = codec(Storage.Readiness, \"readiness\");\nconst credentialCodec = codec(Storage.Credential, \"credential\");\n\n// ---------------------------------------------------------------------------------------------\n// Column conversions\n// ---------------------------------------------------------------------------------------------\n\n/** A `TIMESTAMPTZ` column as the ISO string every DomainKit timestamp schema encodes to. */\nconst iso = (value: unknown): string => {\n if (value instanceof Date) return value.toISOString();\n if (DateTime.isDateTime(value)) return DateTime.toDateUtc(value).toISOString();\n if (typeof value === \"number\") return new Date(value).toISOString();\n if (typeof value === \"string\") {\n const date = new Date(value);\n if (!Number.isNaN(date.getTime())) return date.toISOString();\n }\n return String(value);\n};\n\nconst isoOrNull = (value: unknown): string | null => (value === null ? null : iso(value));\n\n/** An ISO string from a schema's encoded form as the `Date` the driver binds to `TIMESTAMPTZ`. */\nconst at = (value: string): Date => new Date(value);\n\nconst atOrNull = (value: string | null): Date | null => (value === null ? null : at(value));\n\nconst now = Effect.map(DateTime.now, DateTime.toDateUtc);\n\n/**\n * A `JSONB` column as a plain value.\n *\n * Drivers disagree about whether they parse JSON columns, so accept both and normalize here\n * rather than depending on a host's client configuration.\n */\nconst fromJson = (value: unknown): unknown =>\n typeof value === \"string\" ? (JSON.parse(value) as unknown) : value;\n\nconst fromJsonOrNull = (value: unknown): unknown => (value === null ? null : fromJson(value));\n\n/** Bind a value to a `JSONB` column as text; PostgreSQL coerces the untyped parameter. */\nconst toJson = (value: unknown): string => JSON.stringify(value ?? null);\n\nconst toJsonOrNull = (value: unknown): string | null =>\n value === null || value === undefined ? null : toJson(value);\n\n// ---------------------------------------------------------------------------------------------\n// Row shapes\n// ---------------------------------------------------------------------------------------------\n\ninterface AuthorizationRow {\n readonly id: string;\n readonly owner_id: string;\n readonly provider: string;\n readonly method: string;\n readonly capabilities: unknown;\n readonly context: unknown;\n readonly label: string | null;\n readonly revocation: string;\n readonly created_by: string;\n readonly created_at: unknown;\n readonly credential_ciphertext: string;\n readonly credential_expires_at: unknown;\n readonly credential_rotated_at: unknown;\n}\n\ninterface ConnectionRow {\n readonly id: string;\n readonly owner_id: string;\n readonly authorization_id: string;\n readonly created_at: unknown;\n}\n\ninterface AttachmentRow {\n readonly id: string;\n readonly owner_id: string;\n readonly connection_id: string;\n readonly domain: string;\n readonly zone: string;\n readonly label: string;\n readonly target: unknown;\n readonly created_at: unknown;\n}\n\ninterface ContinuationRow {\n readonly id: string;\n readonly owner_id: string;\n readonly actor_id: string;\n readonly provider: string;\n readonly payload: unknown;\n readonly return_to: string | null;\n readonly expires_at: unknown;\n}\n\ninterface AttemptRow {\n readonly id: string;\n readonly owner_id: string;\n readonly attachment_id: string;\n readonly kind: string;\n readonly status: string;\n readonly plan: unknown;\n readonly approval: unknown;\n readonly receipt: unknown;\n readonly rejection: unknown;\n readonly source_receipt_id: string | null;\n readonly lease_expires_at: unknown;\n readonly failure: string | null;\n readonly updated_at: unknown;\n}\n\ninterface BatchRow {\n readonly id: string;\n readonly owner_id: string;\n readonly kind: string;\n readonly status: string;\n readonly digest: string | null;\n readonly approval: unknown;\n readonly rejection: unknown;\n readonly idempotency_key: string;\n readonly created_by: string;\n readonly created_at: unknown;\n readonly updated_at: unknown;\n readonly completed_at: unknown;\n}\n\ninterface BatchItemRow {\n readonly batch_id: string;\n readonly attachment_id: string;\n readonly position: number;\n readonly attempt_id: string | null;\n readonly plan_failure: string | null;\n}\n\n/** An item row with its attempt's status joined in; null while the item carries no plan. */\ninterface BatchItemStatusRow extends BatchItemRow {\n readonly attempt_status: string | null;\n}\n\ninterface ReadinessRow {\n readonly owner_id: string;\n readonly domain: string;\n readonly attachment_id: string | null;\n readonly overall: string;\n readonly requirements: unknown;\n readonly host: unknown;\n readonly pending_since: unknown;\n readonly checked_at: unknown;\n readonly next_check_at: unknown;\n}\n\nconst authorizationOf = (row: AuthorizationRow) =>\n authorizationCodec.read({\n id: row.id,\n ownerId: row.owner_id,\n provider: row.provider,\n method: row.method,\n capabilities: fromJson(row.capabilities),\n context: fromJson(row.context),\n label: row.label,\n revocation: row.revocation,\n createdBy: row.created_by,\n createdAt: iso(row.created_at),\n });\n\nconst credentialOf = (row: AuthorizationRow) =>\n credentialCodec.read({\n ciphertext: row.credential_ciphertext,\n expiresAt: isoOrNull(row.credential_expires_at),\n rotatedAt: iso(row.credential_rotated_at),\n });\n\nconst connectionOf = (row: ConnectionRow) =>\n connectionCodec.read({\n id: row.id,\n ownerId: row.owner_id,\n authorizationId: row.authorization_id,\n createdAt: iso(row.created_at),\n });\n\nconst attachmentOf = (row: AttachmentRow) =>\n attachmentCodec.read({\n id: row.id,\n ownerId: row.owner_id,\n connectionId: row.connection_id,\n domain: row.domain,\n zone: row.zone,\n label: row.label,\n target: fromJson(row.target),\n createdAt: iso(row.created_at),\n });\n\nconst continuationOf = (row: ContinuationRow) =>\n continuationCodec.read({\n id: row.id,\n ownerId: row.owner_id,\n actorId: row.actor_id,\n provider: row.provider,\n payload: fromJson(row.payload),\n returnTo: row.return_to,\n expiresAt: iso(row.expires_at),\n });\n\ntype ContinuationHeaderRow = Pick<\n ContinuationRow,\n \"owner_id\" | \"actor_id\" | \"provider\" | \"expires_at\"\n>;\n\nconst continuationHeaderOf = (row: ContinuationHeaderRow) =>\n continuationHeaderCodec.read({\n ownerId: row.owner_id,\n actorId: row.actor_id,\n provider: row.provider,\n expiresAt: iso(row.expires_at),\n });\n\nconst attemptOf = (row: AttemptRow) =>\n attemptCodec.read({\n id: row.id,\n ownerId: row.owner_id,\n attachmentId: row.attachment_id,\n kind: row.kind,\n status: row.status,\n plan: fromJson(row.plan),\n approval: fromJsonOrNull(row.approval),\n receipt: fromJsonOrNull(row.receipt),\n rejection: fromJsonOrNull(row.rejection),\n sourceReceiptId: row.source_receipt_id,\n leaseExpiresAt: isoOrNull(row.lease_expires_at),\n failure: row.failure,\n updatedAt: iso(row.updated_at),\n });\n\nconst batchOf = (row: BatchRow) =>\n batchCodec.read({\n id: row.id,\n ownerId: row.owner_id,\n kind: row.kind,\n status: row.status,\n digest: row.digest,\n approval: fromJsonOrNull(row.approval),\n rejection: fromJsonOrNull(row.rejection),\n idempotencyKey: row.idempotency_key,\n createdBy: row.created_by,\n createdAt: iso(row.created_at),\n updatedAt: iso(row.updated_at),\n completedAt: isoOrNull(row.completed_at),\n });\n\nconst batchItemOf = (row: BatchItemRow) =>\n batchItemCodec.read({\n batchId: row.batch_id,\n attachmentId: row.attachment_id,\n position: row.position,\n attemptId: row.attempt_id,\n planFailure: row.plan_failure,\n });\n\nconst readinessOf = (row: ReadinessRow) =>\n readinessCodec.read({\n domain: row.domain,\n attachmentId: row.attachment_id,\n ownerId: row.owner_id,\n overall: row.overall,\n requirements: fromJson(row.requirements),\n host: fromJson(row.host),\n pendingSince: isoOrNull(row.pending_since),\n checkedAt: iso(row.checked_at),\n nextCheckAt: isoOrNull(row.next_check_at),\n });\n\nconst stale = (attempt: Storage.Attempt) =>\n fail(new Reason.Stale({ planId: attempt.id, digest: attempt.plan.digest }));\n\nconst batchStale = (batch: Storage.Batch) =>\n fail(new Reason.BatchStale({ batchId: batch.id, status: batch.status, digest: batch.digest }));\n\n/** `prefix_<uuid>`, the same identifier shape the memory implementation mints. */\nconst fresh = (prefix: string) => Effect.sync(() => `${prefix}_${crypto.randomUUID()}`);\n\n// ---------------------------------------------------------------------------------------------\n// Service\n// ---------------------------------------------------------------------------------------------\n\nexport const make = (\n tables: Tables,\n): Effect.Effect<Storage.Interface, never, SqlClient.SqlClient> =>\n Effect.gen(function* () {\n const client = yield* SqlClient.SqlClient;\n // A host may configure result-name transforms for its own tables; these queries read the exact\n // snake_case columns the capsule declared.\n const sql = client.withoutTransforms();\n\n const authorizations = sql(tables.authorizations.name);\n const connections = sql(tables.connections.name);\n const attachments = sql(tables.attachments.name);\n const continuations = sql(tables.continuations.name);\n const attempts = sql(tables.attempts.name);\n const readiness = sql(tables.readiness.name);\n const batches = sql(tables.batches.name);\n const batchItems = sql(tables.batchItems.name);\n\n /** The row this principal owns, locked for the rest of the transaction. */\n const lockedAuthorization = (owner: string, id: string) =>\n sql<AuthorizationRow>`\n SELECT * FROM ${authorizations} WHERE id = ${id} AND owner_id = ${owner} FOR UPDATE\n `.pipe(\n Effect.flatMap((rows) =>\n rows[0] === undefined ? notFound(\"authorization\", id) : Effect.succeed(rows[0]),\n ),\n );\n\n const lockedAttempt = (owner: string, id: string) =>\n sql<AttemptRow>`\n SELECT * FROM ${attempts} WHERE id = ${id} AND owner_id = ${owner} FOR UPDATE\n `.pipe(\n Effect.flatMap((rows) =>\n rows[0] === undefined ? notFound(\"plan\", id) : Effect.succeed(rows[0]),\n ),\n Effect.flatMap(attemptOf),\n );\n\n const requireConnection = (owner: string, id: string) =>\n sql<ConnectionRow>`\n SELECT * FROM ${connections} WHERE id = ${id} AND owner_id = ${owner}\n `.pipe(\n Effect.flatMap((rows) =>\n rows[0] === undefined ? notFound(\"connection\", id) : Effect.succeed(rows[0]),\n ),\n );\n\n const requireAttachment = (owner: string, id: string) =>\n sql<AttachmentRow>`\n SELECT * FROM ${attachments} WHERE id = ${id} AND owner_id = ${owner}\n `.pipe(\n Effect.flatMap((rows) =>\n rows[0] === undefined ? notFound(\"attachment\", id) : Effect.succeed(rows[0]),\n ),\n );\n\n const writeAuthorization = (\n authorization: Storage.Authorization,\n credential: Storage.Credential,\n ) =>\n Effect.all({\n row: authorizationCodec.write(authorization),\n secret: credentialCodec.write(credential),\n });\n\n /**\n * Phase one of revocation: mark the row `pending` so a crash between the provider call and the\n * delete is recoverable. Idempotent, and it never widens the row's state.\n *\n * Returns the ciphertext the caller is about to have revoked, which phase two checks.\n */\n const prepareRevocation = (owner: string, id: string) =>\n sql.withTransaction(\n Effect.gen(function* () {\n const row = yield* lockedAuthorization(owner, id);\n yield* sql`\n UPDATE ${authorizations} SET revocation = 'pending', updated_at = ${yield* now}\n WHERE id = ${id} AND owner_id = ${owner}\n `;\n return row.credential_ciphertext;\n }),\n );\n\n /**\n * Phase two: delete the row, but only while it still holds the credential the provider was\n * asked to revoke.\n *\n * A credential refresh runs concurrently with revocation and rotates the row after the provider\n * call selected the old ciphertext. Deleting unconditionally would drop the row while the newly\n * issued credential is still live at the provider, with no local state left to revoke it from.\n * Leaving the row `pending` instead hands it to `recoverRevocations`, which revokes what the\n * row now holds. Every ciphertext is AES-GCM with a fresh IV, so equality here is exact.\n */\n const completeRevocation = (owner: string, id: string, ciphertext: string) =>\n sql`\n DELETE FROM ${authorizations}\n WHERE id = ${id} AND owner_id = ${owner} AND credential_ciphertext = ${ciphertext}\n `;\n\n const requireBatch = (owner: string, id: string) =>\n sql<BatchRow>`\n SELECT * FROM ${batches} WHERE id = ${id} AND owner_id = ${owner}\n `.pipe(\n Effect.flatMap((rows) =>\n rows[0] === undefined ? notFound(\"batch\", id) : Effect.succeed(rows[0]),\n ),\n Effect.flatMap(batchOf),\n );\n\n /** The batch this principal owns, locked for the rest of the transaction. */\n const lockedBatch = (owner: string, id: string) =>\n sql<BatchRow>`\n SELECT * FROM ${batches} WHERE id = ${id} AND owner_id = ${owner} FOR UPDATE\n `.pipe(\n Effect.flatMap((rows) =>\n rows[0] === undefined ? notFound(\"batch\", id) : Effect.succeed(rows[0]),\n ),\n Effect.flatMap(batchOf),\n );\n\n const requireAttempt = (owner: string, id: string) =>\n sql<AttemptRow>`\n SELECT * FROM ${attempts} WHERE id = ${id} AND owner_id = ${owner}\n `.pipe(\n Effect.flatMap((rows) =>\n rows[0] === undefined ? notFound(\"plan\", id) : Effect.succeed(rows[0]),\n ),\n );\n\n /**\n * A batch's items in `position` order, each with its attempt's status, which is what the\n * aggregate's own status is recomputed from. The batch was already read under its owner, and\n * the join carries the same filter so an item can only ever reach that owner's attempts.\n */\n const itemRows = (owner: string, batchId: string) =>\n sql<BatchItemStatusRow>`\n SELECT item.batch_id, item.attachment_id, item.\"position\", item.attempt_id,\n item.plan_failure, attempt.status AS attempt_status\n FROM ${batchItems} AS item\n LEFT JOIN ${attempts} AS attempt\n ON attempt.id = item.attempt_id AND attempt.owner_id = ${owner}\n WHERE item.batch_id = ${batchId}\n ORDER BY item.\"position\" ASC\n `;\n\n const aggregateOf = (\n owner: string,\n batch: Storage.Batch,\n ): Effect.Effect<Storage.BatchAggregate, Fail | SqlError.SqlError> =>\n itemRows(owner, batch.id).pipe(\n Effect.flatMap((rows) => Effect.forEach(rows, batchItemOf)),\n Effect.map((items) => ({ batch, items })),\n );\n\n /**\n * Write `batch` with its status recomputed from the items' attempts.\n *\n * Every transition ends here, inside the transaction that locked the row, so the stored status\n * and the owner-scoped unfinished index never disagree with the attempts they summarize.\n */\n const settled = (\n owner: string,\n batch: Storage.Batch,\n ): Effect.Effect<Storage.BatchAggregate, Fail | SqlError.SqlError> =>\n Effect.gen(function* () {\n const rows = yield* itemRows(owner, batch.id);\n const items = yield* Effect.forEach(rows, batchItemOf);\n const status = Storage.batchStatusOf({\n approved: batch.approval !== null,\n rejected: batch.rejection !== null,\n items: rows.map((row) =>\n row.attempt_id === null ? null : (row.attempt_status as Storage.AttemptStatus | null),\n ),\n });\n const instant = yield* DateTime.now;\n const next = new Storage.Batch({\n ...batch,\n status,\n completedAt: status === \"complete\" || status === \"rejected\" ? instant : null,\n updatedAt: instant,\n });\n const encoded = yield* batchCodec.write(next);\n yield* sql`\n UPDATE ${batches} SET\n status = ${encoded.status},\n digest = ${encoded.digest},\n approval = ${toJsonOrNull(encoded.approval)},\n rejection = ${toJsonOrNull(encoded.rejection)},\n completed_at = ${atOrNull(encoded.completedAt)},\n updated_at = ${at(encoded.updatedAt)}\n WHERE id = ${batch.id} AND owner_id = ${owner}\n `;\n return { batch: next, items };\n });\n\n const service: Storage.Interface = {\n authorizations: {\n upsert: ({ authorization, credential, expectedId }) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n Effect.gen(function* () {\n if (authorization.ownerId !== ownerId) {\n return yield* invalid(\n \"Authorization owner does not match the principal\",\n \"ownerId\",\n );\n }\n const { row, secret } = yield* writeAuthorization(authorization, credential);\n const stamp = yield* now;\n return yield* sql.withTransaction(\n Effect.gen(function* () {\n if (expectedId !== undefined) {\n const current = yield* lockedAuthorization(ownerId, expectedId);\n if (current.revocation !== \"active\") {\n return yield* busy(`authorization:${expectedId}`);\n }\n if (authorization.id !== expectedId) {\n return yield* invalid(\"Authorization id must match expectedId\", \"id\");\n }\n // A replace overwrites every column the caller supplied, including `created_at`:\n // the row it returns has to be the row a later `get` reads back.\n yield* sql`\n UPDATE ${authorizations} SET\n provider = ${row.provider},\n method = ${row.method},\n capabilities = ${toJson(row.capabilities)},\n context = ${toJson(row.context)},\n label = ${row.label},\n revocation = ${row.revocation},\n created_by = ${row.createdBy},\n created_at = ${at(row.createdAt)},\n credential_ciphertext = ${secret.ciphertext},\n credential_expires_at = ${atOrNull(secret.expiresAt)},\n credential_rotated_at = ${at(secret.rotatedAt)},\n updated_at = ${stamp}\n WHERE id = ${expectedId} AND owner_id = ${ownerId}\n `;\n return authorization;\n }\n // An id already taken by any tenant is a caller defect, not a missing row, so the\n // insert claims it atomically instead of racing a prior existence check.\n const inserted = yield* sql<{ readonly id: string }>`\n INSERT INTO ${authorizations} (\n id, owner_id, provider, method, capabilities, context, label, revocation,\n created_by, created_at, credential_ciphertext, credential_expires_at,\n credential_rotated_at, updated_at\n ) VALUES (\n ${row.id}, ${row.ownerId}, ${row.provider}, ${row.method},\n ${toJson(row.capabilities)}, ${toJson(row.context)}, ${row.label},\n ${row.revocation},\n ${row.createdBy}, ${at(row.createdAt)}, ${secret.ciphertext},\n ${atOrNull(secret.expiresAt)}, ${at(secret.rotatedAt)}, ${stamp}\n ) ON CONFLICT (id) DO NOTHING RETURNING id\n `;\n return inserted[0] === undefined\n ? yield* invalid(`Authorization ${authorization.id} already exists`, \"id\")\n : authorization;\n }),\n );\n }),\n ).pipe(guard(\"authorizations.upsert\")),\n get: (id) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n sql<AuthorizationRow>`\n SELECT * FROM ${authorizations} WHERE id = ${id} AND owner_id = ${ownerId}\n `.pipe(\n Effect.flatMap((rows) =>\n rows[0] === undefined ? notFound(\"authorization\", id) : authorizationOf(rows[0]),\n ),\n ),\n ).pipe(guard(\"authorizations.get\")),\n credential: (id) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n sql<AuthorizationRow>`\n SELECT * FROM ${authorizations} WHERE id = ${id} AND owner_id = ${ownerId}\n `.pipe(\n Effect.flatMap((rows) =>\n rows[0] === undefined ? notFound(\"authorization\", id) : credentialOf(rows[0]),\n ),\n ),\n ).pipe(guard(\"authorizations.credential\")),\n rotate: (id, credential) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n Effect.gen(function* () {\n const secret = yield* credentialCodec.write(credential);\n const updated = yield* sql<{ readonly id: string }>`\n UPDATE ${authorizations} SET\n credential_ciphertext = ${secret.ciphertext},\n credential_expires_at = ${atOrNull(secret.expiresAt)},\n credential_rotated_at = ${at(secret.rotatedAt)},\n updated_at = ${yield* now}\n WHERE id = ${id} AND owner_id = ${ownerId} RETURNING id\n `;\n if (updated[0] === undefined) return yield* notFound(\"authorization\", id);\n }),\n ).pipe(guard(\"authorizations.rotate\")),\n promoteCapabilities: (id, capabilities) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n sql.withTransaction(\n Effect.gen(function* () {\n const current = yield* authorizationOf(yield* lockedAuthorization(ownerId, id));\n const merged = [...new Set([...current.capabilities, ...capabilities])];\n yield* sql`\n UPDATE ${authorizations}\n SET capabilities = ${toJson(merged)}, updated_at = ${yield* now}\n WHERE id = ${id} AND owner_id = ${ownerId}\n `;\n }),\n ),\n ).pipe(guard(\"authorizations.promoteCapabilities\")),\n revoke: (id, revoke) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n Effect.gen(function* () {\n const ciphertext = yield* prepareRevocation(ownerId, id).pipe(\n guard(\"authorizations.revoke\"),\n );\n yield* revoke;\n yield* completeRevocation(ownerId, id, ciphertext).pipe(\n guard(\"authorizations.completeRevocation\"),\n );\n }),\n ),\n recoverRevocations: (revoke) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n Effect.gen(function* () {\n const rows = yield* sql<AuthorizationRow>`\n SELECT * FROM ${authorizations}\n WHERE owner_id = ${ownerId} AND revocation = 'pending'\n ORDER BY created_at\n `.pipe(guard(\"authorizations.pendingRevocations\"));\n yield* Effect.forEach(rows, (row) =>\n Effect.gen(function* () {\n yield* revoke(yield* authorizationOf(row));\n yield* completeRevocation(ownerId, row.id, row.credential_ciphertext).pipe(\n guard(\"authorizations.completeRevocation\"),\n );\n }),\n );\n return rows.length;\n }),\n ),\n },\n connections: {\n create: (authorizationId) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n sql.withTransaction(\n Effect.gen(function* () {\n yield* lockedAuthorization(ownerId, authorizationId);\n const row = new Storage.Connection({\n id: yield* fresh(\"conn\"),\n ownerId,\n authorizationId,\n createdAt: yield* DateTime.now,\n });\n const encoded = yield* connectionCodec.write(row);\n yield* sql`\n INSERT INTO ${connections} (id, owner_id, authorization_id, created_at)\n VALUES (${encoded.id}, ${encoded.ownerId}, ${encoded.authorizationId},\n ${at(encoded.createdAt)})\n `;\n return row;\n }),\n ),\n ).pipe(guard(\"connections.create\")),\n get: (id) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n Effect.flatMap(requireConnection(ownerId, id), connectionOf),\n ).pipe(guard(\"connections.get\")),\n list: (filter) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n Effect.flatMap(\n filter?.provider === undefined\n ? sql<ConnectionRow>`\n SELECT * FROM ${connections} WHERE owner_id = ${ownerId} ORDER BY created_at\n `\n : sql<ConnectionRow>`\n SELECT c.* FROM ${connections} AS c\n JOIN ${authorizations} AS a ON a.id = c.authorization_id\n WHERE c.owner_id = ${ownerId} AND a.provider = ${filter.provider}\n ORDER BY c.created_at\n `,\n (rows) => Effect.forEach(rows, connectionOf),\n ),\n ).pipe(guard(\"connections.list\")),\n remove: (id) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n sql.withTransaction(\n Effect.gen(function* () {\n const rows = yield* sql<ConnectionRow>`\n SELECT * FROM ${connections}\n WHERE id = ${id} AND owner_id = ${ownerId} FOR UPDATE\n `;\n if (rows[0] === undefined) return yield* notFound(\"connection\", id);\n const held = yield* sql<{ readonly id: string }>`\n SELECT id FROM ${attachments}\n WHERE connection_id = ${id} AND owner_id = ${ownerId} LIMIT 1\n `;\n if (held[0] !== undefined) {\n return yield* invalid(`Connection ${id} still has attachments`, \"connectionId\");\n }\n yield* sql`DELETE FROM ${connections} WHERE id = ${id} AND owner_id = ${ownerId}`;\n }),\n ),\n ).pipe(guard(\"connections.remove\")),\n },\n attachments: {\n create: (input) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n sql.withTransaction(\n Effect.gen(function* () {\n yield* requireConnection(ownerId, input.connectionId);\n const row = new Storage.Attachment({\n id: yield* fresh(\"att\"),\n ownerId,\n connectionId: input.connectionId,\n domain: input.domain,\n zone: input.zone,\n label: input.label,\n target: input.target,\n createdAt: yield* DateTime.now,\n });\n const encoded = yield* attachmentCodec.write(row);\n // The unique (owner_id, domain) constraint decides the duplicate, so two concurrent\n // attaches cannot both win.\n const inserted = yield* sql<{ readonly id: string }>`\n INSERT INTO ${attachments} (\n id, owner_id, connection_id, domain, zone, label, target, created_at\n ) VALUES (\n ${encoded.id}, ${encoded.ownerId}, ${encoded.connectionId}, ${encoded.domain},\n ${encoded.zone}, ${encoded.label}, ${toJson(encoded.target)},\n ${at(encoded.createdAt)}\n ) ON CONFLICT (owner_id, domain) DO NOTHING RETURNING id\n `;\n return inserted[0] === undefined\n ? yield* invalid(`${input.domain} is already attached`, \"domain\")\n : row;\n }),\n ),\n ).pipe(guard(\"attachments.create\")),\n get: (id) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n Effect.flatMap(requireAttachment(ownerId, id), attachmentOf),\n ).pipe(guard(\"attachments.get\")),\n byDomain: (domain) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n sql<AttachmentRow>`\n SELECT * FROM ${attachments} WHERE owner_id = ${ownerId} AND domain = ${domain}\n `.pipe(\n Effect.flatMap((rows) =>\n rows[0] === undefined\n ? Effect.succeedNone\n : Effect.map(attachmentOf(rows[0]), Option.some),\n ),\n ),\n ).pipe(guard(\"attachments.byDomain\")),\n list: (connectionId) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n Effect.gen(function* () {\n yield* requireConnection(ownerId, connectionId);\n const rows = yield* sql<AttachmentRow>`\n SELECT * FROM ${attachments}\n WHERE owner_id = ${ownerId} AND connection_id = ${connectionId}\n ORDER BY created_at\n `;\n return yield* Effect.forEach(rows, attachmentOf);\n }),\n ).pipe(guard(\"attachments.list\")),\n remove: (id) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n sql.withTransaction(\n Effect.gen(function* () {\n yield* requireAttachment(ownerId, id);\n // Readiness is keyed by domain and outlives the attachment, so clear the link\n // rather than the row: what was observed about the domain is still true, and a\n // dangling attachment id would fail the next `readiness.put`.\n yield* sql`\n UPDATE ${readiness} SET attachment_id = NULL\n WHERE attachment_id = ${id} AND owner_id = ${ownerId}\n `;\n yield* sql`DELETE FROM ${attachments} WHERE id = ${id} AND owner_id = ${ownerId}`;\n }),\n ),\n ).pipe(guard(\"attachments.remove\")),\n },\n continuations: {\n put: (continuation) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n Effect.gen(function* () {\n if (continuation.ownerId !== ownerId) {\n return yield* invalid(\"Continuation owner does not match the principal\", \"ownerId\");\n }\n const encoded = yield* continuationCodec.write(continuation);\n yield* sql`\n INSERT INTO ${continuations} (\n id, owner_id, actor_id, provider, payload, return_to, expires_at\n ) VALUES (\n ${encoded.id}, ${encoded.ownerId}, ${encoded.actorId}, ${encoded.provider},\n ${toJson(encoded.payload)}, ${encoded.returnTo}, ${at(encoded.expiresAt)}\n ) ON CONFLICT (id) DO UPDATE SET\n owner_id = EXCLUDED.owner_id,\n actor_id = EXCLUDED.actor_id,\n provider = EXCLUDED.provider,\n payload = EXCLUDED.payload,\n return_to = EXCLUDED.return_to,\n expires_at = EXCLUDED.expires_at\n `;\n }),\n ).pipe(guard(\"continuations.put\")),\n get: (id) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n Effect.gen(function* () {\n // A read, not a claim: the row survives so `consume` can still spend it.\n const rows = yield* sql<ContinuationRow>`\n SELECT * FROM ${continuations} WHERE id = ${id} AND owner_id = ${ownerId}\n `;\n if (rows[0] === undefined) return yield* notFound(\"continuation\", id);\n const continuation = yield* continuationOf(rows[0]);\n const instant = yield* DateTime.now;\n return DateTime.toEpochMillis(continuation.expiresAt) <=\n DateTime.toEpochMillis(instant)\n ? yield* fail(new Reason.Expired({ entity: \"continuation\", id }))\n : continuation;\n }),\n ).pipe(guard(\"continuations.get\")),\n header: (id) =>\n Effect.gen(function* () {\n // No owner filter, unlike everything else in this module: the provider callback has to\n // learn whose flow it is finishing before it can resolve a principal to scope by. The\n // projection is the enforcement — `payload` is never selected, so the PKCE verifier\n // stays behind the owner-scoped `get`.\n const rows = yield* sql<ContinuationHeaderRow>`\n SELECT owner_id, actor_id, provider, expires_at\n FROM ${continuations} WHERE id = ${id}\n `;\n if (rows[0] === undefined) return yield* notFound(\"continuation\", id);\n const header = yield* continuationHeaderOf(rows[0]);\n const instant = yield* DateTime.now;\n return DateTime.toEpochMillis(header.expiresAt) <= DateTime.toEpochMillis(instant)\n ? yield* fail(new Reason.Expired({ entity: \"continuation\", id }))\n : header;\n }).pipe(guard(\"continuations.header\")),\n consume: (id) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n Effect.gen(function* () {\n // The delete is the claim: a second consume finds nothing, expired or not.\n const rows = yield* sql<ContinuationRow>`\n DELETE FROM ${continuations}\n WHERE id = ${id} AND owner_id = ${ownerId} RETURNING *\n `;\n if (rows[0] === undefined) return yield* notFound(\"continuation\", id);\n const continuation = yield* continuationOf(rows[0]);\n const instant = yield* DateTime.now;\n return DateTime.toEpochMillis(continuation.expiresAt) <=\n DateTime.toEpochMillis(instant)\n ? yield* fail(new Reason.Expired({ entity: \"continuation\", id }))\n : continuation;\n }),\n ).pipe(guard(\"continuations.consume\")),\n },\n attempts: {\n create: (attempt) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n Effect.gen(function* () {\n if (attempt.ownerId !== ownerId) {\n return yield* invalid(\"Attempt owner does not match the principal\", \"ownerId\");\n }\n const encoded = yield* attemptCodec.write(attempt);\n const inserted = yield* sql<{ readonly id: string }>`\n INSERT INTO ${attempts} (\n id, owner_id, attachment_id, kind, status, plan, approval, approval_id,\n receipt, receipt_id, rejection, source_receipt_id, lease_expires_at, failure,\n plan_created_at, updated_at\n ) VALUES (\n ${encoded.id}, ${encoded.ownerId}, ${encoded.attachmentId}, ${encoded.kind},\n ${encoded.status}, ${toJson(encoded.plan)}, ${toJsonOrNull(encoded.approval)},\n ${attempt.approval?.id ?? null}, ${toJsonOrNull(encoded.receipt)},\n ${attempt.receipt?.id ?? null}, ${toJsonOrNull(encoded.rejection)},\n ${encoded.sourceReceiptId},\n ${atOrNull(encoded.leaseExpiresAt)}, ${encoded.failure},\n ${at(encoded.plan.createdAt)}, ${at(encoded.updatedAt)}\n ) ON CONFLICT (id) DO NOTHING RETURNING id\n `;\n return inserted[0] === undefined\n ? yield* invalid(`Plan ${attempt.id} already exists`, \"id\")\n : attempt;\n }),\n ).pipe(guard(\"attempts.create\")),\n get: (id) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n sql<AttemptRow>`\n SELECT * FROM ${attempts} WHERE id = ${id} AND owner_id = ${ownerId}\n `.pipe(\n Effect.flatMap((rows) =>\n rows[0] === undefined ? notFound(\"plan\", id) : attemptOf(rows[0]),\n ),\n ),\n ).pipe(guard(\"attempts.get\")),\n byApproval: (id) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n sql<AttemptRow>`\n SELECT * FROM ${attempts} WHERE approval_id = ${id} AND owner_id = ${ownerId}\n `.pipe(\n Effect.flatMap((rows) =>\n rows[0] === undefined ? notFound(\"approval\", id) : attemptOf(rows[0]),\n ),\n ),\n ).pipe(guard(\"attempts.byApproval\")),\n byReceipt: (id) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n sql<AttemptRow>`\n SELECT * FROM ${attempts} WHERE receipt_id = ${id} AND owner_id = ${ownerId}\n `.pipe(\n Effect.flatMap((rows) =>\n rows[0] === undefined ? notFound(\"receipt\", id) : attemptOf(rows[0]),\n ),\n ),\n ).pipe(guard(\"attempts.byReceipt\")),\n latest: (attachmentId, kind) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n sql<AttemptRow>`\n SELECT * FROM ${attempts}\n WHERE owner_id = ${ownerId} AND attachment_id = ${attachmentId} AND kind = ${kind}\n ORDER BY plan_created_at DESC, updated_at DESC LIMIT 1\n `.pipe(\n Effect.flatMap((rows) =>\n rows[0] === undefined\n ? Effect.succeedNone\n : Effect.map(attemptOf(rows[0]), Option.some),\n ),\n ),\n ).pipe(guard(\"attempts.latest\")),\n approve: (id, approval) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n sql.withTransaction(\n Effect.gen(function* () {\n const current = yield* lockedAttempt(ownerId, id);\n // Replaying the same approval is how a retried request stays safe.\n if (current.approval?.id === approval.id) return current;\n if (current.status !== \"planned\") return yield* stale(current);\n const next = new Storage.Attempt({\n ...current,\n status: \"approved\",\n approval,\n updatedAt: yield* DateTime.now,\n });\n const encoded = yield* attemptCodec.write(next);\n yield* sql`\n UPDATE ${attempts} SET\n status = ${encoded.status},\n approval = ${toJsonOrNull(encoded.approval)},\n approval_id = ${approval.id},\n updated_at = ${at(encoded.updatedAt)}\n WHERE id = ${id} AND owner_id = ${ownerId}\n `;\n return next;\n }),\n ),\n ).pipe(guard(\"attempts.approve\")),\n reject: (id, input) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n sql.withTransaction(\n Effect.gen(function* () {\n const current = yield* lockedAttempt(ownerId, id);\n // Terminal: a second rejection is the same outcome, so it returns the first one.\n if (current.status === \"rejected\") return current;\n if (current.status === \"expired\") {\n return yield* fail(new Reason.Expired({ entity: \"plan\", id }));\n }\n // A digest mismatch means the reviewer declined a plan that is no longer current.\n if (current.status !== \"planned\" || current.plan.digest !== input.digest) {\n return yield* stale(current);\n }\n const instant = yield* DateTime.now;\n const next = new Storage.Attempt({\n ...current,\n status: \"rejected\",\n rejection: { actorId: input.actorId, reason: input.reason, at: instant },\n updatedAt: instant,\n });\n const encoded = yield* attemptCodec.write(next);\n yield* sql`\n UPDATE ${attempts} SET\n status = ${encoded.status},\n rejection = ${toJsonOrNull(encoded.rejection)},\n updated_at = ${at(encoded.updatedAt)}\n WHERE id = ${id} AND owner_id = ${ownerId}\n `;\n return next;\n }),\n ),\n ).pipe(guard(\"attempts.reject\")),\n claim: (id, lease) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n sql.withTransaction(\n Effect.gen(function* () {\n const current = yield* lockedAttempt(ownerId, id);\n const instant = yield* DateTime.now;\n if (current.status === \"applying\") {\n const held =\n current.leaseExpiresAt !== null &&\n DateTime.toEpochMillis(current.leaseExpiresAt) >\n DateTime.toEpochMillis(instant);\n if (held) return yield* busy(`apply:${id}`);\n } else if (current.status !== \"approved\" && current.status !== \"failed\") {\n return yield* stale(current);\n }\n const next = new Storage.Attempt({\n ...current,\n status: \"applying\",\n leaseExpiresAt: lease,\n failure: null,\n updatedAt: instant,\n });\n const encoded = yield* attemptCodec.write(next);\n yield* sql`\n UPDATE ${attempts} SET\n status = ${encoded.status},\n lease_expires_at = ${atOrNull(encoded.leaseExpiresAt)},\n failure = NULL,\n updated_at = ${at(encoded.updatedAt)}\n WHERE id = ${id} AND owner_id = ${ownerId}\n `;\n return next;\n }),\n ),\n ).pipe(guard(\"attempts.claim\")),\n complete: (id, receipt) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n sql.withTransaction(\n Effect.gen(function* () {\n const current = yield* lockedAttempt(ownerId, id);\n if (current.status !== \"applying\") return yield* stale(current);\n const next = new Storage.Attempt({\n ...current,\n status: receipt.status,\n receipt,\n leaseExpiresAt: null,\n updatedAt: yield* DateTime.now,\n });\n const encoded = yield* attemptCodec.write(next);\n yield* sql`\n UPDATE ${attempts} SET\n status = ${encoded.status},\n receipt = ${toJsonOrNull(encoded.receipt)},\n receipt_id = ${receipt.id},\n lease_expires_at = NULL,\n updated_at = ${at(encoded.updatedAt)}\n WHERE id = ${id} AND owner_id = ${ownerId}\n `;\n return next;\n }),\n ),\n ).pipe(guard(\"attempts.complete\")),\n fail: (id, message) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n sql.withTransaction(\n Effect.gen(function* () {\n const current = yield* lockedAttempt(ownerId, id);\n if (current.status !== \"applying\") return yield* stale(current);\n const next = new Storage.Attempt({\n ...current,\n status: \"failed\",\n failure: message,\n leaseExpiresAt: null,\n updatedAt: yield* DateTime.now,\n });\n const encoded = yield* attemptCodec.write(next);\n yield* sql`\n UPDATE ${attempts} SET\n status = ${encoded.status},\n failure = ${message},\n lease_expires_at = NULL,\n updated_at = ${at(encoded.updatedAt)}\n WHERE id = ${id} AND owner_id = ${ownerId}\n `;\n return next;\n }),\n ),\n ).pipe(guard(\"attempts.fail\")),\n },\n batches: {\n create: (input) =>\n Effect.flatMap(Principal.Service, ({ actorId, ownerId }) =>\n sql.withTransaction(\n Effect.gen(function* () {\n const replayed = (row: BatchRow) =>\n Effect.flatMap(batchOf(row), (batch) => aggregateOf(ownerId, batch));\n const existing = yield* sql<BatchRow>`\n SELECT * FROM ${batches}\n WHERE owner_id = ${ownerId} AND idempotency_key = ${input.idempotencyKey}\n `;\n // A retried create is the same batch, whatever the second call asks for.\n if (existing[0] !== undefined) return yield* replayed(existing[0]);\n if (input.attachmentIds.length === 0) {\n return yield* invalid(\"A batch needs at least one attachment\", \"attachmentIds\");\n }\n if (new Set(input.attachmentIds).size !== input.attachmentIds.length) {\n return yield* invalid(\"A batch holds one item per attachment\", \"attachmentIds\");\n }\n for (const attachmentId of input.attachmentIds) {\n yield* requireAttachment(ownerId, attachmentId);\n }\n const instant = yield* DateTime.now;\n const batch = new Storage.Batch({\n id: Storage.BatchId.make(yield* fresh(\"batch\")),\n ownerId,\n kind: input.kind,\n status: \"planning\",\n digest: null,\n approval: null,\n rejection: null,\n idempotencyKey: input.idempotencyKey,\n createdBy: actorId,\n createdAt: instant,\n updatedAt: instant,\n completedAt: null,\n });\n const encoded = yield* batchCodec.write(batch);\n // The unique key decides the race rather than the read above: a concurrent create\n // under the same key loses the insert and reads the batch it lost to.\n const inserted = yield* sql<{ readonly id: string }>`\n INSERT INTO ${batches} (\n id, owner_id, kind, status, digest, approval, rejection, idempotency_key,\n created_by, created_at, updated_at, completed_at\n ) VALUES (\n ${encoded.id}, ${encoded.ownerId}, ${encoded.kind}, ${encoded.status},\n ${encoded.digest}, ${toJsonOrNull(encoded.approval)},\n ${toJsonOrNull(encoded.rejection)}, ${encoded.idempotencyKey},\n ${encoded.createdBy}, ${at(encoded.createdAt)}, ${at(encoded.updatedAt)},\n ${atOrNull(encoded.completedAt)}\n ) ON CONFLICT (owner_id, idempotency_key) DO NOTHING RETURNING id\n `;\n if (inserted[0] === undefined) {\n const winner = yield* sql<BatchRow>`\n SELECT * FROM ${batches}\n WHERE owner_id = ${ownerId} AND idempotency_key = ${input.idempotencyKey}\n `;\n return winner[0] === undefined\n ? yield* notFound(\"batch\", input.idempotencyKey)\n : yield* replayed(winner[0]);\n }\n const items = input.attachmentIds.map(\n (attachmentId, position) =>\n new Storage.BatchItem({\n batchId: batch.id,\n attachmentId,\n position,\n attemptId: null,\n planFailure: null,\n }),\n );\n for (const item of items) {\n yield* sql`\n INSERT INTO ${batchItems} (\n batch_id, attachment_id, \"position\", attempt_id, plan_failure\n ) VALUES (\n ${item.batchId}, ${item.attachmentId}, ${item.position}, ${item.attemptId},\n ${item.planFailure}\n )\n `;\n }\n return { batch, items };\n }),\n ),\n ).pipe(guard(\"batches.create\")),\n get: (id) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n Effect.flatMap(requireBatch(ownerId, id), (batch) => aggregateOf(ownerId, batch)),\n ).pipe(guard(\"batches.get\")),\n byIdempotencyKey: (key) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n sql<BatchRow>`\n SELECT * FROM ${batches}\n WHERE owner_id = ${ownerId} AND idempotency_key = ${key}\n `.pipe(\n Effect.flatMap((rows) =>\n rows[0] === undefined\n ? Effect.succeedNone\n : Effect.flatMap(batchOf(rows[0]), (batch) =>\n Effect.map(aggregateOf(ownerId, batch), Option.some),\n ),\n ),\n ),\n ).pipe(guard(\"batches.byIdempotencyKey\")),\n listUnfinished: () =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n Effect.gen(function* () {\n const rows = yield* sql<BatchRow>`\n SELECT * FROM ${batches}\n WHERE owner_id = ${ownerId} AND status NOT IN ('complete', 'rejected')\n ORDER BY updated_at DESC\n `;\n if (rows.length === 0) return [];\n const list = yield* Effect.forEach(rows, batchOf);\n // Items are pointers, so the whole index is two queries: no attempt is read here.\n const itemsRows = yield* sql<BatchItemRow>`\n SELECT batch_id, attachment_id, \"position\", attempt_id, plan_failure\n FROM ${batchItems}\n WHERE ${sql.in(\n \"batch_id\",\n list.map(({ id }) => id),\n )}\n ORDER BY \"position\" ASC\n `;\n const items = yield* Effect.forEach(itemsRows, batchItemOf);\n return list.map((batch) => ({\n batch,\n items: items.filter((item) => item.batchId === batch.id),\n }));\n }),\n ).pipe(guard(\"batches.listUnfinished\")),\n recordItemPlan: (id, attachmentId, attemptId) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n sql.withTransaction(\n Effect.gen(function* () {\n const batch = yield* lockedBatch(ownerId, id);\n // The fence: a planning pass still in flight must not land state on a batch the\n // principal declined, or on one already bound to an approved digest.\n if (batch.status !== \"planning\" && batch.status !== \"planned\") {\n return yield* batchStale(batch);\n }\n const attempt = yield* requireAttempt(ownerId, attemptId);\n if (attempt.attachment_id !== attachmentId || attempt.kind !== batch.kind) {\n return yield* invalid(\n `Plan ${attemptId} does not belong to attachment ${attachmentId} in this batch`,\n \"attemptId\",\n );\n }\n const updated = yield* sql<{ readonly attachment_id: string }>`\n UPDATE ${batchItems} SET attempt_id = ${attemptId}, plan_failure = NULL\n WHERE batch_id = ${id} AND attachment_id = ${attachmentId}\n RETURNING attachment_id\n `;\n return updated[0] === undefined\n ? yield* notFound(\"attachment\", attachmentId)\n : yield* settled(ownerId, batch);\n }),\n ),\n ).pipe(guard(\"batches.recordItemPlan\")),\n recordItemPlanFailure: (id, attachmentId, message) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n sql.withTransaction(\n Effect.gen(function* () {\n const batch = yield* lockedBatch(ownerId, id);\n if (batch.status !== \"planning\" && batch.status !== \"planned\") {\n return yield* batchStale(batch);\n }\n const updated = yield* sql<{ readonly attachment_id: string }>`\n UPDATE ${batchItems} SET attempt_id = NULL, plan_failure = ${message}\n WHERE batch_id = ${id} AND attachment_id = ${attachmentId}\n RETURNING attachment_id\n `;\n return updated[0] === undefined\n ? yield* notFound(\"attachment\", attachmentId)\n : yield* settled(ownerId, batch);\n }),\n ),\n ).pipe(guard(\"batches.recordItemPlanFailure\")),\n approve: (id, input) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n sql.withTransaction(\n Effect.gen(function* () {\n const batch = yield* lockedBatch(ownerId, id);\n // Replaying the same approval is how a retried request stays safe.\n if (batch.approval !== null) {\n return batch.digest === input.digest\n ? yield* aggregateOf(ownerId, batch)\n : yield* batchStale(batch);\n }\n if (batch.status !== \"planned\") return yield* batchStale(batch);\n const items = yield* Effect.forEach(yield* itemRows(ownerId, id), batchItemOf);\n const pairs: Array<{\n readonly attemptId: Plan.PlanId;\n readonly approval: Approval.Model;\n }> = [];\n for (const item of items) {\n const supplied = input.approvals.find(\n (entry) => entry.attachmentId === item.attachmentId,\n );\n if (supplied === undefined) {\n return yield* invalid(\n `Batch ${id} has no approval for attachment ${item.attachmentId}`,\n \"approvals\",\n );\n }\n // The item has to still point at the attempt this approval names: anything else\n // means the batch was re-planned after the principal reviewed it.\n if (item.attemptId === null || item.attemptId !== supplied.approval.planId) {\n return yield* batchStale(batch);\n }\n pairs.push({ attemptId: item.attemptId, approval: supplied.approval });\n }\n const instant = yield* DateTime.now;\n // The per-attempt approvals and the batch's own are one transaction: a batch is\n // never approved without the approvals `attempts.apply` takes.\n for (const pair of pairs) {\n const current = yield* lockedAttempt(ownerId, pair.attemptId);\n if (current.approval?.id === pair.approval.id) continue;\n if (current.status !== \"planned\") return yield* stale(current);\n const next = new Storage.Attempt({\n ...current,\n status: \"approved\",\n approval: pair.approval,\n updatedAt: instant,\n });\n const encoded = yield* attemptCodec.write(next);\n yield* sql`\n UPDATE ${attempts} SET\n status = ${encoded.status},\n approval = ${toJsonOrNull(encoded.approval)},\n approval_id = ${pair.approval.id},\n updated_at = ${at(encoded.updatedAt)}\n WHERE id = ${pair.attemptId} AND owner_id = ${ownerId}\n `;\n }\n return yield* settled(\n ownerId,\n new Storage.Batch({\n ...batch,\n digest: input.digest,\n approval: { actorId: input.actorId, at: instant },\n }),\n );\n }),\n ),\n ).pipe(guard(\"batches.approve\")),\n reject: (id, input) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n sql.withTransaction(\n Effect.gen(function* () {\n const batch = yield* lockedBatch(ownerId, id);\n // Terminal: a second rejection is the same outcome, so it returns the first one.\n if (batch.rejection !== null) return yield* aggregateOf(ownerId, batch);\n if (batch.status !== \"planning\" && batch.status !== \"planned\") {\n return yield* batchStale(batch);\n }\n const rows = yield* itemRows(ownerId, id);\n const instant = yield* DateTime.now;\n const rejection = {\n actorId: input.actorId,\n reason: input.reason,\n at: instant,\n };\n for (const row of rows) {\n if (row.attempt_id === null || row.attempt_status !== \"planned\") continue;\n const current = yield* lockedAttempt(ownerId, row.attempt_id);\n if (current.status !== \"planned\") continue;\n const next = new Storage.Attempt({\n ...current,\n status: \"rejected\",\n rejection,\n updatedAt: instant,\n });\n const encoded = yield* attemptCodec.write(next);\n yield* sql`\n UPDATE ${attempts} SET\n status = ${encoded.status},\n rejection = ${toJsonOrNull(encoded.rejection)},\n updated_at = ${at(encoded.updatedAt)}\n WHERE id = ${row.attempt_id} AND owner_id = ${ownerId}\n `;\n }\n return yield* settled(ownerId, new Storage.Batch({ ...batch, rejection }));\n }),\n ),\n ).pipe(guard(\"batches.reject\")),\n refresh: (id) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n sql.withTransaction(\n Effect.flatMap(lockedBatch(ownerId, id), (batch) => settled(ownerId, batch)),\n ),\n ).pipe(guard(\"batches.refresh\")),\n },\n readiness: {\n put: (row) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n Effect.gen(function* () {\n if (row.ownerId !== ownerId) {\n return yield* invalid(\"Readiness owner does not match the principal\", \"ownerId\");\n }\n // A linked attachment has to exist for this owner; observe-only readiness has none.\n if (row.attachmentId !== null) yield* requireAttachment(ownerId, row.attachmentId);\n const encoded = yield* readinessCodec.write(row);\n yield* sql`\n INSERT INTO ${readiness} (\n owner_id, domain, attachment_id, overall, requirements, host, pending_since,\n checked_at, next_check_at\n ) VALUES (\n ${encoded.ownerId}, ${encoded.domain}, ${encoded.attachmentId},\n ${encoded.overall}, ${toJson(encoded.requirements)}, ${toJson(encoded.host)},\n ${atOrNull(encoded.pendingSince)}, ${at(encoded.checkedAt)},\n ${atOrNull(encoded.nextCheckAt)}\n ) ON CONFLICT (owner_id, domain) DO UPDATE SET\n attachment_id = EXCLUDED.attachment_id,\n overall = EXCLUDED.overall,\n requirements = EXCLUDED.requirements,\n host = EXCLUDED.host,\n pending_since = EXCLUDED.pending_since,\n checked_at = EXCLUDED.checked_at,\n next_check_at = EXCLUDED.next_check_at\n `;\n }),\n ).pipe(guard(\"readiness.put\")),\n get: (domain) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n sql<ReadinessRow>`\n SELECT * FROM ${readiness}\n WHERE owner_id = ${ownerId} AND domain = ${domain}\n `.pipe(\n Effect.flatMap((rows) =>\n rows[0] === undefined\n ? Effect.succeedNone\n : Effect.map(readinessOf(rows[0]), Option.some),\n ),\n ),\n ).pipe(guard(\"readiness.get\")),\n },\n withLock: (key, effect) =>\n Effect.flatMap(Principal.Service, ({ ownerId }) =>\n Effect.scoped(\n Effect.gen(function* () {\n // A session lock, not a transaction lock: the guarded effect refreshes a credential\n // against the provider, and no transaction should stay open across an HTTP call.\n // `reserve` pins one pooled connection so the unlock runs on the session that took\n // the lock, and registering it after the connection makes it run first on release.\n const connection = yield* Effect.mapError(sql.reserve, (error) =>\n storageFailed(\"withLock\", sqlMessage(error)),\n );\n const scoped = `${ownerId}:${key}`;\n yield* Effect.acquireRelease(\n connection\n .execute(\n \"SELECT pg_try_advisory_lock(hashtextextended($1, 0)) AS acquired\",\n [scoped],\n undefined,\n )\n .pipe(\n Effect.mapError((error: SqlError.SqlError) =>\n storageFailed(\"withLock\", sqlMessage(error)),\n ),\n Effect.flatMap((rows: ReadonlyArray<{ readonly acquired: boolean }>) =>\n rows[0]?.acquired === true ? Effect.void : busy(key),\n ),\n ),\n () =>\n connection\n .execute(\n \"SELECT pg_advisory_unlock(hashtextextended($1, 0))\",\n [scoped],\n undefined,\n )\n .pipe(Effect.ignore),\n );\n return yield* effect;\n }),\n ),\n ),\n };\n\n return service;\n });\n","/**\n * The eight tables DomainKit owns, declared once and rendered per dialect by CapsuleDB.\n *\n * Every table carries `owner_id` and every query filters by it: tenancy is a column, not a schema.\n * There are no foreign keys to host tables, and none between DomainKit's own tables either, so a\n * host can add its own in the emitted migration without fighting a constraint the package owns.\n */\nimport { Schema } from \"capsuledb\";\n\nexport interface Tables {\n readonly authorizations: Schema.Table;\n readonly connections: Schema.Table;\n readonly attachments: Schema.Table;\n readonly continuations: Schema.Table;\n readonly attempts: Schema.Table;\n readonly readiness: Schema.Table;\n readonly batches: Schema.Table;\n readonly batchItems: Schema.Table;\n}\n\n/** Default table prefix. Part of the physical layout, so it is immutable after the first deploy. */\nexport const DEFAULT_PREFIX = \"domainkit\";\n\n/**\n * Declare the eight tables under `prefix`.\n *\n * `Schema.table` validates every identifier it will quote, so an invalid prefix throws\n * `CapsuleDefinitionError` here rather than reaching a renderer.\n */\nexport const make = (prefix: string): Tables => ({\n authorizations: Schema.table(`${prefix}_authorizations`, {\n columns: {\n id: Schema.text(),\n owner_id: Schema.text(),\n provider: Schema.text(),\n method: Schema.text(),\n capabilities: Schema.json(),\n context: Schema.json(),\n /**\n * What the provider called the account when the credential was issued, so a UI names the\n * connection offline. Null names no account, which is also what rows written before the\n * column existed carry.\n */\n label: Schema.text({ nullable: true }),\n revocation: Schema.text(),\n created_by: Schema.text(),\n created_at: Schema.timestamp(),\n credential_ciphertext: Schema.text(),\n credential_expires_at: Schema.timestamp({ nullable: true }),\n credential_rotated_at: Schema.timestamp(),\n updated_at: Schema.timestamp(),\n },\n primaryKey: [\"id\"],\n indexes: [{ columns: [\"owner_id\", \"revocation\"] }, { columns: [\"owner_id\", \"provider\"] }],\n }),\n connections: Schema.table(`${prefix}_connections`, {\n columns: {\n id: Schema.text(),\n owner_id: Schema.text(),\n authorization_id: Schema.text(),\n created_at: Schema.timestamp(),\n },\n primaryKey: [\"id\"],\n indexes: [{ columns: [\"owner_id\"] }, { columns: [\"authorization_id\"] }],\n }),\n attachments: Schema.table(`${prefix}_attachments`, {\n columns: {\n id: Schema.text(),\n owner_id: Schema.text(),\n connection_id: Schema.text(),\n domain: Schema.text(),\n zone: Schema.text(),\n /**\n * The provider's label for the zone at attach time, so a UI names the account offline. The\n * default is what fills the rows an installation attached before the column existed.\n */\n label: Schema.text({ default: \"\" }),\n target: Schema.json(),\n created_at: Schema.timestamp(),\n },\n primaryKey: [\"id\"],\n // One attachment per domain per tenant; `attachments.create` reads the conflict as InvalidInput.\n uniques: [[\"owner_id\", \"domain\"]],\n indexes: [{ columns: [\"owner_id\", \"connection_id\"] }],\n }),\n continuations: Schema.table(`${prefix}_continuations`, {\n columns: {\n id: Schema.text(),\n owner_id: Schema.text(),\n actor_id: Schema.text(),\n provider: Schema.text(),\n payload: Schema.json(),\n return_to: Schema.text({ nullable: true }),\n expires_at: Schema.timestamp(),\n },\n primaryKey: [\"id\"],\n // Hosts sweep expired rows on this index; consume deletes the row it returns.\n indexes: [{ columns: [\"expires_at\"] }],\n }),\n attempts: Schema.table(`${prefix}_attempts`, {\n columns: {\n id: Schema.text(),\n owner_id: Schema.text(),\n attachment_id: Schema.text(),\n kind: Schema.text(),\n status: Schema.text(),\n plan: Schema.json(),\n approval: Schema.json({ nullable: true }),\n /** Denormalized from `approval` so `byApproval` is an index lookup. */\n approval_id: Schema.text({ nullable: true }),\n receipt: Schema.json({ nullable: true }),\n /** Denormalized from `receipt` so `byReceipt` is an index lookup. */\n receipt_id: Schema.text({ nullable: true }),\n /** Who declined the plan, why, and when; set when an attempt reaches `rejected`. */\n rejection: Schema.json({ nullable: true }),\n source_receipt_id: Schema.text({ nullable: true }),\n lease_expires_at: Schema.timestamp({ nullable: true }),\n failure: Schema.text({ nullable: true }),\n /** The plan's own `createdAt`; `latest` orders by it. */\n plan_created_at: Schema.timestamp(),\n updated_at: Schema.timestamp(),\n },\n primaryKey: [\"id\"],\n indexes: [\n { columns: [\"owner_id\", \"attachment_id\", \"kind\"] },\n { columns: [\"owner_id\", \"approval_id\"] },\n { columns: [\"owner_id\", \"receipt_id\"] },\n ],\n }),\n readiness: Schema.table(`${prefix}_readiness`, {\n columns: {\n owner_id: Schema.text(),\n domain: Schema.text(),\n /** Set while an attachment covers the domain; observe-only readiness leaves it null. */\n attachment_id: Schema.text({ nullable: true }),\n overall: Schema.text(),\n requirements: Schema.json(),\n host: Schema.json(),\n pending_since: Schema.timestamp({ nullable: true }),\n checked_at: Schema.timestamp(),\n next_check_at: Schema.timestamp({ nullable: true }),\n },\n // Keyed by domain, not by attachment, so a host observing public DNS alone gets the same row.\n primaryKey: [\"owner_id\", \"domain\"],\n // The sweep index drives the backoff ladder; the attachment index is for clearing the link.\n indexes: [{ columns: [\"owner_id\", \"next_check_at\"] }, { columns: [\"attachment_id\"] }],\n }),\n batches: Schema.table(`${prefix}_batches`, {\n columns: {\n id: Schema.text(),\n owner_id: Schema.text(),\n kind: Schema.text(),\n status: Schema.text(),\n /** SHA-256 over the items' `attachmentId:planDigest` pairs; set when the batch is approved. */\n digest: Schema.text({ nullable: true }),\n /** Who bound the digest, and when; the per-attempt approvals live on the attempts. */\n approval: Schema.json({ nullable: true }),\n rejection: Schema.json({ nullable: true }),\n idempotency_key: Schema.text(),\n created_by: Schema.text(),\n created_at: Schema.timestamp(),\n updated_at: Schema.timestamp(),\n /** When the batch reached `complete` or `rejected`; null while it still owes a move. */\n completed_at: Schema.timestamp({ nullable: true }),\n },\n primaryKey: [\"id\"],\n // One batch per key per tenant; `batches.create` reads the conflict as a replay.\n uniques: [[\"owner_id\", \"idempotency_key\"]],\n // The owner-scoped unfinished index, newest first.\n indexes: [{ columns: [\"owner_id\", \"status\", \"updated_at\"] }],\n }),\n batchItems: Schema.table(`${prefix}_batch_items`, {\n columns: {\n batch_id: Schema.text(),\n attachment_id: Schema.text(),\n /** The item's place in the batch, as `batches.create` received it. */\n position: Schema.integer(),\n /** The attempt carrying this item's plan; null until one lands. */\n attempt_id: Schema.text({ nullable: true }),\n /** Why the last planning pass stopped here; cleared when a plan lands. */\n plan_failure: Schema.text({ nullable: true }),\n },\n // One item per attachment per batch, which is what makes a replayed plan write idempotent.\n primaryKey: [\"batch_id\", \"attachment_id\"],\n indexes: [{ columns: [\"attempt_id\"] }],\n }),\n});\n\n/**\n * The authorizations table as the first migration created it, before `label`.\n *\n * Frozen for the same reason as `attachmentsV1`: migration 1 renders this shape, and the migration\n * that adds the column carries the difference.\n */\nexport const authorizationsV1 = (prefix: string): Schema.Table =>\n Schema.table(`${prefix}_authorizations`, {\n columns: {\n id: Schema.text(),\n owner_id: Schema.text(),\n provider: Schema.text(),\n method: Schema.text(),\n capabilities: Schema.json(),\n context: Schema.json(),\n revocation: Schema.text(),\n created_by: Schema.text(),\n created_at: Schema.timestamp(),\n credential_ciphertext: Schema.text(),\n credential_expires_at: Schema.timestamp({ nullable: true }),\n credential_rotated_at: Schema.timestamp(),\n updated_at: Schema.timestamp(),\n },\n primaryKey: [\"id\"],\n indexes: [{ columns: [\"owner_id\", \"revocation\"] }, { columns: [\"owner_id\", \"provider\"] }],\n });\n\n/**\n * The attachments table as the first migration created it, before `label`.\n *\n * A migration is history: what it renders must not move, or an installation that already ran it\n * sees a different checksum for work it has done. The declaration above is the current shape, and\n * the migration that adds the column carries the difference.\n */\nexport const attachmentsV1 = (prefix: string): Schema.Table =>\n Schema.table(`${prefix}_attachments`, {\n columns: {\n id: Schema.text(),\n owner_id: Schema.text(),\n connection_id: Schema.text(),\n domain: Schema.text(),\n zone: Schema.text(),\n target: Schema.json(),\n created_at: Schema.timestamp(),\n },\n primaryKey: [\"id\"],\n uniques: [[\"owner_id\", \"domain\"]],\n indexes: [{ columns: [\"owner_id\", \"connection_id\"] }],\n });\n\nexport const list = (tables: Tables): ReadonlyArray<Schema.Table> => [\n ...initial(tables),\n tables.batches,\n tables.batchItems,\n];\n\n/**\n * The tables the first migration creates.\n *\n * A migration is history: what it renders must not move, so a table added later is declared above\n * and created by its own migration rather than joining this list.\n */\nexport const initial = (tables: Tables): ReadonlyArray<Schema.Table> => [\n tables.authorizations,\n tables.connections,\n tables.attachments,\n tables.continuations,\n tables.attempts,\n tables.readiness,\n];\n","/**\n * DomainKit's CapsuleDB capsule: eight tables and one `Storage.Service` implementation.\n *\n * The capsule is a plain value, so a host imports it, points `capsuledb emit` at it, or hands it\n * to `Registry.layer` without running an Effect first.\n */\nimport { Capsule, Migration } from \"capsuledb\";\nimport { Storage } from \"domainkit\";\nimport { Layer } from \"effect\";\nimport type * as SqlClient from \"effect/sql/SqlClient\";\n\nimport { make as makeService } from \"./internal/storage.ts\";\nimport {\n attachmentsV1,\n authorizationsV1,\n DEFAULT_PREFIX,\n initial,\n list,\n make as makeTables,\n} from \"./internal/tables.ts\";\n\nexport { DEFAULT_PREFIX };\n\n/**\n * Build the capsule for a table prefix.\n *\n * The prefix is part of the physical layout: it changes the rendered DDL and therefore the\n * migration checksums, so a deployed registry must keep the prefix it was created with.\n */\nexport const make = (\n prefix: string = DEFAULT_PREFIX,\n): Capsule.Capsule<Storage.Service, never, SqlClient.SqlClient> => {\n const tables = makeTables(prefix);\n return Capsule.make({\n id: \"domainkit.storage\",\n tables: list(tables),\n migrations: [\n Migration.make({\n id: 1,\n name: \"create-storage\",\n risk: \"additive\",\n steps: initial(tables).map((table) =>\n Migration.createTable(\n table.name === tables.attachments.name\n ? attachmentsV1(prefix)\n : table.name === tables.authorizations.name\n ? authorizationsV1(prefix)\n : table,\n ),\n ),\n }),\n // An installation that attached domains before the column existed keeps those rows: the\n // default fills them, and the backfill names each one after the zone it is attached to,\n // which is what the provider's label is built from.\n Migration.make({\n id: 2,\n name: \"attachment-label\",\n risk: \"additive\",\n steps: [\n Migration.addColumn(tables.attachments.name, \"label\", { type: \"text\", default: \"\" }),\n Migration.sql(\n Object.fromEntries(\n ([\"postgres\", \"sqlite\"] as const).map((dialect) => [\n dialect,\n [`UPDATE ${tables.attachments.name} SET label = zone WHERE label = ''`],\n ]),\n ),\n ),\n ],\n }),\n // An installation that connected accounts before the column existed keeps those rows\n // unnamed: the provider named the account at connect time, and nothing here can name it\n // after the fact without a credential.\n Migration.make({\n id: 3,\n name: \"authorization-label\",\n risk: \"additive\",\n steps: [\n Migration.addColumn(tables.authorizations.name, \"label\", {\n type: \"text\",\n nullable: true,\n }),\n ],\n }),\n // The batch aggregate: many attempts planned together and approved once. Both tables are\n // new, so an installation that ran migrations 1 to 3 gains them without touching a row it\n // already holds.\n Migration.make({\n id: 4,\n name: \"batches\",\n risk: \"additive\",\n steps: [Migration.createTable(tables.batches), Migration.createTable(tables.batchItems)],\n }),\n ],\n layer: Layer.effect(Storage.Service)(makeService(tables)),\n });\n};\n\n/** The capsule under the default `domainkit` prefix. `capsuledb emit --export capsule` reads this. */\nexport const capsule: Capsule.Capsule<Storage.Service, never, SqlClient.SqlClient> = make();\n","/**\n * The layer a host installs: DomainKit's `Storage` on the host's own PostgreSQL client.\n *\n * `layer()` runs the capsule through CapsuleDB's registry, which creates the ledger, applies\n * pending migrations, and only then provides `Storage`. A host that owns its migration pipeline\n * applies `capsuledb emit` output instead and boots with `mode: \"assert\"`, which touches no schema\n * and fails unless the database already matches the capsule.\n *\n * A serverless host prepares at deploy time instead: `manifest()` yields the manifest of exactly the\n * capsule `layer()` installs, a deploy stack hands it to `capsuledb/alchemy`, and the function boots\n * with `mode: \"assert\"` and `readiness: \"first-use\"`, which builds without a statement and checks the\n * database once, on the first Storage query.\n *\n * The layer requires only `SqlClient`: credentials arrive sealed, so Storage never needs `Custody`.\n */\nimport { Pg, type Manifest, type Registry as RegistryTypes, Registry } from \"capsuledb\";\nimport type { Storage } from \"domainkit\";\nimport type * as Effect from \"effect/Effect\";\nimport type * as Layer from \"effect/Layer\";\nimport type * as SqlClient from \"effect/sql/SqlClient\";\n\nimport { capsule, DEFAULT_PREFIX, make } from \"./capsule.ts\";\n\nexport interface Options {\n /** Table prefix. Default `domainkit`. Part of the physical layout; immutable after first deploy. */\n readonly prefix?: string;\n /** `prepare` (default) migrates at boot; `assert` expects the host applied `capsuledb emit` output. */\n readonly mode?: \"prepare\" | \"assert\";\n /**\n * Prefix for CapsuleDB's own ledger tables; default `capsuledb`. Set it only to match a prefix a\n * host already uses for other capsules, and pass the same value to `capsuledb emit --prefix`.\n */\n readonly registryPrefix?: string;\n /**\n * When the registry is checked. `boot` (default) prepares or asserts while the layer builds.\n * `first-use` builds with no statement and runs one cached check before the first Storage query,\n * so a cold start that never touches Storage does no registry work; a failed check surfaces as a\n * `SqlError` on that query and is retried on the next. Pair it with `mode: \"assert\"` on a host\n * whose database was prepared at deploy time.\n */\n readonly readiness?: \"boot\" | \"first-use\";\n}\n\n/** The capsule and registry prefix `layer` and `manifest` both derive from one set of options. */\nconst selection = (options: Options) => ({\n provider: Pg.profile,\n capsules: [\n options.prefix === undefined || options.prefix === DEFAULT_PREFIX\n ? capsule\n : make(options.prefix),\n ],\n ...(options.registryPrefix === undefined ? {} : { prefix: options.registryPrefix }),\n});\n\nexport const layer = (\n options: Options = {},\n): Layer.Layer<Storage.Service, RegistryTypes.RegistryRuntimeError, SqlClient.SqlClient> =>\n Registry.layer({\n ...selection(options),\n ...(options.mode === undefined ? {} : { mode: options.mode }),\n ...(options.readiness === undefined ? {} : { readiness: options.readiness }),\n });\n\n/**\n * The CapsuleDB manifest for exactly what `layer(options)` installs, computed without touching a\n * database. A deploy stack passes it to `CapsuleDB.Registry` from `capsuledb/alchemy`, so the\n * schema it prepares is the schema the runtime asserts. Only `prefix` and `registryPrefix` affect\n * it; `mode` and `readiness` are runtime choices.\n */\nexport const manifest = (\n options: Pick<Options, \"prefix\" | \"registryPrefix\"> = {},\n): Effect.Effect<Manifest.Manifest, RegistryTypes.RegistryError> =>\n Registry.manifest(selection(options));\n","/**\n * DomainKit's `Storage` on PostgreSQL, as one declarative CapsuleDB capsule.\n *\n * Hosts install `PgStorage.layer()` under `DomainKit.layer` and supply their own `SqlClient`. The\n * `capsule` value is the same declaration `capsuledb emit` reads to write SQL for a host-owned\n * migration pipeline.\n */\nimport packageJson from \"../package.json\" with { type: \"json\" };\n\nexport const VERSION = packageJson.version;\n\nexport * as PgStorage from \"./PgStorage.ts\";\nexport { capsule } from \"./capsule.ts\";\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@domainkit/capsuledb",
3
- "version": "0.18.0",
3
+ "version": "0.20.0",
4
4
  "description": "DomainKit Storage on PostgreSQL, as one declarative CapsuleDB capsule",
5
5
  "keywords": [
6
6
  "dns",
@@ -45,24 +45,24 @@
45
45
  "typecheck": "tsc --noEmit"
46
46
  },
47
47
  "dependencies": {
48
- "domainkit": "^0.18.0"
48
+ "domainkit": "^0.20.0"
49
49
  },
50
50
  "devDependencies": {
51
- "@effect/sql-pg": "4.0.0-rc.117",
52
- "@effect/vitest": "4.0.0-rc.117",
51
+ "@effect/sql-pg": "4.0.0",
52
+ "@effect/vitest": "4.0.0",
53
53
  "@testcontainers/postgresql": "12.1.0",
54
54
  "@types/bun": "1.4.0",
55
- "capsuledb": "0.3.0",
55
+ "capsuledb": "0.5.0",
56
56
  "drizzle-orm": "1.0.0-rc.5-ab785fc",
57
- "effect": "4.0.0-rc.117",
57
+ "effect": "4.0.0",
58
58
  "tsdown": "0.22.14",
59
59
  "typescript": "7.0.2",
60
60
  "vite": "7.1.12",
61
61
  "vitest": "5.0.1"
62
62
  },
63
63
  "peerDependencies": {
64
- "capsuledb": ">=0.3.0 <0.4.0",
65
- "effect": ">=4.0.0-rc.117 <5.0.0"
64
+ "capsuledb": ">=0.5.0 <0.6.0",
65
+ "effect": ">=4.0.0 <5.0.0"
66
66
  },
67
67
  "engines": {
68
68
  "node": ">=24.10.0"