@zintrust/workers 0.1.30 → 0.1.43

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 (53) hide show
  1. package/dist/ClusterLock.js +3 -2
  2. package/dist/DeadLetterQueue.js +3 -2
  3. package/dist/HealthMonitor.js +24 -13
  4. package/dist/Observability.js +8 -0
  5. package/dist/WorkerFactory.d.ts +4 -0
  6. package/dist/WorkerFactory.js +384 -42
  7. package/dist/WorkerInit.js +122 -43
  8. package/dist/WorkerMetrics.js +5 -1
  9. package/dist/WorkerRegistry.js +8 -0
  10. package/dist/WorkerShutdown.d.ts +0 -13
  11. package/dist/WorkerShutdown.js +1 -44
  12. package/dist/build-manifest.json +99 -83
  13. package/dist/config/workerConfig.d.ts +1 -0
  14. package/dist/config/workerConfig.js +7 -1
  15. package/dist/createQueueWorker.js +281 -42
  16. package/dist/dashboard/workers-api.js +8 -1
  17. package/dist/http/WorkerController.js +90 -35
  18. package/dist/http/WorkerMonitoringService.js +29 -2
  19. package/dist/index.d.ts +1 -2
  20. package/dist/index.js +0 -1
  21. package/dist/routes/workers.js +10 -7
  22. package/dist/storage/WorkerStore.d.ts +6 -3
  23. package/dist/storage/WorkerStore.js +16 -0
  24. package/dist/telemetry/api/TelemetryMonitoringService.js +29 -2
  25. package/dist/ui/router/ui.js +58 -29
  26. package/dist/ui/workers/index.html +202 -0
  27. package/dist/ui/workers/main.js +1952 -0
  28. package/dist/ui/workers/styles.css +1350 -0
  29. package/dist/ui/workers/zintrust.svg +30 -0
  30. package/package.json +5 -5
  31. package/src/ClusterLock.ts +13 -7
  32. package/src/ComplianceManager.ts +3 -2
  33. package/src/DeadLetterQueue.ts +6 -4
  34. package/src/HealthMonitor.ts +33 -17
  35. package/src/Observability.ts +11 -0
  36. package/src/WorkerFactory.ts +446 -43
  37. package/src/WorkerInit.ts +167 -48
  38. package/src/WorkerMetrics.ts +14 -8
  39. package/src/WorkerRegistry.ts +11 -0
  40. package/src/WorkerShutdown.ts +1 -69
  41. package/src/config/workerConfig.ts +9 -1
  42. package/src/createQueueWorker.ts +428 -43
  43. package/src/dashboard/workers-api.ts +8 -1
  44. package/src/http/WorkerController.ts +111 -36
  45. package/src/http/WorkerMonitoringService.ts +35 -2
  46. package/src/index.ts +2 -3
  47. package/src/routes/workers.ts +10 -8
  48. package/src/storage/WorkerStore.ts +21 -3
  49. package/src/telemetry/api/TelemetryMonitoringService.ts +35 -2
  50. package/src/types/queue-monitor.d.ts +2 -1
  51. package/src/ui/router/EmbeddedAssets.ts +3 -0
  52. package/src/ui/router/ui.ts +57 -39
  53. package/src/WorkerShutdownDurableObject.ts +0 -64
@@ -1,15 +1,14 @@
1
1
  import type { AssetsBinding, IRouter } from '@zintrust/core';
2
- import {
3
- Cloudflare,
4
- Logger,
5
- MIME_TYPES,
6
- NodeSingletons,
7
- Router,
8
- detectRuntime,
9
- } from '@zintrust/core';
2
+ import { Cloudflare, Logger, MIME_TYPES, NodeSingletons, Router } from '@zintrust/core';
10
3
  import { INDEX_HTML, MAIN_JS, STYLES_CSS, ZINTRUST_SVG } from './EmbeddedAssets';
11
4
 
12
- const isCloudflare = detectRuntime().isCloudflare;
5
+ const isCloudflare = ((): boolean => {
6
+ try {
7
+ return Cloudflare.getWorkersEnv() !== null;
8
+ } catch {
9
+ return false;
10
+ }
11
+ })();
13
12
 
14
13
  const safeFileUrlToPath = (url: string | undefined): string => {
15
14
  if (typeof url !== 'string' || url.trim() === '') return '';
@@ -51,6 +50,30 @@ const fetchAssetBytes = async (assetPath: string): Promise<Uint8Array | null> =>
51
50
  return new Uint8Array(buffer);
52
51
  };
53
52
 
53
+ const resolveEmbeddedAssetText = (assetPath: string): string | null => {
54
+ const normalizedPath = assetPath.replace(/^\//, '');
55
+ if (normalizedPath === 'workers/index.html') {
56
+ return Buffer.from(INDEX_HTML, 'base64').toString('utf-8');
57
+ }
58
+
59
+ return null;
60
+ };
61
+
62
+ const resolveEmbeddedAssetBytes = (assetPath: string): Uint8Array | null => {
63
+ const normalizedPath = assetPath.replace(/^\//, '');
64
+ if (normalizedPath === 'workers/styles.css') {
65
+ return Buffer.from(STYLES_CSS, 'base64');
66
+ }
67
+ if (normalizedPath === 'workers/main.js') {
68
+ return Buffer.from(MAIN_JS, 'base64');
69
+ }
70
+ if (normalizedPath === 'workers/zintrust.svg') {
71
+ return Buffer.from(ZINTRUST_SVG, 'base64');
72
+ }
73
+
74
+ return null;
75
+ };
76
+
54
77
  export const uiResolver = async (uiBasePath: string): Promise<string> => {
55
78
  // Resolve base path for UI assets
56
79
  // const __filename = NodeSingletons.url.fileURLToPath(import.meta.url);
@@ -58,14 +81,15 @@ export const uiResolver = async (uiBasePath: string): Promise<string> => {
58
81
  const assetHtml = await fetchAssetText('/workers/index.html');
59
82
  if (assetHtml !== '') return assetHtml;
60
83
 
61
- if (isCloudflare) {
62
- return Buffer.from(INDEX_HTML, 'base64').toString('utf-8');
63
- }
64
-
65
84
  const uiPath = NodeSingletons.path.resolve(uiBasePath, 'workers/index.html');
66
- const html = await NodeSingletons.fs.readFile(uiPath, 'utf8');
67
85
 
68
- return html;
86
+ try {
87
+ return await NodeSingletons.fs.readFile(uiPath, 'utf8');
88
+ } catch {
89
+ const embedded = resolveEmbeddedAssetText('/workers/index.html');
90
+ if (embedded !== null) return embedded;
91
+ throw Error('workers index.html is unavailable');
92
+ }
69
93
  };
70
94
 
71
95
  // MIME type mapping for static files
@@ -116,6 +140,16 @@ const serveStaticFile = async (
116
140
  setStatus: (code: number) => void;
117
141
  }
118
142
  ): Promise<void> => {
143
+ const tryServeEmbedded = (assetPath: string): boolean => {
144
+ const bytes = resolveEmbeddedAssetBytes(assetPath);
145
+ if (bytes === null) return false;
146
+ const mimeType = getMimeType(assetPath);
147
+ res.setHeader('Content-Type', mimeType);
148
+ res.setHeader('Cache-Control', 'public, max-age=3600');
149
+ res.send(Buffer.from(bytes));
150
+ return true;
151
+ };
152
+
119
153
  try {
120
154
  const filePath = req.getPath();
121
155
  const assetBytes = await fetchAssetBytes(filePath);
@@ -128,29 +162,7 @@ const serveStaticFile = async (
128
162
  }
129
163
 
130
164
  if (isCloudflare) {
131
- const normalizedPath = filePath.replace(/^\//, '');
132
- if (normalizedPath === 'workers/styles.css') {
133
- const mimeType = MIME_TYPES.CSS;
134
- res.setHeader('Content-Type', mimeType);
135
- res.setHeader('Cache-Control', 'public, max-age=3600');
136
- res.send(Buffer.from(STYLES_CSS, 'base64'));
137
- return;
138
- }
139
- if (normalizedPath === 'workers/main.js') {
140
- const mimeType = MIME_TYPES.JS;
141
- res.setHeader('Content-Type', mimeType);
142
- res.setHeader('Cache-Control', 'public, max-age=3600');
143
- res.send(Buffer.from(MAIN_JS, 'base64'));
144
- return;
145
- }
146
- if (normalizedPath === 'workers/zintrust.svg') {
147
- const mimeType = MIME_TYPES.SVG;
148
- res.setHeader('Content-Type', mimeType);
149
- res.setHeader('Cache-Control', 'public, max-age=3600');
150
- res.send(Buffer.from(ZINTRUST_SVG, 'base64'));
151
- return;
152
- }
153
-
165
+ if (tryServeEmbedded(filePath)) return;
154
166
  res.setStatus(404);
155
167
  res.send(Buffer.from('Not Found'));
156
168
  return;
@@ -165,7 +177,13 @@ const serveStaticFile = async (
165
177
  return;
166
178
  }
167
179
 
168
- const content = await NodeSingletons.fs.readFile(fullPath);
180
+ let content: Buffer;
181
+ try {
182
+ content = await NodeSingletons.fs.readFile(fullPath);
183
+ } catch {
184
+ if (tryServeEmbedded(filePath)) return;
185
+ throw Error(`Missing static asset: ${filePath}`);
186
+ }
169
187
  const mimeType = getMimeType(filePath);
170
188
 
171
189
  res.setHeader('Content-Type', mimeType);
@@ -1,64 +0,0 @@
1
- import { Logger } from '@zintrust/core';
2
-
3
- type DurableObjectState = {
4
- storage: {
5
- get: (key: string) => Promise<unknown>;
6
- put: (key: string, value: unknown) => Promise<void>;
7
- };
8
- };
9
-
10
- type ShutdownState = {
11
- shuttingDown: boolean;
12
- startedAt?: string;
13
- reason?: string;
14
- };
15
-
16
- const loadState = async (state: DurableObjectState): Promise<ShutdownState> => {
17
- const stored = (await state.storage.get('shutdown')) as ShutdownState | undefined;
18
- return stored ?? { shuttingDown: false };
19
- };
20
-
21
- const saveState = async (state: DurableObjectState, value: ShutdownState): Promise<void> => {
22
- await state.storage.put('shutdown', value);
23
- };
24
-
25
- // eslint-disable-next-line no-restricted-syntax
26
- export class ZinTrustWorkerShutdownDurableObject {
27
- private readonly state: DurableObjectState;
28
-
29
- constructor(state: DurableObjectState) {
30
- this.state = state;
31
- }
32
-
33
- async fetch(request: Request): Promise<Response> {
34
- const url = new URL(request.url);
35
- const path = url.pathname;
36
-
37
- if (request.method === 'GET' && path === '/status') {
38
- const current = await loadState(this.state);
39
- return new Response(JSON.stringify(current), {
40
- status: 200,
41
- headers: { 'content-type': 'application/json' },
42
- });
43
- }
44
-
45
- if (request.method === 'POST' && path === '/shutdown') {
46
- const payload = (await request.json().catch(() => ({}))) as { reason?: string };
47
- const next: ShutdownState = {
48
- shuttingDown: true,
49
- startedAt: new Date().toISOString(),
50
- reason: payload.reason ?? 'manual',
51
- };
52
-
53
- await saveState(this.state, next);
54
- Logger.info('Worker shutdown requested via Durable Object', next);
55
-
56
- return new Response(JSON.stringify({ ok: true }), {
57
- status: 202,
58
- headers: { 'content-type': 'application/json' },
59
- });
60
- }
61
-
62
- return new Response('Not Found', { status: 404 });
63
- }
64
- }