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,144 @@
1
+ import type { BillingEstimate } from './billing.js';
2
+ import type { Account, DomainEvent, DomainRow, UsageRow, UsageTotals } from './store.js';
3
+ export declare const iso: (ms: number | null) => string | null;
4
+ /** The public JSON shape of a domain. Never includes credentials. */
5
+ export declare function toPublicDomain(row: DomainRow): {
6
+ id: string;
7
+ object: string;
8
+ domain: string;
9
+ subdomain: string | null;
10
+ tenant_id: string | null;
11
+ metadata: Record<string, string>;
12
+ status: import("./store.js").DomainStatus;
13
+ provider_domain_id: string;
14
+ sendgrid_subuser: string | null;
15
+ dns: {
16
+ provider: string;
17
+ credentials_set: boolean;
18
+ };
19
+ inbound: {
20
+ url: string;
21
+ hostname: string;
22
+ spam_check: boolean;
23
+ send_raw: boolean;
24
+ } | null;
25
+ records: {
26
+ purpose: string | null;
27
+ status: string;
28
+ priority?: number | undefined;
29
+ type: import("../types.js").RecordType;
30
+ name: string;
31
+ value: string;
32
+ }[];
33
+ validation: {
34
+ valid: boolean;
35
+ results: {
36
+ record: string;
37
+ valid: boolean;
38
+ reason: string | null;
39
+ }[];
40
+ } | null;
41
+ conflicts: {
42
+ type: import("../types.js").RecordType;
43
+ name: string;
44
+ value: string;
45
+ reason: string | null;
46
+ }[] | null;
47
+ last_error: string | null;
48
+ attempts: number;
49
+ next_check_at: string | null;
50
+ verified_at: string | null;
51
+ expires_at: string | null;
52
+ created_at: string | null;
53
+ updated_at: string | null;
54
+ };
55
+ export declare function toPublicEvent(event: DomainEvent): {
56
+ id: string;
57
+ object: string;
58
+ type: string;
59
+ domain_id: string;
60
+ data: Record<string, unknown>;
61
+ created_at: string | null;
62
+ };
63
+ export declare function toPublicAccount(account: Account): {
64
+ id: string;
65
+ object: string;
66
+ name: string;
67
+ webhook_url: string | null;
68
+ webhook_secret: string;
69
+ email_provider: string;
70
+ email_credentials_set: boolean;
71
+ widget_origins: string[];
72
+ domain_limit: number | null;
73
+ email: string | null;
74
+ billing_status: import("./store.js").BillingStatus;
75
+ created_at: string | null;
76
+ };
77
+ export declare function toPublicEstimate(e: BillingEstimate): {
78
+ plan: "free" | "pay_as_you_go";
79
+ status: import("./store.js").BillingStatus;
80
+ period_start: string;
81
+ period_end: string | null;
82
+ active_domains: number;
83
+ free_domains: number;
84
+ billable_domains: number;
85
+ unit_amount: number;
86
+ amount_due: number;
87
+ currency: string;
88
+ };
89
+ /**
90
+ * What the embedded widget shows an end user. Leaves out anything that is the
91
+ * app owner's business: webhook URLs, metadata, SendGrid ids and SendGrid errors.
92
+ */
93
+ export declare function toWidgetDomain(row: DomainRow): {
94
+ domain: string;
95
+ status: import("./store.js").DomainStatus;
96
+ dns_provider: string;
97
+ inbound_hostname: string | null;
98
+ records: {
99
+ status: string;
100
+ priority?: number | undefined;
101
+ type: import("../types.js").RecordType;
102
+ name: string;
103
+ value: string;
104
+ }[];
105
+ conflicts: {
106
+ type: import("../types.js").RecordType;
107
+ name: string;
108
+ value: string;
109
+ reason: string | null;
110
+ }[] | null;
111
+ validation: {
112
+ valid: boolean;
113
+ results: {
114
+ record: string;
115
+ valid: boolean;
116
+ reason: string | null;
117
+ }[];
118
+ } | null;
119
+ error: string | null;
120
+ next_check_at: string | null;
121
+ verified_at: string | null;
122
+ };
123
+ export declare function toPublicUsage(from: string, to: string, usage: {
124
+ totals: UsageTotals;
125
+ byTenant: UsageRow[] | null;
126
+ domainCount: number;
127
+ }, account: Account): {
128
+ by_tenant?: {
129
+ domains_created: number;
130
+ verifications: number;
131
+ active_domains: number;
132
+ active_domain_days: number;
133
+ tenant_id: string | null;
134
+ }[] | undefined;
135
+ current_domains: number;
136
+ domain_limit: number | null;
137
+ domains_created: number;
138
+ verifications: number;
139
+ active_domains: number;
140
+ active_domain_days: number;
141
+ object: string;
142
+ from: string;
143
+ to: string;
144
+ };
@@ -0,0 +1,126 @@
1
+ export const iso = (ms) => (ms === null ? null : new Date(ms).toISOString());
2
+ /** The public JSON shape of a domain. Never includes credentials. */
3
+ export function toPublicDomain(row) {
4
+ const pending = new Set(row.pending);
5
+ const conflicting = new Set((row.conflicts ?? []).map((c) => `${c.record.type}|${c.record.name}`));
6
+ const recordStatus = (type, name) => {
7
+ if (conflicting.has(`${type}|${name}`))
8
+ return 'conflict';
9
+ if (row.status === 'verified')
10
+ return 'live';
11
+ return row.status === 'pending' || pending.has(name) ? 'pending' : 'live';
12
+ };
13
+ return {
14
+ id: row.id,
15
+ object: 'domain',
16
+ domain: row.domain,
17
+ subdomain: row.subdomain,
18
+ tenant_id: row.tenantId,
19
+ metadata: row.metadata,
20
+ status: row.status,
21
+ provider_domain_id: row.providerDomainId,
22
+ sendgrid_subuser: row.sendgridSubuser,
23
+ dns: { provider: row.dnsProvider, credentials_set: Boolean(row.dnsCredentialsEnc) },
24
+ inbound: row.inbound && {
25
+ url: row.inbound.url,
26
+ hostname: row.inbound.hostname,
27
+ spam_check: row.inbound.spamCheck,
28
+ send_raw: row.inbound.sendRaw,
29
+ },
30
+ records: row.records.map((r) => ({
31
+ type: r.type,
32
+ name: r.name,
33
+ value: r.value,
34
+ ...(r.priority !== undefined ? { priority: r.priority } : {}),
35
+ purpose: r.purpose ?? null,
36
+ status: recordStatus(r.type, r.name),
37
+ })),
38
+ validation: row.validation && {
39
+ valid: row.validation.valid,
40
+ results: row.validation.results.map((r) => ({ record: r.record, valid: r.valid, reason: r.reason ?? null })),
41
+ },
42
+ conflicts: row.conflicts?.map((c) => ({ type: c.record.type, name: c.record.name, value: c.record.value, reason: c.reason ?? null })) ??
43
+ null,
44
+ last_error: row.lastError,
45
+ attempts: row.attempts,
46
+ next_check_at: iso(row.nextRunAt),
47
+ verified_at: iso(row.verifiedAt),
48
+ expires_at: row.status === 'verified' ? null : iso(row.expiresAt),
49
+ created_at: iso(row.createdAt),
50
+ updated_at: iso(row.updatedAt),
51
+ };
52
+ }
53
+ export function toPublicEvent(event) {
54
+ return { id: event.id, object: 'event', type: event.type, domain_id: event.domainId, data: event.data, created_at: iso(event.createdAt) };
55
+ }
56
+ export function toPublicAccount(account) {
57
+ return {
58
+ id: account.id,
59
+ object: 'account',
60
+ name: account.name,
61
+ webhook_url: account.webhookUrl,
62
+ webhook_secret: account.webhookSecret,
63
+ email_provider: account.emailProvider,
64
+ email_credentials_set: Boolean(account.emailCredentialsEnc),
65
+ widget_origins: account.widgetOrigins,
66
+ domain_limit: account.domainLimit,
67
+ email: account.email,
68
+ billing_status: account.billingStatus,
69
+ created_at: iso(account.createdAt),
70
+ };
71
+ }
72
+ export function toPublicEstimate(e) {
73
+ return {
74
+ plan: e.plan,
75
+ status: e.status,
76
+ period_start: e.periodStart,
77
+ period_end: e.periodEnd,
78
+ active_domains: e.activeDomains,
79
+ free_domains: e.freeDomains,
80
+ billable_domains: e.billableDomains,
81
+ unit_amount: e.unitAmount,
82
+ amount_due: e.amountDue,
83
+ currency: e.currency,
84
+ };
85
+ }
86
+ /**
87
+ * What the embedded widget shows an end user. Leaves out anything that is the
88
+ * app owner's business: webhook URLs, metadata, SendGrid ids and SendGrid errors.
89
+ */
90
+ export function toWidgetDomain(row) {
91
+ const full = toPublicDomain(row);
92
+ // Allowlist: only DNS problems the end user can act on are shown to them. Anything
93
+ // else (email provider errors, configuration) is the app owner's to fix.
94
+ const endUserFixable = /^(Cloudflare API error|Route53 API error|No Cloudflare zone|No public Route53|Not verified in time|DNS records conflict|dns\.)/;
95
+ const ownerSide = row.lastError !== null && !endUserFixable.test(row.lastError);
96
+ return {
97
+ domain: row.domain,
98
+ status: row.status,
99
+ dns_provider: row.dnsProvider,
100
+ inbound_hostname: row.inbound?.hostname ?? null,
101
+ records: full.records.map(({ purpose: _purpose, ...r }) => r),
102
+ conflicts: full.conflicts,
103
+ validation: full.validation,
104
+ error: row.lastError === null ? null : ownerSide ? 'Something went wrong on our side. Please try again later.' : row.lastError,
105
+ next_check_at: full.next_check_at,
106
+ verified_at: full.verified_at,
107
+ };
108
+ }
109
+ const usageTotals = (u) => ({
110
+ domains_created: u.domainsCreated,
111
+ verifications: u.verifications,
112
+ active_domains: u.activeDomains,
113
+ active_domain_days: u.activeDomainDays,
114
+ });
115
+ export function toPublicUsage(from, to, usage, account) {
116
+ return {
117
+ object: 'usage',
118
+ from,
119
+ to,
120
+ ...usageTotals(usage.totals),
121
+ current_domains: usage.domainCount,
122
+ domain_limit: account.domainLimit,
123
+ ...(usage.byTenant ? { by_tenant: usage.byTenant.map((r) => ({ tenant_id: r.tenantId ?? null, ...usageTotals(r) })) } : {}),
124
+ };
125
+ }
126
+ //# sourceMappingURL=serialize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serialize.js","sourceRoot":"","sources":["../../../src/hosted/serialize.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,170 @@
1
+ import { type DnsLookup } from '../propagation.js';
2
+ import { type EmailCredentials } from '../providers/email/factory.js';
3
+ import type { DnsProvider, EmailProvider } from '../types.js';
4
+ import { type Vault } from './crypto.js';
5
+ import { type Account, type DomainRow, type InboundConfig, type ListDomainsQuery, type Store, type UsageRow, type UsageTotals } from './store.js';
6
+ export interface DnsCredentials {
7
+ cloudflareApiToken?: string;
8
+ awsAccessKeyId?: string;
9
+ awsSecretAccessKey?: string;
10
+ awsSessionToken?: string;
11
+ route53HostedZoneId?: string;
12
+ }
13
+ /** Inbound settings as given; the hostname defaults per email provider (e.g. parse.<domain>). */
14
+ export type InboundInput = Omit<InboundConfig, 'hostname'> & {
15
+ hostname?: string;
16
+ };
17
+ export interface DomainInput {
18
+ domain: string;
19
+ subdomain?: string | null;
20
+ tenantId?: string | null;
21
+ metadata?: Record<string, string>;
22
+ sendgridSubuser?: string | null;
23
+ inbound?: InboundInput | null;
24
+ dnsProvider: string;
25
+ dnsCredentials?: DnsCredentials;
26
+ overwrite?: boolean;
27
+ }
28
+ export interface DomainPatch {
29
+ tenantId?: string | null;
30
+ metadata?: Record<string, string>;
31
+ inbound?: InboundInput | null;
32
+ dnsProvider?: string;
33
+ dnsCredentials?: DnsCredentials;
34
+ overwrite?: boolean;
35
+ }
36
+ /** Which email provider an account uses, and its credentials. */
37
+ export interface EmailProviderSetting {
38
+ provider: string;
39
+ credentials: EmailCredentials;
40
+ }
41
+ export interface AccountPatch {
42
+ name?: string;
43
+ webhookUrl?: string | null;
44
+ /** Shorthand for { provider: 'sendgrid', credentials: { apiKey } }. */
45
+ sendgridApiKey?: string;
46
+ emailProvider?: EmailProviderSetting;
47
+ widgetOrigins?: string[];
48
+ }
49
+ export interface ProviderFactory {
50
+ email(provider: string, credentials: EmailCredentials, subuser: string | null): EmailProvider;
51
+ dns(provider: string, credentials: DnsCredentials): DnsProvider;
52
+ }
53
+ /** Tenant credentials only: never falls back to the operator's environment or ~/.aws files. */
54
+ export declare const realProviders: ProviderFactory;
55
+ export declare class NotFoundError extends Error {
56
+ }
57
+ /** The account is at its plan's domain limit. */
58
+ export declare class PlanLimitError extends Error {
59
+ readonly limit: number;
60
+ /** Where to fix it, e.g. the billing dashboard. */
61
+ readonly upgradeUrl?: string | undefined;
62
+ constructor(limit: number, message?: string,
63
+ /** Where to fix it, e.g. the billing dashboard. */
64
+ upgradeUrl?: string | undefined);
65
+ }
66
+ /** A plan-imposed cap on domains (e.g. the free tier), checked alongside the operator's domainLimit. */
67
+ export interface PlanCap {
68
+ limit: number;
69
+ message: string;
70
+ upgradeUrl?: string;
71
+ }
72
+ export declare class ConflictError extends Error {
73
+ readonly existingId: string;
74
+ constructor(message: string, existingId: string);
75
+ }
76
+ export interface ServiceOptions {
77
+ store: Store;
78
+ vault: Vault;
79
+ providers?: ProviderFactory;
80
+ lookup?: (domain: string) => Promise<DnsLookup>;
81
+ now?: () => number;
82
+ /** Give up on an unverified domain after this long. Default 72h. */
83
+ maxAgeMs?: number;
84
+ /** Re-validate verified domains this often to catch DNS drift. Default 24h. */
85
+ reverifyMs?: number;
86
+ allowPrivateWebhooks?: boolean;
87
+ /** Plan-based domain cap for an account (e.g. the free tier); null for none. */
88
+ planCap?: (account: Account) => PlanCap | null;
89
+ log?: Logger;
90
+ }
91
+ export type Logger = (level: 'info' | 'warn' | 'error', message: string, fields?: Record<string, unknown>) => void;
92
+ export declare class DomainService {
93
+ private readonly opts;
94
+ private readonly store;
95
+ private readonly vault;
96
+ private readonly providers;
97
+ private readonly lookup;
98
+ private readonly now;
99
+ private readonly maxAgeMs;
100
+ private readonly reverifyMs;
101
+ private readonly log;
102
+ constructor(opts: ServiceOptions);
103
+ /** `provider` is the email provider and credentials, or a SendGrid API key as shorthand. */
104
+ createAccount(name: string, provider?: string | EmailProviderSetting, opts?: {
105
+ email?: string;
106
+ }): Promise<{
107
+ account: Account;
108
+ apiKey: string;
109
+ }>;
110
+ authenticate(apiKey: string): Promise<Account | undefined>;
111
+ updateAccount(account: Account, patch: AccountPatch): Promise<Account>;
112
+ rotateApiKey(account: Account): Promise<string>;
113
+ rotateWebhookSecret(account: Account): Promise<Account>;
114
+ getDomain(account: Account, id: string): Promise<DomainRow>;
115
+ listDomains(account: Account, query: ListDomainsQuery): Promise<{
116
+ domains: DomainRow[];
117
+ next: string | null;
118
+ }>;
119
+ listEvents(domainId: string, limit?: number): Promise<import("./store.js").DomainEvent[]>;
120
+ /** Creates the domain at the email provider right away so the response can include its DNS records. */
121
+ createDomain(account: Account, input: DomainInput): Promise<DomainRow>;
122
+ private readonly accountQueues;
123
+ /** Runs `fn` after any earlier call for the same account has settled. */
124
+ private serialized;
125
+ private insertNewDomain;
126
+ updateDomain(account: Account, id: string, patch: DomainPatch): Promise<DomainRow>;
127
+ /**
128
+ * Checks that DNS credentials work for this domain's zone by planning the
129
+ * changes, without writing anything. Throws the provider's error if not.
130
+ */
131
+ testDnsAccess(row: DomainRow, provider: string, credentials: DnsCredentials): Promise<import("../types.js").PlannedChange[]>;
132
+ /** Schedules an immediate check. Restarts the clock for failed or conflicting domains. */
133
+ verifyNow(account: Account, id: string): Promise<DomainRow>;
134
+ /** Removes the domain here; with `remote`, also deletes it (and its inbound parse) at the email provider. */
135
+ deleteDomain(account: Account, id: string, { remote }?: {
136
+ remote?: boolean | undefined;
137
+ }): Promise<void>;
138
+ /**
139
+ * One step of the lifecycle for a leased domain: write DNS if needed, check
140
+ * propagation once, validate once, then reschedule. Always releases the lease.
141
+ */
142
+ runDomain(leased: DomainRow): Promise<DomainRow>;
143
+ private reverify;
144
+ private handleError;
145
+ private fail;
146
+ private retry;
147
+ /** Records an active day for every verified domain. Idempotent; the runner calls it hourly. */
148
+ meterActiveDomains(): Promise<void>;
149
+ /** One account's usage for a period, optionally broken down by tenant. */
150
+ usage(account: Account, from: string, to: string, groupByTenant: boolean): Promise<{
151
+ totals: UsageTotals;
152
+ byTenant: UsageRow[] | null;
153
+ domainCount: number;
154
+ }>;
155
+ /** Every account's usage for a period, for invoicing. */
156
+ usageReport(from: string, to: string): Promise<(UsageRow & {
157
+ name: string;
158
+ domainLimit: number | null;
159
+ })[]>;
160
+ setDomainLimit(accountId: string, limit: number | null): Promise<Account>;
161
+ private recordUsage;
162
+ private emit;
163
+ /** Fills in the provider's default inbound hostname, and rejects inbound where the provider can't receive. */
164
+ private resolveInbound;
165
+ /** The account's provider credentials; legacy rows hold a bare (encrypted) SendGrid key. */
166
+ private credentialsOf;
167
+ private emailFor;
168
+ private dnsFor;
169
+ }
170
+ export declare function assertDnsCredentials(provider: string, c: DnsCredentials): void;