@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.
- package/dist/ClusterLock.js +3 -2
- package/dist/DeadLetterQueue.js +3 -2
- package/dist/HealthMonitor.js +24 -13
- package/dist/Observability.js +8 -0
- package/dist/WorkerFactory.d.ts +4 -0
- package/dist/WorkerFactory.js +384 -42
- package/dist/WorkerInit.js +122 -43
- package/dist/WorkerMetrics.js +5 -1
- package/dist/WorkerRegistry.js +8 -0
- package/dist/WorkerShutdown.d.ts +0 -13
- package/dist/WorkerShutdown.js +1 -44
- package/dist/build-manifest.json +99 -83
- package/dist/config/workerConfig.d.ts +1 -0
- package/dist/config/workerConfig.js +7 -1
- package/dist/createQueueWorker.js +281 -42
- package/dist/dashboard/workers-api.js +8 -1
- package/dist/http/WorkerController.js +90 -35
- package/dist/http/WorkerMonitoringService.js +29 -2
- package/dist/index.d.ts +1 -2
- package/dist/index.js +0 -1
- package/dist/routes/workers.js +10 -7
- package/dist/storage/WorkerStore.d.ts +6 -3
- package/dist/storage/WorkerStore.js +16 -0
- package/dist/telemetry/api/TelemetryMonitoringService.js +29 -2
- package/dist/ui/router/ui.js +58 -29
- package/dist/ui/workers/index.html +202 -0
- package/dist/ui/workers/main.js +1952 -0
- package/dist/ui/workers/styles.css +1350 -0
- package/dist/ui/workers/zintrust.svg +30 -0
- package/package.json +5 -5
- package/src/ClusterLock.ts +13 -7
- package/src/ComplianceManager.ts +3 -2
- package/src/DeadLetterQueue.ts +6 -4
- package/src/HealthMonitor.ts +33 -17
- package/src/Observability.ts +11 -0
- package/src/WorkerFactory.ts +446 -43
- package/src/WorkerInit.ts +167 -48
- package/src/WorkerMetrics.ts +14 -8
- package/src/WorkerRegistry.ts +11 -0
- package/src/WorkerShutdown.ts +1 -69
- package/src/config/workerConfig.ts +9 -1
- package/src/createQueueWorker.ts +428 -43
- package/src/dashboard/workers-api.ts +8 -1
- package/src/http/WorkerController.ts +111 -36
- package/src/http/WorkerMonitoringService.ts +35 -2
- package/src/index.ts +2 -3
- package/src/routes/workers.ts +10 -8
- package/src/storage/WorkerStore.ts +21 -3
- package/src/telemetry/api/TelemetryMonitoringService.ts +35 -2
- package/src/types/queue-monitor.d.ts +2 -1
- package/src/ui/router/EmbeddedAssets.ts +3 -0
- package/src/ui/router/ui.ts +57 -39
- package/src/WorkerShutdownDurableObject.ts +0 -64
package/src/ui/router/ui.ts
CHANGED
|
@@ -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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
}
|