domainkit 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/README.md +26 -26
  2. package/dist/index.d.mts +639 -187
  3. package/dist/index.mjs +301 -300
  4. package/dist/index.mjs.map +1 -1
  5. package/dist/promise.d.mts +464 -0
  6. package/dist/promise.mjs +636 -0
  7. package/dist/promise.mjs.map +1 -0
  8. package/dist/{resolver-CxE-VDw4.mjs → resolver-CvK7JoJM.mjs} +401 -54
  9. package/dist/resolver-CvK7JoJM.mjs.map +1 -0
  10. package/dist/{resolver-Dc0hwV-J.d.mts → resolver-uqe1h5Vz.d.mts} +1513 -25
  11. package/dist/testing.d.mts +4 -5
  12. package/dist/testing.mjs +17 -3
  13. package/dist/testing.mjs.map +1 -1
  14. package/dist/verify-B00c81-n.mjs +2420 -0
  15. package/dist/verify-B00c81-n.mjs.map +1 -0
  16. package/dist/{verify-Dls29YC-.d.mts → verify-CkgVrwyl.d.mts} +318 -21
  17. package/package.json +6 -30
  18. package/dist/auth-BR-19zj-.mjs +0 -738
  19. package/dist/auth-BR-19zj-.mjs.map +0 -1
  20. package/dist/auth-g-waCHcz.mjs +0 -671
  21. package/dist/auth-g-waCHcz.mjs.map +0 -1
  22. package/dist/authorization-OeaSR47S.mjs +0 -284
  23. package/dist/authorization-OeaSR47S.mjs.map +0 -1
  24. package/dist/canonical-json-CpvqGMcr.mjs +0 -57
  25. package/dist/canonical-json-CpvqGMcr.mjs.map +0 -1
  26. package/dist/cloudflare-BrZPU9li.d.mts +0 -32
  27. package/dist/cloudflare-CGmasR8A.mjs +0 -69
  28. package/dist/cloudflare-CGmasR8A.mjs.map +0 -1
  29. package/dist/cloudflare.d.mts +0 -3
  30. package/dist/cloudflare.mjs +0 -2
  31. package/dist/connection-BfkloPZy.d.mts +0 -186
  32. package/dist/connection-BwtOwpH6.mjs +0 -195
  33. package/dist/connection-BwtOwpH6.mjs.map +0 -1
  34. package/dist/connection-CjNQe_E-.mjs +0 -58
  35. package/dist/connection-CjNQe_E-.mjs.map +0 -1
  36. package/dist/connection-api-DNuEZ_jR.d.mts +0 -7
  37. package/dist/dns-record-BLeqo56C.mjs +0 -289
  38. package/dist/dns-record-BLeqo56C.mjs.map +0 -1
  39. package/dist/effect-cloudflare.d.mts +0 -2
  40. package/dist/effect-cloudflare.mjs +0 -2
  41. package/dist/effect-vercel.d.mts +0 -2
  42. package/dist/effect-vercel.mjs +0 -2
  43. package/dist/effect.d.mts +0 -36
  44. package/dist/effect.mjs +0 -51
  45. package/dist/effect.mjs.map +0 -1
  46. package/dist/index-BHWRTThN.d.mts +0 -159
  47. package/dist/index-D3PVknwE.d.mts +0 -145
  48. package/dist/resolver-CxE-VDw4.mjs.map +0 -1
  49. package/dist/vercel-BsNDu4Np.d.mts +0 -31
  50. package/dist/vercel-CfoJaaCu.mjs +0 -60
  51. package/dist/vercel-CfoJaaCu.mjs.map +0 -1
  52. package/dist/vercel.d.mts +0 -3
  53. package/dist/vercel.mjs +0 -2
  54. package/dist/verify-BKbvq7IN.mjs +0 -642
  55. package/dist/verify-BKbvq7IN.mjs.map +0 -1
  56. package/dist/zone-discovery-BPnH3sLU.d.mts +0 -1397
  57. package/dist/zones-DKHTpX9C.mjs +0 -19
  58. package/dist/zones-DKHTpX9C.mjs.map +0 -1
@@ -1,738 +0,0 @@
1
- import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
- import { E as decode$2, c as Opaque, h as decode$3, y as Error } from "./dns-record-BLeqo56C.mjs";
3
- import { f as Value, g as Method, h as Error$1, p as make$1, r as Evidence, u as codec } from "./authorization-OeaSR47S.mjs";
4
- import { t as candidates } from "./zones-DKHTpX9C.mjs";
5
- import { Clock, Crypto, Effect, Schema } from "effect";
6
- import * as oauth from "oauth4webapi";
7
- //#region src/auth/authorization-code.ts
8
- const start = Effect.fn("AuthorizationCode.start")(function* (input) {
9
- const crypto = yield* Crypto.Crypto;
10
- const codeVerifier = base64Url(yield* randomBytes(crypto, 32));
11
- const challenge = base64Url(yield* digest(crypto, codeVerifier));
12
- const authorizationUrl = new URL(input.method.authorizationServer.authorization_endpoint);
13
- authorizationUrl.search = new URLSearchParams({
14
- client_id: input.client.clientId,
15
- code_challenge: challenge,
16
- code_challenge_method: "S256",
17
- redirect_uri: input.redirectUri,
18
- response_type: "code",
19
- scope: input.method.scopes.join(" "),
20
- state: input.state
21
- }).toString();
22
- return {
23
- authorizationUrl,
24
- payload: make$1(JSON.stringify({
25
- codeVerifier,
26
- redirectUri: input.redirectUri,
27
- state: input.state
28
- }))
29
- };
30
- });
31
- const complete = Effect.fn("AuthorizationCode.complete")(function* (input) {
32
- const payload = yield* decodePayload(input.payload);
33
- if (input.callbackUrl.searchParams.get("state") !== payload.state) return yield* failure$2("Authorization callback state does not match its continuation");
34
- const server = input.method.authorizationServer;
35
- const client = { client_id: input.client.clientId };
36
- const authentication = yield* clientAuthentication(input.method, input.client);
37
- return yield* Effect.tryPromise({
38
- try: async (signal) => {
39
- const callback = oauth.validateAuthResponse(server, client, input.callbackUrl, payload.state);
40
- const response = await oauth.authorizationCodeGrantRequest(server, client, authentication, callback, payload.redirectUri, payload.codeVerifier, requestOptions(input.fetch, signal));
41
- return oauth.processAuthorizationCodeResponse(server, client, response);
42
- },
43
- catch: (cause) => new Error$1({
44
- category: "provider",
45
- message: cause instanceof globalThis.Error ? cause.name : "OAuth provider request failed",
46
- operation: "AuthorizationCode.complete",
47
- retry: "unknown"
48
- })
49
- });
50
- });
51
- const PayloadSchema = Schema.Struct({
52
- codeVerifier: Schema.String,
53
- redirectUri: Schema.String,
54
- state: Schema.String
55
- });
56
- function decodePayload(payload) {
57
- return Schema.decodeUnknownEffect(Schema.fromJsonString(PayloadSchema))(payload.expose()).pipe(Effect.mapError(() => new Error$1({
58
- category: "authorization",
59
- message: "OAuth continuation payload is invalid",
60
- operation: "AuthorizationCode",
61
- retry: "after-user-action"
62
- })));
63
- }
64
- function clientAuthentication(method, client) {
65
- switch (method.clientAuth) {
66
- case "none": return Effect.succeed(oauth.None());
67
- case "client_secret_basic": return client.clientSecret === void 0 ? failure$2("OAuth client secret is required") : Effect.succeed(oauth.ClientSecretBasic(client.clientSecret.expose()));
68
- case "client_secret_post": return client.clientSecret === void 0 ? failure$2("OAuth client secret is required") : Effect.succeed(oauth.ClientSecretPost(client.clientSecret.expose()));
69
- }
70
- }
71
- function requestOptions(fetchImplementation, signal) {
72
- return fetchImplementation === void 0 ? { signal } : {
73
- signal,
74
- [oauth.customFetch]: (url, options) => fetchImplementation(url, {
75
- ...options,
76
- body: options.body
77
- })
78
- };
79
- }
80
- const failure$2 = (message) => Effect.fail(new Error$1({
81
- category: "authorization",
82
- message,
83
- operation: "AuthorizationCode",
84
- retry: "after-user-action"
85
- }));
86
- function randomBytes(crypto, size) {
87
- return crypto.randomBytes(size).pipe(Effect.mapError((cause) => new Error$1({
88
- category: "validation",
89
- message: cause.message,
90
- operation: "AuthorizationCode.start",
91
- retry: "safe"
92
- })));
93
- }
94
- function digest(crypto, value) {
95
- return crypto.digest("SHA-256", new TextEncoder().encode(value)).pipe(Effect.mapError((cause) => new Error$1({
96
- category: "validation",
97
- message: cause.message,
98
- operation: "AuthorizationCode.start",
99
- retry: "safe"
100
- })));
101
- }
102
- function base64Url(bytes) {
103
- let binary = "";
104
- for (const byte of bytes) binary += String.fromCharCode(byte);
105
- return btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replaceAll("=", "");
106
- }
107
- //#endregion
108
- //#region src/providers/cloudflare/protocol.ts
109
- const ErrorDetail = Schema.Struct({
110
- code: Schema.Number,
111
- message: Schema.String
112
- });
113
- const ResultInfo = Schema.Struct({
114
- count: Schema.optionalKey(Schema.Number),
115
- page: Schema.optionalKey(Schema.Number),
116
- per_page: Schema.optionalKey(Schema.Number),
117
- total_count: Schema.optionalKey(Schema.Number),
118
- total_pages: Schema.optionalKey(Schema.Number)
119
- });
120
- const Message = Schema.Struct({
121
- code: Schema.optionalKey(Schema.Number),
122
- message: Schema.String
123
- });
124
- const BaseEnvelope = Schema.Struct({
125
- errors: Schema.Array(ErrorDetail),
126
- messages: Schema.Array(Message),
127
- success: Schema.Boolean
128
- });
129
- const Account = Schema.Struct({
130
- id: Schema.String,
131
- name: Schema.String
132
- });
133
- const Zone = Schema.Struct({
134
- account: Account,
135
- id: Schema.String,
136
- name: Schema.String,
137
- name_servers: Schema.Array(Schema.String),
138
- status: Schema.optionalKey(Schema.String)
139
- });
140
- const Record = Schema.Struct({
141
- content: Schema.optionalKey(Schema.String),
142
- data: Schema.optionalKey(Schema.Unknown),
143
- id: Schema.String,
144
- name: Schema.String,
145
- priority: Schema.optionalKey(Schema.Number),
146
- proxied: Schema.optionalKey(Schema.Boolean),
147
- ttl: Schema.Number,
148
- type: Schema.String
149
- });
150
- const Token = Schema.Struct({
151
- expires_on: Schema.optionalKey(Schema.String),
152
- id: Schema.String,
153
- not_before: Schema.optionalKey(Schema.String),
154
- status: Schema.Literals([
155
- "active",
156
- "disabled",
157
- "expired"
158
- ])
159
- });
160
- const ZoneListEnvelope = Schema.Struct({
161
- errors: Schema.Array(ErrorDetail),
162
- messages: Schema.Array(Message),
163
- result: Schema.Array(Zone),
164
- result_info: Schema.optionalKey(ResultInfo),
165
- success: Schema.Boolean
166
- });
167
- const RecordListEnvelope = Schema.Struct({
168
- errors: Schema.Array(ErrorDetail),
169
- messages: Schema.Array(Message),
170
- result: Schema.Array(Record),
171
- result_info: Schema.optionalKey(ResultInfo),
172
- success: Schema.Boolean
173
- });
174
- const RecordEnvelope = Schema.Struct({
175
- errors: Schema.Array(ErrorDetail),
176
- messages: Schema.Array(Message),
177
- result: Record,
178
- success: Schema.Boolean
179
- });
180
- const TokenEnvelope = Schema.Struct({
181
- errors: Schema.Array(ErrorDetail),
182
- messages: Schema.Array(Message),
183
- result: Token,
184
- success: Schema.Boolean
185
- });
186
- //#endregion
187
- //#region src/providers/cloudflare/records.ts
188
- const Data$1 = Schema.Struct({
189
- flags: Schema.optionalKey(Schema.Number),
190
- port: Schema.optionalKey(Schema.Number),
191
- priority: Schema.optionalKey(Schema.Number),
192
- tag: Schema.optionalKey(Schema.String),
193
- target: Schema.optionalKey(Schema.String),
194
- value: Schema.optionalKey(Schema.String),
195
- weight: Schema.optionalKey(Schema.Number)
196
- });
197
- const decode$1 = Effect.fn("CloudflareRecords.decode")((record) => Effect.gen(function* () {
198
- const name = yield* decode$2(record.name).pipe(Effect.match({
199
- onFailure: () => null,
200
- onSuccess: (value) => value
201
- }));
202
- if (name === null) return yield* decodeOpaque(record);
203
- const common = {
204
- metadata: {
205
- ownership: "provider",
206
- provenance: record.proxied === true ? "cloudflare:proxied" : "cloudflare",
207
- purpose: "existing DNS record"
208
- },
209
- name,
210
- policy: record.type === "CNAME" ? "exclusive" : "append",
211
- ttl: record.ttl === 1 ? null : record.ttl
212
- };
213
- const content = () => record.content === void 0 ? Effect.fail(failure$1("decodeRecord", `Cloudflare ${record.type} record has no content`)) : Effect.succeed(record.content);
214
- switch (record.type) {
215
- case "A":
216
- case "AAAA": return yield* decode$3({
217
- ...common,
218
- _tag: record.type,
219
- address: yield* content()
220
- }).pipe(Effect.mapError((cause) => failure$1("decodeRecord", cause.message)));
221
- case "CNAME":
222
- case "NS": return yield* decode$3({
223
- ...common,
224
- _tag: record.type,
225
- target: yield* content()
226
- }).pipe(Effect.mapError((cause) => failure$1("decodeRecord", cause.message)));
227
- case "TXT": return yield* decode$3({
228
- ...common,
229
- _tag: "TXT",
230
- value: yield* content()
231
- }).pipe(Effect.mapError((cause) => failure$1("decodeRecord", cause.message)));
232
- case "MX": return yield* decode$3({
233
- ...common,
234
- _tag: "MX",
235
- exchange: yield* content(),
236
- priority: record.priority
237
- }).pipe(Effect.mapError((cause) => failure$1("decodeRecord", cause.message)));
238
- case "CAA": {
239
- const data = yield* decodeData(record);
240
- return yield* decode$3({
241
- ...common,
242
- _tag: "CAA",
243
- ...data
244
- }).pipe(Effect.mapError((cause) => failure$1("decodeRecord", cause.message)));
245
- }
246
- case "SRV": {
247
- const data = yield* decodeData(record);
248
- return yield* decode$3({
249
- ...common,
250
- _tag: "SRV",
251
- ...data
252
- }).pipe(Effect.mapError((cause) => failure$1("decodeRecord", cause.message)));
253
- }
254
- default: return yield* decodeOpaque(record);
255
- }
256
- }));
257
- const decodeOpaque = Effect.fn("CloudflareRecords.decodeOpaque")((record) => Schema.decodeUnknownEffect(Opaque)({
258
- _tag: "Opaque",
259
- name: record.name,
260
- providerRecordId: record.id,
261
- providerType: record.type
262
- }).pipe(Effect.mapError((cause) => failure$1("decodeRecord", cause.message))));
263
- function encode(record) {
264
- const common = {
265
- name: record.name,
266
- proxied: false,
267
- ttl: record.ttl ?? 1,
268
- type: record._tag
269
- };
270
- switch (record._tag) {
271
- case "A":
272
- case "AAAA": return {
273
- ...common,
274
- content: record.address
275
- };
276
- case "CNAME":
277
- case "NS": return {
278
- ...common,
279
- content: record.target
280
- };
281
- case "TXT": return {
282
- ...common,
283
- content: record.value
284
- };
285
- case "MX": return {
286
- ...common,
287
- content: record.exchange,
288
- priority: record.priority
289
- };
290
- case "CAA": return {
291
- ...common,
292
- data: {
293
- flags: record.flags,
294
- tag: record.tag,
295
- value: record.value
296
- }
297
- };
298
- case "SRV": return {
299
- ...common,
300
- data: {
301
- port: record.port,
302
- priority: record.priority,
303
- target: record.target,
304
- weight: record.weight
305
- }
306
- };
307
- }
308
- }
309
- const decodeData = Effect.fn("CloudflareRecords.decodeData")((record) => Schema.decodeUnknownEffect(Data$1)(record.data).pipe(Effect.mapError((cause) => failure$1("decodeRecord", cause.message))));
310
- function failure$1(operation, message, fields = {}) {
311
- return new Error({
312
- message,
313
- operation,
314
- providerId: "cloudflare",
315
- reason: fields.reason ?? "response"
316
- });
317
- }
318
- //#endregion
319
- //#region src/providers/cloudflare/client.ts
320
- var client_exports = /* @__PURE__ */ __exportAll({
321
- discoverAuthorizationAccount: () => discoverAuthorizationAccount,
322
- discovery: () => discovery,
323
- make: () => make,
324
- validateDomainToken: () => validateDomainToken
325
- });
326
- /** Exposes Cloudflare zone lookup as the optional provider discovery capability. */
327
- function discovery(client) {
328
- return {
329
- listZones: (name) => client.listZones({ name }).pipe(Effect.map((zones) => zones.map((zone) => ({
330
- ...zone,
331
- status: zone.status === "active" || zone.status === "pending" ? zone.status : "unknown"
332
- })))),
333
- provider: client
334
- };
335
- }
336
- const makeTransport = (options) => {
337
- const fetch = options.fetch ?? globalThis.fetch;
338
- const baseUrl = (options.baseUrl ?? "https://api.cloudflare.com/client/v4").replace(/\/$/, "");
339
- const request = Effect.fn("CloudflareClient.request")((path, operation, init) => Effect.gen(function* () {
340
- const response = yield* Effect.tryPromise({
341
- try: () => fetch(`${baseUrl}${path}`, {
342
- ...init,
343
- headers: {
344
- Accept: "application/json",
345
- Authorization: `Bearer ${options.token.expose()}`,
346
- ...init?.body === void 0 ? {} : { "Content-Type": "application/json" },
347
- ...init?.headers
348
- }
349
- }),
350
- catch: () => failure(operation, "Cloudflare request failed", { reason: "transport" })
351
- });
352
- return {
353
- body: yield* Effect.tryPromise({
354
- try: () => response.json(),
355
- catch: () => {
356
- const retryAfterMs = retryAfter(response.headers.get("retry-after"));
357
- return failure(operation, response.ok ? "Cloudflare returned a non-JSON response" : `Cloudflare request failed with HTTP ${response.status}`, {
358
- reason: response.ok ? "response" : reason(response.status),
359
- ...retryAfterMs === void 0 ? {} : { retryAfterMs },
360
- status: response.status
361
- });
362
- }
363
- }),
364
- response
365
- };
366
- }));
367
- const listZonesPage = Effect.fn("CloudflareClient.listZonesPage")((accountId, name, page) => Effect.gen(function* () {
368
- const query = new URLSearchParams({
369
- page: String(page),
370
- per_page: "50"
371
- });
372
- query.set("type", "full,partial,secondary,internal");
373
- if (accountId !== void 0) query.set("account.id", accountId);
374
- if (name !== void 0) query.set("name", name);
375
- const { body, response } = yield* request(`/zones?${query}`, "listZones");
376
- yield* ensureSuccess(body, "listZones", response);
377
- return yield* decode(ZoneListEnvelope, body, "listZones", response);
378
- }));
379
- return {
380
- allZones: Effect.fn("CloudflareClient.allZones")((accountId, name) => Effect.gen(function* () {
381
- const zones = [];
382
- let page = 1;
383
- while (true) {
384
- const envelope = yield* listZonesPage(accountId, name, page);
385
- zones.push(...envelope.result);
386
- const totalPages = envelope.result_info?.total_pages;
387
- if (totalPages !== void 0 && page >= totalPages || totalPages === void 0 && envelope.result.length < 50) return zones;
388
- page += 1;
389
- }
390
- })),
391
- inspectToken: Effect.fn("CloudflareClient.inspectToken")((path) => Effect.gen(function* () {
392
- const { body, response } = yield* request(path, "validateToken");
393
- yield* ensureSuccess(body, "validateToken", response);
394
- const envelope = yield* decode(TokenEnvelope, body, "validateToken", response);
395
- if (envelope.result.status !== "active") return yield* Effect.fail(failure("validateToken", `Cloudflare token is ${envelope.result.status}`, {
396
- reason: "authentication",
397
- status: response.status
398
- }));
399
- const expiresAt = envelope.result.expires_on === void 0 ? null : new Date(envelope.result.expires_on);
400
- if (expiresAt !== null && Number.isNaN(expiresAt.valueOf())) return yield* Effect.fail(failure("validateToken", "Cloudflare token expiry is not a valid timestamp", {
401
- reason: "response",
402
- status: response.status
403
- }));
404
- return expiresAt;
405
- })),
406
- request
407
- };
408
- };
409
- const discoverAccount = Effect.fn("CloudflareClient.discoverAccount")((options) => Effect.gen(function* () {
410
- const { allZones } = makeTransport(options);
411
- for (const candidate of candidates(options.domain)) {
412
- const matches = yield* allZones(void 0, candidate);
413
- const match = matches[0];
414
- if (matches.length === 0) continue;
415
- if (matches.length === 1 && match !== void 0) return match.account;
416
- return yield* Effect.fail(failure("discoverAccount", `Cloudflare returned multiple accessible zones named ${candidate}`, { reason: "conflict" }));
417
- }
418
- return yield* Effect.fail(failure("discoverAccount", `Cloudflare did not expose an accessible zone for ${options.domain}`, { reason: "not_found" }));
419
- }));
420
- const discoverAuthorizationAccount = discoverAccount;
421
- const validateDomainToken = Effect.fn("CloudflareClient.validateDomainToken")((options) => Effect.gen(function* () {
422
- const transport = makeTransport(options);
423
- const account = options.tokenKind === "account" ? yield* discoverAccount(options) : void 0;
424
- const expiresAt = yield* transport.inspectToken(account === void 0 ? "/user/tokens/verify" : `/accounts/${encodeURIComponent(account.id)}/tokens/verify`);
425
- return {
426
- accountId: (account ?? (yield* discoverAccount(options))).id,
427
- capabilities: options.capabilities,
428
- expiresAt,
429
- scopes: []
430
- };
431
- }));
432
- /** Creates an Effect-native Cloudflare client without owning the credential lifecycle. */
433
- function make(options) {
434
- const { allZones, inspectToken, request } = makeTransport(options);
435
- const resolveZone = Effect.fn("CloudflareClient.resolveZone")((name) => Effect.gen(function* () {
436
- const matches = yield* allZones(options.accountId, name);
437
- const match = matches[0];
438
- if (matches.length === 1 && match !== void 0) return match;
439
- return yield* Effect.fail(failure("resolveZone", matches.length === 0 ? `Cloudflare zone ${name} was not found in account ${options.accountId}` : `Cloudflare returned multiple zones named ${name} in account ${options.accountId}`, { reason: matches.length === 0 ? "not_found" : "response" }));
440
- }));
441
- const listRecords = Effect.fn("CloudflareClient.listRecords")((zoneName) => Effect.gen(function* () {
442
- const zone = yield* resolveZone(zoneName);
443
- const records = [];
444
- let page = 1;
445
- while (true) {
446
- const query = new URLSearchParams({
447
- page: String(page),
448
- per_page: "100"
449
- });
450
- const { body, response } = yield* request(`/zones/${encodeURIComponent(zone.id)}/dns_records?${query}`, "listRecords");
451
- yield* ensureSuccess(body, "listRecords", response);
452
- const envelope = yield* decode(RecordListEnvelope, body, "listRecords", response);
453
- records.push(...yield* Effect.forEach(envelope.result, decode$1));
454
- const totalPages = envelope.result_info?.total_pages;
455
- if (totalPages !== void 0 && page >= totalPages || totalPages === void 0 && envelope.result.length < 100) return records;
456
- page += 1;
457
- }
458
- }));
459
- const createRecord = Effect.fn("CloudflareClient.createRecord")((zoneName, record) => Effect.gen(function* () {
460
- const zone = yield* resolveZone(zoneName);
461
- const { body, response } = yield* request(`/zones/${encodeURIComponent(zone.id)}/dns_records`, "createRecord", {
462
- body: JSON.stringify(encode(record)),
463
- method: "POST"
464
- });
465
- yield* ensureSuccess(body, "createRecord", response);
466
- return { providerRecordId: (yield* decode(RecordEnvelope, body, "createRecord", response)).result.id };
467
- }));
468
- const getRecord = Effect.fn("CloudflareClient.getRecord")((zoneName, providerRecordId) => Effect.gen(function* () {
469
- const zone = yield* resolveZone(zoneName);
470
- const { body, response } = yield* request(`/zones/${encodeURIComponent(zone.id)}/dns_records/${encodeURIComponent(providerRecordId)}`, "getRecord");
471
- if (response.status === 404) return null;
472
- yield* ensureSuccess(body, "getRecord", response);
473
- const envelope = yield* decode(RecordEnvelope, body, "getRecord", response);
474
- return yield* decode$1(envelope.result);
475
- }));
476
- return {
477
- id: "cloudflare",
478
- createRecord,
479
- deleteRecord: Effect.fn("CloudflareClient.deleteRecord")((zoneName, providerRecordId) => Effect.gen(function* () {
480
- const zone = yield* resolveZone(zoneName);
481
- const { body, response } = yield* request(`/zones/${encodeURIComponent(zone.id)}/dns_records/${encodeURIComponent(providerRecordId)}`, "deleteRecord", { method: "DELETE" });
482
- yield* ensureSuccess(body, "deleteRecord", response);
483
- })),
484
- getRecord,
485
- listAccounts: Effect.fn("CloudflareClient.listAccounts")(() => allZones().pipe(Effect.map((zones) => {
486
- const accounts = /* @__PURE__ */ new Map();
487
- for (const zone of zones) accounts.set(zone.account.id, zone.account);
488
- return [...accounts.values()].sort((left, right) => left.name.localeCompare(right.name));
489
- }))),
490
- listRecords,
491
- listZones: Effect.fn("CloudflareClient.listZones")((input = {}) => allZones(input.accountId ?? options.accountId, input.name).pipe(Effect.flatMap((zones) => Effect.forEach(zones, projectZone)))),
492
- validateToken: Effect.fn("CloudflareClient.validateToken")(() => Effect.gen(function* () {
493
- const path = options.tokenKind === "account" ? `/accounts/${encodeURIComponent(options.accountId)}/tokens/verify` : "/user/tokens/verify";
494
- const expiresAt = yield* inspectToken(path);
495
- yield* allZones(options.accountId);
496
- return {
497
- accountId: options.accountId,
498
- capabilities: options.capabilities,
499
- expiresAt,
500
- scopes: []
501
- };
502
- }))
503
- };
504
- }
505
- const projectZone = Effect.fn("CloudflareClient.projectZone")((zone) => Effect.gen(function* () {
506
- const name = yield* decode$2(zone.name).pipe(Effect.mapError((cause) => failure("listZones", cause.message, { reason: "response" })));
507
- const nameservers = yield* Effect.forEach(zone.name_servers, (nameserver) => decode$2(nameserver).pipe(Effect.mapError((cause) => failure("listZones", cause.message, { reason: "response" }))));
508
- return {
509
- accountId: zone.account.id,
510
- id: zone.id,
511
- name,
512
- nameservers,
513
- status: zone.status ?? null
514
- };
515
- }));
516
- function decode(schema, input, operation, response) {
517
- return Schema.decodeUnknownEffect(schema)(input).pipe(Effect.mapError((cause) => failure(operation, `Cloudflare response did not match its API contract: ${cause.message}`, {
518
- reason: "response",
519
- status: response.status
520
- })));
521
- }
522
- function ensureSuccess(input, operation, response) {
523
- return Schema.decodeUnknownEffect(BaseEnvelope)(input).pipe(Effect.mapError(() => failure(operation, "Cloudflare response did not contain a valid API envelope", {
524
- reason: "response",
525
- status: response.status
526
- })), Effect.flatMap((envelope) => {
527
- if (response.ok && envelope.success) return Effect.void;
528
- const detail = envelope.errors[0];
529
- const retryAfterMs = retryAfter(response.headers.get("retry-after"));
530
- return Effect.fail(failure(operation, detail?.message ?? `Cloudflare request failed with HTTP ${response.status}`, {
531
- ...detail === void 0 ? {} : { code: detail.code },
532
- reason: reason(response.status, detail?.code),
533
- ...retryAfterMs === void 0 ? {} : { retryAfterMs },
534
- status: response.status
535
- }));
536
- }));
537
- }
538
- function reason(status, code) {
539
- if (status === 401) return "authentication";
540
- if (status === 403) return "authorization";
541
- if (status === 404) return "not_found";
542
- if (status === 409 || code === 81056 || code === 81057 || code === 81058) return "conflict";
543
- if (status === 429) return "rate_limit";
544
- if (status >= 500) return "response";
545
- return "request";
546
- }
547
- function retryAfter(value) {
548
- if (value === null) return void 0;
549
- const seconds = Number(value);
550
- if (Number.isFinite(seconds)) return Math.max(0, seconds * 1e3);
551
- const date = Date.parse(value);
552
- return Number.isNaN(date) ? void 0 : Math.max(0, date - Date.now());
553
- }
554
- function failure(operation, message, fields = {}) {
555
- return new Error({
556
- ...fields,
557
- message,
558
- operation,
559
- providerId: "cloudflare"
560
- });
561
- }
562
- //#endregion
563
- //#region src/providers/cloudflare/auth.ts
564
- var auth_exports = /* @__PURE__ */ __exportAll({
565
- contextCodec: () => contextCodec,
566
- manifest: () => manifest,
567
- oauthAuthentication: () => oauthAuthentication,
568
- oauthFlow: () => oauthFlow,
569
- oauthMethod: () => oauthMethod,
570
- subjectResolver: () => subjectResolver,
571
- tokenConnectionMethod: () => tokenConnectionMethod,
572
- tokenMethod: () => tokenMethod,
573
- tokenValidator: () => tokenValidator
574
- });
575
- const authorizationServer = {
576
- authorization_endpoint: "https://dash.cloudflare.com/oauth2/auth",
577
- issuer: "https://dash.cloudflare.com",
578
- revocation_endpoint: "https://dash.cloudflare.com/oauth2/revoke",
579
- token_endpoint: "https://dash.cloudflare.com/oauth2/token"
580
- };
581
- const Context$1 = Schema.Struct({ tokenKind: Schema.Literals(["account", "user"]) });
582
- const contextCodec = codec("cloudflare.v1", Context$1);
583
- /** Describes Cloudflare's caller-created API-token authorization method. */
584
- function tokenMethod(capabilities) {
585
- return {
586
- _tag: "token",
587
- capabilities: [...capabilities],
588
- instructionsUrl: "https://developers.cloudflare.com/fundamentals/api/get-started/create-token/"
589
- };
590
- }
591
- /** Describes a registered Cloudflare OAuth client and its assigned scope IDs. */
592
- function oauthMethod(options) {
593
- return {
594
- _tag: "oauth2",
595
- authorizationServer,
596
- capabilities: [...options.capabilities],
597
- clientAuth: options.clientAuth,
598
- scopes: [...options.scopes]
599
- };
600
- }
601
- /** Creates the Cloudflare token and OAuth authorization manifest. */
602
- function manifest(options) {
603
- return {
604
- methods: [tokenMethod(options.capabilities), oauthMethod(options)],
605
- providerId: "cloudflare"
606
- };
607
- }
608
- /** Resolves the Cloudflare account selected by a completed OAuth grant. */
609
- function subjectResolver(options) {
610
- return (tokens, accessToken) => Effect.gen(function* () {
611
- const accountId = options.accountId ?? (yield* discoverAuthorizationAccount({
612
- ...options.baseUrl === void 0 ? {} : { baseUrl: options.baseUrl },
613
- domain: options.domain,
614
- ...options.fetch === void 0 ? {} : { fetch: options.fetch },
615
- token: accessToken
616
- }).pipe(Effect.map((account) => account.id)));
617
- if (options.accountId !== void 0) yield* make({
618
- accountId: options.accountId,
619
- ...options.baseUrl === void 0 ? {} : { baseUrl: options.baseUrl },
620
- capabilities: options.capabilities,
621
- ...options.fetch === void 0 ? {} : { fetch: options.fetch },
622
- token: accessToken,
623
- tokenKind: "user"
624
- }).listZones();
625
- const now = yield* Clock.currentTimeMillis;
626
- return {
627
- accountId,
628
- expiresAt: typeof tokens.expires_in === "number" ? new Date(now + tokens.expires_in * 1e3) : null
629
- };
630
- });
631
- }
632
- /** Creates a host callback that validates a Cloudflare API token. */
633
- function tokenValidator(options) {
634
- return (token) => options.accountId === void 0 ? validateDomainToken({
635
- ...options.baseUrl === void 0 ? {} : { baseUrl: options.baseUrl },
636
- capabilities: options.capabilities,
637
- domain: options.domain,
638
- ...options.fetch === void 0 ? {} : { fetch: options.fetch },
639
- token,
640
- ...options.tokenKind === void 0 ? {} : { tokenKind: options.tokenKind }
641
- }) : make({
642
- accountId: options.accountId,
643
- ...options.baseUrl === void 0 ? {} : { baseUrl: options.baseUrl },
644
- capabilities: options.capabilities,
645
- ...options.fetch === void 0 ? {} : { fetch: options.fetch },
646
- token,
647
- ...options.tokenKind === void 0 ? {} : { tokenKind: options.tokenKind }
648
- }).validateToken();
649
- }
650
- /** Creates a provider-independent token connection method backed by Cloudflare validation. */
651
- function tokenConnectionMethod(options) {
652
- const requiredCapabilities = [...options.capabilities];
653
- return Method.Token({
654
- authenticate: Effect.fn("CloudflareAuth.authenticateToken")(function* (token) {
655
- const validated = yield* tokenValidator(options)(token);
656
- const observedAt = new Date(yield* Clock.currentTimeMillis);
657
- return {
658
- capabilityEvidence: validated.capabilities.map((capability) => ({
659
- capability,
660
- evidence: Evidence.Introspected({ observedAt })
661
- })),
662
- credential: {
663
- accessToken: token,
664
- refreshToken: null,
665
- tokenType: "bearer"
666
- },
667
- expiresAt: validated.expiresAt,
668
- providerAccountId: validated.accountId,
669
- providerContext: yield* contextCodec.encode({ tokenKind: options.tokenKind ?? "user" }),
670
- scopes: [...validated.scopes]
671
- };
672
- }),
673
- providerId: "cloudflare",
674
- requiredCapabilities,
675
- token: options.token
676
- });
677
- }
678
- /** Converts a completed Cloudflare OAuth grant into the canonical connection authentication. */
679
- const oauthAuthentication = Effect.fn("CloudflareAuth.oauthAuthentication")(function* (options) {
680
- const resolved = yield* subjectResolver(options)(options.tokens, options.accessToken);
681
- const observedAt = new Date(yield* Clock.currentTimeMillis);
682
- return {
683
- capabilityEvidence: options.capabilities.map((capability) => ({
684
- capability,
685
- evidence: Evidence.Introspected({ observedAt })
686
- })),
687
- credential: {
688
- accessToken: options.accessToken,
689
- refreshToken: options.tokens.refresh_token === void 0 ? null : Value.from(options.tokens.refresh_token),
690
- tokenType: options.tokens.token_type
691
- },
692
- expiresAt: resolved.expiresAt,
693
- providerAccountId: resolved.accountId,
694
- providerContext: yield* contextCodec.encode({ tokenKind: "user" }),
695
- scopes: (options.tokens.scope ?? "").split(" ").filter(Boolean)
696
- };
697
- });
698
- /** Creates Cloudflare's OAuth implementation of the common interactive connection capability. */
699
- function oauthFlow(options) {
700
- const method = oauthMethod({
701
- capabilities: options.capabilities,
702
- clientAuth: options.clientAuth,
703
- scopes: options.scopes
704
- });
705
- return {
706
- complete: Effect.fn("CloudflareAuth.oauthFlow.complete")(function* (payload, callbackUrl) {
707
- const tokens = yield* complete({
708
- callbackUrl,
709
- client: options.client,
710
- ...options.fetch === void 0 ? {} : { fetch: options.fetch },
711
- method,
712
- payload,
713
- providerId: "cloudflare"
714
- });
715
- return yield* oauthAuthentication({
716
- ...options.accountId === void 0 ? { domain: options.domain } : { accountId: options.accountId },
717
- ...options.baseUrl === void 0 ? {} : { baseUrl: options.baseUrl },
718
- capabilities: options.capabilities,
719
- ...options.fetch === void 0 ? {} : { fetch: options.fetch },
720
- accessToken: make$1(tokens.access_token),
721
- tokens
722
- });
723
- }),
724
- method: "oauth2",
725
- providerId: "cloudflare",
726
- requiredCapabilities: [...options.capabilities],
727
- start: (continuationId) => start({
728
- client: options.client,
729
- method,
730
- redirectUri: options.redirectUri,
731
- state: continuationId
732
- })
733
- };
734
- }
735
- //#endregion
736
- export { subjectResolver as a, tokenValidator as c, make as d, oauthMethod as i, client_exports as l, manifest as n, tokenConnectionMethod as o, oauthFlow as r, tokenMethod as s, auth_exports as t, discovery as u };
737
-
738
- //# sourceMappingURL=auth-BR-19zj-.mjs.map