@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
@@ -0,0 +1,281 @@
1
+ import * as appstate from '../appstate.js';
2
+ import * as interfaces from '../../dist_ts_interfaces/index.js';
3
+ import { viewHostCss } from './shared/css.js';
4
+
5
+ import {
6
+ DeesElement,
7
+ css,
8
+ cssManager,
9
+ customElement,
10
+ html,
11
+ state,
12
+ type TemplateResult,
13
+ } from '@design.estate/dees-element';
14
+
15
+ type TApiTokenScope = interfaces.data.TApiTokenScope;
16
+
17
+ @customElement('ops-view-apitokens')
18
+ export class OpsViewApiTokens extends DeesElement {
19
+ @state() accessor routeState: appstate.IRouteManagementState = {
20
+ mergedRoutes: [],
21
+ warnings: [],
22
+ apiTokens: [],
23
+ isLoading: false,
24
+ error: null,
25
+ lastUpdated: 0,
26
+ };
27
+
28
+ constructor() {
29
+ super();
30
+ const sub = appstate.routeManagementStatePart
31
+ .select((s) => s)
32
+ .subscribe((routeState) => {
33
+ this.routeState = routeState;
34
+ });
35
+ this.rxSubscriptions.push(sub);
36
+
37
+ // Re-fetch tokens when user logs in (fixes race condition where
38
+ // the view is created before authentication completes)
39
+ const loginSub = appstate.loginStatePart
40
+ .select((s) => s.isLoggedIn)
41
+ .subscribe((isLoggedIn) => {
42
+ if (isLoggedIn) {
43
+ appstate.routeManagementStatePart.dispatchAction(appstate.fetchApiTokensAction, null);
44
+ }
45
+ });
46
+ this.rxSubscriptions.push(loginSub);
47
+ }
48
+
49
+ public static styles = [
50
+ cssManager.defaultStyles,
51
+ viewHostCss,
52
+ css`
53
+ .apiTokensContainer {
54
+ display: flex;
55
+ flex-direction: column;
56
+ gap: 24px;
57
+ }
58
+
59
+ .scopePill {
60
+ display: inline-flex;
61
+ align-items: center;
62
+ padding: 2px 6px;
63
+ border-radius: 3px;
64
+ font-size: 11px;
65
+ background: ${cssManager.bdTheme('rgba(0, 130, 200, 0.1)', 'rgba(0, 170, 255, 0.1)')};
66
+ color: ${cssManager.bdTheme('#0369a1', '#0af')};
67
+ margin-right: 4px;
68
+ margin-bottom: 2px;
69
+ }
70
+
71
+ .statusBadge {
72
+ display: inline-flex;
73
+ align-items: center;
74
+ padding: 3px 10px;
75
+ border-radius: 12px;
76
+ font-size: 12px;
77
+ font-weight: 600;
78
+ letter-spacing: 0.02em;
79
+ text-transform: uppercase;
80
+ }
81
+
82
+ .statusBadge.active {
83
+ background: ${cssManager.bdTheme('#dcfce7', '#14532d')};
84
+ color: ${cssManager.bdTheme('#166534', '#4ade80')};
85
+ }
86
+
87
+ .statusBadge.disabled {
88
+ background: ${cssManager.bdTheme('#fef2f2', '#450a0a')};
89
+ color: ${cssManager.bdTheme('#991b1b', '#f87171')};
90
+ }
91
+
92
+ .statusBadge.expired {
93
+ background: ${cssManager.bdTheme('#f3f4f6', '#374151')};
94
+ color: ${cssManager.bdTheme('#6b7280', '#9ca3af')};
95
+ }
96
+ `,
97
+ ];
98
+
99
+ public render(): TemplateResult {
100
+ const { apiTokens } = this.routeState;
101
+
102
+ return html`
103
+ <ops-sectionheading>API Tokens</ops-sectionheading>
104
+
105
+ <div class="apiTokensContainer">
106
+ <dees-table
107
+ .heading1=${'API Tokens'}
108
+ .heading2=${'Manage programmatic access tokens'}
109
+ .data=${apiTokens}
110
+ .dataName=${'token'}
111
+ .searchable=${true}
112
+ .displayFunction=${(token: interfaces.data.IApiTokenInfo) => ({
113
+ name: token.name,
114
+ scopes: this.renderScopePills(token.scopes),
115
+ status: this.renderStatusBadge(token),
116
+ created: new Date(token.createdAt).toLocaleDateString(),
117
+ expires: token.expiresAt ? new Date(token.expiresAt).toLocaleDateString() : 'Never',
118
+ lastUsed: token.lastUsedAt ? new Date(token.lastUsedAt).toLocaleDateString() : 'Never',
119
+ })}
120
+ .dataActions=${[
121
+ {
122
+ name: 'Create Token',
123
+ iconName: 'lucide:plus',
124
+ type: ['header'],
125
+ actionFunc: async () => {
126
+ await this.showCreateTokenDialog();
127
+ },
128
+ },
129
+ {
130
+ name: 'Enable',
131
+ iconName: 'lucide:play',
132
+ type: ['inRow', 'contextmenu'] as any,
133
+ actionRelevancyCheckFunc: (actionData: any) => !actionData.item.enabled,
134
+ actionFunc: async (actionData: any) => {
135
+ const token = actionData.item as interfaces.data.IApiTokenInfo;
136
+ await appstate.routeManagementStatePart.dispatchAction(
137
+ appstate.toggleApiTokenAction,
138
+ { id: token.id, enabled: true },
139
+ );
140
+ },
141
+ },
142
+ {
143
+ name: 'Disable',
144
+ iconName: 'lucide:pause',
145
+ type: ['inRow', 'contextmenu'] as any,
146
+ actionRelevancyCheckFunc: (actionData: any) => actionData.item.enabled,
147
+ actionFunc: async (actionData: any) => {
148
+ const token = actionData.item as interfaces.data.IApiTokenInfo;
149
+ await appstate.routeManagementStatePart.dispatchAction(
150
+ appstate.toggleApiTokenAction,
151
+ { id: token.id, enabled: false },
152
+ );
153
+ },
154
+ },
155
+ {
156
+ name: 'Revoke',
157
+ iconName: 'lucide:trash2',
158
+ type: ['inRow', 'contextmenu'] as any,
159
+ actionFunc: async (actionData: any) => {
160
+ const token = actionData.item as interfaces.data.IApiTokenInfo;
161
+ await appstate.routeManagementStatePart.dispatchAction(
162
+ appstate.revokeApiTokenAction,
163
+ token.id,
164
+ );
165
+ },
166
+ },
167
+ ]}
168
+ ></dees-table>
169
+ </div>
170
+ `;
171
+ }
172
+
173
+ private renderScopePills(scopes: TApiTokenScope[]): TemplateResult {
174
+ return html`<div style="display: flex; flex-wrap: wrap; gap: 2px;">${scopes.map(
175
+ (s) => html`<span class="scopePill">${s}</span>`,
176
+ )}</div>`;
177
+ }
178
+
179
+ private renderStatusBadge(token: interfaces.data.IApiTokenInfo): TemplateResult {
180
+ if (!token.enabled) {
181
+ return html`<span class="statusBadge disabled">Disabled</span>`;
182
+ }
183
+ if (token.expiresAt && token.expiresAt < Date.now()) {
184
+ return html`<span class="statusBadge expired">Expired</span>`;
185
+ }
186
+ return html`<span class="statusBadge active">Active</span>`;
187
+ }
188
+
189
+ private async showCreateTokenDialog() {
190
+ const { DeesModal } = await import('@design.estate/dees-catalog');
191
+
192
+ const allScopes: TApiTokenScope[] = [
193
+ 'routes:read',
194
+ 'routes:write',
195
+ 'config:read',
196
+ 'tokens:read',
197
+ 'tokens:manage',
198
+ ];
199
+
200
+ await DeesModal.createAndShow({
201
+ heading: 'Create API Token',
202
+ content: html`
203
+ <div style="color: #888; margin-bottom: 12px; font-size: 13px;">
204
+ The token value will be shown once after creation. Copy it immediately.
205
+ </div>
206
+ <dees-form>
207
+ <dees-input-text .key=${'name'} .label=${'Token Name'} .required=${true}></dees-input-text>
208
+ <dees-input-tags
209
+ .key=${'scopes'}
210
+ .label=${'Token Scopes'}
211
+ .value=${['routes:read', 'routes:write']}
212
+ .suggestions=${allScopes}
213
+ .required=${true}
214
+ ></dees-input-tags>
215
+ <dees-input-text .key=${'expiresInDays'} .label=${'Expires in (days, blank = never)'}></dees-input-text>
216
+ </dees-form>
217
+ `,
218
+ menuOptions: [
219
+ {
220
+ name: 'Cancel',
221
+ iconName: 'lucide:x',
222
+ action: async (modalArg: any) => await modalArg.destroy(),
223
+ },
224
+ {
225
+ name: 'Create',
226
+ iconName: 'lucide:key',
227
+ action: async (modalArg: any) => {
228
+ const form = modalArg.shadowRoot?.querySelector('.content')?.querySelector('dees-form');
229
+ if (!form) return;
230
+ const formData = await form.collectFormData();
231
+ if (!formData.name) return;
232
+
233
+ // dees-input-tags returns string[] directly
234
+ const scopes = (formData.scopes || [])
235
+ .filter((s: string) => allScopes.includes(s as any)) as TApiTokenScope[];
236
+
237
+ const expiresInDays = formData.expiresInDays
238
+ ? parseInt(formData.expiresInDays, 10)
239
+ : null;
240
+
241
+ await modalArg.destroy();
242
+
243
+ try {
244
+ const response = await appstate.createApiToken(formData.name, scopes, expiresInDays);
245
+ if (response.success && response.tokenValue) {
246
+ // Refresh the list first so it's ready when user dismisses the modal
247
+ await appstate.routeManagementStatePart.dispatchAction(appstate.fetchApiTokensAction, null);
248
+
249
+ // Show the token value in a new modal
250
+ await DeesModal.createAndShow({
251
+ heading: 'Token Created',
252
+ content: html`
253
+ <div style="color: #ccc; padding: 8px 0;">
254
+ <p>Copy this token now. It will not be shown again.</p>
255
+ <div style="background: #111; padding: 12px; border-radius: 6px; margin-top: 8px;">
256
+ <code style="color: #0f8; word-break: break-all; font-size: 13px;">${response.tokenValue}</code>
257
+ </div>
258
+ </div>
259
+ `,
260
+ menuOptions: [
261
+ {
262
+ name: 'Done',
263
+ iconName: 'lucide:check',
264
+ action: async (m: any) => await m.destroy(),
265
+ },
266
+ ],
267
+ });
268
+ }
269
+ } catch (error) {
270
+ console.error('Failed to create token:', error);
271
+ }
272
+ },
273
+ },
274
+ ],
275
+ });
276
+ }
277
+
278
+ async firstUpdated() {
279
+ await appstate.routeManagementStatePart.dispatchAction(appstate.fetchApiTokensAction, null);
280
+ }
281
+ }