domainkit 0.2.2 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -26
- package/dist/index.d.mts +639 -187
- package/dist/index.mjs +301 -300
- package/dist/index.mjs.map +1 -1
- package/dist/promise.d.mts +464 -0
- package/dist/promise.mjs +636 -0
- package/dist/promise.mjs.map +1 -0
- package/dist/{resolver-CxE-VDw4.mjs → resolver-CvK7JoJM.mjs} +401 -54
- package/dist/resolver-CvK7JoJM.mjs.map +1 -0
- package/dist/{resolver-Dc0hwV-J.d.mts → resolver-uqe1h5Vz.d.mts} +1513 -25
- package/dist/testing.d.mts +4 -5
- package/dist/testing.mjs +17 -3
- package/dist/testing.mjs.map +1 -1
- package/dist/verify-BoWy70ew.mjs +2420 -0
- package/dist/verify-BoWy70ew.mjs.map +1 -0
- package/dist/{verify-Dls29YC-.d.mts → verify-CkgVrwyl.d.mts} +318 -21
- package/package.json +6 -30
- package/dist/auth-BR-19zj-.mjs +0 -738
- package/dist/auth-BR-19zj-.mjs.map +0 -1
- package/dist/auth-g-waCHcz.mjs +0 -671
- package/dist/auth-g-waCHcz.mjs.map +0 -1
- package/dist/authorization-OeaSR47S.mjs +0 -284
- package/dist/authorization-OeaSR47S.mjs.map +0 -1
- package/dist/canonical-json-CpvqGMcr.mjs +0 -57
- package/dist/canonical-json-CpvqGMcr.mjs.map +0 -1
- package/dist/cloudflare-BrZPU9li.d.mts +0 -32
- package/dist/cloudflare-CGmasR8A.mjs +0 -69
- package/dist/cloudflare-CGmasR8A.mjs.map +0 -1
- package/dist/cloudflare.d.mts +0 -3
- package/dist/cloudflare.mjs +0 -2
- package/dist/connection-BfkloPZy.d.mts +0 -186
- package/dist/connection-BwtOwpH6.mjs +0 -195
- package/dist/connection-BwtOwpH6.mjs.map +0 -1
- package/dist/connection-CjNQe_E-.mjs +0 -58
- package/dist/connection-CjNQe_E-.mjs.map +0 -1
- package/dist/connection-api-DNuEZ_jR.d.mts +0 -7
- package/dist/dns-record-BLeqo56C.mjs +0 -289
- package/dist/dns-record-BLeqo56C.mjs.map +0 -1
- package/dist/effect-cloudflare.d.mts +0 -2
- package/dist/effect-cloudflare.mjs +0 -2
- package/dist/effect-vercel.d.mts +0 -2
- package/dist/effect-vercel.mjs +0 -2
- package/dist/effect.d.mts +0 -36
- package/dist/effect.mjs +0 -51
- package/dist/effect.mjs.map +0 -1
- package/dist/index-BHWRTThN.d.mts +0 -159
- package/dist/index-D3PVknwE.d.mts +0 -145
- package/dist/resolver-CxE-VDw4.mjs.map +0 -1
- package/dist/vercel-BsNDu4Np.d.mts +0 -31
- package/dist/vercel-CfoJaaCu.mjs +0 -60
- package/dist/vercel-CfoJaaCu.mjs.map +0 -1
- package/dist/vercel.d.mts +0 -3
- package/dist/vercel.mjs +0 -2
- package/dist/verify-BKbvq7IN.mjs +0 -642
- package/dist/verify-BKbvq7IN.mjs.map +0 -1
- package/dist/zone-discovery-BPnH3sLU.d.mts +0 -1397
- package/dist/zones-DKHTpX9C.mjs +0 -19
- package/dist/zones-DKHTpX9C.mjs.map +0 -1
package/dist/auth-g-waCHcz.mjs
DELETED
|
@@ -1,671 +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 { g as Method, h as Error$1, p as make$1, r as Evidence, u as codec } from "./authorization-OeaSR47S.mjs";
|
|
4
|
-
import { Clock, Effect, Schema } from "effect";
|
|
5
|
-
//#region src/providers/vercel/protocol.ts
|
|
6
|
-
const Pagination = Schema.Struct({
|
|
7
|
-
count: Schema.Number,
|
|
8
|
-
next: Schema.NullOr(Schema.Number),
|
|
9
|
-
prev: Schema.NullOr(Schema.Number)
|
|
10
|
-
});
|
|
11
|
-
const ErrorDetail = Schema.Struct({
|
|
12
|
-
code: Schema.String,
|
|
13
|
-
message: Schema.String,
|
|
14
|
-
limit: Schema.optionalKey(Schema.Struct({
|
|
15
|
-
remaining: Schema.Number,
|
|
16
|
-
reset: Schema.optionalKey(Schema.Number),
|
|
17
|
-
resetMs: Schema.optionalKey(Schema.Number),
|
|
18
|
-
total: Schema.Number
|
|
19
|
-
}))
|
|
20
|
-
});
|
|
21
|
-
const ErrorEnvelope = Schema.Struct({ error: ErrorDetail });
|
|
22
|
-
const User = Schema.Struct({
|
|
23
|
-
id: Schema.String,
|
|
24
|
-
name: Schema.NullOr(Schema.String),
|
|
25
|
-
username: Schema.String
|
|
26
|
-
});
|
|
27
|
-
const UserEnvelope = Schema.Struct({ user: User });
|
|
28
|
-
const Team = Schema.Struct({
|
|
29
|
-
id: Schema.String,
|
|
30
|
-
name: Schema.NullOr(Schema.String),
|
|
31
|
-
slug: Schema.String
|
|
32
|
-
});
|
|
33
|
-
const TeamListEnvelope = Schema.Struct({
|
|
34
|
-
pagination: Pagination,
|
|
35
|
-
teams: Schema.Array(Team)
|
|
36
|
-
});
|
|
37
|
-
const Domain = Schema.Struct({
|
|
38
|
-
id: Schema.String,
|
|
39
|
-
intendedNameservers: Schema.Array(Schema.String),
|
|
40
|
-
name: Schema.String,
|
|
41
|
-
nameservers: Schema.Array(Schema.String),
|
|
42
|
-
serviceType: Schema.Literals([
|
|
43
|
-
"zeit.world",
|
|
44
|
-
"external",
|
|
45
|
-
"na"
|
|
46
|
-
]),
|
|
47
|
-
teamId: Schema.NullOr(Schema.String),
|
|
48
|
-
userId: Schema.String,
|
|
49
|
-
verified: Schema.Boolean,
|
|
50
|
-
zone: Schema.optionalKey(Schema.Boolean)
|
|
51
|
-
});
|
|
52
|
-
const DomainConfig = Schema.Struct({
|
|
53
|
-
misconfigured: Schema.Boolean,
|
|
54
|
-
serviceType: Schema.Literals([
|
|
55
|
-
"zeit.world",
|
|
56
|
-
"external",
|
|
57
|
-
"na"
|
|
58
|
-
])
|
|
59
|
-
});
|
|
60
|
-
const DomainEnvelope = Schema.Struct({ domain: Domain });
|
|
61
|
-
const DomainListEnvelope = Schema.Struct({
|
|
62
|
-
domains: Schema.Array(Domain),
|
|
63
|
-
pagination: Pagination
|
|
64
|
-
});
|
|
65
|
-
const Record = Schema.Struct({
|
|
66
|
-
id: Schema.String,
|
|
67
|
-
mxPriority: Schema.optionalKey(Schema.Number),
|
|
68
|
-
name: Schema.String,
|
|
69
|
-
priority: Schema.optionalKey(Schema.Number),
|
|
70
|
-
ttl: Schema.optionalKey(Schema.Number),
|
|
71
|
-
type: Schema.String,
|
|
72
|
-
value: Schema.String
|
|
73
|
-
});
|
|
74
|
-
const RecordListEnvelope = Schema.Struct({
|
|
75
|
-
pagination: Schema.optionalKey(Pagination),
|
|
76
|
-
records: Schema.Array(Record)
|
|
77
|
-
});
|
|
78
|
-
const CreateRecordEnvelope = Schema.Struct({
|
|
79
|
-
uid: Schema.String,
|
|
80
|
-
updated: Schema.optionalKey(Schema.Number)
|
|
81
|
-
});
|
|
82
|
-
const IntegrationToken = Schema.Struct({
|
|
83
|
-
access_token: Schema.String,
|
|
84
|
-
installation_id: Schema.optionalKey(Schema.String),
|
|
85
|
-
team_id: Schema.NullOr(Schema.String),
|
|
86
|
-
token_type: Schema.optionalKey(Schema.String),
|
|
87
|
-
user_id: Schema.String
|
|
88
|
-
});
|
|
89
|
-
//#endregion
|
|
90
|
-
//#region src/providers/vercel/records.ts
|
|
91
|
-
const decode$1 = Effect.fn("VercelRecords.decode")((zone, record) => Effect.gen(function* () {
|
|
92
|
-
const absolute = absoluteNameCandidate(zone, record.name);
|
|
93
|
-
const name = yield* decode$2(absolute).pipe(Effect.match({
|
|
94
|
-
onFailure: () => null,
|
|
95
|
-
onSuccess: (value) => value
|
|
96
|
-
}));
|
|
97
|
-
if (name === null) return yield* decodeOpaque(record, absolute);
|
|
98
|
-
const common = {
|
|
99
|
-
metadata: {
|
|
100
|
-
ownership: "provider",
|
|
101
|
-
provenance: "vercel",
|
|
102
|
-
purpose: "existing DNS record"
|
|
103
|
-
},
|
|
104
|
-
name,
|
|
105
|
-
policy: record.type === "CNAME" ? "exclusive" : "append",
|
|
106
|
-
ttl: record.ttl ?? 60
|
|
107
|
-
};
|
|
108
|
-
const fromRecord = (input) => decode$3(input).pipe(Effect.mapError((cause) => failure$2("decodeRecord", cause.message)));
|
|
109
|
-
switch (record.type) {
|
|
110
|
-
case "A":
|
|
111
|
-
case "AAAA": return yield* fromRecord({
|
|
112
|
-
...common,
|
|
113
|
-
_tag: record.type,
|
|
114
|
-
address: record.value
|
|
115
|
-
});
|
|
116
|
-
case "CNAME":
|
|
117
|
-
case "NS": return yield* fromRecord({
|
|
118
|
-
...common,
|
|
119
|
-
_tag: record.type,
|
|
120
|
-
target: record.value
|
|
121
|
-
});
|
|
122
|
-
case "TXT": return yield* fromRecord({
|
|
123
|
-
...common,
|
|
124
|
-
_tag: "TXT",
|
|
125
|
-
value: record.value
|
|
126
|
-
});
|
|
127
|
-
case "MX": return yield* fromRecord({
|
|
128
|
-
...common,
|
|
129
|
-
_tag: "MX",
|
|
130
|
-
exchange: record.value,
|
|
131
|
-
priority: record.mxPriority ?? record.priority
|
|
132
|
-
});
|
|
133
|
-
case "CAA": {
|
|
134
|
-
const match = record.value.match(/^(\d{1,3})\s+(issue|issuewild|iodef)\s+(?:"((?:\\.|[^"])*)"|(\S.*))$/);
|
|
135
|
-
if (match === null) return yield* Effect.fail(failure$2("decodeRecord", "Vercel CAA record has an invalid value"));
|
|
136
|
-
return yield* fromRecord({
|
|
137
|
-
...common,
|
|
138
|
-
_tag: "CAA",
|
|
139
|
-
flags: Number(match[1]),
|
|
140
|
-
tag: match[2],
|
|
141
|
-
value: unescapeQuoted(match[3] ?? match[4] ?? "")
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
case "SRV": {
|
|
145
|
-
const parts = record.value.trim().split(/\s+/);
|
|
146
|
-
const [priority, weight, port, target] = parts.length === 4 ? parts : [
|
|
147
|
-
String(record.priority ?? ""),
|
|
148
|
-
parts[0],
|
|
149
|
-
parts[1],
|
|
150
|
-
parts[2]
|
|
151
|
-
];
|
|
152
|
-
return yield* fromRecord({
|
|
153
|
-
...common,
|
|
154
|
-
_tag: "SRV",
|
|
155
|
-
port: Number(port),
|
|
156
|
-
priority: Number(priority),
|
|
157
|
-
target,
|
|
158
|
-
weight: Number(weight)
|
|
159
|
-
});
|
|
160
|
-
}
|
|
161
|
-
default: return yield* decodeOpaque(record, name);
|
|
162
|
-
}
|
|
163
|
-
}));
|
|
164
|
-
const decodeOpaque = Effect.fn("VercelRecords.decodeOpaque")((record, name) => Schema.decodeUnknownEffect(Opaque)({
|
|
165
|
-
_tag: "Opaque",
|
|
166
|
-
name,
|
|
167
|
-
providerRecordId: record.id,
|
|
168
|
-
providerType: record.type
|
|
169
|
-
}).pipe(Effect.mapError((cause) => failure$2("decodeRecord", cause.message))));
|
|
170
|
-
function encode(zone, record) {
|
|
171
|
-
const common = {
|
|
172
|
-
name: relativeName(zone, record.name),
|
|
173
|
-
...record.ttl === null ? {} : { ttl: record.ttl },
|
|
174
|
-
type: record._tag
|
|
175
|
-
};
|
|
176
|
-
switch (record._tag) {
|
|
177
|
-
case "A":
|
|
178
|
-
case "AAAA": return {
|
|
179
|
-
...common,
|
|
180
|
-
value: record.address
|
|
181
|
-
};
|
|
182
|
-
case "CNAME":
|
|
183
|
-
case "NS": return {
|
|
184
|
-
...common,
|
|
185
|
-
value: record.target
|
|
186
|
-
};
|
|
187
|
-
case "TXT": return {
|
|
188
|
-
...common,
|
|
189
|
-
value: record.value
|
|
190
|
-
};
|
|
191
|
-
case "MX": return {
|
|
192
|
-
...common,
|
|
193
|
-
mxPriority: record.priority,
|
|
194
|
-
value: record.exchange
|
|
195
|
-
};
|
|
196
|
-
case "CAA": return {
|
|
197
|
-
...common,
|
|
198
|
-
value: `${record.flags} ${record.tag} "${escapeQuoted(record.value)}"`
|
|
199
|
-
};
|
|
200
|
-
case "SRV": return {
|
|
201
|
-
...common,
|
|
202
|
-
srv: {
|
|
203
|
-
port: record.port,
|
|
204
|
-
priority: record.priority,
|
|
205
|
-
target: record.target,
|
|
206
|
-
weight: record.weight
|
|
207
|
-
}
|
|
208
|
-
};
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
function absoluteNameCandidate(zone, name) {
|
|
212
|
-
return name === "" || name === "@" ? zone : name === zone || name.endsWith(`.${zone}`) ? name : `${name}.${zone}`;
|
|
213
|
-
}
|
|
214
|
-
function relativeName(zone, name) {
|
|
215
|
-
if (name === zone) return "";
|
|
216
|
-
const suffix = `.${zone}`;
|
|
217
|
-
if (!name.endsWith(suffix)) throw failure$2("encodeRecord", `DNS record ${name} is outside Vercel zone ${zone}`, { reason: "request" });
|
|
218
|
-
return name.slice(0, -suffix.length);
|
|
219
|
-
}
|
|
220
|
-
function escapeQuoted(value) {
|
|
221
|
-
return value.replaceAll("\\", "\\\\").replaceAll("\"", "\\\"");
|
|
222
|
-
}
|
|
223
|
-
function unescapeQuoted(value) {
|
|
224
|
-
return value.replace(/\\([\\"])/g, "$1");
|
|
225
|
-
}
|
|
226
|
-
function failure$2(operation, message, fields = {}) {
|
|
227
|
-
return new Error({
|
|
228
|
-
message,
|
|
229
|
-
operation,
|
|
230
|
-
providerId: "vercel",
|
|
231
|
-
reason: fields.reason ?? "response"
|
|
232
|
-
});
|
|
233
|
-
}
|
|
234
|
-
//#endregion
|
|
235
|
-
//#region src/providers/vercel/client.ts
|
|
236
|
-
var client_exports = /* @__PURE__ */ __exportAll({
|
|
237
|
-
discovery: () => discovery,
|
|
238
|
-
make: () => make
|
|
239
|
-
});
|
|
240
|
-
/** Exposes Vercel zone lookup as the optional provider discovery capability. */
|
|
241
|
-
function discovery(client) {
|
|
242
|
-
return {
|
|
243
|
-
listZones: (name) => client.listZones({ name }),
|
|
244
|
-
provider: client
|
|
245
|
-
};
|
|
246
|
-
}
|
|
247
|
-
/** Creates an Effect-native Vercel client without owning the credential lifecycle. */
|
|
248
|
-
function make(options) {
|
|
249
|
-
const fetch = options.fetch ?? globalThis.fetch;
|
|
250
|
-
const baseUrl = (options.baseUrl ?? "https://api.vercel.com").replace(/\/$/, "");
|
|
251
|
-
const withContext = (path, values = {}) => {
|
|
252
|
-
const url = new URL(`${baseUrl}${path}`);
|
|
253
|
-
for (const [key, value] of Object.entries(values)) url.searchParams.set(key, value);
|
|
254
|
-
if (options.context._tag === "team") url.searchParams.set("teamId", options.context.teamId);
|
|
255
|
-
return url;
|
|
256
|
-
};
|
|
257
|
-
const request = Effect.fn("VercelClient.request")((url, operation, init) => Effect.gen(function* () {
|
|
258
|
-
const response = yield* Effect.tryPromise({
|
|
259
|
-
try: () => fetch(url, {
|
|
260
|
-
...init,
|
|
261
|
-
headers: {
|
|
262
|
-
Accept: "application/json",
|
|
263
|
-
Authorization: `Bearer ${options.token.expose()}`,
|
|
264
|
-
...init?.body === void 0 ? {} : { "Content-Type": "application/json" },
|
|
265
|
-
...init?.headers
|
|
266
|
-
}
|
|
267
|
-
}),
|
|
268
|
-
catch: () => failure$1(operation, "Vercel request failed", { reason: "transport" })
|
|
269
|
-
});
|
|
270
|
-
const body = yield* Effect.tryPromise({
|
|
271
|
-
try: () => response.json(),
|
|
272
|
-
catch: () => failure$1(operation, response.ok ? "Vercel returned a non-JSON response" : `Vercel request failed with HTTP ${response.status}`, {
|
|
273
|
-
reason: response.ok ? "response" : reason(response.status),
|
|
274
|
-
...rateLimit(response),
|
|
275
|
-
status: response.status
|
|
276
|
-
})
|
|
277
|
-
});
|
|
278
|
-
if (!response.ok) return yield* Effect.fail(apiFailure(body, operation, response));
|
|
279
|
-
return {
|
|
280
|
-
body,
|
|
281
|
-
response
|
|
282
|
-
};
|
|
283
|
-
}));
|
|
284
|
-
const allTeams = Effect.fn("VercelClient.allTeams")(() => Effect.gen(function* () {
|
|
285
|
-
const teams = [];
|
|
286
|
-
let until = null;
|
|
287
|
-
while (true) {
|
|
288
|
-
const url = new URL(`${baseUrl}/v2/teams`);
|
|
289
|
-
url.searchParams.set("limit", "100");
|
|
290
|
-
if (until !== null) url.searchParams.set("until", String(until));
|
|
291
|
-
const { body, response } = yield* request(url, "listAccounts");
|
|
292
|
-
const envelope = yield* decode(TeamListEnvelope, body, "listAccounts", response);
|
|
293
|
-
teams.push(...envelope.teams);
|
|
294
|
-
if (envelope.pagination.next === null) return teams;
|
|
295
|
-
until = envelope.pagination.next;
|
|
296
|
-
}
|
|
297
|
-
}));
|
|
298
|
-
const allDomains = Effect.fn("VercelClient.allDomains")(() => Effect.gen(function* () {
|
|
299
|
-
const domains = [];
|
|
300
|
-
let until = null;
|
|
301
|
-
while (true) {
|
|
302
|
-
const values = { limit: "100" };
|
|
303
|
-
if (until !== null) values.until = String(until);
|
|
304
|
-
const { body, response } = yield* request(withContext("/v5/domains", values), "listZones");
|
|
305
|
-
const envelope = yield* decode(DomainListEnvelope, body, "listZones", response);
|
|
306
|
-
domains.push(...envelope.domains);
|
|
307
|
-
if (envelope.pagination.next === null) return domains;
|
|
308
|
-
until = envelope.pagination.next;
|
|
309
|
-
}
|
|
310
|
-
}));
|
|
311
|
-
const discoverZone = Effect.fn("VercelClient.discoverZone")((name) => Effect.gen(function* () {
|
|
312
|
-
const configResult = yield* request(withContext(`/v6/domains/${encodeURIComponent(name)}/config`), "resolveZone");
|
|
313
|
-
const config = yield* decode(DomainConfig, configResult.body, "resolveZone", configResult.response);
|
|
314
|
-
const domainResult = yield* request(withContext(`/v5/domains/${encodeURIComponent(name)}`), "resolveZone");
|
|
315
|
-
const envelope = yield* decode(DomainEnvelope, domainResult.body, "resolveZone", domainResult.response);
|
|
316
|
-
if (!hasDnsStorage(envelope.domain, config.serviceType)) return null;
|
|
317
|
-
return envelope.domain;
|
|
318
|
-
}).pipe(Effect.catchTag("ProviderError", (cause) => cause.reason === "not_found" ? Effect.succeed(null) : Effect.fail(cause))));
|
|
319
|
-
const resolveZone = Effect.fn("VercelClient.resolveZone")((name) => Effect.gen(function* () {
|
|
320
|
-
const domain = yield* discoverZone(name);
|
|
321
|
-
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" }));
|
|
322
|
-
return yield* decode$2(domain.name).pipe(Effect.mapError((cause) => failure$1("resolveZone", `Vercel returned an invalid storage zone: ${cause.message}`)));
|
|
323
|
-
}));
|
|
324
|
-
const listRecords = Effect.fn("VercelClient.listRecords")((zoneName) => Effect.gen(function* () {
|
|
325
|
-
const storageZone = yield* resolveZone(zoneName);
|
|
326
|
-
const records = [];
|
|
327
|
-
let until = null;
|
|
328
|
-
while (true) {
|
|
329
|
-
const values = { limit: "100" };
|
|
330
|
-
if (until !== null) values.until = String(until);
|
|
331
|
-
const { body, response } = yield* request(withContext(`/v5/domains/${encodeURIComponent(storageZone)}/records`, values), "listRecords");
|
|
332
|
-
const envelope = yield* decode(RecordListEnvelope, body, "listRecords", response);
|
|
333
|
-
records.push(...yield* Effect.forEach(envelope.records, (record) => decode$1(storageZone, record)));
|
|
334
|
-
const next = envelope.pagination?.next ?? null;
|
|
335
|
-
if (next === null) return records.filter((record) => record.name === zoneName || record.name.endsWith(`.${zoneName}`));
|
|
336
|
-
until = next;
|
|
337
|
-
}
|
|
338
|
-
}));
|
|
339
|
-
const createRecord = Effect.fn("VercelClient.createRecord")((zoneName, record) => Effect.gen(function* () {
|
|
340
|
-
const storageZone = yield* resolveZone(zoneName);
|
|
341
|
-
const body = yield* Effect.try({
|
|
342
|
-
try: () => encode(storageZone, record),
|
|
343
|
-
catch: (cause) => cause instanceof Error ? cause : failure$1("createRecord", "Vercel record could not be encoded", { reason: "request" })
|
|
344
|
-
});
|
|
345
|
-
const result = yield* request(withContext(`/v2/domains/${encodeURIComponent(storageZone)}/records`), "createRecord", {
|
|
346
|
-
body: JSON.stringify(body),
|
|
347
|
-
method: "POST"
|
|
348
|
-
});
|
|
349
|
-
return { providerRecordId: (yield* decode(CreateRecordEnvelope, result.body, "createRecord", result.response)).uid };
|
|
350
|
-
}));
|
|
351
|
-
const getRecord = Effect.fn("VercelClient.getRecord")((zoneName, providerRecordId) => Effect.gen(function* () {
|
|
352
|
-
const storageZone = yield* resolveZone(zoneName);
|
|
353
|
-
let until = null;
|
|
354
|
-
while (true) {
|
|
355
|
-
const values = { limit: "100" };
|
|
356
|
-
if (until !== null) values.until = String(until);
|
|
357
|
-
const { body, response } = yield* request(withContext(`/v5/domains/${encodeURIComponent(storageZone)}/records`, values), "getRecord");
|
|
358
|
-
const envelope = yield* decode(RecordListEnvelope, body, "getRecord", response);
|
|
359
|
-
const record = envelope.records.find(({ id }) => id === providerRecordId);
|
|
360
|
-
if (record !== void 0) return yield* decode$1(storageZone, record);
|
|
361
|
-
const next = envelope.pagination?.next ?? null;
|
|
362
|
-
if (next === null) return null;
|
|
363
|
-
until = next;
|
|
364
|
-
}
|
|
365
|
-
}));
|
|
366
|
-
return {
|
|
367
|
-
id: "vercel",
|
|
368
|
-
createRecord,
|
|
369
|
-
deleteRecord: Effect.fn("VercelClient.deleteRecord")((zoneName, providerRecordId) => Effect.gen(function* () {
|
|
370
|
-
const storageZone = yield* resolveZone(zoneName);
|
|
371
|
-
yield* request(withContext(`/v2/domains/${encodeURIComponent(storageZone)}/records/${encodeURIComponent(providerRecordId)}`), "deleteRecord", { method: "DELETE" });
|
|
372
|
-
})),
|
|
373
|
-
getRecord,
|
|
374
|
-
listAccounts: Effect.fn("VercelClient.listAccounts")(() => Effect.gen(function* () {
|
|
375
|
-
const userResult = yield* request(new URL(`${baseUrl}/v2/user`), "listAccounts");
|
|
376
|
-
const { user } = yield* decode(UserEnvelope, userResult.body, "listAccounts", userResult.response);
|
|
377
|
-
const teams = yield* allTeams();
|
|
378
|
-
return [{
|
|
379
|
-
id: user.id,
|
|
380
|
-
name: user.name ?? user.username,
|
|
381
|
-
type: "personal"
|
|
382
|
-
}, ...teams.map((team) => ({
|
|
383
|
-
id: team.id,
|
|
384
|
-
name: team.name ?? team.slug,
|
|
385
|
-
type: "team"
|
|
386
|
-
}))];
|
|
387
|
-
})),
|
|
388
|
-
listRecords,
|
|
389
|
-
listZones: Effect.fn("VercelClient.listZones")((input = {}) => Effect.gen(function* () {
|
|
390
|
-
const domains = (yield* allDomains()).filter((domain) => hasDnsStorage(domain) && (input.name === void 0 || domain.name === input.name));
|
|
391
|
-
if (domains.length > 0 || input.name === void 0) return yield* Effect.forEach(domains, projectZone);
|
|
392
|
-
const discovered = yield* discoverZone(input.name);
|
|
393
|
-
return discovered === null ? [] : [yield* projectZone(discovered)];
|
|
394
|
-
})),
|
|
395
|
-
validateToken: Effect.fn("VercelClient.validateToken")(() => Effect.gen(function* () {
|
|
396
|
-
let accountId;
|
|
397
|
-
if (options.context._tag === "team") {
|
|
398
|
-
yield* allDomains();
|
|
399
|
-
accountId = options.context.teamId;
|
|
400
|
-
} else {
|
|
401
|
-
const result = yield* request(new URL(`${baseUrl}/v2/user`), "validateToken");
|
|
402
|
-
const { user } = yield* decode(UserEnvelope, result.body, "validateToken", result.response);
|
|
403
|
-
accountId = user.id;
|
|
404
|
-
}
|
|
405
|
-
return {
|
|
406
|
-
accountId,
|
|
407
|
-
capabilities: options.capabilities,
|
|
408
|
-
expiresAt: null,
|
|
409
|
-
scopes: []
|
|
410
|
-
};
|
|
411
|
-
}))
|
|
412
|
-
};
|
|
413
|
-
}
|
|
414
|
-
function hasDnsStorage(domain, configuredServiceType = domain.serviceType) {
|
|
415
|
-
return configuredServiceType === "zeit.world" || domain.zone === true || domain.intendedNameservers.length > 0;
|
|
416
|
-
}
|
|
417
|
-
const projectZone = Effect.fn("VercelClient.projectZone")((domain) => Effect.gen(function* () {
|
|
418
|
-
const name = yield* decode$2(domain.name).pipe(Effect.mapError((cause) => failure$1("listZones", cause.message, { reason: "response" })));
|
|
419
|
-
const nameservers = yield* Effect.forEach(domain.intendedNameservers, (nameserver) => decode$2(nameserver).pipe(Effect.mapError((cause) => failure$1("listZones", cause.message, { reason: "response" }))));
|
|
420
|
-
return {
|
|
421
|
-
accountId: domain.teamId ?? domain.userId,
|
|
422
|
-
id: domain.id,
|
|
423
|
-
name,
|
|
424
|
-
nameservers,
|
|
425
|
-
status: domain.verified ? "active" : "pending"
|
|
426
|
-
};
|
|
427
|
-
}));
|
|
428
|
-
function decode(schema, input, operation, response) {
|
|
429
|
-
return Schema.decodeUnknownEffect(schema)(input).pipe(Effect.mapError((cause) => failure$1(operation, `Vercel response did not match its API contract: ${cause.message}`, {
|
|
430
|
-
reason: "response",
|
|
431
|
-
status: response.status
|
|
432
|
-
})));
|
|
433
|
-
}
|
|
434
|
-
function apiFailure(input, operation, response) {
|
|
435
|
-
const detail = Schema.decodeUnknownOption(ErrorEnvelope)(input);
|
|
436
|
-
return failure$1(operation, detail._tag === "Some" ? detail.value.error.message : `Vercel request failed with HTTP ${response.status}`, {
|
|
437
|
-
...detail._tag === "Some" ? { code: detail.value.error.code } : {},
|
|
438
|
-
reason: reason(response.status, detail._tag === "Some" ? detail.value.error.code : void 0),
|
|
439
|
-
...rateLimit(response, detail._tag === "Some" ? detail.value.error : void 0),
|
|
440
|
-
status: response.status
|
|
441
|
-
});
|
|
442
|
-
}
|
|
443
|
-
function reason(status, code) {
|
|
444
|
-
if (status === 401 || code === "invalid_token") return "authentication";
|
|
445
|
-
if (status === 403) return "authorization";
|
|
446
|
-
if (status === 404 || code === "not_found") return "not_found";
|
|
447
|
-
if (status === 409 || code === "conflict") return "conflict";
|
|
448
|
-
if (status === 429 || code === "rate_limited") return "rate_limit";
|
|
449
|
-
if (status >= 500) return "response";
|
|
450
|
-
return "request";
|
|
451
|
-
}
|
|
452
|
-
function rateLimit(response, detail) {
|
|
453
|
-
const resetMs = detail?.limit?.resetMs;
|
|
454
|
-
const header = response.headers.get("x-ratelimit-reset");
|
|
455
|
-
const reset = resetMs ?? (header === null ? void 0 : Number(header) * 1e3);
|
|
456
|
-
return reset === void 0 || !Number.isFinite(reset) ? {} : { retryAfterMs: Math.max(0, reset - Date.now()) };
|
|
457
|
-
}
|
|
458
|
-
function failure$1(operation, message, fields = {}) {
|
|
459
|
-
return new Error({
|
|
460
|
-
...fields,
|
|
461
|
-
message,
|
|
462
|
-
operation,
|
|
463
|
-
providerId: "vercel"
|
|
464
|
-
});
|
|
465
|
-
}
|
|
466
|
-
//#endregion
|
|
467
|
-
//#region src/providers/vercel/auth.ts
|
|
468
|
-
var auth_exports = /* @__PURE__ */ __exportAll({
|
|
469
|
-
contextCodec: () => contextCodec,
|
|
470
|
-
exchangeCode: () => exchangeCode,
|
|
471
|
-
integrationAuthentication: () => integrationAuthentication,
|
|
472
|
-
integrationFlow: () => integrationFlow,
|
|
473
|
-
integrationMethod: () => integrationMethod,
|
|
474
|
-
manifest: () => manifest,
|
|
475
|
-
tokenConnectionMethod: () => tokenConnectionMethod,
|
|
476
|
-
tokenMethod: () => tokenMethod
|
|
477
|
-
});
|
|
478
|
-
const Context$1 = Schema.TaggedUnion({
|
|
479
|
-
personal: { installationId: Schema.NullOr(Schema.String) },
|
|
480
|
-
team: {
|
|
481
|
-
installationId: Schema.NullOr(Schema.String),
|
|
482
|
-
teamId: Schema.String
|
|
483
|
-
}
|
|
484
|
-
});
|
|
485
|
-
const contextCodec = codec("vercel.v1", Context$1);
|
|
486
|
-
/** Describes Vercel's caller-created personal access-token method. */
|
|
487
|
-
function tokenMethod(capabilities) {
|
|
488
|
-
return {
|
|
489
|
-
_tag: "token",
|
|
490
|
-
capabilities: [...capabilities],
|
|
491
|
-
instructionsUrl: "https://vercel.com/account/settings/tokens"
|
|
492
|
-
};
|
|
493
|
-
}
|
|
494
|
-
/** Describes Vercel's provider-specific integration installation flow. */
|
|
495
|
-
function integrationMethod(options) {
|
|
496
|
-
return {
|
|
497
|
-
_tag: "integration",
|
|
498
|
-
capabilities: [...options.capabilities],
|
|
499
|
-
installUrl: `https://vercel.com/integrations/${encodeURIComponent(options.slug)}/new`,
|
|
500
|
-
tokenEndpoint: "https://api.vercel.com/oauth/access_token"
|
|
501
|
-
};
|
|
502
|
-
}
|
|
503
|
-
/** Creates the Vercel token and integration authorization manifest. */
|
|
504
|
-
function manifest(options) {
|
|
505
|
-
return {
|
|
506
|
-
methods: [tokenMethod(options.capabilities), integrationMethod(options)],
|
|
507
|
-
providerId: "vercel"
|
|
508
|
-
};
|
|
509
|
-
}
|
|
510
|
-
/** Exchanges Vercel's one-time integration code and preserves its account context. */
|
|
511
|
-
const exchangeCode = Effect.fn("VercelAuth.exchangeCode")((options) => Effect.gen(function* () {
|
|
512
|
-
const fetch = options.fetch ?? globalThis.fetch;
|
|
513
|
-
const baseUrl = (options.baseUrl ?? "https://api.vercel.com").replace(/\/$/, "");
|
|
514
|
-
const body = new URLSearchParams({
|
|
515
|
-
client_id: options.clientId,
|
|
516
|
-
client_secret: options.clientSecret.expose(),
|
|
517
|
-
code: options.code.expose(),
|
|
518
|
-
redirect_uri: options.redirectUri
|
|
519
|
-
});
|
|
520
|
-
const response = yield* Effect.tryPromise({
|
|
521
|
-
try: () => fetch(`${baseUrl}/oauth/access_token`, {
|
|
522
|
-
body,
|
|
523
|
-
headers: {
|
|
524
|
-
Accept: "application/json",
|
|
525
|
-
"Content-Type": "application/x-www-form-urlencoded"
|
|
526
|
-
},
|
|
527
|
-
method: "POST"
|
|
528
|
-
}),
|
|
529
|
-
catch: () => failure("exchangeCode", "Vercel token exchange failed", "transport")
|
|
530
|
-
});
|
|
531
|
-
const input = yield* Effect.tryPromise({
|
|
532
|
-
try: () => response.json(),
|
|
533
|
-
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)
|
|
534
|
-
});
|
|
535
|
-
if (!response.ok) {
|
|
536
|
-
const detail = Schema.decodeUnknownOption(ErrorEnvelope)(input);
|
|
537
|
-
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));
|
|
538
|
-
}
|
|
539
|
-
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)));
|
|
540
|
-
return {
|
|
541
|
-
accessToken: make$1(token.access_token),
|
|
542
|
-
context: token.team_id === null ? { _tag: "personal" } : {
|
|
543
|
-
_tag: "team",
|
|
544
|
-
teamId: token.team_id
|
|
545
|
-
},
|
|
546
|
-
installationId: token.installation_id ?? null,
|
|
547
|
-
userId: token.user_id
|
|
548
|
-
};
|
|
549
|
-
}));
|
|
550
|
-
/** Creates a provider-independent token connection method backed by Vercel validation. */
|
|
551
|
-
function tokenConnectionMethod(options) {
|
|
552
|
-
const requiredCapabilities = [...options.capabilities];
|
|
553
|
-
return Method.Token({
|
|
554
|
-
authenticate: Effect.fn("VercelAuth.authenticateToken")(function* (token) {
|
|
555
|
-
const validated = yield* make({
|
|
556
|
-
...options,
|
|
557
|
-
token
|
|
558
|
-
}).validateToken();
|
|
559
|
-
const observedAt = new Date(yield* Clock.currentTimeMillis);
|
|
560
|
-
return {
|
|
561
|
-
capabilityEvidence: validated.capabilities.map((capability) => ({
|
|
562
|
-
capability,
|
|
563
|
-
evidence: Evidence.Introspected({ observedAt })
|
|
564
|
-
})),
|
|
565
|
-
credential: {
|
|
566
|
-
accessToken: token,
|
|
567
|
-
refreshToken: null,
|
|
568
|
-
tokenType: "bearer"
|
|
569
|
-
},
|
|
570
|
-
expiresAt: validated.expiresAt,
|
|
571
|
-
providerAccountId: validated.accountId,
|
|
572
|
-
providerContext: yield* contextCodec.encode(options.context._tag === "team" ? {
|
|
573
|
-
_tag: "team",
|
|
574
|
-
installationId: null,
|
|
575
|
-
teamId: options.context.teamId
|
|
576
|
-
} : {
|
|
577
|
-
_tag: "personal",
|
|
578
|
-
installationId: null
|
|
579
|
-
}),
|
|
580
|
-
scopes: [...validated.scopes]
|
|
581
|
-
};
|
|
582
|
-
}),
|
|
583
|
-
providerId: "vercel",
|
|
584
|
-
requiredCapabilities,
|
|
585
|
-
token: options.token
|
|
586
|
-
});
|
|
587
|
-
}
|
|
588
|
-
/** Converts a completed Vercel Integration exchange into canonical connection authentication. */
|
|
589
|
-
const integrationAuthentication = Effect.fn("VercelAuth.integrationAuthentication")(function* (options) {
|
|
590
|
-
const exchanged = yield* exchangeCode(options);
|
|
591
|
-
const observedAt = new Date(yield* Clock.currentTimeMillis);
|
|
592
|
-
return {
|
|
593
|
-
capabilityEvidence: options.capabilities.map((capability) => ({
|
|
594
|
-
capability,
|
|
595
|
-
evidence: Evidence.Introspected({ observedAt })
|
|
596
|
-
})),
|
|
597
|
-
credential: {
|
|
598
|
-
accessToken: exchanged.accessToken,
|
|
599
|
-
refreshToken: null,
|
|
600
|
-
tokenType: "bearer"
|
|
601
|
-
},
|
|
602
|
-
expiresAt: null,
|
|
603
|
-
providerAccountId: exchanged.context._tag === "team" ? exchanged.context.teamId : exchanged.userId,
|
|
604
|
-
providerContext: yield* contextCodec.encode(exchanged.context._tag === "team" ? {
|
|
605
|
-
_tag: "team",
|
|
606
|
-
installationId: exchanged.installationId,
|
|
607
|
-
teamId: exchanged.context.teamId
|
|
608
|
-
} : {
|
|
609
|
-
_tag: "personal",
|
|
610
|
-
installationId: exchanged.installationId
|
|
611
|
-
}),
|
|
612
|
-
scopes: []
|
|
613
|
-
};
|
|
614
|
-
});
|
|
615
|
-
/** Creates Vercel Integration's implementation of the common interactive connection capability. */
|
|
616
|
-
function integrationFlow(options) {
|
|
617
|
-
const method = integrationMethod(options);
|
|
618
|
-
const Payload = Schema.fromJsonString(Schema.Struct({ state: Schema.String }));
|
|
619
|
-
return {
|
|
620
|
-
complete: Effect.fn("VercelAuth.integrationFlow.complete")(function* (payload, callbackUrl) {
|
|
621
|
-
const continuation = yield* Schema.decodeUnknownEffect(Payload)(payload.expose()).pipe(Effect.mapError(() => new Error$1({
|
|
622
|
-
category: "authorization",
|
|
623
|
-
message: "Vercel Integration continuation payload is invalid",
|
|
624
|
-
operation: "VercelAuth.integrationFlow.complete",
|
|
625
|
-
retry: "after-user-action"
|
|
626
|
-
})));
|
|
627
|
-
const code = callbackUrl.searchParams.get("code");
|
|
628
|
-
if (callbackUrl.searchParams.get("state") !== continuation.state || code === null) return yield* new Error$1({
|
|
629
|
-
category: "authorization",
|
|
630
|
-
message: "Vercel Integration callback does not match its continuation",
|
|
631
|
-
operation: "VercelAuth.integrationFlow.complete",
|
|
632
|
-
retry: "after-user-action"
|
|
633
|
-
});
|
|
634
|
-
return yield* integrationAuthentication({
|
|
635
|
-
...options.baseUrl === void 0 ? {} : { baseUrl: options.baseUrl },
|
|
636
|
-
capabilities: options.capabilities,
|
|
637
|
-
clientId: options.clientId,
|
|
638
|
-
clientSecret: options.clientSecret,
|
|
639
|
-
code: make$1(code),
|
|
640
|
-
...options.fetch === void 0 ? {} : { fetch: options.fetch },
|
|
641
|
-
redirectUri: options.redirectUri
|
|
642
|
-
});
|
|
643
|
-
}),
|
|
644
|
-
method: "integration",
|
|
645
|
-
providerId: "vercel",
|
|
646
|
-
requiredCapabilities: [...options.capabilities],
|
|
647
|
-
start: (continuationId) => {
|
|
648
|
-
const authorizationUrl = new URL(method.installUrl);
|
|
649
|
-
authorizationUrl.searchParams.set("source", "external");
|
|
650
|
-
authorizationUrl.searchParams.set("state", continuationId);
|
|
651
|
-
return Effect.succeed({
|
|
652
|
-
authorizationUrl,
|
|
653
|
-
payload: make$1(JSON.stringify({ state: continuationId }))
|
|
654
|
-
});
|
|
655
|
-
}
|
|
656
|
-
};
|
|
657
|
-
}
|
|
658
|
-
function failure(operation, message, reason, status, code) {
|
|
659
|
-
return new Error({
|
|
660
|
-
...code === void 0 ? {} : { code },
|
|
661
|
-
message,
|
|
662
|
-
operation,
|
|
663
|
-
providerId: "vercel",
|
|
664
|
-
reason,
|
|
665
|
-
...status === void 0 ? {} : { status }
|
|
666
|
-
});
|
|
667
|
-
}
|
|
668
|
-
//#endregion
|
|
669
|
-
export { manifest as a, client_exports as c, integrationMethod as i, discovery as l, exchangeCode as n, tokenConnectionMethod as o, integrationFlow as r, tokenMethod as s, auth_exports as t, make as u };
|
|
670
|
-
|
|
671
|
-
//# sourceMappingURL=auth-g-waCHcz.mjs.map
|