@serve.zone/dcrouter 7.4.3 → 8.1.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 (110) hide show
  1. package/dist_serve/bundle.js +11567 -3516
  2. package/dist_ts/00_commitinfo_data.js +1 -1
  3. package/dist_ts/classes.dcrouter.d.ts +9 -0
  4. package/dist_ts/classes.dcrouter.js +27 -1
  5. package/dist_ts/config/classes.api-token-manager.d.ts +38 -0
  6. package/dist_ts/config/classes.api-token-manager.js +134 -0
  7. package/dist_ts/config/classes.route-config-manager.d.ts +35 -0
  8. package/dist_ts/config/classes.route-config-manager.js +231 -0
  9. package/dist_ts/config/index.d.ts +2 -0
  10. package/dist_ts/config/index.js +3 -1
  11. package/dist_ts/opsserver/classes.opsserver.d.ts +2 -0
  12. package/dist_ts/opsserver/classes.opsserver.js +5 -1
  13. package/dist_ts/opsserver/handlers/{email-ops.handler.d.ts → api-token.handler.d.ts} +4 -4
  14. package/dist_ts/opsserver/handlers/api-token.handler.js +66 -0
  15. package/dist_ts/opsserver/handlers/index.d.ts +2 -0
  16. package/dist_ts/opsserver/handlers/index.js +3 -1
  17. package/dist_ts/opsserver/handlers/{radius.handler.d.ts → route-management.handler.d.ts} +6 -1
  18. package/dist_ts/opsserver/handlers/route-management.handler.js +117 -0
  19. package/dist_ts_interfaces/data/index.d.ts +1 -0
  20. package/dist_ts_interfaces/data/index.js +2 -1
  21. package/dist_ts_interfaces/data/route-management.d.ts +68 -0
  22. package/dist_ts_interfaces/data/route-management.js +2 -0
  23. package/dist_ts_interfaces/requests/api-tokens.d.ts +63 -0
  24. package/dist_ts_interfaces/requests/api-tokens.js +2 -0
  25. package/dist_ts_interfaces/requests/email-ops.d.ts +51 -108
  26. package/dist_ts_interfaces/requests/index.d.ts +2 -0
  27. package/dist_ts_interfaces/requests/index.js +3 -1
  28. package/dist_ts_interfaces/requests/route-management.d.ts +114 -0
  29. package/dist_ts_interfaces/requests/route-management.js +2 -0
  30. package/dist_ts_web/00_commitinfo_data.js +1 -1
  31. package/dist_ts_web/appstate.d.ts +38 -16
  32. package/dist_ts_web/appstate.js +226 -177
  33. package/dist_ts_web/elements/index.d.ts +2 -0
  34. package/dist_ts_web/elements/index.js +3 -1
  35. package/dist_ts_web/elements/ops-dashboard.js +11 -1
  36. package/dist_ts_web/elements/ops-view-apitokens.d.ts +12 -0
  37. package/dist_ts_web/elements/ops-view-apitokens.js +306 -0
  38. package/dist_ts_web/elements/ops-view-emails.d.ts +8 -31
  39. package/dist_ts_web/elements/ops-view-emails.js +54 -769
  40. package/dist_ts_web/elements/ops-view-logs.d.ts +2 -8
  41. package/dist_ts_web/elements/ops-view-logs.js +4 -101
  42. package/dist_ts_web/elements/ops-view-routes.d.ts +12 -0
  43. package/dist_ts_web/elements/ops-view-routes.js +404 -0
  44. package/dist_ts_web/plugins.d.ts +2 -1
  45. package/dist_ts_web/plugins.js +4 -2
  46. package/dist_ts_web/router.d.ts +1 -7
  47. package/dist_ts_web/router.js +8 -82
  48. package/package.json +2 -1
  49. package/ts/00_commitinfo_data.ts +1 -1
  50. package/ts/classes.dcrouter.ts +37 -1
  51. package/ts/config/classes.api-token-manager.ts +155 -0
  52. package/ts/config/classes.route-config-manager.ts +271 -0
  53. package/ts/config/index.ts +3 -1
  54. package/ts/opsserver/classes.opsserver.ts +4 -0
  55. package/ts/opsserver/handlers/api-token.handler.ts +96 -0
  56. package/ts/opsserver/handlers/email-ops.handler.ts +177 -225
  57. package/ts/opsserver/handlers/index.ts +3 -1
  58. package/ts/opsserver/handlers/route-management.handler.ts +163 -0
  59. package/ts_web/00_commitinfo_data.ts +1 -1
  60. package/ts_web/appstate.ts +316 -222
  61. package/ts_web/elements/index.ts +2 -0
  62. package/ts_web/elements/ops-dashboard.ts +10 -0
  63. package/ts_web/elements/ops-view-apitokens.ts +281 -0
  64. package/ts_web/elements/ops-view-emails.ts +40 -749
  65. package/ts_web/elements/ops-view-logs.ts +2 -87
  66. package/ts_web/elements/ops-view-routes.ts +389 -0
  67. package/ts_web/plugins.ts +4 -0
  68. package/ts_web/router.ts +7 -82
  69. package/dist_ts/cache/classes.cache.cleaner.d.ts +0 -47
  70. package/dist_ts/cache/classes.cache.cleaner.js +0 -130
  71. package/dist_ts/cache/classes.cached.document.d.ts +0 -76
  72. package/dist_ts/cache/classes.cached.document.js +0 -100
  73. package/dist_ts/cache/classes.cachedb.d.ts +0 -60
  74. package/dist_ts/cache/classes.cachedb.js +0 -126
  75. package/dist_ts/cache/documents/classes.cached.email.d.ts +0 -125
  76. package/dist_ts/cache/documents/classes.cached.email.js +0 -337
  77. package/dist_ts/cache/documents/classes.cached.ip.reputation.d.ts +0 -119
  78. package/dist_ts/cache/documents/classes.cached.ip.reputation.js +0 -323
  79. package/dist_ts/cache/documents/index.d.ts +0 -2
  80. package/dist_ts/cache/documents/index.js +0 -3
  81. package/dist_ts/cache/index.d.ts +0 -4
  82. package/dist_ts/cache/index.js +0 -7
  83. package/dist_ts/monitoring/classes.metricscache.d.ts +0 -32
  84. package/dist_ts/monitoring/classes.metricscache.js +0 -63
  85. package/dist_ts/monitoring/classes.metricsmanager.d.ts +0 -169
  86. package/dist_ts/monitoring/classes.metricsmanager.js +0 -591
  87. package/dist_ts/monitoring/index.d.ts +0 -1
  88. package/dist_ts/monitoring/index.js +0 -2
  89. package/dist_ts/opsserver/handlers/admin.handler.d.ts +0 -31
  90. package/dist_ts/opsserver/handlers/admin.handler.js +0 -180
  91. package/dist_ts/opsserver/handlers/certificate.handler.d.ts +0 -34
  92. package/dist_ts/opsserver/handlers/certificate.handler.js +0 -419
  93. package/dist_ts/opsserver/handlers/config.handler.d.ts +0 -9
  94. package/dist_ts/opsserver/handlers/config.handler.js +0 -67
  95. package/dist_ts/opsserver/handlers/email-ops.handler.js +0 -219
  96. package/dist_ts/opsserver/handlers/logs.handler.d.ts +0 -17
  97. package/dist_ts/opsserver/handlers/logs.handler.js +0 -215
  98. package/dist_ts/opsserver/handlers/radius.handler.js +0 -296
  99. package/dist_ts/opsserver/handlers/remoteingress.handler.d.ts +0 -8
  100. package/dist_ts/opsserver/handlers/remoteingress.handler.js +0 -154
  101. package/dist_ts/opsserver/handlers/security.handler.d.ts +0 -11
  102. package/dist_ts/opsserver/handlers/security.handler.js +0 -232
  103. package/dist_ts/opsserver/handlers/stats.handler.d.ts +0 -13
  104. package/dist_ts/opsserver/handlers/stats.handler.js +0 -400
  105. package/dist_ts/security/classes.securitylogger.d.ts +0 -140
  106. package/dist_ts/security/classes.securitylogger.js +0 -235
  107. package/dist_ts/storage/classes.storagemanager.d.ts +0 -82
  108. package/dist_ts/storage/classes.storagemanager.js +0 -344
  109. package/dist_ts/storage/index.d.ts +0 -1
  110. package/dist_ts/storage/index.js +0 -3
@@ -67,14 +67,7 @@ export interface ICertificateState {
67
67
  }
68
68
 
69
69
  export interface IEmailOpsState {
70
- currentView: 'queued' | 'sent' | 'failed' | 'received' | 'security';
71
- queuedEmails: interfaces.requests.IEmailQueueItem[];
72
- sentEmails: interfaces.requests.IEmailQueueItem[];
73
- failedEmails: interfaces.requests.IEmailQueueItem[];
74
- securityIncidents: interfaces.requests.ISecurityIncident[];
75
- bounceRecords: interfaces.requests.IBounceRecord[];
76
- suppressionList: string[];
77
- selectedEmailId: string | null;
70
+ emails: interfaces.requests.IEmail[];
78
71
  isLoading: boolean;
79
72
  error: string | null;
80
73
  lastUpdated: number;
@@ -116,7 +109,7 @@ export const configStatePart = await appState.getStatePart<IConfigState>(
116
109
  // Determine initial view from URL path
117
110
  const getInitialView = (): string => {
118
111
  const path = typeof window !== 'undefined' ? window.location.pathname : '/';
119
- const validViews = ['overview', 'network', 'emails', 'logs', 'configuration', 'security', 'certificates', 'remoteingress'];
112
+ const validViews = ['overview', 'network', 'emails', 'logs', 'routes', 'apitokens', 'configuration', 'security', 'certificates', 'remoteingress'];
120
113
  const segments = path.split('/').filter(Boolean);
121
114
  const view = segments[0];
122
115
  return validViews.includes(view) ? view : 'overview';
@@ -165,14 +158,7 @@ export const networkStatePart = await appState.getStatePart<INetworkState>(
165
158
  export const emailOpsStatePart = await appState.getStatePart<IEmailOpsState>(
166
159
  'emailOps',
167
160
  {
168
- currentView: 'queued',
169
- queuedEmails: [],
170
- sentEmails: [],
171
- failedEmails: [],
172
- securityIncidents: [],
173
- bounceRecords: [],
174
- suppressionList: [],
175
- selectedEmailId: null,
161
+ emails: [],
176
162
  isLoading: false,
177
163
  error: null,
178
164
  lastUpdated: 0,
@@ -220,6 +206,32 @@ export const remoteIngressStatePart = await appState.getStatePart<IRemoteIngress
220
206
  'soft'
221
207
  );
222
208
 
209
+ // ============================================================================
210
+ // Route Management State
211
+ // ============================================================================
212
+
213
+ export interface IRouteManagementState {
214
+ mergedRoutes: interfaces.data.IMergedRoute[];
215
+ warnings: interfaces.data.IRouteWarning[];
216
+ apiTokens: interfaces.data.IApiTokenInfo[];
217
+ isLoading: boolean;
218
+ error: string | null;
219
+ lastUpdated: number;
220
+ }
221
+
222
+ export const routeManagementStatePart = await appState.getStatePart<IRouteManagementState>(
223
+ 'routeManagement',
224
+ {
225
+ mergedRoutes: [],
226
+ warnings: [],
227
+ apiTokens: [],
228
+ isLoading: false,
229
+ error: null,
230
+ lastUpdated: 0,
231
+ },
232
+ 'soft'
233
+ );
234
+
223
235
  // Actions for state management
224
236
  interface IActionContext {
225
237
  identity: interfaces.data.IIdentity | null;
@@ -406,6 +418,20 @@ export const setActiveViewAction = uiStatePart.createAction<string>(async (state
406
418
  }, 100);
407
419
  }
408
420
 
421
+ // If switching to routes view, ensure we fetch route data
422
+ if (viewName === 'routes' && currentState.activeView !== 'routes') {
423
+ setTimeout(() => {
424
+ routeManagementStatePart.dispatchAction(fetchMergedRoutesAction, null);
425
+ }, 100);
426
+ }
427
+
428
+ // If switching to apitokens view, ensure we fetch token data
429
+ if (viewName === 'apitokens' && currentState.activeView !== 'apitokens') {
430
+ setTimeout(() => {
431
+ routeManagementStatePart.dispatchAction(fetchApiTokensAction, null);
432
+ }, 100);
433
+ }
434
+
409
435
  // If switching to remoteingress view, ensure we fetch edge data
410
436
  if (viewName === 'remoteingress' && currentState.activeView !== 'remoteingress') {
411
437
  setTimeout(() => {
@@ -492,128 +518,22 @@ export const fetchNetworkStatsAction = networkStatePart.createAction(async (stat
492
518
  // Email Operations Actions
493
519
  // ============================================================================
494
520
 
495
- // Set Email Ops View Action
496
- export const setEmailOpsViewAction = emailOpsStatePart.createAction<IEmailOpsState['currentView']>(
497
- async (statePartArg, view) => {
498
- return {
499
- ...statePartArg.getState(),
500
- currentView: view,
501
- };
502
- }
503
- );
504
-
505
- // Fetch Queued Emails Action
506
- export const fetchQueuedEmailsAction = emailOpsStatePart.createAction(async (statePartArg) => {
507
- const context = getActionContext();
508
- const currentState = statePartArg.getState();
509
-
510
- try {
511
- const request = new plugins.domtools.plugins.typedrequest.TypedRequest<
512
- interfaces.requests.IReq_GetQueuedEmails
513
- >('/typedrequest', 'getQueuedEmails');
514
-
515
- const response = await request.fire({
516
- identity: context.identity,
517
- status: 'pending',
518
- limit: 100,
519
- });
520
-
521
- return {
522
- ...currentState,
523
- queuedEmails: response.items,
524
- isLoading: false,
525
- error: null,
526
- lastUpdated: Date.now(),
527
- };
528
- } catch (error) {
529
- return {
530
- ...currentState,
531
- isLoading: false,
532
- error: error instanceof Error ? error.message : 'Failed to fetch queued emails',
533
- };
534
- }
535
- });
536
-
537
- // Fetch Sent Emails Action
538
- export const fetchSentEmailsAction = emailOpsStatePart.createAction(async (statePartArg) => {
539
- const context = getActionContext();
540
- const currentState = statePartArg.getState();
541
-
542
- try {
543
- const request = new plugins.domtools.plugins.typedrequest.TypedRequest<
544
- interfaces.requests.IReq_GetSentEmails
545
- >('/typedrequest', 'getSentEmails');
546
-
547
- const response = await request.fire({
548
- identity: context.identity,
549
- limit: 100,
550
- });
551
-
552
- return {
553
- ...currentState,
554
- sentEmails: response.items,
555
- isLoading: false,
556
- error: null,
557
- lastUpdated: Date.now(),
558
- };
559
- } catch (error) {
560
- return {
561
- ...currentState,
562
- isLoading: false,
563
- error: error instanceof Error ? error.message : 'Failed to fetch sent emails',
564
- };
565
- }
566
- });
567
-
568
- // Fetch Failed Emails Action
569
- export const fetchFailedEmailsAction = emailOpsStatePart.createAction(async (statePartArg) => {
570
- const context = getActionContext();
571
- const currentState = statePartArg.getState();
572
-
573
- try {
574
- const request = new plugins.domtools.plugins.typedrequest.TypedRequest<
575
- interfaces.requests.IReq_GetFailedEmails
576
- >('/typedrequest', 'getFailedEmails');
577
-
578
- const response = await request.fire({
579
- identity: context.identity,
580
- limit: 100,
581
- });
582
-
583
- return {
584
- ...currentState,
585
- failedEmails: response.items,
586
- isLoading: false,
587
- error: null,
588
- lastUpdated: Date.now(),
589
- };
590
- } catch (error) {
591
- return {
592
- ...currentState,
593
- isLoading: false,
594
- error: error instanceof Error ? error.message : 'Failed to fetch failed emails',
595
- };
596
- }
597
- });
598
-
599
- // Fetch Security Incidents Action
600
- export const fetchSecurityIncidentsAction = emailOpsStatePart.createAction(async (statePartArg) => {
521
+ // Fetch All Emails Action
522
+ export const fetchAllEmailsAction = emailOpsStatePart.createAction(async (statePartArg) => {
601
523
  const context = getActionContext();
602
524
  const currentState = statePartArg.getState();
603
525
 
604
526
  try {
605
527
  const request = new plugins.domtools.plugins.typedrequest.TypedRequest<
606
- interfaces.requests.IReq_GetSecurityIncidents
607
- >('/typedrequest', 'getSecurityIncidents');
528
+ interfaces.requests.IReq_GetAllEmails
529
+ >('/typedrequest', 'getAllEmails');
608
530
 
609
531
  const response = await request.fire({
610
532
  identity: context.identity,
611
- limit: 100,
612
533
  });
613
534
 
614
535
  return {
615
- ...currentState,
616
- securityIncidents: response.incidents,
536
+ emails: response.emails,
617
537
  isLoading: false,
618
538
  error: null,
619
539
  lastUpdated: Date.now(),
@@ -622,104 +542,11 @@ export const fetchSecurityIncidentsAction = emailOpsStatePart.createAction(async
622
542
  return {
623
543
  ...currentState,
624
544
  isLoading: false,
625
- error: error instanceof Error ? error.message : 'Failed to fetch security incidents',
545
+ error: error instanceof Error ? error.message : 'Failed to fetch emails',
626
546
  };
627
547
  }
628
548
  });
629
549
 
630
- // Fetch Bounce Records Action
631
- export const fetchBounceRecordsAction = emailOpsStatePart.createAction(async (statePartArg) => {
632
- const context = getActionContext();
633
- const currentState = statePartArg.getState();
634
-
635
- try {
636
- const request = new plugins.domtools.plugins.typedrequest.TypedRequest<
637
- interfaces.requests.IReq_GetBounceRecords
638
- >('/typedrequest', 'getBounceRecords');
639
-
640
- const response = await request.fire({
641
- identity: context.identity,
642
- limit: 100,
643
- });
644
-
645
- return {
646
- ...currentState,
647
- bounceRecords: response.records,
648
- suppressionList: response.suppressionList,
649
- isLoading: false,
650
- error: null,
651
- lastUpdated: Date.now(),
652
- };
653
- } catch (error) {
654
- return {
655
- ...currentState,
656
- isLoading: false,
657
- error: error instanceof Error ? error.message : 'Failed to fetch bounce records',
658
- };
659
- }
660
- });
661
-
662
- // Resend Failed Email Action
663
- export const resendEmailAction = emailOpsStatePart.createAction<string>(async (statePartArg, emailId) => {
664
- const context = getActionContext();
665
- const currentState = statePartArg.getState();
666
-
667
- try {
668
- const request = new plugins.domtools.plugins.typedrequest.TypedRequest<
669
- interfaces.requests.IReq_ResendEmail
670
- >('/typedrequest', 'resendEmail');
671
-
672
- const response = await request.fire({
673
- identity: context.identity,
674
- emailId,
675
- });
676
-
677
- if (response.success) {
678
- // Refresh failed emails list
679
- await emailOpsStatePart.dispatchAction(fetchFailedEmailsAction, null);
680
- await emailOpsStatePart.dispatchAction(fetchQueuedEmailsAction, null);
681
- }
682
-
683
- return statePartArg.getState();
684
- } catch (error) {
685
- return {
686
- ...currentState,
687
- error: error instanceof Error ? error.message : 'Failed to resend email',
688
- };
689
- }
690
- });
691
-
692
- // Remove from Suppression List Action
693
- export const removeFromSuppressionListAction = emailOpsStatePart.createAction<string>(
694
- async (statePartArg, email) => {
695
- const context = getActionContext();
696
- const currentState = statePartArg.getState();
697
-
698
- try {
699
- const request = new plugins.domtools.plugins.typedrequest.TypedRequest<
700
- interfaces.requests.IReq_RemoveFromSuppressionList
701
- >('/typedrequest', 'removeFromSuppressionList');
702
-
703
- const response = await request.fire({
704
- identity: context.identity,
705
- email,
706
- });
707
-
708
- if (response.success) {
709
- // Refresh bounce records
710
- await emailOpsStatePart.dispatchAction(fetchBounceRecordsAction, null);
711
- }
712
-
713
- return statePartArg.getState();
714
- } catch (error) {
715
- return {
716
- ...currentState,
717
- error: error instanceof Error ? error.message : 'Failed to remove from suppression list',
718
- };
719
- }
720
- }
721
- );
722
-
723
550
  // ============================================================================
724
551
  // Certificate Actions
725
552
  // ============================================================================
@@ -1075,6 +902,273 @@ export const toggleRemoteIngressAction = remoteIngressStatePart.createAction<{
1075
902
  }
1076
903
  });
1077
904
 
905
+ // ============================================================================
906
+ // Route Management Actions
907
+ // ============================================================================
908
+
909
+ export const fetchMergedRoutesAction = routeManagementStatePart.createAction(async (statePartArg) => {
910
+ const context = getActionContext();
911
+ const currentState = statePartArg.getState();
912
+
913
+ try {
914
+ const request = new plugins.domtools.plugins.typedrequest.TypedRequest<
915
+ interfaces.requests.IReq_GetMergedRoutes
916
+ >('/typedrequest', 'getMergedRoutes');
917
+
918
+ const response = await request.fire({
919
+ identity: context.identity,
920
+ });
921
+
922
+ return {
923
+ ...currentState,
924
+ mergedRoutes: response.routes,
925
+ warnings: response.warnings,
926
+ isLoading: false,
927
+ error: null,
928
+ lastUpdated: Date.now(),
929
+ };
930
+ } catch (error) {
931
+ return {
932
+ ...currentState,
933
+ isLoading: false,
934
+ error: error instanceof Error ? error.message : 'Failed to fetch routes',
935
+ };
936
+ }
937
+ });
938
+
939
+ export const createRouteAction = routeManagementStatePart.createAction<{
940
+ route: any;
941
+ enabled?: boolean;
942
+ }>(async (statePartArg, dataArg) => {
943
+ const context = getActionContext();
944
+ const currentState = statePartArg.getState();
945
+
946
+ try {
947
+ const request = new plugins.domtools.plugins.typedrequest.TypedRequest<
948
+ interfaces.requests.IReq_CreateRoute
949
+ >('/typedrequest', 'createRoute');
950
+
951
+ await request.fire({
952
+ identity: context.identity,
953
+ route: dataArg.route,
954
+ enabled: dataArg.enabled,
955
+ });
956
+
957
+ await routeManagementStatePart.dispatchAction(fetchMergedRoutesAction, null);
958
+ return statePartArg.getState();
959
+ } catch (error) {
960
+ return {
961
+ ...currentState,
962
+ error: error instanceof Error ? error.message : 'Failed to create route',
963
+ };
964
+ }
965
+ });
966
+
967
+ export const deleteRouteAction = routeManagementStatePart.createAction<string>(
968
+ async (statePartArg, routeId) => {
969
+ const context = getActionContext();
970
+ const currentState = statePartArg.getState();
971
+
972
+ try {
973
+ const request = new plugins.domtools.plugins.typedrequest.TypedRequest<
974
+ interfaces.requests.IReq_DeleteRoute
975
+ >('/typedrequest', 'deleteRoute');
976
+
977
+ await request.fire({
978
+ identity: context.identity,
979
+ id: routeId,
980
+ });
981
+
982
+ await routeManagementStatePart.dispatchAction(fetchMergedRoutesAction, null);
983
+ return statePartArg.getState();
984
+ } catch (error) {
985
+ return {
986
+ ...currentState,
987
+ error: error instanceof Error ? error.message : 'Failed to delete route',
988
+ };
989
+ }
990
+ }
991
+ );
992
+
993
+ export const toggleRouteAction = routeManagementStatePart.createAction<{
994
+ id: string;
995
+ enabled: boolean;
996
+ }>(async (statePartArg, dataArg) => {
997
+ const context = getActionContext();
998
+ const currentState = statePartArg.getState();
999
+
1000
+ try {
1001
+ const request = new plugins.domtools.plugins.typedrequest.TypedRequest<
1002
+ interfaces.requests.IReq_ToggleRoute
1003
+ >('/typedrequest', 'toggleRoute');
1004
+
1005
+ await request.fire({
1006
+ identity: context.identity,
1007
+ id: dataArg.id,
1008
+ enabled: dataArg.enabled,
1009
+ });
1010
+
1011
+ await routeManagementStatePart.dispatchAction(fetchMergedRoutesAction, null);
1012
+ return statePartArg.getState();
1013
+ } catch (error) {
1014
+ return {
1015
+ ...currentState,
1016
+ error: error instanceof Error ? error.message : 'Failed to toggle route',
1017
+ };
1018
+ }
1019
+ });
1020
+
1021
+ export const setRouteOverrideAction = routeManagementStatePart.createAction<{
1022
+ routeName: string;
1023
+ enabled: boolean;
1024
+ }>(async (statePartArg, dataArg) => {
1025
+ const context = getActionContext();
1026
+ const currentState = statePartArg.getState();
1027
+
1028
+ try {
1029
+ const request = new plugins.domtools.plugins.typedrequest.TypedRequest<
1030
+ interfaces.requests.IReq_SetRouteOverride
1031
+ >('/typedrequest', 'setRouteOverride');
1032
+
1033
+ await request.fire({
1034
+ identity: context.identity,
1035
+ routeName: dataArg.routeName,
1036
+ enabled: dataArg.enabled,
1037
+ });
1038
+
1039
+ await routeManagementStatePart.dispatchAction(fetchMergedRoutesAction, null);
1040
+ return statePartArg.getState();
1041
+ } catch (error) {
1042
+ return {
1043
+ ...currentState,
1044
+ error: error instanceof Error ? error.message : 'Failed to set override',
1045
+ };
1046
+ }
1047
+ });
1048
+
1049
+ export const removeRouteOverrideAction = routeManagementStatePart.createAction<string>(
1050
+ async (statePartArg, routeName) => {
1051
+ const context = getActionContext();
1052
+ const currentState = statePartArg.getState();
1053
+
1054
+ try {
1055
+ const request = new plugins.domtools.plugins.typedrequest.TypedRequest<
1056
+ interfaces.requests.IReq_RemoveRouteOverride
1057
+ >('/typedrequest', 'removeRouteOverride');
1058
+
1059
+ await request.fire({
1060
+ identity: context.identity,
1061
+ routeName,
1062
+ });
1063
+
1064
+ await routeManagementStatePart.dispatchAction(fetchMergedRoutesAction, null);
1065
+ return statePartArg.getState();
1066
+ } catch (error) {
1067
+ return {
1068
+ ...currentState,
1069
+ error: error instanceof Error ? error.message : 'Failed to remove override',
1070
+ };
1071
+ }
1072
+ }
1073
+ );
1074
+
1075
+ // ============================================================================
1076
+ // API Token Actions
1077
+ // ============================================================================
1078
+
1079
+ export const fetchApiTokensAction = routeManagementStatePart.createAction(async (statePartArg) => {
1080
+ const context = getActionContext();
1081
+ const currentState = statePartArg.getState();
1082
+
1083
+ try {
1084
+ const request = new plugins.domtools.plugins.typedrequest.TypedRequest<
1085
+ interfaces.requests.IReq_ListApiTokens
1086
+ >('/typedrequest', 'listApiTokens');
1087
+
1088
+ const response = await request.fire({
1089
+ identity: context.identity,
1090
+ });
1091
+
1092
+ return {
1093
+ ...currentState,
1094
+ apiTokens: response.tokens,
1095
+ };
1096
+ } catch (error) {
1097
+ return {
1098
+ ...currentState,
1099
+ error: error instanceof Error ? error.message : 'Failed to fetch tokens',
1100
+ };
1101
+ }
1102
+ });
1103
+
1104
+ export async function createApiToken(name: string, scopes: interfaces.data.TApiTokenScope[], expiresInDays?: number | null) {
1105
+ const context = getActionContext();
1106
+ const request = new plugins.domtools.plugins.typedrequest.TypedRequest<
1107
+ interfaces.requests.IReq_CreateApiToken
1108
+ >('/typedrequest', 'createApiToken');
1109
+
1110
+ return request.fire({
1111
+ identity: context.identity,
1112
+ name,
1113
+ scopes,
1114
+ expiresInDays,
1115
+ });
1116
+ }
1117
+
1118
+ export const revokeApiTokenAction = routeManagementStatePart.createAction<string>(
1119
+ async (statePartArg, tokenId) => {
1120
+ const context = getActionContext();
1121
+ const currentState = statePartArg.getState();
1122
+
1123
+ try {
1124
+ const request = new plugins.domtools.plugins.typedrequest.TypedRequest<
1125
+ interfaces.requests.IReq_RevokeApiToken
1126
+ >('/typedrequest', 'revokeApiToken');
1127
+
1128
+ await request.fire({
1129
+ identity: context.identity,
1130
+ id: tokenId,
1131
+ });
1132
+
1133
+ await routeManagementStatePart.dispatchAction(fetchApiTokensAction, null);
1134
+ return statePartArg.getState();
1135
+ } catch (error) {
1136
+ return {
1137
+ ...currentState,
1138
+ error: error instanceof Error ? error.message : 'Failed to revoke token',
1139
+ };
1140
+ }
1141
+ }
1142
+ );
1143
+
1144
+ export const toggleApiTokenAction = routeManagementStatePart.createAction<{
1145
+ id: string;
1146
+ enabled: boolean;
1147
+ }>(async (statePartArg, dataArg) => {
1148
+ const context = getActionContext();
1149
+ const currentState = statePartArg.getState();
1150
+
1151
+ try {
1152
+ const request = new plugins.domtools.plugins.typedrequest.TypedRequest<
1153
+ interfaces.requests.IReq_ToggleApiToken
1154
+ >('/typedrequest', 'toggleApiToken');
1155
+
1156
+ await request.fire({
1157
+ identity: context.identity,
1158
+ id: dataArg.id,
1159
+ enabled: dataArg.enabled,
1160
+ });
1161
+
1162
+ await routeManagementStatePart.dispatchAction(fetchApiTokensAction, null);
1163
+ return statePartArg.getState();
1164
+ } catch (error) {
1165
+ return {
1166
+ ...currentState,
1167
+ error: error instanceof Error ? error.message : 'Failed to toggle token',
1168
+ };
1169
+ }
1170
+ });
1171
+
1078
1172
  // ============================================================================
1079
1173
  // TypedSocket Client for Real-time Log Streaming
1080
1174
  // ============================================================================
@@ -4,6 +4,8 @@ export * from './ops-view-network.js';
4
4
  export * from './ops-view-emails.js';
5
5
  export * from './ops-view-logs.js';
6
6
  export * from './ops-view-config.js';
7
+ export * from './ops-view-routes.js';
8
+ export * from './ops-view-apitokens.js';
7
9
  export * from './ops-view-security.js';
8
10
  export * from './ops-view-certificates.js';
9
11
  export * from './ops-view-remoteingress.js';
@@ -18,6 +18,8 @@ import { OpsViewNetwork } from './ops-view-network.js';
18
18
  import { OpsViewEmails } from './ops-view-emails.js';
19
19
  import { OpsViewLogs } from './ops-view-logs.js';
20
20
  import { OpsViewConfig } from './ops-view-config.js';
21
+ import { OpsViewRoutes } from './ops-view-routes.js';
22
+ import { OpsViewApiTokens } from './ops-view-apitokens.js';
21
23
  import { OpsViewSecurity } from './ops-view-security.js';
22
24
  import { OpsViewCertificates } from './ops-view-certificates.js';
23
25
  import { OpsViewRemoteIngress } from './ops-view-remoteingress.js';
@@ -55,6 +57,14 @@ export class OpsDashboard extends DeesElement {
55
57
  name: 'Logs',
56
58
  element: OpsViewLogs,
57
59
  },
60
+ {
61
+ name: 'Routes',
62
+ element: OpsViewRoutes,
63
+ },
64
+ {
65
+ name: 'ApiTokens',
66
+ element: OpsViewApiTokens,
67
+ },
58
68
  {
59
69
  name: 'Configuration',
60
70
  element: OpsViewConfig,