dkimkit 0.0.0-stage → 0.7.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 +161 -2
- package/dist/src/cli.d.ts +2 -0
- package/dist/src/cli.js +398 -0
- package/dist/src/cli.js.map +1 -0
- package/dist/src/dns-host.d.ts +10 -0
- package/dist/src/dns-host.js +31 -0
- package/dist/src/dns-host.js.map +1 -0
- package/dist/src/errors.d.ts +17 -0
- package/dist/src/errors.js +51 -0
- package/dist/src/errors.js.map +1 -0
- package/dist/src/hosted/api.d.ts +107 -0
- package/dist/src/hosted/api.js +919 -0
- package/dist/src/hosted/api.js.map +1 -0
- package/dist/src/hosted/auth.d.ts +80 -0
- package/dist/src/hosted/auth.js +147 -0
- package/dist/src/hosted/auth.js.map +1 -0
- package/dist/src/hosted/billing-dodo.d.ts +58 -0
- package/dist/src/hosted/billing-dodo.js +139 -0
- package/dist/src/hosted/billing-dodo.js.map +1 -0
- package/dist/src/hosted/billing-stripe.d.ts +82 -0
- package/dist/src/hosted/billing-stripe.js +205 -0
- package/dist/src/hosted/billing-stripe.js.map +1 -0
- package/dist/src/hosted/billing.d.ts +114 -0
- package/dist/src/hosted/billing.js +173 -0
- package/dist/src/hosted/billing.js.map +1 -0
- package/dist/src/hosted/bulk.d.ts +47 -0
- package/dist/src/hosted/bulk.js +66 -0
- package/dist/src/hosted/bulk.js.map +1 -0
- package/dist/src/hosted/cli.d.ts +2 -0
- package/dist/src/hosted/cli.js +318 -0
- package/dist/src/hosted/cli.js.map +1 -0
- package/dist/src/hosted/crypto.d.ts +22 -0
- package/dist/src/hosted/crypto.js +55 -0
- package/dist/src/hosted/crypto.js.map +1 -0
- package/dist/src/hosted/index.d.ts +7 -0
- package/dist/src/hosted/index.js +11 -0
- package/dist/src/hosted/index.js.map +1 -0
- package/dist/src/hosted/markdown.d.ts +16 -0
- package/dist/src/hosted/markdown.js +168 -0
- package/dist/src/hosted/markdown.js.map +1 -0
- package/dist/src/hosted/net.d.ts +9 -0
- package/dist/src/hosted/net.js +60 -0
- package/dist/src/hosted/net.js.map +1 -0
- package/dist/src/hosted/postgres-store.d.ts +62 -0
- package/dist/src/hosted/postgres-store.js +387 -0
- package/dist/src/hosted/postgres-store.js.map +1 -0
- package/dist/src/hosted/serialize.d.ts +144 -0
- package/dist/src/hosted/serialize.js +126 -0
- package/dist/src/hosted/serialize.js.map +1 -0
- package/dist/src/hosted/service.d.ts +170 -0
- package/dist/src/hosted/service.js +603 -0
- package/dist/src/hosted/service.js.map +1 -0
- package/dist/src/hosted/site.d.ts +84 -0
- package/dist/src/hosted/site.js +653 -0
- package/dist/src/hosted/site.js.map +1 -0
- package/dist/src/hosted/sqlite-store.d.ts +45 -0
- package/dist/src/hosted/sqlite-store.js +351 -0
- package/dist/src/hosted/sqlite-store.js.map +1 -0
- package/dist/src/hosted/store.d.ts +257 -0
- package/dist/src/hosted/store.js +181 -0
- package/dist/src/hosted/store.js.map +1 -0
- package/dist/src/hosted/widget.d.ts +46 -0
- package/dist/src/hosted/widget.js +130 -0
- package/dist/src/hosted/widget.js.map +1 -0
- package/dist/src/hosted/worker.d.ts +45 -0
- package/dist/src/hosted/worker.js +142 -0
- package/dist/src/hosted/worker.js.map +1 -0
- package/dist/src/http.d.ts +14 -0
- package/dist/src/http.js +54 -0
- package/dist/src/http.js.map +1 -0
- package/dist/src/index.d.ts +19 -0
- package/dist/src/index.js +19 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/orchestrator.d.ts +70 -0
- package/dist/src/orchestrator.js +69 -0
- package/dist/src/orchestrator.js.map +1 -0
- package/dist/src/propagation.d.ts +30 -0
- package/dist/src/propagation.js +76 -0
- package/dist/src/propagation.js.map +1 -0
- package/dist/src/providers/dns/aws.d.ts +28 -0
- package/dist/src/providers/dns/aws.js +103 -0
- package/dist/src/providers/dns/aws.js.map +1 -0
- package/dist/src/providers/dns/cloudflare.d.ts +26 -0
- package/dist/src/providers/dns/cloudflare.js +97 -0
- package/dist/src/providers/dns/cloudflare.js.map +1 -0
- package/dist/src/providers/dns/manual.d.ts +12 -0
- package/dist/src/providers/dns/manual.js +18 -0
- package/dist/src/providers/dns/manual.js.map +1 -0
- package/dist/src/providers/dns/route53.d.ts +34 -0
- package/dist/src/providers/dns/route53.js +176 -0
- package/dist/src/providers/dns/route53.js.map +1 -0
- package/dist/src/providers/email/factory.d.ts +29 -0
- package/dist/src/providers/email/factory.js +67 -0
- package/dist/src/providers/email/factory.js.map +1 -0
- package/dist/src/providers/email/mailgun.d.ts +36 -0
- package/dist/src/providers/email/mailgun.js +141 -0
- package/dist/src/providers/email/mailgun.js.map +1 -0
- package/dist/src/providers/email/postmark.d.ts +37 -0
- package/dist/src/providers/email/postmark.js +121 -0
- package/dist/src/providers/email/postmark.js.map +1 -0
- package/dist/src/providers/email/sendgrid.d.ts +31 -0
- package/dist/src/providers/email/sendgrid.js +109 -0
- package/dist/src/providers/email/sendgrid.js.map +1 -0
- package/dist/src/providers/email/ses.d.ts +39 -0
- package/dist/src/providers/email/ses.js +123 -0
- package/dist/src/providers/email/ses.js.map +1 -0
- package/dist/src/providers/factory.d.ts +14 -0
- package/dist/src/providers/factory.js +32 -0
- package/dist/src/providers/factory.js.map +1 -0
- package/dist/src/records.d.ts +35 -0
- package/dist/src/records.js +109 -0
- package/dist/src/records.js.map +1 -0
- package/dist/src/server.d.ts +67 -0
- package/dist/src/server.js +301 -0
- package/dist/src/server.js.map +1 -0
- package/dist/src/types.d.ts +75 -0
- package/dist/src/types.js +2 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/xml.d.ts +6 -0
- package/dist/src/xml.js +23 -0
- package/dist/src/xml.js.map +1 -0
- package/docs/billing.md +43 -0
- package/docs/getting-started.md +66 -0
- package/docs/hosted-api.md +192 -0
- package/docs/library.md +253 -0
- package/docs/self-hosting.md +153 -0
- package/docs/widget.md +121 -0
- package/package.json +63 -4
- package/web/dashboard.html +669 -0
- package/web/index.html +697 -0
- package/web/widget-frame.html +480 -0
- package/web/widget.js +91 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { FetchLike } from '../http.js';
|
|
2
|
+
import type { DomainService, Logger } from './service.js';
|
|
3
|
+
import type { Store } from './store.js';
|
|
4
|
+
export interface RunnerOptions {
|
|
5
|
+
/** Domains checked in parallel. Default 4. */
|
|
6
|
+
concurrency?: number;
|
|
7
|
+
pollMs?: number;
|
|
8
|
+
/** How long a claimed job stays locked if the process dies mid-run. */
|
|
9
|
+
leaseMs?: number;
|
|
10
|
+
now?: () => number;
|
|
11
|
+
fetch?: FetchLike;
|
|
12
|
+
allowPrivateWebhooks?: boolean;
|
|
13
|
+
/** Reports usage to the billing provider after each metering pass. */
|
|
14
|
+
billing?: {
|
|
15
|
+
reportUsage(): Promise<void>;
|
|
16
|
+
};
|
|
17
|
+
log?: Logger;
|
|
18
|
+
}
|
|
19
|
+
/** Polls the store for due domain checks and webhook deliveries. Safe to run in several processes. */
|
|
20
|
+
export declare class BackgroundRunner {
|
|
21
|
+
private readonly service;
|
|
22
|
+
private readonly store;
|
|
23
|
+
private readonly opts;
|
|
24
|
+
private readonly concurrency;
|
|
25
|
+
private readonly pollMs;
|
|
26
|
+
private readonly leaseMs;
|
|
27
|
+
private readonly now;
|
|
28
|
+
private readonly fetchImpl;
|
|
29
|
+
private readonly log;
|
|
30
|
+
private readonly inflight;
|
|
31
|
+
private domainsRunning;
|
|
32
|
+
private lastMeteredAt;
|
|
33
|
+
private timer;
|
|
34
|
+
private stopped;
|
|
35
|
+
constructor(service: DomainService, store: Store, opts?: RunnerOptions);
|
|
36
|
+
start(): void;
|
|
37
|
+
/** Stops polling and waits for in-flight work to finish. */
|
|
38
|
+
stop(): Promise<void>;
|
|
39
|
+
/** Claims and starts whatever is due. Doesn't wait for the work itself; see `drain`. */
|
|
40
|
+
tick(): Promise<void>;
|
|
41
|
+
drain(): Promise<void>;
|
|
42
|
+
private track;
|
|
43
|
+
private deliver;
|
|
44
|
+
private retryLater;
|
|
45
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { signWebhook, WEBHOOK_SIGNATURE_HEADER } from './crypto.js';
|
|
2
|
+
import { assertPublicHttpsUrl } from './net.js';
|
|
3
|
+
// After the first attempt: 10s, 1m, 5m, 30m, 2h, 6h, 12h, 24h — then give up.
|
|
4
|
+
const WEBHOOK_RETRY_MS = [10e3, 60e3, 5 * 60e3, 30 * 60e3, 2 * 3600e3, 6 * 3600e3, 12 * 3600e3, 24 * 3600e3];
|
|
5
|
+
const WEBHOOK_TIMEOUT_MS = 10_000;
|
|
6
|
+
const METER_EVERY_MS = 3600e3;
|
|
7
|
+
/** Polls the store for due domain checks and webhook deliveries. Safe to run in several processes. */
|
|
8
|
+
export class BackgroundRunner {
|
|
9
|
+
service;
|
|
10
|
+
store;
|
|
11
|
+
opts;
|
|
12
|
+
concurrency;
|
|
13
|
+
pollMs;
|
|
14
|
+
leaseMs;
|
|
15
|
+
now;
|
|
16
|
+
fetchImpl;
|
|
17
|
+
log;
|
|
18
|
+
inflight = new Set();
|
|
19
|
+
domainsRunning = 0;
|
|
20
|
+
lastMeteredAt = -Infinity;
|
|
21
|
+
timer;
|
|
22
|
+
stopped = true;
|
|
23
|
+
constructor(service, store, opts = {}) {
|
|
24
|
+
this.service = service;
|
|
25
|
+
this.store = store;
|
|
26
|
+
this.opts = opts;
|
|
27
|
+
this.concurrency = opts.concurrency ?? 4;
|
|
28
|
+
this.pollMs = opts.pollMs ?? 2000;
|
|
29
|
+
this.leaseMs = opts.leaseMs ?? 5 * 60e3;
|
|
30
|
+
this.now = opts.now ?? Date.now;
|
|
31
|
+
this.fetchImpl = opts.fetch ?? fetch;
|
|
32
|
+
this.log = opts.log ?? (() => { });
|
|
33
|
+
}
|
|
34
|
+
start() {
|
|
35
|
+
this.stopped = false;
|
|
36
|
+
const loop = async () => {
|
|
37
|
+
if (this.stopped)
|
|
38
|
+
return;
|
|
39
|
+
try {
|
|
40
|
+
await this.tick();
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
// e.g. the database is briefly unreachable; try again next poll.
|
|
44
|
+
this.log('error', 'runner tick failed', { error: String(err) });
|
|
45
|
+
}
|
|
46
|
+
if (!this.stopped)
|
|
47
|
+
this.timer = setTimeout(loop, this.pollMs);
|
|
48
|
+
};
|
|
49
|
+
void loop();
|
|
50
|
+
}
|
|
51
|
+
/** Stops polling and waits for in-flight work to finish. */
|
|
52
|
+
async stop() {
|
|
53
|
+
this.stopped = true;
|
|
54
|
+
clearTimeout(this.timer);
|
|
55
|
+
await this.drain();
|
|
56
|
+
}
|
|
57
|
+
/** Claims and starts whatever is due. Doesn't wait for the work itself; see `drain`. */
|
|
58
|
+
async tick() {
|
|
59
|
+
const now = this.now();
|
|
60
|
+
const runs = [];
|
|
61
|
+
const free = this.concurrency - this.domainsRunning;
|
|
62
|
+
if (free > 0) {
|
|
63
|
+
for (const row of await this.store.claimDueDomains(now, free, this.leaseMs)) {
|
|
64
|
+
this.domainsRunning++;
|
|
65
|
+
const run = this.service
|
|
66
|
+
.runDomain(row)
|
|
67
|
+
.catch((err) => this.log('error', 'domain run crashed', { domain_id: row.id, error: String(err) }))
|
|
68
|
+
.finally(() => this.domainsRunning--);
|
|
69
|
+
runs.push(run);
|
|
70
|
+
this.track(run);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
for (const delivery of await this.store.claimDueDeliveries(now, 10, this.leaseMs)) {
|
|
74
|
+
this.track(this.deliver(delivery));
|
|
75
|
+
}
|
|
76
|
+
// Usage metering: an active day per verified domain. Idempotent, so several
|
|
77
|
+
// runner processes doing this at once is fine.
|
|
78
|
+
if (now - this.lastMeteredAt >= METER_EVERY_MS) {
|
|
79
|
+
this.lastMeteredAt = now;
|
|
80
|
+
const meter = async () => {
|
|
81
|
+
// Count domains this pass just verified, not only those verified before it.
|
|
82
|
+
await Promise.allSettled(runs);
|
|
83
|
+
await this.service.meterActiveDomains();
|
|
84
|
+
// After metering, so the report includes today's active days.
|
|
85
|
+
await this.opts.billing?.reportUsage();
|
|
86
|
+
};
|
|
87
|
+
this.track(meter().catch((err) => this.log('error', 'usage metering failed', { error: String(err) })));
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
async drain() {
|
|
91
|
+
while (this.inflight.size > 0)
|
|
92
|
+
await Promise.allSettled([...this.inflight]);
|
|
93
|
+
}
|
|
94
|
+
track(p) {
|
|
95
|
+
this.inflight.add(p);
|
|
96
|
+
void p.finally(() => this.inflight.delete(p));
|
|
97
|
+
}
|
|
98
|
+
async deliver(d) {
|
|
99
|
+
const account = await this.store.getAccount(d.accountId);
|
|
100
|
+
if (!account)
|
|
101
|
+
return;
|
|
102
|
+
const attempts = d.attempts + 1;
|
|
103
|
+
try {
|
|
104
|
+
await assertPublicHttpsUrl(d.url, { allowPrivate: this.opts.allowPrivateWebhooks });
|
|
105
|
+
const event = JSON.parse(d.payload);
|
|
106
|
+
const res = await this.fetchImpl(d.url, {
|
|
107
|
+
method: 'POST',
|
|
108
|
+
headers: {
|
|
109
|
+
'content-type': 'application/json',
|
|
110
|
+
'user-agent': 'dkimkit-webhooks/1',
|
|
111
|
+
[WEBHOOK_SIGNATURE_HEADER]: signWebhook(account.webhookSecret, d.payload, Math.floor(this.now() / 1000)),
|
|
112
|
+
'x-dkimkit-event-id': event.id,
|
|
113
|
+
'x-dkimkit-event-type': event.type,
|
|
114
|
+
},
|
|
115
|
+
body: d.payload,
|
|
116
|
+
redirect: 'manual',
|
|
117
|
+
signal: AbortSignal.timeout(WEBHOOK_TIMEOUT_MS),
|
|
118
|
+
});
|
|
119
|
+
await res.body?.cancel();
|
|
120
|
+
if (res.ok) {
|
|
121
|
+
await this.store.updateDelivery(d.id, { status: 'delivered', attempts, responseStatus: res.status, lastError: null, lockedUntil: null, nextAttemptAt: null });
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
await this.retryLater(d, attempts, `HTTP ${res.status}`, res.status);
|
|
125
|
+
}
|
|
126
|
+
catch (err) {
|
|
127
|
+
await this.retryLater(d, attempts, err instanceof Error ? err.message : String(err), null);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
async retryLater(d, attempts, error, status) {
|
|
131
|
+
const delay = WEBHOOK_RETRY_MS[attempts - 1];
|
|
132
|
+
if (delay === undefined) {
|
|
133
|
+
await this.store.updateDelivery(d.id, { status: 'failed', attempts, lastError: error, responseStatus: status, lockedUntil: null, nextAttemptAt: null });
|
|
134
|
+
this.log('warn', 'webhook delivery abandoned', { delivery_id: d.id, error });
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
await this.store.updateDelivery(d.id, {
|
|
138
|
+
attempts, lastError: error, responseStatus: status, lockedUntil: null, nextAttemptAt: this.now() + delay,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=worker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker.js","sourceRoot":"","sources":["../../../src/hosted/worker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export type FetchLike = (url: string, init?: RequestInit) => Promise<Response>;
|
|
2
|
+
export interface RequestOptions {
|
|
3
|
+
method?: string;
|
|
4
|
+
headers?: Record<string, string>;
|
|
5
|
+
body?: unknown;
|
|
6
|
+
}
|
|
7
|
+
export declare const sleep: (ms: number, signal?: AbortSignal) => Promise<undefined>;
|
|
8
|
+
/** JSON request with retries on rate limits and transient server errors. */
|
|
9
|
+
export declare function requestJson<T>(fetchImpl: FetchLike, provider: string, url: string, opts: RequestOptions, describeError: (body: unknown) => string | undefined, retries?: number): Promise<T>;
|
|
10
|
+
/**
|
|
11
|
+
* Raw request returning the response text. `buildInit` runs per attempt so
|
|
12
|
+
* callers can re-sign requests on retry.
|
|
13
|
+
*/
|
|
14
|
+
export declare function requestText(fetchImpl: FetchLike, provider: string, url: string, buildInit: () => RequestInit, describeError: (text: string) => string | undefined, retries?: number): Promise<string>;
|
package/dist/src/http.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { setTimeout as delay } from 'node:timers/promises';
|
|
2
|
+
import { ApiError } from './errors.js';
|
|
3
|
+
const RETRYABLE = new Set([429, 500, 502, 503, 504]);
|
|
4
|
+
const MAX_RETRY_DELAY_MS = 30_000;
|
|
5
|
+
export const sleep = (ms, signal) => delay(ms, undefined, { signal });
|
|
6
|
+
/** JSON request with retries on rate limits and transient server errors. */
|
|
7
|
+
export async function requestJson(fetchImpl, provider, url, opts, describeError, retries = 2) {
|
|
8
|
+
const hasBody = opts.body !== undefined;
|
|
9
|
+
const init = {
|
|
10
|
+
method: opts.method ?? 'GET',
|
|
11
|
+
headers: {
|
|
12
|
+
Accept: 'application/json',
|
|
13
|
+
...(hasBody ? { 'Content-Type': 'application/json' } : {}),
|
|
14
|
+
...opts.headers,
|
|
15
|
+
},
|
|
16
|
+
body: hasBody ? JSON.stringify(opts.body) : undefined,
|
|
17
|
+
};
|
|
18
|
+
const text = await send(fetchImpl, provider, url, () => init, (t) => describeError(parseJson(t)), retries);
|
|
19
|
+
return (text ? parseJson(text) : undefined);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Raw request returning the response text. `buildInit` runs per attempt so
|
|
23
|
+
* callers can re-sign requests on retry.
|
|
24
|
+
*/
|
|
25
|
+
export async function requestText(fetchImpl, provider, url, buildInit, describeError, retries = 2) {
|
|
26
|
+
return send(fetchImpl, provider, url, buildInit, describeError, retries);
|
|
27
|
+
}
|
|
28
|
+
async function send(fetchImpl, provider, url, buildInit, describeError, retries) {
|
|
29
|
+
for (let attempt = 0;; attempt++) {
|
|
30
|
+
const res = await fetchImpl(url, buildInit());
|
|
31
|
+
const text = await res.text();
|
|
32
|
+
if (res.ok)
|
|
33
|
+
return text;
|
|
34
|
+
if (RETRYABLE.has(res.status) && attempt < retries) {
|
|
35
|
+
await sleep(retryDelay(res, attempt));
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
throw new ApiError(provider, res.status, describeError(text) || res.statusText || `HTTP ${res.status}`, parseJson(text));
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function parseJson(text) {
|
|
42
|
+
try {
|
|
43
|
+
return JSON.parse(text);
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return text;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function retryDelay(res, attempt) {
|
|
50
|
+
const retryAfter = Number(res.headers.get('retry-after'));
|
|
51
|
+
const ms = Number.isFinite(retryAfter) && retryAfter > 0 ? retryAfter * 1000 : 1000 * 2 ** attempt;
|
|
52
|
+
return Math.min(ms, MAX_RETRY_DELAY_MS);
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=http.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/http.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,IAAI,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAUvC,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;AACrD,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAElC,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,EAAU,EAAE,MAAoB,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;AAE5F,4EAA4E;AAC5E,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,SAAoB,EACpB,QAAgB,EAChB,GAAW,EACX,IAAoB,EACpB,aAAoD,EACpD,OAAO,GAAG,CAAC;IAEX,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC;IACxC,MAAM,IAAI,GAAgB;QACxB,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,KAAK;QAC5B,OAAO,EAAE;YACP,MAAM,EAAE,kBAAkB;YAC1B,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC1D,GAAG,IAAI,CAAC,OAAO;SAChB;QACD,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;KACtD,CAAC;IACF,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,SAAS,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IAC3G,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAM,CAAC;AACnD,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,SAAoB,EACpB,QAAgB,EAChB,GAAW,EACX,SAA4B,EAC5B,aAAmD,EACnD,OAAO,GAAG,CAAC;IAEX,OAAO,IAAI,CAAC,SAAS,EAAE,QAAQ,EAAE,GAAG,EAAE,SAAS,EAAE,aAAa,EAAE,OAAO,CAAC,CAAC;AAC3E,CAAC;AAED,KAAK,UAAU,IAAI,CACjB,SAAoB,EACpB,QAAgB,EAChB,GAAW,EACX,SAA4B,EAC5B,aAAmD,EACnD,OAAe;IAEf,KAAK,IAAI,OAAO,GAAG,CAAC,GAAI,OAAO,EAAE,EAAE,CAAC;QAClC,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE,SAAS,EAAE,CAAC,CAAC;QAC9C,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAC9B,IAAI,GAAG,CAAC,EAAE;YAAE,OAAO,IAAI,CAAC;QACxB,IAAI,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,OAAO,GAAG,OAAO,EAAE,CAAC;YACnD,MAAM,KAAK,CAAC,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC;YACtC,SAAS;QACX,CAAC;QACD,MAAM,IAAI,QAAQ,CAAC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,UAAU,IAAI,QAAQ,GAAG,CAAC,MAAM,EAAE,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;IAC3H,CAAC;AACH,CAAC;AAED,SAAS,SAAS,CAAC,IAAY;IAC7B,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,UAAU,CAAC,GAAa,EAAE,OAAe;IAChD,MAAM,UAAU,GAAG,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC;IAC1D,MAAM,EAAE,GAAG,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,IAAI,OAAO,CAAC;IACnG,OAAO,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,kBAAkB,CAAC,CAAC;AAC1C,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export * from './types.js';
|
|
2
|
+
export * from './errors.js';
|
|
3
|
+
export { decideChange, describeRecord, isValidDomain, normalizeName, normalizeValue, sameValue, type ExistingRecord } from './records.js';
|
|
4
|
+
export { authoritativeLookup, ResolverLookup, waitForPropagation, type DnsLookup, type WaitOptions } from './propagation.js';
|
|
5
|
+
export { setupDomain, checkStatus, type SetupOptions, type SetupResult, type SetupEvent, type SetupStatus, type StatusResult } from './orchestrator.js';
|
|
6
|
+
export { SendGridProvider, SENDGRID_INBOUND_MX, type SendGridOptions } from './providers/email/sendgrid.js';
|
|
7
|
+
export { CloudflareDns, type CloudflareOptions } from './providers/dns/cloudflare.js';
|
|
8
|
+
export { ManualDns } from './providers/dns/manual.js';
|
|
9
|
+
export type { FetchLike } from './http.js';
|
|
10
|
+
export { Route53Dns, type Route53Options } from './providers/dns/route53.js';
|
|
11
|
+
export { loadAwsCredentials, signRequest, type AwsCredentials } from './providers/dns/aws.js';
|
|
12
|
+
export { createDnsProvider, DNS_PROVIDERS, type DnsProviderName, type DnsProviderConfig } from './providers/factory.js';
|
|
13
|
+
export { startUiServer, parseSetupRequest, type UiServer, type UiServerOptions, type SetupRequest } from './server.js';
|
|
14
|
+
export { verifyWebhookSignature, signWebhook, WEBHOOK_SIGNATURE_HEADER } from './hosted/crypto.js';
|
|
15
|
+
export { detectDnsHost, type DnsHost } from './dns-host.js';
|
|
16
|
+
export { PostmarkProvider, type PostmarkOptions } from './providers/email/postmark.js';
|
|
17
|
+
export { MailgunProvider, type MailgunOptions } from './providers/email/mailgun.js';
|
|
18
|
+
export { SesProvider, type SesOptions } from './providers/email/ses.js';
|
|
19
|
+
export { createEmailProvider, EMAIL_PROVIDERS, type EmailCredentials, type EmailProviderName } from './providers/email/factory.js';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export * from './types.js';
|
|
2
|
+
export * from './errors.js';
|
|
3
|
+
export { decideChange, describeRecord, isValidDomain, normalizeName, normalizeValue, sameValue } from './records.js';
|
|
4
|
+
export { authoritativeLookup, ResolverLookup, waitForPropagation } from './propagation.js';
|
|
5
|
+
export { setupDomain, checkStatus } from './orchestrator.js';
|
|
6
|
+
export { SendGridProvider, SENDGRID_INBOUND_MX } from './providers/email/sendgrid.js';
|
|
7
|
+
export { CloudflareDns } from './providers/dns/cloudflare.js';
|
|
8
|
+
export { ManualDns } from './providers/dns/manual.js';
|
|
9
|
+
export { Route53Dns } from './providers/dns/route53.js';
|
|
10
|
+
export { loadAwsCredentials, signRequest } from './providers/dns/aws.js';
|
|
11
|
+
export { createDnsProvider, DNS_PROVIDERS } from './providers/factory.js';
|
|
12
|
+
export { startUiServer, parseSetupRequest } from './server.js';
|
|
13
|
+
export { verifyWebhookSignature, signWebhook, WEBHOOK_SIGNATURE_HEADER } from './hosted/crypto.js';
|
|
14
|
+
export { detectDnsHost } from './dns-host.js';
|
|
15
|
+
export { PostmarkProvider } from './providers/email/postmark.js';
|
|
16
|
+
export { MailgunProvider } from './providers/email/mailgun.js';
|
|
17
|
+
export { SesProvider } from './providers/email/ses.js';
|
|
18
|
+
export { createEmailProvider, EMAIL_PROVIDERS } from './providers/email/factory.js';
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,aAAa,EAAE,cAAc,EAAE,SAAS,EAAuB,MAAM,cAAc,CAAC;AAC1I,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,kBAAkB,EAAoC,MAAM,kBAAkB,CAAC;AAC7H,OAAO,EAAE,WAAW,EAAE,WAAW,EAA6F,MAAM,mBAAmB,CAAC;AACxJ,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAwB,MAAM,+BAA+B,CAAC;AAC5G,OAAO,EAAE,aAAa,EAA0B,MAAM,+BAA+B,CAAC;AACtF,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAEtD,OAAO,EAAE,UAAU,EAAuB,MAAM,4BAA4B,CAAC;AAC7E,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAuB,MAAM,wBAAwB,CAAC;AAC9F,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAgD,MAAM,wBAAwB,CAAC;AACxH,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAA0D,MAAM,aAAa,CAAC;AACvH,OAAO,EAAE,sBAAsB,EAAE,WAAW,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AACnG,OAAO,EAAE,aAAa,EAAgB,MAAM,eAAe,CAAC;AAC5D,OAAO,EAAE,gBAAgB,EAAwB,MAAM,+BAA+B,CAAC;AACvF,OAAO,EAAE,eAAe,EAAuB,MAAM,8BAA8B,CAAC;AACpF,OAAO,EAAE,WAAW,EAAmB,MAAM,0BAA0B,CAAC;AACxE,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAiD,MAAM,8BAA8B,CAAC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { type DnsLookup } from './propagation.js';
|
|
2
|
+
import type { DnsProvider, DnsRecord, DomainAuthentication, EmailProvider, InboundAction, InboundParseOptions, PlannedChange, ValidationResult } from './types.js';
|
|
3
|
+
export type SetupEvent = {
|
|
4
|
+
type: 'domain';
|
|
5
|
+
auth: DomainAuthentication;
|
|
6
|
+
} | {
|
|
7
|
+
type: 'plan';
|
|
8
|
+
changes: PlannedChange[];
|
|
9
|
+
} | {
|
|
10
|
+
type: 'applied';
|
|
11
|
+
changes: PlannedChange[];
|
|
12
|
+
} | {
|
|
13
|
+
type: 'propagation';
|
|
14
|
+
pending: DnsRecord[];
|
|
15
|
+
total: number;
|
|
16
|
+
elapsedMs: number;
|
|
17
|
+
} | {
|
|
18
|
+
type: 'validation';
|
|
19
|
+
attempt: number;
|
|
20
|
+
result: ValidationResult;
|
|
21
|
+
} | {
|
|
22
|
+
type: 'inbound';
|
|
23
|
+
hostname: string;
|
|
24
|
+
url: string;
|
|
25
|
+
action: InboundAction;
|
|
26
|
+
};
|
|
27
|
+
export interface SetupOptions {
|
|
28
|
+
domain: string;
|
|
29
|
+
subdomain?: string;
|
|
30
|
+
inbound?: InboundParseOptions;
|
|
31
|
+
/** Replace existing CNAME/MX records that point elsewhere. */
|
|
32
|
+
overwrite?: boolean;
|
|
33
|
+
/** Plan only: create nothing in DNS. Note the provider may still create the domain to learn its records. */
|
|
34
|
+
dryRun?: boolean;
|
|
35
|
+
/** Called before writing DNS when there are changes; return false to abort. */
|
|
36
|
+
confirm?: (changes: PlannedChange[]) => Promise<boolean>;
|
|
37
|
+
propagation?: {
|
|
38
|
+
timeoutMs?: number;
|
|
39
|
+
intervalMs?: number;
|
|
40
|
+
lookup?: DnsLookup;
|
|
41
|
+
};
|
|
42
|
+
validation?: {
|
|
43
|
+
attempts?: number;
|
|
44
|
+
intervalMs?: number;
|
|
45
|
+
};
|
|
46
|
+
onEvent?: (event: SetupEvent) => void;
|
|
47
|
+
/** Stops waiting (propagation, validation retries) and rejects with an AbortError. */
|
|
48
|
+
signal?: AbortSignal;
|
|
49
|
+
}
|
|
50
|
+
export type SetupStatus = 'complete' | 'dry-run' | 'aborted' | 'dns-pending' | 'validation-failed';
|
|
51
|
+
export interface SetupResult {
|
|
52
|
+
status: SetupStatus;
|
|
53
|
+
domain: DomainAuthentication;
|
|
54
|
+
changes: PlannedChange[];
|
|
55
|
+
pending?: DnsRecord[];
|
|
56
|
+
validation?: ValidationResult;
|
|
57
|
+
inbound?: InboundAction;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Runs the full lifecycle: provider domain → DNS plan/apply → propagation →
|
|
61
|
+
* provider validation → inbound parse. Idempotent, so it is safe to re-run
|
|
62
|
+
* after a `dns-pending` or `validation-failed` result.
|
|
63
|
+
*/
|
|
64
|
+
export declare function setupDomain(email: EmailProvider, dns: DnsProvider, opts: SetupOptions): Promise<SetupResult>;
|
|
65
|
+
export interface StatusResult {
|
|
66
|
+
domain: DomainAuthentication | null;
|
|
67
|
+
validation?: ValidationResult;
|
|
68
|
+
}
|
|
69
|
+
/** Read-only check: finds the domain and asks the provider to re-validate it. */
|
|
70
|
+
export declare function checkStatus(email: EmailProvider, domain: string, subdomain?: string): Promise<StatusResult>;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { DnsConflictError } from './errors.js';
|
|
2
|
+
import { sleep } from './http.js';
|
|
3
|
+
import { authoritativeLookup, waitForPropagation } from './propagation.js';
|
|
4
|
+
/**
|
|
5
|
+
* Runs the full lifecycle: provider domain → DNS plan/apply → propagation →
|
|
6
|
+
* provider validation → inbound parse. Idempotent, so it is safe to re-run
|
|
7
|
+
* after a `dns-pending` or `validation-failed` result.
|
|
8
|
+
*/
|
|
9
|
+
export async function setupDomain(email, dns, opts) {
|
|
10
|
+
const emit = opts.onEvent ?? (() => { });
|
|
11
|
+
const { signal } = opts;
|
|
12
|
+
const auth = await email.ensureDomain(opts.domain, { subdomain: opts.subdomain });
|
|
13
|
+
emit({ type: 'domain', auth });
|
|
14
|
+
const records = [...auth.records, ...(opts.inbound ? email.inboundRecords(opts.inbound.hostname) : [])];
|
|
15
|
+
const changes = await dns.plan(records, { overwrite: opts.overwrite });
|
|
16
|
+
emit({ type: 'plan', changes });
|
|
17
|
+
const conflicts = changes.filter((c) => c.action === 'conflict');
|
|
18
|
+
if (conflicts.length > 0)
|
|
19
|
+
throw new DnsConflictError(conflicts);
|
|
20
|
+
if (opts.dryRun)
|
|
21
|
+
return { status: 'dry-run', domain: auth, changes };
|
|
22
|
+
const writes = changes.filter((c) => c.action === 'create' || c.action === 'update');
|
|
23
|
+
if (writes.length > 0) {
|
|
24
|
+
if (opts.confirm && !(await opts.confirm(changes)))
|
|
25
|
+
return { status: 'aborted', domain: auth, changes };
|
|
26
|
+
await dns.apply(changes);
|
|
27
|
+
emit({ type: 'applied', changes: writes });
|
|
28
|
+
}
|
|
29
|
+
// Wait for the planned values, which can differ from the provider's (e.g. an SPF record merged into an existing one).
|
|
30
|
+
const planned = changes.map((c) => c.record);
|
|
31
|
+
const lookup = opts.propagation?.lookup ?? (await authoritativeLookup(opts.domain));
|
|
32
|
+
const pending = await waitForPropagation(planned, lookup, {
|
|
33
|
+
timeoutMs: opts.propagation?.timeoutMs,
|
|
34
|
+
intervalMs: opts.propagation?.intervalMs,
|
|
35
|
+
onProgress: (p, elapsedMs) => emit({ type: 'propagation', pending: p, total: planned.length, elapsedMs }),
|
|
36
|
+
signal,
|
|
37
|
+
});
|
|
38
|
+
if (pending.length > 0)
|
|
39
|
+
return { status: 'dns-pending', domain: auth, changes, pending };
|
|
40
|
+
// The provider's resolvers can lag behind the authoritative servers, so retry.
|
|
41
|
+
const { attempts = 6, intervalMs = 10_000 } = opts.validation ?? {};
|
|
42
|
+
let validation;
|
|
43
|
+
for (let attempt = 1; attempt <= attempts; attempt++) {
|
|
44
|
+
signal?.throwIfAborted();
|
|
45
|
+
validation = await email.validateDomain(auth.id);
|
|
46
|
+
emit({ type: 'validation', attempt, result: validation });
|
|
47
|
+
if (validation.valid)
|
|
48
|
+
break;
|
|
49
|
+
if (attempt < attempts)
|
|
50
|
+
await sleep(intervalMs, signal);
|
|
51
|
+
}
|
|
52
|
+
if (!validation?.valid)
|
|
53
|
+
return { status: 'validation-failed', domain: auth, changes, validation };
|
|
54
|
+
let inbound;
|
|
55
|
+
if (opts.inbound) {
|
|
56
|
+
signal?.throwIfAborted();
|
|
57
|
+
inbound = await email.ensureInboundParse(opts.inbound);
|
|
58
|
+
emit({ type: 'inbound', hostname: opts.inbound.hostname, url: opts.inbound.url, action: inbound });
|
|
59
|
+
}
|
|
60
|
+
return { status: 'complete', domain: { ...auth, valid: true }, changes, validation, inbound };
|
|
61
|
+
}
|
|
62
|
+
/** Read-only check: finds the domain and asks the provider to re-validate it. */
|
|
63
|
+
export async function checkStatus(email, domain, subdomain) {
|
|
64
|
+
const auth = await email.findDomain(domain, subdomain);
|
|
65
|
+
if (!auth)
|
|
66
|
+
return { domain: null };
|
|
67
|
+
return { domain: auth, validation: await email.validateDomain(auth.id) };
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=orchestrator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../../src/orchestrator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Resolver } from 'node:dns/promises';
|
|
2
|
+
import type { DnsRecord } from './types.js';
|
|
3
|
+
export interface DnsLookup {
|
|
4
|
+
/** True when `record` is currently visible with the expected value. */
|
|
5
|
+
check(record: DnsRecord): Promise<boolean>;
|
|
6
|
+
}
|
|
7
|
+
export declare class ResolverLookup implements DnsLookup {
|
|
8
|
+
private readonly resolver;
|
|
9
|
+
constructor(resolver: Resolver);
|
|
10
|
+
check(record: DnsRecord): Promise<boolean>;
|
|
11
|
+
}
|
|
12
|
+
/** The zone apex holding `domain` and its nameservers, found by walking up the labels. */
|
|
13
|
+
export declare function findZoneNameservers(domain: string, resolveNs?: (name: string) => Promise<string[]>): Promise<{
|
|
14
|
+
zone: string;
|
|
15
|
+
nameservers: string[];
|
|
16
|
+
} | null>;
|
|
17
|
+
/**
|
|
18
|
+
* Queries the domain's authoritative nameservers directly, so results reflect
|
|
19
|
+
* what was just written rather than a recursive resolver's cache. Falls back
|
|
20
|
+
* to public resolvers if the nameservers can't be found.
|
|
21
|
+
*/
|
|
22
|
+
export declare function authoritativeLookup(domain: string): Promise<DnsLookup>;
|
|
23
|
+
export interface WaitOptions {
|
|
24
|
+
timeoutMs?: number;
|
|
25
|
+
intervalMs?: number;
|
|
26
|
+
onProgress?: (pending: DnsRecord[], elapsedMs: number) => void;
|
|
27
|
+
signal?: AbortSignal;
|
|
28
|
+
}
|
|
29
|
+
/** Polls until every record is visible or the timeout passes. Returns the records still missing. */
|
|
30
|
+
export declare function waitForPropagation(records: DnsRecord[], lookup: DnsLookup, opts?: WaitOptions): Promise<DnsRecord[]>;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { Resolver } from 'node:dns/promises';
|
|
2
|
+
import { sleep } from './http.js';
|
|
3
|
+
import { normalizeValue, sameValue } from './records.js';
|
|
4
|
+
const PUBLIC_RESOLVERS = ['1.1.1.1', '8.8.8.8'];
|
|
5
|
+
export class ResolverLookup {
|
|
6
|
+
resolver;
|
|
7
|
+
constructor(resolver) {
|
|
8
|
+
this.resolver = resolver;
|
|
9
|
+
}
|
|
10
|
+
async check(record) {
|
|
11
|
+
try {
|
|
12
|
+
switch (record.type) {
|
|
13
|
+
case 'CNAME':
|
|
14
|
+
return (await this.resolver.resolveCname(record.name)).some((v) => sameValue('CNAME', v, record.value));
|
|
15
|
+
case 'MX':
|
|
16
|
+
return (await this.resolver.resolveMx(record.name)).some((mx) => sameValue('MX', mx.exchange, record.value));
|
|
17
|
+
case 'TXT': {
|
|
18
|
+
const wanted = normalizeValue('TXT', record.value);
|
|
19
|
+
return (await this.resolver.resolveTxt(record.name)).some((chunks) => chunks.join('') === wanted);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
catch (err) {
|
|
24
|
+
// NXDOMAIN, NODATA, SERVFAIL, timeouts: not visible yet.
|
|
25
|
+
if (typeof err.code === 'string')
|
|
26
|
+
return false;
|
|
27
|
+
throw err;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/** The zone apex holding `domain` and its nameservers, found by walking up the labels. */
|
|
32
|
+
export async function findZoneNameservers(domain, resolveNs = (name) => new Resolver().resolveNs(name)) {
|
|
33
|
+
const labels = domain.split('.');
|
|
34
|
+
for (let i = 0; i < labels.length - 1; i++) {
|
|
35
|
+
const zone = labels.slice(i).join('.');
|
|
36
|
+
try {
|
|
37
|
+
const nameservers = await resolveNs(zone);
|
|
38
|
+
if (nameservers.length > 0)
|
|
39
|
+
return { zone, nameservers: nameservers.map((n) => n.toLowerCase()) };
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
// Not a zone apex; try the parent.
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Queries the domain's authoritative nameservers directly, so results reflect
|
|
49
|
+
* what was just written rather than a recursive resolver's cache. Falls back
|
|
50
|
+
* to public resolvers if the nameservers can't be found.
|
|
51
|
+
*/
|
|
52
|
+
export async function authoritativeLookup(domain) {
|
|
53
|
+
const system = new Resolver();
|
|
54
|
+
const found = await findZoneNameservers(domain);
|
|
55
|
+
const ips = found ? (await Promise.all(found.nameservers.map((ns) => system.resolve4(ns).catch(() => [])))).flat() : [];
|
|
56
|
+
const resolver = new Resolver({ timeout: 3000, tries: 2 });
|
|
57
|
+
resolver.setServers(ips.length > 0 ? ips : PUBLIC_RESOLVERS);
|
|
58
|
+
return new ResolverLookup(resolver);
|
|
59
|
+
}
|
|
60
|
+
/** Polls until every record is visible or the timeout passes. Returns the records still missing. */
|
|
61
|
+
export async function waitForPropagation(records, lookup, opts = {}) {
|
|
62
|
+
const { timeoutMs = 300_000, intervalMs = 5_000, onProgress, signal } = opts;
|
|
63
|
+
const started = Date.now();
|
|
64
|
+
let pending = records;
|
|
65
|
+
for (;;) {
|
|
66
|
+
signal?.throwIfAborted();
|
|
67
|
+
const visible = await Promise.all(pending.map((r) => lookup.check(r)));
|
|
68
|
+
pending = pending.filter((_, i) => !visible[i]);
|
|
69
|
+
const elapsed = Date.now() - started;
|
|
70
|
+
onProgress?.(pending, elapsed);
|
|
71
|
+
if (pending.length === 0 || elapsed + intervalMs > timeoutMs)
|
|
72
|
+
return pending;
|
|
73
|
+
await sleep(intervalMs, signal);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=propagation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"propagation.js","sourceRoot":"","sources":["../../src/propagation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export interface AwsCredentials {
|
|
2
|
+
accessKeyId: string;
|
|
3
|
+
secretAccessKey: string;
|
|
4
|
+
sessionToken?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface SignableRequest {
|
|
7
|
+
method: string;
|
|
8
|
+
url: string;
|
|
9
|
+
headers?: Record<string, string>;
|
|
10
|
+
body?: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* AWS Signature Version 4. Returns the headers to send (everything except
|
|
14
|
+
* `host`, which fetch sets itself to the same value that was signed).
|
|
15
|
+
*/
|
|
16
|
+
export declare function signRequest(req: SignableRequest, credentials: AwsCredentials, region: string, service: string, now?: Date): Record<string, string>;
|
|
17
|
+
export interface LoadCredentialsOptions {
|
|
18
|
+
/** Named profile in the shared credentials file. Overrides environment keys. */
|
|
19
|
+
profile?: string;
|
|
20
|
+
env?: NodeJS.ProcessEnv;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Static credentials from AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY, or a profile
|
|
24
|
+
* in ~/.aws/credentials (AWS_PROFILE, AWS_SHARED_CREDENTIALS_FILE honored).
|
|
25
|
+
* SSO and instance roles are not supported; export keys for those
|
|
26
|
+
* (e.g. `aws configure export-credentials --format env`).
|
|
27
|
+
*/
|
|
28
|
+
export declare function loadAwsCredentials(opts?: LoadCredentialsOptions): Promise<AwsCredentials>;
|