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.
- package/README.md +213 -41
- package/dist/Approval.mjs +34 -0
- package/dist/Approval.mjs.map +1 -0
- package/dist/Cleanup.mjs +97 -0
- package/dist/Cleanup.mjs.map +1 -0
- package/dist/Cloudflare.mjs +225 -0
- package/dist/Cloudflare.mjs.map +1 -0
- package/dist/Connect.mjs +463 -0
- package/dist/Connect.mjs.map +1 -0
- package/dist/Custody.mjs +64 -0
- package/dist/Custody.mjs.map +1 -0
- package/dist/DnsRecord.mjs +213 -0
- package/dist/DnsRecord.mjs.map +1 -0
- package/dist/DomainKit.mjs +34 -0
- package/dist/DomainKit.mjs.map +1 -0
- package/dist/DomainName.mjs +100 -0
- package/dist/DomainName.mjs.map +1 -0
- package/dist/Plan.mjs +102 -0
- package/dist/Plan.mjs.map +1 -0
- package/dist/Principal.mjs +23 -0
- package/dist/Principal.mjs.map +1 -0
- package/dist/Provider.mjs +130 -0
- package/dist/Provider.mjs.map +1 -0
- package/dist/Providers.mjs +40 -0
- package/dist/Providers.mjs.map +1 -0
- package/dist/Provision.mjs +93 -0
- package/dist/Provision.mjs.map +1 -0
- package/dist/Reason.mjs +162 -0
- package/dist/Reason.mjs.map +1 -0
- package/dist/Receipt.mjs +71 -0
- package/dist/Receipt.mjs.map +1 -0
- package/dist/Resolver.mjs +75 -0
- package/dist/Resolver.mjs.map +1 -0
- package/dist/Server.mjs +516 -0
- package/dist/Server.mjs.map +1 -0
- package/dist/Storage.mjs +236 -0
- package/dist/Storage.mjs.map +1 -0
- package/dist/Testing.mjs +226 -0
- package/dist/Testing.mjs.map +1 -0
- package/dist/Transport.mjs +187 -0
- package/dist/Transport.mjs.map +1 -0
- package/dist/Vercel.mjs +116 -0
- package/dist/Vercel.mjs.map +1 -0
- package/dist/Verify.mjs +292 -0
- package/dist/Verify.mjs.map +1 -0
- package/dist/{rolldown-runtime-D7D4PA-g.mjs → _virtual/_rolldown/runtime.mjs} +1 -1
- package/dist/entry/client.mjs +2 -0
- package/dist/entry/server.mjs +2 -0
- package/dist/entry/testing.mjs +3 -0
- package/dist/index.mjs +33 -462
- package/dist/index.mjs.map +1 -1
- package/dist/internal/aes.mjs +61 -0
- package/dist/internal/aes.mjs.map +1 -0
- package/dist/internal/attempts.mjs +284 -0
- package/dist/internal/attempts.mjs.map +1 -0
- package/dist/internal/cloudflare/client.mjs +100 -0
- package/dist/internal/cloudflare/client.mjs.map +1 -0
- package/dist/internal/cloudflare/protocol.mjs +59 -0
- package/dist/internal/cloudflare/protocol.mjs.map +1 -0
- package/dist/internal/cloudflare/records.mjs +156 -0
- package/dist/internal/cloudflare/records.mjs.map +1 -0
- package/dist/internal/config.mjs +13 -0
- package/dist/internal/config.mjs.map +1 -0
- package/dist/internal/conformance/provider.mjs +207 -0
- package/dist/internal/conformance/provider.mjs.map +1 -0
- package/dist/internal/conformance/storage.mjs +428 -0
- package/dist/internal/conformance/storage.mjs.map +1 -0
- package/dist/internal/digest.mjs +25 -0
- package/dist/internal/digest.mjs.map +1 -0
- package/dist/internal/doh.mjs +153 -0
- package/dist/internal/doh.mjs.map +1 -0
- package/dist/internal/error.mjs +69 -0
- package/dist/internal/error.mjs.map +1 -0
- package/dist/internal/http.mjs +90 -0
- package/dist/internal/http.mjs.map +1 -0
- package/dist/internal/ids.mjs +8 -0
- package/dist/internal/ids.mjs.map +1 -0
- package/dist/internal/oauth.mjs +113 -0
- package/dist/internal/oauth.mjs.map +1 -0
- package/dist/internal/planner.mjs +88 -0
- package/dist/internal/planner.mjs.map +1 -0
- package/dist/internal/provider-async.mjs +83 -0
- package/dist/internal/provider-async.mjs.map +1 -0
- package/dist/internal/storage-memory.mjs +302 -0
- package/dist/internal/storage-memory.mjs.map +1 -0
- package/dist/internal/vercel/client.mjs +122 -0
- package/dist/internal/vercel/client.mjs.map +1 -0
- package/dist/internal/vercel/protocol.mjs +80 -0
- package/dist/internal/vercel/protocol.mjs.map +1 -0
- package/dist/internal/vercel/records.mjs +151 -0
- package/dist/internal/vercel/records.mjs.map +1 -0
- package/dist/package.mjs +6 -0
- package/dist/package.mjs.map +1 -0
- package/dist/types/Approval.d.ts +26 -0
- package/dist/types/Cleanup.d.ts +41 -0
- package/dist/types/Cloudflare.d.ts +36 -0
- package/dist/types/Connect.d.ts +506 -0
- package/dist/types/Custody.d.ts +38 -0
- package/dist/types/DnsRecord.d.ts +158 -0
- package/dist/types/DomainKit.d.ts +31 -0
- package/dist/types/DomainName.d.ts +27 -0
- package/dist/types/Plan.d.ts +76 -0
- package/dist/types/Principal.d.ts +18 -0
- package/dist/types/Provider.d.ts +248 -0
- package/dist/types/Providers.d.ts +16 -0
- package/dist/types/Provision.d.ts +75 -0
- package/dist/types/Reason.d.ts +118 -0
- package/dist/types/Receipt.d.ts +55 -0
- package/dist/types/Resolver.d.ts +135 -0
- package/dist/types/Server.d.ts +6523 -0
- package/dist/types/Storage.d.ts +314 -0
- package/dist/types/Testing.d.ts +84 -0
- package/dist/types/Transport.d.ts +124 -0
- package/dist/types/Vercel.d.ts +25 -0
- package/dist/types/Verify.d.ts +109 -0
- package/dist/types/entry/client.d.ts +2 -0
- package/dist/types/entry/server.d.ts +2 -0
- package/dist/types/entry/testing.d.ts +3 -0
- package/dist/types/index.d.ts +21 -0
- package/dist/types/internal/aes.d.ts +8 -0
- package/dist/types/internal/attempts.d.ts +40 -0
- package/dist/types/internal/cloudflare/client.d.ts +23 -0
- package/dist/types/internal/cloudflare/protocol.d.ts +71 -0
- package/dist/types/internal/cloudflare/records.d.ts +8 -0
- package/dist/types/internal/config.d.ts +4 -0
- package/dist/types/internal/conformance/provider.d.ts +12 -0
- package/dist/types/internal/conformance/storage.d.ts +14 -0
- package/dist/types/internal/digest.d.ts +10 -0
- package/dist/types/internal/doh.d.ts +19 -0
- package/dist/types/internal/error.d.ts +24 -0
- package/dist/types/internal/http.d.ts +27 -0
- package/dist/types/internal/ids.d.ts +3 -0
- package/dist/types/internal/oauth.d.ts +58 -0
- package/dist/types/internal/planner.d.ts +22 -0
- package/dist/types/internal/provider-async.d.ts +78 -0
- package/dist/types/internal/storage-memory.d.ts +2 -0
- package/dist/types/internal/vercel/client.d.ts +29 -0
- package/dist/types/internal/vercel/protocol.d.ts +124 -0
- package/dist/types/internal/vercel/records.d.ts +7 -0
- package/package.json +88 -12
- package/dist/canonical-json-CQYKsZw7.mjs +0 -310
- package/dist/canonical-json-CQYKsZw7.mjs.map +0 -1
- package/dist/connect-D-X8T9W8.d.mts +0 -1597
- package/dist/connect-oI8hcMxc.mjs +0 -185
- package/dist/connect-oI8hcMxc.mjs.map +0 -1
- package/dist/connection-Dp6ZdSo8.d.mts +0 -186
- package/dist/connection-api-lqG1nBtD.d.mts +0 -26
- package/dist/index.d.mts +0 -1551
- package/dist/managed-dns-connections-C3A_GBaz.mjs +0 -99
- package/dist/managed-dns-connections-C3A_GBaz.mjs.map +0 -1
- package/dist/promise.d.mts +0 -378
- package/dist/promise.mjs +0 -598
- package/dist/promise.mjs.map +0 -1
- package/dist/resolver-BeGz1ukw.mjs +0 -921
- package/dist/resolver-BeGz1ukw.mjs.map +0 -1
- package/dist/resolver-xoSwyXDJ.d.mts +0 -3734
- package/dist/server.d.mts +0 -128
- package/dist/server.mjs +0 -319
- package/dist/server.mjs.map +0 -1
- package/dist/testing.d.mts +0 -62
- package/dist/testing.mjs +0 -507
- package/dist/testing.mjs.map +0 -1
- package/dist/verify-DvGPb5C9.mjs +0 -2402
- package/dist/verify-DvGPb5C9.mjs.map +0 -1
- package/dist/verify-FpunAcM7.d.mts +0 -1335
|
@@ -1,921 +0,0 @@
|
|
|
1
|
-
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
|
-
import { A as Error$4, D as decode$2, E as Schema$2, k as parse$1, n as sha256Encoded, r as stringify } from "./canonical-json-CQYKsZw7.mjs";
|
|
3
|
-
import { Cause, Clock, Context, Data, Effect, Layer, Schema } from "effect";
|
|
4
|
-
import { getDomain } from "tldts";
|
|
5
|
-
//#region src/discovery/zones.ts
|
|
6
|
-
var zones_exports = /* @__PURE__ */ __exportAll({ candidates: () => candidates });
|
|
7
|
-
function candidates(input) {
|
|
8
|
-
const domain = parse$1(input);
|
|
9
|
-
const registrable = getDomain(domain, { allowPrivateDomains: true });
|
|
10
|
-
if (registrable === null) throw new Error$4({ message: "Domain does not have a registrable DNS zone" });
|
|
11
|
-
const labels = domain.split(".");
|
|
12
|
-
const registrableLabels = registrable.split(".").length;
|
|
13
|
-
const values = [];
|
|
14
|
-
for (let index = 0; index <= labels.length - registrableLabels; index += 1) values.push(parse$1(labels.slice(index).join(".")));
|
|
15
|
-
return values;
|
|
16
|
-
}
|
|
17
|
-
//#endregion
|
|
18
|
-
//#region src/discovery/zone-discovery.ts
|
|
19
|
-
var zone_discovery_exports = /* @__PURE__ */ __exportAll({
|
|
20
|
-
Candidate: () => Candidate,
|
|
21
|
-
Outcome: () => Outcome,
|
|
22
|
-
Service: () => Service$2,
|
|
23
|
-
make: () => make
|
|
24
|
-
});
|
|
25
|
-
/** Display-safe identity and nameserver evidence for one provider-owned zone. */
|
|
26
|
-
const Candidate = Schema.Struct({
|
|
27
|
-
accountId: Schema.String,
|
|
28
|
-
id: Schema.String,
|
|
29
|
-
name: Schema$2,
|
|
30
|
-
nameservers: Schema.Array(Schema$2),
|
|
31
|
-
providerId: Schema.String,
|
|
32
|
-
status: Schema.Literals([
|
|
33
|
-
"active",
|
|
34
|
-
"pending",
|
|
35
|
-
"unknown"
|
|
36
|
-
])
|
|
37
|
-
});
|
|
38
|
-
const Outcome = Data.taggedEnum();
|
|
39
|
-
var Service$2 = class extends Context.Service()("@domainkit/ZoneDiscovery") {};
|
|
40
|
-
/** Compose provider-account discovery sources without expanding the record-provider contract. */
|
|
41
|
-
function make(sources) {
|
|
42
|
-
return Service$2.of({ discover: Effect.fn("ZoneDiscovery.discover")(function* (domain) {
|
|
43
|
-
for (const name of candidates(domain)) {
|
|
44
|
-
const matches = deduplicate((yield* Effect.forEach(sources, (source) => source.listZones(name).pipe(Effect.map((zones) => zones.filter((zone) => zone.name === name).map((zone) => ({
|
|
45
|
-
candidate: {
|
|
46
|
-
...zone,
|
|
47
|
-
providerId: source.provider.id
|
|
48
|
-
},
|
|
49
|
-
provider: source.provider
|
|
50
|
-
})))), { concurrency: "unbounded" })).flat());
|
|
51
|
-
const match = matches[0];
|
|
52
|
-
if (matches.length === 1 && match !== void 0) return Outcome.Resolved(match);
|
|
53
|
-
if (matches.length > 1) return Outcome.SelectionRequired({ candidates: matches.map(({ candidate }) => candidate) });
|
|
54
|
-
}
|
|
55
|
-
return Outcome.NotFound({ domain });
|
|
56
|
-
}) });
|
|
57
|
-
}
|
|
58
|
-
function deduplicate(matches) {
|
|
59
|
-
const unique = /* @__PURE__ */ new Map();
|
|
60
|
-
for (const match of matches) {
|
|
61
|
-
const key = [
|
|
62
|
-
match.candidate.providerId,
|
|
63
|
-
match.candidate.accountId,
|
|
64
|
-
match.candidate.id,
|
|
65
|
-
match.candidate.name
|
|
66
|
-
].join(":");
|
|
67
|
-
if (unique.get(key) === void 0) unique.set(key, match);
|
|
68
|
-
}
|
|
69
|
-
return [...unique.values()].sort((left, right) => candidateKey(left.candidate).localeCompare(candidateKey(right.candidate)));
|
|
70
|
-
}
|
|
71
|
-
function candidateKey(candidate) {
|
|
72
|
-
return [
|
|
73
|
-
candidate.name,
|
|
74
|
-
candidate.providerId,
|
|
75
|
-
candidate.accountId,
|
|
76
|
-
candidate.id
|
|
77
|
-
].join(":");
|
|
78
|
-
}
|
|
79
|
-
//#endregion
|
|
80
|
-
//#region src/domain/dns-record.ts
|
|
81
|
-
var dns_record_exports = /* @__PURE__ */ __exportAll({
|
|
82
|
-
A: () => A,
|
|
83
|
-
Aaaa: () => Aaaa,
|
|
84
|
-
Caa: () => Caa,
|
|
85
|
-
Cname: () => Cname,
|
|
86
|
-
Mx: () => Mx,
|
|
87
|
-
Ns: () => Ns,
|
|
88
|
-
Observed: () => Observed,
|
|
89
|
-
Opaque: () => Opaque,
|
|
90
|
-
RequirementMetadata: () => RequirementMetadata,
|
|
91
|
-
Schema: () => RecordSchema,
|
|
92
|
-
Srv: () => Srv,
|
|
93
|
-
Txt: () => Txt,
|
|
94
|
-
Type: () => Type,
|
|
95
|
-
data: () => data,
|
|
96
|
-
decode: () => decode$1,
|
|
97
|
-
equals: () => equals,
|
|
98
|
-
parse: () => parse
|
|
99
|
-
});
|
|
100
|
-
const Type = Schema.Literals([
|
|
101
|
-
"A",
|
|
102
|
-
"AAAA",
|
|
103
|
-
"CNAME",
|
|
104
|
-
"TXT",
|
|
105
|
-
"MX",
|
|
106
|
-
"CAA",
|
|
107
|
-
"NS",
|
|
108
|
-
"SRV"
|
|
109
|
-
]);
|
|
110
|
-
const RequirementMetadata = Schema.Struct({
|
|
111
|
-
ownership: Schema.String.check(Schema.isMinLength(1)),
|
|
112
|
-
provenance: Schema.String.check(Schema.isMinLength(1)),
|
|
113
|
-
purpose: Schema.String.check(Schema.isMinLength(1))
|
|
114
|
-
});
|
|
115
|
-
const CommonFields = {
|
|
116
|
-
metadata: RequirementMetadata,
|
|
117
|
-
name: Schema$2,
|
|
118
|
-
policy: Schema.Literals(["exclusive", "append"]),
|
|
119
|
-
ttl: Schema.NullOr(Schema.Int.check(Schema.isBetween({
|
|
120
|
-
minimum: 60,
|
|
121
|
-
maximum: 2147483647
|
|
122
|
-
})))
|
|
123
|
-
};
|
|
124
|
-
const ExclusiveCommonFields = {
|
|
125
|
-
...CommonFields,
|
|
126
|
-
policy: Schema.Literal("exclusive")
|
|
127
|
-
};
|
|
128
|
-
const Address = Schema.String.check(Schema.makeFilter((value) => isIpv4(value) ? void 0 : "Expected an IPv4 address"));
|
|
129
|
-
const Ipv6Address = Schema.String.check(Schema.makeFilter((value) => isIpv6(value) ? void 0 : "Expected an IPv6 address"));
|
|
130
|
-
const Port = Schema.Int.check(Schema.isBetween({
|
|
131
|
-
minimum: 0,
|
|
132
|
-
maximum: 65535
|
|
133
|
-
}));
|
|
134
|
-
const Priority = Schema.Int.check(Schema.isBetween({
|
|
135
|
-
minimum: 0,
|
|
136
|
-
maximum: 65535
|
|
137
|
-
}));
|
|
138
|
-
const RecordSchema = Schema.TaggedUnion({
|
|
139
|
-
A: {
|
|
140
|
-
...CommonFields,
|
|
141
|
-
address: Address
|
|
142
|
-
},
|
|
143
|
-
AAAA: {
|
|
144
|
-
...CommonFields,
|
|
145
|
-
address: Ipv6Address
|
|
146
|
-
},
|
|
147
|
-
CNAME: {
|
|
148
|
-
...ExclusiveCommonFields,
|
|
149
|
-
target: Schema$2
|
|
150
|
-
},
|
|
151
|
-
TXT: {
|
|
152
|
-
...CommonFields,
|
|
153
|
-
value: Schema.String.check(Schema.isMinLength(1))
|
|
154
|
-
},
|
|
155
|
-
MX: {
|
|
156
|
-
...CommonFields,
|
|
157
|
-
exchange: Schema$2,
|
|
158
|
-
priority: Priority
|
|
159
|
-
},
|
|
160
|
-
CAA: {
|
|
161
|
-
...CommonFields,
|
|
162
|
-
flags: Schema.Int.check(Schema.isBetween({
|
|
163
|
-
minimum: 0,
|
|
164
|
-
maximum: 255
|
|
165
|
-
})),
|
|
166
|
-
tag: Schema.Literals([
|
|
167
|
-
"issue",
|
|
168
|
-
"issuewild",
|
|
169
|
-
"iodef"
|
|
170
|
-
]),
|
|
171
|
-
value: Schema.String.check(Schema.isMinLength(1))
|
|
172
|
-
},
|
|
173
|
-
NS: {
|
|
174
|
-
...CommonFields,
|
|
175
|
-
target: Schema$2
|
|
176
|
-
},
|
|
177
|
-
SRV: {
|
|
178
|
-
...CommonFields,
|
|
179
|
-
port: Port,
|
|
180
|
-
priority: Priority,
|
|
181
|
-
target: Schema$2,
|
|
182
|
-
weight: Priority
|
|
183
|
-
}
|
|
184
|
-
});
|
|
185
|
-
/** Constructs an A record requirement from trusted application data. */
|
|
186
|
-
function A(input) {
|
|
187
|
-
return RecordSchema.cases.A.make(input);
|
|
188
|
-
}
|
|
189
|
-
(function(_A) {
|
|
190
|
-
_A.Schema = RecordSchema.cases.A;
|
|
191
|
-
})(A || (A = {}));
|
|
192
|
-
/** Constructs an AAAA record requirement from trusted application data. */
|
|
193
|
-
function Aaaa(input) {
|
|
194
|
-
return RecordSchema.cases.AAAA.make(input);
|
|
195
|
-
}
|
|
196
|
-
(function(_Aaaa) {
|
|
197
|
-
_Aaaa.Schema = RecordSchema.cases.AAAA;
|
|
198
|
-
})(Aaaa || (Aaaa = {}));
|
|
199
|
-
/** Constructs a CAA record requirement from trusted application data. */
|
|
200
|
-
function Caa(input) {
|
|
201
|
-
return RecordSchema.cases.CAA.make(input);
|
|
202
|
-
}
|
|
203
|
-
(function(_Caa) {
|
|
204
|
-
_Caa.Schema = RecordSchema.cases.CAA;
|
|
205
|
-
})(Caa || (Caa = {}));
|
|
206
|
-
/** Constructs a CNAME record requirement from trusted application data. */
|
|
207
|
-
function Cname(input) {
|
|
208
|
-
return RecordSchema.cases.CNAME.make(input);
|
|
209
|
-
}
|
|
210
|
-
(function(_Cname) {
|
|
211
|
-
_Cname.Schema = RecordSchema.cases.CNAME;
|
|
212
|
-
})(Cname || (Cname = {}));
|
|
213
|
-
/** Constructs an MX record requirement from trusted application data. */
|
|
214
|
-
function Mx(input) {
|
|
215
|
-
return RecordSchema.cases.MX.make(input);
|
|
216
|
-
}
|
|
217
|
-
(function(_Mx) {
|
|
218
|
-
_Mx.Schema = RecordSchema.cases.MX;
|
|
219
|
-
})(Mx || (Mx = {}));
|
|
220
|
-
/** Constructs an NS record requirement from trusted application data. */
|
|
221
|
-
function Ns(input) {
|
|
222
|
-
return RecordSchema.cases.NS.make(input);
|
|
223
|
-
}
|
|
224
|
-
(function(_Ns) {
|
|
225
|
-
_Ns.Schema = RecordSchema.cases.NS;
|
|
226
|
-
})(Ns || (Ns = {}));
|
|
227
|
-
/** Constructs an SRV record requirement from trusted application data. */
|
|
228
|
-
function Srv(input) {
|
|
229
|
-
return RecordSchema.cases.SRV.make(input);
|
|
230
|
-
}
|
|
231
|
-
(function(_Srv) {
|
|
232
|
-
_Srv.Schema = RecordSchema.cases.SRV;
|
|
233
|
-
})(Srv || (Srv = {}));
|
|
234
|
-
/** Constructs a TXT record requirement from trusted application data. */
|
|
235
|
-
function Txt(input) {
|
|
236
|
-
return RecordSchema.cases.TXT.make(input);
|
|
237
|
-
}
|
|
238
|
-
(function(_Txt) {
|
|
239
|
-
_Txt.Schema = RecordSchema.cases.TXT;
|
|
240
|
-
})(Txt || (Txt = {}));
|
|
241
|
-
/** Provider state that DomainKit cannot create but must retain for safe reconciliation. */
|
|
242
|
-
const OpaqueSchema = Schema.TaggedStruct("Opaque", {
|
|
243
|
-
name: Schema.String.check(Schema.isMinLength(1)),
|
|
244
|
-
providerRecordId: Schema.NullOr(Schema.String),
|
|
245
|
-
providerType: Schema.String.check(Schema.isMinLength(1))
|
|
246
|
-
});
|
|
247
|
-
/** Constructs an opaque provider record from trusted adapter data. */
|
|
248
|
-
function Opaque(input) {
|
|
249
|
-
return OpaqueSchema.make(input);
|
|
250
|
-
}
|
|
251
|
-
(function(_Opaque) {
|
|
252
|
-
_Opaque.Schema = OpaqueSchema;
|
|
253
|
-
})(Opaque || (Opaque = {}));
|
|
254
|
-
/** Any DNS record observed through a provider, including non-portable record types. */
|
|
255
|
-
const Observed = Schema.Union([RecordSchema, OpaqueSchema]);
|
|
256
|
-
const decode$1 = Effect.fn("DnsRecord.decode")((input) => Schema.decodeUnknownEffect(RecordSchema)(input).pipe(Effect.mapError((cause) => new Error$4({ message: cause.message }))));
|
|
257
|
-
function parse(input) {
|
|
258
|
-
try {
|
|
259
|
-
return Schema.decodeUnknownSync(RecordSchema)(input);
|
|
260
|
-
} catch (cause) {
|
|
261
|
-
throw new Error$4({ message: cause instanceof Error ? cause.message : String(cause) });
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
function data(record) {
|
|
265
|
-
switch (record._tag) {
|
|
266
|
-
case "A":
|
|
267
|
-
case "AAAA": return { address: record.address };
|
|
268
|
-
case "CNAME":
|
|
269
|
-
case "NS": return { target: record.target };
|
|
270
|
-
case "TXT": return { value: record.value };
|
|
271
|
-
case "MX": return {
|
|
272
|
-
exchange: record.exchange,
|
|
273
|
-
priority: record.priority
|
|
274
|
-
};
|
|
275
|
-
case "CAA": return {
|
|
276
|
-
flags: record.flags,
|
|
277
|
-
tag: record.tag,
|
|
278
|
-
value: record.value
|
|
279
|
-
};
|
|
280
|
-
case "SRV": return {
|
|
281
|
-
port: record.port,
|
|
282
|
-
priority: record.priority,
|
|
283
|
-
target: record.target,
|
|
284
|
-
weight: record.weight
|
|
285
|
-
};
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
function equals(left, right) {
|
|
289
|
-
return left._tag === right._tag && left.name === right.name && JSON.stringify(data(left)) === JSON.stringify(data(right));
|
|
290
|
-
}
|
|
291
|
-
function isIpv4(value) {
|
|
292
|
-
const parts = value.split(".");
|
|
293
|
-
return parts.length === 4 && parts.every((part) => /^\d{1,3}$/.test(part) && Number(part) <= 255 && String(Number(part)) === part);
|
|
294
|
-
}
|
|
295
|
-
function isIpv6(value) {
|
|
296
|
-
try {
|
|
297
|
-
return new URL(`http://[${value}]/`).hostname.startsWith("[");
|
|
298
|
-
} catch {
|
|
299
|
-
return false;
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
//#endregion
|
|
303
|
-
//#region src/provider/provider.ts
|
|
304
|
-
var provider_exports = /* @__PURE__ */ __exportAll({
|
|
305
|
-
Error: () => Error$3,
|
|
306
|
-
ErrorReason: () => ErrorReason,
|
|
307
|
-
Service: () => Service$1,
|
|
308
|
-
fromAsync: () => fromAsync,
|
|
309
|
-
layerFromAsync: () => layerFromAsync$1,
|
|
310
|
-
toAsync: () => toAsync$1
|
|
311
|
-
});
|
|
312
|
-
const ErrorReason = Schema.Literals([
|
|
313
|
-
"authentication",
|
|
314
|
-
"authorization",
|
|
315
|
-
"conflict",
|
|
316
|
-
"not_found",
|
|
317
|
-
"rate_limit",
|
|
318
|
-
"request",
|
|
319
|
-
"response",
|
|
320
|
-
"transport",
|
|
321
|
-
"unsupported"
|
|
322
|
-
]);
|
|
323
|
-
var Error$3 = class extends Schema.TaggedError()("ProviderError", {
|
|
324
|
-
cause: Schema.optionalKey(Schema.Unknown),
|
|
325
|
-
code: Schema.optionalKey(Schema.Union([Schema.Number, Schema.String])),
|
|
326
|
-
message: Schema.String,
|
|
327
|
-
operation: Schema.String,
|
|
328
|
-
providerId: Schema.String,
|
|
329
|
-
reason: Schema.optionalKey(ErrorReason),
|
|
330
|
-
retryAfterMs: Schema.optionalKey(Schema.Number),
|
|
331
|
-
status: Schema.optionalKey(Schema.Number)
|
|
332
|
-
}) {};
|
|
333
|
-
var Service$1 = class extends Context.Service()("@domainkit/DnsProvider") {};
|
|
334
|
-
const fromAsync = (provider) => Service$1.of({
|
|
335
|
-
id: provider.id,
|
|
336
|
-
createRecord: Effect.fn("DnsProvider.createRecord")((zone, record) => Effect.tryPromise({
|
|
337
|
-
try: () => provider.createRecord(zone, record),
|
|
338
|
-
catch: (cause) => failure(provider, "createRecord", cause)
|
|
339
|
-
})),
|
|
340
|
-
deleteRecord: Effect.fn("DnsProvider.deleteRecord")((zone, providerRecordId) => Effect.tryPromise({
|
|
341
|
-
try: () => provider.deleteRecord(zone, providerRecordId),
|
|
342
|
-
catch: (cause) => failure(provider, "deleteRecord", cause)
|
|
343
|
-
})),
|
|
344
|
-
getRecord: Effect.fn("DnsProvider.getRecord")((zone, providerRecordId) => Effect.tryPromise({
|
|
345
|
-
try: () => provider.getRecord(zone, providerRecordId),
|
|
346
|
-
catch: (cause) => failure(provider, "getRecord", cause)
|
|
347
|
-
})),
|
|
348
|
-
listRecords: Effect.fn("DnsProvider.listRecords")((zone) => Effect.tryPromise({
|
|
349
|
-
try: () => provider.listRecords(zone),
|
|
350
|
-
catch: (cause) => failure(provider, "listRecords", cause)
|
|
351
|
-
}))
|
|
352
|
-
});
|
|
353
|
-
const layerFromAsync$1 = (provider) => Layer.succeed(Service$1, fromAsync(provider));
|
|
354
|
-
const toAsync$1 = (provider) => ({
|
|
355
|
-
id: provider.id,
|
|
356
|
-
createRecord: (zone, record) => Effect.runPromise(provider.createRecord(zone, record)),
|
|
357
|
-
deleteRecord: (zone, providerRecordId) => Effect.runPromise(provider.deleteRecord(zone, providerRecordId)),
|
|
358
|
-
getRecord: (zone, providerRecordId) => Effect.runPromise(provider.getRecord(zone, providerRecordId)),
|
|
359
|
-
listRecords: (zone) => Effect.runPromise(provider.listRecords(zone))
|
|
360
|
-
});
|
|
361
|
-
function failure(provider, operation, cause) {
|
|
362
|
-
return cause instanceof Error$3 ? cause : new Error$3({
|
|
363
|
-
cause,
|
|
364
|
-
message: cause instanceof globalThis.Error ? cause.message : String(cause),
|
|
365
|
-
operation,
|
|
366
|
-
providerId: provider.id
|
|
367
|
-
});
|
|
368
|
-
}
|
|
369
|
-
//#endregion
|
|
370
|
-
//#region src/plan/types.ts
|
|
371
|
-
var types_exports = /* @__PURE__ */ __exportAll({
|
|
372
|
-
Authorization: () => Authorization$1,
|
|
373
|
-
Operation: () => Operation$1,
|
|
374
|
-
Receipt: () => Receipt$1,
|
|
375
|
-
Schema: () => Schema$1,
|
|
376
|
-
decode: () => decode,
|
|
377
|
-
decodeReceipt: () => decodeReceipt,
|
|
378
|
-
encode: () => encode,
|
|
379
|
-
encodeReceipt: () => encodeReceipt
|
|
380
|
-
});
|
|
381
|
-
const OperationSchema = Schema.TaggedUnion({
|
|
382
|
-
create: {
|
|
383
|
-
id: Schema.String,
|
|
384
|
-
requirement: RecordSchema
|
|
385
|
-
},
|
|
386
|
-
noop: {
|
|
387
|
-
id: Schema.String,
|
|
388
|
-
requirement: RecordSchema,
|
|
389
|
-
ttlDrift: Schema.Boolean
|
|
390
|
-
},
|
|
391
|
-
conflict: {
|
|
392
|
-
existing: Schema.Array(Observed),
|
|
393
|
-
id: Schema.String,
|
|
394
|
-
reason: Schema.String,
|
|
395
|
-
requirement: RecordSchema
|
|
396
|
-
}
|
|
397
|
-
});
|
|
398
|
-
/** DNS plan operation schema and callable constructors for trusted plan values. */
|
|
399
|
-
const Operation$1 = {
|
|
400
|
-
Schema: OperationSchema,
|
|
401
|
-
conflict: (input) => OperationSchema.cases.conflict.make(input),
|
|
402
|
-
create: (input) => OperationSchema.cases.create.make(input),
|
|
403
|
-
noop: (input) => OperationSchema.cases.noop.make(input)
|
|
404
|
-
};
|
|
405
|
-
const Schema$1 = Schema.Struct({
|
|
406
|
-
digest: Schema.String,
|
|
407
|
-
operations: Schema.Array(Operation$1.Schema),
|
|
408
|
-
providerId: Schema.String,
|
|
409
|
-
version: Schema.Literal("domainkit.dns-plan.v1"),
|
|
410
|
-
zone: Schema$2
|
|
411
|
-
});
|
|
412
|
-
const Authorization$1 = Schema.Struct({
|
|
413
|
-
allowPartial: Schema.Boolean,
|
|
414
|
-
operationIds: Schema.Array(Schema.String),
|
|
415
|
-
planDigest: Schema.String,
|
|
416
|
-
version: Schema.Literal("domainkit.plan-authorization.v1")
|
|
417
|
-
});
|
|
418
|
-
const Receipt$1 = Schema.Struct({
|
|
419
|
-
appliedAt: Schema.DateFromString,
|
|
420
|
-
operations: Schema.Array(Schema.Struct({
|
|
421
|
-
operationId: Schema.String,
|
|
422
|
-
providerRecordId: Schema.NullOr(Schema.String)
|
|
423
|
-
})),
|
|
424
|
-
planDigest: Schema.String,
|
|
425
|
-
providerId: Schema.String,
|
|
426
|
-
status: Schema.Literals(["complete", "partial"]),
|
|
427
|
-
version: Schema.Literal("domainkit.apply-receipt.v1"),
|
|
428
|
-
zone: Schema$2
|
|
429
|
-
});
|
|
430
|
-
const decode = Effect.fn("DnsPlan.decode")((input) => Schema.decodeUnknownEffect(Schema$1)(input).pipe(Effect.mapError((cause) => new Error$4({ message: cause.message }))));
|
|
431
|
-
const encode = Schema.encodeSync(Schema$1);
|
|
432
|
-
const decodeReceipt = Effect.fn("DnsPlan.decodeReceipt")((input) => Schema.decodeUnknownEffect(Receipt$1)(input).pipe(Effect.mapError((cause) => new Error$4({ message: cause.message }))));
|
|
433
|
-
const encodeReceipt = Schema.encodeSync(Receipt$1);
|
|
434
|
-
//#endregion
|
|
435
|
-
//#region src/plan/plan.ts
|
|
436
|
-
var plan_exports = /* @__PURE__ */ __exportAll({
|
|
437
|
-
AuthorizationError: () => AuthorizationError,
|
|
438
|
-
ConflictError: () => ConflictError,
|
|
439
|
-
CreateResult: () => CreateResult,
|
|
440
|
-
PartialApplyError: () => PartialApplyError,
|
|
441
|
-
StaleError: () => StaleError,
|
|
442
|
-
Target: () => Target,
|
|
443
|
-
apply: () => apply$1,
|
|
444
|
-
authorize: () => authorize$1,
|
|
445
|
-
create: () => create$1,
|
|
446
|
-
renderManualInstructions: () => renderManualInstructions,
|
|
447
|
-
validate: () => validate$1
|
|
448
|
-
});
|
|
449
|
-
const UnsignedPlan$1 = Schema.Struct({
|
|
450
|
-
operations: Schema.Array(Operation$1.Schema),
|
|
451
|
-
providerId: Schema.String,
|
|
452
|
-
version: Schema.Literal("domainkit.dns-plan.v1"),
|
|
453
|
-
zone: Schema$2
|
|
454
|
-
});
|
|
455
|
-
const RequirementDigest = Schema.Struct({ requirement: RecordSchema });
|
|
456
|
-
var ConflictError = class extends Schema.TaggedError()("PlanConflictError", { operationIds: Schema.Array(Schema.String) }) {};
|
|
457
|
-
var AuthorizationError = class extends Schema.TaggedError()("AuthorizationError", { message: Schema.String }) {};
|
|
458
|
-
var StaleError = class extends Schema.TaggedError()("StalePlanError", {
|
|
459
|
-
approvedPlanDigest: Schema.String,
|
|
460
|
-
currentPlanDigest: Schema.String
|
|
461
|
-
}) {};
|
|
462
|
-
var PartialApplyError = class extends Schema.TaggedError()("PartialApplyError", {
|
|
463
|
-
causeTag: Schema.Literals([
|
|
464
|
-
"CryptoError",
|
|
465
|
-
"InvalidInputError",
|
|
466
|
-
"Interrupted",
|
|
467
|
-
"ProviderError",
|
|
468
|
-
"StalePlanError"
|
|
469
|
-
]),
|
|
470
|
-
failedOperationId: Schema.String,
|
|
471
|
-
message: Schema.String,
|
|
472
|
-
receipt: Receipt$1
|
|
473
|
-
}) {};
|
|
474
|
-
const Target = Data.taggedEnum();
|
|
475
|
-
const CreateResult = Data.taggedEnum();
|
|
476
|
-
function create$1(input) {
|
|
477
|
-
const target = input.target;
|
|
478
|
-
if (target._tag === "ExactZone") return Effect.gen(function* () {
|
|
479
|
-
const provider = yield* Service$1;
|
|
480
|
-
const zone = yield* decode$2(target.zone);
|
|
481
|
-
return CreateResult.Resolved({
|
|
482
|
-
candidate: null,
|
|
483
|
-
plan: yield* planAgainst(provider, zone, input.requirements)
|
|
484
|
-
});
|
|
485
|
-
}).pipe(Effect.withSpan("Provisioning.create"));
|
|
486
|
-
return Effect.gen(function* () {
|
|
487
|
-
const discovery = yield* Service$2;
|
|
488
|
-
const domain = yield* decode$2(target.domain);
|
|
489
|
-
const outcome = yield* discovery.discover(domain);
|
|
490
|
-
switch (outcome._tag) {
|
|
491
|
-
case "NotFound": return CreateResult.NotFound({ domain: outcome.domain });
|
|
492
|
-
case "SelectionRequired": return CreateResult.SelectionRequired({ candidates: outcome.candidates });
|
|
493
|
-
case "Resolved": return CreateResult.Resolved({
|
|
494
|
-
candidate: outcome.candidate,
|
|
495
|
-
plan: yield* planAgainst(outcome.provider, outcome.candidate.name, input.requirements)
|
|
496
|
-
});
|
|
497
|
-
}
|
|
498
|
-
}).pipe(Effect.withSpan("Provisioning.create"));
|
|
499
|
-
}
|
|
500
|
-
const planAgainst = Effect.fn("Provisioning.planAgainst")(function* (provider, zone, inputs) {
|
|
501
|
-
const requirements = (yield* Effect.forEach(inputs, decode$1, { concurrency: "unbounded" })).sort(compareRecords);
|
|
502
|
-
const existing = [...yield* provider.listRecords(zone)].sort(compareRecords);
|
|
503
|
-
const { operations } = yield* Effect.reduce(requirements, () => ({
|
|
504
|
-
operations: [],
|
|
505
|
-
projected: existing
|
|
506
|
-
}), (state, requirement) => reconcileRequirement(requirement, state.projected).pipe(Effect.map((operation) => ({
|
|
507
|
-
operations: [...state.operations, operation],
|
|
508
|
-
projected: operation._tag === "create" ? [...state.projected, operation.requirement].sort(compareRecords) : state.projected
|
|
509
|
-
}))));
|
|
510
|
-
const unsigned = {
|
|
511
|
-
operations,
|
|
512
|
-
providerId: provider.id,
|
|
513
|
-
version: "domainkit.dns-plan.v1",
|
|
514
|
-
zone
|
|
515
|
-
};
|
|
516
|
-
return {
|
|
517
|
-
...unsigned,
|
|
518
|
-
digest: yield* sha256Encoded(UnsignedPlan$1, unsigned)
|
|
519
|
-
};
|
|
520
|
-
});
|
|
521
|
-
/** Authorizes all or a selected subset of create operations in a digest-bound plan. */
|
|
522
|
-
const authorize$1 = Effect.fn("Provisioning.authorize")(function* (plan, operationIds, options = {}) {
|
|
523
|
-
yield* validate$1(plan);
|
|
524
|
-
const createIds = plan.operations.filter((operation) => operation._tag === "create").map(({ id }) => id);
|
|
525
|
-
const selected = [...new Set(operationIds ?? createIds)].sort();
|
|
526
|
-
const unknown = selected.filter((id) => !createIds.includes(id));
|
|
527
|
-
if (unknown.length > 0) return yield* new AuthorizationError({ message: `Unknown operation IDs: ${unknown.join(", ")}` });
|
|
528
|
-
if (!options.allowPartial && selected.length !== createIds.length) return yield* new AuthorizationError({ message: "Partial authorization requires allowPartial" });
|
|
529
|
-
return {
|
|
530
|
-
allowPartial: options.allowPartial ?? false,
|
|
531
|
-
operationIds: selected,
|
|
532
|
-
planDigest: plan.digest,
|
|
533
|
-
version: "domainkit.plan-authorization.v1"
|
|
534
|
-
};
|
|
535
|
-
});
|
|
536
|
-
/** Applies approved creates sequentially after full and per-operation revalidation. */
|
|
537
|
-
const apply$1 = Effect.fn("Provisioning.apply")(function* (input) {
|
|
538
|
-
const { authorization, plan } = input;
|
|
539
|
-
const provider = yield* Service$1;
|
|
540
|
-
yield* validate$1(plan);
|
|
541
|
-
if (authorization.planDigest !== plan.digest) return yield* new AuthorizationError({ message: "Authorization belongs to a different plan" });
|
|
542
|
-
if (provider.id !== plan.providerId) return yield* new AuthorizationError({ message: "Provider does not match the approved plan" });
|
|
543
|
-
const conflicts = plan.operations.filter((operation) => operation._tag === "conflict");
|
|
544
|
-
if (conflicts.length > 0) return yield* new ConflictError({ operationIds: conflicts.map(({ id }) => id) });
|
|
545
|
-
const creates = plan.operations.filter((operation) => operation._tag === "create");
|
|
546
|
-
const approved = new Set(authorization.operationIds);
|
|
547
|
-
const unknown = authorization.operationIds.filter((id) => !creates.some((operation) => operation.id === id));
|
|
548
|
-
if (unknown.length > 0) return yield* new AuthorizationError({ message: `Authorization contains unknown operations: ${unknown.join(", ")}` });
|
|
549
|
-
if (!authorization.allowPartial && creates.some(({ id }) => !approved.has(id))) return yield* new AuthorizationError({ message: "Authorization does not cover every create operation" });
|
|
550
|
-
const currentPlan = yield* planAgainst(provider, plan.zone, plan.operations.map(({ requirement }) => requirement));
|
|
551
|
-
if (currentPlan.digest !== plan.digest) return yield* new StaleError({
|
|
552
|
-
approvedPlanDigest: plan.digest,
|
|
553
|
-
currentPlanDigest: currentPlan.digest
|
|
554
|
-
});
|
|
555
|
-
const operations = [];
|
|
556
|
-
for (const operation of creates) {
|
|
557
|
-
if (!approved.has(operation.id)) continue;
|
|
558
|
-
yield* Effect.gen(function* () {
|
|
559
|
-
yield* assertStillCreatable(plan, operation);
|
|
560
|
-
const result = yield* provider.createRecord(plan.zone, operation.requirement);
|
|
561
|
-
operations.push({
|
|
562
|
-
operationId: operation.id,
|
|
563
|
-
providerRecordId: result.providerRecordId
|
|
564
|
-
});
|
|
565
|
-
}).pipe(Effect.catch((failure) => operations.length === 0 ? Effect.fail(failure) : makeReceipt$1(input, operations, "partial").pipe(Effect.flatMap((receipt) => Effect.fail(new PartialApplyError({
|
|
566
|
-
causeTag: failure._tag,
|
|
567
|
-
failedOperationId: operation.id,
|
|
568
|
-
message: failureMessage(failure),
|
|
569
|
-
receipt
|
|
570
|
-
}))))), Effect.catchCause((cause) => {
|
|
571
|
-
if (!Cause.hasInterruptsOnly(cause) || operations.length === 0) return Effect.failCause(cause);
|
|
572
|
-
return makeReceipt$1(input, operations, "partial").pipe(Effect.flatMap((receipt) => Effect.fail(new PartialApplyError({
|
|
573
|
-
causeTag: "Interrupted",
|
|
574
|
-
failedOperationId: operation.id,
|
|
575
|
-
message: "DNS apply was interrupted after confirmed writes",
|
|
576
|
-
receipt
|
|
577
|
-
}))));
|
|
578
|
-
}));
|
|
579
|
-
}
|
|
580
|
-
return yield* makeReceipt$1(input, operations, "complete");
|
|
581
|
-
});
|
|
582
|
-
function renderManualInstructions(plan) {
|
|
583
|
-
return plan.operations.map((operation) => {
|
|
584
|
-
const record = operation.requirement;
|
|
585
|
-
const data$1 = Object.entries(data(record)).map(([key, value]) => `${key}=${value}`).join(" ");
|
|
586
|
-
return `${operation._tag.toUpperCase()} ${record._tag} ${record.name} ${data$1}`.trim();
|
|
587
|
-
});
|
|
588
|
-
}
|
|
589
|
-
function makeReceipt$1(input, operations, status) {
|
|
590
|
-
return Clock.currentTimeMillis.pipe(Effect.map((now) => ({
|
|
591
|
-
appliedAt: new Date(now),
|
|
592
|
-
operations,
|
|
593
|
-
planDigest: input.plan.digest,
|
|
594
|
-
providerId: input.plan.providerId,
|
|
595
|
-
status,
|
|
596
|
-
version: "domainkit.apply-receipt.v1",
|
|
597
|
-
zone: input.plan.zone
|
|
598
|
-
})));
|
|
599
|
-
}
|
|
600
|
-
function assertStillCreatable(plan, operation) {
|
|
601
|
-
return Service$1.pipe(Effect.flatMap((provider) => planAgainst(provider, plan.zone, [operation.requirement])), Effect.flatMap((currentPlan) => {
|
|
602
|
-
const currentOperation = currentPlan.operations[0];
|
|
603
|
-
return currentOperation?._tag === "create" && currentOperation.id === operation.id ? Effect.void : Effect.fail(new StaleError({
|
|
604
|
-
approvedPlanDigest: plan.digest,
|
|
605
|
-
currentPlanDigest: currentPlan.digest
|
|
606
|
-
}));
|
|
607
|
-
}));
|
|
608
|
-
}
|
|
609
|
-
function reconcileRequirement(requirement, allExisting) {
|
|
610
|
-
return Effect.gen(function* () {
|
|
611
|
-
const sameName = allExisting.filter((record) => record.name === requirement.name);
|
|
612
|
-
const sameSet = sameName.filter((record) => record._tag !== "Opaque" && record._tag === requirement._tag);
|
|
613
|
-
const exact = sameSet.find((record) => equals(record, requirement));
|
|
614
|
-
const id = yield* sha256Encoded(RequirementDigest, { requirement });
|
|
615
|
-
if (exact !== void 0) return Operation$1.noop({
|
|
616
|
-
id,
|
|
617
|
-
requirement,
|
|
618
|
-
ttlDrift: exact.ttl !== requirement.ttl
|
|
619
|
-
});
|
|
620
|
-
if (sameName.length > 0 && (requirement._tag === "CNAME" || sameName.some((record) => record._tag === "CNAME"))) return Operation$1.conflict({
|
|
621
|
-
existing: sameName,
|
|
622
|
-
id,
|
|
623
|
-
reason: "CNAME records cannot coexist with other records at the same name",
|
|
624
|
-
requirement
|
|
625
|
-
});
|
|
626
|
-
if (sameSet.length > 0 && (requirement.policy === "exclusive" || sameSet.some(({ policy }) => policy === "exclusive"))) return Operation$1.conflict({
|
|
627
|
-
existing: sameSet,
|
|
628
|
-
id,
|
|
629
|
-
reason: "The exclusive record set already contains incompatible data",
|
|
630
|
-
requirement
|
|
631
|
-
});
|
|
632
|
-
return Operation$1.create({
|
|
633
|
-
id,
|
|
634
|
-
requirement
|
|
635
|
-
});
|
|
636
|
-
});
|
|
637
|
-
}
|
|
638
|
-
function validate$1(plan) {
|
|
639
|
-
const unsigned = {
|
|
640
|
-
operations: plan.operations,
|
|
641
|
-
providerId: plan.providerId,
|
|
642
|
-
version: plan.version,
|
|
643
|
-
zone: plan.zone
|
|
644
|
-
};
|
|
645
|
-
return sha256Encoded(UnsignedPlan$1, unsigned).pipe(Effect.flatMap((digest) => digest === plan.digest ? Effect.void : Effect.fail(new AuthorizationError({ message: "Plan digest does not match its contents" }))));
|
|
646
|
-
}
|
|
647
|
-
function failureMessage(failure) {
|
|
648
|
-
return failure._tag === "StalePlanError" ? "DNS state changed while applying the approved plan" : failure.message;
|
|
649
|
-
}
|
|
650
|
-
function compareRecords(left, right) {
|
|
651
|
-
const encode = Schema.encodeSync(Observed);
|
|
652
|
-
const toJson = Schema.decodeUnknownSync(Schema.Json);
|
|
653
|
-
const leftJson = stringify(toJson(encode(left)));
|
|
654
|
-
const rightJson = stringify(toJson(encode(right)));
|
|
655
|
-
return leftJson < rightJson ? -1 : leftJson > rightJson ? 1 : 0;
|
|
656
|
-
}
|
|
657
|
-
//#endregion
|
|
658
|
-
//#region src/plan/deletion.ts
|
|
659
|
-
var deletion_exports = /* @__PURE__ */ __exportAll({
|
|
660
|
-
Authorization: () => Authorization,
|
|
661
|
-
Error: () => Error$2,
|
|
662
|
-
Operation: () => Operation,
|
|
663
|
-
PartialError: () => PartialError,
|
|
664
|
-
Plan: () => Plan,
|
|
665
|
-
Receipt: () => Receipt,
|
|
666
|
-
apply: () => apply,
|
|
667
|
-
authorize: () => authorize,
|
|
668
|
-
create: () => create,
|
|
669
|
-
validate: () => validate
|
|
670
|
-
});
|
|
671
|
-
const Operation = Schema.Struct({
|
|
672
|
-
id: Schema.String,
|
|
673
|
-
providerRecordId: Schema.String,
|
|
674
|
-
record: RecordSchema
|
|
675
|
-
});
|
|
676
|
-
const UnsignedPlan = Schema.Struct({
|
|
677
|
-
createdAt: Schema.DateFromString,
|
|
678
|
-
expiresAt: Schema.DateFromString,
|
|
679
|
-
operations: Schema.Array(Operation),
|
|
680
|
-
providerId: Schema.String,
|
|
681
|
-
sourcePlanDigest: Schema.String,
|
|
682
|
-
version: Schema.Literal("domainkit.deletion-plan.v1"),
|
|
683
|
-
zone: Schema$2
|
|
684
|
-
});
|
|
685
|
-
const Plan = Schema.Struct({
|
|
686
|
-
...UnsignedPlan.fields,
|
|
687
|
-
digest: Schema.String
|
|
688
|
-
});
|
|
689
|
-
const Authorization = Schema.Struct({
|
|
690
|
-
operationIds: Schema.Array(Schema.String),
|
|
691
|
-
planDigest: Schema.String,
|
|
692
|
-
version: Schema.Literal("domainkit.deletion-authorization.v1")
|
|
693
|
-
});
|
|
694
|
-
const Receipt = Schema.Struct({
|
|
695
|
-
deletedAt: Schema.DateFromString,
|
|
696
|
-
operations: Schema.Array(Schema.Struct({
|
|
697
|
-
operationId: Schema.String,
|
|
698
|
-
providerRecordId: Schema.String
|
|
699
|
-
})),
|
|
700
|
-
planDigest: Schema.String,
|
|
701
|
-
providerId: Schema.String,
|
|
702
|
-
status: Schema.Literals(["complete", "partial"]),
|
|
703
|
-
version: Schema.Literal("domainkit.deletion-receipt.v1"),
|
|
704
|
-
zone: Schema$2
|
|
705
|
-
});
|
|
706
|
-
var Error$2 = class extends Schema.TaggedError()("UnsafeDeletionError", {
|
|
707
|
-
message: Schema.String,
|
|
708
|
-
operationId: Schema.optionalKey(Schema.String)
|
|
709
|
-
}) {};
|
|
710
|
-
var PartialError = class extends Schema.TaggedError()("PartialDeletionError", {
|
|
711
|
-
failedOperationId: Schema.String,
|
|
712
|
-
message: Schema.String,
|
|
713
|
-
receipt: Receipt
|
|
714
|
-
}) {};
|
|
715
|
-
/** Build a fresh deletion plan only from records proven by a prior create receipt. */
|
|
716
|
-
const create = Effect.fn("Deletion.create")(function* (input) {
|
|
717
|
-
const provider = yield* Service$1;
|
|
718
|
-
yield* validate$1(input.plan);
|
|
719
|
-
if (input.receipt.planDigest !== input.plan.digest || input.receipt.providerId !== input.plan.providerId || input.receipt.zone !== input.plan.zone) return yield* new Error$2({ message: "Create receipt does not belong to the source plan" });
|
|
720
|
-
if (provider.id !== input.plan.providerId) return yield* new Error$2({ message: "Provider does not match the source receipt" });
|
|
721
|
-
const operations = yield* Effect.forEach(input.receipt.operations, (applied) => Effect.gen(function* () {
|
|
722
|
-
const source = input.plan.operations.find((operation) => operation._tag === "create" && operation.id === applied.operationId);
|
|
723
|
-
if (source === void 0 || source._tag !== "create") return yield* new Error$2({
|
|
724
|
-
message: "Receipt operation is not a created source record",
|
|
725
|
-
operationId: applied.operationId
|
|
726
|
-
});
|
|
727
|
-
if (applied.providerRecordId === null) return yield* new Error$2({
|
|
728
|
-
message: "Provider record ID is required for safe deletion",
|
|
729
|
-
operationId: applied.operationId
|
|
730
|
-
});
|
|
731
|
-
yield* assertExact(provider, input.plan.zone, applied.providerRecordId, source.requirement, source.id);
|
|
732
|
-
return {
|
|
733
|
-
id: source.id,
|
|
734
|
-
providerRecordId: applied.providerRecordId,
|
|
735
|
-
record: source.requirement
|
|
736
|
-
};
|
|
737
|
-
}));
|
|
738
|
-
const now = yield* Clock.currentTimeMillis;
|
|
739
|
-
const unsigned = {
|
|
740
|
-
createdAt: new Date(now),
|
|
741
|
-
expiresAt: new Date(now + (input.ttlMs ?? 9e5)),
|
|
742
|
-
operations,
|
|
743
|
-
providerId: input.plan.providerId,
|
|
744
|
-
sourcePlanDigest: input.plan.digest,
|
|
745
|
-
version: "domainkit.deletion-plan.v1",
|
|
746
|
-
zone: input.plan.zone
|
|
747
|
-
};
|
|
748
|
-
return {
|
|
749
|
-
...unsigned,
|
|
750
|
-
digest: yield* sha256Encoded(UnsignedPlan, unsigned)
|
|
751
|
-
};
|
|
752
|
-
});
|
|
753
|
-
/** Produce a separate digest-bound consent artifact for destructive operations. */
|
|
754
|
-
const authorize = Effect.fn("Deletion.authorize")(function* (plan, operationIds) {
|
|
755
|
-
yield* validate(plan);
|
|
756
|
-
const selected = [...new Set(operationIds ?? plan.operations.map(({ id }) => id))].sort();
|
|
757
|
-
const unknown = selected.filter((id) => !plan.operations.some((operation) => operation.id === id));
|
|
758
|
-
if (unknown.length > 0) return yield* new Error$2({ message: `Unknown deletion operation IDs: ${unknown.join(", ")}` });
|
|
759
|
-
return {
|
|
760
|
-
operationIds: selected,
|
|
761
|
-
planDigest: plan.digest,
|
|
762
|
-
version: "domainkit.deletion-authorization.v1"
|
|
763
|
-
};
|
|
764
|
-
});
|
|
765
|
-
/** Re-read every approved record before the first delete, then delete by provider record ID. */
|
|
766
|
-
const apply = Effect.fn("Deletion.apply")(function* (input) {
|
|
767
|
-
const provider = yield* Service$1;
|
|
768
|
-
yield* validate(input.plan);
|
|
769
|
-
if (input.authorization.planDigest !== input.plan.digest) return yield* new Error$2({ message: "Deletion authorization belongs to a different plan" });
|
|
770
|
-
if (provider.id !== input.plan.providerId) return yield* new Error$2({ message: "Provider does not match the deletion plan" });
|
|
771
|
-
const now = yield* Clock.currentTimeMillis;
|
|
772
|
-
if (input.plan.expiresAt <= new Date(now)) return yield* new Error$2({ message: "Deletion plan has expired" });
|
|
773
|
-
const selected = input.plan.operations.filter(({ id }) => input.authorization.operationIds.includes(id));
|
|
774
|
-
if (selected.length !== input.authorization.operationIds.length) return yield* new Error$2({ message: "Deletion authorization contains unknown operations" });
|
|
775
|
-
const previouslyDeleted = yield* validatePriorReceipt(input.plan, input.priorReceipt);
|
|
776
|
-
const completedIds = new Set(previouslyDeleted.map(({ operationId }) => operationId));
|
|
777
|
-
if (previouslyDeleted.some(({ operationId }) => !input.authorization.operationIds.includes(operationId))) return yield* new Error$2({ message: "Prior receipt contains an unauthorized operation" });
|
|
778
|
-
const remaining = selected.filter(({ id }) => !completedIds.has(id));
|
|
779
|
-
yield* Effect.forEach(remaining, (operation) => assertExact(provider, input.plan.zone, operation.providerRecordId, operation.record, operation.id));
|
|
780
|
-
const deleted = [...previouslyDeleted];
|
|
781
|
-
for (const operation of remaining) {
|
|
782
|
-
const failure = yield* Effect.gen(function* () {
|
|
783
|
-
yield* assertExact(provider, input.plan.zone, operation.providerRecordId, operation.record, operation.id);
|
|
784
|
-
yield* provider.deleteRecord(input.plan.zone, operation.providerRecordId);
|
|
785
|
-
deleted.push({
|
|
786
|
-
operationId: operation.id,
|
|
787
|
-
providerRecordId: operation.providerRecordId
|
|
788
|
-
});
|
|
789
|
-
}).pipe(Effect.match({
|
|
790
|
-
onFailure: (cause) => cause,
|
|
791
|
-
onSuccess: () => null
|
|
792
|
-
}));
|
|
793
|
-
if (failure !== null) {
|
|
794
|
-
if (deleted.length === 0) return yield* failure;
|
|
795
|
-
return yield* new PartialError({
|
|
796
|
-
failedOperationId: operation.id,
|
|
797
|
-
message: failure.message,
|
|
798
|
-
receipt: yield* makeReceipt(input.plan, deleted, "partial")
|
|
799
|
-
});
|
|
800
|
-
}
|
|
801
|
-
}
|
|
802
|
-
return yield* makeReceipt(input.plan, deleted, "complete");
|
|
803
|
-
});
|
|
804
|
-
function validate(plan) {
|
|
805
|
-
const unsigned = {
|
|
806
|
-
createdAt: plan.createdAt,
|
|
807
|
-
expiresAt: plan.expiresAt,
|
|
808
|
-
operations: plan.operations,
|
|
809
|
-
providerId: plan.providerId,
|
|
810
|
-
sourcePlanDigest: plan.sourcePlanDigest,
|
|
811
|
-
version: plan.version,
|
|
812
|
-
zone: plan.zone
|
|
813
|
-
};
|
|
814
|
-
return sha256Encoded(UnsignedPlan, unsigned).pipe(Effect.flatMap((digest) => digest === plan.digest ? Effect.void : Effect.fail(new Error$2({ message: "Deletion plan digest does not match its contents" }))));
|
|
815
|
-
}
|
|
816
|
-
function validatePriorReceipt(plan, receipt) {
|
|
817
|
-
if (receipt === void 0) return Effect.succeed([]);
|
|
818
|
-
if (receipt.planDigest !== plan.digest || receipt.providerId !== plan.providerId || receipt.zone !== plan.zone || receipt.status !== "partial") return Effect.fail(new Error$2({ message: "Prior receipt does not belong to this deletion plan" }));
|
|
819
|
-
for (const completed of receipt.operations) {
|
|
820
|
-
const operation = plan.operations.find(({ id }) => id === completed.operationId);
|
|
821
|
-
if (operation === void 0 || operation.providerRecordId !== completed.providerRecordId) return Effect.fail(new Error$2({ message: "Prior receipt operation does not match the deletion plan" }));
|
|
822
|
-
}
|
|
823
|
-
return Effect.succeed([...receipt.operations]);
|
|
824
|
-
}
|
|
825
|
-
function assertExact(provider, zone, providerRecordId, expected, operationId) {
|
|
826
|
-
return provider.getRecord(zone, providerRecordId).pipe(Effect.flatMap((observed) => observed !== null && observed._tag !== "Opaque" && equals(observed, expected) ? Effect.void : Effect.fail(new Error$2({
|
|
827
|
-
message: observed === null ? "Created record no longer exists" : "Created record content no longer matches its receipt",
|
|
828
|
-
operationId
|
|
829
|
-
}))));
|
|
830
|
-
}
|
|
831
|
-
function makeReceipt(plan, operations, status) {
|
|
832
|
-
return Clock.currentTimeMillis.pipe(Effect.map((now) => ({
|
|
833
|
-
deletedAt: new Date(now),
|
|
834
|
-
operations,
|
|
835
|
-
planDigest: plan.digest,
|
|
836
|
-
providerId: plan.providerId,
|
|
837
|
-
status,
|
|
838
|
-
version: "domainkit.deletion-receipt.v1",
|
|
839
|
-
zone: plan.zone
|
|
840
|
-
})));
|
|
841
|
-
}
|
|
842
|
-
//#endregion
|
|
843
|
-
//#region src/verification/resolver.ts
|
|
844
|
-
var resolver_exports = /* @__PURE__ */ __exportAll({
|
|
845
|
-
Answer: () => Answer,
|
|
846
|
-
AsyncResolution: () => AsyncResolution,
|
|
847
|
-
Error: () => Error$1,
|
|
848
|
-
Resolution: () => Resolution,
|
|
849
|
-
Service: () => Service,
|
|
850
|
-
layerFromAsync: () => layerFromAsync,
|
|
851
|
-
toAsync: () => toAsync
|
|
852
|
-
});
|
|
853
|
-
const Answer = Schema.Struct({
|
|
854
|
-
data: Schema.String,
|
|
855
|
-
name: Schema$2,
|
|
856
|
-
ttl: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),
|
|
857
|
-
type: Type
|
|
858
|
-
});
|
|
859
|
-
const ResolutionSchema = Schema.TaggedUnion({
|
|
860
|
-
answer: { answers: Schema.Array(Answer) },
|
|
861
|
-
nodata: {}
|
|
862
|
-
});
|
|
863
|
-
/** DNS answer schema and callable constructors for trusted resolver values. */
|
|
864
|
-
const Resolution = {
|
|
865
|
-
Schema: ResolutionSchema,
|
|
866
|
-
answer: (input) => ResolutionSchema.cases.answer.make(input),
|
|
867
|
-
nodata: () => ResolutionSchema.cases.nodata.make({})
|
|
868
|
-
};
|
|
869
|
-
var Error$1 = class extends Schema.TaggedError()("ResolverError", {
|
|
870
|
-
cause: Schema.optionalKey(Schema.Unknown),
|
|
871
|
-
message: Schema.String,
|
|
872
|
-
reason: Schema.Literals([
|
|
873
|
-
"response",
|
|
874
|
-
"timeout",
|
|
875
|
-
"transport"
|
|
876
|
-
])
|
|
877
|
-
}) {};
|
|
878
|
-
var Service = class extends Context.Service()("@domainkit/DnsResolver") {};
|
|
879
|
-
const AsyncResolutionSchema = Schema.TaggedUnion({
|
|
880
|
-
answer: { answers: Schema.Array(Answer) },
|
|
881
|
-
nodata: {},
|
|
882
|
-
timeout: {},
|
|
883
|
-
failure: { message: Schema.String }
|
|
884
|
-
});
|
|
885
|
-
/** Promise bridge result schema and callable constructors, including typed failures. */
|
|
886
|
-
const AsyncResolution = {
|
|
887
|
-
Schema: AsyncResolutionSchema,
|
|
888
|
-
answer: (input) => AsyncResolutionSchema.cases.answer.make(input),
|
|
889
|
-
failure: (input) => AsyncResolutionSchema.cases.failure.make(input),
|
|
890
|
-
nodata: () => AsyncResolutionSchema.cases.nodata.make({}),
|
|
891
|
-
timeout: () => AsyncResolutionSchema.cases.timeout.make({})
|
|
892
|
-
};
|
|
893
|
-
const layerFromAsync = (resolver) => Layer.succeed(Service, { resolve: Effect.fn("DnsResolver.resolve")((query) => Effect.tryPromise({
|
|
894
|
-
try: () => resolver.resolve(query),
|
|
895
|
-
catch: (cause) => new Error$1({
|
|
896
|
-
cause,
|
|
897
|
-
message: cause instanceof globalThis.Error ? cause.message : String(cause),
|
|
898
|
-
reason: "transport"
|
|
899
|
-
})
|
|
900
|
-
}).pipe(Effect.flatMap((resolution) => {
|
|
901
|
-
switch (resolution._tag) {
|
|
902
|
-
case "answer":
|
|
903
|
-
case "nodata": return Effect.succeed(resolution);
|
|
904
|
-
case "timeout": return Effect.fail(new Error$1({
|
|
905
|
-
message: "DNS query timed out",
|
|
906
|
-
reason: "timeout"
|
|
907
|
-
}));
|
|
908
|
-
case "failure": return Effect.fail(new Error$1({
|
|
909
|
-
message: resolution.message,
|
|
910
|
-
reason: "transport"
|
|
911
|
-
}));
|
|
912
|
-
}
|
|
913
|
-
}))) });
|
|
914
|
-
const toAsync = (resolver) => ({ resolve: (query) => Effect.runPromise(resolver.resolve(query).pipe(Effect.match({
|
|
915
|
-
onFailure: (failure) => failure.reason === "timeout" ? AsyncResolution.timeout() : AsyncResolution.failure({ message: failure.message }),
|
|
916
|
-
onSuccess: (resolution) => resolution
|
|
917
|
-
}))) });
|
|
918
|
-
//#endregion
|
|
919
|
-
export { Txt as $, Schema$1 as A, provider_exports as B, authorize$1 as C, Authorization$1 as D, renderManualInstructions as E, types_exports as F, Cname as G, A as H, Error$3 as I, Observed as J, Mx as K, Service$1 as L, decodeReceipt as M, encode as N, Operation$1 as O, encodeReceipt as P, Srv as Q, fromAsync as R, apply$1 as S, plan_exports as T, Aaaa as U, toAsync$1 as V, Caa as W, RecordSchema as X, Opaque as Y, RequirementMetadata as Z, ConflictError as _, resolver_exports as a, parse as at, StaleError as b, Error$2 as c, make as ct, Plan as d, zones_exports as dt, Type as et, Receipt as f, deletion_exports as g, create as h, Service as i, equals as it, decode as j, Receipt$1 as k, Operation as l, zone_discovery_exports as lt, authorize as m, Error$1 as n, decode$1 as nt, toAsync as o, Candidate as ot, apply as p, Ns as q, Resolution as r, dns_record_exports as rt, Authorization as s, Service$2 as st, AsyncResolution as t, data as tt, PartialError as u, candidates as ut, CreateResult as v, create$1 as w, Target as x, PartialApplyError as y, layerFromAsync$1 as z };
|
|
920
|
-
|
|
921
|
-
//# sourceMappingURL=resolver-BeGz1ukw.mjs.map
|