domainkit 0.7.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (165) hide show
  1. package/README.md +214 -39
  2. package/dist/Approval.mjs +34 -0
  3. package/dist/Approval.mjs.map +1 -0
  4. package/dist/Cleanup.mjs +97 -0
  5. package/dist/Cleanup.mjs.map +1 -0
  6. package/dist/Cloudflare.mjs +225 -0
  7. package/dist/Cloudflare.mjs.map +1 -0
  8. package/dist/Connect.mjs +463 -0
  9. package/dist/Connect.mjs.map +1 -0
  10. package/dist/Custody.mjs +64 -0
  11. package/dist/Custody.mjs.map +1 -0
  12. package/dist/DnsRecord.mjs +213 -0
  13. package/dist/DnsRecord.mjs.map +1 -0
  14. package/dist/DomainKit.mjs +34 -0
  15. package/dist/DomainKit.mjs.map +1 -0
  16. package/dist/DomainName.mjs +100 -0
  17. package/dist/DomainName.mjs.map +1 -0
  18. package/dist/Plan.mjs +102 -0
  19. package/dist/Plan.mjs.map +1 -0
  20. package/dist/Principal.mjs +23 -0
  21. package/dist/Principal.mjs.map +1 -0
  22. package/dist/Provider.mjs +130 -0
  23. package/dist/Provider.mjs.map +1 -0
  24. package/dist/Providers.mjs +40 -0
  25. package/dist/Providers.mjs.map +1 -0
  26. package/dist/Provision.mjs +93 -0
  27. package/dist/Provision.mjs.map +1 -0
  28. package/dist/Reason.mjs +162 -0
  29. package/dist/Reason.mjs.map +1 -0
  30. package/dist/Receipt.mjs +71 -0
  31. package/dist/Receipt.mjs.map +1 -0
  32. package/dist/Resolver.mjs +75 -0
  33. package/dist/Resolver.mjs.map +1 -0
  34. package/dist/Server.mjs +516 -0
  35. package/dist/Server.mjs.map +1 -0
  36. package/dist/Storage.mjs +236 -0
  37. package/dist/Storage.mjs.map +1 -0
  38. package/dist/Testing.mjs +226 -0
  39. package/dist/Testing.mjs.map +1 -0
  40. package/dist/Transport.mjs +187 -0
  41. package/dist/Transport.mjs.map +1 -0
  42. package/dist/Vercel.mjs +116 -0
  43. package/dist/Vercel.mjs.map +1 -0
  44. package/dist/Verify.mjs +292 -0
  45. package/dist/Verify.mjs.map +1 -0
  46. package/dist/{rolldown-runtime-D7D4PA-g.mjs → _virtual/_rolldown/runtime.mjs} +1 -1
  47. package/dist/entry/client.mjs +2 -0
  48. package/dist/entry/server.mjs +2 -0
  49. package/dist/entry/testing.mjs +3 -0
  50. package/dist/index.mjs +33 -356
  51. package/dist/index.mjs.map +1 -1
  52. package/dist/internal/aes.mjs +61 -0
  53. package/dist/internal/aes.mjs.map +1 -0
  54. package/dist/internal/attempts.mjs +284 -0
  55. package/dist/internal/attempts.mjs.map +1 -0
  56. package/dist/internal/cloudflare/client.mjs +100 -0
  57. package/dist/internal/cloudflare/client.mjs.map +1 -0
  58. package/dist/internal/cloudflare/protocol.mjs +59 -0
  59. package/dist/internal/cloudflare/protocol.mjs.map +1 -0
  60. package/dist/internal/cloudflare/records.mjs +156 -0
  61. package/dist/internal/cloudflare/records.mjs.map +1 -0
  62. package/dist/internal/config.mjs +13 -0
  63. package/dist/internal/config.mjs.map +1 -0
  64. package/dist/internal/conformance/provider.mjs +207 -0
  65. package/dist/internal/conformance/provider.mjs.map +1 -0
  66. package/dist/internal/conformance/storage.mjs +428 -0
  67. package/dist/internal/conformance/storage.mjs.map +1 -0
  68. package/dist/internal/digest.mjs +25 -0
  69. package/dist/internal/digest.mjs.map +1 -0
  70. package/dist/internal/doh.mjs +152 -0
  71. package/dist/internal/doh.mjs.map +1 -0
  72. package/dist/internal/error.mjs +69 -0
  73. package/dist/internal/error.mjs.map +1 -0
  74. package/dist/internal/http.mjs +89 -0
  75. package/dist/internal/http.mjs.map +1 -0
  76. package/dist/internal/ids.mjs +8 -0
  77. package/dist/internal/ids.mjs.map +1 -0
  78. package/dist/internal/oauth.mjs +113 -0
  79. package/dist/internal/oauth.mjs.map +1 -0
  80. package/dist/internal/planner.mjs +88 -0
  81. package/dist/internal/planner.mjs.map +1 -0
  82. package/dist/internal/provider-async.mjs +83 -0
  83. package/dist/internal/provider-async.mjs.map +1 -0
  84. package/dist/internal/storage-memory.mjs +302 -0
  85. package/dist/internal/storage-memory.mjs.map +1 -0
  86. package/dist/internal/vercel/client.mjs +122 -0
  87. package/dist/internal/vercel/client.mjs.map +1 -0
  88. package/dist/internal/vercel/protocol.mjs +80 -0
  89. package/dist/internal/vercel/protocol.mjs.map +1 -0
  90. package/dist/internal/vercel/records.mjs +151 -0
  91. package/dist/internal/vercel/records.mjs.map +1 -0
  92. package/dist/package.mjs +6 -0
  93. package/dist/package.mjs.map +1 -0
  94. package/dist/types/Approval.d.ts +26 -0
  95. package/dist/types/Cleanup.d.ts +41 -0
  96. package/dist/types/Cloudflare.d.ts +36 -0
  97. package/dist/types/Connect.d.ts +506 -0
  98. package/dist/types/Custody.d.ts +38 -0
  99. package/dist/types/DnsRecord.d.ts +158 -0
  100. package/dist/types/DomainKit.d.ts +31 -0
  101. package/dist/types/DomainName.d.ts +27 -0
  102. package/dist/types/Plan.d.ts +76 -0
  103. package/dist/types/Principal.d.ts +18 -0
  104. package/dist/types/Provider.d.ts +248 -0
  105. package/dist/types/Providers.d.ts +16 -0
  106. package/dist/types/Provision.d.ts +75 -0
  107. package/dist/types/Reason.d.ts +118 -0
  108. package/dist/types/Receipt.d.ts +55 -0
  109. package/dist/types/Resolver.d.ts +135 -0
  110. package/dist/types/Server.d.ts +6523 -0
  111. package/dist/types/Storage.d.ts +314 -0
  112. package/dist/types/Testing.d.ts +84 -0
  113. package/dist/types/Transport.d.ts +124 -0
  114. package/dist/types/Vercel.d.ts +25 -0
  115. package/dist/types/Verify.d.ts +109 -0
  116. package/dist/types/entry/client.d.ts +2 -0
  117. package/dist/types/entry/server.d.ts +2 -0
  118. package/dist/types/entry/testing.d.ts +3 -0
  119. package/dist/types/index.d.ts +21 -0
  120. package/dist/types/internal/aes.d.ts +8 -0
  121. package/dist/types/internal/attempts.d.ts +40 -0
  122. package/dist/types/internal/cloudflare/client.d.ts +23 -0
  123. package/dist/types/internal/cloudflare/protocol.d.ts +71 -0
  124. package/dist/types/internal/cloudflare/records.d.ts +8 -0
  125. package/dist/types/internal/config.d.ts +4 -0
  126. package/dist/types/internal/conformance/provider.d.ts +12 -0
  127. package/dist/types/internal/conformance/storage.d.ts +14 -0
  128. package/dist/types/internal/digest.d.ts +10 -0
  129. package/dist/types/internal/doh.d.ts +19 -0
  130. package/dist/types/internal/error.d.ts +24 -0
  131. package/dist/types/internal/http.d.ts +27 -0
  132. package/dist/types/internal/ids.d.ts +3 -0
  133. package/dist/types/internal/oauth.d.ts +58 -0
  134. package/dist/types/internal/planner.d.ts +22 -0
  135. package/dist/types/internal/provider-async.d.ts +78 -0
  136. package/dist/types/internal/storage-memory.d.ts +2 -0
  137. package/dist/types/internal/vercel/client.d.ts +29 -0
  138. package/dist/types/internal/vercel/protocol.d.ts +124 -0
  139. package/dist/types/internal/vercel/records.d.ts +7 -0
  140. package/package.json +88 -12
  141. package/dist/canonical-json-CQYKsZw7.mjs +0 -310
  142. package/dist/canonical-json-CQYKsZw7.mjs.map +0 -1
  143. package/dist/connect-10vHuShV.d.mts +0 -1401
  144. package/dist/connect-oI8hcMxc.mjs +0 -185
  145. package/dist/connect-oI8hcMxc.mjs.map +0 -1
  146. package/dist/connection-C0xsU41C.d.mts +0 -186
  147. package/dist/connection-api-DW7xUJdj.d.mts +0 -26
  148. package/dist/index.d.mts +0 -882
  149. package/dist/managed-dns-connections-C3A_GBaz.mjs +0 -99
  150. package/dist/managed-dns-connections-C3A_GBaz.mjs.map +0 -1
  151. package/dist/promise.d.mts +0 -378
  152. package/dist/promise.mjs +0 -598
  153. package/dist/promise.mjs.map +0 -1
  154. package/dist/resolver-DPJs8h0a.mjs +0 -859
  155. package/dist/resolver-DPJs8h0a.mjs.map +0 -1
  156. package/dist/resolver-DRrLm_hB.d.mts +0 -3734
  157. package/dist/server.d.mts +0 -128
  158. package/dist/server.mjs +0 -319
  159. package/dist/server.mjs.map +0 -1
  160. package/dist/testing.d.mts +0 -62
  161. package/dist/testing.mjs +0 -507
  162. package/dist/testing.mjs.map +0 -1
  163. package/dist/verify-C3V_GtzL.d.mts +0 -1268
  164. package/dist/verify-DDnK8U7C.mjs +0 -2396
  165. package/dist/verify-DDnK8U7C.mjs.map +0 -1
@@ -0,0 +1,83 @@
1
+ import { ProviderUnavailable } from "../Reason.mjs";
2
+ import { DomainKitError, isDomainKitError } from "./error.mjs";
3
+ import { make, tokenAuth } from "../Provider.mjs";
4
+ import { DateTime, Effect, Redacted } from "effect";
5
+ //#region src/internal/provider-async.ts
6
+ const failure = (provider) => (cause) => isDomainKitError(cause) ? cause : new DomainKitError({ reason: new ProviderUnavailable({
7
+ provider,
8
+ message: cause instanceof Error ? cause.message : `${provider} request failed`
9
+ }) });
10
+ const issued = (value) => ({
11
+ secret: Redacted.make(value.secret),
12
+ context: value.context,
13
+ expiresAt: value.expiresAt === null ? null : DateTime.fromDateUnsafe(value.expiresAt)
14
+ });
15
+ const plain = (credential) => ({
16
+ secret: Redacted.value(credential.secret),
17
+ context: credential.context
18
+ });
19
+ /** Adapt a Promise-shaped provider; rejections become `DomainKit.Error` (a thrown one passes through). */
20
+ const fromAsync = (definition) => {
21
+ const call = (run) => Effect.tryPromise({
22
+ try: run,
23
+ catch: failure(definition.id)
24
+ });
25
+ const dns = (target, inner) => ({
26
+ list: (zone) => call(() => inner.list(zone)),
27
+ create: (zone, record) => call(() => inner.create(zone, record)),
28
+ get: (zone, providerRecordId) => call(() => inner.get(zone, providerRecordId)),
29
+ delete: (zone, providerRecordId) => call(() => inner.delete(zone, providerRecordId))
30
+ });
31
+ const session = (credential) => {
32
+ const inner = definition.session(plain(credential));
33
+ return {
34
+ listTargets: () => call(() => inner.listTargets()),
35
+ resolveTarget: (domain) => call(() => inner.resolveTarget(domain)),
36
+ capabilities: () => call(() => inner.capabilities()),
37
+ dns: (target) => dns(target, inner.dns(target))
38
+ };
39
+ };
40
+ const token = definition.auth.token;
41
+ const oauth = definition.auth.oauth;
42
+ const integration = definition.auth.integration;
43
+ const migrate = definition.migrateContext;
44
+ const oauthRevoke = oauth?.revoke;
45
+ const integrationRefresh = integration?.refresh;
46
+ const integrationRevoke = integration?.revoke;
47
+ return make({
48
+ id: definition.id,
49
+ name: definition.name,
50
+ context: definition.context,
51
+ contextVersion: definition.contextVersion,
52
+ ...migrate === void 0 ? {} : { migrateContext: (envelope) => call(() => migrate(envelope)) },
53
+ auth: {
54
+ ...token === void 0 ? {} : { token: tokenAuth({
55
+ label: token.label,
56
+ ...token.docsUrl === void 0 ? {} : { docsUrl: token.docsUrl },
57
+ requiredCapabilities: token.requiredCapabilities,
58
+ fields: token.fields,
59
+ authenticate: (values) => call(() => token.authenticate(Object.fromEntries(Object.entries(values).map(([name, value]) => [name, Redacted.isRedacted(value) ? String(Redacted.value(value)) : value === void 0 ? void 0 : String(value)])))).pipe(Effect.map(issued))
60
+ }) },
61
+ ...oauth === void 0 ? {} : { oauth: {
62
+ label: oauth.label,
63
+ scopes: oauth.scopes,
64
+ start: (input) => call(() => oauth.start(input)),
65
+ complete: (input) => call(() => oauth.complete(input)).pipe(Effect.map(issued)),
66
+ refresh: (credential) => call(() => oauth.refresh(plain(credential))).pipe(Effect.map(issued)),
67
+ ...oauthRevoke === void 0 ? {} : { revoke: (credential) => call(() => oauthRevoke(plain(credential))) }
68
+ } },
69
+ ...integration === void 0 ? {} : { integration: {
70
+ label: integration.label,
71
+ start: (input) => call(() => integration.start(input)),
72
+ complete: (input) => call(() => integration.complete(input)).pipe(Effect.map(issued)),
73
+ ...integrationRefresh === void 0 ? {} : { refresh: (credential) => call(() => integrationRefresh(plain(credential))).pipe(Effect.map(issued)) },
74
+ ...integrationRevoke === void 0 ? {} : { revoke: (credential) => call(() => integrationRevoke(plain(credential))) }
75
+ } }
76
+ },
77
+ session
78
+ });
79
+ };
80
+ //#endregion
81
+ export { fromAsync };
82
+
83
+ //# sourceMappingURL=provider-async.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider-async.mjs","names":["Errors.isDomainKitError","Errors.DomainKitError","Reason.ProviderUnavailable","Provider.make","Provider.tokenAuth"],"sources":["../../src/internal/provider-async.ts"],"sourcesContent":["import { DateTime, Effect, Redacted, type Schema } from \"effect\";\n\nimport * as Errors from \"./error.ts\";\nimport * as Reason from \"../Reason.ts\";\nimport type * as DnsRecord from \"../DnsRecord.ts\";\nimport * as Provider from \"../Provider.ts\";\nimport type { Capability } from \"../Storage.ts\";\n\n/** Plain-object credential for Promise-shaped providers; `secret` is the raw string. */\nexport interface AsyncCredential {\n readonly secret: string;\n readonly context: unknown;\n}\n\nexport interface AsyncIssuedCredential extends AsyncCredential {\n readonly expiresAt: Date | null;\n}\n\nexport interface AsyncDns {\n readonly list: (zone: string) => Promise<ReadonlyArray<Provider.ObservedRecord>>;\n readonly create: (\n zone: string,\n record: DnsRecord.Model,\n ) => Promise<{ readonly providerRecordId: string }>;\n readonly get: (zone: string, providerRecordId: string) => Promise<DnsRecord.Observed | null>;\n readonly delete: (zone: string, providerRecordId: string) => Promise<void>;\n}\n\nexport interface AsyncSession {\n readonly listTargets: () => Promise<ReadonlyArray<Provider.Target>>;\n readonly resolveTarget: (domain: string) => Promise<Provider.Resolution>;\n readonly dns: (target: Provider.Target) => AsyncDns;\n readonly capabilities: () => Promise<ReadonlyArray<Capability>>;\n}\n\nexport interface AsyncTokenAuth {\n readonly label: string;\n readonly docsUrl?: string;\n readonly requiredCapabilities: ReadonlyArray<Capability>;\n readonly fields: Schema.Struct<Provider.TokenFieldSchemas>;\n /** Decoded field values with secrets unwrapped to strings. */\n readonly authenticate: (\n values: Readonly<Record<string, string | undefined>>,\n ) => Promise<AsyncIssuedCredential>;\n}\n\nexport interface AsyncOAuthAuth {\n readonly label: string;\n readonly scopes: ReadonlyArray<string>;\n readonly start: (input: {\n readonly state: string;\n readonly callbackUrl: string;\n readonly codeChallenge: string;\n }) => Promise<{ readonly authorizationUrl: string }>;\n readonly complete: (\n input: Provider.CallbackInput & { readonly codeVerifier: string },\n ) => Promise<AsyncIssuedCredential>;\n readonly refresh: (credential: AsyncCredential) => Promise<AsyncIssuedCredential>;\n readonly revoke?: (credential: AsyncCredential) => Promise<void>;\n}\n\nexport interface AsyncIntegrationAuth {\n readonly label: string;\n readonly start: (input: {\n readonly state: string;\n readonly callbackUrl: string;\n }) => Promise<{ readonly authorizationUrl: string }>;\n readonly complete: (input: Provider.CallbackInput) => Promise<AsyncIssuedCredential>;\n readonly refresh?: (credential: AsyncCredential) => Promise<AsyncIssuedCredential>;\n readonly revoke?: (credential: AsyncCredential) => Promise<void>;\n}\n\n/** `Provider.Definition` with every operation returning a Promise. */\nexport interface AsyncDefinition<Context = unknown> {\n readonly id: string;\n readonly name: string;\n readonly auth: {\n readonly token?: AsyncTokenAuth;\n readonly oauth?: AsyncOAuthAuth;\n readonly integration?: AsyncIntegrationAuth;\n };\n readonly context: Schema.Codec<Context, unknown, never, never>;\n readonly contextVersion: string;\n readonly migrateContext?: (envelope: Provider.Envelope) => Promise<Context>;\n readonly session: (credential: AsyncCredential) => AsyncSession;\n}\n\nconst failure = (provider: string) => (cause: unknown) =>\n Errors.isDomainKitError(cause)\n ? cause\n : new Errors.DomainKitError({\n reason: new Reason.ProviderUnavailable({\n provider,\n message: cause instanceof Error ? cause.message : `${provider} request failed`,\n }),\n });\n\nconst issued = (value: AsyncIssuedCredential): Provider.IssuedCredential => ({\n secret: Redacted.make(value.secret),\n context: value.context,\n expiresAt: value.expiresAt === null ? null : DateTime.fromDateUnsafe(value.expiresAt),\n});\n\nconst plain = (credential: Provider.Credential): AsyncCredential => ({\n secret: Redacted.value(credential.secret),\n context: credential.context,\n});\n\n/** Adapt a Promise-shaped provider; rejections become `DomainKit.Error` (a thrown one passes through). */\nexport const fromAsync = <Context>(\n definition: AsyncDefinition<Context>,\n): Provider.Definition<Context> => {\n const call = <A>(run: () => Promise<A>): Provider.Fx<A> =>\n Effect.tryPromise({ try: run, catch: failure(definition.id) });\n const dns = (target: Provider.Target, inner: AsyncDns): Provider.Dns => ({\n list: (zone) => call(() => inner.list(zone)),\n create: (zone, record) => call(() => inner.create(zone, record)),\n get: (zone, providerRecordId) => call(() => inner.get(zone, providerRecordId)),\n delete: (zone, providerRecordId) => call(() => inner.delete(zone, providerRecordId)),\n });\n const session = (credential: Provider.Credential): Provider.Session => {\n const inner = definition.session(plain(credential));\n return {\n listTargets: () => call(() => inner.listTargets()),\n resolveTarget: (domain) => call(() => inner.resolveTarget(domain)),\n capabilities: () => call(() => inner.capabilities()),\n dns: (target) => dns(target, inner.dns(target)),\n };\n };\n const token = definition.auth.token;\n const oauth = definition.auth.oauth;\n const integration = definition.auth.integration;\n const migrate = definition.migrateContext;\n const oauthRevoke = oauth?.revoke;\n const integrationRefresh = integration?.refresh;\n const integrationRevoke = integration?.revoke;\n return Provider.make<Context>({\n id: definition.id,\n name: definition.name,\n context: definition.context,\n contextVersion: definition.contextVersion,\n ...(migrate === undefined\n ? {}\n : {\n migrateContext: (envelope: Provider.Envelope) => call(() => migrate(envelope)),\n }),\n auth: {\n ...(token === undefined\n ? {}\n : {\n token: Provider.tokenAuth({\n label: token.label,\n ...(token.docsUrl === undefined ? {} : { docsUrl: token.docsUrl }),\n requiredCapabilities: token.requiredCapabilities,\n fields: token.fields,\n authenticate: (values) =>\n call(() =>\n token.authenticate(\n Object.fromEntries(\n Object.entries(values as Record<string, unknown>).map(([name, value]) => [\n name,\n Redacted.isRedacted(value)\n ? String(Redacted.value(value))\n : value === undefined\n ? undefined\n : String(value),\n ]),\n ),\n ),\n ).pipe(Effect.map(issued)),\n }),\n }),\n ...(oauth === undefined\n ? {}\n : {\n oauth: {\n label: oauth.label,\n scopes: oauth.scopes,\n start: (input) => call(() => oauth.start(input)),\n complete: (input) => call(() => oauth.complete(input)).pipe(Effect.map(issued)),\n refresh: (credential) =>\n call(() => oauth.refresh(plain(credential))).pipe(Effect.map(issued)),\n ...(oauthRevoke === undefined\n ? {}\n : {\n revoke: (credential: Provider.Credential) =>\n call(() => oauthRevoke(plain(credential))),\n }),\n } satisfies Provider.OAuthAuth,\n }),\n ...(integration === undefined\n ? {}\n : {\n integration: {\n label: integration.label,\n start: (input) => call(() => integration.start(input)),\n complete: (input) => call(() => integration.complete(input)).pipe(Effect.map(issued)),\n ...(integrationRefresh === undefined\n ? {}\n : {\n refresh: (credential: Provider.Credential) =>\n call(() => integrationRefresh(plain(credential))).pipe(Effect.map(issued)),\n }),\n ...(integrationRevoke === undefined\n ? {}\n : {\n revoke: (credential: Provider.Credential) =>\n call(() => integrationRevoke(plain(credential))),\n }),\n } satisfies Provider.IntegrationAuth,\n }),\n },\n session,\n });\n};\n"],"mappings":"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"}
@@ -0,0 +1,302 @@
1
+ import { PlanId } from "../Plan.mjs";
2
+ import { Busy, Expired, InvalidInput, NotFound, Stale } from "../Reason.mjs";
3
+ import { fail } from "./error.mjs";
4
+ import { fresh } from "./ids.mjs";
5
+ import { Service } from "../Principal.mjs";
6
+ import { Attachment, Attempt, Authorization, Connection } from "../Storage.mjs";
7
+ import { DateTime, Effect, Option, Semaphore } from "effect";
8
+ //#region src/internal/storage-memory.ts
9
+ const notFound = (entity, id) => fail(new NotFound({
10
+ entity,
11
+ id
12
+ }));
13
+ const invalid = (message, field) => fail(new InvalidInput({
14
+ message,
15
+ ...field === void 0 ? {} : { field }
16
+ }));
17
+ function makeMemory(options = {}) {
18
+ const state = {
19
+ authorizations: /* @__PURE__ */ new Map(),
20
+ credentials: /* @__PURE__ */ new Map(),
21
+ connections: /* @__PURE__ */ new Map(),
22
+ attachments: /* @__PURE__ */ new Map(),
23
+ continuations: /* @__PURE__ */ new Map(),
24
+ attempts: /* @__PURE__ */ new Map(),
25
+ readiness: /* @__PURE__ */ new Map(),
26
+ locks: /* @__PURE__ */ new Set()
27
+ };
28
+ const mutations = Semaphore.makeUnsafe(1);
29
+ const commit = (operation) => options.beforeCommit === void 0 ? Effect.void : options.beforeCommit(operation);
30
+ const read = (run) => Effect.flatMap(Service, run);
31
+ const write = (run) => Effect.flatMap(Service, (principal) => mutations.withPermit(run(principal)));
32
+ const owned = (rows, principal, id) => {
33
+ const row = rows.get(id);
34
+ return row !== void 0 && row.ownerId === principal.ownerId ? row : void 0;
35
+ };
36
+ const ownedRows = (rows, principal) => [...rows.values()].filter((row) => row.ownerId === principal.ownerId);
37
+ const authorization = (principal, id) => Effect.suspend(() => {
38
+ const row = owned(state.authorizations, principal, id);
39
+ return row === void 0 ? notFound("authorization", id) : Effect.succeed(row);
40
+ });
41
+ const connection = (principal, id) => Effect.suspend(() => {
42
+ const row = owned(state.connections, principal, id);
43
+ return row === void 0 ? notFound("connection", id) : Effect.succeed(row);
44
+ });
45
+ const attachment = (principal, id) => Effect.suspend(() => {
46
+ const row = owned(state.attachments, principal, id);
47
+ return row === void 0 ? notFound("attachment", id) : Effect.succeed(row);
48
+ });
49
+ const attempt = (principal, id) => Effect.suspend(() => {
50
+ const row = owned(state.attempts, principal, id);
51
+ return row === void 0 ? notFound("plan", id) : Effect.succeed(row);
52
+ });
53
+ const attemptWhere = (principal, entity, id, predicate) => Effect.suspend(() => {
54
+ const row = ownedRows(state.attempts, principal).find(predicate);
55
+ return row === void 0 ? notFound(entity, id) : Effect.succeed(row);
56
+ });
57
+ const finishRevocation = (principal, row, revoke) => Effect.gen(function* () {
58
+ yield* commit("authorizations.prepareRevocation");
59
+ state.authorizations.set(row.id, new Authorization({
60
+ ...row,
61
+ revocation: "pending"
62
+ }));
63
+ yield* revoke;
64
+ yield* commit("authorizations.completeRevocation");
65
+ if (owned(state.authorizations, principal, row.id) !== void 0) {
66
+ state.authorizations.delete(row.id);
67
+ state.credentials.delete(row.id);
68
+ }
69
+ });
70
+ return {
71
+ authorizations: {
72
+ upsert: ({ authorization: input, credential, expectedId }) => write((principal) => Effect.gen(function* () {
73
+ if (input.ownerId !== principal.ownerId) return yield* invalid("Authorization owner does not match the principal", "ownerId");
74
+ if (expectedId !== void 0) {
75
+ if ((yield* authorization(principal, expectedId)).revocation !== "active") return yield* fail(new Busy({ key: `authorization:${expectedId}` }));
76
+ if (input.id !== expectedId) return yield* invalid("Authorization id must match expectedId", "id");
77
+ } else if (state.authorizations.has(input.id)) return yield* invalid(`Authorization ${input.id} already exists`, "id");
78
+ yield* commit("authorizations.upsert");
79
+ state.authorizations.set(input.id, input);
80
+ state.credentials.set(input.id, credential);
81
+ return input;
82
+ })),
83
+ get: (id) => read((principal) => authorization(principal, id)),
84
+ credential: (id) => read((principal) => authorization(principal, id).pipe(Effect.flatMap(() => {
85
+ const row = state.credentials.get(id);
86
+ return row === void 0 ? notFound("authorization", id) : Effect.succeed(row);
87
+ }))),
88
+ rotate: (id, credential) => write((principal) => Effect.gen(function* () {
89
+ yield* authorization(principal, id);
90
+ yield* commit("authorizations.rotate");
91
+ state.credentials.set(id, credential);
92
+ })),
93
+ promoteCapabilities: (id, capabilities) => write((principal) => Effect.gen(function* () {
94
+ const row = yield* authorization(principal, id);
95
+ yield* commit("authorizations.promoteCapabilities");
96
+ state.authorizations.set(id, new Authorization({
97
+ ...row,
98
+ capabilities: [.../* @__PURE__ */ new Set([...row.capabilities, ...capabilities])]
99
+ }));
100
+ })),
101
+ revoke: (id, revoke) => read((principal) => authorization(principal, id).pipe(Effect.flatMap((row) => finishRevocation(principal, row, revoke)))),
102
+ recoverRevocations: (revoke) => read((principal) => Effect.forEach(ownedRows(state.authorizations, principal).filter((row) => row.revocation === "pending"), (row) => finishRevocation(principal, row, revoke(row))).pipe(Effect.map((finished) => finished.length)))
103
+ },
104
+ connections: {
105
+ create: (authorizationId) => write((principal) => Effect.gen(function* () {
106
+ yield* authorization(principal, authorizationId);
107
+ const row = new Connection({
108
+ id: yield* fresh("conn"),
109
+ ownerId: principal.ownerId,
110
+ authorizationId,
111
+ createdAt: yield* DateTime.now
112
+ });
113
+ yield* commit("connections.create");
114
+ state.connections.set(row.id, row);
115
+ return row;
116
+ })),
117
+ get: (id) => read((principal) => connection(principal, id)),
118
+ list: (filter) => read((principal) => Effect.sync(() => ownedRows(state.connections, principal).filter((row) => filter?.provider === void 0 || state.authorizations.get(row.authorizationId)?.provider === filter.provider))),
119
+ remove: (id) => write((principal) => Effect.gen(function* () {
120
+ yield* connection(principal, id);
121
+ if (ownedRows(state.attachments, principal).some((row) => row.connectionId === id)) return yield* invalid(`Connection ${id} still has attachments`, "connectionId");
122
+ yield* commit("connections.remove");
123
+ state.connections.delete(id);
124
+ }))
125
+ },
126
+ attachments: {
127
+ create: (input) => write((principal) => Effect.gen(function* () {
128
+ yield* connection(principal, input.connectionId);
129
+ if (ownedRows(state.attachments, principal).some((row) => row.domain === input.domain)) return yield* invalid(`${input.domain} is already attached`, "domain");
130
+ const row = new Attachment({
131
+ id: yield* fresh("att"),
132
+ ownerId: principal.ownerId,
133
+ connectionId: input.connectionId,
134
+ domain: input.domain,
135
+ zone: input.zone,
136
+ target: input.target,
137
+ createdAt: yield* DateTime.now
138
+ });
139
+ yield* commit("attachments.create");
140
+ state.attachments.set(row.id, row);
141
+ return row;
142
+ })),
143
+ get: (id) => read((principal) => attachment(principal, id)),
144
+ byDomain: (domain) => read((principal) => Effect.sync(() => Option.fromNullishOr(ownedRows(state.attachments, principal).find((row) => row.domain === domain)))),
145
+ list: (connectionId) => read((principal) => connection(principal, connectionId).pipe(Effect.map(() => ownedRows(state.attachments, principal).filter((row) => row.connectionId === connectionId)))),
146
+ remove: (id) => write((principal) => Effect.gen(function* () {
147
+ yield* attachment(principal, id);
148
+ yield* commit("attachments.remove");
149
+ state.attachments.delete(id);
150
+ }))
151
+ },
152
+ continuations: {
153
+ put: (continuation) => write((principal) => Effect.gen(function* () {
154
+ if (continuation.ownerId !== principal.ownerId) return yield* invalid("Continuation owner does not match the principal", "ownerId");
155
+ yield* commit("continuations.put");
156
+ state.continuations.set(continuation.id, continuation);
157
+ })),
158
+ get: (id) => read((principal) => Effect.gen(function* () {
159
+ const row = owned(state.continuations, principal, id);
160
+ if (row === void 0) return yield* notFound("continuation", id);
161
+ const now = yield* DateTime.now;
162
+ if (DateTime.toEpochMillis(row.expiresAt) <= DateTime.toEpochMillis(now)) return yield* fail(new Expired({
163
+ entity: "continuation",
164
+ id
165
+ }));
166
+ return row;
167
+ })),
168
+ consume: (id) => write((principal) => Effect.gen(function* () {
169
+ const row = owned(state.continuations, principal, id);
170
+ if (row === void 0) return yield* notFound("continuation", id);
171
+ yield* commit("continuations.consume");
172
+ state.continuations.delete(id);
173
+ const now = yield* DateTime.now;
174
+ if (DateTime.toEpochMillis(row.expiresAt) <= DateTime.toEpochMillis(now)) return yield* fail(new Expired({
175
+ entity: "continuation",
176
+ id
177
+ }));
178
+ return row;
179
+ }))
180
+ },
181
+ attempts: {
182
+ create: (input) => write((principal) => Effect.gen(function* () {
183
+ if (input.ownerId !== principal.ownerId) return yield* invalid("Attempt owner does not match the principal", "ownerId");
184
+ if (state.attempts.has(input.id)) return yield* invalid(`Plan ${input.id} already exists`, "id");
185
+ yield* commit("attempts.create");
186
+ state.attempts.set(input.id, input);
187
+ return input;
188
+ })),
189
+ get: (id) => read((principal) => attempt(principal, id)),
190
+ byApproval: (id) => read((principal) => attemptWhere(principal, "approval", id, (row) => row.approval?.id === id)),
191
+ byReceipt: (id) => read((principal) => attemptWhere(principal, "receipt", id, (row) => row.receipt?.id === id)),
192
+ latest: (attachmentId, kind) => read((principal) => Effect.sync(() => Option.fromNullishOr(ownedRows(state.attempts, principal).filter((row) => row.attachmentId === attachmentId && row.kind === kind).reduce((best, row) => best === void 0 || DateTime.toEpochMillis(row.plan.createdAt) >= DateTime.toEpochMillis(best.plan.createdAt) ? row : best, void 0)))),
193
+ approve: (id, approval) => write((principal) => Effect.gen(function* () {
194
+ const row = yield* attempt(principal, id);
195
+ if (row.approval?.id === approval.id) return row;
196
+ if (row.status !== "planned") return yield* stale(row);
197
+ const next = new Attempt({
198
+ ...row,
199
+ status: "approved",
200
+ approval,
201
+ updatedAt: yield* DateTime.now
202
+ });
203
+ yield* commit("attempts.approve");
204
+ state.attempts.set(id, next);
205
+ return next;
206
+ })),
207
+ reject: (id, input) => write((principal) => Effect.gen(function* () {
208
+ const row = yield* attempt(principal, id);
209
+ if (row.status === "rejected") return row;
210
+ if (row.status === "expired") return yield* fail(new Expired({
211
+ entity: "plan",
212
+ id
213
+ }));
214
+ if (row.status !== "planned" || row.plan.digest !== input.digest) return yield* stale(row);
215
+ const now = yield* DateTime.now;
216
+ const next = new Attempt({
217
+ ...row,
218
+ status: "rejected",
219
+ rejection: {
220
+ actorId: input.actorId,
221
+ reason: input.reason,
222
+ at: now
223
+ },
224
+ updatedAt: now
225
+ });
226
+ yield* commit("attempts.reject");
227
+ state.attempts.set(id, next);
228
+ return next;
229
+ })),
230
+ claim: (id, lease) => write((principal) => Effect.gen(function* () {
231
+ const row = yield* attempt(principal, id);
232
+ const now = yield* DateTime.now;
233
+ if (row.status === "applying") {
234
+ if (row.leaseExpiresAt !== null && DateTime.toEpochMillis(row.leaseExpiresAt) > DateTime.toEpochMillis(now)) return yield* fail(new Busy({ key: `apply:${id}` }));
235
+ } else if (row.status !== "approved" && row.status !== "failed") return yield* stale(row);
236
+ const next = new Attempt({
237
+ ...row,
238
+ status: "applying",
239
+ leaseExpiresAt: lease,
240
+ failure: null,
241
+ updatedAt: now
242
+ });
243
+ yield* commit("attempts.claim");
244
+ state.attempts.set(id, next);
245
+ return next;
246
+ })),
247
+ complete: (id, receipt) => write((principal) => Effect.gen(function* () {
248
+ const row = yield* attempt(principal, id);
249
+ if (row.status !== "applying") return yield* stale(row);
250
+ const next = new Attempt({
251
+ ...row,
252
+ status: receipt.status,
253
+ receipt,
254
+ leaseExpiresAt: null,
255
+ updatedAt: yield* DateTime.now
256
+ });
257
+ yield* commit("attempts.complete");
258
+ state.attempts.set(id, next);
259
+ return next;
260
+ })),
261
+ fail: (id, message) => write((principal) => Effect.gen(function* () {
262
+ const row = yield* attempt(principal, id);
263
+ if (row.status !== "applying") return yield* stale(row);
264
+ const next = new Attempt({
265
+ ...row,
266
+ status: "failed",
267
+ failure: message,
268
+ leaseExpiresAt: null,
269
+ updatedAt: yield* DateTime.now
270
+ });
271
+ yield* commit("attempts.fail");
272
+ state.attempts.set(id, next);
273
+ return next;
274
+ }))
275
+ },
276
+ readiness: {
277
+ put: (readiness) => write((principal) => Effect.gen(function* () {
278
+ if (readiness.ownerId !== principal.ownerId) return yield* invalid("Readiness owner does not match the principal", "ownerId");
279
+ if (readiness.attachmentId !== null) yield* attachment(principal, readiness.attachmentId);
280
+ yield* commit("readiness.put");
281
+ state.readiness.set(`${principal.ownerId}:${readiness.domain}`, readiness);
282
+ })),
283
+ get: (domain) => read((principal) => Effect.sync(() => Option.fromNullishOr(state.readiness.get(`${principal.ownerId}:${domain}`))))
284
+ },
285
+ withLock: (key, effect) => Effect.flatMap(Service, (principal) => {
286
+ const scoped = `${principal.ownerId}:${key}`;
287
+ return Effect.acquireRelease(Effect.suspend(() => {
288
+ if (state.locks.has(scoped)) return fail(new Busy({ key }));
289
+ state.locks.add(scoped);
290
+ return Effect.void;
291
+ }), () => Effect.sync(() => void state.locks.delete(scoped))).pipe(Effect.flatMap(() => effect), Effect.scoped);
292
+ })
293
+ };
294
+ }
295
+ const stale = (row) => fail(new Stale({
296
+ planId: PlanId.make(row.id),
297
+ digest: row.plan.digest
298
+ }));
299
+ //#endregion
300
+ export { makeMemory };
301
+
302
+ //# sourceMappingURL=storage-memory.mjs.map
@@ -0,0 +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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"}
@@ -0,0 +1,122 @@
1
+ import { isWithin } from "../../DomainName.mjs";
2
+ import { NotFound } from "../../Reason.mjs";
3
+ import { decode, fail } from "../error.mjs";
4
+ import { bearer, classify, rejected, requestJson } from "../http.mjs";
5
+ import { CreateRecordEnvelope, DomainListEnvelope, ErrorEnvelope, IntegrationToken, RecordListEnvelope, TeamListEnvelope, UserEnvelope } from "./protocol.mjs";
6
+ import { decode as decode$1, encode, outsideZone } from "./records.mjs";
7
+ import { Effect, Schema } from "effect";
8
+ //#region src/internal/vercel/client.ts
9
+ const provider = "vercel";
10
+ const url = (options, path, teamId, values = {}) => {
11
+ const target = new URL(`${options.baseUrl}${path}`);
12
+ for (const [key, value] of Object.entries(values)) target.searchParams.set(key, value);
13
+ if (teamId !== null) target.searchParams.set("teamId", teamId);
14
+ return target;
15
+ };
16
+ const call = (options, target, result, init) => Effect.gen(function* () {
17
+ const reply = yield* requestJson({
18
+ fetch: options.fetch,
19
+ provider,
20
+ url: target,
21
+ init: bearer(options.token, init)
22
+ });
23
+ if (!reply.ok) {
24
+ const detail = Schema.decodeUnknownOption(ErrorEnvelope)(reply.body);
25
+ const message = detail._tag === "Some" ? detail.value.error.message : `Vercel request failed with HTTP ${reply.status}`;
26
+ if (reply.status === 404 || detail._tag === "Some" && detail.value.error.code === "not_found") return yield* fail(new NotFound({
27
+ entity: "zone",
28
+ id: decodeURIComponent(target.pathname)
29
+ }));
30
+ const code = detail._tag === "Some" ? detail.value.error.code : void 0;
31
+ const headers = new Headers(reply.headers);
32
+ const resetMs = detail._tag === "Some" ? detail.value.error.limit?.resetMs : void 0;
33
+ if (resetMs !== void 0 && !headers.has("retry-after")) headers.set("retry-after", String(Math.max(0, Math.ceil((resetMs - Date.now()) / 1e3))));
34
+ return yield* fail(classify(provider, code === "rate_limited" ? 429 : reply.status, headers, message, code));
35
+ }
36
+ return yield* decode(result, reply.body).pipe(Effect.mapError(() => rejected(provider, "Vercel response did not match its API contract", "response")));
37
+ });
38
+ const user = (options) => call(options, url(options, "/v2/user", null), UserEnvelope).pipe(Effect.map((envelope) => envelope.user));
39
+ const teams = (options) => Effect.gen(function* () {
40
+ const rows = [];
41
+ let until = null;
42
+ while (true) {
43
+ const values = { limit: "100" };
44
+ if (until !== null) values.until = String(until);
45
+ const envelope = yield* call(options, url(options, "/v2/teams", null, values), TeamListEnvelope);
46
+ rows.push(...envelope.teams);
47
+ if (envelope.pagination.next === null) return rows;
48
+ until = envelope.pagination.next;
49
+ }
50
+ });
51
+ /** Domains with Vercel-hosted DNS for one account (`teamId` null means the personal account). */
52
+ const zones = (options, teamId) => Effect.gen(function* () {
53
+ const rows = [];
54
+ let until = null;
55
+ while (true) {
56
+ const values = { limit: "100" };
57
+ if (until !== null) values.until = String(until);
58
+ const envelope = yield* call(options, url(options, "/v5/domains", teamId, values), DomainListEnvelope);
59
+ rows.push(...envelope.domains);
60
+ if (envelope.pagination.next === null) return rows.filter(hasDnsStorage);
61
+ until = envelope.pagination.next;
62
+ }
63
+ });
64
+ const exchangeCode = (input) => Effect.gen(function* () {
65
+ const body = new URLSearchParams({
66
+ client_id: input.clientId,
67
+ client_secret: input.clientSecret,
68
+ code: input.code,
69
+ redirect_uri: input.callbackUrl
70
+ });
71
+ const reply = yield* requestJson({
72
+ fetch: input.options.fetch,
73
+ provider,
74
+ url: `${input.options.baseUrl}/v2/oauth/access_token`,
75
+ init: {
76
+ method: "POST",
77
+ body,
78
+ headers: {
79
+ Accept: "application/json",
80
+ "Content-Type": "application/x-www-form-urlencoded"
81
+ }
82
+ }
83
+ });
84
+ if (!reply.ok) {
85
+ const detail = Schema.decodeUnknownOption(ErrorEnvelope)(reply.body);
86
+ return yield* fail(classify(provider, reply.status, reply.headers, detail._tag === "Some" ? detail.value.error.message : `Vercel token exchange failed with HTTP ${reply.status}`, detail._tag === "Some" ? detail.value.error.code : void 0));
87
+ }
88
+ return yield* decode(IntegrationToken, reply.body).pipe(Effect.mapError(() => rejected(provider, "Vercel token response did not match its API contract", "response")));
89
+ });
90
+ const listRecords = (options, teamId, zone) => Effect.gen(function* () {
91
+ const rows = [];
92
+ let until = null;
93
+ while (true) {
94
+ const values = { limit: "100" };
95
+ if (until !== null) values.until = String(until);
96
+ const envelope = yield* call(options, url(options, `/v5/domains/${encodeURIComponent(zone)}/records`, teamId, values), RecordListEnvelope);
97
+ rows.push(...yield* Effect.forEach(envelope.records, (record) => decode$1(zone, record)));
98
+ const next = envelope.pagination?.next ?? null;
99
+ if (next === null) return rows;
100
+ until = next;
101
+ }
102
+ });
103
+ const dns = (options, teamId) => ({
104
+ list: (zone) => listRecords(options, teamId, zone),
105
+ create: (zone, record) => Effect.gen(function* () {
106
+ if (!isWithin(record.name, zone)) return yield* outsideZone(zone, record.name);
107
+ const body = yield* encode(zone, record);
108
+ return { providerRecordId: (yield* call(options, url(options, `/v2/domains/${encodeURIComponent(zone)}/records`, teamId), CreateRecordEnvelope, {
109
+ method: "POST",
110
+ body: JSON.stringify(body)
111
+ })).uid };
112
+ }),
113
+ get: (zone, providerRecordId) => listRecords(options, teamId, zone).pipe(Effect.map((records) => records.find((row) => row.providerRecordId === providerRecordId)?.record ?? null)),
114
+ delete: (zone, providerRecordId) => call(options, url(options, `/v2/domains/${encodeURIComponent(zone)}/records/${encodeURIComponent(providerRecordId)}`, teamId), Schema.Unknown, { method: "DELETE" }).pipe(Effect.asVoid)
115
+ });
116
+ function hasDnsStorage(domain) {
117
+ return domain.serviceType === "zeit.world" || domain.zone === true || domain.intendedNameservers.length > 0;
118
+ }
119
+ //#endregion
120
+ export { dns, exchangeCode, provider, teams, user, zones };
121
+
122
+ //# sourceMappingURL=client.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.mjs","names":["S","Protocol.ErrorEnvelope","Errors.fail","Reason.NotFound","Errors.decode","Protocol.UserEnvelope","Protocol.TeamListEnvelope","Protocol.DomainListEnvelope","Protocol.IntegrationToken","Protocol.RecordListEnvelope","Records.decode","DomainName.isWithin","Records.outsideZone","Records.encode","Protocol.CreateRecordEnvelope"],"sources":["../../../src/internal/vercel/client.ts"],"sourcesContent":["import { Effect, Schema as S } from \"effect\";\n\nimport * as Errors from \"../error.ts\";\nimport * as Reason from \"../../Reason.ts\";\nimport * as DomainName from \"../../DomainName.ts\";\nimport type * as Provider from \"../../Provider.ts\";\nimport { bearer, classify, type Fetch, rejected, requestJson } from \"../http.ts\";\nimport * as Protocol from \"./protocol.ts\";\nimport * as Records from \"./records.ts\";\n\nexport const provider = \"vercel\";\n\nexport interface Options {\n readonly token: string;\n readonly fetch: Fetch;\n readonly baseUrl: string;\n}\n\ntype Fx<A> = Effect.Effect<A, Errors.DomainKitError>;\n\nconst url = (\n options: Options,\n path: string,\n teamId: string | null,\n values: Record<string, string> = {},\n) => {\n const target = new URL(`${options.baseUrl}${path}`);\n for (const [key, value] of Object.entries(values)) target.searchParams.set(key, value);\n if (teamId !== null) target.searchParams.set(\"teamId\", teamId);\n return target;\n};\n\nconst call = <R extends S.ConstraintDecoder<unknown>>(\n options: Options,\n target: URL,\n result: R,\n init?: RequestInit,\n): Fx<R[\"Type\"]> =>\n Effect.gen(function* () {\n const reply = yield* requestJson({\n fetch: options.fetch,\n provider,\n url: target,\n init: bearer(options.token, init),\n });\n if (!reply.ok) {\n const detail = S.decodeUnknownOption(Protocol.ErrorEnvelope)(reply.body);\n const message =\n detail._tag === \"Some\"\n ? detail.value.error.message\n : `Vercel request failed with HTTP ${reply.status}`;\n if (\n reply.status === 404 ||\n (detail._tag === \"Some\" && detail.value.error.code === \"not_found\")\n ) {\n return yield* Errors.fail(\n new Reason.NotFound({ entity: \"zone\", id: decodeURIComponent(target.pathname) }),\n );\n }\n const code = detail._tag === \"Some\" ? detail.value.error.code : undefined;\n const headers = new Headers(reply.headers);\n const resetMs = detail._tag === \"Some\" ? detail.value.error.limit?.resetMs : undefined;\n if (resetMs !== undefined && !headers.has(\"retry-after\")) {\n headers.set(\"retry-after\", String(Math.max(0, Math.ceil((resetMs - Date.now()) / 1_000))));\n }\n return yield* Errors.fail(\n classify(provider, code === \"rate_limited\" ? 429 : reply.status, headers, message, code),\n );\n }\n return yield* Errors.decode(result, reply.body).pipe(\n Effect.mapError(() =>\n rejected(provider, \"Vercel response did not match its API contract\", \"response\"),\n ),\n );\n });\n\nexport const user = (options: Options) =>\n call(options, url(options, \"/v2/user\", null), Protocol.UserEnvelope).pipe(\n Effect.map((envelope) => envelope.user),\n );\n\nexport const teams = (options: Options): Fx<ReadonlyArray<typeof Protocol.Team.Type>> =>\n Effect.gen(function* () {\n const rows: Array<typeof Protocol.Team.Type> = [];\n let until: number | null = null;\n while (true) {\n const values: Record<string, string> = { limit: \"100\" };\n if (until !== null) values.until = String(until);\n const envelope = yield* call(\n options,\n url(options, \"/v2/teams\", null, values),\n Protocol.TeamListEnvelope,\n );\n rows.push(...envelope.teams);\n if (envelope.pagination.next === null) return rows;\n until = envelope.pagination.next;\n }\n });\n\n/** Domains with Vercel-hosted DNS for one account (`teamId` null means the personal account). */\nexport const zones = (\n options: Options,\n teamId: string | null,\n): Fx<ReadonlyArray<Protocol.Domain>> =>\n Effect.gen(function* () {\n const rows: Array<Protocol.Domain> = [];\n let until: number | null = null;\n while (true) {\n const values: Record<string, string> = { limit: \"100\" };\n if (until !== null) values.until = String(until);\n const envelope = yield* call(\n options,\n url(options, \"/v5/domains\", teamId, values),\n Protocol.DomainListEnvelope,\n );\n rows.push(...envelope.domains);\n if (envelope.pagination.next === null) return rows.filter(hasDnsStorage);\n until = envelope.pagination.next;\n }\n });\n\nexport const exchangeCode = (input: {\n readonly options: Options;\n readonly clientId: string;\n readonly clientSecret: string;\n readonly code: string;\n readonly callbackUrl: string;\n}): Fx<typeof Protocol.IntegrationToken.Type> =>\n Effect.gen(function* () {\n const body = new URLSearchParams({\n client_id: input.clientId,\n client_secret: input.clientSecret,\n code: input.code,\n redirect_uri: input.callbackUrl,\n });\n const reply = yield* requestJson({\n fetch: input.options.fetch,\n provider,\n url: `${input.options.baseUrl}/v2/oauth/access_token`,\n init: {\n method: \"POST\",\n body,\n headers: {\n Accept: \"application/json\",\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n },\n },\n });\n if (!reply.ok) {\n const detail = S.decodeUnknownOption(Protocol.ErrorEnvelope)(reply.body);\n return yield* Errors.fail(\n classify(\n provider,\n reply.status,\n reply.headers,\n detail._tag === \"Some\"\n ? detail.value.error.message\n : `Vercel token exchange failed with HTTP ${reply.status}`,\n detail._tag === \"Some\" ? detail.value.error.code : undefined,\n ),\n );\n }\n return yield* Errors.decode(Protocol.IntegrationToken, reply.body).pipe(\n Effect.mapError(() =>\n rejected(provider, \"Vercel token response did not match its API contract\", \"response\"),\n ),\n );\n });\n\nconst listRecords = (\n options: Options,\n teamId: string | null,\n zone: string,\n): Fx<ReadonlyArray<Provider.ObservedRecord>> =>\n Effect.gen(function* () {\n const rows: Array<Provider.ObservedRecord> = [];\n let until: number | null = null;\n while (true) {\n const values: Record<string, string> = { limit: \"100\" };\n if (until !== null) values.until = String(until);\n const envelope = yield* call(\n options,\n url(options, `/v5/domains/${encodeURIComponent(zone)}/records`, teamId, values),\n Protocol.RecordListEnvelope,\n );\n rows.push(\n ...(yield* Effect.forEach(envelope.records, (record) => Records.decode(zone, record))),\n );\n const next = envelope.pagination?.next ?? null;\n if (next === null) return rows;\n until = next;\n }\n });\n\nexport const dns = (options: Options, teamId: string | null): Provider.Dns => ({\n list: (zone) => listRecords(options, teamId, zone),\n create: (zone, record) =>\n Effect.gen(function* () {\n if (!DomainName.isWithin(record.name, zone))\n return yield* Records.outsideZone(zone, record.name);\n const body = yield* Records.encode(zone, record);\n const created = yield* call(\n options,\n url(options, `/v2/domains/${encodeURIComponent(zone)}/records`, teamId),\n Protocol.CreateRecordEnvelope,\n { method: \"POST\", body: JSON.stringify(body) },\n );\n return { providerRecordId: created.uid };\n }),\n get: (zone, providerRecordId) =>\n listRecords(options, teamId, zone).pipe(\n Effect.map(\n (records) =>\n records.find((row) => row.providerRecordId === providerRecordId)?.record ?? null,\n ),\n ),\n delete: (zone, providerRecordId) =>\n call(\n options,\n url(\n options,\n `/v2/domains/${encodeURIComponent(zone)}/records/${encodeURIComponent(providerRecordId)}`,\n teamId,\n ),\n S.Unknown,\n { method: \"DELETE\" },\n ).pipe(Effect.asVoid),\n});\n\nfunction hasDnsStorage(domain: Protocol.Domain): boolean {\n return (\n domain.serviceType === \"zeit.world\" ||\n domain.zone === true ||\n domain.intendedNameservers.length > 0\n );\n}\n"],"mappings":"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"}