@serve.zone/dcrouter 13.11.0 → 13.13.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/dist_serve/bundle.js +333 -305
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/classes.dcrouter.js +6 -5
- package/dist_ts/db/documents/classes.email-domain.doc.d.ts +1 -0
- package/dist_ts/db/documents/classes.email-domain.doc.js +8 -2
- package/dist_ts/dns/manager.dns.d.ts +46 -8
- package/dist_ts/dns/manager.dns.js +189 -36
- package/dist_ts/email/classes.email-domain.manager.d.ts +1 -0
- package/dist_ts/email/classes.email-domain.manager.js +6 -2
- package/dist_ts/opsserver/handlers/config.handler.js +2 -2
- package/dist_ts/opsserver/handlers/domain.handler.js +14 -1
- package/dist_ts/opsserver/handlers/email-domain.handler.js +2 -1
- package/dist_ts_interfaces/data/email-domain.d.ts +3 -1
- package/dist_ts_interfaces/requests/domains.d.ts +24 -0
- package/dist_ts_interfaces/requests/email-domains.d.ts +2 -0
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/dist_ts_web/appstate.d.ts +7 -0
- package/dist_ts_web/appstate.js +18 -1
- package/dist_ts_web/elements/domains/ops-view-domains.d.ts +1 -0
- package/dist_ts_web/elements/domains/ops-view-domains.js +97 -1
- package/dist_ts_web/elements/email/ops-view-email-domains.js +8 -1
- package/package.json +2 -2
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/classes.dcrouter.ts +5 -4
- package/ts/db/documents/classes.email-domain.doc.ts +3 -0
- package/ts/dns/manager.dns.ts +219 -35
- package/ts/email/classes.email-domain.manager.ts +6 -1
- package/ts/opsserver/handlers/config.handler.ts +1 -1
- package/ts/opsserver/handlers/domain.handler.ts +18 -0
- package/ts/opsserver/handlers/email-domain.handler.ts +1 -0
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/appstate.ts +27 -0
- package/ts_web/elements/domains/ops-view-domains.ts +99 -0
- package/ts_web/elements/email/ops-view-email-domains.ts +7 -0
- package/dist_ts_oci_container/plugins.d.ts +0 -3
- package/dist_ts_oci_container/plugins.js +0 -4
|
@@ -48,6 +48,7 @@ export class EmailDomainManager {
|
|
|
48
48
|
|
|
49
49
|
public async createEmailDomain(opts: {
|
|
50
50
|
linkedDomainId: string;
|
|
51
|
+
subdomain?: string;
|
|
51
52
|
dkimSelector?: string;
|
|
52
53
|
dkimKeySize?: number;
|
|
53
54
|
rotateKeys?: boolean;
|
|
@@ -58,7 +59,9 @@ export class EmailDomainManager {
|
|
|
58
59
|
if (!domainDoc) {
|
|
59
60
|
throw new Error(`DNS domain not found: ${opts.linkedDomainId}`);
|
|
60
61
|
}
|
|
61
|
-
const
|
|
62
|
+
const baseDomain = domainDoc.name;
|
|
63
|
+
const subdomain = opts.subdomain?.trim() || undefined;
|
|
64
|
+
const domainName = subdomain ? `${subdomain}.${baseDomain}` : baseDomain;
|
|
62
65
|
|
|
63
66
|
// Check for duplicates
|
|
64
67
|
const existing = await EmailDomainDoc.findByDomain(domainName);
|
|
@@ -90,6 +93,7 @@ export class EmailDomainManager {
|
|
|
90
93
|
doc.id = plugins.smartunique.shortId();
|
|
91
94
|
doc.domain = domainName.toLowerCase();
|
|
92
95
|
doc.linkedDomainId = opts.linkedDomainId;
|
|
96
|
+
doc.subdomain = subdomain;
|
|
93
97
|
doc.dkim = {
|
|
94
98
|
selector,
|
|
95
99
|
keySize,
|
|
@@ -306,6 +310,7 @@ export class EmailDomainManager {
|
|
|
306
310
|
id: doc.id,
|
|
307
311
|
domain: doc.domain,
|
|
308
312
|
linkedDomainId: doc.linkedDomainId,
|
|
313
|
+
subdomain: doc.subdomain,
|
|
309
314
|
dkim: doc.dkim,
|
|
310
315
|
rateLimits: doc.rateLimits,
|
|
311
316
|
dnsStatus: doc.dnsStatus,
|
|
@@ -127,7 +127,7 @@ export class ConfigHandler {
|
|
|
127
127
|
// (replaces the legacy `dnsChallenge.cloudflareApiKey` constructor field).
|
|
128
128
|
let dnsChallengeEnabled = false;
|
|
129
129
|
try {
|
|
130
|
-
dnsChallengeEnabled = (await dcRouter.dnsManager?.
|
|
130
|
+
dnsChallengeEnabled = (await dcRouter.dnsManager?.hasAnyManagedDomain()) ?? false;
|
|
131
131
|
} catch {
|
|
132
132
|
dnsChallengeEnabled = false;
|
|
133
133
|
}
|
|
@@ -157,5 +157,23 @@ export class DomainHandler {
|
|
|
157
157
|
},
|
|
158
158
|
),
|
|
159
159
|
);
|
|
160
|
+
|
|
161
|
+
// Migrate domain between dcrouter-hosted and provider-managed
|
|
162
|
+
this.typedrouter.addTypedHandler(
|
|
163
|
+
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_MigrateDomain>(
|
|
164
|
+
'migrateDomain',
|
|
165
|
+
async (dataArg) => {
|
|
166
|
+
await this.requireAuth(dataArg, 'domains:write');
|
|
167
|
+
const dnsManager = this.opsServerRef.dcRouterRef.dnsManager;
|
|
168
|
+
if (!dnsManager) return { success: false, message: 'DnsManager not initialized' };
|
|
169
|
+
return await dnsManager.migrateDomain({
|
|
170
|
+
id: dataArg.id,
|
|
171
|
+
targetSource: dataArg.targetSource,
|
|
172
|
+
targetProviderId: dataArg.targetProviderId,
|
|
173
|
+
deleteExistingProviderRecords: dataArg.deleteExistingProviderRecords,
|
|
174
|
+
});
|
|
175
|
+
},
|
|
176
|
+
),
|
|
177
|
+
);
|
|
160
178
|
}
|
|
161
179
|
}
|
|
@@ -85,6 +85,7 @@ export class EmailDomainHandler {
|
|
|
85
85
|
try {
|
|
86
86
|
const domain = await this.manager.createEmailDomain({
|
|
87
87
|
linkedDomainId: dataArg.linkedDomainId,
|
|
88
|
+
subdomain: dataArg.subdomain,
|
|
88
89
|
dkimSelector: dataArg.dkimSelector,
|
|
89
90
|
dkimKeySize: dataArg.dkimKeySize,
|
|
90
91
|
rotateKeys: dataArg.rotateKeys,
|
package/ts_web/appstate.ts
CHANGED
|
@@ -1887,6 +1887,32 @@ export const syncDomainAction = domainsStatePart.createAction<{ id: string }>(
|
|
|
1887
1887
|
},
|
|
1888
1888
|
);
|
|
1889
1889
|
|
|
1890
|
+
export const migrateDomainAction = domainsStatePart.createAction<{
|
|
1891
|
+
id: string;
|
|
1892
|
+
targetSource: interfaces.data.TDomainSource;
|
|
1893
|
+
targetProviderId?: string;
|
|
1894
|
+
deleteExistingProviderRecords?: boolean;
|
|
1895
|
+
}>(
|
|
1896
|
+
async (statePartArg, dataArg, actionContext): Promise<IDomainsState> => {
|
|
1897
|
+
const context = getActionContext();
|
|
1898
|
+
try {
|
|
1899
|
+
const request = new plugins.domtools.plugins.typedrequest.TypedRequest<
|
|
1900
|
+
interfaces.requests.IReq_MigrateDomain
|
|
1901
|
+
>('/typedrequest', 'migrateDomain');
|
|
1902
|
+
const response = await request.fire({ identity: context.identity!, ...dataArg });
|
|
1903
|
+
if (!response.success) {
|
|
1904
|
+
return { ...statePartArg.getState()!, error: response.message || 'Migration failed' };
|
|
1905
|
+
}
|
|
1906
|
+
return await actionContext!.dispatch(fetchDomainsAndProvidersAction, null);
|
|
1907
|
+
} catch (error: unknown) {
|
|
1908
|
+
return {
|
|
1909
|
+
...statePartArg.getState()!,
|
|
1910
|
+
error: error instanceof Error ? error.message : 'Migration failed',
|
|
1911
|
+
};
|
|
1912
|
+
}
|
|
1913
|
+
},
|
|
1914
|
+
);
|
|
1915
|
+
|
|
1890
1916
|
export const createDnsRecordAction = domainsStatePart.createAction<{
|
|
1891
1917
|
domainId: string;
|
|
1892
1918
|
name: string;
|
|
@@ -2422,6 +2448,7 @@ export const fetchEmailDomainsAction = emailDomainsStatePart.createAction(
|
|
|
2422
2448
|
|
|
2423
2449
|
export const createEmailDomainAction = emailDomainsStatePart.createAction<{
|
|
2424
2450
|
linkedDomainId: string;
|
|
2451
|
+
subdomain?: string;
|
|
2425
2452
|
dkimSelector?: string;
|
|
2426
2453
|
dkimKeySize?: number;
|
|
2427
2454
|
rotateKeys?: boolean;
|
|
@@ -149,6 +149,15 @@ export class OpsViewDomains extends DeesElement {
|
|
|
149
149
|
});
|
|
150
150
|
},
|
|
151
151
|
},
|
|
152
|
+
{
|
|
153
|
+
name: 'Migrate',
|
|
154
|
+
iconName: 'lucide:arrow-right-left',
|
|
155
|
+
type: ['inRow', 'contextmenu'] as any,
|
|
156
|
+
actionFunc: async (actionData: any) => {
|
|
157
|
+
const domain = actionData.item as interfaces.data.IDomain;
|
|
158
|
+
await this.showMigrateDialog(domain);
|
|
159
|
+
},
|
|
160
|
+
},
|
|
152
161
|
{
|
|
153
162
|
name: 'Delete',
|
|
154
163
|
iconName: 'lucide:trash2',
|
|
@@ -308,6 +317,96 @@ export class OpsViewDomains extends DeesElement {
|
|
|
308
317
|
});
|
|
309
318
|
}
|
|
310
319
|
|
|
320
|
+
private async showMigrateDialog(domain: interfaces.data.IDomain) {
|
|
321
|
+
const { DeesModal, DeesToast } = await import('@design.estate/dees-catalog');
|
|
322
|
+
const providers = this.domainsState.providers;
|
|
323
|
+
|
|
324
|
+
// Build target options based on current source
|
|
325
|
+
const targetOptions: { option: string; key: string }[] = [];
|
|
326
|
+
if (domain.source === 'provider') {
|
|
327
|
+
targetOptions.push({ option: 'DcRouter (authoritative)', key: 'dcrouter' });
|
|
328
|
+
}
|
|
329
|
+
// Add all providers (except the current one if already provider-managed)
|
|
330
|
+
for (const p of providers) {
|
|
331
|
+
if (domain.source === 'provider' && domain.providerId === p.id) continue;
|
|
332
|
+
targetOptions.push({ option: `${p.name} (${p.type})`, key: `provider:${p.id}` });
|
|
333
|
+
}
|
|
334
|
+
if (domain.source === 'dcrouter') {
|
|
335
|
+
targetOptions.unshift({ option: 'DcRouter (authoritative)', key: 'dcrouter' });
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
if (targetOptions.length === 0) {
|
|
339
|
+
DeesToast.show({
|
|
340
|
+
message: 'No migration targets available. Add a DNS provider first.',
|
|
341
|
+
type: 'warning',
|
|
342
|
+
duration: 3000,
|
|
343
|
+
});
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
const currentLabel = domain.source === 'dcrouter'
|
|
348
|
+
? 'DcRouter (authoritative)'
|
|
349
|
+
: providers.find((p) => p.id === domain.providerId)?.name || 'Provider';
|
|
350
|
+
|
|
351
|
+
DeesModal.createAndShow({
|
|
352
|
+
heading: `Migrate: ${domain.name}`,
|
|
353
|
+
content: html`
|
|
354
|
+
<dees-form>
|
|
355
|
+
<dees-input-text
|
|
356
|
+
.key=${'currentSource'}
|
|
357
|
+
.label=${'Current source'}
|
|
358
|
+
.value=${currentLabel}
|
|
359
|
+
.disabled=${true}
|
|
360
|
+
></dees-input-text>
|
|
361
|
+
<dees-input-dropdown
|
|
362
|
+
.key=${'target'}
|
|
363
|
+
.label=${'Migrate to'}
|
|
364
|
+
.description=${'Select the target DNS management'}
|
|
365
|
+
.options=${targetOptions}
|
|
366
|
+
.required=${true}
|
|
367
|
+
></dees-input-dropdown>
|
|
368
|
+
<dees-input-checkbox
|
|
369
|
+
.key=${'deleteExisting'}
|
|
370
|
+
.label=${'Delete existing records at provider first'}
|
|
371
|
+
.description=${'Removes all records at the provider before pushing migrated records'}
|
|
372
|
+
.value=${true}
|
|
373
|
+
></dees-input-checkbox>
|
|
374
|
+
</dees-form>
|
|
375
|
+
`,
|
|
376
|
+
menuOptions: [
|
|
377
|
+
{ name: 'Cancel', action: async (m: any) => m.destroy() },
|
|
378
|
+
{
|
|
379
|
+
name: 'Migrate',
|
|
380
|
+
action: async (m: any) => {
|
|
381
|
+
const form = m.shadowRoot?.querySelector('.content')?.querySelector('dees-form');
|
|
382
|
+
if (!form) return;
|
|
383
|
+
const data = await form.collectFormData();
|
|
384
|
+
const targetKey = typeof data.target === 'object' ? data.target.key : data.target;
|
|
385
|
+
if (!targetKey) return;
|
|
386
|
+
|
|
387
|
+
let targetSource: interfaces.data.TDomainSource;
|
|
388
|
+
let targetProviderId: string | undefined;
|
|
389
|
+
if (targetKey === 'dcrouter') {
|
|
390
|
+
targetSource = 'dcrouter';
|
|
391
|
+
} else {
|
|
392
|
+
targetSource = 'provider';
|
|
393
|
+
targetProviderId = targetKey.replace('provider:', '');
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
await appstate.domainsStatePart.dispatchAction(appstate.migrateDomainAction, {
|
|
397
|
+
id: domain.id,
|
|
398
|
+
targetSource,
|
|
399
|
+
targetProviderId,
|
|
400
|
+
deleteExistingProviderRecords: targetSource === 'provider' ? Boolean(data.deleteExisting) : false,
|
|
401
|
+
});
|
|
402
|
+
DeesToast.show({ message: `Domain ${domain.name} migrated successfully`, type: 'success', duration: 3000 });
|
|
403
|
+
m.destroy();
|
|
404
|
+
},
|
|
405
|
+
},
|
|
406
|
+
],
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
|
|
311
410
|
private async deleteDomain(domain: interfaces.data.IDomain) {
|
|
312
411
|
const { DeesModal } = await import('@design.estate/dees-catalog');
|
|
313
412
|
DeesModal.createAndShow({
|
|
@@ -276,6 +276,11 @@ export class OpsViewEmailDomains extends DeesElement {
|
|
|
276
276
|
.options=${domainOptions}
|
|
277
277
|
.required=${true}
|
|
278
278
|
></dees-input-dropdown>
|
|
279
|
+
<dees-input-text
|
|
280
|
+
.key=${'subdomain'}
|
|
281
|
+
.label=${'Subdomain'}
|
|
282
|
+
.description=${'Leave empty for bare domain, e.g. "mail" for mail.example.com'}
|
|
283
|
+
></dees-input-text>
|
|
279
284
|
<dees-input-text
|
|
280
285
|
.key=${'dkimSelector'}
|
|
281
286
|
.label=${'DKIM Selector'}
|
|
@@ -316,10 +321,12 @@ export class OpsViewEmailDomains extends DeesElement {
|
|
|
316
321
|
? parseInt(data.dkimKeySize.key, 10)
|
|
317
322
|
: parseInt(data.dkimKeySize || '2048', 10);
|
|
318
323
|
|
|
324
|
+
const subdomain = data.subdomain?.trim() || undefined;
|
|
319
325
|
await appstate.emailDomainsStatePart.dispatchAction(
|
|
320
326
|
appstate.createEmailDomainAction,
|
|
321
327
|
{
|
|
322
328
|
linkedDomainId,
|
|
329
|
+
subdomain,
|
|
323
330
|
dkimSelector: data.dkimSelector || 'default',
|
|
324
331
|
dkimKeySize: keySize,
|
|
325
332
|
rotateKeys: Boolean(data.rotateKeys),
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import * as fs from 'fs';
|
|
2
|
-
import * as path from 'path';
|
|
3
|
-
export { fs, path, };
|
|
4
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGx1Z2lucy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzX29jaV9jb250YWluZXIvcGx1Z2lucy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssRUFBRSxNQUFNLElBQUksQ0FBQztBQUN6QixPQUFPLEtBQUssSUFBSSxNQUFNLE1BQU0sQ0FBQztBQUU3QixPQUFPLEVBQ0wsRUFBRSxFQUNGLElBQUksR0FDTCxDQUFDIn0=
|