@serve.zone/dcrouter 13.28.0 → 13.30.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 (39) hide show
  1. package/.smartconfig.json +32 -10
  2. package/dist_serve/bundle.js +609 -592
  3. package/dist_ts/00_commitinfo_data.js +1 -1
  4. package/dist_ts/classes.dcrouter.d.ts +7 -0
  5. package/dist_ts/classes.dcrouter.js +12 -2
  6. package/dist_ts/config/classes.route-config-manager.js +8 -7
  7. package/dist_ts/opsserver/classes.opsserver.js +4 -1
  8. package/dist_ts/opsserver/handlers/admin.handler.d.ts +21 -6
  9. package/dist_ts/opsserver/handlers/admin.handler.js +188 -29
  10. package/dist_ts/opsserver/handlers/target-profile.handler.js +3 -1
  11. package/dist_ts/opsserver/handlers/users.handler.js +2 -2
  12. package/dist_ts/plugins.d.ts +2 -0
  13. package/dist_ts/plugins.js +4 -1
  14. package/dist_ts/vpn/classes.vpn-manager.d.ts +2 -0
  15. package/dist_ts/vpn/classes.vpn-manager.js +41 -20
  16. package/dist_ts_interfaces/requests/admin.d.ts +38 -0
  17. package/dist_ts_interfaces/requests/users.d.ts +2 -5
  18. package/dist_ts_web/00_commitinfo_data.js +1 -1
  19. package/dist_ts_web/appstate.d.ts +17 -0
  20. package/dist_ts_web/appstate.js +27 -1
  21. package/dist_ts_web/elements/ops-dashboard.d.ts +4 -0
  22. package/dist_ts_web/elements/ops-dashboard.js +100 -3
  23. package/package.json +27 -34
  24. package/readme.md +15 -3
  25. package/ts/00_commitinfo_data.ts +1 -1
  26. package/ts/classes.dcrouter.ts +20 -1
  27. package/ts/config/classes.route-config-manager.ts +8 -6
  28. package/ts/opsserver/classes.opsserver.ts +3 -0
  29. package/ts/opsserver/handlers/admin.handler.ts +244 -32
  30. package/ts/opsserver/handlers/target-profile.handler.ts +2 -0
  31. package/ts/opsserver/handlers/users.handler.ts +1 -1
  32. package/ts/plugins.ts +7 -0
  33. package/ts/readme.md +1 -1
  34. package/ts/vpn/classes.vpn-manager.ts +56 -25
  35. package/ts_apiclient/readme.md +4 -4
  36. package/ts_web/00_commitinfo_data.ts +1 -1
  37. package/ts_web/appstate.ts +49 -0
  38. package/ts_web/elements/ops-dashboard.ts +100 -0
  39. package/ts_web/readme.md +5 -3
@@ -66,6 +66,9 @@ export class OpsDashboard extends DeesElement {
66
66
  isLoggedIn: false,
67
67
  };
68
68
 
69
+ private bootstrapStepper?: any;
70
+ private bootstrapCheckPromise?: Promise<void>;
71
+
69
72
  @state() accessor uiState: appstate.IUiState = {
70
73
  activeView: 'overview',
71
74
  activeSubview: null,
@@ -336,6 +339,7 @@ export class OpsDashboard extends DeesElement {
336
339
  await (simpleLogin as any).switchToSlottedContent();
337
340
  await appstate.statsStatePart.dispatchAction(appstate.fetchAllStatsAction, null);
338
341
  await appstate.configStatePart.dispatchAction(appstate.fetchConfigurationAction, null);
342
+ await this.ensureAdminBootstrap();
339
343
  } else {
340
344
  // Server rejected the JWT — clear state, show login
341
345
  await appstate.loginStatePart.dispatchAction(appstate.logoutAction, null);
@@ -370,10 +374,106 @@ export class OpsDashboard extends DeesElement {
370
374
  await simpleLogin!.switchToSlottedContent();
371
375
  await appstate.statsStatePart.dispatchAction(appstate.fetchAllStatsAction, null);
372
376
  await appstate.configStatePart.dispatchAction(appstate.fetchConfigurationAction, null);
377
+ await this.ensureAdminBootstrap();
373
378
  } else {
374
379
  form!.setStatus('error', 'Login failed!');
375
380
  await domtools.convenience.smartdelay.delayFor(2000);
376
381
  form!.reset();
377
382
  }
378
383
  }
384
+
385
+ private async ensureAdminBootstrap(): Promise<void> {
386
+ if (!this.loginState.identity || this.bootstrapStepper?.isConnected) {
387
+ return;
388
+ }
389
+ if (this.bootstrapCheckPromise) {
390
+ return this.bootstrapCheckPromise;
391
+ }
392
+
393
+ this.bootstrapCheckPromise = (async () => {
394
+ try {
395
+ const status = await appstate.getAdminBootstrapStatus();
396
+ if (status.needsBootstrap) {
397
+ await this.showAdminBootstrapStepper(status);
398
+ }
399
+ } catch (error) {
400
+ console.error('Admin bootstrap status check failed:', error);
401
+ } finally {
402
+ this.bootstrapCheckPromise = undefined;
403
+ }
404
+ })();
405
+
406
+ return this.bootstrapCheckPromise;
407
+ }
408
+
409
+ private async showAdminBootstrapStepper(statusArg: appstate.IAdminBootstrapStatus): Promise<void> {
410
+ const { DeesStepper } = await import('@design.estate/dees-catalog');
411
+ this.bootstrapStepper = await DeesStepper.createAndShow({
412
+ cancelable: false,
413
+ steps: [
414
+ {
415
+ title: 'Create Persisted Admin',
416
+ content: html`
417
+ <div style="display: grid; gap: 16px; color: var(--dees-color-text-secondary); font-size: 14px; line-height: 1.5;">
418
+ <p style="margin: 0;">
419
+ This router is currently using the temporary bootstrap admin. Create the first persisted admin account to continue.
420
+ </p>
421
+ <dees-form>
422
+ <dees-input-text .key=${'email'} .label=${'Admin email'} .required=${true}></dees-input-text>
423
+ <dees-input-text .key=${'name'} .label=${'Display name'}></dees-input-text>
424
+ <dees-input-text .key=${'password'} .label=${'Password'} .required=${true} .isPasswordBool=${true}></dees-input-text>
425
+ <dees-input-text .key=${'passwordConfirm'} .label=${'Confirm password'} .required=${true} .isPasswordBool=${true}></dees-input-text>
426
+ <dees-input-checkbox
427
+ .key=${'enableIdpGlobalAuth'}
428
+ .label=${'Allow idp.global login for this email'}
429
+ .description=${statusArg.idpGlobalConfigured
430
+ ? 'The local account remains authoritative; idp.global only verifies identity.'
431
+ : 'Requires DCROUTER_IDP_GLOBAL_URL before idp.global logins can work.'}
432
+ ></dees-input-checkbox>
433
+ </dees-form>
434
+ </div>
435
+ `,
436
+ menuOptions: [
437
+ {
438
+ name: 'Create admin',
439
+ action: async (stepperArg: any) => {
440
+ const form = stepperArg.shadowRoot?.querySelector('.selected dees-form') as any;
441
+ if (!form) return;
442
+ const formData = await form.collectFormData();
443
+ const email = String(formData.email || '').trim();
444
+ const name = String(formData.name || '').trim();
445
+ const password = String(formData.password || '');
446
+ const passwordConfirm = String(formData.passwordConfirm || '');
447
+
448
+ if (!email || !password) {
449
+ form.setStatus?.('error', 'Email and password are required.');
450
+ return;
451
+ }
452
+ if (password !== passwordConfirm) {
453
+ form.setStatus?.('error', 'Passwords do not match.');
454
+ return;
455
+ }
456
+
457
+ try {
458
+ form.setStatus?.('pending', 'Creating persisted admin...');
459
+ await appstate.createInitialAdminUser({
460
+ email,
461
+ name,
462
+ password,
463
+ enableIdpGlobalAuth: Boolean(formData.enableIdpGlobalAuth),
464
+ });
465
+ form.setStatus?.('success', 'Persisted admin created.');
466
+ await stepperArg.destroy();
467
+ this.bootstrapStepper = undefined;
468
+ await appstate.usersStatePart.dispatchAction(appstate.fetchUsersAction, null);
469
+ } catch (error) {
470
+ form.setStatus?.('error', error instanceof Error ? error.message : 'Failed to create admin.');
471
+ }
472
+ },
473
+ },
474
+ ],
475
+ },
476
+ ],
477
+ });
478
+ }
379
479
  }
package/ts_web/readme.md CHANGED
@@ -12,8 +12,8 @@ For reporting bugs, issues, or security vulnerabilities, please visit [community
12
12
  | --- | --- |
13
13
  | `index.ts` | Initializes the app router and renders `<ops-dashboard>` into `document.body`. |
14
14
  | `router.ts` | Defines top-level dashboard routes, subviews, redirects, and URL/state synchronization. |
15
- | `appstate.ts` | Holds reactive login, UI, config, stats, route, DNS, email, remote ingress, VPN, and log state. |
16
- | `elements/` | Contains the dashboard shell and feature-specific Dees web components. |
15
+ | `appstate.ts` | Holds reactive login, bootstrap, UI, config, stats, route, DNS, email, remote ingress, VPN, and log state. |
16
+ | `elements/` | Contains the dashboard shell, first-admin bootstrap stepper, and feature-specific Dees web components. |
17
17
 
18
18
  ## View Map
19
19
 
@@ -37,6 +37,8 @@ The dashboard talks to the dcrouter OpsServer through:
37
37
  - Dees web components and app-state subscriptions for UI updates
38
38
  - QR code rendering for VPN client UX
39
39
 
40
+ On a fresh DB-backed instance, the dashboard checks `getAdminBootstrapStatus` and shows a non-cancelable first-admin stepper before normal dashboard access.
41
+
40
42
  ## Usage
41
43
 
42
44
  This package is primarily consumed by the main dcrouter build and served by OpsServer. Install it directly only when you intentionally need the dashboard module boundary.
@@ -79,7 +81,7 @@ Use of these trademarks must comply with Task Venture Capital GmbH's Trademark G
79
81
 
80
82
  ### Company Information
81
83
 
82
- Task Venture Capital GmbH
84
+ Task Venture Capital GmbH
83
85
  Registered at District Court Bremen HRB 35230 HB, Germany
84
86
 
85
87
  For any legal inquiries or further information, please contact us via email at hello@task.vc.