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
@@ -1,2396 +0,0 @@
1
- import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
- import { A as Error$1, D as decode$5, E as Schema$2, b as assertAttachment, c as Evidence$1, d as codec, k as parse$1, p as AuthorizationError, s as Service$1, x as authorizationError } from "./canonical-json-CQYKsZw7.mjs";
3
- import { n as Method$1, t as Error$2 } from "./connect-oI8hcMxc.mjs";
4
- import { C as authorize$1, I as Error$3, L as Service$3, R as fromAsync$1, V as toAsync$4, Y as Opaque, i as Service$2, it as equals, n as Error$4, nt as decode$6, o as toAsync$5, r as Resolution$1, tt as data, ut as candidates } from "./resolver-DPJs8h0a.mjs";
5
- import { Clock, Context, Crypto, Data, Effect, Layer, Option, Schema, SchemaIssue, SchemaTransformation } from "effect";
6
- import * as oauth from "oauth4webapi";
7
- import * as DnsPacket from "@leichtgewicht/dns-packet";
8
- //#region package.json
9
- var version = "0.7.0";
10
- //#endregion
11
- //#region src/auth/diagnostic.ts
12
- var diagnostic_exports = /* @__PURE__ */ __exportAll({
13
- Category: () => Category,
14
- Fields: () => Fields,
15
- RetryAdvice: () => RetryAdvice,
16
- from: () => from
17
- });
18
- const Category = Schema.Literals([
19
- "authorization",
20
- "configuration",
21
- "provider",
22
- "storage",
23
- "validation"
24
- ]);
25
- const RetryAdvice = Schema.Literals([
26
- "never",
27
- "after-user-action",
28
- "safe",
29
- "unknown"
30
- ]);
31
- const Fields = {
32
- category: Category,
33
- message: Schema.String,
34
- operation: Schema.String,
35
- retry: RetryAdvice
36
- };
37
- function from(error) {
38
- return {
39
- category: error.category,
40
- message: error.message,
41
- operation: error.operation,
42
- retry: error.retry,
43
- tag: error._tag
44
- };
45
- }
46
- //#endregion
47
- //#region src/auth/manifest.ts
48
- var manifest_exports = /* @__PURE__ */ __exportAll({
49
- Method: () => Method,
50
- Schema: () => Schema$1,
51
- decode: () => decode$4
52
- });
53
- const Method = Schema.TaggedUnion({
54
- integration: {
55
- capabilities: Schema.Array(Schema.Literals(["dns:read", "dns:write"])),
56
- installUrl: Schema.String,
57
- tokenEndpoint: Schema.String
58
- },
59
- oauth2: {
60
- authorizationServer: Schema.Struct({
61
- authorization_endpoint: Schema.String,
62
- issuer: Schema.String,
63
- revocation_endpoint: Schema.optionalKey(Schema.String),
64
- token_endpoint: Schema.String
65
- }),
66
- capabilities: Schema.Array(Schema.Literals(["dns:read", "dns:write"])),
67
- clientAuth: Schema.Literals([
68
- "none",
69
- "client_secret_basic",
70
- "client_secret_post"
71
- ]),
72
- scopes: Schema.Array(Schema.String)
73
- },
74
- token: {
75
- capabilities: Schema.Array(Schema.Literals(["dns:read", "dns:write"])),
76
- instructionsUrl: Schema.String
77
- }
78
- });
79
- const Schema$1 = Schema.Struct({
80
- methods: Schema.Array(Method),
81
- providerId: Schema.String
82
- });
83
- const decode$4 = Effect.fn("ProviderAuth.decode")((input) => Schema.decodeUnknownEffect(Schema$1)(input).pipe(Effect.mapError((cause) => new Error$1({ message: cause.message }))));
84
- //#endregion
85
- //#region src/auth/secret.ts
86
- var secret_exports = /* @__PURE__ */ __exportAll({
87
- Value: () => Value,
88
- make: () => make$6
89
- });
90
- /** A deliberately non-serializable credential value. */
91
- var Value = class Value {
92
- #value;
93
- constructor(value) {
94
- this.#value = value;
95
- }
96
- static from(value) {
97
- if (value.length === 0) throw new Error("Secret values cannot be empty");
98
- return new Value(value);
99
- }
100
- expose() {
101
- return this.#value;
102
- }
103
- toJSON() {
104
- return "[REDACTED]";
105
- }
106
- toString() {
107
- return "[REDACTED]";
108
- }
109
- };
110
- const make$6 = Value.from;
111
- //#endregion
112
- //#region src/discovery/selection.ts
113
- var selection_exports = /* @__PURE__ */ __exportAll({
114
- Evidence: () => Evidence,
115
- Selection: () => Selection,
116
- select: () => select
117
- });
118
- const Evidence = Schema.Struct({
119
- accountId: Schema.String,
120
- connectionId: Schema.String,
121
- decisiveNameserverMatch: Schema.Boolean,
122
- matchedNameservers: Schema.Array(Schema$2),
123
- providerId: Schema.String,
124
- zone: Schema$2
125
- });
126
- const Selection = Schema.TaggedUnion({
127
- selected: {
128
- candidate: Evidence,
129
- evidence: Schema.Array(Evidence),
130
- reason: Schema.Literals(["explicit", "unique-nameserver-match"])
131
- },
132
- manual: {
133
- evidence: Schema.Array(Evidence),
134
- reason: Schema.Literals(["ambiguous", "unsupported"])
135
- }
136
- });
137
- function select(input) {
138
- const domain = parse$1(input.domain);
139
- const zoneCandidates = new Set(candidates(domain));
140
- const authoritative = nameserverSet(input.authoritativeNameservers);
141
- const eligible = input.connectedZones.filter((connected) => {
142
- if (!zoneCandidates.has(connected.attachment.target.zoneName)) return false;
143
- try {
144
- assertAttachment({
145
- attachment: connected.attachment,
146
- capability: "dns:read",
147
- connection: connected.connection,
148
- domain,
149
- ...input.now === void 0 ? {} : { now: input.now },
150
- providerId: connected.connection.providerId,
151
- authorization: connected.authorization
152
- });
153
- return true;
154
- } catch {
155
- return false;
156
- }
157
- });
158
- const evidence = eligible.map((connected) => evidenceFor(connected, authoritative));
159
- if (input.explicit !== void 0) {
160
- const explicitZone = parse$1(input.explicit.zone);
161
- const index = eligible.findIndex((connected) => connected.connection.providerId === input.explicit?.providerId && connected.attachment.target.accountId === input.explicit.accountId && connected.attachment.target.zoneName === explicitZone);
162
- if (index < 0) throw authorizationError("Explicit provider zone is not connected for this domain", "ProviderDiscovery.select");
163
- const candidate = evidence[index];
164
- if (candidate === void 0) throw new Error("Eligible provider evidence is missing");
165
- return {
166
- _tag: "selected",
167
- candidate,
168
- evidence,
169
- reason: "explicit"
170
- };
171
- }
172
- const decisive = evidence.filter(({ decisiveNameserverMatch }) => decisiveNameserverMatch);
173
- const candidate = decisive[0];
174
- return decisive.length === 1 && candidate !== void 0 ? {
175
- _tag: "selected",
176
- candidate,
177
- evidence,
178
- reason: "unique-nameserver-match"
179
- } : {
180
- _tag: "manual",
181
- evidence,
182
- reason: decisive.length > 1 ? "ambiguous" : "unsupported"
183
- };
184
- }
185
- function evidenceFor(connected, authoritative) {
186
- const configured = new Set(nameserverSet(connected.nameservers));
187
- const matchedNameservers = authoritative.filter((nameserver) => configured.has(nameserver));
188
- return {
189
- accountId: connected.attachment.target.accountId,
190
- connectionId: connected.connection.id,
191
- decisiveNameserverMatch: authoritative.length > 0 && matchedNameservers.length === authoritative.length,
192
- matchedNameservers,
193
- providerId: connected.connection.providerId,
194
- zone: connected.attachment.target.zoneName
195
- };
196
- }
197
- function nameserverSet(nameservers) {
198
- return [...new Set(nameservers.map(parse$1))].sort();
199
- }
200
- //#endregion
201
- //#region src/provider/session.ts
202
- var session_exports = /* @__PURE__ */ __exportAll({
203
- Resolution: () => Resolution,
204
- fromAsync: () => fromAsync,
205
- toAsync: () => toAsync$3
206
- });
207
- const Resolution = Data.taggedEnum();
208
- /** Adapts a Promise-shaped session to the Effect-native session boundary. */
209
- const fromAsync = (session) => ({
210
- providerId: session.providerId,
211
- listTargets: (input) => Effect.tryPromise({
212
- try: () => session.listTargets(input),
213
- catch: (cause) => sessionFailure(session.providerId, "listTargets", cause)
214
- }),
215
- resolveTarget: (domain) => Effect.tryPromise({
216
- try: () => session.resolveTarget(domain),
217
- catch: (cause) => sessionFailure(session.providerId, "resolveTarget", cause)
218
- }),
219
- forTarget: (target) => Effect.tryPromise({
220
- try: () => session.forTarget(target),
221
- catch: (cause) => sessionFailure(session.providerId, "forTarget", cause)
222
- }).pipe(Effect.map(fromAsync$1))
223
- });
224
- /** Adapts an Effect-native session to the Promise facade. */
225
- const toAsync$3 = (session) => ({
226
- providerId: session.providerId,
227
- listTargets: (input) => Effect.runPromise(session.listTargets(input)),
228
- resolveTarget: (domain) => Effect.runPromise(session.resolveTarget(domain)),
229
- forTarget: (target) => Effect.runPromise(session.forTarget(target)).then(toAsync$4)
230
- });
231
- function sessionFailure(providerId, operation, cause) {
232
- return cause instanceof Error$3 ? cause : new Error$3({
233
- message: cause instanceof globalThis.Error ? cause.message : String(cause),
234
- operation: `ProviderSession.${operation}`,
235
- providerId,
236
- reason: "transport"
237
- });
238
- }
239
- //#endregion
240
- //#region src/plan/connection-authorization.ts
241
- var connection_authorization_exports = /* @__PURE__ */ __exportAll({ authorize: () => authorize });
242
- const authorize = Effect.fn("ConnectionAuthorization.authorize")(function* (input) {
243
- const aggregate = yield* (yield* Service$1).getByConnectionId(input.connection.id);
244
- const storedConnection = aggregate?.connections.find(({ id }) => id === input.connection.id);
245
- const storedAttachment = aggregate?.attachments.find(({ id }) => id === input.attachment.id);
246
- if (aggregate === null || storedConnection === void 0 || storedAttachment === void 0 || storedConnection.ownerId !== input.connection.ownerId || storedConnection.providerId !== input.connection.providerId || storedConnection.method !== aggregate.authorization.method || storedConnection.authorizationId !== input.authorization.id || storedAttachment.connectionId !== storedConnection.id) return yield* authorizationError("Domain attachment is not owned by the active provider connection", "ConnectionAuthorization.authorize");
247
- const domain = yield* Effect.try({
248
- try: () => assertAttachment({
249
- attachment: storedAttachment,
250
- capability: "dns:write",
251
- authorization: aggregate.authorization,
252
- connection: storedConnection,
253
- credential: aggregate.credential,
254
- domain: input.domain,
255
- providerId: input.plan.providerId
256
- }),
257
- catch: (cause) => cause instanceof AuthorizationError || cause instanceof Error$1 ? cause : authorizationError("Domain attachment is invalid", "ConnectionAuthorization.authorize")
258
- });
259
- const authorization = yield* authorize$1(input.plan, input.operationIds, input.allowPartial === void 0 ? {} : { allowPartial: input.allowPartial });
260
- const selected = new Set(authorization.operationIds);
261
- if (input.plan.operations.filter((operation) => operation._tag === "create" && selected.has(operation.id) && operation.requirement.name !== domain && !operation.requirement.name.endsWith(`.${domain}`)).length > 0) return yield* authorizationError(`Plan operations are outside the attached domain ${domain}`, "ConnectionAuthorization.authorize");
262
- return authorization;
263
- });
264
- //#endregion
265
- //#region src/auth/authorization-code.ts
266
- const start = Effect.fn("AuthorizationCode.start")(function* (input) {
267
- const crypto = yield* Crypto.Crypto;
268
- const codeVerifier = base64Url(yield* randomBytes(crypto, 32));
269
- const challenge = base64Url(yield* digest(crypto, codeVerifier));
270
- const authorizationUrl = new URL(input.method.authorizationServer.authorization_endpoint);
271
- authorizationUrl.search = new URLSearchParams({
272
- client_id: input.client.clientId,
273
- code_challenge: challenge,
274
- code_challenge_method: "S256",
275
- redirect_uri: input.redirectUri,
276
- response_type: "code",
277
- scope: input.method.scopes.join(" "),
278
- state: input.state
279
- }).toString();
280
- return {
281
- authorizationUrl,
282
- payload: make$6(JSON.stringify({
283
- codeVerifier,
284
- redirectUri: input.redirectUri,
285
- state: input.state
286
- }))
287
- };
288
- });
289
- const complete = Effect.fn("AuthorizationCode.complete")(function* (input) {
290
- const payload = yield* decodePayload(input.payload);
291
- if (input.callbackUrl.searchParams.get("state") !== payload.state) return yield* failure$6("Authorization callback state does not match its continuation");
292
- const server = input.method.authorizationServer;
293
- const client = { client_id: input.client.clientId };
294
- const authentication = yield* clientAuthentication$1(input.method, input.client);
295
- return yield* Effect.tryPromise({
296
- try: async (signal) => {
297
- const callback = oauth.validateAuthResponse(server, client, input.callbackUrl, payload.state);
298
- const response = await oauth.authorizationCodeGrantRequest(server, client, authentication, callback, payload.redirectUri, payload.codeVerifier, requestOptions(input.fetch, signal));
299
- return oauth.processAuthorizationCodeResponse(server, client, response);
300
- },
301
- catch: (cause) => new Error$2({
302
- category: "provider",
303
- message: cause instanceof globalThis.Error ? cause.name : "OAuth provider request failed",
304
- operation: "AuthorizationCode.complete",
305
- retry: "unknown"
306
- })
307
- });
308
- });
309
- const PayloadSchema = Schema.Struct({
310
- codeVerifier: Schema.String,
311
- redirectUri: Schema.String,
312
- state: Schema.String
313
- });
314
- function decodePayload(payload) {
315
- return Schema.decodeUnknownEffect(Schema.fromJsonString(PayloadSchema))(payload.expose()).pipe(Effect.mapError(() => new Error$2({
316
- category: "authorization",
317
- message: "OAuth continuation payload is invalid",
318
- operation: "AuthorizationCode",
319
- retry: "after-user-action"
320
- })));
321
- }
322
- function clientAuthentication$1(method, client) {
323
- switch (method.clientAuth) {
324
- case "none": return Effect.succeed(oauth.None());
325
- case "client_secret_basic": return client.clientSecret === void 0 ? failure$6("OAuth client secret is required") : Effect.succeed(oauth.ClientSecretBasic(client.clientSecret.expose()));
326
- case "client_secret_post": return client.clientSecret === void 0 ? failure$6("OAuth client secret is required") : Effect.succeed(oauth.ClientSecretPost(client.clientSecret.expose()));
327
- }
328
- }
329
- function requestOptions(fetchImplementation, signal) {
330
- return fetchImplementation === void 0 ? { signal } : {
331
- signal,
332
- [oauth.customFetch]: (url, options) => fetchImplementation(url, {
333
- ...options,
334
- body: options.body
335
- })
336
- };
337
- }
338
- const failure$6 = (message) => Effect.fail(new Error$2({
339
- category: "authorization",
340
- message,
341
- operation: "AuthorizationCode",
342
- retry: "after-user-action"
343
- }));
344
- function randomBytes(crypto, size) {
345
- return crypto.randomBytes(size).pipe(Effect.mapError((cause) => new Error$2({
346
- category: "validation",
347
- message: cause.message,
348
- operation: "AuthorizationCode.start",
349
- retry: "safe"
350
- })));
351
- }
352
- function digest(crypto, value) {
353
- return crypto.digest("SHA-256", new TextEncoder().encode(value)).pipe(Effect.mapError((cause) => new Error$2({
354
- category: "validation",
355
- message: cause.message,
356
- operation: "AuthorizationCode.start",
357
- retry: "safe"
358
- })));
359
- }
360
- function base64Url(bytes) {
361
- let binary = "";
362
- for (const byte of bytes) binary += String.fromCharCode(byte);
363
- return btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replaceAll("=", "");
364
- }
365
- //#endregion
366
- //#region src/providers/cloudflare/protocol.ts
367
- const ErrorDetail$1 = Schema.Struct({
368
- code: Schema.Number,
369
- message: Schema.String
370
- });
371
- const ResultInfo = Schema.Struct({
372
- count: Schema.optionalKey(Schema.Number),
373
- page: Schema.optionalKey(Schema.Number),
374
- per_page: Schema.optionalKey(Schema.Number),
375
- total_count: Schema.optionalKey(Schema.Number),
376
- total_pages: Schema.optionalKey(Schema.Number)
377
- });
378
- const Message = Schema.Struct({
379
- code: Schema.optionalKey(Schema.Number),
380
- message: Schema.String
381
- });
382
- const BaseEnvelope = Schema.Struct({
383
- errors: Schema.Array(ErrorDetail$1),
384
- messages: Schema.Array(Message),
385
- success: Schema.Boolean
386
- });
387
- const Account = Schema.Struct({
388
- id: Schema.String,
389
- name: Schema.String
390
- });
391
- const Zone = Schema.Struct({
392
- account: Account,
393
- id: Schema.String,
394
- name: Schema.String,
395
- name_servers: Schema.Array(Schema.String),
396
- status: Schema.optionalKey(Schema.String),
397
- type: Schema.optionalKey(Schema.Literals([
398
- "full",
399
- "partial",
400
- "secondary",
401
- "internal"
402
- ]))
403
- });
404
- const Record$1 = Schema.Struct({
405
- content: Schema.optionalKey(Schema.String),
406
- data: Schema.optionalKey(Schema.Unknown),
407
- id: Schema.String,
408
- name: Schema.String,
409
- priority: Schema.optionalKey(Schema.Number),
410
- proxied: Schema.optionalKey(Schema.Boolean),
411
- ttl: Schema.Number,
412
- type: Schema.String
413
- });
414
- const Token = Schema.Struct({
415
- expires_on: Schema.optionalKey(Schema.String),
416
- id: Schema.String,
417
- not_before: Schema.optionalKey(Schema.String),
418
- status: Schema.Literals([
419
- "active",
420
- "disabled",
421
- "expired"
422
- ])
423
- });
424
- const ZoneListEnvelope = Schema.Struct({
425
- errors: Schema.Array(ErrorDetail$1),
426
- messages: Schema.Array(Message),
427
- result: Schema.Array(Zone),
428
- result_info: Schema.optionalKey(ResultInfo),
429
- success: Schema.Boolean
430
- });
431
- const RecordListEnvelope$1 = Schema.Struct({
432
- errors: Schema.Array(ErrorDetail$1),
433
- messages: Schema.Array(Message),
434
- result: Schema.Array(Record$1),
435
- result_info: Schema.optionalKey(ResultInfo),
436
- success: Schema.Boolean
437
- });
438
- const RecordEnvelope = Schema.Struct({
439
- errors: Schema.Array(ErrorDetail$1),
440
- messages: Schema.Array(Message),
441
- result: Record$1,
442
- success: Schema.Boolean
443
- });
444
- const TokenEnvelope = Schema.Struct({
445
- errors: Schema.Array(ErrorDetail$1),
446
- messages: Schema.Array(Message),
447
- result: Token,
448
- success: Schema.Boolean
449
- });
450
- //#endregion
451
- //#region src/providers/cloudflare/records.ts
452
- const Data$1 = Schema.Struct({
453
- flags: Schema.optionalKey(Schema.Number),
454
- port: Schema.optionalKey(Schema.Number),
455
- priority: Schema.optionalKey(Schema.Number),
456
- tag: Schema.optionalKey(Schema.String),
457
- target: Schema.optionalKey(Schema.String),
458
- value: Schema.optionalKey(Schema.String),
459
- weight: Schema.optionalKey(Schema.Number)
460
- });
461
- const decode$3 = Effect.fn("CloudflareRecords.decode")((record) => Effect.gen(function* () {
462
- const name = yield* decode$5(record.name).pipe(Effect.match({
463
- onFailure: () => null,
464
- onSuccess: (value) => value
465
- }));
466
- if (name === null) return yield* decodeOpaque$1(record);
467
- const common = {
468
- metadata: {
469
- ownership: "provider",
470
- provenance: record.proxied === true ? "cloudflare:proxied" : "cloudflare",
471
- purpose: "existing DNS record"
472
- },
473
- name,
474
- policy: record.type === "CNAME" ? "exclusive" : "append",
475
- ttl: record.ttl === 1 ? null : record.ttl
476
- };
477
- const content = () => record.content === void 0 ? Effect.fail(failure$5("decodeRecord", `Cloudflare ${record.type} record has no content`)) : Effect.succeed(record.content);
478
- switch (record.type) {
479
- case "A":
480
- case "AAAA": return yield* decode$6({
481
- ...common,
482
- _tag: record.type,
483
- address: yield* content()
484
- }).pipe(Effect.mapError((cause) => failure$5("decodeRecord", cause.message)));
485
- case "CNAME":
486
- case "NS": return yield* decode$6({
487
- ...common,
488
- _tag: record.type,
489
- target: yield* content()
490
- }).pipe(Effect.mapError((cause) => failure$5("decodeRecord", cause.message)));
491
- case "TXT": return yield* decode$6({
492
- ...common,
493
- _tag: "TXT",
494
- value: yield* content()
495
- }).pipe(Effect.mapError((cause) => failure$5("decodeRecord", cause.message)));
496
- case "MX": return yield* decode$6({
497
- ...common,
498
- _tag: "MX",
499
- exchange: yield* content(),
500
- priority: record.priority
501
- }).pipe(Effect.mapError((cause) => failure$5("decodeRecord", cause.message)));
502
- case "CAA": {
503
- const data = yield* decodeData(record);
504
- return yield* decode$6({
505
- ...common,
506
- _tag: "CAA",
507
- ...data
508
- }).pipe(Effect.mapError((cause) => failure$5("decodeRecord", cause.message)));
509
- }
510
- case "SRV": {
511
- const data = yield* decodeData(record);
512
- return yield* decode$6({
513
- ...common,
514
- _tag: "SRV",
515
- ...data
516
- }).pipe(Effect.mapError((cause) => failure$5("decodeRecord", cause.message)));
517
- }
518
- default: return yield* decodeOpaque$1(record);
519
- }
520
- }));
521
- const decodeOpaque$1 = Effect.fn("CloudflareRecords.decodeOpaque")((record) => Schema.decodeUnknownEffect(Opaque)({
522
- _tag: "Opaque",
523
- name: record.name,
524
- providerRecordId: record.id,
525
- providerType: record.type
526
- }).pipe(Effect.mapError((cause) => failure$5("decodeRecord", cause.message))));
527
- function encode$1(record) {
528
- const common = {
529
- name: record.name,
530
- proxied: false,
531
- ttl: record.ttl ?? 1,
532
- type: record._tag
533
- };
534
- switch (record._tag) {
535
- case "A":
536
- case "AAAA": return {
537
- ...common,
538
- content: record.address
539
- };
540
- case "CNAME":
541
- case "NS": return {
542
- ...common,
543
- content: record.target
544
- };
545
- case "TXT": return {
546
- ...common,
547
- content: record.value
548
- };
549
- case "MX": return {
550
- ...common,
551
- content: record.exchange,
552
- priority: record.priority
553
- };
554
- case "CAA": return {
555
- ...common,
556
- data: {
557
- flags: record.flags,
558
- tag: record.tag,
559
- value: record.value
560
- }
561
- };
562
- case "SRV": return {
563
- ...common,
564
- data: {
565
- port: record.port,
566
- priority: record.priority,
567
- target: record.target,
568
- weight: record.weight
569
- }
570
- };
571
- }
572
- }
573
- const decodeData = Effect.fn("CloudflareRecords.decodeData")((record) => Schema.decodeUnknownEffect(Data$1)(record.data).pipe(Effect.mapError((cause) => failure$5("decodeRecord", cause.message))));
574
- function failure$5(operation, message, fields = {}) {
575
- return new Error$3({
576
- message,
577
- operation,
578
- providerId: "cloudflare",
579
- reason: fields.reason ?? "response"
580
- });
581
- }
582
- //#endregion
583
- //#region src/providers/cloudflare/client.ts
584
- var client_exports$1 = /* @__PURE__ */ __exportAll({
585
- discoverAuthorizationAccount: () => discoverAuthorizationAccount,
586
- discovery: () => discovery$1,
587
- make: () => make$5,
588
- validateDomainToken: () => validateDomainToken
589
- });
590
- /** Exposes Cloudflare zone lookup as the optional provider discovery capability. */
591
- function discovery$1(client) {
592
- return {
593
- listZones: (name) => client.listZones({ name }).pipe(Effect.map((zones) => zones.map((zone) => ({
594
- ...zone,
595
- status: zone.status === "active" || zone.status === "pending" ? zone.status : "unknown"
596
- })))),
597
- provider: client
598
- };
599
- }
600
- const makeTransport = (options) => {
601
- const fetch = options.fetch ?? globalThis.fetch;
602
- const baseUrl = (options.baseUrl ?? "https://api.cloudflare.com/client/v4").replace(/\/$/, "");
603
- const request = Effect.fn("CloudflareClient.request")((path, operation, init) => Effect.gen(function* () {
604
- const response = yield* Effect.tryPromise({
605
- try: () => fetch(`${baseUrl}${path}`, {
606
- ...init,
607
- headers: {
608
- Accept: "application/json",
609
- Authorization: `Bearer ${options.token.expose()}`,
610
- ...init?.body === void 0 ? {} : { "Content-Type": "application/json" },
611
- ...init?.headers
612
- }
613
- }),
614
- catch: () => failure$4(operation, "Cloudflare request failed", { reason: "transport" })
615
- });
616
- return {
617
- body: yield* Effect.tryPromise({
618
- try: () => response.json(),
619
- catch: () => {
620
- const retryAfterMs = retryAfter(response.headers.get("retry-after"));
621
- return failure$4(operation, response.ok ? "Cloudflare returned a non-JSON response" : `Cloudflare request failed with HTTP ${response.status}`, {
622
- reason: response.ok ? "response" : reason$1(response.status),
623
- ...retryAfterMs === void 0 ? {} : { retryAfterMs },
624
- status: response.status
625
- });
626
- }
627
- }),
628
- response
629
- };
630
- }));
631
- const listZonesPage = Effect.fn("CloudflareClient.listZonesPage")((accountId, name, page) => Effect.gen(function* () {
632
- const query = new URLSearchParams({
633
- page: String(page),
634
- per_page: "50"
635
- });
636
- query.set("type", "full,partial,secondary,internal");
637
- if (accountId !== void 0) query.set("account.id", accountId);
638
- if (name !== void 0) query.set("name", name);
639
- const { body, response } = yield* request(`/zones?${query}`, "listZones");
640
- yield* ensureSuccess(body, "listZones", response);
641
- return yield* decode$2(ZoneListEnvelope, body, "listZones", response);
642
- }));
643
- return {
644
- allZones: Effect.fn("CloudflareClient.allZones")((accountId, name) => Effect.gen(function* () {
645
- const zones = [];
646
- let page = 1;
647
- while (true) {
648
- const envelope = yield* listZonesPage(accountId, name, page);
649
- zones.push(...envelope.result);
650
- const totalPages = envelope.result_info?.total_pages;
651
- if (totalPages !== void 0 && page >= totalPages || totalPages === void 0 && envelope.result.length < 50) return zones;
652
- page += 1;
653
- }
654
- })),
655
- inspectToken: Effect.fn("CloudflareClient.inspectToken")((path) => Effect.gen(function* () {
656
- const { body, response } = yield* request(path, "validateToken");
657
- yield* ensureSuccess(body, "validateToken", response);
658
- const envelope = yield* decode$2(TokenEnvelope, body, "validateToken", response);
659
- if (envelope.result.status !== "active") return yield* Effect.fail(failure$4("validateToken", `Cloudflare token is ${envelope.result.status}`, {
660
- reason: "authentication",
661
- status: response.status
662
- }));
663
- const expiresAt = envelope.result.expires_on === void 0 ? null : new Date(envelope.result.expires_on);
664
- if (expiresAt !== null && Number.isNaN(expiresAt.valueOf())) return yield* Effect.fail(failure$4("validateToken", "Cloudflare token expiry is not a valid timestamp", {
665
- reason: "response",
666
- status: response.status
667
- }));
668
- return expiresAt;
669
- })),
670
- request
671
- };
672
- };
673
- const discoverAccount = Effect.fn("CloudflareClient.discoverAccount")((options) => Effect.gen(function* () {
674
- const { allZones } = makeTransport(options);
675
- for (const candidate of candidates(options.domain)) {
676
- const matches = yield* allZones(void 0, candidate);
677
- const match = matches[0];
678
- if (matches.length === 0) continue;
679
- if (matches.length === 1 && match !== void 0) return match.account;
680
- return yield* Effect.fail(failure$4("discoverAccount", `Cloudflare returned multiple accessible zones named ${candidate}`, { reason: "conflict" }));
681
- }
682
- return yield* Effect.fail(failure$4("discoverAccount", `Cloudflare did not expose an accessible zone for ${options.domain}`, { reason: "not_found" }));
683
- }));
684
- const discoverAuthorizationAccount = discoverAccount;
685
- const validateDomainToken = Effect.fn("CloudflareClient.validateDomainToken")((options) => Effect.gen(function* () {
686
- const transport = makeTransport(options);
687
- const account = options.tokenKind === "account" ? yield* discoverAccount(options) : void 0;
688
- const expiresAt = yield* transport.inspectToken(account === void 0 ? "/user/tokens/verify" : `/accounts/${encodeURIComponent(account.id)}/tokens/verify`);
689
- return {
690
- accountId: (account ?? (yield* discoverAccount(options))).id,
691
- capabilities: options.capabilities,
692
- expiresAt,
693
- scopes: []
694
- };
695
- }));
696
- /** Creates an Effect-native Cloudflare client without owning the credential lifecycle. */
697
- function make$5(options) {
698
- return makeClient$1(options);
699
- }
700
- function makeClient$1(options) {
701
- const { allZones, inspectToken, request } = makeTransport(options);
702
- const resolveZone = Effect.fn("CloudflareClient.resolveZone")((name) => Effect.gen(function* () {
703
- if (options.target !== void 0) {
704
- if (name !== options.target.zoneName && !name.endsWith(`.${options.target.zoneName}`)) return yield* Effect.fail(failure$4("resolveZone", `Cloudflare target ${options.target.zoneName} does not cover ${name}`, { reason: "not_found" }));
705
- return {
706
- account: {
707
- id: options.target.accountId,
708
- name: options.target.accountId
709
- },
710
- id: options.target.zoneId,
711
- name: options.target.zoneName,
712
- name_servers: options.target.evidence?.nameservers ?? []
713
- };
714
- }
715
- const matches = yield* allZones(options.accountId, name);
716
- const match = matches[0];
717
- if (matches.length === 1 && match !== void 0) return match;
718
- return yield* Effect.fail(failure$4("resolveZone", matches.length === 0 ? options.accountId === void 0 ? `Cloudflare zone ${name} was not found in the authorized accounts` : `Cloudflare zone ${name} was not found in account ${options.accountId}` : options.accountId === void 0 ? `Cloudflare returned multiple zones named ${name} across authorized accounts` : `Cloudflare returned multiple zones named ${name} in account ${options.accountId}`, { reason: matches.length === 0 ? "not_found" : "response" }));
719
- }));
720
- const listRecords = Effect.fn("CloudflareClient.listRecords")((zoneName) => Effect.gen(function* () {
721
- const zone = yield* resolveZone(zoneName);
722
- const records = [];
723
- let page = 1;
724
- while (true) {
725
- const query = new URLSearchParams({
726
- page: String(page),
727
- per_page: "100"
728
- });
729
- const { body, response } = yield* request(`/zones/${encodeURIComponent(zone.id)}/dns_records?${query}`, "listRecords");
730
- yield* ensureSuccess(body, "listRecords", response);
731
- const envelope = yield* decode$2(RecordListEnvelope$1, body, "listRecords", response);
732
- records.push(...yield* Effect.forEach(envelope.result, decode$3));
733
- const totalPages = envelope.result_info?.total_pages;
734
- if (totalPages !== void 0 && page >= totalPages || totalPages === void 0 && envelope.result.length < 100) return records;
735
- page += 1;
736
- }
737
- }));
738
- const createRecord = Effect.fn("CloudflareClient.createRecord")((zoneName, record) => Effect.gen(function* () {
739
- const zone = yield* resolveZone(zoneName);
740
- const { body, response } = yield* request(`/zones/${encodeURIComponent(zone.id)}/dns_records`, "createRecord", {
741
- body: JSON.stringify(encode$1(record)),
742
- method: "POST"
743
- });
744
- yield* ensureSuccess(body, "createRecord", response);
745
- return { providerRecordId: (yield* decode$2(RecordEnvelope, body, "createRecord", response)).result.id };
746
- }));
747
- const getRecord = Effect.fn("CloudflareClient.getRecord")((zoneName, providerRecordId) => Effect.gen(function* () {
748
- const zone = yield* resolveZone(zoneName);
749
- const { body, response } = yield* request(`/zones/${encodeURIComponent(zone.id)}/dns_records/${encodeURIComponent(providerRecordId)}`, "getRecord");
750
- if (response.status === 404) return null;
751
- yield* ensureSuccess(body, "getRecord", response);
752
- const envelope = yield* decode$2(RecordEnvelope, body, "getRecord", response);
753
- return yield* decode$3(envelope.result);
754
- }));
755
- const deleteRecord = Effect.fn("CloudflareClient.deleteRecord")((zoneName, providerRecordId) => Effect.gen(function* () {
756
- const zone = yield* resolveZone(zoneName);
757
- const { body, response } = yield* request(`/zones/${encodeURIComponent(zone.id)}/dns_records/${encodeURIComponent(providerRecordId)}`, "deleteRecord", { method: "DELETE" });
758
- yield* ensureSuccess(body, "deleteRecord", response);
759
- }));
760
- const listAccounts = Effect.fn("CloudflareClient.listAccounts")(() => allZones().pipe(Effect.map((zones) => {
761
- const accounts = /* @__PURE__ */ new Map();
762
- for (const zone of zones) accounts.set(zone.account.id, zone.account);
763
- return [...accounts.values()].sort((left, right) => left.name.localeCompare(right.name));
764
- })));
765
- const listZones = Effect.fn("CloudflareClient.listZones")((input = {}) => allZones(input.accountId ?? options.accountId, input.name).pipe(Effect.flatMap((zones) => Effect.forEach(zones, projectZone$1))));
766
- const listTargets = Effect.fn("CloudflareClient.listTargets")((input = {}) => Effect.gen(function* () {
767
- const names = input.domain === void 0 ? void 0 : new Set(candidates(input.domain).map((name) => String(name)));
768
- const zones = yield* allZones(input.accountId ?? options.accountId);
769
- return yield* Effect.forEach(zones.filter((zone) => zone.type !== "internal" && (names === void 0 || names.has(zone.name))), targetFromZone);
770
- }));
771
- return {
772
- id: "cloudflare",
773
- providerId: "cloudflare",
774
- createRecord,
775
- deleteRecord,
776
- getRecord,
777
- listAccounts,
778
- listRecords,
779
- listZones,
780
- listTargets,
781
- resolveTarget: Effect.fn("CloudflareClient.resolveTarget")((domain) => Effect.gen(function* () {
782
- const candidates$2 = yield* listTargets({ domain });
783
- for (const zoneName of candidates(domain)) {
784
- const matches = candidates$2.filter((target) => target.zoneName === zoneName);
785
- if (matches.length === 1) {
786
- const target = matches[0];
787
- if (target !== void 0) return Resolution.Resolved({ target });
788
- }
789
- if (matches.length > 1) return Resolution.SelectionRequired({ candidates: matches });
790
- }
791
- return Resolution.NotFound({ domain });
792
- })),
793
- forTarget: Effect.fn("CloudflareClient.forTarget")((target) => Effect.gen(function* () {
794
- if (target.accountKind !== null && target.accountKind !== "account") return yield* Effect.fail(failure$4("forTarget", "Cloudflare targets must use the account account kind", { reason: "request" }));
795
- if (target.evidence?.zoneType === "internal") return yield* Effect.fail(failure$4("forTarget", "Cloudflare internal zones cannot host managed DNS records", { reason: "unsupported" }));
796
- const selected = (yield* listTargets({
797
- accountId: target.accountId,
798
- domain: target.zoneName
799
- })).find((candidate) => candidate.accountId === target.accountId && candidate.zoneId === target.zoneId && candidate.zoneName === target.zoneName);
800
- if (selected === void 0) return yield* Effect.fail(failure$4("forTarget", `Cloudflare target ${target.zoneName} is not visible to this credential`, { reason: "authorization" }));
801
- if (selected.evidence?.zoneType === "internal") return yield* Effect.fail(failure$4("forTarget", "Cloudflare internal zones cannot host managed DNS records", { reason: "unsupported" }));
802
- const client = makeClient$1({
803
- ...options,
804
- accountId: selected.accountId,
805
- target: selected
806
- });
807
- return {
808
- id: client.id,
809
- createRecord: client.createRecord,
810
- deleteRecord: client.deleteRecord,
811
- getRecord: client.getRecord,
812
- listRecords: client.listRecords
813
- };
814
- })),
815
- validateToken: Effect.fn("CloudflareClient.validateToken")(() => Effect.gen(function* () {
816
- const path = options.tokenKind === "account" ? options.accountId === void 0 ? yield* Effect.fail(failure$4("validateToken", "Cloudflare account tokens require an account ID", { reason: "request" })) : `/accounts/${encodeURIComponent(options.accountId)}/tokens/verify` : "/user/tokens/verify";
817
- const expiresAt = yield* inspectToken(path);
818
- yield* allZones(options.accountId);
819
- return {
820
- accountId: options.accountId ?? "",
821
- capabilities: options.capabilities,
822
- expiresAt,
823
- scopes: []
824
- };
825
- }))
826
- };
827
- }
828
- const targetFromZone = Effect.fn("CloudflareClient.targetFromZone")((zone) => Effect.gen(function* () {
829
- const name = yield* decode$5(zone.name).pipe(Effect.mapError((cause) => failure$4("listTargets", cause.message, { reason: "response" })));
830
- const nameservers = yield* Effect.forEach(zone.name_servers, (nameserver) => decode$5(nameserver).pipe(Effect.mapError((cause) => failure$4("listTargets", cause.message, { reason: "response" }))));
831
- return {
832
- accountId: zone.account.id,
833
- accountKind: "account",
834
- evidence: {
835
- accountName: zone.account.name,
836
- nameservers,
837
- status: zone.status ?? "unknown",
838
- zoneType: zone.type ?? "unknown"
839
- },
840
- zoneId: zone.id,
841
- zoneName: name
842
- };
843
- }));
844
- const projectZone$1 = Effect.fn("CloudflareClient.projectZone")((zone) => Effect.gen(function* () {
845
- const name = yield* decode$5(zone.name).pipe(Effect.mapError((cause) => failure$4("listZones", cause.message, { reason: "response" })));
846
- const nameservers = yield* Effect.forEach(zone.name_servers, (nameserver) => decode$5(nameserver).pipe(Effect.mapError((cause) => failure$4("listZones", cause.message, { reason: "response" }))));
847
- return {
848
- accountId: zone.account.id,
849
- id: zone.id,
850
- name,
851
- nameservers,
852
- status: zone.status ?? null
853
- };
854
- }));
855
- function decode$2(schema, input, operation, response) {
856
- return Schema.decodeUnknownEffect(schema)(input).pipe(Effect.mapError((cause) => failure$4(operation, `Cloudflare response did not match its API contract: ${cause.message}`, {
857
- reason: "response",
858
- status: response.status
859
- })));
860
- }
861
- function ensureSuccess(input, operation, response) {
862
- return Schema.decodeUnknownEffect(BaseEnvelope)(input).pipe(Effect.mapError(() => failure$4(operation, "Cloudflare response did not contain a valid API envelope", {
863
- reason: "response",
864
- status: response.status
865
- })), Effect.flatMap((envelope) => {
866
- if (response.ok && envelope.success) return Effect.void;
867
- const detail = envelope.errors[0];
868
- const retryAfterMs = retryAfter(response.headers.get("retry-after"));
869
- return Effect.fail(failure$4(operation, detail?.message ?? `Cloudflare request failed with HTTP ${response.status}`, {
870
- ...detail === void 0 ? {} : { code: detail.code },
871
- reason: reason$1(response.status, detail?.code),
872
- ...retryAfterMs === void 0 ? {} : { retryAfterMs },
873
- status: response.status
874
- }));
875
- }));
876
- }
877
- function reason$1(status, code) {
878
- if (status === 401) return "authentication";
879
- if (status === 403) return "authorization";
880
- if (status === 404) return "not_found";
881
- if (status === 409 || code === 81056 || code === 81057 || code === 81058) return "conflict";
882
- if (status === 429) return "rate_limit";
883
- if (status >= 500) return "response";
884
- return "request";
885
- }
886
- function retryAfter(value) {
887
- if (value === null) return void 0;
888
- const seconds = Number(value);
889
- if (Number.isFinite(seconds)) return Math.max(0, seconds * 1e3);
890
- const date = Date.parse(value);
891
- return Number.isNaN(date) ? void 0 : Math.max(0, date - Date.now());
892
- }
893
- function failure$4(operation, message, fields = {}) {
894
- return new Error$3({
895
- ...fields,
896
- message,
897
- operation,
898
- providerId: "cloudflare"
899
- });
900
- }
901
- //#endregion
902
- //#region src/providers/cloudflare/auth.ts
903
- var auth_exports$1 = /* @__PURE__ */ __exportAll({
904
- contextCodec: () => contextCodec$1,
905
- manifest: () => manifest$1,
906
- oauthAuthentication: () => oauthAuthentication,
907
- oauthFlow: () => oauthFlow,
908
- oauthMethod: () => oauthMethod,
909
- refreshCredential: () => refreshCredential,
910
- restore: () => restore$1,
911
- subjectResolver: () => subjectResolver,
912
- tokenConnectionMethod: () => tokenConnectionMethod$1,
913
- tokenMethod: () => tokenMethod$1,
914
- tokenValidator: () => tokenValidator
915
- });
916
- const authorizationServer = {
917
- authorization_endpoint: "https://dash.cloudflare.com/oauth2/auth",
918
- issuer: "https://dash.cloudflare.com",
919
- revocation_endpoint: "https://dash.cloudflare.com/oauth2/revoke",
920
- token_endpoint: "https://dash.cloudflare.com/oauth2/token"
921
- };
922
- const Context$2 = Schema.Struct({
923
- accountId: Schema.optionalKey(Schema.String),
924
- tokenKind: Schema.Literals(["account", "user"])
925
- });
926
- const contextCodec$1 = codec("cloudflare.v1", Context$2);
927
- /** Describes Cloudflare's caller-created API-token authorization method. */
928
- function tokenMethod$1(capabilities) {
929
- return {
930
- _tag: "token",
931
- capabilities: [...capabilities],
932
- instructionsUrl: "https://developers.cloudflare.com/fundamentals/api/get-started/create-token/"
933
- };
934
- }
935
- /** Describes a registered Cloudflare OAuth client and its assigned scope IDs. */
936
- function oauthMethod(options) {
937
- return {
938
- _tag: "oauth2",
939
- authorizationServer,
940
- capabilities: [...options.capabilities],
941
- clientAuth: options.clientAuth,
942
- scopes: [...options.scopes]
943
- };
944
- }
945
- /** Creates the Cloudflare token and OAuth authorization manifest. */
946
- function manifest$1(options) {
947
- return {
948
- methods: [tokenMethod$1(options.capabilities), oauthMethod(options)],
949
- providerId: "cloudflare"
950
- };
951
- }
952
- /** Resolves the Cloudflare account selected by a completed OAuth authorization. */
953
- function subjectResolver(options) {
954
- return (tokens, accessToken) => Effect.gen(function* () {
955
- const accountId = options.accountId ?? (yield* discoverAuthorizationAccount({
956
- ...options.baseUrl === void 0 ? {} : { baseUrl: options.baseUrl },
957
- domain: options.domain,
958
- ...options.fetch === void 0 ? {} : { fetch: options.fetch },
959
- token: accessToken
960
- }).pipe(Effect.map((account) => account.id)));
961
- if (options.accountId !== void 0) yield* make$5({
962
- accountId: options.accountId,
963
- ...options.baseUrl === void 0 ? {} : { baseUrl: options.baseUrl },
964
- capabilities: options.capabilities,
965
- ...options.fetch === void 0 ? {} : { fetch: options.fetch },
966
- token: accessToken,
967
- tokenKind: "user"
968
- }).listZones();
969
- const now = yield* Clock.currentTimeMillis;
970
- return {
971
- accountId,
972
- expiresAt: typeof tokens.expires_in === "number" ? new Date(now + tokens.expires_in * 1e3) : null
973
- };
974
- });
975
- }
976
- /** Creates a host callback that validates a Cloudflare API token. */
977
- function tokenValidator(options) {
978
- return (token) => options.accountId === void 0 ? validateDomainToken({
979
- ...options.baseUrl === void 0 ? {} : { baseUrl: options.baseUrl },
980
- capabilities: options.capabilities,
981
- domain: options.domain,
982
- ...options.fetch === void 0 ? {} : { fetch: options.fetch },
983
- token,
984
- ...options.tokenKind === void 0 ? {} : { tokenKind: options.tokenKind }
985
- }) : make$5({
986
- accountId: options.accountId,
987
- ...options.baseUrl === void 0 ? {} : { baseUrl: options.baseUrl },
988
- capabilities: options.capabilities,
989
- ...options.fetch === void 0 ? {} : { fetch: options.fetch },
990
- token,
991
- ...options.tokenKind === void 0 ? {} : { tokenKind: options.tokenKind }
992
- }).validateToken();
993
- }
994
- /** Creates a provider-independent token connection method backed by Cloudflare validation. */
995
- function tokenConnectionMethod$1(options) {
996
- const requiredCapabilities = [...options.capabilities];
997
- return Method$1.Token({
998
- authenticate: Effect.fn("CloudflareAuth.authenticateToken")(function* (token) {
999
- const validated = yield* tokenValidator(options)(token);
1000
- const observedAt = new Date(yield* Clock.currentTimeMillis);
1001
- return {
1002
- capabilityEvidence: validated.capabilities.map((capability) => ({
1003
- capability,
1004
- evidence: Evidence$1.Introspected({ observedAt })
1005
- })),
1006
- credential: {
1007
- accessToken: token,
1008
- expiresAt: validated.expiresAt,
1009
- refreshToken: null,
1010
- tokenType: "bearer"
1011
- },
1012
- providerAccountId: validated.accountId,
1013
- providerContext: yield* contextCodec$1.encode(options.tokenKind === "account" ? {
1014
- accountId: validated.accountId,
1015
- tokenKind: "account"
1016
- } : { tokenKind: "user" }),
1017
- scopes: [...validated.scopes]
1018
- };
1019
- }),
1020
- providerId: "cloudflare",
1021
- requiredCapabilities,
1022
- token: options.token
1023
- });
1024
- }
1025
- /** Converts a completed Cloudflare OAuth authorization into canonical connection authentication. */
1026
- const oauthAuthentication = Effect.fn("CloudflareAuth.oauthAuthentication")(function* (options) {
1027
- const resolved = yield* subjectResolver(options)(options.tokens, options.accessToken);
1028
- const observedAt = new Date(yield* Clock.currentTimeMillis);
1029
- return {
1030
- capabilityEvidence: options.capabilities.map((capability) => ({
1031
- capability,
1032
- evidence: Evidence$1.Introspected({ observedAt })
1033
- })),
1034
- credential: {
1035
- accessToken: options.accessToken,
1036
- expiresAt: resolved.expiresAt,
1037
- refreshToken: options.tokens.refresh_token === void 0 ? null : Value.from(options.tokens.refresh_token),
1038
- tokenType: options.tokens.token_type
1039
- },
1040
- providerAccountId: resolved.accountId,
1041
- providerContext: yield* contextCodec$1.encode({ tokenKind: "user" }),
1042
- scopes: (options.tokens.scope ?? "").split(" ").filter(Boolean)
1043
- };
1044
- });
1045
- /** Restore a credential-scoped Cloudflare session from persisted authorization state. */
1046
- function restore$1(options) {
1047
- return Effect.gen(function* () {
1048
- if (options.authorization.providerId !== "cloudflare") return yield* Effect.fail(failure$3("restore", "Provider authorization belongs to another provider", "authorization"));
1049
- if (options.authorization.method === "integration") return yield* Effect.fail(failure$3("restore", "Cloudflare does not support integration credentials", "unsupported"));
1050
- if (options.authorization.revocation._tag !== "Active") return yield* Effect.fail(failure$3("restore", "Cloudflare authorization is pending revocation", "authorization"));
1051
- const missingCapability = options.authorization.requiredCapabilities.find((capability) => !options.authorization.capabilityEvidence.some((item) => item.capability === capability));
1052
- if (missingCapability !== void 0) return yield* Effect.fail(failure$3("restore", `Cloudflare authorization lacks evidence for ${missingCapability}`, "authorization"));
1053
- if (options.credential.expiresAt !== null && (Number.isNaN(options.credential.expiresAt.valueOf()) || options.credential.expiresAt <= /* @__PURE__ */ new Date())) return yield* Effect.fail(failure$3("restore", "Cloudflare authorization has expired", "authentication"));
1054
- const context = yield* contextCodec$1.decode(options.authorization.providerContext).pipe(Effect.mapError((cause) => failure$3("restore", cause.message, "response")));
1055
- return make$5({
1056
- ...context.accountId === void 0 ? {} : { accountId: context.accountId },
1057
- ...options.baseUrl === void 0 ? {} : { baseUrl: options.baseUrl },
1058
- capabilities: options.authorization.capabilityEvidence.map(({ capability }) => capability),
1059
- ...options.fetch === void 0 ? {} : { fetch: options.fetch },
1060
- token: options.credential.accessToken,
1061
- tokenKind: context.tokenKind
1062
- });
1063
- });
1064
- }
1065
- /** Exchanges a Cloudflare refresh token for a fresh provider credential. */
1066
- const refreshCredential = Effect.fn("CloudflareAuth.refreshCredential")(function* (options) {
1067
- if (options.credential.refreshToken === null) return yield* new Error$2({
1068
- category: "authorization",
1069
- message: "Cloudflare credential has no refresh token",
1070
- operation: "CloudflareAuth.refreshCredential",
1071
- retry: "after-user-action"
1072
- });
1073
- const refreshToken = options.credential.refreshToken;
1074
- const client = { client_id: options.client.clientId };
1075
- const authentication = yield* Effect.try({
1076
- try: () => clientAuthentication(options.clientAuth, options.client),
1077
- catch: () => new Error$2({
1078
- category: "authorization",
1079
- message: "Cloudflare OAuth client authentication is invalid",
1080
- operation: "CloudflareAuth.refreshCredential",
1081
- retry: "never"
1082
- })
1083
- });
1084
- const fetch = options.fetch;
1085
- const tokens = yield* Effect.tryPromise({
1086
- try: async (signal) => {
1087
- const request = await oauth.refreshTokenGrantRequest(authorizationServer, client, authentication, refreshToken.expose(), fetch === void 0 ? { signal } : {
1088
- signal,
1089
- [oauth.customFetch]: (url, init) => fetch(url, {
1090
- ...init,
1091
- body: init.body
1092
- })
1093
- });
1094
- return oauth.processRefreshTokenResponse(authorizationServer, client, request);
1095
- },
1096
- catch: (cause) => refreshFailure(cause)
1097
- });
1098
- const now = yield* Clock.currentTimeMillis;
1099
- return {
1100
- accessToken: Value.from(tokens.access_token),
1101
- expiresAt: typeof tokens.expires_in === "number" ? new Date(now + tokens.expires_in * 1e3) : null,
1102
- refreshToken: tokens.refresh_token === void 0 ? refreshToken : Value.from(tokens.refresh_token),
1103
- tokenType: tokens.token_type
1104
- };
1105
- });
1106
- /** Creates Cloudflare's OAuth implementation of the common interactive connection capability. */
1107
- function oauthFlow(options) {
1108
- const method = oauthMethod({
1109
- capabilities: options.capabilities,
1110
- clientAuth: options.clientAuth,
1111
- scopes: options.scopes
1112
- });
1113
- return {
1114
- complete: Effect.fn("CloudflareAuth.oauthFlow.complete")(function* (payload, callbackUrl) {
1115
- const tokens = yield* complete({
1116
- callbackUrl,
1117
- client: options.client,
1118
- ...options.fetch === void 0 ? {} : { fetch: options.fetch },
1119
- method,
1120
- payload,
1121
- providerId: "cloudflare"
1122
- });
1123
- return yield* oauthAuthentication({
1124
- ...options.accountId === void 0 ? { domain: options.domain } : { accountId: options.accountId },
1125
- ...options.baseUrl === void 0 ? {} : { baseUrl: options.baseUrl },
1126
- capabilities: options.capabilities,
1127
- ...options.fetch === void 0 ? {} : { fetch: options.fetch },
1128
- accessToken: make$6(tokens.access_token),
1129
- tokens
1130
- });
1131
- }),
1132
- method: "oauth2",
1133
- providerId: "cloudflare",
1134
- requiredCapabilities: [...options.capabilities],
1135
- start: (continuationId) => start({
1136
- client: options.client,
1137
- method,
1138
- redirectUri: options.redirectUri,
1139
- state: continuationId
1140
- })
1141
- };
1142
- }
1143
- function failure$3(operation, message, reason) {
1144
- return new Error$3({
1145
- message,
1146
- operation,
1147
- providerId: "cloudflare",
1148
- reason
1149
- });
1150
- }
1151
- function clientAuthentication(method, client) {
1152
- if (method === "none") return oauth.None();
1153
- if (client.clientSecret === void 0) throw new Error("Client secret is required");
1154
- return method === "client_secret_basic" ? oauth.ClientSecretBasic(client.clientSecret.expose()) : oauth.ClientSecretPost(client.clientSecret.expose());
1155
- }
1156
- function refreshFailure(cause) {
1157
- if (cause instanceof oauth.ResponseBodyError && ["invalid_client", "invalid_grant"].includes(cause.error)) return new Error$2({
1158
- category: "authorization",
1159
- message: "Cloudflare authorization can no longer be refreshed",
1160
- operation: "CloudflareAuth.refreshCredential",
1161
- retry: "after-user-action"
1162
- });
1163
- return failure$3("refreshCredential", cause instanceof Error ? cause.message : "Cloudflare token refresh failed", cause instanceof oauth.ResponseBodyError ? "response" : "transport");
1164
- }
1165
- //#endregion
1166
- //#region src/providers/vercel/protocol.ts
1167
- const Pagination = Schema.Struct({
1168
- count: Schema.Number,
1169
- next: Schema.NullOr(Schema.Number),
1170
- prev: Schema.NullOr(Schema.Number)
1171
- });
1172
- const ErrorDetail = Schema.Struct({
1173
- code: Schema.String,
1174
- message: Schema.String,
1175
- limit: Schema.optionalKey(Schema.Struct({
1176
- remaining: Schema.Number,
1177
- reset: Schema.optionalKey(Schema.Number),
1178
- resetMs: Schema.optionalKey(Schema.Number),
1179
- total: Schema.Number
1180
- }))
1181
- });
1182
- const ErrorEnvelope = Schema.Struct({ error: ErrorDetail });
1183
- const User = Schema.Struct({
1184
- id: Schema.String,
1185
- name: Schema.NullOr(Schema.String),
1186
- username: Schema.String
1187
- });
1188
- const UserEnvelope = Schema.Struct({ user: User });
1189
- const Team = Schema.Struct({
1190
- id: Schema.String,
1191
- name: Schema.NullOr(Schema.String),
1192
- slug: Schema.String
1193
- });
1194
- const TeamListEnvelope = Schema.Struct({
1195
- pagination: Pagination,
1196
- teams: Schema.Array(Team)
1197
- });
1198
- const Domain = Schema.Struct({
1199
- id: Schema.String,
1200
- intendedNameservers: Schema.Array(Schema.String),
1201
- name: Schema.String,
1202
- nameservers: Schema.Array(Schema.String),
1203
- serviceType: Schema.Literals([
1204
- "zeit.world",
1205
- "external",
1206
- "na"
1207
- ]),
1208
- teamId: Schema.NullOr(Schema.String),
1209
- userId: Schema.String,
1210
- verified: Schema.Boolean,
1211
- zone: Schema.optionalKey(Schema.Boolean)
1212
- });
1213
- const DomainConfig = Schema.Struct({
1214
- misconfigured: Schema.Boolean,
1215
- serviceType: Schema.Literals([
1216
- "zeit.world",
1217
- "external",
1218
- "na"
1219
- ])
1220
- });
1221
- const DomainEnvelope = Schema.Struct({ domain: Domain });
1222
- const DomainListEnvelope = Schema.Struct({
1223
- domains: Schema.Array(Domain),
1224
- pagination: Pagination
1225
- });
1226
- const Record = Schema.Struct({
1227
- id: Schema.String,
1228
- mxPriority: Schema.optionalKey(Schema.Number),
1229
- name: Schema.String,
1230
- priority: Schema.optionalKey(Schema.Number),
1231
- ttl: Schema.optionalKey(Schema.Number),
1232
- type: Schema.String,
1233
- value: Schema.String
1234
- });
1235
- const RecordListEnvelope = Schema.Struct({
1236
- pagination: Schema.optionalKey(Pagination),
1237
- records: Schema.Array(Record)
1238
- });
1239
- const CreateRecordEnvelope = Schema.Struct({
1240
- uid: Schema.String,
1241
- updated: Schema.optionalKey(Schema.Number)
1242
- });
1243
- const IntegrationToken = Schema.Struct({
1244
- access_token: Schema.String,
1245
- installation_id: Schema.optionalKey(Schema.String),
1246
- team_id: Schema.NullOr(Schema.String),
1247
- token_type: Schema.optionalKey(Schema.String),
1248
- user_id: Schema.String
1249
- });
1250
- //#endregion
1251
- //#region src/providers/vercel/records.ts
1252
- const decode$1 = Effect.fn("VercelRecords.decode")((zone, record) => Effect.gen(function* () {
1253
- const absolute = absoluteNameCandidate(zone, record.name);
1254
- const name = yield* decode$5(absolute).pipe(Effect.match({
1255
- onFailure: () => null,
1256
- onSuccess: (value) => value
1257
- }));
1258
- if (name === null) return yield* decodeOpaque(record, absolute);
1259
- const common = {
1260
- metadata: {
1261
- ownership: "provider",
1262
- provenance: "vercel",
1263
- purpose: "existing DNS record"
1264
- },
1265
- name,
1266
- policy: record.type === "CNAME" ? "exclusive" : "append",
1267
- ttl: record.ttl ?? 60
1268
- };
1269
- const fromRecord = (input) => decode$6(input).pipe(Effect.mapError((cause) => failure$2("decodeRecord", cause.message)));
1270
- switch (record.type) {
1271
- case "A":
1272
- case "AAAA": return yield* fromRecord({
1273
- ...common,
1274
- _tag: record.type,
1275
- address: record.value
1276
- });
1277
- case "CNAME":
1278
- case "NS": return yield* fromRecord({
1279
- ...common,
1280
- _tag: record.type,
1281
- target: record.value
1282
- });
1283
- case "TXT": return yield* fromRecord({
1284
- ...common,
1285
- _tag: "TXT",
1286
- value: record.value
1287
- });
1288
- case "MX": return yield* fromRecord({
1289
- ...common,
1290
- _tag: "MX",
1291
- exchange: record.value,
1292
- priority: record.mxPriority ?? record.priority
1293
- });
1294
- case "CAA": {
1295
- const match = record.value.match(/^(\d{1,3})\s+(issue|issuewild|iodef)\s+(?:"((?:\\.|[^"])*)"|(\S.*))$/);
1296
- if (match === null) return yield* Effect.fail(failure$2("decodeRecord", "Vercel CAA record has an invalid value"));
1297
- return yield* fromRecord({
1298
- ...common,
1299
- _tag: "CAA",
1300
- flags: Number(match[1]),
1301
- tag: match[2],
1302
- value: unescapeQuoted(match[3] ?? match[4] ?? "")
1303
- });
1304
- }
1305
- case "SRV": {
1306
- const parts = record.value.trim().split(/\s+/);
1307
- const [priority, weight, port, target] = parts.length === 4 ? parts : [
1308
- String(record.priority ?? ""),
1309
- parts[0],
1310
- parts[1],
1311
- parts[2]
1312
- ];
1313
- return yield* fromRecord({
1314
- ...common,
1315
- _tag: "SRV",
1316
- port: Number(port),
1317
- priority: Number(priority),
1318
- target,
1319
- weight: Number(weight)
1320
- });
1321
- }
1322
- default: return yield* decodeOpaque(record, name);
1323
- }
1324
- }));
1325
- const decodeOpaque = Effect.fn("VercelRecords.decodeOpaque")((record, name) => Schema.decodeUnknownEffect(Opaque)({
1326
- _tag: "Opaque",
1327
- name,
1328
- providerRecordId: record.id,
1329
- providerType: record.type
1330
- }).pipe(Effect.mapError((cause) => failure$2("decodeRecord", cause.message))));
1331
- function encode(zone, record) {
1332
- const common = {
1333
- name: relativeName(zone, record.name),
1334
- ...record.ttl === null ? {} : { ttl: record.ttl },
1335
- type: record._tag
1336
- };
1337
- switch (record._tag) {
1338
- case "A":
1339
- case "AAAA": return {
1340
- ...common,
1341
- value: record.address
1342
- };
1343
- case "CNAME":
1344
- case "NS": return {
1345
- ...common,
1346
- value: record.target
1347
- };
1348
- case "TXT": return {
1349
- ...common,
1350
- value: record.value
1351
- };
1352
- case "MX": return {
1353
- ...common,
1354
- mxPriority: record.priority,
1355
- value: record.exchange
1356
- };
1357
- case "CAA": return {
1358
- ...common,
1359
- value: `${record.flags} ${record.tag} "${escapeQuoted(record.value)}"`
1360
- };
1361
- case "SRV": return {
1362
- ...common,
1363
- srv: {
1364
- port: record.port,
1365
- priority: record.priority,
1366
- target: record.target,
1367
- weight: record.weight
1368
- }
1369
- };
1370
- }
1371
- }
1372
- function absoluteNameCandidate(zone, name) {
1373
- return name === "" || name === "@" ? zone : name === zone || name.endsWith(`.${zone}`) ? name : `${name}.${zone}`;
1374
- }
1375
- function relativeName(zone, name) {
1376
- if (name === zone) return "";
1377
- const suffix = `.${zone}`;
1378
- if (!name.endsWith(suffix)) throw failure$2("encodeRecord", `DNS record ${name} is outside Vercel zone ${zone}`, { reason: "request" });
1379
- return name.slice(0, -suffix.length);
1380
- }
1381
- function escapeQuoted(value) {
1382
- return value.replaceAll("\\", "\\\\").replaceAll("\"", "\\\"");
1383
- }
1384
- function unescapeQuoted(value) {
1385
- return value.replace(/\\([\\"])/g, "$1");
1386
- }
1387
- function failure$2(operation, message, fields = {}) {
1388
- return new Error$3({
1389
- message,
1390
- operation,
1391
- providerId: "vercel",
1392
- reason: fields.reason ?? "response"
1393
- });
1394
- }
1395
- //#endregion
1396
- //#region src/providers/vercel/client.ts
1397
- var client_exports = /* @__PURE__ */ __exportAll({
1398
- AccountContext: () => AccountContext,
1399
- discovery: () => discovery,
1400
- make: () => make$4
1401
- });
1402
- /** Constructs the account scope used by Vercel API requests. */
1403
- const AccountContext = {
1404
- personal: () => ({ _tag: "personal" }),
1405
- team: ({ teamId }) => ({
1406
- _tag: "team",
1407
- teamId
1408
- })
1409
- };
1410
- /** Exposes Vercel zone lookup as the optional provider discovery capability. */
1411
- function discovery(client) {
1412
- return {
1413
- listZones: (name) => client.listZones({ name }),
1414
- provider: client
1415
- };
1416
- }
1417
- /** Creates an Effect-native Vercel client without owning the credential lifecycle. */
1418
- function make$4(options) {
1419
- return makeClient(options);
1420
- }
1421
- function makeClient(options) {
1422
- const fetch = options.fetch ?? globalThis.fetch;
1423
- const baseUrl = (options.baseUrl ?? "https://api.vercel.com").replace(/\/$/, "");
1424
- const withContext = (path, values = {}) => {
1425
- const url = new URL(`${baseUrl}${path}`);
1426
- for (const [key, value] of Object.entries(values)) url.searchParams.set(key, value);
1427
- if (options.context._tag === "team") url.searchParams.set("teamId", options.context.teamId);
1428
- return url;
1429
- };
1430
- const request = Effect.fn("VercelClient.request")((url, operation, init) => Effect.gen(function* () {
1431
- const response = yield* Effect.tryPromise({
1432
- try: () => fetch(url, {
1433
- ...init,
1434
- headers: {
1435
- Accept: "application/json",
1436
- Authorization: `Bearer ${options.token.expose()}`,
1437
- ...init?.body === void 0 ? {} : { "Content-Type": "application/json" },
1438
- ...init?.headers
1439
- }
1440
- }),
1441
- catch: () => failure$1(operation, "Vercel request failed", { reason: "transport" })
1442
- });
1443
- const body = yield* Effect.tryPromise({
1444
- try: () => response.json(),
1445
- catch: () => failure$1(operation, response.ok ? "Vercel returned a non-JSON response" : `Vercel request failed with HTTP ${response.status}`, {
1446
- reason: response.ok ? "response" : reason(response.status),
1447
- ...rateLimit(response),
1448
- status: response.status
1449
- })
1450
- });
1451
- if (!response.ok) return yield* Effect.fail(apiFailure(body, operation, response));
1452
- return {
1453
- body,
1454
- response
1455
- };
1456
- }));
1457
- const allTeams = Effect.fn("VercelClient.allTeams")(() => Effect.gen(function* () {
1458
- const teams = [];
1459
- let until = null;
1460
- while (true) {
1461
- const url = new URL(`${baseUrl}/v2/teams`);
1462
- url.searchParams.set("limit", "100");
1463
- if (until !== null) url.searchParams.set("until", String(until));
1464
- const { body, response } = yield* request(url, "listAccounts");
1465
- const envelope = yield* decode(TeamListEnvelope, body, "listAccounts", response);
1466
- teams.push(...envelope.teams);
1467
- if (envelope.pagination.next === null) return teams;
1468
- until = envelope.pagination.next;
1469
- }
1470
- }));
1471
- const allDomains = Effect.fn("VercelClient.allDomains")(() => Effect.gen(function* () {
1472
- const domains = [];
1473
- let until = null;
1474
- while (true) {
1475
- const values = { limit: "100" };
1476
- if (until !== null) values.until = String(until);
1477
- const { body, response } = yield* request(withContext("/v5/domains", values), "listZones");
1478
- const envelope = yield* decode(DomainListEnvelope, body, "listZones", response);
1479
- domains.push(...envelope.domains);
1480
- if (envelope.pagination.next === null) return domains;
1481
- until = envelope.pagination.next;
1482
- }
1483
- }));
1484
- const discoverZone = Effect.fn("VercelClient.discoverZone")((name) => Effect.gen(function* () {
1485
- const configResult = yield* request(withContext(`/v6/domains/${encodeURIComponent(name)}/config`), "resolveZone");
1486
- const config = yield* decode(DomainConfig, configResult.body, "resolveZone", configResult.response);
1487
- const domainResult = yield* request(withContext(`/v5/domains/${encodeURIComponent(name)}`), "resolveZone");
1488
- const envelope = yield* decode(DomainEnvelope, domainResult.body, "resolveZone", domainResult.response);
1489
- if (!hasDnsStorage(envelope.domain, config.serviceType)) return null;
1490
- return envelope.domain;
1491
- }).pipe(Effect.catchTag("ProviderError", (cause) => cause.reason === "not_found" ? Effect.succeed(null) : Effect.fail(cause))));
1492
- const resolveZone = Effect.fn("VercelClient.resolveZone")((name) => Effect.gen(function* () {
1493
- if (options.target !== void 0) {
1494
- if (name !== options.target.zoneName && !name.endsWith(`.${options.target.zoneName}`)) return yield* Effect.fail(failure$1("resolveZone", `Vercel target ${options.target.zoneName} does not cover ${name}`, { reason: "not_found" }));
1495
- return options.target.zoneName;
1496
- }
1497
- const domain = yield* discoverZone(name);
1498
- if (domain === null) return yield* Effect.fail(failure$1("resolveZone", `Vercel zone ${name} is not configured for authoritative DNS in the selected account`, { reason: "not_found" }));
1499
- return yield* decode$5(domain.name).pipe(Effect.mapError((cause) => failure$1("resolveZone", `Vercel returned an invalid storage zone: ${cause.message}`)));
1500
- }));
1501
- const listRecords = Effect.fn("VercelClient.listRecords")((zoneName) => Effect.gen(function* () {
1502
- const storageZone = yield* resolveZone(zoneName);
1503
- const records = [];
1504
- let until = null;
1505
- while (true) {
1506
- const values = { limit: "100" };
1507
- if (until !== null) values.until = String(until);
1508
- const { body, response } = yield* request(withContext(`/v5/domains/${encodeURIComponent(storageZone)}/records`, values), "listRecords");
1509
- const envelope = yield* decode(RecordListEnvelope, body, "listRecords", response);
1510
- records.push(...yield* Effect.forEach(envelope.records, (record) => decode$1(storageZone, record)));
1511
- const next = envelope.pagination?.next ?? null;
1512
- if (next === null) return records.filter((record) => record.name === zoneName || record.name.endsWith(`.${zoneName}`));
1513
- until = next;
1514
- }
1515
- }));
1516
- const createRecord = Effect.fn("VercelClient.createRecord")((zoneName, record) => Effect.gen(function* () {
1517
- const storageZone = yield* resolveZone(zoneName);
1518
- const body = yield* Effect.try({
1519
- try: () => encode(storageZone, record),
1520
- catch: (cause) => cause instanceof Error$3 ? cause : failure$1("createRecord", "Vercel record could not be encoded", { reason: "request" })
1521
- });
1522
- const result = yield* request(withContext(`/v2/domains/${encodeURIComponent(storageZone)}/records`), "createRecord", {
1523
- body: JSON.stringify(body),
1524
- method: "POST"
1525
- });
1526
- return { providerRecordId: (yield* decode(CreateRecordEnvelope, result.body, "createRecord", result.response)).uid };
1527
- }));
1528
- const getRecord = Effect.fn("VercelClient.getRecord")((zoneName, providerRecordId) => Effect.gen(function* () {
1529
- const storageZone = yield* resolveZone(zoneName);
1530
- let until = null;
1531
- while (true) {
1532
- const values = { limit: "100" };
1533
- if (until !== null) values.until = String(until);
1534
- const { body, response } = yield* request(withContext(`/v5/domains/${encodeURIComponent(storageZone)}/records`, values), "getRecord");
1535
- const envelope = yield* decode(RecordListEnvelope, body, "getRecord", response);
1536
- const record = envelope.records.find(({ id }) => id === providerRecordId);
1537
- if (record !== void 0) return yield* decode$1(storageZone, record);
1538
- const next = envelope.pagination?.next ?? null;
1539
- if (next === null) return null;
1540
- until = next;
1541
- }
1542
- }));
1543
- const deleteRecord = Effect.fn("VercelClient.deleteRecord")((zoneName, providerRecordId) => Effect.gen(function* () {
1544
- const storageZone = yield* resolveZone(zoneName);
1545
- yield* request(withContext(`/v2/domains/${encodeURIComponent(storageZone)}/records/${encodeURIComponent(providerRecordId)}`), "deleteRecord", { method: "DELETE" });
1546
- }));
1547
- const listAccounts = Effect.fn("VercelClient.listAccounts")(() => Effect.gen(function* () {
1548
- const userResult = yield* request(new URL(`${baseUrl}/v2/user`), "listAccounts");
1549
- const { user } = yield* decode(UserEnvelope, userResult.body, "listAccounts", userResult.response);
1550
- const teams = yield* allTeams();
1551
- return [{
1552
- id: user.id,
1553
- name: user.name ?? user.username,
1554
- type: "personal"
1555
- }, ...teams.map((team) => ({
1556
- id: team.id,
1557
- name: team.name ?? team.slug,
1558
- type: "team"
1559
- }))];
1560
- }));
1561
- const listZones = Effect.fn("VercelClient.listZones")((input = {}) => Effect.gen(function* () {
1562
- const domains = (yield* allDomains()).filter((domain) => hasDnsStorage(domain) && (input.name === void 0 || domain.name === input.name));
1563
- if (domains.length > 0 || input.name === void 0) return yield* Effect.forEach(domains, projectZone);
1564
- const discovered = yield* discoverZone(input.name);
1565
- return discovered === null ? [] : [yield* projectZone(discovered)];
1566
- }));
1567
- const listTargets = Effect.fn("VercelClient.listTargets")((input = {}) => Effect.gen(function* () {
1568
- const names = input.domain === void 0 ? void 0 : new Set(candidates(input.domain).map((name) => String(name)));
1569
- const domains = (yield* allDomains()).filter((domain) => hasDnsStorage(domain) && (names === void 0 || names.has(domain.name)) && (input.accountId === void 0 || (domain.teamId ?? domain.userId) === input.accountId));
1570
- if (domains.length > 0 || input.domain === void 0) return yield* Effect.forEach(domains, targetFromDomain);
1571
- for (const name of candidates(input.domain)) {
1572
- const discovered = yield* discoverZone(name);
1573
- if (discovered !== null && (input.accountId === void 0 || (discovered.teamId ?? discovered.userId) === input.accountId)) return [yield* targetFromDomain(discovered)];
1574
- }
1575
- return [];
1576
- }));
1577
- return {
1578
- id: "vercel",
1579
- providerId: "vercel",
1580
- createRecord,
1581
- deleteRecord,
1582
- getRecord,
1583
- listAccounts,
1584
- listRecords,
1585
- listZones,
1586
- listTargets,
1587
- resolveTarget: Effect.fn("VercelClient.resolveTarget")((domain) => Effect.gen(function* () {
1588
- const candidates$1 = yield* listTargets({ domain });
1589
- for (const zoneName of candidates(domain)) {
1590
- const matches = candidates$1.filter((target) => target.zoneName === zoneName);
1591
- if (matches.length === 1) {
1592
- const target = matches[0];
1593
- if (target !== void 0) return Resolution.Resolved({ target });
1594
- }
1595
- if (matches.length > 1) return Resolution.SelectionRequired({ candidates: matches });
1596
- }
1597
- return Resolution.NotFound({ domain });
1598
- })),
1599
- forTarget: Effect.fn("VercelClient.forTarget")((target) => Effect.gen(function* () {
1600
- if (target.accountKind === "team") {
1601
- if (options.context._tag !== "team" || options.context.teamId !== target.accountId) return yield* Effect.fail(failure$1("forTarget", "Vercel team target is outside the selected installation", { reason: "authorization" }));
1602
- } else if (target.accountKind === "personal" && options.context._tag !== "personal") return yield* Effect.fail(failure$1("forTarget", "Vercel personal target is outside the selected installation", { reason: "authorization" }));
1603
- else if (target.accountKind === "account") return yield* Effect.fail(failure$1("forTarget", "Vercel does not support account-kind targets", { reason: "unsupported" }));
1604
- else if (target.accountKind === null) return yield* Effect.fail(failure$1("forTarget", "Vercel targets must identify a personal or team account", { reason: "request" }));
1605
- const selected = (yield* listTargets({
1606
- accountId: target.accountId,
1607
- domain: target.zoneName
1608
- })).find((candidate) => candidate.accountId === target.accountId && candidate.accountKind === target.accountKind && candidate.zoneId === target.zoneId && candidate.zoneName === target.zoneName);
1609
- if (selected === void 0) return yield* Effect.fail(failure$1("forTarget", `Vercel target ${target.zoneName} is not visible to this installation`, { reason: "authorization" }));
1610
- const client = makeClient({
1611
- ...options,
1612
- target: selected
1613
- });
1614
- return {
1615
- id: client.id,
1616
- createRecord: client.createRecord,
1617
- deleteRecord: client.deleteRecord,
1618
- getRecord: client.getRecord,
1619
- listRecords: client.listRecords
1620
- };
1621
- })),
1622
- validateToken: Effect.fn("VercelClient.validateToken")(() => Effect.gen(function* () {
1623
- let accountId;
1624
- if (options.context._tag === "team") {
1625
- yield* allDomains();
1626
- accountId = options.context.teamId;
1627
- } else {
1628
- const result = yield* request(new URL(`${baseUrl}/v2/user`), "validateToken");
1629
- const { user } = yield* decode(UserEnvelope, result.body, "validateToken", result.response);
1630
- accountId = user.id;
1631
- }
1632
- return {
1633
- accountId,
1634
- capabilities: options.capabilities,
1635
- expiresAt: null,
1636
- scopes: []
1637
- };
1638
- }))
1639
- };
1640
- }
1641
- function hasDnsStorage(domain, configuredServiceType = domain.serviceType) {
1642
- return configuredServiceType === "zeit.world" || domain.zone === true || domain.intendedNameservers.length > 0;
1643
- }
1644
- const projectZone = Effect.fn("VercelClient.projectZone")((domain) => Effect.gen(function* () {
1645
- const name = yield* decode$5(domain.name).pipe(Effect.mapError((cause) => failure$1("listZones", cause.message, { reason: "response" })));
1646
- const nameservers = yield* Effect.forEach(domain.intendedNameservers, (nameserver) => decode$5(nameserver).pipe(Effect.mapError((cause) => failure$1("listZones", cause.message, { reason: "response" }))));
1647
- return {
1648
- accountId: domain.teamId ?? domain.userId,
1649
- id: domain.id,
1650
- name,
1651
- nameservers,
1652
- status: domain.verified ? "active" : "pending"
1653
- };
1654
- }));
1655
- const targetFromDomain = Effect.fn("VercelClient.targetFromDomain")((domain) => Effect.gen(function* () {
1656
- const zoneName = yield* decode$5(domain.name).pipe(Effect.mapError((cause) => failure$1("listTargets", cause.message, { reason: "response" })));
1657
- const nameservers = yield* Effect.forEach(domain.nameservers.length > 0 ? domain.nameservers : domain.intendedNameservers, (nameserver) => decode$5(nameserver).pipe(Effect.mapError((cause) => failure$1("listTargets", cause.message, { reason: "response" }))));
1658
- return {
1659
- accountId: domain.teamId ?? domain.userId,
1660
- accountKind: domain.teamId === null ? "personal" : "team",
1661
- evidence: {
1662
- nameservers,
1663
- status: domain.verified ? "active" : "pending",
1664
- zoneType: domain.serviceType
1665
- },
1666
- zoneId: domain.id,
1667
- zoneName
1668
- };
1669
- }));
1670
- function decode(schema, input, operation, response) {
1671
- return Schema.decodeUnknownEffect(schema)(input).pipe(Effect.mapError((cause) => failure$1(operation, `Vercel response did not match its API contract: ${cause.message}`, {
1672
- reason: "response",
1673
- status: response.status
1674
- })));
1675
- }
1676
- function apiFailure(input, operation, response) {
1677
- const detail = Schema.decodeUnknownOption(ErrorEnvelope)(input);
1678
- return failure$1(operation, detail._tag === "Some" ? detail.value.error.message : `Vercel request failed with HTTP ${response.status}`, {
1679
- ...detail._tag === "Some" ? { code: detail.value.error.code } : {},
1680
- reason: reason(response.status, detail._tag === "Some" ? detail.value.error.code : void 0),
1681
- ...rateLimit(response, detail._tag === "Some" ? detail.value.error : void 0),
1682
- status: response.status
1683
- });
1684
- }
1685
- function reason(status, code) {
1686
- if (status === 401 || code === "invalid_token") return "authentication";
1687
- if (status === 403) return "authorization";
1688
- if (status === 404 || code === "not_found") return "not_found";
1689
- if (status === 409 || code === "conflict") return "conflict";
1690
- if (status === 429 || code === "rate_limited") return "rate_limit";
1691
- if (status >= 500) return "response";
1692
- return "request";
1693
- }
1694
- function rateLimit(response, detail) {
1695
- const resetMs = detail?.limit?.resetMs;
1696
- const header = response.headers.get("x-ratelimit-reset");
1697
- const reset = resetMs ?? (header === null ? void 0 : Number(header) * 1e3);
1698
- return reset === void 0 || !Number.isFinite(reset) ? {} : { retryAfterMs: Math.max(0, reset - Date.now()) };
1699
- }
1700
- function failure$1(operation, message, fields = {}) {
1701
- return new Error$3({
1702
- ...fields,
1703
- message,
1704
- operation,
1705
- providerId: "vercel"
1706
- });
1707
- }
1708
- //#endregion
1709
- //#region src/providers/vercel/auth.ts
1710
- var auth_exports = /* @__PURE__ */ __exportAll({
1711
- contextCodec: () => contextCodec,
1712
- exchangeCode: () => exchangeCode,
1713
- integrationAuthentication: () => integrationAuthentication,
1714
- integrationFlow: () => integrationFlow,
1715
- integrationMethod: () => integrationMethod,
1716
- manifest: () => manifest,
1717
- restore: () => restore,
1718
- tokenConnectionMethod: () => tokenConnectionMethod,
1719
- tokenMethod: () => tokenMethod
1720
- });
1721
- const Context$1 = Schema.TaggedUnion({
1722
- personal: { installationId: Schema.NullOr(Schema.String) },
1723
- team: {
1724
- installationId: Schema.NullOr(Schema.String),
1725
- teamId: Schema.String
1726
- }
1727
- });
1728
- const contextCodec = codec("vercel.v1", Context$1);
1729
- /** Describes Vercel's caller-created personal access-token method. */
1730
- function tokenMethod(capabilities) {
1731
- return {
1732
- _tag: "token",
1733
- capabilities: [...capabilities],
1734
- instructionsUrl: "https://vercel.com/account/settings/tokens"
1735
- };
1736
- }
1737
- /** Describes Vercel's provider-specific integration installation flow. */
1738
- function integrationMethod(options) {
1739
- return {
1740
- _tag: "integration",
1741
- capabilities: [...options.capabilities],
1742
- installUrl: `https://vercel.com/integrations/${encodeURIComponent(options.slug)}/new`,
1743
- tokenEndpoint: "https://api.vercel.com/v2/oauth/access_token"
1744
- };
1745
- }
1746
- /** Creates the Vercel token and integration authorization manifest. */
1747
- function manifest(options) {
1748
- return {
1749
- methods: [tokenMethod(options.capabilities), integrationMethod(options)],
1750
- providerId: "vercel"
1751
- };
1752
- }
1753
- /** Exchanges Vercel's one-time integration code and preserves its account context. */
1754
- const exchangeCode = Effect.fn("VercelAuth.exchangeCode")((options) => Effect.gen(function* () {
1755
- const fetch = options.fetch ?? globalThis.fetch;
1756
- const baseUrl = (options.baseUrl ?? "https://api.vercel.com").replace(/\/$/, "");
1757
- const body = new URLSearchParams({
1758
- client_id: options.clientId,
1759
- client_secret: options.clientSecret.expose(),
1760
- code: options.code.expose(),
1761
- redirect_uri: options.redirectUri
1762
- });
1763
- const response = yield* Effect.tryPromise({
1764
- try: () => fetch(`${baseUrl}/v2/oauth/access_token`, {
1765
- body,
1766
- headers: {
1767
- Accept: "application/json",
1768
- "Content-Type": "application/x-www-form-urlencoded"
1769
- },
1770
- method: "POST"
1771
- }),
1772
- catch: () => failure("exchangeCode", "Vercel token exchange failed", "transport")
1773
- });
1774
- const input = yield* Effect.tryPromise({
1775
- try: () => response.json(),
1776
- catch: () => failure("exchangeCode", response.ok ? "Vercel returned a non-JSON token response" : `Vercel token exchange failed with HTTP ${response.status}`, response.ok ? "response" : response.status === 401 ? "authentication" : "request", response.status)
1777
- });
1778
- if (!response.ok) {
1779
- const detail = Schema.decodeUnknownOption(ErrorEnvelope)(input);
1780
- return yield* Effect.fail(failure("exchangeCode", detail._tag === "Some" ? detail.value.error.message : `Vercel token exchange failed with HTTP ${response.status}`, response.status === 401 ? "authentication" : "request", response.status, detail._tag === "Some" ? detail.value.error.code : void 0));
1781
- }
1782
- const token = yield* Schema.decodeUnknownEffect(IntegrationToken)(input).pipe(Effect.mapError((cause) => failure("exchangeCode", `Vercel token response did not match its API contract: ${cause.message}`, "response", response.status)));
1783
- return {
1784
- accessToken: make$6(token.access_token),
1785
- context: token.team_id === null ? AccountContext.personal() : AccountContext.team({ teamId: token.team_id }),
1786
- installationId: token.installation_id ?? options.configurationId ?? null,
1787
- userId: token.user_id
1788
- };
1789
- }));
1790
- /** Creates a provider-independent token connection method backed by Vercel validation. */
1791
- function tokenConnectionMethod(options) {
1792
- const requiredCapabilities = [...options.capabilities];
1793
- return Method$1.Token({
1794
- authenticate: Effect.fn("VercelAuth.authenticateToken")(function* (token) {
1795
- const validated = yield* make$4({
1796
- ...options,
1797
- token
1798
- }).validateToken();
1799
- const observedAt = new Date(yield* Clock.currentTimeMillis);
1800
- return {
1801
- capabilityEvidence: validated.capabilities.map((capability) => ({
1802
- capability,
1803
- evidence: Evidence$1.Introspected({ observedAt })
1804
- })),
1805
- credential: {
1806
- accessToken: token,
1807
- expiresAt: validated.expiresAt,
1808
- refreshToken: null,
1809
- tokenType: "bearer"
1810
- },
1811
- providerAccountId: validated.accountId,
1812
- providerContext: yield* contextCodec.encode(options.context._tag === "team" ? {
1813
- _tag: "team",
1814
- installationId: null,
1815
- teamId: options.context.teamId
1816
- } : {
1817
- _tag: "personal",
1818
- installationId: null
1819
- }),
1820
- scopes: [...validated.scopes]
1821
- };
1822
- }),
1823
- providerId: "vercel",
1824
- requiredCapabilities,
1825
- token: options.token
1826
- });
1827
- }
1828
- /** Converts a completed Vercel Integration exchange into canonical connection authentication. */
1829
- const integrationAuthentication = Effect.fn("VercelAuth.integrationAuthentication")(function* (options) {
1830
- const exchanged = yield* exchangeCode(options);
1831
- const observedAt = new Date(yield* Clock.currentTimeMillis);
1832
- return {
1833
- capabilityEvidence: options.capabilities.map((capability) => ({
1834
- capability,
1835
- evidence: Evidence$1.Introspected({ observedAt })
1836
- })),
1837
- credential: {
1838
- accessToken: exchanged.accessToken,
1839
- expiresAt: null,
1840
- refreshToken: null,
1841
- tokenType: "bearer"
1842
- },
1843
- providerAccountId: exchanged.context._tag === "team" ? exchanged.context.teamId : exchanged.userId,
1844
- providerContext: yield* contextCodec.encode(exchanged.context._tag === "team" ? {
1845
- _tag: "team",
1846
- installationId: exchanged.installationId,
1847
- teamId: exchanged.context.teamId
1848
- } : {
1849
- _tag: "personal",
1850
- installationId: exchanged.installationId
1851
- }),
1852
- scopes: []
1853
- };
1854
- });
1855
- /** Restore a credential-scoped Vercel session from persisted authorization state. */
1856
- function restore(options) {
1857
- return Effect.gen(function* () {
1858
- if (options.authorization.providerId !== "vercel") return yield* Effect.fail(failure("restore", "Provider authorization belongs to another provider", "authorization"));
1859
- if (options.authorization.revocation._tag !== "Active") return yield* Effect.fail(failure("restore", "Vercel authorization is pending revocation", "authorization"));
1860
- const missingCapability = options.authorization.requiredCapabilities.find((capability) => !options.authorization.capabilityEvidence.some((item) => item.capability === capability));
1861
- if (missingCapability !== void 0) return yield* Effect.fail(failure("restore", `Vercel authorization lacks evidence for ${missingCapability}`, "authorization"));
1862
- if (options.credential.expiresAt !== null && (Number.isNaN(options.credential.expiresAt.valueOf()) || options.credential.expiresAt <= /* @__PURE__ */ new Date())) return yield* Effect.fail(failure("restore", "Vercel authorization has expired", "authentication"));
1863
- const context = yield* contextCodec.decode(options.authorization.providerContext).pipe(Effect.mapError((cause) => failure("restore", cause.message, "response")));
1864
- return make$4({
1865
- ...options.baseUrl === void 0 ? {} : { baseUrl: options.baseUrl },
1866
- capabilities: options.authorization.capabilityEvidence.map(({ capability }) => capability),
1867
- ...options.fetch === void 0 ? {} : { fetch: options.fetch },
1868
- context: context._tag === "team" ? AccountContext.team({ teamId: context.teamId }) : AccountContext.personal(),
1869
- token: options.credential.accessToken
1870
- });
1871
- });
1872
- }
1873
- /** Creates Vercel Integration's implementation of the common interactive connection capability. */
1874
- function integrationFlow(options) {
1875
- const method = integrationMethod(options);
1876
- const Payload = Schema.fromJsonString(Schema.Struct({ state: Schema.String }));
1877
- return {
1878
- complete: Effect.fn("VercelAuth.integrationFlow.complete")(function* (payload, callbackUrl) {
1879
- const continuation = yield* Schema.decodeUnknownEffect(Payload)(payload.expose()).pipe(Effect.mapError(() => new Error$2({
1880
- category: "authorization",
1881
- message: "Vercel Integration continuation payload is invalid",
1882
- operation: "VercelAuth.integrationFlow.complete",
1883
- retry: "after-user-action"
1884
- })));
1885
- const code = callbackUrl.searchParams.get("code");
1886
- const configurationId = callbackUrl.searchParams.get("configurationId");
1887
- if (callbackUrl.searchParams.get("state") !== continuation.state || code === null || configurationId === null) return yield* new Error$2({
1888
- category: "authorization",
1889
- message: "Vercel Integration callback does not match its continuation",
1890
- operation: "VercelAuth.integrationFlow.complete",
1891
- retry: "after-user-action"
1892
- });
1893
- const authentication = yield* integrationAuthentication({
1894
- ...options.baseUrl === void 0 ? {} : { baseUrl: options.baseUrl },
1895
- capabilities: options.capabilities,
1896
- clientId: options.clientId,
1897
- clientSecret: options.clientSecret,
1898
- code: make$6(code),
1899
- configurationId,
1900
- ...options.fetch === void 0 ? {} : { fetch: options.fetch },
1901
- redirectUri: options.redirectUri
1902
- });
1903
- const callbackTeamId = callbackUrl.searchParams.get("teamId");
1904
- if (callbackTeamId !== null) {
1905
- const context = yield* contextCodec.decode(authentication.providerContext).pipe(Effect.mapError((cause) => new Error$2({
1906
- category: "provider",
1907
- message: cause.message,
1908
- operation: "VercelAuth.integrationFlow.complete",
1909
- retry: "unknown"
1910
- })));
1911
- if (context._tag !== "team" || context.teamId !== callbackTeamId) return yield* new Error$2({
1912
- category: "authorization",
1913
- message: "Vercel Integration callback team does not match the exchanged installation",
1914
- operation: "VercelAuth.integrationFlow.complete",
1915
- retry: "after-user-action"
1916
- });
1917
- }
1918
- return authentication;
1919
- }),
1920
- method: "integration",
1921
- providerId: "vercel",
1922
- requiredCapabilities: [...options.capabilities],
1923
- start: (continuationId) => {
1924
- const authorizationUrl = new URL(method.installUrl);
1925
- authorizationUrl.searchParams.set("source", "external");
1926
- authorizationUrl.searchParams.set("state", continuationId);
1927
- return Effect.succeed({
1928
- authorizationUrl,
1929
- payload: make$6(JSON.stringify({ state: continuationId }))
1930
- });
1931
- }
1932
- };
1933
- }
1934
- function failure(operation, message, reason, status, code) {
1935
- return new Error$3({
1936
- ...code === void 0 ? {} : { code },
1937
- message,
1938
- operation,
1939
- providerId: "vercel",
1940
- reason,
1941
- ...status === void 0 ? {} : { status }
1942
- });
1943
- }
1944
- //#endregion
1945
- //#region src/verification/dns-data.ts
1946
- var dns_data_exports = /* @__PURE__ */ __exportAll({ parse: () => parse });
1947
- const CanonicalAddress = Schema.String.pipe(Schema.decodeTo(Schema.String, SchemaTransformation.transform({
1948
- decode: (value) => value.trim().toLowerCase(),
1949
- encode: (value) => value
1950
- })));
1951
- const CanonicalDomain = Schema.String.pipe(Schema.decodeTo(Schema.String, SchemaTransformation.transformOrFail({
1952
- decode: (value, options) => Effect.try({
1953
- try: () => parse$1(value).toString(),
1954
- catch: (cause) => new SchemaIssue.InvalidValue({ message: cause instanceof Error ? cause.message : String(cause) }, value, options)
1955
- }),
1956
- encode: (value) => Effect.succeed(value)
1957
- })));
1958
- const CanonicalMx = tokenizedDomain(2, 1);
1959
- const CanonicalSrv = tokenizedDomain(4, 3);
1960
- const CanonicalTxt = Schema.String.pipe(Schema.decodeTo(Schema.String, SchemaTransformation.transform({
1961
- decode: (value) => {
1962
- const trimmed = value.trim();
1963
- const chunks = [...trimmed.matchAll(/"((?:\\.|[^"])*)"/g)];
1964
- return chunks.length === 0 ? trimmed : chunks.map((match) => (match[1] ?? "").replace(/\\"/g, "\"").replace(/\\\\/g, "\\")).join("");
1965
- },
1966
- encode: (value) => value
1967
- })));
1968
- const CanonicalCaa = Schema.String.pipe(Schema.decodeTo(Schema.String, SchemaTransformation.transform({
1969
- decode: (value) => value.trim().replace(/\s+"([\s\S]*)"$/, " $1"),
1970
- encode: (value) => value
1971
- })));
1972
- function parse(type, input) {
1973
- const schema = (() => {
1974
- switch (type) {
1975
- case "A":
1976
- case "AAAA": return CanonicalAddress;
1977
- case "CNAME":
1978
- case "NS": return CanonicalDomain;
1979
- case "MX": return CanonicalMx;
1980
- case "SRV": return CanonicalSrv;
1981
- case "TXT": return CanonicalTxt;
1982
- case "CAA": return CanonicalCaa;
1983
- }
1984
- })();
1985
- try {
1986
- return Schema.decodeUnknownSync(schema)(input);
1987
- } catch (cause) {
1988
- throw new Error$1({ message: cause instanceof Error ? cause.message : String(cause) });
1989
- }
1990
- }
1991
- function tokenizedDomain(length, domainIndex) {
1992
- return Schema.String.pipe(Schema.decodeTo(Schema.String, SchemaTransformation.transformOrFail({
1993
- decode: (value, options) => Effect.try({
1994
- try: () => {
1995
- const parts = value.trim().split(/\s+/);
1996
- if (parts.length !== length) throw new Error("DNS record data has an invalid field count");
1997
- const domain = parts[domainIndex];
1998
- if (domain === void 0) throw new Error("DNS record target is missing");
1999
- parts[domainIndex] = parse$1(domain);
2000
- return parts.join(" ");
2001
- },
2002
- catch: (cause) => new SchemaIssue.InvalidValue({ message: cause instanceof Error ? cause.message : String(cause) }, value, options)
2003
- }),
2004
- encode: (value) => Effect.succeed(value)
2005
- })));
2006
- }
2007
- //#endregion
2008
- //#region src/verification/doh.ts
2009
- var doh_exports = /* @__PURE__ */ __exportAll({
2010
- layer: () => layer$2,
2011
- make: () => make$3,
2012
- toAsync: () => toAsync$2
2013
- });
2014
- function make$3(options) {
2015
- const fetch = options.fetch ?? globalThis.fetch;
2016
- const timeoutMs = options.timeoutMs ?? 5e3;
2017
- return { resolve: Effect.fn("DnsOverHttps.resolve")((query) => Effect.tryPromise({
2018
- try: (effectSignal) => request({
2019
- effectSignal,
2020
- fetch,
2021
- query,
2022
- timeoutMs,
2023
- endpoint: options.endpoint
2024
- }),
2025
- catch: (cause) => cause instanceof Error$4 ? cause : new Error$4({
2026
- cause,
2027
- message: cause instanceof Error ? cause.message : "DNS resolution failed",
2028
- reason: "transport"
2029
- })
2030
- }).pipe(Effect.flatMap((message) => decodeResolution(query, message)))) };
2031
- }
2032
- const layer$2 = (options) => Layer.succeed(Service$2, make$3(options));
2033
- const toAsync$2 = (options) => toAsync$5(make$3(options));
2034
- function decodeResolution(query, message) {
2035
- return Effect.try({
2036
- try: () => DnsPacket.decode(message),
2037
- catch: (cause) => new Error$4({
2038
- cause,
2039
- message: "DoH returned an invalid DNS message",
2040
- reason: "response"
2041
- })
2042
- }).pipe(Effect.flatMap((packet) => validatePacket(query, packet)), Effect.flatMap(decodePacket));
2043
- }
2044
- function decodePacket(packet) {
2045
- if (packet.rcode === "NXDOMAIN") return Effect.succeed(Resolution$1.nodata());
2046
- if (packet.rcode !== "NOERROR") return Effect.fail(new Error$4({
2047
- message: `DNS resolver returned ${packet.rcode ?? "an unknown response code"}`,
2048
- reason: "response"
2049
- }));
2050
- if (packet.answers === void 0 || packet.answers.length === 0) return Effect.succeed(Resolution$1.nodata());
2051
- return Effect.forEach(packet.answers, decodeAnswer, { concurrency: "unbounded" }).pipe(Effect.map((answers) => {
2052
- const supportedAnswers = answers.filter((answer) => answer !== null);
2053
- return supportedAnswers.length === 0 ? Resolution$1.nodata() : Resolution$1.answer({ answers: supportedAnswers });
2054
- }));
2055
- }
2056
- function validatePacket(query, packet) {
2057
- return Effect.try({
2058
- try: () => {
2059
- if (packet.type !== "response") throw new Error("DoH returned a DNS query");
2060
- if (packet.id !== 0) throw new Error("DoH response used an unexpected message ID");
2061
- if (packet.flag_tc) throw new Error("DoH returned a truncated DNS response");
2062
- const questions = packet.questions ?? [];
2063
- if (questions.length !== 1) throw new Error("DoH returned an unexpected question count");
2064
- const question = questions[0];
2065
- if (question === void 0) throw new Error("DoH response omitted the DNS question");
2066
- if (question.class !== "IN" || question.type !== query.type || parse$1(question.name) !== query.name) throw new Error("DoH response did not match the DNS question");
2067
- return packet;
2068
- },
2069
- catch: (cause) => new Error$4({
2070
- cause,
2071
- message: cause instanceof Error ? cause.message : "DoH returned an invalid DNS response",
2072
- reason: "response"
2073
- })
2074
- });
2075
- }
2076
- function decodeAnswer(answer) {
2077
- return Effect.gen(function* () {
2078
- if (answer.class !== "IN") return null;
2079
- const decoded = yield* Effect.try({
2080
- try: () => answerData(answer),
2081
- catch: (cause) => new Error$4({
2082
- cause,
2083
- message: "DoH returned invalid DNS record data",
2084
- reason: "response"
2085
- })
2086
- });
2087
- if (decoded === void 0) return null;
2088
- const name = yield* decode$5(answer.name);
2089
- const data = yield* Effect.try({
2090
- try: () => parse(decoded.type, decoded.data),
2091
- catch: (cause) => new Error$4({
2092
- cause,
2093
- message: "DoH returned invalid DNS record data",
2094
- reason: "response"
2095
- })
2096
- });
2097
- if (answer.ttl === void 0) return yield* new Error$4({
2098
- message: "DoH response omitted the DNS record TTL",
2099
- reason: "response"
2100
- });
2101
- return {
2102
- data,
2103
- name,
2104
- ttl: answer.ttl,
2105
- type: decoded.type
2106
- };
2107
- }).pipe(Effect.mapError((cause) => cause instanceof Error$4 ? cause : new Error$4({
2108
- cause,
2109
- message: cause.message,
2110
- reason: "response"
2111
- })));
2112
- }
2113
- function answerData(answer) {
2114
- switch (answer.type) {
2115
- case "A":
2116
- case "AAAA":
2117
- case "CNAME":
2118
- case "NS": return {
2119
- data: answer.data,
2120
- type: answer.type
2121
- };
2122
- case "CAA": return {
2123
- data: `${answer.data.flags ?? 0} ${answer.data.tag} ${answer.data.value}`,
2124
- type: answer.type
2125
- };
2126
- case "MX": return {
2127
- data: `${requiredNumber(answer.data.preference, "MX preference")} ${answer.data.exchange}`,
2128
- type: answer.type
2129
- };
2130
- case "SRV": return {
2131
- data: [
2132
- requiredNumber(answer.data.priority, "SRV priority"),
2133
- requiredNumber(answer.data.weight, "SRV weight"),
2134
- requiredNumber(answer.data.port, "SRV port"),
2135
- answer.data.target
2136
- ].join(" "),
2137
- type: answer.type
2138
- };
2139
- case "TXT": return {
2140
- data: decodeTxt(answer.data),
2141
- type: answer.type
2142
- };
2143
- default: return;
2144
- }
2145
- }
2146
- function decodeTxt(data) {
2147
- const encoded = (Array.isArray(data) ? data : [data]).map((chunk) => typeof chunk === "string" ? new TextEncoder().encode(chunk) : chunk);
2148
- const length = encoded.reduce((total, chunk) => total + chunk.length, 0);
2149
- const joined = new Uint8Array(length);
2150
- let offset = 0;
2151
- for (const chunk of encoded) {
2152
- joined.set(chunk, offset);
2153
- offset += chunk.length;
2154
- }
2155
- return new TextDecoder("utf-8", { fatal: true }).decode(joined);
2156
- }
2157
- function requiredNumber(value, field) {
2158
- if (value === void 0) throw new Error(`DoH response omitted ${field}`);
2159
- return value;
2160
- }
2161
- async function request(input) {
2162
- const controller = new AbortController();
2163
- let timedOut = false;
2164
- const abortFromEffect = () => controller.abort(input.effectSignal.reason);
2165
- const abortFromHost = () => controller.abort(input.query.signal?.reason);
2166
- input.effectSignal.addEventListener("abort", abortFromEffect, { once: true });
2167
- input.query.signal?.addEventListener("abort", abortFromHost, { once: true });
2168
- const timer = setTimeout(() => {
2169
- timedOut = true;
2170
- controller.abort(/* @__PURE__ */ new Error("DNS resolution timed out"));
2171
- }, input.timeoutMs);
2172
- try {
2173
- const query = Uint8Array.from(DnsPacket.encode({
2174
- flags: DnsPacket.RECURSION_DESIRED,
2175
- id: 0,
2176
- questions: [{
2177
- name: input.query.name,
2178
- type: input.query.type
2179
- }],
2180
- type: "query"
2181
- }));
2182
- const response = await input.fetch(new URL(input.endpoint), {
2183
- body: query,
2184
- headers: {
2185
- accept: "application/dns-message",
2186
- "content-type": "application/dns-message"
2187
- },
2188
- method: "POST",
2189
- signal: controller.signal
2190
- });
2191
- if (!response.ok) throw new Error$4({
2192
- message: `DoH returned HTTP ${response.status}`,
2193
- reason: "transport"
2194
- });
2195
- const contentType = response.headers.get("content-type")?.split(";", 1)[0]?.trim().toLowerCase();
2196
- if (contentType !== "application/dns-message") throw new Error$4({
2197
- message: `DoH returned unsupported content type ${contentType ?? "<missing>"}`,
2198
- reason: "response"
2199
- });
2200
- return new Uint8Array(await response.arrayBuffer());
2201
- } catch (cause) {
2202
- if (timedOut) throw new Error$4({
2203
- message: "DNS query timed out",
2204
- reason: "timeout"
2205
- });
2206
- throw cause;
2207
- } finally {
2208
- clearTimeout(timer);
2209
- input.effectSignal.removeEventListener("abort", abortFromEffect);
2210
- input.query.signal?.removeEventListener("abort", abortFromHost);
2211
- }
2212
- }
2213
- //#endregion
2214
- //#region src/verification/cloudflare-doh.ts
2215
- var cloudflare_doh_exports = /* @__PURE__ */ __exportAll({
2216
- layer: () => layer$1,
2217
- make: () => make$2,
2218
- toAsync: () => toAsync$1
2219
- });
2220
- const endpoint$1 = "https://cloudflare-dns.com/dns-query";
2221
- function make$2(options = {}) {
2222
- return make$3({
2223
- ...options,
2224
- endpoint: options.endpoint ?? endpoint$1
2225
- });
2226
- }
2227
- const layer$1 = (options = {}) => Layer.succeed(Service$2, make$2(options));
2228
- const toAsync$1 = (options = {}) => toAsync$5(make$2(options));
2229
- //#endregion
2230
- //#region src/verification/google-doh.ts
2231
- var google_doh_exports = /* @__PURE__ */ __exportAll({
2232
- layer: () => layer,
2233
- make: () => make$1,
2234
- toAsync: () => toAsync
2235
- });
2236
- const endpoint = "https://dns.google/dns-query";
2237
- function make$1(options = {}) {
2238
- return make$3({
2239
- ...options,
2240
- endpoint: options.endpoint ?? endpoint
2241
- });
2242
- }
2243
- const layer = (options = {}) => Layer.succeed(Service$2, make$1(options));
2244
- const toAsync = (options = {}) => toAsync$5(make$1(options));
2245
- //#endregion
2246
- //#region src/verification/resolver-pool.ts
2247
- var resolver_pool_exports = /* @__PURE__ */ __exportAll({
2248
- Observation: () => Observation,
2249
- Policy: () => Policy,
2250
- Service: () => Service,
2251
- defaultLayer: () => defaultLayer,
2252
- defaultMake: () => defaultMake,
2253
- make: () => make
2254
- });
2255
- const Observation = Data.taggedEnum();
2256
- const PolicyVariants = Data.taggedEnum();
2257
- const QuorumMinimum = Schema.Int.check(Schema.isGreaterThanOrEqualTo(1));
2258
- const PolicySchema = Schema.TaggedUnion({
2259
- AllMatch: {},
2260
- AnyMatch: {},
2261
- Quorum: { minimum: QuorumMinimum }
2262
- });
2263
- const Policy = {
2264
- AllMatch: PolicyVariants.AllMatch,
2265
- AnyMatch: PolicyVariants.AnyMatch,
2266
- Quorum: ({ minimum }) => PolicyVariants.Quorum({ minimum: Schema.decodeUnknownSync(QuorumMinimum)(minimum) }),
2267
- Schema: PolicySchema
2268
- };
2269
- var Service = class extends Context.Service()("@domainkit/DnsResolverPool") {};
2270
- function make(entries) {
2271
- return Service.of({ observe: Effect.fn("DnsResolverPool.observe")((query) => Effect.forEach(entries, (entry) => observe$1(entry, query), { concurrency: "unbounded" })) });
2272
- }
2273
- /** Cloudflare and Google RFC wire-format DoH resolvers. */
2274
- function defaultMake(options = {}) {
2275
- const timeoutMs = options.timeoutMs ?? 5e3;
2276
- return make([{
2277
- id: "cloudflare",
2278
- resolver: make$2(options),
2279
- timeoutMs
2280
- }, {
2281
- id: "google",
2282
- resolver: make$1(options),
2283
- timeoutMs
2284
- }]);
2285
- }
2286
- const defaultLayer = (options = {}) => Layer.succeed(Service, defaultMake(options));
2287
- function observe$1(entry, query) {
2288
- const timeoutMs = entry.timeoutMs ?? 5e3;
2289
- return entry.resolver.resolve(query).pipe(Effect.timeout(timeoutMs), Effect.match({
2290
- onFailure: (failure) => {
2291
- if (failure._tag === "TimeoutError" || failure._tag === "ResolverError" && failure.reason === "timeout") return Observation.TimedOut({
2292
- resolverId: entry.id,
2293
- timeoutMs
2294
- });
2295
- return Observation.Failed({
2296
- message: failure.message,
2297
- reason: failure.reason === "response" ? "response" : "transport",
2298
- resolverId: entry.id
2299
- });
2300
- },
2301
- onSuccess: (resolution) => resolution._tag === "nodata" ? Observation.NoData({ resolverId: entry.id }) : Observation.Answer({
2302
- answers: resolution.answers,
2303
- resolverId: entry.id
2304
- })
2305
- }));
2306
- }
2307
- //#endregion
2308
- //#region src/verification/verify.ts
2309
- var verify_exports = /* @__PURE__ */ __exportAll({
2310
- Provider: () => Provider,
2311
- ProviderObservation: () => ProviderObservation,
2312
- PublicDns: () => PublicDns,
2313
- PublicDnsObservation: () => PublicDnsObservation,
2314
- Result: () => Result,
2315
- observe: () => observe
2316
- });
2317
- const PublicDns = Data.taggedEnum();
2318
- const Provider = Data.taggedEnum();
2319
- const ProviderObservation = Data.taggedEnum();
2320
- const PublicDnsObservation = Data.taggedEnum();
2321
- const Result = Data.taggedEnum();
2322
- function observe(input) {
2323
- return observeEffect(input);
2324
- }
2325
- const observeEffect = Effect.fn("Verification.observe")(function* (input) {
2326
- const publicDns = input.publicDns ?? PublicDns.Enabled({});
2327
- const provider = input.provider ?? Provider.Disabled();
2328
- const publicEffect = publicDns._tag === "Disabled" ? Effect.succeed(null) : observePublicDns(input.record, publicDns.policy ?? Policy.AnyMatch());
2329
- const providerEffect = provider._tag === "Disabled" ? Effect.succeed(null) : Effect.flatMap(Service$3, (service) => observeProvider(service, provider.zone, input.record).pipe(Effect.catch((failure) => Effect.succeed(ProviderObservation.Unavailable({ message: failure.message })))));
2330
- const [providerObservation, publicDnsObservation] = yield* Effect.all([providerEffect, publicEffect], { concurrency: "unbounded" });
2331
- return aggregate({
2332
- provider: providerObservation,
2333
- publicDns: publicDnsObservation
2334
- });
2335
- });
2336
- function observeProvider(provider, zone, requirement) {
2337
- return provider.listRecords(zone).pipe(Effect.map((records) => {
2338
- if (records.some((existing) => existing._tag !== "Opaque" && equals(existing, requirement))) return ProviderObservation.Matched();
2339
- const sameSet = records.filter((existing) => existing._tag !== "Opaque" && existing.name === requirement.name && existing._tag === requirement._tag);
2340
- return sameSet.length === 0 ? ProviderObservation.Pending() : ProviderObservation.Mismatch({ records: sameSet });
2341
- }));
2342
- }
2343
- function observePublicDns(requirement, policy) {
2344
- return Effect.gen(function* () {
2345
- const validatedPolicy = yield* Schema.decodeUnknownEffect(Policy.Schema)(policy).pipe(Effect.mapError((cause) => new Error$1({ message: cause.message })));
2346
- const configuredPool = yield* Effect.serviceOption(Service);
2347
- const evidence = yield* Option.getOrElse(configuredPool, () => defaultMake()).observe({
2348
- name: requirement.name,
2349
- type: requirement._tag
2350
- });
2351
- if (validatedPolicy._tag === "Quorum" && validatedPolicy.minimum > evidence.length) return yield* new Error$1({ message: `Quorum minimum ${validatedPolicy.minimum} exceeds the ${evidence.length} configured resolvers` });
2352
- return evaluatePublicDns(requirement, validatedPolicy, evidence);
2353
- });
2354
- }
2355
- function evaluatePublicDns(requirement, policy, evidence) {
2356
- const matchedResolverIds = evidence.flatMap((observation) => observation._tag === "Answer" && answersMatch(requirement, observation.answers) ? [observation.resolverId] : []);
2357
- const required = policy._tag === "AnyMatch" ? 1 : policy._tag === "AllMatch" ? evidence.length : policy.minimum;
2358
- if (required > 0 && matchedResolverIds.length >= required) return PublicDnsObservation.Verified({
2359
- evidence,
2360
- matchedResolverIds
2361
- });
2362
- const unavailable = evidence.filter((observation) => observation._tag === "TimedOut" || observation._tag === "Failed").length;
2363
- if (unavailable > 0 && matchedResolverIds.length + unavailable >= required) return PublicDnsObservation.Unavailable({ evidence });
2364
- if (evidence.some((observation) => observation._tag === "Answer" && !answersMatch(requirement, observation.answers))) return PublicDnsObservation.Mismatch({ evidence });
2365
- if (evidence.some((observation) => observation._tag === "NoData")) return PublicDnsObservation.Pending({ evidence });
2366
- return PublicDnsObservation.Unavailable({ evidence });
2367
- }
2368
- function answersMatch(requirement, answers) {
2369
- const expected = parse(requirement._tag, recordValue(requirement));
2370
- return answers.some((answer) => answer.name === requirement.name && answer.type === requirement._tag && parse(requirement._tag, answer.data) === expected);
2371
- }
2372
- function aggregate(evidence) {
2373
- const requested = [evidence.provider, evidence.publicDns].filter((observation) => observation !== null);
2374
- if (requested.length === 0) return Result.NotObserved(evidence);
2375
- if (requested.every((observation) => observation._tag === "Matched" || observation._tag === "Verified")) return Result.Verified(evidence);
2376
- if (requested.some((observation) => observation._tag === "Unavailable")) return Result.Unavailable(evidence);
2377
- if (requested.some((observation) => observation._tag === "Mismatch")) return Result.Mismatch(evidence);
2378
- return Result.Pending(evidence);
2379
- }
2380
- function recordValue(requirement) {
2381
- const data$1 = data(requirement);
2382
- switch (requirement._tag) {
2383
- case "A":
2384
- case "AAAA": return String(data$1.address);
2385
- case "CNAME":
2386
- case "NS": return String(data$1.target);
2387
- case "TXT": return String(data$1.value);
2388
- case "MX": return `${data$1.priority} ${data$1.exchange}`;
2389
- case "CAA": return `${data$1.flags} ${data$1.tag} ${data$1.value}`;
2390
- case "SRV": return `${data$1.priority} ${data$1.weight} ${data$1.port} ${data$1.target}`;
2391
- }
2392
- }
2393
- //#endregion
2394
- export { decode$4 as $, client_exports as A, tokenConnectionMethod$1 as B, integrationFlow as C, tokenConnectionMethod as D, restore as E, oauthFlow as F, make$5 as G, tokenValidator as H, oauthMethod as I, session_exports as J, authorize as K, refreshCredential as L, make$4 as M, auth_exports$1 as N, tokenMethod as O, manifest$1 as P, Schema$1 as Q, restore$1 as R, exchangeCode as S, manifest as T, client_exports$1 as U, tokenMethod$1 as V, discovery$1 as W, secret_exports as X, selection_exports as Y, Method as Z, toAsync$1 as _, Result as a, dns_data_exports as b, Observation as c, defaultMake as d, manifest_exports as et, make as f, cloudflare_doh_exports as g, toAsync as h, PublicDnsObservation as i, discovery as j, AccountContext as k, Policy as l, google_doh_exports as m, ProviderObservation as n, version as nt, observe as o, resolver_pool_exports as p, connection_authorization_exports as q, PublicDns as r, verify_exports as s, Provider as t, diagnostic_exports as tt, Service as u, doh_exports as v, integrationMethod as w, auth_exports as x, toAsync$2 as y, subjectResolver as z };
2395
-
2396
- //# sourceMappingURL=verify-DDnK8U7C.mjs.map