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.
Files changed (132) hide show
  1. package/README.md +161 -2
  2. package/dist/src/cli.d.ts +2 -0
  3. package/dist/src/cli.js +398 -0
  4. package/dist/src/cli.js.map +1 -0
  5. package/dist/src/dns-host.d.ts +10 -0
  6. package/dist/src/dns-host.js +31 -0
  7. package/dist/src/dns-host.js.map +1 -0
  8. package/dist/src/errors.d.ts +17 -0
  9. package/dist/src/errors.js +51 -0
  10. package/dist/src/errors.js.map +1 -0
  11. package/dist/src/hosted/api.d.ts +107 -0
  12. package/dist/src/hosted/api.js +919 -0
  13. package/dist/src/hosted/api.js.map +1 -0
  14. package/dist/src/hosted/auth.d.ts +80 -0
  15. package/dist/src/hosted/auth.js +147 -0
  16. package/dist/src/hosted/auth.js.map +1 -0
  17. package/dist/src/hosted/billing-dodo.d.ts +58 -0
  18. package/dist/src/hosted/billing-dodo.js +139 -0
  19. package/dist/src/hosted/billing-dodo.js.map +1 -0
  20. package/dist/src/hosted/billing-stripe.d.ts +82 -0
  21. package/dist/src/hosted/billing-stripe.js +205 -0
  22. package/dist/src/hosted/billing-stripe.js.map +1 -0
  23. package/dist/src/hosted/billing.d.ts +114 -0
  24. package/dist/src/hosted/billing.js +173 -0
  25. package/dist/src/hosted/billing.js.map +1 -0
  26. package/dist/src/hosted/bulk.d.ts +47 -0
  27. package/dist/src/hosted/bulk.js +66 -0
  28. package/dist/src/hosted/bulk.js.map +1 -0
  29. package/dist/src/hosted/cli.d.ts +2 -0
  30. package/dist/src/hosted/cli.js +318 -0
  31. package/dist/src/hosted/cli.js.map +1 -0
  32. package/dist/src/hosted/crypto.d.ts +22 -0
  33. package/dist/src/hosted/crypto.js +55 -0
  34. package/dist/src/hosted/crypto.js.map +1 -0
  35. package/dist/src/hosted/index.d.ts +7 -0
  36. package/dist/src/hosted/index.js +11 -0
  37. package/dist/src/hosted/index.js.map +1 -0
  38. package/dist/src/hosted/markdown.d.ts +16 -0
  39. package/dist/src/hosted/markdown.js +168 -0
  40. package/dist/src/hosted/markdown.js.map +1 -0
  41. package/dist/src/hosted/net.d.ts +9 -0
  42. package/dist/src/hosted/net.js +60 -0
  43. package/dist/src/hosted/net.js.map +1 -0
  44. package/dist/src/hosted/postgres-store.d.ts +62 -0
  45. package/dist/src/hosted/postgres-store.js +387 -0
  46. package/dist/src/hosted/postgres-store.js.map +1 -0
  47. package/dist/src/hosted/serialize.d.ts +144 -0
  48. package/dist/src/hosted/serialize.js +126 -0
  49. package/dist/src/hosted/serialize.js.map +1 -0
  50. package/dist/src/hosted/service.d.ts +170 -0
  51. package/dist/src/hosted/service.js +603 -0
  52. package/dist/src/hosted/service.js.map +1 -0
  53. package/dist/src/hosted/site.d.ts +84 -0
  54. package/dist/src/hosted/site.js +653 -0
  55. package/dist/src/hosted/site.js.map +1 -0
  56. package/dist/src/hosted/sqlite-store.d.ts +45 -0
  57. package/dist/src/hosted/sqlite-store.js +351 -0
  58. package/dist/src/hosted/sqlite-store.js.map +1 -0
  59. package/dist/src/hosted/store.d.ts +257 -0
  60. package/dist/src/hosted/store.js +181 -0
  61. package/dist/src/hosted/store.js.map +1 -0
  62. package/dist/src/hosted/widget.d.ts +46 -0
  63. package/dist/src/hosted/widget.js +130 -0
  64. package/dist/src/hosted/widget.js.map +1 -0
  65. package/dist/src/hosted/worker.d.ts +45 -0
  66. package/dist/src/hosted/worker.js +142 -0
  67. package/dist/src/hosted/worker.js.map +1 -0
  68. package/dist/src/http.d.ts +14 -0
  69. package/dist/src/http.js +54 -0
  70. package/dist/src/http.js.map +1 -0
  71. package/dist/src/index.d.ts +19 -0
  72. package/dist/src/index.js +19 -0
  73. package/dist/src/index.js.map +1 -0
  74. package/dist/src/orchestrator.d.ts +70 -0
  75. package/dist/src/orchestrator.js +69 -0
  76. package/dist/src/orchestrator.js.map +1 -0
  77. package/dist/src/propagation.d.ts +30 -0
  78. package/dist/src/propagation.js +76 -0
  79. package/dist/src/propagation.js.map +1 -0
  80. package/dist/src/providers/dns/aws.d.ts +28 -0
  81. package/dist/src/providers/dns/aws.js +103 -0
  82. package/dist/src/providers/dns/aws.js.map +1 -0
  83. package/dist/src/providers/dns/cloudflare.d.ts +26 -0
  84. package/dist/src/providers/dns/cloudflare.js +97 -0
  85. package/dist/src/providers/dns/cloudflare.js.map +1 -0
  86. package/dist/src/providers/dns/manual.d.ts +12 -0
  87. package/dist/src/providers/dns/manual.js +18 -0
  88. package/dist/src/providers/dns/manual.js.map +1 -0
  89. package/dist/src/providers/dns/route53.d.ts +34 -0
  90. package/dist/src/providers/dns/route53.js +176 -0
  91. package/dist/src/providers/dns/route53.js.map +1 -0
  92. package/dist/src/providers/email/factory.d.ts +29 -0
  93. package/dist/src/providers/email/factory.js +67 -0
  94. package/dist/src/providers/email/factory.js.map +1 -0
  95. package/dist/src/providers/email/mailgun.d.ts +36 -0
  96. package/dist/src/providers/email/mailgun.js +141 -0
  97. package/dist/src/providers/email/mailgun.js.map +1 -0
  98. package/dist/src/providers/email/postmark.d.ts +37 -0
  99. package/dist/src/providers/email/postmark.js +121 -0
  100. package/dist/src/providers/email/postmark.js.map +1 -0
  101. package/dist/src/providers/email/sendgrid.d.ts +31 -0
  102. package/dist/src/providers/email/sendgrid.js +109 -0
  103. package/dist/src/providers/email/sendgrid.js.map +1 -0
  104. package/dist/src/providers/email/ses.d.ts +39 -0
  105. package/dist/src/providers/email/ses.js +123 -0
  106. package/dist/src/providers/email/ses.js.map +1 -0
  107. package/dist/src/providers/factory.d.ts +14 -0
  108. package/dist/src/providers/factory.js +32 -0
  109. package/dist/src/providers/factory.js.map +1 -0
  110. package/dist/src/records.d.ts +35 -0
  111. package/dist/src/records.js +109 -0
  112. package/dist/src/records.js.map +1 -0
  113. package/dist/src/server.d.ts +67 -0
  114. package/dist/src/server.js +301 -0
  115. package/dist/src/server.js.map +1 -0
  116. package/dist/src/types.d.ts +75 -0
  117. package/dist/src/types.js +2 -0
  118. package/dist/src/types.js.map +1 -0
  119. package/dist/src/xml.d.ts +6 -0
  120. package/dist/src/xml.js +23 -0
  121. package/dist/src/xml.js.map +1 -0
  122. package/docs/billing.md +43 -0
  123. package/docs/getting-started.md +66 -0
  124. package/docs/hosted-api.md +192 -0
  125. package/docs/library.md +253 -0
  126. package/docs/self-hosting.md +153 -0
  127. package/docs/widget.md +121 -0
  128. package/package.json +63 -4
  129. package/web/dashboard.html +669 -0
  130. package/web/index.html +697 -0
  131. package/web/widget-frame.html +480 -0
  132. package/web/widget.js +91 -0
@@ -0,0 +1,103 @@
1
+ import { createHash, createHmac } from 'node:crypto';
2
+ import { readFile } from 'node:fs/promises';
3
+ import { homedir } from 'node:os';
4
+ import { join } from 'node:path';
5
+ const sha256Hex = (data) => createHash('sha256').update(data, 'utf8').digest('hex');
6
+ const hmac = (key, data) => createHmac('sha256', key).update(data, 'utf8').digest();
7
+ /** encodeURIComponent plus the reserved characters SigV4 requires escaped. */
8
+ function uriEncode(s) {
9
+ return encodeURIComponent(s).replace(/[!'()*]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`);
10
+ }
11
+ /**
12
+ * AWS Signature Version 4. Returns the headers to send (everything except
13
+ * `host`, which fetch sets itself to the same value that was signed).
14
+ */
15
+ export function signRequest(req, credentials, region, service, now = new Date()) {
16
+ const url = new URL(req.url);
17
+ const amzDate = now.toISOString().replace(/[:-]|\.\d{3}/g, '');
18
+ const date = amzDate.slice(0, 8);
19
+ const headers = { ...req.headers, 'x-amz-date': amzDate };
20
+ if (credentials.sessionToken)
21
+ headers['x-amz-security-token'] = credentials.sessionToken;
22
+ const canonical = { host: url.host };
23
+ for (const [k, v] of Object.entries(headers))
24
+ canonical[k.toLowerCase()] = v.trim().replace(/\s+/g, ' ');
25
+ const names = Object.keys(canonical).sort();
26
+ const signedHeaders = names.join(';');
27
+ const query = [...url.searchParams]
28
+ .map(([k, v]) => [uriEncode(k), uriEncode(v)])
29
+ .sort(([ak, av], [bk, bv]) => (ak === bk ? (av < bv ? -1 : av > bv ? 1 : 0) : ak < bk ? -1 : 1))
30
+ .map(([k, v]) => `${k}=${v}`)
31
+ .join('&');
32
+ // url.pathname is already encoded once; non-S3 services expect it encoded again.
33
+ const path = url.pathname.split('/').map(uriEncode).join('/') || '/';
34
+ const canonicalRequest = [
35
+ req.method.toUpperCase(),
36
+ path,
37
+ query,
38
+ names.map((n) => `${n}:${canonical[n]}\n`).join(''),
39
+ signedHeaders,
40
+ sha256Hex(req.body ?? ''),
41
+ ].join('\n');
42
+ const scope = `${date}/${region}/${service}/aws4_request`;
43
+ const stringToSign = ['AWS4-HMAC-SHA256', amzDate, scope, sha256Hex(canonicalRequest)].join('\n');
44
+ const key = hmac(hmac(hmac(hmac(`AWS4${credentials.secretAccessKey}`, date), region), service), 'aws4_request');
45
+ const signature = createHmac('sha256', key).update(stringToSign, 'utf8').digest('hex');
46
+ return {
47
+ ...headers,
48
+ Authorization: `AWS4-HMAC-SHA256 Credential=${credentials.accessKeyId}/${scope}, SignedHeaders=${signedHeaders}, Signature=${signature}`,
49
+ };
50
+ }
51
+ /**
52
+ * Static credentials from AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY, or a profile
53
+ * in ~/.aws/credentials (AWS_PROFILE, AWS_SHARED_CREDENTIALS_FILE honored).
54
+ * SSO and instance roles are not supported; export keys for those
55
+ * (e.g. `aws configure export-credentials --format env`).
56
+ */
57
+ export async function loadAwsCredentials(opts = {}) {
58
+ const env = opts.env ?? process.env;
59
+ if (!opts.profile && env.AWS_ACCESS_KEY_ID && env.AWS_SECRET_ACCESS_KEY) {
60
+ return {
61
+ accessKeyId: env.AWS_ACCESS_KEY_ID,
62
+ secretAccessKey: env.AWS_SECRET_ACCESS_KEY,
63
+ ...(env.AWS_SESSION_TOKEN ? { sessionToken: env.AWS_SESSION_TOKEN } : {}),
64
+ };
65
+ }
66
+ const profile = opts.profile ?? env.AWS_PROFILE ?? 'default';
67
+ const file = env.AWS_SHARED_CREDENTIALS_FILE ?? join(homedir(), '.aws', 'credentials');
68
+ let text;
69
+ try {
70
+ text = await readFile(file, 'utf8');
71
+ }
72
+ catch {
73
+ throw new Error(`No AWS credentials: set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY, or create ${file}.`);
74
+ }
75
+ const section = parseIni(text)[profile];
76
+ if (!section?.aws_access_key_id || !section.aws_secret_access_key) {
77
+ throw new Error(`AWS profile "${profile}" in ${file} has no aws_access_key_id/aws_secret_access_key.`);
78
+ }
79
+ return {
80
+ accessKeyId: section.aws_access_key_id,
81
+ secretAccessKey: section.aws_secret_access_key,
82
+ ...(section.aws_session_token ? { sessionToken: section.aws_session_token } : {}),
83
+ };
84
+ }
85
+ function parseIni(text) {
86
+ const sections = {};
87
+ let current;
88
+ for (const raw of text.split(/\r?\n/)) {
89
+ const line = raw.trim();
90
+ if (!line || line.startsWith('#') || line.startsWith(';'))
91
+ continue;
92
+ const header = /^\[\s*(?:profile\s+)?([^\]]+?)\s*\]$/.exec(line);
93
+ if (header) {
94
+ current = sections[header[1]] ??= {};
95
+ continue;
96
+ }
97
+ const eq = line.indexOf('=');
98
+ if (current && eq > 0)
99
+ current[line.slice(0, eq).trim().toLowerCase()] = line.slice(eq + 1).trim();
100
+ }
101
+ return sections;
102
+ }
103
+ //# sourceMappingURL=aws.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aws.js","sourceRoot":"","sources":["../../../../src/providers/dns/aws.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import { type FetchLike } from '../../http.js';
2
+ import type { DnsProvider, DnsRecord, PlannedChange } from '../../types.js';
3
+ export interface CloudflareOptions {
4
+ /** Needs Zone:Read and DNS:Edit on the target zone. */
5
+ apiToken: string;
6
+ baseUrl?: string;
7
+ fetch?: FetchLike;
8
+ }
9
+ export declare class CloudflareDns implements DnsProvider {
10
+ private readonly opts;
11
+ readonly name = "cloudflare";
12
+ private readonly baseUrl;
13
+ private readonly fetchImpl;
14
+ private readonly zoneIds;
15
+ /** Zones confirmed to exist, by name. */
16
+ private readonly knownZones;
17
+ constructor(opts: CloudflareOptions);
18
+ plan(records: DnsRecord[], opts?: {
19
+ overwrite?: boolean;
20
+ }): Promise<PlannedChange[]>;
21
+ apply(changes: PlannedChange[]): Promise<void>;
22
+ /** Finds the zone holding `name` by trying it and each parent domain. */
23
+ zoneFor(name: string): Promise<string>;
24
+ private lookupZone;
25
+ private request;
26
+ }
@@ -0,0 +1,97 @@
1
+ import { ConfigError, DnsConflictError } from '../../errors.js';
2
+ import { requestJson } from '../../http.js';
3
+ import { decideChange, normalizeName } from '../../records.js';
4
+ export class CloudflareDns {
5
+ opts;
6
+ name = 'cloudflare';
7
+ baseUrl;
8
+ fetchImpl;
9
+ zoneIds = new Map();
10
+ /** Zones confirmed to exist, by name. */
11
+ knownZones = new Map();
12
+ constructor(opts) {
13
+ this.opts = opts;
14
+ this.baseUrl = opts.baseUrl ?? 'https://api.cloudflare.com/client/v4';
15
+ this.fetchImpl = opts.fetch ?? fetch;
16
+ }
17
+ async plan(records, opts = {}) {
18
+ const changes = [];
19
+ for (const record of records) {
20
+ const zoneId = await this.zoneFor(record.name);
21
+ const existing = await this.request(`/zones/${zoneId}/dns_records?name=${encodeURIComponent(record.name)}&per_page=100`);
22
+ const neutral = existing.map((e) => ({
23
+ id: e.id,
24
+ type: e.type,
25
+ value: e.content,
26
+ priority: e.priority,
27
+ proxied: e.proxied,
28
+ }));
29
+ changes.push(decideChange(record, neutral, opts.overwrite, records));
30
+ }
31
+ return changes;
32
+ }
33
+ async apply(changes) {
34
+ const conflicts = changes.filter((c) => c.action === 'conflict');
35
+ if (conflicts.length > 0)
36
+ throw new DnsConflictError(conflicts);
37
+ for (const change of changes) {
38
+ if (change.action === 'noop')
39
+ continue;
40
+ const zoneId = await this.zoneFor(change.record.name);
41
+ const body = toCloudflareBody(change.record);
42
+ if (change.action === 'update') {
43
+ await this.request(`/zones/${zoneId}/dns_records/${change.existingId}`, { method: 'PUT', body });
44
+ }
45
+ else {
46
+ await this.request(`/zones/${zoneId}/dns_records`, { method: 'POST', body });
47
+ }
48
+ }
49
+ }
50
+ /** Finds the zone holding `name` by trying it and each parent domain. */
51
+ async zoneFor(name) {
52
+ const labels = normalizeName(name).split('.');
53
+ const candidates = labels.slice(0, -1).map((_, i) => labels.slice(i).join('.'));
54
+ // Records usually share a zone; reuse one already found before calling the API.
55
+ const known = candidates.find((c) => this.knownZones.has(c));
56
+ if (known)
57
+ return this.knownZones.get(known);
58
+ for (const candidate of candidates) {
59
+ const id = await this.lookupZone(candidate);
60
+ if (id) {
61
+ this.knownZones.set(candidate, id);
62
+ return id;
63
+ }
64
+ }
65
+ throw new ConfigError(`No Cloudflare zone found for ${name}. Check the domain is on this Cloudflare account and the token has Zone:Read access.`);
66
+ }
67
+ lookupZone(zoneName) {
68
+ let id = this.zoneIds.get(zoneName);
69
+ if (!id) {
70
+ id = this.request(`/zones?name=${encodeURIComponent(zoneName)}`).then((z) => z[0]?.id ?? null);
71
+ this.zoneIds.set(zoneName, id);
72
+ }
73
+ return id;
74
+ }
75
+ async request(path, opts = {}) {
76
+ const envelope = await requestJson(this.fetchImpl, 'Cloudflare', this.baseUrl + path, { ...opts, headers: { Authorization: `Bearer ${this.opts.apiToken}` } }, describeCloudflareError);
77
+ return envelope.result;
78
+ }
79
+ }
80
+ function toCloudflareBody(record) {
81
+ return {
82
+ type: record.type,
83
+ name: record.name,
84
+ content: record.value,
85
+ ttl: 1, // automatic
86
+ // Proxied CNAMEs resolve to Cloudflare IPs, which fails provider verification.
87
+ ...(record.type === 'CNAME' ? { proxied: false } : {}),
88
+ ...(record.type === 'MX' ? { priority: record.priority ?? 10 } : {}),
89
+ };
90
+ }
91
+ function describeCloudflareError(body) {
92
+ const errors = body?.errors;
93
+ if (!Array.isArray(errors) || errors.length === 0)
94
+ return undefined;
95
+ return errors.map((e) => `${e.message} (code ${e.code})`).join('; ');
96
+ }
97
+ //# sourceMappingURL=cloudflare.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudflare.js","sourceRoot":"","sources":["../../../../src/providers/dns/cloudflare.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { DnsProvider, DnsRecord, PlannedChange } from '../../types.js';
2
+ /**
3
+ * For DNS hosts without an API integration: hands the records to a callback
4
+ * (e.g. print them and wait for the user), then relies on propagation polling.
5
+ */
6
+ export declare class ManualDns implements DnsProvider {
7
+ private readonly onRecords;
8
+ readonly name = "manual";
9
+ constructor(onRecords: (records: DnsRecord[]) => Promise<void>);
10
+ plan(records: DnsRecord[]): Promise<PlannedChange[]>;
11
+ apply(changes: PlannedChange[]): Promise<void>;
12
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * For DNS hosts without an API integration: hands the records to a callback
3
+ * (e.g. print them and wait for the user), then relies on propagation polling.
4
+ */
5
+ export class ManualDns {
6
+ onRecords;
7
+ name = 'manual';
8
+ constructor(onRecords) {
9
+ this.onRecords = onRecords;
10
+ }
11
+ async plan(records) {
12
+ return records.map((record) => ({ record, action: 'create' }));
13
+ }
14
+ async apply(changes) {
15
+ await this.onRecords(changes.filter((c) => c.action !== 'noop').map((c) => c.record));
16
+ }
17
+ }
18
+ //# sourceMappingURL=manual.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manual.js","sourceRoot":"","sources":["../../../../src/providers/dns/manual.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,OAAO,SAAS;IAGS;IAFpB,IAAI,GAAG,QAAQ,CAAC;IAEzB,YAA6B,SAAkD;QAAlD,cAAS,GAAT,SAAS,CAAyC;IAAG,CAAC;IAEnF,KAAK,CAAC,IAAI,CAAC,OAAoB;QAC7B,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;IACjE,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,OAAwB;QAClC,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;IACxF,CAAC;CACF"}
@@ -0,0 +1,34 @@
1
+ import { type FetchLike } from '../../http.js';
2
+ import type { DnsProvider, DnsRecord, PlannedChange } from '../../types.js';
3
+ import { type AwsCredentials } from './aws.js';
4
+ export interface Route53Options {
5
+ /** Static credentials, or a loader called once on first use (e.g. `() => loadAwsCredentials()`). */
6
+ credentials: AwsCredentials | (() => Promise<AwsCredentials>);
7
+ /** Use this hosted zone instead of looking one up by name. */
8
+ hostedZoneId?: string;
9
+ baseUrl?: string;
10
+ fetch?: FetchLike;
11
+ }
12
+ /**
13
+ * Route53 stores one record set per (name, type) holding every value, so
14
+ * writes rebuild the whole set (keeping values we didn't create) and UPSERT it.
15
+ */
16
+ export declare class Route53Dns implements DnsProvider {
17
+ private readonly opts;
18
+ readonly name = "route53";
19
+ private readonly baseUrl;
20
+ private readonly fetchImpl;
21
+ private credentials?;
22
+ private readonly zoneIds;
23
+ private readonly knownZones;
24
+ constructor(opts: Route53Options);
25
+ plan(records: DnsRecord[], opts?: {
26
+ overwrite?: boolean;
27
+ }): Promise<PlannedChange[]>;
28
+ apply(changes: PlannedChange[]): Promise<void>;
29
+ /** Finds the public hosted zone holding `name` by trying it and each parent domain. */
30
+ zoneFor(name: string): Promise<string>;
31
+ private lookupZone;
32
+ private listSets;
33
+ private call;
34
+ }
@@ -0,0 +1,176 @@
1
+ import { ConfigError, DnsConflictError } from '../../errors.js';
2
+ import { requestText } from '../../http.js';
3
+ import { decideChange, normalizeName } from '../../records.js';
4
+ import { decodeXml, encodeXml, xmlTags, xmlText } from '../../xml.js';
5
+ import { signRequest } from './aws.js';
6
+ const API_VERSION = '2013-04-01';
7
+ const DEFAULT_TTL = 300;
8
+ /**
9
+ * Route53 stores one record set per (name, type) holding every value, so
10
+ * writes rebuild the whole set (keeping values we didn't create) and UPSERT it.
11
+ */
12
+ export class Route53Dns {
13
+ opts;
14
+ name = 'route53';
15
+ baseUrl;
16
+ fetchImpl;
17
+ credentials;
18
+ zoneIds = new Map();
19
+ knownZones = new Map();
20
+ constructor(opts) {
21
+ this.opts = opts;
22
+ this.baseUrl = opts.baseUrl ?? 'https://route53.amazonaws.com';
23
+ this.fetchImpl = opts.fetch ?? fetch;
24
+ }
25
+ async plan(records, opts = {}) {
26
+ const changes = [];
27
+ for (const record of records) {
28
+ const zoneId = await this.zoneFor(record.name);
29
+ const existing = (await this.listSets(zoneId, record.name)).flatMap(toExisting);
30
+ changes.push(decideChange(record, existing, opts.overwrite, records));
31
+ }
32
+ return changes;
33
+ }
34
+ async apply(changes) {
35
+ const conflicts = changes.filter((c) => c.action === 'conflict');
36
+ if (conflicts.length > 0)
37
+ throw new DnsConflictError(conflicts);
38
+ // zone → (name|type → changes)
39
+ const byZone = new Map();
40
+ for (const change of changes) {
41
+ if (change.action === 'noop')
42
+ continue;
43
+ const zoneId = await this.zoneFor(change.record.name);
44
+ const sets = byZone.get(zoneId) ?? new Map();
45
+ byZone.set(zoneId, sets);
46
+ const key = `${change.record.name}|${change.record.type}`;
47
+ sets.set(key, [...(sets.get(key) ?? []), change]);
48
+ }
49
+ for (const [zoneId, sets] of byZone) {
50
+ const upserts = [];
51
+ for (const group of sets.values()) {
52
+ const { name, type } = group[0].record;
53
+ // Re-read so values added since planning aren't dropped.
54
+ const current = (await this.listSets(zoneId, name)).find((s) => s.type === type);
55
+ let values = type === 'CNAME' ? [] : [...(current?.values ?? [])];
56
+ for (const change of group) {
57
+ if (change.action === 'update' && change.existingId)
58
+ values = values.filter((v) => v !== change.existingId);
59
+ values.push(formatValue(change.record));
60
+ }
61
+ upserts.push({ name, type, ttl: current?.ttl ?? DEFAULT_TTL, values: [...new Set(values)] });
62
+ }
63
+ await this.call('POST', `/hostedzone/${zoneId}/rrset`, changeBatchXml(upserts));
64
+ }
65
+ }
66
+ /** Finds the public hosted zone holding `name` by trying it and each parent domain. */
67
+ async zoneFor(name) {
68
+ if (this.opts.hostedZoneId)
69
+ return this.opts.hostedZoneId.replace(/^\/hostedzone\//, '');
70
+ const labels = normalizeName(name).split('.');
71
+ const candidates = labels.slice(0, -1).map((_, i) => labels.slice(i).join('.'));
72
+ const known = candidates.find((c) => this.knownZones.has(c));
73
+ if (known)
74
+ return this.knownZones.get(known);
75
+ for (const candidate of candidates) {
76
+ const id = await this.lookupZone(candidate);
77
+ if (id) {
78
+ this.knownZones.set(candidate, id);
79
+ return id;
80
+ }
81
+ }
82
+ throw new ConfigError(`No public Route53 hosted zone found for ${name}. Check the AWS account, or pass a hosted zone id.`);
83
+ }
84
+ lookupZone(zoneName) {
85
+ let id = this.zoneIds.get(zoneName);
86
+ if (!id) {
87
+ id = this.call('GET', `/hostedzonesbyname?dnsname=${encodeURIComponent(zoneName)}&maxitems=10`).then((xml) => {
88
+ // Results start at dnsname and continue alphabetically, so match exactly.
89
+ const zone = xmlTags(xml, 'HostedZone').find((z) => decodeName(xmlText(z, 'Name') ?? '') === zoneName && xmlText(z, 'PrivateZone') !== 'true');
90
+ return zone ? xmlText(zone, 'Id').replace(/^\/hostedzone\//, '') : null;
91
+ });
92
+ this.zoneIds.set(zoneName, id);
93
+ }
94
+ return id;
95
+ }
96
+ async listSets(zoneId, name) {
97
+ // Listing starts at `name`; all of a name's sets are adjacent.
98
+ const xml = await this.call('GET', `/hostedzone/${zoneId}/rrset?name=${encodeURIComponent(name)}&maxitems=20`);
99
+ return xmlTags(xml, 'ResourceRecordSet')
100
+ .map((s) => {
101
+ const ttl = xmlText(s, 'TTL');
102
+ const alias = xmlTags(s, 'AliasTarget')[0];
103
+ return {
104
+ name: decodeName(xmlText(s, 'Name') ?? ''),
105
+ type: xmlText(s, 'Type') ?? '',
106
+ ...(ttl ? { ttl: Number(ttl) } : {}),
107
+ values: xmlTags(s, 'Value').map((v) => decodeXml(v.trim())),
108
+ ...(alias ? { alias: normalizeName(xmlText(alias, 'DNSName') ?? '') } : {}),
109
+ };
110
+ })
111
+ .filter((s) => s.name === name);
112
+ }
113
+ async call(method, path, body) {
114
+ this.credentials ??= Promise.resolve(typeof this.opts.credentials === 'function' ? this.opts.credentials() : this.opts.credentials);
115
+ const credentials = await this.credentials;
116
+ const url = `${this.baseUrl}/${API_VERSION}${path}`;
117
+ return requestText(this.fetchImpl, 'Route53', url, () => ({
118
+ method,
119
+ body,
120
+ headers: signRequest({ method, url, body, headers: body ? { 'content-type': 'application/xml' } : {} }, credentials, 'us-east-1', 'route53'),
121
+ }), describeRoute53Error);
122
+ }
123
+ }
124
+ function toExisting(set) {
125
+ if (set.alias)
126
+ return [{ id: `alias:${set.alias}`, type: set.type, value: set.alias }];
127
+ return set.values.map((raw) => {
128
+ if (set.type === 'MX') {
129
+ const [priority, host] = raw.split(/\s+/);
130
+ return { id: raw, type: 'MX', value: host ?? '', priority: Number(priority) };
131
+ }
132
+ return { id: raw, type: set.type, value: set.type === 'TXT' ? unquoteTxt(raw) : raw };
133
+ });
134
+ }
135
+ function formatValue(record) {
136
+ switch (record.type) {
137
+ case 'MX':
138
+ return `${record.priority ?? 10} ${record.value}`;
139
+ case 'TXT': {
140
+ // Route53 wants quoted strings, each at most 255 characters.
141
+ const escaped = record.value.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
142
+ return (escaped.match(/[\s\S]{1,255}/g) ?? ['']).map((chunk) => `"${chunk}"`).join(' ');
143
+ }
144
+ default:
145
+ return record.value;
146
+ }
147
+ }
148
+ function unquoteTxt(raw) {
149
+ const chunks = [...raw.matchAll(/"((?:[^"\\]|\\.)*)"/g)].map((m) => m[1].replace(/\\(.)/g, '$1'));
150
+ return chunks.length > 0 ? chunks.join('') : raw;
151
+ }
152
+ /** Route53 returns names with a trailing dot and octal escapes (e.g. \052 for *). */
153
+ function decodeName(name) {
154
+ return normalizeName(name.replace(/\\(\d{3})/g, (_, oct) => String.fromCharCode(parseInt(oct, 8))));
155
+ }
156
+ function changeBatchXml(sets) {
157
+ const changes = sets
158
+ .map((s) => `<Change><Action>UPSERT</Action><ResourceRecordSet><Name>${encodeXml(s.name)}</Name><Type>${s.type}</Type>` +
159
+ `<TTL>${s.ttl ?? DEFAULT_TTL}</TTL><ResourceRecords>` +
160
+ s.values.map((v) => `<ResourceRecord><Value>${encodeXml(v)}</Value></ResourceRecord>`).join('') +
161
+ `</ResourceRecords></ResourceRecordSet></Change>`)
162
+ .join('');
163
+ return (`<?xml version="1.0" encoding="UTF-8"?>` +
164
+ `<ChangeResourceRecordSetsRequest xmlns="https://route53.amazonaws.com/doc/${API_VERSION}/">` +
165
+ `<ChangeBatch><Comment>dkimkit</Comment><Changes>${changes}</Changes></ChangeBatch>` +
166
+ `</ChangeResourceRecordSetsRequest>`);
167
+ }
168
+ function describeRoute53Error(text) {
169
+ // InvalidChangeBatch nests per-change <Message>s; other errors have one.
170
+ const messages = xmlTags(text, 'Message').map((m) => decodeXml(m.trim()));
171
+ const code = xmlText(text, 'Code');
172
+ if (messages.length === 0)
173
+ return code;
174
+ return code ? `${code}: ${messages.join('; ')}` : messages.join('; ');
175
+ }
176
+ //# sourceMappingURL=route53.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route53.js","sourceRoot":"","sources":["../../../../src/providers/dns/route53.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import type { FetchLike } from '../../http.js';
2
+ import type { EmailProvider } from '../../types.js';
3
+ export declare const EMAIL_PROVIDERS: readonly ["sendgrid", "postmark", "mailgun", "ses"];
4
+ export type EmailProviderName = (typeof EMAIL_PROVIDERS)[number];
5
+ export declare const EMAIL_PROVIDER_LABELS: Record<EmailProviderName, string>;
6
+ /** Credentials for any supported email provider; each uses its own fields. */
7
+ export interface EmailCredentials {
8
+ /** SendGrid, Mailgun */
9
+ apiKey?: string;
10
+ /** Postmark account token */
11
+ accountToken?: string;
12
+ /** Postmark server that receives inbound mail */
13
+ inboundServerId?: string;
14
+ /** Mailgun: us | eu. SES: AWS region. */
15
+ region?: string;
16
+ /** SES */
17
+ accessKeyId?: string;
18
+ secretAccessKey?: string;
19
+ sessionToken?: string;
20
+ }
21
+ export declare function isEmailProvider(name: string): name is EmailProviderName;
22
+ /** Throws a ConfigError naming what's missing for the provider. */
23
+ export declare function assertEmailCredentials(provider: string, c: EmailCredentials): void;
24
+ /** Keeps only the fields the provider uses, so nothing extra is stored. */
25
+ export declare function pickEmailCredentials(provider: string, c: EmailCredentials): EmailCredentials;
26
+ export declare function createEmailProvider(provider: string, credentials: EmailCredentials, opts?: {
27
+ subuser?: string | null;
28
+ fetch?: FetchLike;
29
+ }): EmailProvider;
@@ -0,0 +1,67 @@
1
+ import { ConfigError } from '../../errors.js';
2
+ import { MailgunProvider } from './mailgun.js';
3
+ import { PostmarkProvider } from './postmark.js';
4
+ import { SendGridProvider } from './sendgrid.js';
5
+ import { SesProvider } from './ses.js';
6
+ export const EMAIL_PROVIDERS = ['sendgrid', 'postmark', 'mailgun', 'ses'];
7
+ export const EMAIL_PROVIDER_LABELS = {
8
+ sendgrid: 'SendGrid',
9
+ postmark: 'Postmark',
10
+ mailgun: 'Mailgun',
11
+ ses: 'Amazon SES',
12
+ };
13
+ export function isEmailProvider(name) {
14
+ return EMAIL_PROVIDERS.includes(name);
15
+ }
16
+ /** Throws a ConfigError naming what's missing for the provider. */
17
+ export function assertEmailCredentials(provider, c) {
18
+ const need = (ok, message) => {
19
+ if (!ok)
20
+ throw new ConfigError(message);
21
+ };
22
+ switch (provider) {
23
+ case 'sendgrid':
24
+ return need(c.apiKey, 'SendGrid needs an API key.');
25
+ case 'postmark':
26
+ return need(c.accountToken, 'Postmark needs an account API token.');
27
+ case 'mailgun':
28
+ need(c.apiKey, 'Mailgun needs an API key.');
29
+ return need(!c.region || c.region === 'us' || c.region === 'eu', 'Mailgun region must be us or eu.');
30
+ case 'ses':
31
+ need(c.accessKeyId && c.secretAccessKey, 'Amazon SES needs an AWS access key id and secret access key.');
32
+ return need(c.region, 'Amazon SES needs an AWS region, e.g. us-east-1.');
33
+ default:
34
+ throw new ConfigError(`Email provider must be one of: ${EMAIL_PROVIDERS.join(', ')}.`);
35
+ }
36
+ }
37
+ /** Keeps only the fields the provider uses, so nothing extra is stored. */
38
+ export function pickEmailCredentials(provider, c) {
39
+ const keys = {
40
+ sendgrid: ['apiKey'],
41
+ postmark: ['accountToken', 'inboundServerId'],
42
+ mailgun: ['apiKey', 'region'],
43
+ ses: ['accessKeyId', 'secretAccessKey', 'sessionToken', 'region'],
44
+ };
45
+ return Object.fromEntries((keys[provider] ?? []).filter((k) => c[k]).map((k) => [k, c[k]]));
46
+ }
47
+ export function createEmailProvider(provider, credentials, opts = {}) {
48
+ assertEmailCredentials(provider, credentials);
49
+ if (opts.subuser && provider !== 'sendgrid')
50
+ throw new ConfigError('Subusers only apply to SendGrid.');
51
+ const c = credentials;
52
+ switch (provider) {
53
+ case 'sendgrid':
54
+ return new SendGridProvider({ apiKey: c.apiKey, onBehalfOf: opts.subuser ?? undefined, fetch: opts.fetch });
55
+ case 'postmark':
56
+ return new PostmarkProvider({ accountToken: c.accountToken, inboundServerId: c.inboundServerId, fetch: opts.fetch });
57
+ case 'mailgun':
58
+ return new MailgunProvider({ apiKey: c.apiKey, region: c.region ?? 'us', fetch: opts.fetch });
59
+ default:
60
+ return new SesProvider({
61
+ credentials: { accessKeyId: c.accessKeyId, secretAccessKey: c.secretAccessKey, ...(c.sessionToken ? { sessionToken: c.sessionToken } : {}) },
62
+ region: c.region,
63
+ fetch: opts.fetch,
64
+ });
65
+ }
66
+ }
67
+ //# sourceMappingURL=factory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factory.js","sourceRoot":"","sources":["../../../../src/providers/email/factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAG9C,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAEvC,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,CAAU,CAAC;AAGnF,MAAM,CAAC,MAAM,qBAAqB,GAAsC;IACtE,QAAQ,EAAE,UAAU;IACpB,QAAQ,EAAE,UAAU;IACpB,OAAO,EAAE,SAAS;IAClB,GAAG,EAAE,YAAY;CAClB,CAAC;AAkBF,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,OAAQ,eAAqC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AAC/D,CAAC;AAED,mEAAmE;AACnE,MAAM,UAAU,sBAAsB,CAAC,QAAgB,EAAE,CAAmB;IAC1E,MAAM,IAAI,GAAG,CAAC,EAAW,EAAE,OAAe,EAAE,EAAE;QAC5C,IAAI,CAAC,EAAE;YAAE,MAAM,IAAI,WAAW,CAAC,OAAO,CAAC,CAAC;IAC1C,CAAC,CAAC;IACF,QAAQ,QAAQ,EAAE,CAAC;QACjB,KAAK,UAAU;YACb,OAAO,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,4BAA4B,CAAC,CAAC;QACtD,KAAK,UAAU;YACb,OAAO,IAAI,CAAC,CAAC,CAAC,YAAY,EAAE,sCAAsC,CAAC,CAAC;QACtE,KAAK,SAAS;YACZ,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,2BAA2B,CAAC,CAAC;YAC5C,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,MAAM,KAAK,IAAI,IAAI,CAAC,CAAC,MAAM,KAAK,IAAI,EAAE,kCAAkC,CAAC,CAAC;QACvG,KAAK,KAAK;YACR,IAAI,CAAC,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,eAAe,EAAE,8DAA8D,CAAC,CAAC;YACzG,OAAO,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,iDAAiD,CAAC,CAAC;QAC3E;YACE,MAAM,IAAI,WAAW,CAAC,kCAAkC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC3F,CAAC;AACH,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,oBAAoB,CAAC,QAAgB,EAAE,CAAmB;IACxE,MAAM,IAAI,GAA+C;QACvD,QAAQ,EAAE,CAAC,QAAQ,CAAC;QACpB,QAAQ,EAAE,CAAC,cAAc,EAAE,iBAAiB,CAAC;QAC7C,OAAO,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC;QAC7B,GAAG,EAAE,CAAC,aAAa,EAAE,iBAAiB,EAAE,cAAc,EAAE,QAAQ,CAAC;KAClE,CAAC;IACF,OAAO,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9F,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,QAAgB,EAChB,WAA6B,EAC7B,OAAuD,EAAE;IAEzD,sBAAsB,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;IAC9C,IAAI,IAAI,CAAC,OAAO,IAAI,QAAQ,KAAK,UAAU;QAAE,MAAM,IAAI,WAAW,CAAC,kCAAkC,CAAC,CAAC;IACvG,MAAM,CAAC,GAAG,WAAW,CAAC;IACtB,QAAQ,QAAQ,EAAE,CAAC;QACjB,KAAK,UAAU;YACb,OAAO,IAAI,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,MAAO,EAAE,UAAU,EAAE,IAAI,CAAC,OAAO,IAAI,SAAS,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;QAC/G,KAAK,UAAU;YACb,OAAO,IAAI,gBAAgB,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,YAAa,EAAE,eAAe,EAAE,CAAC,CAAC,eAAe,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;QACxH,KAAK,SAAS;YACZ,OAAO,IAAI,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,MAAO,EAAE,MAAM,EAAG,CAAC,CAAC,MAAkC,IAAI,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;QAC9H;YACE,OAAO,IAAI,WAAW,CAAC;gBACrB,WAAW,EAAE,EAAE,WAAW,EAAE,CAAC,CAAC,WAAY,EAAE,eAAe,EAAE,CAAC,CAAC,eAAgB,EAAE,GAAG,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE;gBAC9I,MAAM,EAAE,CAAC,CAAC,MAAO;gBACjB,KAAK,EAAE,IAAI,CAAC,KAAK;aAClB,CAAC,CAAC;IACP,CAAC;AACH,CAAC"}