domainkit 0.11.0 → 0.12.1
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/dist/Connect.mjs +157 -35
- package/dist/Connect.mjs.map +1 -1
- package/dist/Server.mjs +136 -22
- package/dist/Server.mjs.map +1 -1
- package/dist/Storage.mjs +2 -0
- package/dist/Storage.mjs.map +1 -1
- package/dist/Testing.mjs +2 -1
- package/dist/Testing.mjs.map +1 -1
- package/dist/Transport.mjs +25 -2
- package/dist/Transport.mjs.map +1 -1
- package/dist/internal/conformance/storage.mjs +16 -0
- package/dist/internal/conformance/storage.mjs.map +1 -1
- package/dist/internal/storage-memory.mjs +1 -0
- package/dist/internal/storage-memory.mjs.map +1 -1
- package/dist/package.mjs +1 -1
- package/dist/types/Connect.d.ts +63 -0
- package/dist/types/Server.d.ts +948 -26
- package/dist/types/Storage.d.ts +4 -0
- package/dist/types/Testing.d.ts +2 -0
- package/dist/types/Transport.d.ts +16 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage.mjs","names":["Principal.make","Errors.isDomainKitError","Storage.Authorization","Storage.Credential","Storage.Service","Principal.Service","Plan.Model","Plan.Create","DnsRecord.txt","Storage.Attempt","Approval.Model","Receipt.Model","Receipt.Applied","Storage.Continuation","Storage.Readiness"],"sources":["../../../src/internal/conformance/storage.ts"],"sourcesContent":["import { DateTime, Deferred, Effect, Fiber, Layer, Option } from \"effect\";\n\nimport * as Approval from \"../../Approval.ts\";\nimport * as DnsRecord from \"../../DnsRecord.ts\";\nimport * as Errors from \"../error.ts\";\nimport * as Reason from \"../../Reason.ts\";\nimport * as Plan from \"../../Plan.ts\";\nimport * as Principal from \"../../Principal.ts\";\nimport * as Receipt from \"../../Receipt.ts\";\nimport * as Storage from \"../../Storage.ts\";\n\nexport interface Case {\n readonly name: string;\n readonly run: Effect.Effect<void, unknown>;\n}\n\nexport interface Options {\n /** Register each case with a test runner, e.g. vitest's `it`. */\n readonly it?: (name: string, run: () => Promise<void>) => void;\n}\n\nconst owner = Principal.make({ ownerId: \"conformance-owner-a\", actorId: \"actor-a\" });\nconst other = Principal.make({ ownerId: \"conformance-owner-b\", actorId: \"actor-b\" });\n\nclass Failure extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"StorageConformanceFailure\";\n }\n}\n\nconst expect = (condition: boolean, message: string) =>\n condition ? Effect.void : Effect.fail(new Failure(message));\n\nconst expectReason = <A, R>(\n effect: Effect.Effect<A, unknown, R>,\n tag: Reason.Model[\"_tag\"],\n label: string,\n): Effect.Effect<void, Failure, R> =>\n effect.pipe(\n Effect.flip,\n Effect.mapError(() => new Failure(`${label}: expected failure ${tag}, effect succeeded`)),\n Effect.flatMap((cause) =>\n expect(\n Errors.isDomainKitError(cause) && cause.reason._tag === tag,\n `${label}: expected reason ${tag}, received ${Errors.isDomainKitError(cause) ? cause.reason._tag : String(cause)}`,\n ),\n ),\n );\n\nconst authorizationRow = (principal: Principal.Interface, id: string, now: DateTime.Utc) =>\n new Storage.Authorization({\n id,\n ownerId: principal.ownerId,\n provider: \"fake\",\n method: \"token\",\n capabilities: [\"dns:read\"],\n context: { account: \"acc\" },\n revocation: \"active\",\n createdBy: principal.actorId,\n createdAt: now,\n });\n\nconst credentialRow = (now: DateTime.Utc, ciphertext = \"sealed-1\") =>\n new Storage.Credential({ ciphertext, expiresAt: null, rotatedAt: now });\n\nconst connect = (principal: Principal.Interface, id: string) =>\n Effect.gen(function* () {\n const storage = yield* Storage.Service;\n const now = yield* DateTime.now;\n yield* storage.authorizations.upsert({\n authorization: authorizationRow(principal, id, now),\n credential: credentialRow(now),\n });\n const connection = yield* storage.connections.create(id);\n const attachment = yield* storage.attachments.create({\n connectionId: connection.id,\n domain: `app.${id}.example.com`,\n zone: `${id}.example.com`,\n target: { zoneId: `zone-${id}` },\n });\n return { storage, connection, attachment };\n }).pipe(Effect.provideService(Principal.Service, principal));\n\nconst planRow = (attachmentId: string, now: DateTime.Utc, suffix: string) =>\n new Plan.Model({\n id: Plan.PlanId.make(`plan-${suffix}`),\n version: \"domainkit.plan.v2\",\n kind: \"provisioning\",\n digest: Plan.Digest.make(`digest-${suffix}`),\n domain: \"app.example.com\",\n zone: \"example.com\",\n provider: \"fake\",\n attachmentId,\n operations: [\n new Plan.Create({\n id: Plan.OperationId.make(`op-${suffix}`),\n record: DnsRecord.txt({ name: \"app.example.com\", value: suffix }),\n }),\n ],\n createdAt: now,\n expiresAt: DateTime.add(now, { hours: 1 }),\n });\n\nconst attemptRow = (principal: Principal.Interface, plan: Plan.Model) =>\n new Storage.Attempt({\n id: plan.id,\n ownerId: principal.ownerId,\n attachmentId: plan.attachmentId,\n kind: plan.kind,\n status: \"planned\",\n plan,\n approval: null,\n receipt: null,\n rejection: null,\n sourceReceiptId: null,\n leaseExpiresAt: null,\n failure: null,\n updatedAt: plan.createdAt,\n });\n\nconst approvalRow = (plan: Plan.Model, suffix: string) =>\n new Approval.Model({\n id: Approval.ApprovalId.make(`approval-${suffix}`),\n version: \"domainkit.approval.v2\",\n kind: plan.kind,\n planId: plan.id,\n digest: plan.digest,\n operationIds: plan.operations.map(({ id }) => id),\n approvedBy: \"actor\",\n approvedAt: plan.createdAt,\n expiresAt: plan.expiresAt,\n });\n\nconst receiptRow = (plan: Plan.Model, approval: Approval.Model, suffix: string) =>\n new Receipt.Model({\n id: Receipt.ReceiptId.make(`receipt-${suffix}`),\n version: \"domainkit.receipt.v2\",\n kind: plan.kind,\n planId: plan.id,\n approvalId: approval.id,\n digest: plan.digest,\n provider: plan.provider,\n zone: plan.zone,\n status: \"complete\",\n outcomes: plan.operations.map(\n (operation) => new Receipt.Applied({ operationId: operation.id, providerRecordId: \"r1\" }),\n ),\n appliedAt: plan.createdAt,\n });\n\n/** Every invariant a `Storage` implementation must hold. Each case runs against a fresh layer. */\nexport const cases = (layer: Layer.Layer<Storage.Service, unknown>): ReadonlyArray<Case> => {\n const run = <E>(effect: Effect.Effect<void, E, Storage.Service>): Effect.Effect<void, unknown> =>\n effect.pipe(Effect.provide(layer));\n return [\n {\n name: \"scopes every row by the principal's owner\",\n run: run(\n Effect.gen(function* () {\n const { storage, connection, attachment } = yield* connect(owner, \"auth-a\");\n const asOther = <A, E>(effect: Effect.Effect<A, E, Principal.Service>) =>\n effect.pipe(Effect.provideService(Principal.Service, other));\n yield* expectReason(\n asOther(storage.authorizations.get(\"auth-a\")),\n \"NotFound\",\n \"authorizations.get\",\n );\n yield* expectReason(\n asOther(storage.authorizations.credential(\"auth-a\")),\n \"NotFound\",\n \"authorizations.credential\",\n );\n yield* expectReason(\n asOther(storage.connections.get(connection.id)),\n \"NotFound\",\n \"connections.get\",\n );\n yield* expectReason(\n asOther(storage.attachments.get(attachment.id)),\n \"NotFound\",\n \"attachments.get\",\n );\n yield* expectReason(\n asOther(storage.attachments.list(connection.id)),\n \"NotFound\",\n \"attachments.list\",\n );\n const connections = yield* asOther(storage.connections.list());\n yield* expect(connections.length === 0, \"connections.list leaked across owners\");\n const byDomain = yield* asOther(storage.attachments.byDomain(attachment.domain));\n yield* expect(Option.isNone(byDomain), \"attachments.byDomain leaked across owners\");\n const now = yield* DateTime.now;\n yield* expectReason(\n asOther(\n storage.authorizations.upsert({\n authorization: authorizationRow(owner, \"auth-b\", now),\n credential: credentialRow(now),\n }),\n ),\n \"InvalidInput\",\n \"authorizations.upsert with a foreign ownerId\",\n );\n }),\n ),\n },\n {\n name: \"stores, rotates, and promotes credentials without exposing plaintext\",\n run: run(\n Effect.gen(function* () {\n const { storage } = yield* connect(owner, \"auth-cred\");\n const first = yield* storage.authorizations.credential(\"auth-cred\");\n yield* expect(first.ciphertext === \"sealed-1\", \"credential ciphertext was not stored\");\n const now = yield* DateTime.now;\n yield* storage.authorizations.rotate(\"auth-cred\", credentialRow(now, \"sealed-2\"));\n const rotated = yield* storage.authorizations.credential(\"auth-cred\");\n yield* expect(rotated.ciphertext === \"sealed-2\", \"rotate did not replace the credential\");\n yield* storage.authorizations.promoteCapabilities(\"auth-cred\", [\"dns:write\", \"dns:read\"]);\n const promoted = yield* storage.authorizations.get(\"auth-cred\");\n yield* expect(\n [...promoted.capabilities].sort().join(\",\") === \"dns:read,dns:write\",\n \"promoteCapabilities did not merge capabilities\",\n );\n }).pipe(Effect.provideService(Principal.Service, owner)),\n ),\n },\n {\n name: \"replaces an authorization only through the expected id\",\n run: run(\n Effect.gen(function* () {\n const { storage } = yield* connect(owner, \"auth-cas\");\n const now = yield* DateTime.now;\n const replaced = yield* storage.authorizations.upsert({\n authorization: new Storage.Authorization({\n ...authorizationRow(owner, \"auth-cas\", now),\n method: \"oauth\",\n }),\n credential: credentialRow(now, \"sealed-oauth\"),\n expectedId: \"auth-cas\",\n });\n yield* expect(\n replaced.method === \"oauth\",\n \"upsert with expectedId did not replace the row\",\n );\n const credential = yield* storage.authorizations.credential(\"auth-cas\");\n yield* expect(\n credential.ciphertext === \"sealed-oauth\",\n \"upsert with expectedId did not replace the credential\",\n );\n yield* expectReason(\n storage.authorizations.upsert({\n authorization: authorizationRow(owner, \"auth-missing\", now),\n credential: credentialRow(now),\n expectedId: \"auth-missing\",\n }),\n \"NotFound\",\n \"upsert with an unknown expectedId\",\n );\n yield* expectReason(\n storage.authorizations.upsert({\n authorization: authorizationRow(owner, \"auth-cas\", now),\n credential: credentialRow(now),\n }),\n \"InvalidInput\",\n \"insert of an existing id\",\n );\n }).pipe(Effect.provideService(Principal.Service, owner)),\n ),\n },\n {\n name: \"consumes continuations exactly once and rejects expired ones\",\n run: run(\n Effect.gen(function* () {\n const storage = yield* Storage.Service;\n const now = yield* DateTime.now;\n const continuation = new Storage.Continuation({\n id: \"cont-1\",\n ownerId: owner.ownerId,\n actorId: owner.actorId,\n provider: \"fake\",\n payload: { codeVerifier: \"v\" },\n returnTo: null,\n expiresAt: DateTime.add(now, { minutes: 15 }),\n });\n yield* storage.continuations.put(continuation);\n yield* expectReason(\n storage.continuations\n .consume(\"cont-1\")\n .pipe(Effect.provideService(Principal.Service, other)),\n \"NotFound\",\n \"consume by another owner\",\n );\n const peeked = yield* storage.continuations.get(\"cont-1\");\n yield* expect(peeked.id === \"cont-1\", \"get did not return the continuation\");\n const consumed = yield* storage.continuations.consume(\"cont-1\");\n yield* expect(consumed.id === \"cont-1\", \"consume did not return the continuation\");\n yield* expectReason(storage.continuations.get(\"cont-1\"), \"NotFound\", \"get after consume\");\n yield* expectReason(\n storage.continuations.consume(\"cont-1\"),\n \"NotFound\",\n \"second consume\",\n );\n yield* storage.continuations.put(\n new Storage.Continuation({\n ...continuation,\n id: \"cont-2\",\n expiresAt: DateTime.subtract(now, { minutes: 1 }),\n }),\n );\n yield* expectReason(storage.continuations.get(\"cont-2\"), \"Expired\", \"expired get\");\n yield* expectReason(\n storage.continuations.consume(\"cont-2\"),\n \"Expired\",\n \"expired consume\",\n );\n yield* expectReason(\n storage.continuations.consume(\"cont-2\"),\n \"NotFound\",\n \"expired consume is also spent\",\n );\n }).pipe(Effect.provideService(Principal.Service, owner)),\n ),\n },\n {\n name: \"moves attempts through planned, approved, applying, and complete with leases\",\n run: run(\n Effect.gen(function* () {\n const { storage, attachment } = yield* connect(owner, \"auth-attempt\");\n const now = yield* DateTime.now;\n const plan = planRow(attachment.id, now, \"1\");\n yield* storage.attempts.create(attemptRow(owner, plan));\n yield* expectReason(\n storage.attempts.create(attemptRow(owner, plan)),\n \"InvalidInput\",\n \"duplicate attempt\",\n );\n yield* expectReason(\n storage.attempts.claim(plan.id, DateTime.add(now, { minutes: 2 })),\n \"Stale\",\n \"claim before approval\",\n );\n const approval = approvalRow(plan, \"1\");\n const approved = yield* storage.attempts.approve(plan.id, approval);\n yield* expect(approved.status === \"approved\", \"approve did not move the status\");\n const again = yield* storage.attempts.approve(plan.id, approval);\n yield* expect(\n again.approval?.id === approval.id,\n \"re-approving with the same approval must be idempotent\",\n );\n yield* expectReason(\n storage.attempts.approve(plan.id, approvalRow(plan, \"other\")),\n \"Stale\",\n \"second approval\",\n );\n const byApproval = yield* storage.attempts.byApproval(approval.id);\n yield* expect(byApproval.id === plan.id, \"byApproval did not find the attempt\");\n const claimed = yield* storage.attempts.claim(plan.id, DateTime.add(now, { minutes: 2 }));\n yield* expect(\n claimed.status === \"applying\" && claimed.leaseExpiresAt !== null,\n \"claim did not lease\",\n );\n yield* expectReason(\n storage.attempts.claim(plan.id, DateTime.add(now, { minutes: 2 })),\n \"Busy\",\n \"claim while leased\",\n );\n yield* storage.attempts.fail(plan.id, \"provider down\");\n const failed = yield* storage.attempts.get(plan.id);\n yield* expect(\n failed.status === \"failed\" && failed.failure === \"provider down\",\n \"fail did not record the message\",\n );\n const reclaimed = yield* storage.attempts.claim(\n plan.id,\n DateTime.subtract(now, { minutes: 1 }),\n );\n yield* expect(reclaimed.failure === null, \"claim did not clear the failure\");\n const expiredLease = yield* storage.attempts.claim(\n plan.id,\n DateTime.add(now, { minutes: 2 }),\n );\n yield* expect(expiredLease.status === \"applying\", \"an expired lease must be reclaimable\");\n const receipt = receiptRow(plan, approval, \"1\");\n const completed = yield* storage.attempts.complete(plan.id, receipt);\n yield* expect(\n completed.status === \"complete\" && completed.leaseExpiresAt === null,\n \"complete did not clear the lease\",\n );\n yield* expectReason(\n storage.attempts.claim(plan.id, DateTime.add(now, { minutes: 2 })),\n \"Stale\",\n \"claim after completion\",\n );\n const byReceipt = yield* storage.attempts.byReceipt(receipt.id);\n yield* expect(byReceipt.receipt?.id === receipt.id, \"byReceipt did not find the attempt\");\n const later = planRow(attachment.id, DateTime.add(now, { seconds: 1 }), \"2\");\n yield* storage.attempts.create(attemptRow(owner, later));\n const latest = yield* storage.attempts.latest(attachment.id, \"provisioning\");\n yield* expect(\n Option.isSome(latest) && latest.value.id === later.id,\n \"latest did not return the newest attempt\",\n );\n const cleanup = yield* storage.attempts.latest(attachment.id, \"cleanup\");\n yield* expect(Option.isNone(cleanup), \"latest must filter by kind\");\n yield* expectReason(\n storage.attempts.get(plan.id).pipe(Effect.provideService(Principal.Service, other)),\n \"NotFound\",\n \"attempts.get across owners\",\n );\n }).pipe(Effect.provideService(Principal.Service, owner)),\n ),\n },\n {\n name: \"rejects a planned attempt once and terminally\",\n run: run(\n Effect.gen(function* () {\n const { storage, attachment } = yield* connect(owner, \"auth-reject\");\n const now = yield* DateTime.now;\n const plan = planRow(attachment.id, now, \"r1\");\n yield* storage.attempts.create(attemptRow(owner, plan));\n yield* expectReason(\n storage.attempts.reject(plan.id, {\n digest: Plan.Digest.make(\"other\"),\n actorId: \"a\",\n reason: null,\n }),\n \"Stale\",\n \"reject with a digest mismatch\",\n );\n yield* expectReason(\n storage.attempts\n .reject(plan.id, { digest: plan.digest, actorId: other.actorId, reason: null })\n .pipe(Effect.provideService(Principal.Service, other)),\n \"NotFound\",\n \"reject by another owner\",\n );\n const rejected = yield* storage.attempts.reject(plan.id, {\n digest: plan.digest,\n actorId: owner.actorId,\n reason: \"wrong zone\",\n });\n yield* expect(\n rejected.status === \"rejected\" &&\n rejected.rejection?.actorId === owner.actorId &&\n rejected.rejection.reason === \"wrong zone\" &&\n DateTime.toEpochMillis(rejected.rejection.at) >= DateTime.toEpochMillis(now),\n \"reject did not record the actor, reason, and time\",\n );\n const again = yield* storage.attempts.reject(plan.id, {\n digest: plan.digest,\n actorId: \"someone-else\",\n reason: \"later\",\n });\n yield* expect(\n again.rejection?.reason === \"wrong zone\",\n \"rejecting a rejected attempt must return it unchanged\",\n );\n yield* expectReason(\n storage.attempts.approve(plan.id, approvalRow(plan, \"r1\")),\n \"Stale\",\n \"approve after reject\",\n );\n yield* expectReason(\n storage.attempts.claim(plan.id, DateTime.add(now, { minutes: 2 })),\n \"Stale\",\n \"claim after reject\",\n );\n const approvedPlan = planRow(attachment.id, now, \"r2\");\n yield* storage.attempts.create(attemptRow(owner, approvedPlan));\n yield* storage.attempts.approve(approvedPlan.id, approvalRow(approvedPlan, \"r2\"));\n yield* expectReason(\n storage.attempts.reject(approvedPlan.id, {\n digest: approvedPlan.digest,\n actorId: \"a\",\n reason: null,\n }),\n \"Stale\",\n \"reject after approve\",\n );\n const expiredPlan = planRow(attachment.id, now, \"r3\");\n yield* storage.attempts.create(\n new Storage.Attempt({ ...attemptRow(owner, expiredPlan), status: \"expired\" }),\n );\n yield* expectReason(\n storage.attempts.reject(expiredPlan.id, {\n digest: expiredPlan.digest,\n actorId: \"a\",\n reason: null,\n }),\n \"Expired\",\n \"reject an expired plan\",\n );\n }).pipe(Effect.provideService(Principal.Service, owner)),\n ),\n },\n {\n name: \"keeps a failed revocation pending and finishes it on recovery\",\n run: run(\n Effect.gen(function* () {\n const { storage, connection, attachment } = yield* connect(owner, \"auth-revoke\");\n yield* storage.attachments.remove(attachment.id);\n yield* storage.connections.remove(connection.id);\n const revokeFailure = yield* storage.authorizations\n .revoke(\"auth-revoke\", Effect.fail(new Failure(\"provider unavailable\")))\n .pipe(Effect.flip);\n yield* expect(\n revokeFailure instanceof Failure,\n \"revoke must surface the provider failure\",\n );\n const pending = yield* storage.authorizations.get(\"auth-revoke\");\n yield* expect(\n pending.revocation === \"pending\",\n \"a failed revoke must leave the row pending\",\n );\n const now = yield* DateTime.now;\n yield* expectReason(\n storage.authorizations.upsert({\n authorization: authorizationRow(owner, \"auth-revoke\", now),\n credential: credentialRow(now),\n expectedId: \"auth-revoke\",\n }),\n \"Busy\",\n \"reconnect while revocation is pending\",\n );\n const recoveredByOther = yield* storage.authorizations\n .recoverRevocations(() => Effect.void)\n .pipe(Effect.provideService(Principal.Service, other));\n yield* expect(recoveredByOther === 0, \"recovery must not cross owners\");\n let calls = 0;\n const recovered = yield* storage.authorizations.recoverRevocations(() =>\n Effect.sync(() => void (calls += 1)),\n );\n yield* expect(\n recovered === 1 && calls === 1,\n \"recovery must revoke exactly the pending authorization\",\n );\n yield* expectReason(\n storage.authorizations.get(\"auth-revoke\"),\n \"NotFound\",\n \"authorization after recovery\",\n );\n const again = yield* storage.authorizations.recoverRevocations(() => Effect.void);\n yield* expect(again === 0, \"recovery must be idempotent\");\n }).pipe(Effect.provideService(Principal.Service, owner)),\n ),\n },\n {\n name: \"blocks connection removal while attachments exist\",\n run: run(\n Effect.gen(function* () {\n const { storage, connection, attachment } = yield* connect(owner, \"auth-remove\");\n yield* expectReason(\n storage.connections.remove(connection.id),\n \"InvalidInput\",\n \"remove with attachments\",\n );\n yield* expectReason(\n storage.attachments.create({\n connectionId: connection.id,\n domain: attachment.domain,\n zone: attachment.zone,\n target: {},\n }),\n \"InvalidInput\",\n \"duplicate domain attachment\",\n );\n yield* storage.attachments.remove(attachment.id);\n yield* storage.connections.remove(connection.id);\n yield* expectReason(\n storage.connections.get(connection.id),\n \"NotFound\",\n \"connection after remove\",\n );\n }).pipe(Effect.provideService(Principal.Service, owner)),\n ),\n },\n {\n name: \"fails Busy while a lock is held and releases it afterwards\",\n run: run(\n Effect.gen(function* () {\n const storage = yield* Storage.Service;\n const gate = yield* Deferred.make<void>();\n const holder = yield* Effect.forkChild(\n storage.withLock(\"refresh:auth-1\", Deferred.await(gate)),\n );\n yield* Effect.yieldNow;\n yield* expectReason(\n storage.withLock(\"refresh:auth-1\", Effect.void),\n \"Busy\",\n \"second holder\",\n );\n const otherOwner = yield* storage\n .withLock(\"refresh:auth-1\", Effect.succeed(\"ok\"))\n .pipe(Effect.provideService(Principal.Service, other));\n yield* expect(otherOwner === \"ok\", \"locks must be scoped by owner\");\n yield* Deferred.succeed(gate, undefined);\n yield* Fiber.join(holder);\n const after = yield* storage.withLock(\"refresh:auth-1\", Effect.succeed(\"free\"));\n yield* expect(after === \"free\", \"lock was not released\");\n yield* storage\n .withLock(\"refresh:auth-1\", Effect.fail(new Failure(\"inside\")))\n .pipe(Effect.ignore);\n const afterFailure = yield* storage.withLock(\"refresh:auth-1\", Effect.succeed(\"free\"));\n yield* expect(afterFailure === \"free\", \"lock was not released after a failure\");\n }).pipe(Effect.provideService(Principal.Service, owner)),\n ),\n },\n {\n name: \"stores readiness per domain, with or without an attachment\",\n run: run(\n Effect.gen(function* () {\n const { storage, attachment } = yield* connect(owner, \"auth-ready\");\n const now = yield* DateTime.now;\n const readiness = new Storage.Readiness({\n domain: attachment.domain,\n attachmentId: attachment.id,\n ownerId: owner.ownerId,\n overall: \"pending\",\n requirements: [\n {\n operationId: null,\n record: DnsRecord.txt({ name: \"app.example.com\", value: \"v\" }),\n status: \"missing\",\n evidence: [],\n },\n ],\n host: [],\n pendingSince: now,\n checkedAt: now,\n nextCheckAt: DateTime.add(now, { seconds: 15 }),\n });\n yield* storage.readiness.put(readiness);\n const stored = yield* storage.readiness.get(attachment.domain);\n yield* expect(\n Option.isSome(stored) && stored.value.overall === \"pending\",\n \"readiness was not stored\",\n );\n const foreign = yield* storage.readiness\n .get(attachment.domain)\n .pipe(Effect.provideService(Principal.Service, other));\n yield* expect(Option.isNone(foreign), \"readiness leaked across owners\");\n yield* storage.readiness.put(\n new Storage.Readiness({\n ...readiness,\n domain: \"observe-only.example.com\",\n attachmentId: null,\n }),\n );\n const observeOnly = yield* storage.readiness.get(\"observe-only.example.com\");\n yield* expect(\n Option.isSome(observeOnly) && observeOnly.value.attachmentId === null,\n \"readiness without an attachment was not stored\",\n );\n yield* expectReason(\n storage.readiness.put(\n new Storage.Readiness({ ...readiness, attachmentId: \"att-missing\" }),\n ),\n \"NotFound\",\n \"readiness with an unknown attachment\",\n );\n }).pipe(Effect.provideService(Principal.Service, owner)),\n ),\n },\n ];\n};\n\n/** Registers every case with `options.it` when given; always returns the cases. */\nexport const storage = (\n layer: Layer.Layer<Storage.Service, unknown>,\n options: Options = {},\n): ReadonlyArray<Case> => {\n const all = cases(layer);\n if (options.it !== undefined) {\n for (const item of all) options.it(item.name, () => Effect.runPromise(item.run));\n }\n return all;\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"storage.mjs","names":["Principal.make","Errors.isDomainKitError","Storage.Authorization","Storage.Credential","Storage.Service","Principal.Service","Plan.Model","Plan.Create","DnsRecord.txt","Storage.Attempt","Approval.Model","Receipt.Model","Receipt.Applied","Storage.Continuation","Storage.Readiness"],"sources":["../../../src/internal/conformance/storage.ts"],"sourcesContent":["import { DateTime, Deferred, Effect, Fiber, Layer, Option } from \"effect\";\n\nimport * as Approval from \"../../Approval.ts\";\nimport * as DnsRecord from \"../../DnsRecord.ts\";\nimport * as Errors from \"../error.ts\";\nimport * as Reason from \"../../Reason.ts\";\nimport * as Plan from \"../../Plan.ts\";\nimport * as Principal from \"../../Principal.ts\";\nimport * as Receipt from \"../../Receipt.ts\";\nimport * as Storage from \"../../Storage.ts\";\n\nexport interface Case {\n readonly name: string;\n readonly run: Effect.Effect<void, unknown>;\n}\n\nexport interface Options {\n /** Register each case with a test runner, e.g. vitest's `it`. */\n readonly it?: (name: string, run: () => Promise<void>) => void;\n}\n\nconst owner = Principal.make({ ownerId: \"conformance-owner-a\", actorId: \"actor-a\" });\nconst other = Principal.make({ ownerId: \"conformance-owner-b\", actorId: \"actor-b\" });\n\nclass Failure extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"StorageConformanceFailure\";\n }\n}\n\nconst expect = (condition: boolean, message: string) =>\n condition ? Effect.void : Effect.fail(new Failure(message));\n\nconst expectReason = <A, R>(\n effect: Effect.Effect<A, unknown, R>,\n tag: Reason.Model[\"_tag\"],\n label: string,\n): Effect.Effect<void, Failure, R> =>\n effect.pipe(\n Effect.flip,\n Effect.mapError(() => new Failure(`${label}: expected failure ${tag}, effect succeeded`)),\n Effect.flatMap((cause) =>\n expect(\n Errors.isDomainKitError(cause) && cause.reason._tag === tag,\n `${label}: expected reason ${tag}, received ${Errors.isDomainKitError(cause) ? cause.reason._tag : String(cause)}`,\n ),\n ),\n );\n\nconst authorizationRow = (principal: Principal.Interface, id: string, now: DateTime.Utc) =>\n new Storage.Authorization({\n id,\n ownerId: principal.ownerId,\n provider: \"fake\",\n method: \"token\",\n capabilities: [\"dns:read\"],\n context: { account: \"acc\" },\n revocation: \"active\",\n createdBy: principal.actorId,\n createdAt: now,\n });\n\nconst credentialRow = (now: DateTime.Utc, ciphertext = \"sealed-1\") =>\n new Storage.Credential({ ciphertext, expiresAt: null, rotatedAt: now });\n\nconst connect = (principal: Principal.Interface, id: string) =>\n Effect.gen(function* () {\n const storage = yield* Storage.Service;\n const now = yield* DateTime.now;\n yield* storage.authorizations.upsert({\n authorization: authorizationRow(principal, id, now),\n credential: credentialRow(now),\n });\n const connection = yield* storage.connections.create(id);\n const attachment = yield* storage.attachments.create({\n connectionId: connection.id,\n domain: `app.${id}.example.com`,\n zone: `${id}.example.com`,\n label: `${id}.example.com (${id})`,\n target: { zoneId: `zone-${id}` },\n });\n return { storage, connection, attachment };\n }).pipe(Effect.provideService(Principal.Service, principal));\n\nconst planRow = (attachmentId: string, now: DateTime.Utc, suffix: string) =>\n new Plan.Model({\n id: Plan.PlanId.make(`plan-${suffix}`),\n version: \"domainkit.plan.v2\",\n kind: \"provisioning\",\n digest: Plan.Digest.make(`digest-${suffix}`),\n domain: \"app.example.com\",\n zone: \"example.com\",\n provider: \"fake\",\n attachmentId,\n operations: [\n new Plan.Create({\n id: Plan.OperationId.make(`op-${suffix}`),\n record: DnsRecord.txt({ name: \"app.example.com\", value: suffix }),\n }),\n ],\n createdAt: now,\n expiresAt: DateTime.add(now, { hours: 1 }),\n });\n\nconst attemptRow = (principal: Principal.Interface, plan: Plan.Model) =>\n new Storage.Attempt({\n id: plan.id,\n ownerId: principal.ownerId,\n attachmentId: plan.attachmentId,\n kind: plan.kind,\n status: \"planned\",\n plan,\n approval: null,\n receipt: null,\n rejection: null,\n sourceReceiptId: null,\n leaseExpiresAt: null,\n failure: null,\n updatedAt: plan.createdAt,\n });\n\nconst approvalRow = (plan: Plan.Model, suffix: string) =>\n new Approval.Model({\n id: Approval.ApprovalId.make(`approval-${suffix}`),\n version: \"domainkit.approval.v2\",\n kind: plan.kind,\n planId: plan.id,\n digest: plan.digest,\n operationIds: plan.operations.map(({ id }) => id),\n approvedBy: \"actor\",\n approvedAt: plan.createdAt,\n expiresAt: plan.expiresAt,\n });\n\nconst receiptRow = (plan: Plan.Model, approval: Approval.Model, suffix: string) =>\n new Receipt.Model({\n id: Receipt.ReceiptId.make(`receipt-${suffix}`),\n version: \"domainkit.receipt.v2\",\n kind: plan.kind,\n planId: plan.id,\n approvalId: approval.id,\n digest: plan.digest,\n provider: plan.provider,\n zone: plan.zone,\n status: \"complete\",\n outcomes: plan.operations.map(\n (operation) => new Receipt.Applied({ operationId: operation.id, providerRecordId: \"r1\" }),\n ),\n appliedAt: plan.createdAt,\n });\n\n/** Every invariant a `Storage` implementation must hold. Each case runs against a fresh layer. */\nexport const cases = (layer: Layer.Layer<Storage.Service, unknown>): ReadonlyArray<Case> => {\n const run = <E>(effect: Effect.Effect<void, E, Storage.Service>): Effect.Effect<void, unknown> =>\n effect.pipe(Effect.provide(layer));\n return [\n {\n name: \"scopes every row by the principal's owner\",\n run: run(\n Effect.gen(function* () {\n const { storage, connection, attachment } = yield* connect(owner, \"auth-a\");\n const asOther = <A, E>(effect: Effect.Effect<A, E, Principal.Service>) =>\n effect.pipe(Effect.provideService(Principal.Service, other));\n yield* expectReason(\n asOther(storage.authorizations.get(\"auth-a\")),\n \"NotFound\",\n \"authorizations.get\",\n );\n yield* expectReason(\n asOther(storage.authorizations.credential(\"auth-a\")),\n \"NotFound\",\n \"authorizations.credential\",\n );\n yield* expectReason(\n asOther(storage.connections.get(connection.id)),\n \"NotFound\",\n \"connections.get\",\n );\n yield* expectReason(\n asOther(storage.attachments.get(attachment.id)),\n \"NotFound\",\n \"attachments.get\",\n );\n yield* expectReason(\n asOther(storage.attachments.list(connection.id)),\n \"NotFound\",\n \"attachments.list\",\n );\n const connections = yield* asOther(storage.connections.list());\n yield* expect(connections.length === 0, \"connections.list leaked across owners\");\n const byDomain = yield* asOther(storage.attachments.byDomain(attachment.domain));\n yield* expect(Option.isNone(byDomain), \"attachments.byDomain leaked across owners\");\n const now = yield* DateTime.now;\n yield* expectReason(\n asOther(\n storage.authorizations.upsert({\n authorization: authorizationRow(owner, \"auth-b\", now),\n credential: credentialRow(now),\n }),\n ),\n \"InvalidInput\",\n \"authorizations.upsert with a foreign ownerId\",\n );\n }),\n ),\n },\n {\n name: \"stores, rotates, and promotes credentials without exposing plaintext\",\n run: run(\n Effect.gen(function* () {\n const { storage } = yield* connect(owner, \"auth-cred\");\n const first = yield* storage.authorizations.credential(\"auth-cred\");\n yield* expect(first.ciphertext === \"sealed-1\", \"credential ciphertext was not stored\");\n const now = yield* DateTime.now;\n yield* storage.authorizations.rotate(\"auth-cred\", credentialRow(now, \"sealed-2\"));\n const rotated = yield* storage.authorizations.credential(\"auth-cred\");\n yield* expect(rotated.ciphertext === \"sealed-2\", \"rotate did not replace the credential\");\n yield* storage.authorizations.promoteCapabilities(\"auth-cred\", [\"dns:write\", \"dns:read\"]);\n const promoted = yield* storage.authorizations.get(\"auth-cred\");\n yield* expect(\n [...promoted.capabilities].sort().join(\",\") === \"dns:read,dns:write\",\n \"promoteCapabilities did not merge capabilities\",\n );\n }).pipe(Effect.provideService(Principal.Service, owner)),\n ),\n },\n {\n name: \"replaces an authorization only through the expected id\",\n run: run(\n Effect.gen(function* () {\n const { storage } = yield* connect(owner, \"auth-cas\");\n const now = yield* DateTime.now;\n const replaced = yield* storage.authorizations.upsert({\n authorization: new Storage.Authorization({\n ...authorizationRow(owner, \"auth-cas\", now),\n method: \"oauth\",\n }),\n credential: credentialRow(now, \"sealed-oauth\"),\n expectedId: \"auth-cas\",\n });\n yield* expect(\n replaced.method === \"oauth\",\n \"upsert with expectedId did not replace the row\",\n );\n const credential = yield* storage.authorizations.credential(\"auth-cas\");\n yield* expect(\n credential.ciphertext === \"sealed-oauth\",\n \"upsert with expectedId did not replace the credential\",\n );\n yield* expectReason(\n storage.authorizations.upsert({\n authorization: authorizationRow(owner, \"auth-missing\", now),\n credential: credentialRow(now),\n expectedId: \"auth-missing\",\n }),\n \"NotFound\",\n \"upsert with an unknown expectedId\",\n );\n yield* expectReason(\n storage.authorizations.upsert({\n authorization: authorizationRow(owner, \"auth-cas\", now),\n credential: credentialRow(now),\n }),\n \"InvalidInput\",\n \"insert of an existing id\",\n );\n }).pipe(Effect.provideService(Principal.Service, owner)),\n ),\n },\n {\n name: \"consumes continuations exactly once and rejects expired ones\",\n run: run(\n Effect.gen(function* () {\n const storage = yield* Storage.Service;\n const now = yield* DateTime.now;\n const continuation = new Storage.Continuation({\n id: \"cont-1\",\n ownerId: owner.ownerId,\n actorId: owner.actorId,\n provider: \"fake\",\n payload: { codeVerifier: \"v\" },\n returnTo: null,\n expiresAt: DateTime.add(now, { minutes: 15 }),\n });\n yield* storage.continuations.put(continuation);\n yield* expectReason(\n storage.continuations\n .consume(\"cont-1\")\n .pipe(Effect.provideService(Principal.Service, other)),\n \"NotFound\",\n \"consume by another owner\",\n );\n const peeked = yield* storage.continuations.get(\"cont-1\");\n yield* expect(peeked.id === \"cont-1\", \"get did not return the continuation\");\n const consumed = yield* storage.continuations.consume(\"cont-1\");\n yield* expect(consumed.id === \"cont-1\", \"consume did not return the continuation\");\n yield* expectReason(storage.continuations.get(\"cont-1\"), \"NotFound\", \"get after consume\");\n yield* expectReason(\n storage.continuations.consume(\"cont-1\"),\n \"NotFound\",\n \"second consume\",\n );\n yield* storage.continuations.put(\n new Storage.Continuation({\n ...continuation,\n id: \"cont-2\",\n expiresAt: DateTime.subtract(now, { minutes: 1 }),\n }),\n );\n yield* expectReason(storage.continuations.get(\"cont-2\"), \"Expired\", \"expired get\");\n yield* expectReason(\n storage.continuations.consume(\"cont-2\"),\n \"Expired\",\n \"expired consume\",\n );\n yield* expectReason(\n storage.continuations.consume(\"cont-2\"),\n \"NotFound\",\n \"expired consume is also spent\",\n );\n }).pipe(Effect.provideService(Principal.Service, owner)),\n ),\n },\n {\n name: \"moves attempts through planned, approved, applying, and complete with leases\",\n run: run(\n Effect.gen(function* () {\n const { storage, attachment } = yield* connect(owner, \"auth-attempt\");\n const now = yield* DateTime.now;\n const plan = planRow(attachment.id, now, \"1\");\n yield* storage.attempts.create(attemptRow(owner, plan));\n yield* expectReason(\n storage.attempts.create(attemptRow(owner, plan)),\n \"InvalidInput\",\n \"duplicate attempt\",\n );\n yield* expectReason(\n storage.attempts.claim(plan.id, DateTime.add(now, { minutes: 2 })),\n \"Stale\",\n \"claim before approval\",\n );\n const approval = approvalRow(plan, \"1\");\n const approved = yield* storage.attempts.approve(plan.id, approval);\n yield* expect(approved.status === \"approved\", \"approve did not move the status\");\n const again = yield* storage.attempts.approve(plan.id, approval);\n yield* expect(\n again.approval?.id === approval.id,\n \"re-approving with the same approval must be idempotent\",\n );\n yield* expectReason(\n storage.attempts.approve(plan.id, approvalRow(plan, \"other\")),\n \"Stale\",\n \"second approval\",\n );\n const byApproval = yield* storage.attempts.byApproval(approval.id);\n yield* expect(byApproval.id === plan.id, \"byApproval did not find the attempt\");\n const claimed = yield* storage.attempts.claim(plan.id, DateTime.add(now, { minutes: 2 }));\n yield* expect(\n claimed.status === \"applying\" && claimed.leaseExpiresAt !== null,\n \"claim did not lease\",\n );\n yield* expectReason(\n storage.attempts.claim(plan.id, DateTime.add(now, { minutes: 2 })),\n \"Busy\",\n \"claim while leased\",\n );\n yield* storage.attempts.fail(plan.id, \"provider down\");\n const failed = yield* storage.attempts.get(plan.id);\n yield* expect(\n failed.status === \"failed\" && failed.failure === \"provider down\",\n \"fail did not record the message\",\n );\n const reclaimed = yield* storage.attempts.claim(\n plan.id,\n DateTime.subtract(now, { minutes: 1 }),\n );\n yield* expect(reclaimed.failure === null, \"claim did not clear the failure\");\n const expiredLease = yield* storage.attempts.claim(\n plan.id,\n DateTime.add(now, { minutes: 2 }),\n );\n yield* expect(expiredLease.status === \"applying\", \"an expired lease must be reclaimable\");\n const receipt = receiptRow(plan, approval, \"1\");\n const completed = yield* storage.attempts.complete(plan.id, receipt);\n yield* expect(\n completed.status === \"complete\" && completed.leaseExpiresAt === null,\n \"complete did not clear the lease\",\n );\n yield* expectReason(\n storage.attempts.claim(plan.id, DateTime.add(now, { minutes: 2 })),\n \"Stale\",\n \"claim after completion\",\n );\n const byReceipt = yield* storage.attempts.byReceipt(receipt.id);\n yield* expect(byReceipt.receipt?.id === receipt.id, \"byReceipt did not find the attempt\");\n const later = planRow(attachment.id, DateTime.add(now, { seconds: 1 }), \"2\");\n yield* storage.attempts.create(attemptRow(owner, later));\n const latest = yield* storage.attempts.latest(attachment.id, \"provisioning\");\n yield* expect(\n Option.isSome(latest) && latest.value.id === later.id,\n \"latest did not return the newest attempt\",\n );\n const cleanup = yield* storage.attempts.latest(attachment.id, \"cleanup\");\n yield* expect(Option.isNone(cleanup), \"latest must filter by kind\");\n yield* expectReason(\n storage.attempts.get(plan.id).pipe(Effect.provideService(Principal.Service, other)),\n \"NotFound\",\n \"attempts.get across owners\",\n );\n }).pipe(Effect.provideService(Principal.Service, owner)),\n ),\n },\n {\n name: \"rejects a planned attempt once and terminally\",\n run: run(\n Effect.gen(function* () {\n const { storage, attachment } = yield* connect(owner, \"auth-reject\");\n const now = yield* DateTime.now;\n const plan = planRow(attachment.id, now, \"r1\");\n yield* storage.attempts.create(attemptRow(owner, plan));\n yield* expectReason(\n storage.attempts.reject(plan.id, {\n digest: Plan.Digest.make(\"other\"),\n actorId: \"a\",\n reason: null,\n }),\n \"Stale\",\n \"reject with a digest mismatch\",\n );\n yield* expectReason(\n storage.attempts\n .reject(plan.id, { digest: plan.digest, actorId: other.actorId, reason: null })\n .pipe(Effect.provideService(Principal.Service, other)),\n \"NotFound\",\n \"reject by another owner\",\n );\n const rejected = yield* storage.attempts.reject(plan.id, {\n digest: plan.digest,\n actorId: owner.actorId,\n reason: \"wrong zone\",\n });\n yield* expect(\n rejected.status === \"rejected\" &&\n rejected.rejection?.actorId === owner.actorId &&\n rejected.rejection.reason === \"wrong zone\" &&\n DateTime.toEpochMillis(rejected.rejection.at) >= DateTime.toEpochMillis(now),\n \"reject did not record the actor, reason, and time\",\n );\n const again = yield* storage.attempts.reject(plan.id, {\n digest: plan.digest,\n actorId: \"someone-else\",\n reason: \"later\",\n });\n yield* expect(\n again.rejection?.reason === \"wrong zone\",\n \"rejecting a rejected attempt must return it unchanged\",\n );\n yield* expectReason(\n storage.attempts.approve(plan.id, approvalRow(plan, \"r1\")),\n \"Stale\",\n \"approve after reject\",\n );\n yield* expectReason(\n storage.attempts.claim(plan.id, DateTime.add(now, { minutes: 2 })),\n \"Stale\",\n \"claim after reject\",\n );\n const approvedPlan = planRow(attachment.id, now, \"r2\");\n yield* storage.attempts.create(attemptRow(owner, approvedPlan));\n yield* storage.attempts.approve(approvedPlan.id, approvalRow(approvedPlan, \"r2\"));\n yield* expectReason(\n storage.attempts.reject(approvedPlan.id, {\n digest: approvedPlan.digest,\n actorId: \"a\",\n reason: null,\n }),\n \"Stale\",\n \"reject after approve\",\n );\n const expiredPlan = planRow(attachment.id, now, \"r3\");\n yield* storage.attempts.create(\n new Storage.Attempt({ ...attemptRow(owner, expiredPlan), status: \"expired\" }),\n );\n yield* expectReason(\n storage.attempts.reject(expiredPlan.id, {\n digest: expiredPlan.digest,\n actorId: \"a\",\n reason: null,\n }),\n \"Expired\",\n \"reject an expired plan\",\n );\n }).pipe(Effect.provideService(Principal.Service, owner)),\n ),\n },\n {\n name: \"keeps a failed revocation pending and finishes it on recovery\",\n run: run(\n Effect.gen(function* () {\n const { storage, connection, attachment } = yield* connect(owner, \"auth-revoke\");\n yield* storage.attachments.remove(attachment.id);\n yield* storage.connections.remove(connection.id);\n const revokeFailure = yield* storage.authorizations\n .revoke(\"auth-revoke\", Effect.fail(new Failure(\"provider unavailable\")))\n .pipe(Effect.flip);\n yield* expect(\n revokeFailure instanceof Failure,\n \"revoke must surface the provider failure\",\n );\n const pending = yield* storage.authorizations.get(\"auth-revoke\");\n yield* expect(\n pending.revocation === \"pending\",\n \"a failed revoke must leave the row pending\",\n );\n const now = yield* DateTime.now;\n yield* expectReason(\n storage.authorizations.upsert({\n authorization: authorizationRow(owner, \"auth-revoke\", now),\n credential: credentialRow(now),\n expectedId: \"auth-revoke\",\n }),\n \"Busy\",\n \"reconnect while revocation is pending\",\n );\n const recoveredByOther = yield* storage.authorizations\n .recoverRevocations(() => Effect.void)\n .pipe(Effect.provideService(Principal.Service, other));\n yield* expect(recoveredByOther === 0, \"recovery must not cross owners\");\n let calls = 0;\n const recovered = yield* storage.authorizations.recoverRevocations(() =>\n Effect.sync(() => void (calls += 1)),\n );\n yield* expect(\n recovered === 1 && calls === 1,\n \"recovery must revoke exactly the pending authorization\",\n );\n yield* expectReason(\n storage.authorizations.get(\"auth-revoke\"),\n \"NotFound\",\n \"authorization after recovery\",\n );\n const again = yield* storage.authorizations.recoverRevocations(() => Effect.void);\n yield* expect(again === 0, \"recovery must be idempotent\");\n }).pipe(Effect.provideService(Principal.Service, owner)),\n ),\n },\n {\n name: \"returns an attachment's label from every read\",\n run: run(\n Effect.gen(function* () {\n const { storage, connection, attachment } = yield* connect(owner, \"auth-label\");\n const label = `${attachment.zone} (auth-label)`;\n yield* expect(attachment.label === label, \"create must return the label it was given\");\n const read = yield* storage.attachments.get(attachment.id);\n yield* expect(read.label === label, \"get must return the stored label\");\n const byDomain = yield* storage.attachments.byDomain(attachment.domain);\n yield* expect(\n Option.isSome(byDomain) && byDomain.value.label === label,\n \"byDomain must return the stored label\",\n );\n const listed = yield* storage.attachments.list(connection.id);\n yield* expect(\n listed.every((row) => row.label === label),\n \"list must return the stored label\",\n );\n }).pipe(Effect.provideService(Principal.Service, owner)),\n ),\n },\n {\n name: \"blocks connection removal while attachments exist\",\n run: run(\n Effect.gen(function* () {\n const { storage, connection, attachment } = yield* connect(owner, \"auth-remove\");\n yield* expectReason(\n storage.connections.remove(connection.id),\n \"InvalidInput\",\n \"remove with attachments\",\n );\n yield* expectReason(\n storage.attachments.create({\n connectionId: connection.id,\n domain: attachment.domain,\n zone: attachment.zone,\n label: attachment.label,\n target: {},\n }),\n \"InvalidInput\",\n \"duplicate domain attachment\",\n );\n yield* storage.attachments.remove(attachment.id);\n yield* storage.connections.remove(connection.id);\n yield* expectReason(\n storage.connections.get(connection.id),\n \"NotFound\",\n \"connection after remove\",\n );\n }).pipe(Effect.provideService(Principal.Service, owner)),\n ),\n },\n {\n name: \"fails Busy while a lock is held and releases it afterwards\",\n run: run(\n Effect.gen(function* () {\n const storage = yield* Storage.Service;\n const gate = yield* Deferred.make<void>();\n const holder = yield* Effect.forkChild(\n storage.withLock(\"refresh:auth-1\", Deferred.await(gate)),\n );\n yield* Effect.yieldNow;\n yield* expectReason(\n storage.withLock(\"refresh:auth-1\", Effect.void),\n \"Busy\",\n \"second holder\",\n );\n const otherOwner = yield* storage\n .withLock(\"refresh:auth-1\", Effect.succeed(\"ok\"))\n .pipe(Effect.provideService(Principal.Service, other));\n yield* expect(otherOwner === \"ok\", \"locks must be scoped by owner\");\n yield* Deferred.succeed(gate, undefined);\n yield* Fiber.join(holder);\n const after = yield* storage.withLock(\"refresh:auth-1\", Effect.succeed(\"free\"));\n yield* expect(after === \"free\", \"lock was not released\");\n yield* storage\n .withLock(\"refresh:auth-1\", Effect.fail(new Failure(\"inside\")))\n .pipe(Effect.ignore);\n const afterFailure = yield* storage.withLock(\"refresh:auth-1\", Effect.succeed(\"free\"));\n yield* expect(afterFailure === \"free\", \"lock was not released after a failure\");\n }).pipe(Effect.provideService(Principal.Service, owner)),\n ),\n },\n {\n name: \"stores readiness per domain, with or without an attachment\",\n run: run(\n Effect.gen(function* () {\n const { storage, attachment } = yield* connect(owner, \"auth-ready\");\n const now = yield* DateTime.now;\n const readiness = new Storage.Readiness({\n domain: attachment.domain,\n attachmentId: attachment.id,\n ownerId: owner.ownerId,\n overall: \"pending\",\n requirements: [\n {\n operationId: null,\n record: DnsRecord.txt({ name: \"app.example.com\", value: \"v\" }),\n status: \"missing\",\n evidence: [],\n },\n ],\n host: [],\n pendingSince: now,\n checkedAt: now,\n nextCheckAt: DateTime.add(now, { seconds: 15 }),\n });\n yield* storage.readiness.put(readiness);\n const stored = yield* storage.readiness.get(attachment.domain);\n yield* expect(\n Option.isSome(stored) && stored.value.overall === \"pending\",\n \"readiness was not stored\",\n );\n const foreign = yield* storage.readiness\n .get(attachment.domain)\n .pipe(Effect.provideService(Principal.Service, other));\n yield* expect(Option.isNone(foreign), \"readiness leaked across owners\");\n yield* storage.readiness.put(\n new Storage.Readiness({\n ...readiness,\n domain: \"observe-only.example.com\",\n attachmentId: null,\n }),\n );\n const observeOnly = yield* storage.readiness.get(\"observe-only.example.com\");\n yield* expect(\n Option.isSome(observeOnly) && observeOnly.value.attachmentId === null,\n \"readiness without an attachment was not stored\",\n );\n yield* expectReason(\n storage.readiness.put(\n new Storage.Readiness({ ...readiness, attachmentId: \"att-missing\" }),\n ),\n \"NotFound\",\n \"readiness with an unknown attachment\",\n );\n }).pipe(Effect.provideService(Principal.Service, owner)),\n ),\n },\n ];\n};\n\n/** Registers every case with `options.it` when given; always returns the cases. */\nexport const storage = (\n layer: Layer.Layer<Storage.Service, unknown>,\n options: Options = {},\n): ReadonlyArray<Case> => {\n const all = cases(layer);\n if (options.it !== undefined) {\n for (const item of all) options.it(item.name, () => Effect.runPromise(item.run));\n }\n return all;\n};\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage-memory.mjs","names":["Errors.fail","Reason.NotFound","Reason.InvalidInput","Principal.Service","Storage.Authorization","Reason.Busy","Storage.Connection","Storage.Attachment","Reason.Expired","Storage.Attempt","Reason.Stale"],"sources":["../../src/internal/storage-memory.ts"],"sourcesContent":["import { DateTime, Effect, Option, Semaphore } from \"effect\";\n\nimport type * as Approval from \"../Approval.ts\";\nimport * as Errors from \"./error.ts\";\nimport * as Reason from \"../Reason.ts\";\nimport * as Plan from \"../Plan.ts\";\nimport * as Principal from \"../Principal.ts\";\nimport type * as Receipt from \"../Receipt.ts\";\nimport * as Storage from \"../Storage.ts\";\nimport { fresh } from \"./ids.ts\";\n\ninterface State {\n readonly authorizations: Map<string, Storage.Authorization>;\n readonly credentials: Map<string, Storage.Credential>;\n readonly connections: Map<string, Storage.Connection>;\n readonly attachments: Map<string, Storage.Attachment>;\n readonly continuations: Map<string, Storage.Continuation>;\n readonly attempts: Map<string, Storage.Attempt>;\n readonly readiness: Map<string, Storage.Readiness>;\n readonly locks: Set<string>;\n}\n\nconst notFound = (entity: Reason.NotFound[\"entity\"], id: string) =>\n Errors.fail(new Reason.NotFound({ entity, id }));\nconst invalid = (message: string, field?: string) =>\n Errors.fail(new Reason.InvalidInput({ message, ...(field === undefined ? {} : { field }) }));\n\nexport function makeMemory(options: Storage.MemoryOptions = {}): Storage.Interface {\n const state: State = {\n authorizations: new Map(),\n credentials: new Map(),\n connections: new Map(),\n attachments: new Map(),\n continuations: new Map(),\n attempts: new Map(),\n readiness: new Map(),\n locks: new Set(),\n };\n const mutations = Semaphore.makeUnsafe(1);\n const commit = (operation: string) =>\n options.beforeCommit === undefined ? Effect.void : options.beforeCommit(operation);\n\n const read = <A, E, R = never>(\n run: (principal: Principal.Interface) => Effect.Effect<A, E, R>,\n ): Effect.Effect<A, E, Principal.Service | R> => Effect.flatMap(Principal.Service, run);\n const write = <A, E>(\n run: (principal: Principal.Interface) => Effect.Effect<A, E>,\n ): Effect.Effect<A, E, Principal.Service> =>\n Effect.flatMap(Principal.Service, (principal) => mutations.withPermit(run(principal)));\n\n const owned = <Row extends { readonly ownerId: string }>(\n rows: Map<string, Row>,\n principal: Principal.Interface,\n id: string,\n ): Row | undefined => {\n const row = rows.get(id);\n return row !== undefined && row.ownerId === principal.ownerId ? row : undefined;\n };\n const ownedRows = <Row extends { readonly ownerId: string }>(\n rows: Map<string, Row>,\n principal: Principal.Interface,\n ) => [...rows.values()].filter((row) => row.ownerId === principal.ownerId);\n\n const authorization = (principal: Principal.Interface, id: string) =>\n Effect.suspend(() => {\n const row = owned(state.authorizations, principal, id);\n return row === undefined ? notFound(\"authorization\", id) : Effect.succeed(row);\n });\n const connection = (principal: Principal.Interface, id: string) =>\n Effect.suspend(() => {\n const row = owned(state.connections, principal, id);\n return row === undefined ? notFound(\"connection\", id) : Effect.succeed(row);\n });\n const attachment = (principal: Principal.Interface, id: string) =>\n Effect.suspend(() => {\n const row = owned(state.attachments, principal, id);\n return row === undefined ? notFound(\"attachment\", id) : Effect.succeed(row);\n });\n const attempt = (principal: Principal.Interface, id: string) =>\n Effect.suspend(() => {\n const row = owned(state.attempts, principal, id);\n return row === undefined ? notFound(\"plan\", id) : Effect.succeed(row);\n });\n const attemptWhere = (\n principal: Principal.Interface,\n entity: Reason.NotFound[\"entity\"],\n id: string,\n predicate: (row: Storage.Attempt) => boolean,\n ) =>\n Effect.suspend(() => {\n const row = ownedRows(state.attempts, principal).find(predicate);\n return row === undefined ? notFound(entity, id) : Effect.succeed(row);\n });\n\n const finishRevocation = <E, R>(\n principal: Principal.Interface,\n row: Storage.Authorization,\n revoke: Effect.Effect<void, E, R>,\n ): Effect.Effect<void, Errors.DomainKitError | E, R> =>\n Effect.gen(function* () {\n yield* commit(\"authorizations.prepareRevocation\");\n state.authorizations.set(\n row.id,\n new Storage.Authorization({ ...row, revocation: \"pending\" }),\n );\n yield* revoke;\n yield* commit(\"authorizations.completeRevocation\");\n if (owned(state.authorizations, principal, row.id) !== undefined) {\n state.authorizations.delete(row.id);\n state.credentials.delete(row.id);\n }\n });\n\n return {\n authorizations: {\n upsert: ({ authorization: input, credential, expectedId }) =>\n write((principal) =>\n Effect.gen(function* () {\n if (input.ownerId !== principal.ownerId) {\n return yield* invalid(\"Authorization owner does not match the principal\", \"ownerId\");\n }\n if (expectedId !== undefined) {\n const current = yield* authorization(principal, expectedId);\n if (current.revocation !== \"active\") {\n return yield* Errors.fail(new Reason.Busy({ key: `authorization:${expectedId}` }));\n }\n if (input.id !== expectedId) {\n return yield* invalid(\"Authorization id must match expectedId\", \"id\");\n }\n } else if (state.authorizations.has(input.id)) {\n return yield* invalid(`Authorization ${input.id} already exists`, \"id\");\n }\n yield* commit(\"authorizations.upsert\");\n state.authorizations.set(input.id, input);\n state.credentials.set(input.id, credential);\n return input;\n }),\n ),\n get: (id) => read((principal) => authorization(principal, id)),\n credential: (id) =>\n read((principal) =>\n authorization(principal, id).pipe(\n Effect.flatMap(() => {\n const row = state.credentials.get(id);\n return row === undefined ? notFound(\"authorization\", id) : Effect.succeed(row);\n }),\n ),\n ),\n rotate: (id, credential) =>\n write((principal) =>\n Effect.gen(function* () {\n yield* authorization(principal, id);\n yield* commit(\"authorizations.rotate\");\n state.credentials.set(id, credential);\n }),\n ),\n promoteCapabilities: (id, capabilities) =>\n write((principal) =>\n Effect.gen(function* () {\n const row = yield* authorization(principal, id);\n yield* commit(\"authorizations.promoteCapabilities\");\n state.authorizations.set(\n id,\n new Storage.Authorization({\n ...row,\n capabilities: [...new Set([...row.capabilities, ...capabilities])],\n }),\n );\n }),\n ),\n revoke: (id, revoke) =>\n read((principal) =>\n authorization(principal, id).pipe(\n Effect.flatMap((row) => finishRevocation(principal, row, revoke)),\n ),\n ),\n recoverRevocations: (revoke) =>\n read((principal) =>\n Effect.forEach(\n ownedRows(state.authorizations, principal).filter(\n (row) => row.revocation === \"pending\",\n ),\n (row) => finishRevocation(principal, row, revoke(row)),\n ).pipe(Effect.map((finished) => finished.length)),\n ),\n },\n connections: {\n create: (authorizationId) =>\n write((principal) =>\n Effect.gen(function* () {\n yield* authorization(principal, authorizationId);\n const row = new Storage.Connection({\n id: yield* fresh(\"conn\"),\n ownerId: principal.ownerId,\n authorizationId,\n createdAt: yield* DateTime.now,\n });\n yield* commit(\"connections.create\");\n state.connections.set(row.id, row);\n return row;\n }),\n ),\n get: (id) => read((principal) => connection(principal, id)),\n list: (filter) =>\n read((principal) =>\n Effect.sync(() =>\n ownedRows(state.connections, principal).filter(\n (row) =>\n filter?.provider === undefined ||\n state.authorizations.get(row.authorizationId)?.provider === filter.provider,\n ),\n ),\n ),\n remove: (id) =>\n write((principal) =>\n Effect.gen(function* () {\n yield* connection(principal, id);\n if (ownedRows(state.attachments, principal).some((row) => row.connectionId === id)) {\n return yield* invalid(`Connection ${id} still has attachments`, \"connectionId\");\n }\n yield* commit(\"connections.remove\");\n state.connections.delete(id);\n }),\n ),\n },\n attachments: {\n create: (input) =>\n write((principal) =>\n Effect.gen(function* () {\n yield* connection(principal, input.connectionId);\n if (\n ownedRows(state.attachments, principal).some((row) => row.domain === input.domain)\n ) {\n return yield* invalid(`${input.domain} is already attached`, \"domain\");\n }\n const row = new Storage.Attachment({\n id: yield* fresh(\"att\"),\n ownerId: principal.ownerId,\n connectionId: input.connectionId,\n domain: input.domain,\n zone: input.zone,\n target: input.target,\n createdAt: yield* DateTime.now,\n });\n yield* commit(\"attachments.create\");\n state.attachments.set(row.id, row);\n return row;\n }),\n ),\n get: (id) => read((principal) => attachment(principal, id)),\n byDomain: (domain) =>\n read((principal) =>\n Effect.sync(() =>\n Option.fromNullishOr(\n ownedRows(state.attachments, principal).find((row) => row.domain === domain),\n ),\n ),\n ),\n list: (connectionId) =>\n read((principal) =>\n connection(principal, connectionId).pipe(\n Effect.map(() =>\n ownedRows(state.attachments, principal).filter(\n (row) => row.connectionId === connectionId,\n ),\n ),\n ),\n ),\n remove: (id) =>\n write((principal) =>\n Effect.gen(function* () {\n yield* attachment(principal, id);\n yield* commit(\"attachments.remove\");\n state.attachments.delete(id);\n }),\n ),\n },\n continuations: {\n put: (continuation) =>\n write((principal) =>\n Effect.gen(function* () {\n if (continuation.ownerId !== principal.ownerId) {\n return yield* invalid(\"Continuation owner does not match the principal\", \"ownerId\");\n }\n yield* commit(\"continuations.put\");\n state.continuations.set(continuation.id, continuation);\n }),\n ),\n get: (id) =>\n read((principal) =>\n Effect.gen(function* () {\n const row = owned(state.continuations, principal, id);\n if (row === undefined) return yield* notFound(\"continuation\", id);\n const now = yield* DateTime.now;\n if (DateTime.toEpochMillis(row.expiresAt) <= DateTime.toEpochMillis(now)) {\n return yield* Errors.fail(new Reason.Expired({ entity: \"continuation\", id }));\n }\n return row;\n }),\n ),\n consume: (id) =>\n write((principal) =>\n Effect.gen(function* () {\n const row = owned(state.continuations, principal, id);\n if (row === undefined) return yield* notFound(\"continuation\", id);\n yield* commit(\"continuations.consume\");\n state.continuations.delete(id);\n const now = yield* DateTime.now;\n if (DateTime.toEpochMillis(row.expiresAt) <= DateTime.toEpochMillis(now)) {\n return yield* Errors.fail(new Reason.Expired({ entity: \"continuation\", id }));\n }\n return row;\n }),\n ),\n },\n attempts: {\n create: (input) =>\n write((principal) =>\n Effect.gen(function* () {\n if (input.ownerId !== principal.ownerId) {\n return yield* invalid(\"Attempt owner does not match the principal\", \"ownerId\");\n }\n if (state.attempts.has(input.id)) {\n return yield* invalid(`Plan ${input.id} already exists`, \"id\");\n }\n yield* commit(\"attempts.create\");\n state.attempts.set(input.id, input);\n return input;\n }),\n ),\n get: (id) => read((principal) => attempt(principal, id)),\n byApproval: (id) =>\n read((principal) =>\n attemptWhere(principal, \"approval\", id, (row) => row.approval?.id === id),\n ),\n byReceipt: (id) =>\n read((principal) =>\n attemptWhere(principal, \"receipt\", id, (row) => row.receipt?.id === id),\n ),\n latest: (attachmentId, kind) =>\n read((principal) =>\n Effect.sync(() =>\n Option.fromNullishOr(\n ownedRows(state.attempts, principal)\n .filter((row) => row.attachmentId === attachmentId && row.kind === kind)\n .reduce<Storage.Attempt | undefined>(\n (best, row) =>\n best === undefined ||\n DateTime.toEpochMillis(row.plan.createdAt) >=\n DateTime.toEpochMillis(best.plan.createdAt)\n ? row\n : best,\n undefined,\n ),\n ),\n ),\n ),\n approve: (id, approval: Approval.Model) =>\n write((principal) =>\n Effect.gen(function* () {\n const row = yield* attempt(principal, id);\n if (row.approval?.id === approval.id) return row;\n if (row.status !== \"planned\") return yield* stale(row);\n const next = new Storage.Attempt({\n ...row,\n status: \"approved\",\n approval,\n updatedAt: yield* DateTime.now,\n });\n yield* commit(\"attempts.approve\");\n state.attempts.set(id, next);\n return next;\n }),\n ),\n reject: (id, input) =>\n write((principal) =>\n Effect.gen(function* () {\n const row = yield* attempt(principal, id);\n if (row.status === \"rejected\") return row;\n if (row.status === \"expired\") {\n return yield* Errors.fail(new Reason.Expired({ entity: \"plan\", id }));\n }\n if (row.status !== \"planned\" || row.plan.digest !== input.digest)\n return yield* stale(row);\n const now = yield* DateTime.now;\n const next = new Storage.Attempt({\n ...row,\n status: \"rejected\",\n rejection: { actorId: input.actorId, reason: input.reason, at: now },\n updatedAt: now,\n });\n yield* commit(\"attempts.reject\");\n state.attempts.set(id, next);\n return next;\n }),\n ),\n claim: (id, lease) =>\n write((principal) =>\n Effect.gen(function* () {\n const row = yield* attempt(principal, id);\n const now = yield* DateTime.now;\n if (row.status === \"applying\") {\n const held =\n row.leaseExpiresAt !== null &&\n DateTime.toEpochMillis(row.leaseExpiresAt) > DateTime.toEpochMillis(now);\n if (held) {\n return yield* Errors.fail(new Reason.Busy({ key: `apply:${id}` }));\n }\n } else if (row.status !== \"approved\" && row.status !== \"failed\") {\n return yield* stale(row);\n }\n const next = new Storage.Attempt({\n ...row,\n status: \"applying\",\n leaseExpiresAt: lease,\n failure: null,\n updatedAt: now,\n });\n yield* commit(\"attempts.claim\");\n state.attempts.set(id, next);\n return next;\n }),\n ),\n complete: (id, receipt: Receipt.Model) =>\n write((principal) =>\n Effect.gen(function* () {\n const row = yield* attempt(principal, id);\n if (row.status !== \"applying\") return yield* stale(row);\n const next = new Storage.Attempt({\n ...row,\n status: receipt.status,\n receipt,\n leaseExpiresAt: null,\n updatedAt: yield* DateTime.now,\n });\n yield* commit(\"attempts.complete\");\n state.attempts.set(id, next);\n return next;\n }),\n ),\n fail: (id, message) =>\n write((principal) =>\n Effect.gen(function* () {\n const row = yield* attempt(principal, id);\n if (row.status !== \"applying\") return yield* stale(row);\n const next = new Storage.Attempt({\n ...row,\n status: \"failed\",\n failure: message,\n leaseExpiresAt: null,\n updatedAt: yield* DateTime.now,\n });\n yield* commit(\"attempts.fail\");\n state.attempts.set(id, next);\n return next;\n }),\n ),\n },\n readiness: {\n put: (readiness) =>\n write((principal) =>\n Effect.gen(function* () {\n if (readiness.ownerId !== principal.ownerId) {\n return yield* invalid(\"Readiness owner does not match the principal\", \"ownerId\");\n }\n if (readiness.attachmentId !== null)\n yield* attachment(principal, readiness.attachmentId);\n yield* commit(\"readiness.put\");\n state.readiness.set(`${principal.ownerId}:${readiness.domain}`, readiness);\n }),\n ),\n get: (domain) =>\n read((principal) =>\n Effect.sync(() =>\n Option.fromNullishOr(state.readiness.get(`${principal.ownerId}:${domain}`)),\n ),\n ),\n },\n withLock: (key, effect) =>\n Effect.flatMap(Principal.Service, (principal) => {\n const scoped = `${principal.ownerId}:${key}`;\n return Effect.acquireRelease(\n Effect.suspend(() => {\n if (state.locks.has(scoped)) {\n return Errors.fail(new Reason.Busy({ key }));\n }\n state.locks.add(scoped);\n return Effect.void;\n }),\n () => Effect.sync(() => void state.locks.delete(scoped)),\n ).pipe(\n Effect.flatMap(() => effect),\n Effect.scoped,\n );\n }),\n };\n}\n\nconst stale = (row: Storage.Attempt) =>\n Errors.fail(new Reason.Stale({ planId: Plan.PlanId.make(row.id), digest: row.plan.digest }));\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"storage-memory.mjs","names":["Errors.fail","Reason.NotFound","Reason.InvalidInput","Principal.Service","Storage.Authorization","Reason.Busy","Storage.Connection","Storage.Attachment","Reason.Expired","Storage.Attempt","Reason.Stale"],"sources":["../../src/internal/storage-memory.ts"],"sourcesContent":["import { DateTime, Effect, Option, Semaphore } from \"effect\";\n\nimport type * as Approval from \"../Approval.ts\";\nimport * as Errors from \"./error.ts\";\nimport * as Reason from \"../Reason.ts\";\nimport * as Plan from \"../Plan.ts\";\nimport * as Principal from \"../Principal.ts\";\nimport type * as Receipt from \"../Receipt.ts\";\nimport * as Storage from \"../Storage.ts\";\nimport { fresh } from \"./ids.ts\";\n\ninterface State {\n readonly authorizations: Map<string, Storage.Authorization>;\n readonly credentials: Map<string, Storage.Credential>;\n readonly connections: Map<string, Storage.Connection>;\n readonly attachments: Map<string, Storage.Attachment>;\n readonly continuations: Map<string, Storage.Continuation>;\n readonly attempts: Map<string, Storage.Attempt>;\n readonly readiness: Map<string, Storage.Readiness>;\n readonly locks: Set<string>;\n}\n\nconst notFound = (entity: Reason.NotFound[\"entity\"], id: string) =>\n Errors.fail(new Reason.NotFound({ entity, id }));\nconst invalid = (message: string, field?: string) =>\n Errors.fail(new Reason.InvalidInput({ message, ...(field === undefined ? {} : { field }) }));\n\nexport function makeMemory(options: Storage.MemoryOptions = {}): Storage.Interface {\n const state: State = {\n authorizations: new Map(),\n credentials: new Map(),\n connections: new Map(),\n attachments: new Map(),\n continuations: new Map(),\n attempts: new Map(),\n readiness: new Map(),\n locks: new Set(),\n };\n const mutations = Semaphore.makeUnsafe(1);\n const commit = (operation: string) =>\n options.beforeCommit === undefined ? Effect.void : options.beforeCommit(operation);\n\n const read = <A, E, R = never>(\n run: (principal: Principal.Interface) => Effect.Effect<A, E, R>,\n ): Effect.Effect<A, E, Principal.Service | R> => Effect.flatMap(Principal.Service, run);\n const write = <A, E>(\n run: (principal: Principal.Interface) => Effect.Effect<A, E>,\n ): Effect.Effect<A, E, Principal.Service> =>\n Effect.flatMap(Principal.Service, (principal) => mutations.withPermit(run(principal)));\n\n const owned = <Row extends { readonly ownerId: string }>(\n rows: Map<string, Row>,\n principal: Principal.Interface,\n id: string,\n ): Row | undefined => {\n const row = rows.get(id);\n return row !== undefined && row.ownerId === principal.ownerId ? row : undefined;\n };\n const ownedRows = <Row extends { readonly ownerId: string }>(\n rows: Map<string, Row>,\n principal: Principal.Interface,\n ) => [...rows.values()].filter((row) => row.ownerId === principal.ownerId);\n\n const authorization = (principal: Principal.Interface, id: string) =>\n Effect.suspend(() => {\n const row = owned(state.authorizations, principal, id);\n return row === undefined ? notFound(\"authorization\", id) : Effect.succeed(row);\n });\n const connection = (principal: Principal.Interface, id: string) =>\n Effect.suspend(() => {\n const row = owned(state.connections, principal, id);\n return row === undefined ? notFound(\"connection\", id) : Effect.succeed(row);\n });\n const attachment = (principal: Principal.Interface, id: string) =>\n Effect.suspend(() => {\n const row = owned(state.attachments, principal, id);\n return row === undefined ? notFound(\"attachment\", id) : Effect.succeed(row);\n });\n const attempt = (principal: Principal.Interface, id: string) =>\n Effect.suspend(() => {\n const row = owned(state.attempts, principal, id);\n return row === undefined ? notFound(\"plan\", id) : Effect.succeed(row);\n });\n const attemptWhere = (\n principal: Principal.Interface,\n entity: Reason.NotFound[\"entity\"],\n id: string,\n predicate: (row: Storage.Attempt) => boolean,\n ) =>\n Effect.suspend(() => {\n const row = ownedRows(state.attempts, principal).find(predicate);\n return row === undefined ? notFound(entity, id) : Effect.succeed(row);\n });\n\n const finishRevocation = <E, R>(\n principal: Principal.Interface,\n row: Storage.Authorization,\n revoke: Effect.Effect<void, E, R>,\n ): Effect.Effect<void, Errors.DomainKitError | E, R> =>\n Effect.gen(function* () {\n yield* commit(\"authorizations.prepareRevocation\");\n state.authorizations.set(\n row.id,\n new Storage.Authorization({ ...row, revocation: \"pending\" }),\n );\n yield* revoke;\n yield* commit(\"authorizations.completeRevocation\");\n if (owned(state.authorizations, principal, row.id) !== undefined) {\n state.authorizations.delete(row.id);\n state.credentials.delete(row.id);\n }\n });\n\n return {\n authorizations: {\n upsert: ({ authorization: input, credential, expectedId }) =>\n write((principal) =>\n Effect.gen(function* () {\n if (input.ownerId !== principal.ownerId) {\n return yield* invalid(\"Authorization owner does not match the principal\", \"ownerId\");\n }\n if (expectedId !== undefined) {\n const current = yield* authorization(principal, expectedId);\n if (current.revocation !== \"active\") {\n return yield* Errors.fail(new Reason.Busy({ key: `authorization:${expectedId}` }));\n }\n if (input.id !== expectedId) {\n return yield* invalid(\"Authorization id must match expectedId\", \"id\");\n }\n } else if (state.authorizations.has(input.id)) {\n return yield* invalid(`Authorization ${input.id} already exists`, \"id\");\n }\n yield* commit(\"authorizations.upsert\");\n state.authorizations.set(input.id, input);\n state.credentials.set(input.id, credential);\n return input;\n }),\n ),\n get: (id) => read((principal) => authorization(principal, id)),\n credential: (id) =>\n read((principal) =>\n authorization(principal, id).pipe(\n Effect.flatMap(() => {\n const row = state.credentials.get(id);\n return row === undefined ? notFound(\"authorization\", id) : Effect.succeed(row);\n }),\n ),\n ),\n rotate: (id, credential) =>\n write((principal) =>\n Effect.gen(function* () {\n yield* authorization(principal, id);\n yield* commit(\"authorizations.rotate\");\n state.credentials.set(id, credential);\n }),\n ),\n promoteCapabilities: (id, capabilities) =>\n write((principal) =>\n Effect.gen(function* () {\n const row = yield* authorization(principal, id);\n yield* commit(\"authorizations.promoteCapabilities\");\n state.authorizations.set(\n id,\n new Storage.Authorization({\n ...row,\n capabilities: [...new Set([...row.capabilities, ...capabilities])],\n }),\n );\n }),\n ),\n revoke: (id, revoke) =>\n read((principal) =>\n authorization(principal, id).pipe(\n Effect.flatMap((row) => finishRevocation(principal, row, revoke)),\n ),\n ),\n recoverRevocations: (revoke) =>\n read((principal) =>\n Effect.forEach(\n ownedRows(state.authorizations, principal).filter(\n (row) => row.revocation === \"pending\",\n ),\n (row) => finishRevocation(principal, row, revoke(row)),\n ).pipe(Effect.map((finished) => finished.length)),\n ),\n },\n connections: {\n create: (authorizationId) =>\n write((principal) =>\n Effect.gen(function* () {\n yield* authorization(principal, authorizationId);\n const row = new Storage.Connection({\n id: yield* fresh(\"conn\"),\n ownerId: principal.ownerId,\n authorizationId,\n createdAt: yield* DateTime.now,\n });\n yield* commit(\"connections.create\");\n state.connections.set(row.id, row);\n return row;\n }),\n ),\n get: (id) => read((principal) => connection(principal, id)),\n list: (filter) =>\n read((principal) =>\n Effect.sync(() =>\n ownedRows(state.connections, principal).filter(\n (row) =>\n filter?.provider === undefined ||\n state.authorizations.get(row.authorizationId)?.provider === filter.provider,\n ),\n ),\n ),\n remove: (id) =>\n write((principal) =>\n Effect.gen(function* () {\n yield* connection(principal, id);\n if (ownedRows(state.attachments, principal).some((row) => row.connectionId === id)) {\n return yield* invalid(`Connection ${id} still has attachments`, \"connectionId\");\n }\n yield* commit(\"connections.remove\");\n state.connections.delete(id);\n }),\n ),\n },\n attachments: {\n create: (input) =>\n write((principal) =>\n Effect.gen(function* () {\n yield* connection(principal, input.connectionId);\n if (\n ownedRows(state.attachments, principal).some((row) => row.domain === input.domain)\n ) {\n return yield* invalid(`${input.domain} is already attached`, \"domain\");\n }\n const row = new Storage.Attachment({\n id: yield* fresh(\"att\"),\n ownerId: principal.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 yield* commit(\"attachments.create\");\n state.attachments.set(row.id, row);\n return row;\n }),\n ),\n get: (id) => read((principal) => attachment(principal, id)),\n byDomain: (domain) =>\n read((principal) =>\n Effect.sync(() =>\n Option.fromNullishOr(\n ownedRows(state.attachments, principal).find((row) => row.domain === domain),\n ),\n ),\n ),\n list: (connectionId) =>\n read((principal) =>\n connection(principal, connectionId).pipe(\n Effect.map(() =>\n ownedRows(state.attachments, principal).filter(\n (row) => row.connectionId === connectionId,\n ),\n ),\n ),\n ),\n remove: (id) =>\n write((principal) =>\n Effect.gen(function* () {\n yield* attachment(principal, id);\n yield* commit(\"attachments.remove\");\n state.attachments.delete(id);\n }),\n ),\n },\n continuations: {\n put: (continuation) =>\n write((principal) =>\n Effect.gen(function* () {\n if (continuation.ownerId !== principal.ownerId) {\n return yield* invalid(\"Continuation owner does not match the principal\", \"ownerId\");\n }\n yield* commit(\"continuations.put\");\n state.continuations.set(continuation.id, continuation);\n }),\n ),\n get: (id) =>\n read((principal) =>\n Effect.gen(function* () {\n const row = owned(state.continuations, principal, id);\n if (row === undefined) return yield* notFound(\"continuation\", id);\n const now = yield* DateTime.now;\n if (DateTime.toEpochMillis(row.expiresAt) <= DateTime.toEpochMillis(now)) {\n return yield* Errors.fail(new Reason.Expired({ entity: \"continuation\", id }));\n }\n return row;\n }),\n ),\n consume: (id) =>\n write((principal) =>\n Effect.gen(function* () {\n const row = owned(state.continuations, principal, id);\n if (row === undefined) return yield* notFound(\"continuation\", id);\n yield* commit(\"continuations.consume\");\n state.continuations.delete(id);\n const now = yield* DateTime.now;\n if (DateTime.toEpochMillis(row.expiresAt) <= DateTime.toEpochMillis(now)) {\n return yield* Errors.fail(new Reason.Expired({ entity: \"continuation\", id }));\n }\n return row;\n }),\n ),\n },\n attempts: {\n create: (input) =>\n write((principal) =>\n Effect.gen(function* () {\n if (input.ownerId !== principal.ownerId) {\n return yield* invalid(\"Attempt owner does not match the principal\", \"ownerId\");\n }\n if (state.attempts.has(input.id)) {\n return yield* invalid(`Plan ${input.id} already exists`, \"id\");\n }\n yield* commit(\"attempts.create\");\n state.attempts.set(input.id, input);\n return input;\n }),\n ),\n get: (id) => read((principal) => attempt(principal, id)),\n byApproval: (id) =>\n read((principal) =>\n attemptWhere(principal, \"approval\", id, (row) => row.approval?.id === id),\n ),\n byReceipt: (id) =>\n read((principal) =>\n attemptWhere(principal, \"receipt\", id, (row) => row.receipt?.id === id),\n ),\n latest: (attachmentId, kind) =>\n read((principal) =>\n Effect.sync(() =>\n Option.fromNullishOr(\n ownedRows(state.attempts, principal)\n .filter((row) => row.attachmentId === attachmentId && row.kind === kind)\n .reduce<Storage.Attempt | undefined>(\n (best, row) =>\n best === undefined ||\n DateTime.toEpochMillis(row.plan.createdAt) >=\n DateTime.toEpochMillis(best.plan.createdAt)\n ? row\n : best,\n undefined,\n ),\n ),\n ),\n ),\n approve: (id, approval: Approval.Model) =>\n write((principal) =>\n Effect.gen(function* () {\n const row = yield* attempt(principal, id);\n if (row.approval?.id === approval.id) return row;\n if (row.status !== \"planned\") return yield* stale(row);\n const next = new Storage.Attempt({\n ...row,\n status: \"approved\",\n approval,\n updatedAt: yield* DateTime.now,\n });\n yield* commit(\"attempts.approve\");\n state.attempts.set(id, next);\n return next;\n }),\n ),\n reject: (id, input) =>\n write((principal) =>\n Effect.gen(function* () {\n const row = yield* attempt(principal, id);\n if (row.status === \"rejected\") return row;\n if (row.status === \"expired\") {\n return yield* Errors.fail(new Reason.Expired({ entity: \"plan\", id }));\n }\n if (row.status !== \"planned\" || row.plan.digest !== input.digest)\n return yield* stale(row);\n const now = yield* DateTime.now;\n const next = new Storage.Attempt({\n ...row,\n status: \"rejected\",\n rejection: { actorId: input.actorId, reason: input.reason, at: now },\n updatedAt: now,\n });\n yield* commit(\"attempts.reject\");\n state.attempts.set(id, next);\n return next;\n }),\n ),\n claim: (id, lease) =>\n write((principal) =>\n Effect.gen(function* () {\n const row = yield* attempt(principal, id);\n const now = yield* DateTime.now;\n if (row.status === \"applying\") {\n const held =\n row.leaseExpiresAt !== null &&\n DateTime.toEpochMillis(row.leaseExpiresAt) > DateTime.toEpochMillis(now);\n if (held) {\n return yield* Errors.fail(new Reason.Busy({ key: `apply:${id}` }));\n }\n } else if (row.status !== \"approved\" && row.status !== \"failed\") {\n return yield* stale(row);\n }\n const next = new Storage.Attempt({\n ...row,\n status: \"applying\",\n leaseExpiresAt: lease,\n failure: null,\n updatedAt: now,\n });\n yield* commit(\"attempts.claim\");\n state.attempts.set(id, next);\n return next;\n }),\n ),\n complete: (id, receipt: Receipt.Model) =>\n write((principal) =>\n Effect.gen(function* () {\n const row = yield* attempt(principal, id);\n if (row.status !== \"applying\") return yield* stale(row);\n const next = new Storage.Attempt({\n ...row,\n status: receipt.status,\n receipt,\n leaseExpiresAt: null,\n updatedAt: yield* DateTime.now,\n });\n yield* commit(\"attempts.complete\");\n state.attempts.set(id, next);\n return next;\n }),\n ),\n fail: (id, message) =>\n write((principal) =>\n Effect.gen(function* () {\n const row = yield* attempt(principal, id);\n if (row.status !== \"applying\") return yield* stale(row);\n const next = new Storage.Attempt({\n ...row,\n status: \"failed\",\n failure: message,\n leaseExpiresAt: null,\n updatedAt: yield* DateTime.now,\n });\n yield* commit(\"attempts.fail\");\n state.attempts.set(id, next);\n return next;\n }),\n ),\n },\n readiness: {\n put: (readiness) =>\n write((principal) =>\n Effect.gen(function* () {\n if (readiness.ownerId !== principal.ownerId) {\n return yield* invalid(\"Readiness owner does not match the principal\", \"ownerId\");\n }\n if (readiness.attachmentId !== null)\n yield* attachment(principal, readiness.attachmentId);\n yield* commit(\"readiness.put\");\n state.readiness.set(`${principal.ownerId}:${readiness.domain}`, readiness);\n }),\n ),\n get: (domain) =>\n read((principal) =>\n Effect.sync(() =>\n Option.fromNullishOr(state.readiness.get(`${principal.ownerId}:${domain}`)),\n ),\n ),\n },\n withLock: (key, effect) =>\n Effect.flatMap(Principal.Service, (principal) => {\n const scoped = `${principal.ownerId}:${key}`;\n return Effect.acquireRelease(\n Effect.suspend(() => {\n if (state.locks.has(scoped)) {\n return Errors.fail(new Reason.Busy({ key }));\n }\n state.locks.add(scoped);\n return Effect.void;\n }),\n () => Effect.sync(() => void state.locks.delete(scoped)),\n ).pipe(\n Effect.flatMap(() => effect),\n Effect.scoped,\n );\n }),\n };\n}\n\nconst stale = (row: Storage.Attempt) =>\n Errors.fail(new Reason.Stale({ planId: Plan.PlanId.make(row.id), digest: row.plan.digest }));\n"],"mappings":"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"}
|
package/dist/package.mjs
CHANGED
package/dist/types/Connect.d.ts
CHANGED
|
@@ -412,8 +412,39 @@ export declare const Discovery: {
|
|
|
412
412
|
}>;
|
|
413
413
|
}, "_tag">;
|
|
414
414
|
};
|
|
415
|
+
/** One zone a connection reaches, with the connection that reaches it. */
|
|
416
|
+
export interface Zone {
|
|
417
|
+
readonly connectionId: string;
|
|
418
|
+
readonly provider: string;
|
|
419
|
+
readonly target: Provider.Target;
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* A connection's standing in a zone listing. `reconnect` is a credential the provider turned down:
|
|
423
|
+
* the connection is still the owner's, and the other connections' zones came back regardless.
|
|
424
|
+
*/
|
|
425
|
+
export interface ZoneConnection {
|
|
426
|
+
readonly connectionId: string;
|
|
427
|
+
readonly provider: string;
|
|
428
|
+
readonly status: "connected" | "reconnect";
|
|
429
|
+
}
|
|
430
|
+
/** Every zone the principal's connections reach, and how each connection is standing. */
|
|
431
|
+
export interface Zones {
|
|
432
|
+
/** Ordered by zone, then by connection, so two listings of the same state read the same. */
|
|
433
|
+
readonly zones: ReadonlyArray<Zone>;
|
|
434
|
+
readonly connections: ReadonlyArray<ZoneConnection>;
|
|
435
|
+
/** Every provider a customer could connect from here, so an offer needs no second call. */
|
|
436
|
+
readonly providers: Snapshot["providers"];
|
|
437
|
+
}
|
|
415
438
|
export interface Interface {
|
|
416
439
|
readonly inspect: (domain: string) => Fx<Snapshot>;
|
|
440
|
+
/**
|
|
441
|
+
* Every zone the principal's connections can serve, from `Provider.Session.listTargets`. A
|
|
442
|
+
* connection whose credential the provider turned down is marked `reconnect` in `connections`
|
|
443
|
+
* and contributes no zones; the rest still list.
|
|
444
|
+
*/
|
|
445
|
+
readonly zones: (options?: {
|
|
446
|
+
readonly provider?: string;
|
|
447
|
+
}) => Fx<Zones>;
|
|
417
448
|
/**
|
|
418
449
|
* Resolve the domain's authoritative nameservers, then match them against the zones each of
|
|
419
450
|
* the principal's connections can reach: the closest zone wins, a decisive nameserver match
|
|
@@ -427,6 +458,18 @@ export interface Interface {
|
|
|
427
458
|
readonly domain?: string;
|
|
428
459
|
readonly callbackUrl?: string;
|
|
429
460
|
}) => Fx<Started>;
|
|
461
|
+
/**
|
|
462
|
+
* Replace the credential behind a connection the owner already holds, keeping the connection and
|
|
463
|
+
* every domain attached to it. This is what a customer means by reconnecting: starting again
|
|
464
|
+
* would mint a second account and leave the domains on the one the provider turned down. The
|
|
465
|
+
* provider is the connection's own; a credential for a different account is the customer's
|
|
466
|
+
* choice, and the zone check on every session catches a zone it can no longer reach.
|
|
467
|
+
*/
|
|
468
|
+
readonly reconnect: (input: {
|
|
469
|
+
readonly connectionId: string;
|
|
470
|
+
readonly method: Method;
|
|
471
|
+
readonly callbackUrl?: string;
|
|
472
|
+
}) => Fx<Started>;
|
|
430
473
|
/** Finish an interactive connection from the provider callback (the full callback URL). */
|
|
431
474
|
readonly complete: (input: {
|
|
432
475
|
readonly continuationId: string;
|
|
@@ -470,6 +513,9 @@ export declare class Policy extends Policy_base {
|
|
|
470
513
|
export declare const make: Effect.Effect<Interface, never, Storage.Service | Custody.Service | Providers.Service | Resolver.Service>;
|
|
471
514
|
export declare const layer: Layer.Layer<Service, never, Storage.Service | Custody.Service | Providers.Service | Resolver.Service>;
|
|
472
515
|
export declare const inspect: (domain: string) => Effect.Effect<Snapshot, Errors.DomainKitError, Principal.Service | Service>;
|
|
516
|
+
export declare const zones: (options?: {
|
|
517
|
+
readonly provider?: string;
|
|
518
|
+
} | undefined) => Effect.Effect<Zones, Errors.DomainKitError, Principal.Service | Service>;
|
|
473
519
|
export declare const discover: (domain: string) => Effect.Effect<{
|
|
474
520
|
readonly _tag: "NotFound";
|
|
475
521
|
readonly nameservers: ReadonlyArray<string>;
|
|
@@ -505,6 +551,23 @@ export declare const start: (input: {
|
|
|
505
551
|
readonly connection: Storage.Connection;
|
|
506
552
|
readonly candidates: ReadonlyArray<Provider.Target>;
|
|
507
553
|
}, Errors.DomainKitError, Principal.Service | Service>;
|
|
554
|
+
export declare const reconnect: (input: {
|
|
555
|
+
readonly connectionId: string;
|
|
556
|
+
readonly method: Method;
|
|
557
|
+
readonly callbackUrl?: string;
|
|
558
|
+
}) => Effect.Effect<{
|
|
559
|
+
readonly _tag: "Connected";
|
|
560
|
+
readonly connection: Storage.Connection;
|
|
561
|
+
readonly attachment: Storage.Attachment | null;
|
|
562
|
+
} | {
|
|
563
|
+
readonly _tag: "Redirect";
|
|
564
|
+
readonly authorizationUrl: string;
|
|
565
|
+
readonly continuationId: string;
|
|
566
|
+
} | {
|
|
567
|
+
readonly _tag: "SelectionRequired";
|
|
568
|
+
readonly connection: Storage.Connection;
|
|
569
|
+
readonly candidates: ReadonlyArray<Provider.Target>;
|
|
570
|
+
}, Errors.DomainKitError, Principal.Service | Service>;
|
|
508
571
|
export declare const complete: (input: {
|
|
509
572
|
readonly continuationId: string;
|
|
510
573
|
readonly callbackUrl: string;
|