domainkit 0.7.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +214 -39
- 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 -356
- 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 +152 -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 +89 -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-10vHuShV.d.mts +0 -1401
- package/dist/connect-oI8hcMxc.mjs +0 -185
- package/dist/connect-oI8hcMxc.mjs.map +0 -1
- package/dist/connection-C0xsU41C.d.mts +0 -186
- package/dist/connection-api-DW7xUJdj.d.mts +0 -26
- package/dist/index.d.mts +0 -882
- 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-DPJs8h0a.mjs +0 -859
- package/dist/resolver-DPJs8h0a.mjs.map +0 -1
- package/dist/resolver-DRrLm_hB.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-C3V_GtzL.d.mts +0 -1268
- package/dist/verify-DDnK8U7C.mjs +0 -2396
- package/dist/verify-DDnK8U7C.mjs.map +0 -1
package/dist/Verify.mjs
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import { __exportAll } from "./_virtual/_rolldown/runtime.mjs";
|
|
2
|
+
import { decode } from "./DomainName.mjs";
|
|
3
|
+
import { data, equals, sameSet } from "./DnsRecord.mjs";
|
|
4
|
+
import { InvalidInput } from "./Reason.mjs";
|
|
5
|
+
import { decode as decode$1, fail } from "./internal/error.mjs";
|
|
6
|
+
import { Service as Service$1 } from "./Principal.mjs";
|
|
7
|
+
import { Service as Service$2 } from "./Resolver.mjs";
|
|
8
|
+
import { Readiness, RequirementStatus, Service as Service$3 } from "./Storage.mjs";
|
|
9
|
+
import { Service as Service$4 } from "./Connect.mjs";
|
|
10
|
+
import { Context, DateTime, Duration, Effect, Layer, Option, Schema } from "effect";
|
|
11
|
+
//#region src/Verify.ts
|
|
12
|
+
/**
|
|
13
|
+
* Observe provider and public DNS for an attachment, persist per-requirement readiness, and say
|
|
14
|
+
* when to look again. The host keeps its own state machine (and any provider-side verification
|
|
15
|
+
* such as SES) and feeds that in as `HostEvidence`.
|
|
16
|
+
*/
|
|
17
|
+
var Verify_exports = /* @__PURE__ */ __exportAll({
|
|
18
|
+
Evidence: () => Evidence,
|
|
19
|
+
HostEvidence: () => HostEvidence,
|
|
20
|
+
Policy: () => Policy,
|
|
21
|
+
ProviderEvidence: () => ProviderEvidence,
|
|
22
|
+
PublicDnsEvidence: () => PublicDnsEvidence,
|
|
23
|
+
Service: () => Service,
|
|
24
|
+
attachEvidence: () => attachEvidence,
|
|
25
|
+
defaults: () => defaults,
|
|
26
|
+
latest: () => latest,
|
|
27
|
+
layer: () => layer,
|
|
28
|
+
make: () => make,
|
|
29
|
+
observe: () => observe,
|
|
30
|
+
statusAgainst: () => statusAgainst
|
|
31
|
+
});
|
|
32
|
+
/**
|
|
33
|
+
* Every piece of evidence carries `values`, what the observer returned for the requirement's name
|
|
34
|
+
* and type (empty when nothing was found, the lookup timed out, or the resolver failed), and
|
|
35
|
+
* `detail`, `null` when the requirement is satisfied and otherwise the mismatch summary or the
|
|
36
|
+
* resolver's error text, so a host can render "found X, expected Y".
|
|
37
|
+
*/
|
|
38
|
+
const Values = Schema.Array(Schema.String).pipe(Schema.withDecodingDefaultKey(Effect.succeed([])));
|
|
39
|
+
const Detail = Schema.NullOr(Schema.String).pipe(Schema.withDecodingDefaultKey(Effect.succeed(null)));
|
|
40
|
+
var ProviderEvidence = class extends Schema.TaggedClass("@domainkit/Evidence/Provider")("Provider", {
|
|
41
|
+
provider: Schema.String,
|
|
42
|
+
status: RequirementStatus,
|
|
43
|
+
values: Values,
|
|
44
|
+
detail: Detail,
|
|
45
|
+
observedAt: Schema.DateTimeUtcFromString
|
|
46
|
+
}) {};
|
|
47
|
+
var PublicDnsEvidence = class extends Schema.TaggedClass("@domainkit/Evidence/PublicDns")("PublicDns", {
|
|
48
|
+
resolver: Schema.String,
|
|
49
|
+
status: RequirementStatus,
|
|
50
|
+
values: Values,
|
|
51
|
+
detail: Detail,
|
|
52
|
+
observedAt: Schema.DateTimeUtcFromString
|
|
53
|
+
}) {};
|
|
54
|
+
/** Anything the host knows that DomainKit cannot observe: SES identity status, a CDN cert, ... */
|
|
55
|
+
var HostEvidence = class extends Schema.TaggedClass("@domainkit/Evidence/Host")("Host", {
|
|
56
|
+
source: Schema.String,
|
|
57
|
+
status: Schema.Literals([
|
|
58
|
+
"ok",
|
|
59
|
+
"pending",
|
|
60
|
+
"failed"
|
|
61
|
+
]),
|
|
62
|
+
label: Schema.String,
|
|
63
|
+
detail: Detail,
|
|
64
|
+
observedAt: Schema.DateTimeUtcFromString
|
|
65
|
+
}) {};
|
|
66
|
+
const Evidence = Schema.Union([
|
|
67
|
+
ProviderEvidence,
|
|
68
|
+
PublicDnsEvidence,
|
|
69
|
+
HostEvidence
|
|
70
|
+
]);
|
|
71
|
+
var Service = class extends Context.Service()("@domainkit/Verify") {};
|
|
72
|
+
const defaults = {
|
|
73
|
+
backoff: (pendingForMs) => pendingForMs < 6e4 ? 15e3 : pendingForMs < 6e5 ? 6e4 : pendingForMs < 36e5 ? 3e5 : 18e5,
|
|
74
|
+
quorum: "any"
|
|
75
|
+
};
|
|
76
|
+
var Policy = class extends Context.Reference("@domainkit/Verify/Policy", { defaultValue: () => defaults }) {};
|
|
77
|
+
const StoredEvidence = Schema.Array(Evidence);
|
|
78
|
+
const StoredHost = Schema.Array(HostEvidence);
|
|
79
|
+
/** A requirement is satisfied by an exact match; an exclusive one is contradicted by any same-set record. */
|
|
80
|
+
const statusAgainst = (record, observed) => {
|
|
81
|
+
if (observed.some((candidate) => equals(candidate, record))) return "satisfied";
|
|
82
|
+
if (record.policy === "exclusive" && observed.some((candidate) => sameSet(candidate, record))) return "mismatch";
|
|
83
|
+
return "missing";
|
|
84
|
+
};
|
|
85
|
+
const render = (observed) => observed._tag === "Opaque" ? JSON.stringify(observed.raw) : data(observed);
|
|
86
|
+
/** Status plus what the observer holds for the requirement's name and type. */
|
|
87
|
+
const observation = (record, observed) => {
|
|
88
|
+
const status = statusAgainst(record, observed);
|
|
89
|
+
const values = observed.filter((candidate) => sameSet(candidate, record)).map(render);
|
|
90
|
+
return {
|
|
91
|
+
status,
|
|
92
|
+
values,
|
|
93
|
+
detail: status === "satisfied" ? null : values.length === 0 ? `no ${record._tag} record at ${record.name}` : `expected ${data(record)}; found ${values.join(", ")}`
|
|
94
|
+
};
|
|
95
|
+
};
|
|
96
|
+
const combine = (statuses) => {
|
|
97
|
+
const known = statuses.filter((status) => status !== "unknown");
|
|
98
|
+
if (known.length === 0) return "unknown";
|
|
99
|
+
if (known.includes("mismatch")) return "mismatch";
|
|
100
|
+
return known.every((status) => status === "satisfied") ? "satisfied" : "missing";
|
|
101
|
+
};
|
|
102
|
+
const quorumStatus = (quorum, statuses) => {
|
|
103
|
+
const known = statuses.filter((status) => status !== "unknown");
|
|
104
|
+
const satisfied = known.filter((status) => status === "satisfied").length;
|
|
105
|
+
const needed = quorum === "any" ? 1 : quorum === "all" ? Math.max(1, known.length) : quorum.minimum;
|
|
106
|
+
if (known.includes("mismatch")) return "mismatch";
|
|
107
|
+
if (known.length > 0 && satisfied >= needed) return "satisfied";
|
|
108
|
+
return known.length === 0 ? "unknown" : "missing";
|
|
109
|
+
};
|
|
110
|
+
const overallOf = (requirements, host) => {
|
|
111
|
+
if (requirements.some(({ status }) => status === "mismatch") || host.some(({ status }) => status === "failed")) return "failed";
|
|
112
|
+
return requirements.length + host.length > 0 && requirements.every(({ status }) => status === "satisfied") && host.every(({ status }) => status === "ok") ? "ready" : "pending";
|
|
113
|
+
};
|
|
114
|
+
/** The identity of a requirement set: type, name, data, and policy, independent of labels and order. */
|
|
115
|
+
const requirementKey = (requirements) => requirements.map(({ record }) => `${record._tag} ${record.name} ${data(record)} ${record.policy}`).sort().join("\n");
|
|
116
|
+
const make = Effect.gen(function* () {
|
|
117
|
+
const storage = yield* Service$3;
|
|
118
|
+
const connect = yield* Service$4;
|
|
119
|
+
const resolver = yield* Service$2;
|
|
120
|
+
const attachmentFor = (input) => Effect.gen(function* () {
|
|
121
|
+
const domain = yield* decode(input);
|
|
122
|
+
const attachment = yield* storage.attachments.byDomain(domain);
|
|
123
|
+
return {
|
|
124
|
+
domain,
|
|
125
|
+
attachment: Option.getOrNull(attachment)
|
|
126
|
+
};
|
|
127
|
+
});
|
|
128
|
+
const decodeRow = (row) => Effect.gen(function* () {
|
|
129
|
+
const requirements = yield* Effect.forEach(row.requirements, (requirement) => decode$1(StoredEvidence, requirement.evidence, "evidence").pipe(Effect.map((evidence) => ({
|
|
130
|
+
operationId: requirement.operationId,
|
|
131
|
+
record: requirement.record,
|
|
132
|
+
status: requirement.status,
|
|
133
|
+
evidence
|
|
134
|
+
}))));
|
|
135
|
+
const host = yield* decode$1(StoredHost, row.host, "host");
|
|
136
|
+
return {
|
|
137
|
+
domain: row.domain,
|
|
138
|
+
attachmentId: row.attachmentId,
|
|
139
|
+
overall: row.overall,
|
|
140
|
+
requirements,
|
|
141
|
+
host,
|
|
142
|
+
checkedAt: row.checkedAt,
|
|
143
|
+
nextCheckAt: row.nextCheckAt
|
|
144
|
+
};
|
|
145
|
+
});
|
|
146
|
+
/** Persist readiness, carrying the pending streak forward for the backoff ladder. */
|
|
147
|
+
const store = (input) => Effect.gen(function* () {
|
|
148
|
+
const principal = yield* Service$1;
|
|
149
|
+
const policy = yield* Policy;
|
|
150
|
+
const now = yield* DateTime.now;
|
|
151
|
+
const overall = overallOf(input.requirements, input.host);
|
|
152
|
+
const sameRequirements = Option.isSome(input.previous) && requirementKey(input.previous.value.requirements) === requirementKey(input.requirements);
|
|
153
|
+
const pendingSince = overall === "ready" ? null : sameRequirements && Option.isSome(input.previous) && input.previous.value.pendingSince !== null ? input.previous.value.pendingSince : now;
|
|
154
|
+
const nextCheckAt = pendingSince === null ? null : DateTime.addDuration(now, Duration.millis(policy.backoff(DateTime.toEpochMillis(now) - DateTime.toEpochMillis(pendingSince))));
|
|
155
|
+
const row = new Readiness({
|
|
156
|
+
domain: input.domain,
|
|
157
|
+
attachmentId: input.attachment?.id ?? null,
|
|
158
|
+
ownerId: principal.ownerId,
|
|
159
|
+
overall,
|
|
160
|
+
requirements: input.requirements.map((requirement) => ({
|
|
161
|
+
operationId: requirement.operationId,
|
|
162
|
+
record: requirement.record,
|
|
163
|
+
status: requirement.status,
|
|
164
|
+
evidence: Schema.encodeSync(StoredEvidence)(requirement.evidence)
|
|
165
|
+
})),
|
|
166
|
+
host: Schema.encodeSync(StoredHost)(input.host),
|
|
167
|
+
pendingSince,
|
|
168
|
+
checkedAt: now,
|
|
169
|
+
nextCheckAt
|
|
170
|
+
});
|
|
171
|
+
yield* storage.readiness.put(row);
|
|
172
|
+
return {
|
|
173
|
+
domain: row.domain,
|
|
174
|
+
attachmentId: row.attachmentId,
|
|
175
|
+
overall,
|
|
176
|
+
requirements: input.requirements,
|
|
177
|
+
host: input.host,
|
|
178
|
+
checkedAt: now,
|
|
179
|
+
nextCheckAt
|
|
180
|
+
};
|
|
181
|
+
});
|
|
182
|
+
const defaultRequirements = (attachment) => Effect.gen(function* () {
|
|
183
|
+
const latest = yield* storage.attempts.latest(attachment.id, "provisioning");
|
|
184
|
+
if (Option.isNone(latest) || latest.value.receipt === null) return yield* fail(new InvalidInput({
|
|
185
|
+
message: `${attachment.domain} has no provisioning receipt; pass requirements to observe`,
|
|
186
|
+
field: "requirements"
|
|
187
|
+
}));
|
|
188
|
+
const receipt = latest.value.receipt;
|
|
189
|
+
const inPlace = new Set(receipt.outcomes.flatMap((outcome) => outcome._tag === "Applied" || outcome._tag === "Skipped" && outcome.reason === "noop" ? [outcome.operationId] : []));
|
|
190
|
+
return latest.value.plan.operations.filter((operation) => inPlace.has(operation.id)).map((operation) => ({
|
|
191
|
+
operationId: operation.id,
|
|
192
|
+
record: operation.record
|
|
193
|
+
}));
|
|
194
|
+
});
|
|
195
|
+
const observe = (input) => Effect.gen(function* () {
|
|
196
|
+
const policy = yield* Policy;
|
|
197
|
+
const { domain, attachment } = yield* attachmentFor(input.domain);
|
|
198
|
+
if (input.requirements === void 0 && attachment === null) return yield* fail(new InvalidInput({
|
|
199
|
+
message: `${domain} is not attached; pass requirements to observe public DNS`,
|
|
200
|
+
field: "requirements"
|
|
201
|
+
}));
|
|
202
|
+
const requirements = input.requirements === void 0 && attachment !== null ? yield* defaultRequirements(attachment) : (input.requirements ?? []).map((record) => ({
|
|
203
|
+
operationId: null,
|
|
204
|
+
record
|
|
205
|
+
}));
|
|
206
|
+
if (requirements.length === 0) return yield* fail(new InvalidInput({
|
|
207
|
+
message: "Nothing to observe: pass at least one requirement",
|
|
208
|
+
field: "requirements"
|
|
209
|
+
}));
|
|
210
|
+
const now = yield* DateTime.now;
|
|
211
|
+
const providerSide = yield* attachment === null ? Effect.succeed(Option.none()) : Effect.gen(function* () {
|
|
212
|
+
const connection = yield* storage.connections.get(attachment.connectionId);
|
|
213
|
+
const authorization = yield* storage.authorizations.get(connection.authorizationId);
|
|
214
|
+
const { session, target } = yield* connect.session(attachment.id);
|
|
215
|
+
const observed = yield* session.dns(target).list(target.zone);
|
|
216
|
+
return Option.some({
|
|
217
|
+
provider: authorization.provider,
|
|
218
|
+
records: observed.map(({ record }) => record)
|
|
219
|
+
});
|
|
220
|
+
}).pipe(Effect.catch(() => Effect.succeed(Option.none())));
|
|
221
|
+
const observed = yield* Effect.forEach(requirements, ({ operationId, record }) => Effect.gen(function* () {
|
|
222
|
+
const providerEvidence = Option.isSome(providerSide) ? [new ProviderEvidence({
|
|
223
|
+
provider: providerSide.value.provider,
|
|
224
|
+
...observation(record, providerSide.value.records),
|
|
225
|
+
observedAt: now
|
|
226
|
+
})] : [];
|
|
227
|
+
const publicEvidence = (yield* resolver.resolve(record.name, record._tag)).map((outcome) => outcome._tag === "Answered" ? new PublicDnsEvidence({
|
|
228
|
+
resolver: outcome.answer.resolver,
|
|
229
|
+
...observation(record, outcome.answer.records),
|
|
230
|
+
observedAt: now
|
|
231
|
+
}) : new PublicDnsEvidence({
|
|
232
|
+
resolver: outcome.resolver,
|
|
233
|
+
status: "unknown",
|
|
234
|
+
values: [],
|
|
235
|
+
detail: outcome._tag === "TimedOut" ? `${outcome.resolver} timed out` : outcome.message,
|
|
236
|
+
observedAt: now
|
|
237
|
+
}));
|
|
238
|
+
const publicStatus = quorumStatus(policy.quorum, publicEvidence.map(({ status }) => status));
|
|
239
|
+
return {
|
|
240
|
+
operationId,
|
|
241
|
+
record,
|
|
242
|
+
status: combine([...providerEvidence.map((evidence) => evidence.status), publicStatus]),
|
|
243
|
+
evidence: [...providerEvidence, ...publicEvidence]
|
|
244
|
+
};
|
|
245
|
+
}), { concurrency: "unbounded" });
|
|
246
|
+
const previous = yield* storage.readiness.get(domain);
|
|
247
|
+
const host = Option.isSome(previous) ? yield* decode$1(StoredHost, previous.value.host, "host") : [];
|
|
248
|
+
return yield* store({
|
|
249
|
+
domain,
|
|
250
|
+
attachment,
|
|
251
|
+
requirements: observed,
|
|
252
|
+
host,
|
|
253
|
+
previous
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
const attachEvidence = (input) => Effect.gen(function* () {
|
|
257
|
+
const { domain, attachment } = yield* attachmentFor(input.domain);
|
|
258
|
+
const previous = yield* storage.readiness.get(domain);
|
|
259
|
+
const current = Option.isSome(previous) ? yield* decodeRow(previous.value) : {
|
|
260
|
+
requirements: [],
|
|
261
|
+
host: []
|
|
262
|
+
};
|
|
263
|
+
const bySource = new Map(current.host.map((evidence) => [evidence.source, evidence]));
|
|
264
|
+
for (const evidence of input.evidence) bySource.set(evidence.source, evidence);
|
|
265
|
+
return yield* store({
|
|
266
|
+
domain,
|
|
267
|
+
attachment,
|
|
268
|
+
requirements: current.requirements,
|
|
269
|
+
host: [...bySource.values()],
|
|
270
|
+
previous
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
const latest = (domain) => Effect.gen(function* () {
|
|
274
|
+
const { domain: name } = yield* attachmentFor(domain);
|
|
275
|
+
const stored = yield* storage.readiness.get(name);
|
|
276
|
+
return Option.isSome(stored) ? yield* decodeRow(stored.value) : null;
|
|
277
|
+
});
|
|
278
|
+
return {
|
|
279
|
+
observe,
|
|
280
|
+
attachEvidence,
|
|
281
|
+
latest
|
|
282
|
+
};
|
|
283
|
+
});
|
|
284
|
+
const layer = Layer.effect(Service)(make);
|
|
285
|
+
const accessor = (pick) => (...args) => Effect.flatMap(Service, (service) => pick(service)(...args));
|
|
286
|
+
const observe = accessor((service) => service.observe);
|
|
287
|
+
const attachEvidence = accessor((service) => service.attachEvidence);
|
|
288
|
+
const latest = accessor((service) => service.latest);
|
|
289
|
+
//#endregion
|
|
290
|
+
export { Evidence, HostEvidence, Policy, ProviderEvidence, PublicDnsEvidence, Service, Verify_exports, attachEvidence, defaults, latest, layer, make, observe, statusAgainst };
|
|
291
|
+
|
|
292
|
+
//# sourceMappingURL=Verify.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Verify.mjs","names":["Storage.RequirementStatus","DnsRecord.equals","DnsRecord.sameSet","DnsRecord.data","Storage.Service","Connect.Service","Resolver.Service","DomainName.decode","Errors.decode","Principal.Service","Storage.Readiness","Errors.fail","Reason.InvalidInput"],"sources":["../src/Verify.ts"],"sourcesContent":["/**\n * Observe provider and public DNS for an attachment, persist per-requirement readiness, and say\n * when to look again. The host keeps its own state machine (and any provider-side verification\n * such as SES) and feeds that in as `HostEvidence`.\n */\nimport { Context, DateTime, Duration, Effect, Layer, Option, Schema } from \"effect\";\n\nimport * as Connect from \"./Connect.ts\";\nimport * as DnsRecord from \"./DnsRecord.ts\";\nimport * as Errors from \"./internal/error.ts\";\nimport * as Reason from \"./Reason.ts\";\nimport * as DomainName from \"./DomainName.ts\";\nimport type * as Plan from \"./Plan.ts\";\nimport * as Principal from \"./Principal.ts\";\nimport * as Resolver from \"./Resolver.ts\";\nimport * as Storage from \"./Storage.ts\";\n\n/**\n * Every piece of evidence carries `values`, what the observer returned for the requirement's name\n * and type (empty when nothing was found, the lookup timed out, or the resolver failed), and\n * `detail`, `null` when the requirement is satisfied and otherwise the mismatch summary or the\n * resolver's error text, so a host can render \"found X, expected Y\".\n */\n// Rows written before these fields existed decode with the empty values.\nconst Values = Schema.Array(Schema.String).pipe(Schema.withDecodingDefaultKey(Effect.succeed([])));\nconst Detail = Schema.NullOr(Schema.String).pipe(\n Schema.withDecodingDefaultKey(Effect.succeed(null)),\n);\n\nexport class ProviderEvidence extends Schema.TaggedClass<ProviderEvidence>(\n \"@domainkit/Evidence/Provider\",\n)(\"Provider\", {\n provider: Schema.String,\n status: Storage.RequirementStatus,\n values: Values,\n detail: Detail,\n observedAt: Schema.DateTimeUtcFromString,\n}) {}\nexport class PublicDnsEvidence extends Schema.TaggedClass<PublicDnsEvidence>(\n \"@domainkit/Evidence/PublicDns\",\n)(\"PublicDns\", {\n resolver: Schema.String,\n status: Storage.RequirementStatus,\n values: Values,\n detail: Detail,\n observedAt: Schema.DateTimeUtcFromString,\n}) {}\n/** Anything the host knows that DomainKit cannot observe: SES identity status, a CDN cert, ... */\nexport class HostEvidence extends Schema.TaggedClass<HostEvidence>(\"@domainkit/Evidence/Host\")(\n \"Host\",\n {\n source: Schema.String,\n status: Schema.Literals([\"ok\", \"pending\", \"failed\"]),\n label: Schema.String,\n detail: Detail,\n observedAt: Schema.DateTimeUtcFromString,\n },\n) {}\nexport const Evidence = Schema.Union([ProviderEvidence, PublicDnsEvidence, HostEvidence]);\nexport type Evidence = typeof Evidence.Type;\n\nexport interface Requirement {\n readonly operationId: Plan.OperationId | null;\n readonly record: DnsRecord.Model;\n readonly status: Storage.RequirementStatus;\n readonly evidence: ReadonlyArray<Evidence>;\n}\n\nexport interface Readiness {\n readonly domain: string;\n /** `null` for observe-only domains that have no attachment. */\n readonly attachmentId: string | null;\n readonly overall: Storage.Overall;\n readonly requirements: ReadonlyArray<Requirement>;\n readonly host: ReadonlyArray<HostEvidence>;\n readonly checkedAt: DateTime.Utc;\n readonly nextCheckAt: DateTime.Utc | null;\n}\n\ntype Fx<A> = Effect.Effect<A, Errors.DomainKitError, Principal.Service>;\n\nexport interface Interface {\n /**\n * What to observe, in order of precedence: `requirements` when supplied (an attached domain\n * without a provisioning receipt, or a domain with no attachment whose records the customer\n * applies by hand), else the latest provisioning receipt of the domain's attachment (records it\n * applied or found in place). Neither is `InvalidInput`. Provider evidence is added when the\n * attachment's session can be built; public DNS is always observed, and readiness is stored\n * per domain either way.\n */\n readonly observe: (input: {\n readonly domain: string;\n readonly requirements?: ReadonlyArray<DnsRecord.Model>;\n }) => Fx<Readiness>;\n /** Merge host evidence into stored readiness without re-observing DNS. */\n readonly attachEvidence: (input: {\n readonly domain: string;\n readonly evidence: ReadonlyArray<HostEvidence>;\n }) => Fx<Readiness>;\n readonly latest: (domain: string) => Fx<Readiness | null>;\n}\n\nexport class Service extends Context.Service<Service, Interface>()(\"@domainkit/Verify\") {}\n\nexport interface PolicyShape {\n /** Delay before the next check, given time since the first pending observation. Default ladder: 15s, 1m, 5m, 30m. */\n readonly backoff: (pendingForMs: number) => number;\n /** Which resolvers must agree for `satisfied`: default `any`. */\n readonly quorum: \"any\" | \"all\" | { readonly minimum: number };\n}\nexport const defaults: PolicyShape = {\n backoff: (pendingForMs) =>\n pendingForMs < 60_000\n ? 15_000\n : pendingForMs < 10 * 60_000\n ? 60_000\n : pendingForMs < 60 * 60_000\n ? 5 * 60_000\n : 30 * 60_000,\n quorum: \"any\",\n};\nexport class Policy extends Context.Reference<PolicyShape>(\"@domainkit/Verify/Policy\", {\n defaultValue: () => defaults,\n}) {}\n\n// ---------------------------------------------------------------------------------------------\n// Implementation\n// ---------------------------------------------------------------------------------------------\n\nconst StoredEvidence = Schema.Array(Evidence);\n\ninterface ProviderSide {\n readonly provider: string;\n readonly records: ReadonlyArray<DnsRecord.Observed>;\n}\nconst StoredHost = Schema.Array(HostEvidence);\n\n/** A requirement is satisfied by an exact match; an exclusive one is contradicted by any same-set record. */\nexport const statusAgainst = (\n record: DnsRecord.Model,\n observed: ReadonlyArray<DnsRecord.Observed>,\n): Storage.RequirementStatus => {\n if (observed.some((candidate) => DnsRecord.equals(candidate, record))) return \"satisfied\";\n if (\n record.policy === \"exclusive\" &&\n observed.some((candidate) => DnsRecord.sameSet(candidate, record))\n ) {\n return \"mismatch\";\n }\n return \"missing\";\n};\n\ninterface Observation {\n readonly status: Storage.RequirementStatus;\n readonly values: ReadonlyArray<string>;\n readonly detail: string | null;\n}\n\nconst render = (observed: DnsRecord.Observed): string =>\n observed._tag === \"Opaque\" ? JSON.stringify(observed.raw) : DnsRecord.data(observed);\n\n/** Status plus what the observer holds for the requirement's name and type. */\nconst observation = (\n record: DnsRecord.Model,\n observed: ReadonlyArray<DnsRecord.Observed>,\n): Observation => {\n const status = statusAgainst(record, observed);\n const values = observed.filter((candidate) => DnsRecord.sameSet(candidate, record)).map(render);\n const detail =\n status === \"satisfied\"\n ? null\n : values.length === 0\n ? `no ${record._tag} record at ${record.name}`\n : `expected ${DnsRecord.data(record)}; found ${values.join(\", \")}`;\n return { status, values, detail };\n};\n\nconst combine = (statuses: ReadonlyArray<Storage.RequirementStatus>): Storage.RequirementStatus => {\n const known = statuses.filter((status) => status !== \"unknown\");\n if (known.length === 0) return \"unknown\";\n if (known.includes(\"mismatch\")) return \"mismatch\";\n return known.every((status) => status === \"satisfied\") ? \"satisfied\" : \"missing\";\n};\n\nconst quorumStatus = (\n quorum: PolicyShape[\"quorum\"],\n statuses: ReadonlyArray<Storage.RequirementStatus>,\n): Storage.RequirementStatus => {\n const known = statuses.filter((status) => status !== \"unknown\");\n const satisfied = known.filter((status) => status === \"satisfied\").length;\n const needed =\n quorum === \"any\" ? 1 : quorum === \"all\" ? Math.max(1, known.length) : quorum.minimum;\n if (known.includes(\"mismatch\")) return \"mismatch\";\n if (known.length > 0 && satisfied >= needed) return \"satisfied\";\n return known.length === 0 ? \"unknown\" : \"missing\";\n};\n\nconst overallOf = (\n requirements: ReadonlyArray<{ readonly status: Storage.RequirementStatus }>,\n host: ReadonlyArray<HostEvidence>,\n): Storage.Overall => {\n if (\n requirements.some(({ status }) => status === \"mismatch\") ||\n host.some(({ status }) => status === \"failed\")\n ) {\n return \"failed\";\n }\n const ready =\n requirements.length + host.length > 0 &&\n requirements.every(({ status }) => status === \"satisfied\") &&\n host.every(({ status }) => status === \"ok\");\n return ready ? \"ready\" : \"pending\";\n};\n\n/** The identity of a requirement set: type, name, data, and policy, independent of labels and order. */\nconst requirementKey = (requirements: ReadonlyArray<{ readonly record: DnsRecord.Model }>) =>\n requirements\n .map(({ record }) => `${record._tag} ${record.name} ${DnsRecord.data(record)} ${record.policy}`)\n .sort()\n .join(\"\\n\");\n\nexport const make: Effect.Effect<\n Interface,\n never,\n Storage.Service | Connect.Service | Resolver.Service\n> = Effect.gen(function* () {\n const storage = yield* Storage.Service;\n const connect = yield* Connect.Service;\n const resolver = yield* Resolver.Service;\n\n const attachmentFor = (\n input: string,\n ): Fx<{\n readonly domain: DomainName.Model;\n readonly attachment: Storage.Attachment | null;\n }> =>\n Effect.gen(function* () {\n const domain = yield* DomainName.decode(input);\n const attachment = yield* storage.attachments.byDomain(domain);\n return { domain, attachment: Option.getOrNull(attachment) };\n });\n\n const decodeRow = (row: Storage.Readiness): Effect.Effect<Readiness, Errors.DomainKitError> =>\n Effect.gen(function* () {\n const requirements = yield* Effect.forEach(row.requirements, (requirement) =>\n Errors.decode(StoredEvidence, requirement.evidence, \"evidence\").pipe(\n Effect.map((evidence): Requirement => ({\n operationId: requirement.operationId,\n record: requirement.record,\n status: requirement.status,\n evidence,\n })),\n ),\n );\n const host = yield* Errors.decode(StoredHost, row.host, \"host\");\n return {\n domain: row.domain,\n attachmentId: row.attachmentId,\n overall: row.overall,\n requirements,\n host,\n checkedAt: row.checkedAt,\n nextCheckAt: row.nextCheckAt,\n };\n });\n\n /** Persist readiness, carrying the pending streak forward for the backoff ladder. */\n const store = (input: {\n readonly domain: string;\n readonly attachment: Storage.Attachment | null;\n readonly requirements: ReadonlyArray<Requirement>;\n readonly host: ReadonlyArray<HostEvidence>;\n readonly previous: Option.Option<Storage.Readiness>;\n }): Fx<Readiness> =>\n Effect.gen(function* () {\n const principal = yield* Principal.Service;\n const policy = yield* Policy;\n const now = yield* DateTime.now;\n const overall = overallOf(input.requirements, input.host);\n const sameRequirements =\n Option.isSome(input.previous) &&\n requirementKey(input.previous.value.requirements) === requirementKey(input.requirements);\n const pendingSince =\n overall === \"ready\"\n ? null\n : sameRequirements &&\n Option.isSome(input.previous) &&\n input.previous.value.pendingSince !== null\n ? input.previous.value.pendingSince\n : now;\n const nextCheckAt =\n pendingSince === null\n ? null\n : DateTime.addDuration(\n now,\n Duration.millis(\n policy.backoff(DateTime.toEpochMillis(now) - DateTime.toEpochMillis(pendingSince)),\n ),\n );\n const row = new Storage.Readiness({\n domain: input.domain,\n attachmentId: input.attachment?.id ?? null,\n ownerId: principal.ownerId,\n overall,\n requirements: input.requirements.map((requirement) => ({\n operationId: requirement.operationId,\n record: requirement.record,\n status: requirement.status,\n evidence: Schema.encodeSync(StoredEvidence)(requirement.evidence),\n })),\n host: Schema.encodeSync(StoredHost)(input.host),\n pendingSince,\n checkedAt: now,\n nextCheckAt,\n });\n yield* storage.readiness.put(row);\n return {\n domain: row.domain,\n attachmentId: row.attachmentId,\n overall,\n requirements: input.requirements,\n host: input.host,\n checkedAt: now,\n nextCheckAt,\n };\n });\n\n const defaultRequirements = (\n attachment: Storage.Attachment,\n ): Fx<\n ReadonlyArray<{\n readonly operationId: Plan.OperationId | null;\n readonly record: DnsRecord.Model;\n }>\n > =>\n Effect.gen(function* () {\n const latest = yield* storage.attempts.latest(attachment.id, \"provisioning\");\n if (Option.isNone(latest) || latest.value.receipt === null) {\n return yield* Errors.fail(\n new Reason.InvalidInput({\n message: `${attachment.domain} has no provisioning receipt; pass requirements to observe`,\n field: \"requirements\",\n }),\n );\n }\n const receipt = latest.value.receipt;\n const inPlace = new Set(\n receipt.outcomes.flatMap((outcome) =>\n outcome._tag === \"Applied\" || (outcome._tag === \"Skipped\" && outcome.reason === \"noop\")\n ? [outcome.operationId]\n : [],\n ),\n );\n return latest.value.plan.operations\n .filter((operation) => inPlace.has(operation.id))\n .map((operation) => ({ operationId: operation.id, record: operation.record }));\n });\n\n const observe: Interface[\"observe\"] = (input) =>\n Effect.gen(function* () {\n const policy = yield* Policy;\n const { domain, attachment } = yield* attachmentFor(input.domain);\n if (input.requirements === undefined && attachment === null) {\n return yield* Errors.fail(\n new Reason.InvalidInput({\n message: `${domain} is not attached; pass requirements to observe public DNS`,\n field: \"requirements\",\n }),\n );\n }\n const requirements =\n input.requirements === undefined && attachment !== null\n ? yield* defaultRequirements(attachment)\n : (input.requirements ?? []).map((record) => ({ operationId: null, record }));\n if (requirements.length === 0) {\n return yield* Errors.fail(\n new Reason.InvalidInput({\n message: \"Nothing to observe: pass at least one requirement\",\n field: \"requirements\",\n }),\n );\n }\n const now = yield* DateTime.now;\n // Provider readback is evidence when the attachment's session can be built; when it\n // cannot (no attachment, revoked credential, provider outage) public DNS stands alone.\n const providerSide = yield* attachment === null\n ? Effect.succeed(Option.none<ProviderSide>())\n : Effect.gen(function* () {\n const connection = yield* storage.connections.get(attachment.connectionId);\n const authorization = yield* storage.authorizations.get(connection.authorizationId);\n const { session, target } = yield* connect.session(attachment.id);\n const observed = yield* session.dns(target).list(target.zone);\n return Option.some<ProviderSide>({\n provider: authorization.provider,\n records: observed.map(({ record }) => record),\n });\n }).pipe(Effect.catch(() => Effect.succeed(Option.none<ProviderSide>())));\n const observed = yield* Effect.forEach(\n requirements,\n ({ operationId, record }) =>\n Effect.gen(function* () {\n const providerEvidence = Option.isSome(providerSide)\n ? [\n new ProviderEvidence({\n provider: providerSide.value.provider,\n ...observation(record, providerSide.value.records),\n observedAt: now,\n }),\n ]\n : [];\n const outcomes = yield* resolver.resolve(record.name, record._tag);\n const publicEvidence = outcomes.map((outcome) =>\n outcome._tag === \"Answered\"\n ? new PublicDnsEvidence({\n resolver: outcome.answer.resolver,\n ...observation(record, outcome.answer.records),\n observedAt: now,\n })\n : new PublicDnsEvidence({\n resolver: outcome.resolver,\n status: \"unknown\",\n values: [],\n detail:\n outcome._tag === \"TimedOut\"\n ? `${outcome.resolver} timed out`\n : outcome.message,\n observedAt: now,\n }),\n );\n const publicStatus = quorumStatus(\n policy.quorum,\n publicEvidence.map(({ status }) => status),\n );\n const status = combine([\n ...providerEvidence.map((evidence) => evidence.status),\n publicStatus,\n ]);\n return {\n operationId,\n record,\n status,\n evidence: [...providerEvidence, ...publicEvidence],\n } satisfies Requirement;\n }),\n { concurrency: \"unbounded\" },\n );\n const previous = yield* storage.readiness.get(domain);\n const host = Option.isSome(previous)\n ? yield* Errors.decode(StoredHost, previous.value.host, \"host\")\n : [];\n return yield* store({ domain, attachment, requirements: observed, host, previous });\n });\n\n const attachEvidence: Interface[\"attachEvidence\"] = (input) =>\n Effect.gen(function* () {\n const { domain, attachment } = yield* attachmentFor(input.domain);\n const previous = yield* storage.readiness.get(domain);\n const current = Option.isSome(previous)\n ? yield* decodeRow(previous.value)\n : {\n requirements: [] as ReadonlyArray<Requirement>,\n host: [] as ReadonlyArray<HostEvidence>,\n };\n const bySource = new Map(current.host.map((evidence) => [evidence.source, evidence]));\n for (const evidence of input.evidence) bySource.set(evidence.source, evidence);\n return yield* store({\n domain,\n attachment,\n requirements: current.requirements,\n host: [...bySource.values()],\n previous,\n });\n });\n\n const latest: Interface[\"latest\"] = (domain) =>\n Effect.gen(function* () {\n const { domain: name } = yield* attachmentFor(domain);\n const stored = yield* storage.readiness.get(name);\n return Option.isSome(stored) ? yield* decodeRow(stored.value) : null;\n });\n\n return { observe, attachEvidence, latest };\n});\n\nexport const layer: Layer.Layer<\n Service,\n never,\n Storage.Service | Connect.Service | Resolver.Service\n> = Layer.effect(Service)(make);\n\nconst accessor =\n <Args extends ReadonlyArray<unknown>, A>(\n pick: (service: Interface) => (...args: Args) => Fx<A>,\n ): ((...args: Args) => Effect.Effect<A, Errors.DomainKitError, Principal.Service | Service>) =>\n (...args) =>\n Effect.flatMap(Service, (service) => pick(service)(...args));\n\nexport const observe = accessor((service) => service.observe);\nexport const attachEvidence = accessor((service) => service.attachEvidence);\nexport const latest = accessor((service) => service.latest);\n"],"mappings":"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"}
|