domainkit 0.8.0 → 0.9.1

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