@morojs/moro 1.8.2 → 1.8.4
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/core/config/config-sources.js.map +1 -1
- package/dist/core/framework.d.ts +11 -0
- package/dist/core/framework.js +107 -36
- package/dist/core/framework.js.map +1 -1
- package/dist/core/graphql/core.js.map +1 -1
- package/dist/core/grpc/types.js.map +1 -1
- package/dist/core/http/moro-engine-server.js.map +1 -1
- package/dist/core/mail/mail-adapter.js.map +1 -1
- package/dist/core/middleware/built-in/cloudwatch/index.d.ts +4 -0
- package/dist/core/middleware/built-in/cloudwatch/index.js +5 -0
- package/dist/core/middleware/built-in/cloudwatch/index.js.map +1 -0
- package/dist/core/middleware/built-in/cloudwatch/middleware.d.ts +31 -0
- package/dist/core/middleware/built-in/cloudwatch/middleware.js +52 -0
- package/dist/core/middleware/built-in/cloudwatch/middleware.js.map +1 -0
- package/dist/core/middleware/built-in/error-tracker/index.d.ts +3 -1
- package/dist/core/middleware/built-in/error-tracker/index.js +3 -2
- package/dist/core/middleware/built-in/error-tracker/index.js.map +1 -1
- package/dist/core/middleware/built-in/error-tracker/middleware.d.ts +6 -3
- package/dist/core/middleware/built-in/error-tracker/middleware.js +18 -13
- package/dist/core/middleware/built-in/error-tracker/middleware.js.map +1 -1
- package/dist/core/middleware/built-in/index.d.ts +43 -7
- package/dist/core/middleware/built-in/index.js +37 -7
- package/dist/core/middleware/built-in/index.js.map +1 -1
- package/dist/core/middleware/built-in/performance-monitor/index.d.ts +3 -1
- package/dist/core/middleware/built-in/performance-monitor/index.js +3 -2
- package/dist/core/middleware/built-in/performance-monitor/index.js.map +1 -1
- package/dist/core/middleware/built-in/performance-monitor/middleware.d.ts +3 -3
- package/dist/core/middleware/built-in/performance-monitor/middleware.js +19 -17
- package/dist/core/middleware/built-in/performance-monitor/middleware.js.map +1 -1
- package/dist/core/middleware/built-in/prometheus/core.d.ts +27 -0
- package/dist/core/middleware/built-in/prometheus/core.js +0 -0
- package/dist/core/middleware/built-in/prometheus/core.js.map +1 -0
- package/dist/core/middleware/built-in/prometheus/index.d.ts +5 -0
- package/dist/core/middleware/built-in/prometheus/index.js +6 -0
- package/dist/core/middleware/built-in/prometheus/index.js.map +1 -0
- package/dist/core/middleware/built-in/prometheus/middleware.d.ts +15 -0
- package/dist/core/middleware/built-in/prometheus/middleware.js +30 -0
- package/dist/core/middleware/built-in/prometheus/middleware.js.map +1 -0
- package/dist/core/middleware/built-in/request-logger/index.d.ts +3 -1
- package/dist/core/middleware/built-in/request-logger/index.js +3 -2
- package/dist/core/middleware/built-in/request-logger/index.js.map +1 -1
- package/dist/core/middleware/built-in/request-logger/middleware.d.ts +4 -4
- package/dist/core/middleware/built-in/request-logger/middleware.js +14 -12
- package/dist/core/middleware/built-in/request-logger/middleware.js.map +1 -1
- package/dist/core/middleware/index.d.ts +1 -1
- package/dist/core/middleware/index.js +1 -1
- package/dist/core/middleware/index.js.map +1 -1
- package/dist/core/pooling/index.d.ts +3 -0
- package/dist/core/pooling/index.js +5 -0
- package/dist/core/pooling/index.js.map +1 -0
- package/dist/core/pooling/lru-cache.d.ts +32 -0
- package/dist/core/pooling/lru-cache.js +74 -0
- package/dist/core/pooling/lru-cache.js.map +1 -0
- package/dist/core/pooling/object-pool-manager.d.ts +3 -1
- package/dist/core/pooling/object-pool-manager.js +37 -140
- package/dist/core/pooling/object-pool-manager.js.map +1 -1
- package/dist/core/pooling/object-pool.d.ts +42 -0
- package/dist/core/pooling/object-pool.js +78 -0
- package/dist/core/pooling/object-pool.js.map +1 -0
- package/dist/core/routing/create-router.js.map +1 -1
- package/dist/core/routing/path-matcher.js +1 -43
- package/dist/core/routing/path-matcher.js.map +1 -1
- package/dist/core/utilities/hooks.d.ts +0 -1
- package/dist/core/utilities/hooks.js +0 -2
- package/dist/core/utilities/hooks.js.map +1 -1
- package/dist/core/utilities/index.d.ts +0 -1
- package/dist/core/utilities/index.js +0 -2
- package/dist/core/utilities/index.js.map +1 -1
- package/dist/core/utilities/package-utils.js +7 -0
- package/dist/core/utilities/package-utils.js.map +1 -1
- package/dist/core/utilities/self-require.d.ts +2 -0
- package/dist/core/utilities/self-require.js +13 -0
- package/dist/core/utilities/self-require.js.map +1 -0
- package/dist/core/workers/facade.d.ts +20 -4
- package/dist/core/workers/facade.js +15 -7
- package/dist/core/workers/facade.js.map +1 -1
- package/dist/core/workers/worker-manager.d.ts +12 -0
- package/dist/core/workers/worker-manager.js +27 -0
- package/dist/core/workers/worker-manager.js.map +1 -1
- package/dist/core/workers/worker.d.ts +17 -1
- package/dist/core/workers/worker.js +28 -26
- package/dist/core/workers/worker.js.map +1 -1
- package/dist/index.d.ts +39 -2
- package/dist/index.js +14 -2
- package/dist/index.js.map +1 -1
- package/dist/moro.js +25 -1
- package/dist/moro.js.map +1 -1
- package/dist/types/config.js.map +1 -1
- package/dist/types/core.d.ts +1 -0
- package/dist/types/core.js.map +1 -1
- package/dist/types/module.js.map +1 -1
- package/package.json +3 -3
|
@@ -4,6 +4,7 @@ import { createRequire } from 'module';
|
|
|
4
4
|
import { dirname, join } from 'path';
|
|
5
5
|
import { existsSync, realpathSync } from 'fs';
|
|
6
6
|
import { pathToFileURL } from 'url';
|
|
7
|
+
import { selfRequire } from './self-require.js';
|
|
7
8
|
/**
|
|
8
9
|
* Check if a package is available in the user's node_modules
|
|
9
10
|
* Uses ESM-compatible module resolution from the user's working directory
|
|
@@ -119,6 +120,12 @@ let engineLoadErrors = [];
|
|
|
119
120
|
* Inside the framework repo itself (tests, examples) cwd is the framework dir.
|
|
120
121
|
*/
|
|
121
122
|
function findFrameworkAnchor() {
|
|
123
|
+
// Primary: anchor to moro's OWN compiled location, so moro's `@morojs/engine`
|
|
124
|
+
// dependency resolves relative to where moro is installed regardless of
|
|
125
|
+
// `process.cwd()` (Docker WORKDIR, supervisord, pm2, a subdirectory, …). The
|
|
126
|
+
// cwd-based walk below is a defensive fallback for exotic layouts.
|
|
127
|
+
if (selfRequire)
|
|
128
|
+
return selfRequire;
|
|
122
129
|
try {
|
|
123
130
|
const cwdPackageJson = join(process.cwd(), 'package.json');
|
|
124
131
|
if (existsSync(cwdPackageJson)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"package-utils.js","sourceRoot":"","sources":["../../../src/core/utilities/package-utils.ts"],"names":[],"mappings":"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","sourcesContent":["// Package and Module Resolution Utilities\n// ESM-compatible helpers for detecting and resolving optional dependencies\n\nimport { createRequire } from 'module';\nimport { dirname, join } from 'path';\nimport { existsSync, realpathSync } from 'fs';\nimport { pathToFileURL } from 'url';\n\n/**\n * Check if a package is available in the user's node_modules\n * Uses ESM-compatible module resolution from the user's working directory\n *\n * @param packageName - The name of the package to check (e.g., 'socket.io', 'zod')\n * @returns true if the package is installed, false otherwise\n *\n * @example\n * if (isPackageAvailable('socket.io')) {\n * // socket.io is installed, safe to import\n * const { Server } = await import('socket.io');\n * }\n */\nexport function isPackageAvailable(packageName: string): boolean {\n try {\n const userRequire = createRequire(join(process.cwd(), 'package.json'));\n userRequire.resolve(packageName);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Resolve a package path from the user's node_modules\n * Uses ESM-compatible module resolution from the user's working directory\n *\n * @param packageName - The name of the package to resolve\n * @returns The resolved package path\n * @throws Error if the package is not found\n *\n * @example\n * const socketIOPath = resolveUserPackage('socket.io');\n * const { Server } = await import(socketIOPath);\n */\nexport function resolveUserPackage(packageName: string): string {\n const userRequire = createRequire(join(process.cwd(), 'package.json'));\n return userRequire.resolve(packageName);\n}\n\n/**\n * Create a require function for the user's working directory\n * Useful for resolving packages installed by the user, not in Moro's dependencies\n *\n * @returns A require function scoped to the user's working directory\n *\n * @example\n * const userRequire = createUserRequire();\n * const packagePath = userRequire.resolve('some-package');\n */\nexport function createUserRequire() {\n return createRequire(join(process.cwd(), 'package.json'));\n}\n\n// ---------------------------------------------------------------------------\n// Native HTTP engine loading\n// ---------------------------------------------------------------------------\n\n/**\n * Package names probed for the native HTTP engine, in priority order.\n * '@morojs/engine' is Moro's own engine (installed as an optionalDependency of\n * the framework); 'uWebSockets.js' is honored as a legacy user-installed peer.\n */\nexport const NATIVE_ENGINE_PACKAGES = ['@morojs/engine', 'uWebSockets.js'] as const;\n\nconst FRAMEWORK_PACKAGE_NAME = '@morojs/moro';\n\n/** Feature flags the framework gates option-passing on, so it never hands a\n * serve() option to an engine build that predates it. Everything defaults\n * false, so an older engine behaves exactly as it did before these existed. */\nexport interface EngineCapabilities {\n /** The full serve() limit surface is parsed (engine >= 1.1.0). */\n limits: boolean;\n /** In-process TLS termination via options.ssl (engine >= 1.2.0). */\n tls: boolean;\n /** ALPN HTTP/2 via options.http2 (engine >= 1.4.0). */\n http2: boolean;\n /** WebSocket permessage-deflate via options.wsDeflate (engine >= 1.5.0). */\n wsDeflate: boolean;\n}\n\nexport interface NativeEngineLoadResult {\n /** The loaded engine module (CJS namespace: App, SSLApp, ...) */\n module: any;\n /** Which package satisfied the load */\n source: string;\n /** The engine package's version, when its package.json is resolvable */\n version?: string;\n /** Feature flags (Moro-shaped engine only; all-false for uWS or an\n * engine too old to advertise them). */\n capabilities?: EngineCapabilities;\n}\n\nconst NO_CAPABILITIES: EngineCapabilities = {\n limits: false,\n tls: false,\n http2: false,\n wsDeflate: false,\n};\n\nconst capabilitiesCache = new WeakMap<object, EngineCapabilities>();\n\n/**\n * Feature-detect a loaded engine module. Reads probe().capabilities when the\n * engine exposes it (>= 1.1.0); otherwise everything is false so the framework\n * passes only the options an older engine understood. uWS-style modules (no\n * probe/serve) report all-false — their SSL/limits go through the uWS-specific\n * paths, not these flags.\n */\nexport function getEngineCapabilities(module: any): EngineCapabilities {\n const surface = module?.default || module;\n if (!surface || typeof surface !== 'object') return NO_CAPABILITIES;\n const cached = capabilitiesCache.get(surface);\n if (cached) return cached;\n\n let caps: EngineCapabilities = NO_CAPABILITIES;\n try {\n if (typeof surface.probe === 'function') {\n const probe = surface.probe();\n const c = probe?.capabilities;\n if (c && typeof c === 'object') {\n caps = {\n limits: c.limits === true,\n tls: c.tls === true,\n http2: c.http2 === true,\n wsDeflate: c.wsDeflate === true,\n };\n }\n }\n } catch {\n caps = NO_CAPABILITIES;\n }\n capabilitiesCache.set(surface, caps);\n return caps;\n}\n\n// undefined = never attempted, null = attempted and failed\nlet cachedEngine: NativeEngineLoadResult | null | undefined;\nlet engineLoadErrors: string[] = [];\n\n/**\n * Locate the installed framework package directory so the engine (a dependency\n * of moro, not of the user's app) resolves under strict layouts like pnpm's.\n * Walks up from cwd looking for node_modules/@morojs/moro, resolving symlinks\n * so pnpm's store-linked layout anchors requires next to moro's own deps.\n * Inside the framework repo itself (tests, examples) cwd is the framework dir.\n */\nfunction findFrameworkAnchor(): ReturnType<typeof createRequire> | null {\n try {\n const cwdPackageJson = join(process.cwd(), 'package.json');\n if (existsSync(cwdPackageJson)) {\n const require = createRequire(cwdPackageJson);\n const name = require(cwdPackageJson)?.name;\n if (name === FRAMEWORK_PACKAGE_NAME) {\n return require;\n }\n }\n } catch {\n // fall through to the node_modules walk\n }\n\n let dir = process.cwd();\n for (;;) {\n const packageJson = join(dir, 'node_modules', '@morojs', 'moro', 'package.json');\n try {\n if (existsSync(packageJson)) {\n return createRequire(join(realpathSync(dirname(packageJson)), 'package.json'));\n }\n } catch {\n // unreadable/broken link - keep walking up\n }\n const parent = dirname(dir);\n if (parent === dir) return null;\n dir = parent;\n }\n}\n\n/**\n * Synchronously load the native HTTP engine, trying '@morojs/engine' first and\n * falling back to a user-installed 'uWebSockets.js'. Loading is require-based\n * (both packages are CJS at their core - .node addon loading is require-based),\n * so the instance is shared with any later import() via the CJS module cache.\n *\n * The default call is memoized: the engine either loads once per process or it\n * doesn't. Failure details are retained for logging via\n * getNativeEngineLoadErrors().\n *\n * @param options.candidates - Override the probed package names (testing).\n * When provided, the call bypasses the cache.\n * @returns The loaded engine and its source package, or null if none loads\n */\nexport function loadNativeEngine(options?: {\n candidates?: readonly string[];\n /** When provided, every per-attempt failure message is appended here, so a\n * candidate-override caller (which bypasses the memoized diagnostics) can\n * still report exactly WHY the engine didn't load — not just \"not installed\". */\n collectErrors?: string[];\n}): NativeEngineLoadResult | null {\n const useCache = !options?.candidates;\n if (useCache && cachedEngine !== undefined) {\n if (options?.collectErrors && !cachedEngine) {\n options.collectErrors.push(...engineLoadErrors);\n }\n return cachedEngine;\n }\n\n const candidates = options?.candidates ?? NATIVE_ENGINE_PACKAGES;\n const errors: string[] = [];\n let result: NativeEngineLoadResult | null = null;\n\n const frameworkRequire = findFrameworkAnchor();\n const userRequire = createUserRequire();\n\n for (const candidate of candidates) {\n // Moro's own engine lives in moro's dependencies (framework anchor first);\n // the legacy uWS peer dep lives in the user's node_modules (cwd first).\n const anchors =\n candidate === 'uWebSockets.js'\n ? [userRequire, frameworkRequire]\n : [frameworkRequire, userRequire];\n\n for (const anchor of anchors) {\n if (!anchor) continue;\n try {\n const module = anchor(candidate);\n // Capability check: the HTTP server needs either a uWS-style App()\n // factory or the Moro-shaped engine surface (serve()/respond()).\n // A package that loads but can't serve (e.g. a pre-M1 @morojs/engine\n // that only exposes probe()) must not shadow a usable alternative.\n const surface = module?.default || module;\n const uwsStyle = typeof surface?.App === 'function';\n const moroStyle =\n !uwsStyle &&\n typeof surface?.serve === 'function' &&\n typeof surface?.respond === 'function';\n if (!uwsStyle && !moroStyle) {\n errors.push(\n `${candidate}: loaded but provides neither App() nor serve()/respond() - not a usable HTTP engine`\n );\n continue;\n }\n let version: string | undefined;\n try {\n // May be blocked by the package's exports map - version is optional\n version = anchor(`${candidate}/package.json`)?.version;\n } catch {\n version = undefined;\n }\n result = {\n module,\n source: candidate,\n ...(version !== undefined ? { version } : {}),\n capabilities: moroStyle ? getEngineCapabilities(module) : NO_CAPABILITIES,\n };\n break;\n } catch (error) {\n const message = error instanceof Error ? error.message.split('\\n')[0] : String(error);\n errors.push(`${candidate}: ${message}`);\n }\n }\n if (result) break;\n }\n\n // Candidate-override probes (e.g. the clustering worker's uWS-only check)\n // must not clobber the diagnostics of the real default load, which\n // framework startup logging reads via getNativeEngineLoadErrors().\n if (useCache) {\n engineLoadErrors = result ? [] : [...new Set(errors)];\n cachedEngine = result;\n }\n // Hand this specific call's failure detail back to a caller that asked for it,\n // regardless of caching (so 'moro'/'uws' fallback reasons are precise).\n if (options?.collectErrors && !result) {\n options.collectErrors.push(...new Set(errors));\n }\n return result;\n}\n\n/**\n * Failure details from the most recent unsuccessful loadNativeEngine() call,\n * one entry per package/anchor attempt. Empty after a successful load.\n */\nexport function getNativeEngineLoadErrors(): readonly string[] {\n return engineLoadErrors;\n}\n\n/**\n * Clear the memoized engine load result. Testing only.\n */\nexport function resetNativeEngineLoaderForTesting(): void {\n cachedEngine = undefined;\n engineLoadErrors = [];\n}\n\n/**\n * Convert a file path to a file URL for ESM dynamic imports\n * This is required on Windows where absolute paths like C:\\path\\to\\module\n * need to be converted to file:/// URLs for dynamic import() to work\n *\n * @param filePath - The file path to convert (absolute or relative)\n * @returns A proper URL string for ESM import() that works cross-platform\n *\n * @example\n * const modulePath = 'C:\\\\Users\\\\project\\\\module.js';\n * const module = await import(filePathToImportURL(modulePath));\n */\nexport function filePathToImportURL(filePath: string): string {\n if (!filePath) {\n return filePath;\n }\n\n // If it's already a URL (starts with file:// or http(s)://), return as-is\n if (\n filePath.startsWith('file://') ||\n filePath.startsWith('http://') ||\n filePath.startsWith('https://')\n ) {\n return filePath;\n }\n\n // Check if it's a Windows absolute path (C:\\ or C:/)\n const windowsAbsolutePathRegex = /^[A-Za-z]:[\\\\//]/;\n const isWindowsAbsolute = windowsAbsolutePathRegex.test(filePath);\n\n // Check if it's a Unix absolute path (starts with /)\n const isUnixAbsolute = filePath.startsWith('/');\n\n // Check if it's a Windows UNC path (\\\\server\\share)\n const isWindowsUNC = filePath.startsWith('\\\\\\\\');\n\n // Convert absolute paths to file URLs\n if (isWindowsAbsolute || isUnixAbsolute || isWindowsUNC) {\n return pathToFileURL(filePath).href;\n }\n\n // For relative paths, return as-is (they work in import())\n return filePath;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"package-utils.js","sourceRoot":"","sources":["../../../src/core/utilities/package-utils.ts"],"names":[],"mappings":"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","sourcesContent":["// Package and Module Resolution Utilities\n// ESM-compatible helpers for detecting and resolving optional dependencies\n\nimport { createRequire } from 'module';\nimport { dirname, join } from 'path';\nimport { existsSync, realpathSync } from 'fs';\nimport { pathToFileURL } from 'url';\nimport { selfRequire } from './self-require.js';\n\n/**\n * Check if a package is available in the user's node_modules\n * Uses ESM-compatible module resolution from the user's working directory\n *\n * @param packageName - The name of the package to check (e.g., 'socket.io', 'zod')\n * @returns true if the package is installed, false otherwise\n *\n * @example\n * if (isPackageAvailable('socket.io')) {\n * // socket.io is installed, safe to import\n * const { Server } = await import('socket.io');\n * }\n */\nexport function isPackageAvailable(packageName: string): boolean {\n try {\n const userRequire = createRequire(join(process.cwd(), 'package.json'));\n userRequire.resolve(packageName);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Resolve a package path from the user's node_modules\n * Uses ESM-compatible module resolution from the user's working directory\n *\n * @param packageName - The name of the package to resolve\n * @returns The resolved package path\n * @throws Error if the package is not found\n *\n * @example\n * const socketIOPath = resolveUserPackage('socket.io');\n * const { Server } = await import(socketIOPath);\n */\nexport function resolveUserPackage(packageName: string): string {\n const userRequire = createRequire(join(process.cwd(), 'package.json'));\n return userRequire.resolve(packageName);\n}\n\n/**\n * Create a require function for the user's working directory\n * Useful for resolving packages installed by the user, not in Moro's dependencies\n *\n * @returns A require function scoped to the user's working directory\n *\n * @example\n * const userRequire = createUserRequire();\n * const packagePath = userRequire.resolve('some-package');\n */\nexport function createUserRequire() {\n return createRequire(join(process.cwd(), 'package.json'));\n}\n\n// ---------------------------------------------------------------------------\n// Native HTTP engine loading\n// ---------------------------------------------------------------------------\n\n/**\n * Package names probed for the native HTTP engine, in priority order.\n * '@morojs/engine' is Moro's own engine (installed as an optionalDependency of\n * the framework); 'uWebSockets.js' is honored as a legacy user-installed peer.\n */\nexport const NATIVE_ENGINE_PACKAGES = ['@morojs/engine', 'uWebSockets.js'] as const;\n\nconst FRAMEWORK_PACKAGE_NAME = '@morojs/moro';\n\n/** Feature flags the framework gates option-passing on, so it never hands a\n * serve() option to an engine build that predates it. Everything defaults\n * false, so an older engine behaves exactly as it did before these existed. */\nexport interface EngineCapabilities {\n /** The full serve() limit surface is parsed (engine >= 1.1.0). */\n limits: boolean;\n /** In-process TLS termination via options.ssl (engine >= 1.2.0). */\n tls: boolean;\n /** ALPN HTTP/2 via options.http2 (engine >= 1.4.0). */\n http2: boolean;\n /** WebSocket permessage-deflate via options.wsDeflate (engine >= 1.5.0). */\n wsDeflate: boolean;\n}\n\nexport interface NativeEngineLoadResult {\n /** The loaded engine module (CJS namespace: App, SSLApp, ...) */\n module: any;\n /** Which package satisfied the load */\n source: string;\n /** The engine package's version, when its package.json is resolvable */\n version?: string;\n /** Feature flags (Moro-shaped engine only; all-false for uWS or an\n * engine too old to advertise them). */\n capabilities?: EngineCapabilities;\n}\n\nconst NO_CAPABILITIES: EngineCapabilities = {\n limits: false,\n tls: false,\n http2: false,\n wsDeflate: false,\n};\n\nconst capabilitiesCache = new WeakMap<object, EngineCapabilities>();\n\n/**\n * Feature-detect a loaded engine module. Reads probe().capabilities when the\n * engine exposes it (>= 1.1.0); otherwise everything is false so the framework\n * passes only the options an older engine understood. uWS-style modules (no\n * probe/serve) report all-false — their SSL/limits go through the uWS-specific\n * paths, not these flags.\n */\nexport function getEngineCapabilities(module: any): EngineCapabilities {\n const surface = module?.default || module;\n if (!surface || typeof surface !== 'object') return NO_CAPABILITIES;\n const cached = capabilitiesCache.get(surface);\n if (cached) return cached;\n\n let caps: EngineCapabilities = NO_CAPABILITIES;\n try {\n if (typeof surface.probe === 'function') {\n const probe = surface.probe();\n const c = probe?.capabilities;\n if (c && typeof c === 'object') {\n caps = {\n limits: c.limits === true,\n tls: c.tls === true,\n http2: c.http2 === true,\n wsDeflate: c.wsDeflate === true,\n };\n }\n }\n } catch {\n caps = NO_CAPABILITIES;\n }\n capabilitiesCache.set(surface, caps);\n return caps;\n}\n\n// undefined = never attempted, null = attempted and failed\nlet cachedEngine: NativeEngineLoadResult | null | undefined;\nlet engineLoadErrors: string[] = [];\n\n/**\n * Locate the installed framework package directory so the engine (a dependency\n * of moro, not of the user's app) resolves under strict layouts like pnpm's.\n * Walks up from cwd looking for node_modules/@morojs/moro, resolving symlinks\n * so pnpm's store-linked layout anchors requires next to moro's own deps.\n * Inside the framework repo itself (tests, examples) cwd is the framework dir.\n */\nfunction findFrameworkAnchor(): ReturnType<typeof createRequire> | null {\n // Primary: anchor to moro's OWN compiled location, so moro's `@morojs/engine`\n // dependency resolves relative to where moro is installed regardless of\n // `process.cwd()` (Docker WORKDIR, supervisord, pm2, a subdirectory, …). The\n // cwd-based walk below is a defensive fallback for exotic layouts.\n if (selfRequire) return selfRequire;\n\n try {\n const cwdPackageJson = join(process.cwd(), 'package.json');\n if (existsSync(cwdPackageJson)) {\n const require = createRequire(cwdPackageJson);\n const name = require(cwdPackageJson)?.name;\n if (name === FRAMEWORK_PACKAGE_NAME) {\n return require;\n }\n }\n } catch {\n // fall through to the node_modules walk\n }\n\n let dir = process.cwd();\n for (;;) {\n const packageJson = join(dir, 'node_modules', '@morojs', 'moro', 'package.json');\n try {\n if (existsSync(packageJson)) {\n return createRequire(join(realpathSync(dirname(packageJson)), 'package.json'));\n }\n } catch {\n // unreadable/broken link - keep walking up\n }\n const parent = dirname(dir);\n if (parent === dir) return null;\n dir = parent;\n }\n}\n\n/**\n * Synchronously load the native HTTP engine, trying '@morojs/engine' first and\n * falling back to a user-installed 'uWebSockets.js'. Loading is require-based\n * (both packages are CJS at their core - .node addon loading is require-based),\n * so the instance is shared with any later import() via the CJS module cache.\n *\n * The default call is memoized: the engine either loads once per process or it\n * doesn't. Failure details are retained for logging via\n * getNativeEngineLoadErrors().\n *\n * @param options.candidates - Override the probed package names (testing).\n * When provided, the call bypasses the cache.\n * @returns The loaded engine and its source package, or null if none loads\n */\nexport function loadNativeEngine(options?: {\n candidates?: readonly string[];\n /** When provided, every per-attempt failure message is appended here, so a\n * candidate-override caller (which bypasses the memoized diagnostics) can\n * still report exactly WHY the engine didn't load — not just \"not installed\". */\n collectErrors?: string[];\n}): NativeEngineLoadResult | null {\n const useCache = !options?.candidates;\n if (useCache && cachedEngine !== undefined) {\n if (options?.collectErrors && !cachedEngine) {\n options.collectErrors.push(...engineLoadErrors);\n }\n return cachedEngine;\n }\n\n const candidates = options?.candidates ?? NATIVE_ENGINE_PACKAGES;\n const errors: string[] = [];\n let result: NativeEngineLoadResult | null = null;\n\n const frameworkRequire = findFrameworkAnchor();\n const userRequire = createUserRequire();\n\n for (const candidate of candidates) {\n // Moro's own engine lives in moro's dependencies (framework anchor first);\n // the legacy uWS peer dep lives in the user's node_modules (cwd first).\n const anchors =\n candidate === 'uWebSockets.js'\n ? [userRequire, frameworkRequire]\n : [frameworkRequire, userRequire];\n\n for (const anchor of anchors) {\n if (!anchor) continue;\n try {\n const module = anchor(candidate);\n // Capability check: the HTTP server needs either a uWS-style App()\n // factory or the Moro-shaped engine surface (serve()/respond()).\n // A package that loads but can't serve (e.g. a pre-M1 @morojs/engine\n // that only exposes probe()) must not shadow a usable alternative.\n const surface = module?.default || module;\n const uwsStyle = typeof surface?.App === 'function';\n const moroStyle =\n !uwsStyle &&\n typeof surface?.serve === 'function' &&\n typeof surface?.respond === 'function';\n if (!uwsStyle && !moroStyle) {\n errors.push(\n `${candidate}: loaded but provides neither App() nor serve()/respond() - not a usable HTTP engine`\n );\n continue;\n }\n let version: string | undefined;\n try {\n // May be blocked by the package's exports map - version is optional\n version = anchor(`${candidate}/package.json`)?.version;\n } catch {\n version = undefined;\n }\n result = {\n module,\n source: candidate,\n ...(version !== undefined ? { version } : {}),\n capabilities: moroStyle ? getEngineCapabilities(module) : NO_CAPABILITIES,\n };\n break;\n } catch (error) {\n const message = error instanceof Error ? error.message.split('\\n')[0] : String(error);\n errors.push(`${candidate}: ${message}`);\n }\n }\n if (result) break;\n }\n\n // Candidate-override probes (e.g. the clustering worker's uWS-only check)\n // must not clobber the diagnostics of the real default load, which\n // framework startup logging reads via getNativeEngineLoadErrors().\n if (useCache) {\n engineLoadErrors = result ? [] : [...new Set(errors)];\n cachedEngine = result;\n }\n // Hand this specific call's failure detail back to a caller that asked for it,\n // regardless of caching (so 'moro'/'uws' fallback reasons are precise).\n if (options?.collectErrors && !result) {\n options.collectErrors.push(...new Set(errors));\n }\n return result;\n}\n\n/**\n * Failure details from the most recent unsuccessful loadNativeEngine() call,\n * one entry per package/anchor attempt. Empty after a successful load.\n */\nexport function getNativeEngineLoadErrors(): readonly string[] {\n return engineLoadErrors;\n}\n\n/**\n * Clear the memoized engine load result. Testing only.\n */\nexport function resetNativeEngineLoaderForTesting(): void {\n cachedEngine = undefined;\n engineLoadErrors = [];\n}\n\n/**\n * Convert a file path to a file URL for ESM dynamic imports\n * This is required on Windows where absolute paths like C:\\path\\to\\module\n * need to be converted to file:/// URLs for dynamic import() to work\n *\n * @param filePath - The file path to convert (absolute or relative)\n * @returns A proper URL string for ESM import() that works cross-platform\n *\n * @example\n * const modulePath = 'C:\\\\Users\\\\project\\\\module.js';\n * const module = await import(filePathToImportURL(modulePath));\n */\nexport function filePathToImportURL(filePath: string): string {\n if (!filePath) {\n return filePath;\n }\n\n // If it's already a URL (starts with file:// or http(s)://), return as-is\n if (\n filePath.startsWith('file://') ||\n filePath.startsWith('http://') ||\n filePath.startsWith('https://')\n ) {\n return filePath;\n }\n\n // Check if it's a Windows absolute path (C:\\ or C:/)\n const windowsAbsolutePathRegex = /^[A-Za-z]:[\\\\//]/;\n const isWindowsAbsolute = windowsAbsolutePathRegex.test(filePath);\n\n // Check if it's a Unix absolute path (starts with /)\n const isUnixAbsolute = filePath.startsWith('/');\n\n // Check if it's a Windows UNC path (\\\\server\\share)\n const isWindowsUNC = filePath.startsWith('\\\\\\\\');\n\n // Convert absolute paths to file URLs\n if (isWindowsAbsolute || isUnixAbsolute || isWindowsUNC) {\n return pathToFileURL(filePath).href;\n }\n\n // For relative paths, return as-is (they work in import())\n return filePath;\n}\n"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// This file exists solely to isolate the ESM-only `import.meta` token (like
|
|
2
|
+
// worker-entry.ts): ts-jest transpiles to CommonJS, where `import.meta` is a
|
|
3
|
+
// load-time SyntaxError, so jest.config maps this module to a stub.
|
|
4
|
+
//
|
|
5
|
+
// `selfRequire` resolves modules relative to moro's OWN compiled location, so
|
|
6
|
+
// moro's `@morojs/engine` dependency loads regardless of `process.cwd()`. Without
|
|
7
|
+
// this, the engine silently falls back to the Node http server whenever the
|
|
8
|
+
// process runs from a directory other than the app root (Docker WORKDIR,
|
|
9
|
+
// supervisord, pm2, a subdirectory, …) — because the resolver walked up from
|
|
10
|
+
// the cwd instead of from where moro is installed.
|
|
11
|
+
import { createRequire } from 'node:module';
|
|
12
|
+
export const selfRequire = createRequire(import.meta.url);
|
|
13
|
+
//# sourceMappingURL=self-require.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"self-require.js","sourceRoot":"","sources":["../../../src/core/utilities/self-require.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,6EAA6E;AAC7E,oEAAoE;AACpE,EAAE;AACF,8EAA8E;AAC9E,kFAAkF;AAClF,4EAA4E;AAC5E,yEAAyE;AACzE,6EAA6E;AAC7E,mDAAmD;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,CAAC,MAAM,WAAW,GAAqC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC","sourcesContent":["// This file exists solely to isolate the ESM-only `import.meta` token (like\n// worker-entry.ts): ts-jest transpiles to CommonJS, where `import.meta` is a\n// load-time SyntaxError, so jest.config maps this module to a stub.\n//\n// `selfRequire` resolves modules relative to moro's OWN compiled location, so\n// moro's `@morojs/engine` dependency loads regardless of `process.cwd()`. Without\n// this, the engine silently falls back to the Node http server whenever the\n// process runs from a directory other than the app root (Docker WORKDIR,\n// supervisord, pm2, a subdirectory, …) — because the resolver walked up from\n// the cwd instead of from where moro is installed.\nimport { createRequire } from 'node:module';\n\nexport const selfRequire: ReturnType<typeof createRequire> = createRequire(import.meta.url);\n"]}
|
|
@@ -20,9 +20,19 @@ export interface WorkerHelpers {
|
|
|
20
20
|
verifyJWT(token: string, secret: string, options?: any): Promise<any>;
|
|
21
21
|
signJWT(payload: any, secret: string, options?: any): Promise<string>;
|
|
22
22
|
hash(data: string, algorithm?: string): Promise<string>;
|
|
23
|
+
compress(data: string | Buffer | Uint8Array, options?: {
|
|
24
|
+
format?: 'gzip' | 'deflate' | 'brotli';
|
|
25
|
+
}): Promise<Buffer>;
|
|
26
|
+
decompress(data: Buffer | Uint8Array, options?: {
|
|
27
|
+
format?: 'gzip' | 'deflate' | 'brotli';
|
|
28
|
+
}): Promise<Buffer>;
|
|
23
29
|
heavyComputation(data: any): Promise<any>;
|
|
24
30
|
transformJSON(data: any, transformer: (data: any) => any): Promise<any>;
|
|
25
31
|
}
|
|
32
|
+
export interface WorkerPoolOptions {
|
|
33
|
+
workerCount?: number;
|
|
34
|
+
maxQueueSize?: number;
|
|
35
|
+
}
|
|
26
36
|
/**
|
|
27
37
|
* Worker Threads Facade - Provides clean access to optional worker functionality
|
|
28
38
|
*/
|
|
@@ -32,19 +42,25 @@ export declare class WorkerThreadsFacade {
|
|
|
32
42
|
private executeOnWorker;
|
|
33
43
|
private initialized;
|
|
34
44
|
/**
|
|
35
|
-
* Lazy initialize worker threads
|
|
45
|
+
* Lazy initialize worker threads.
|
|
46
|
+
* Pool options only take effect on the first initialization (the underlying
|
|
47
|
+
* manager is a singleton).
|
|
36
48
|
*/
|
|
37
|
-
ensureInitialized(): Promise<void>;
|
|
49
|
+
ensureInitialized(options?: WorkerPoolOptions): Promise<void>;
|
|
38
50
|
/**
|
|
39
51
|
* Execute a task on worker threads
|
|
40
52
|
*/
|
|
41
53
|
executeTask<T = any>(task: WorkerTask): Promise<T>;
|
|
42
54
|
/**
|
|
43
|
-
* Get worker thread statistics
|
|
55
|
+
* Get worker thread statistics.
|
|
56
|
+
* Returns null when workers were never initialized — observing stats
|
|
57
|
+
* must not spawn a pool.
|
|
44
58
|
*/
|
|
45
59
|
getStats(): Promise<WorkerStats | null>;
|
|
46
60
|
/**
|
|
47
|
-
* Shutdown worker threads
|
|
61
|
+
* Shutdown worker threads.
|
|
62
|
+
* A no-op when workers were never initialized — never spin up a pool
|
|
63
|
+
* just to tear it down.
|
|
48
64
|
*/
|
|
49
65
|
shutdown(): Promise<void>;
|
|
50
66
|
/**
|
|
@@ -9,14 +9,16 @@ export class WorkerThreadsFacade {
|
|
|
9
9
|
executeOnWorker = null;
|
|
10
10
|
initialized = false;
|
|
11
11
|
/**
|
|
12
|
-
* Lazy initialize worker threads
|
|
12
|
+
* Lazy initialize worker threads.
|
|
13
|
+
* Pool options only take effect on the first initialization (the underlying
|
|
14
|
+
* manager is a singleton).
|
|
13
15
|
*/
|
|
14
|
-
async ensureInitialized() {
|
|
16
|
+
async ensureInitialized(options) {
|
|
15
17
|
if (this.initialized)
|
|
16
18
|
return;
|
|
17
19
|
try {
|
|
18
20
|
const workers = await import('./index.js');
|
|
19
|
-
this.workerManager = workers.getWorkerManager();
|
|
21
|
+
this.workerManager = workers.getWorkerManager(options);
|
|
20
22
|
this.workerTasks = workers.workerTasks;
|
|
21
23
|
this.executeOnWorker = workers.executeOnWorker;
|
|
22
24
|
}
|
|
@@ -39,17 +41,23 @@ export class WorkerThreadsFacade {
|
|
|
39
41
|
return this.workerManager.executeTask(task);
|
|
40
42
|
}
|
|
41
43
|
/**
|
|
42
|
-
* Get worker thread statistics
|
|
44
|
+
* Get worker thread statistics.
|
|
45
|
+
* Returns null when workers were never initialized — observing stats
|
|
46
|
+
* must not spawn a pool.
|
|
43
47
|
*/
|
|
44
48
|
async getStats() {
|
|
45
|
-
|
|
49
|
+
if (!this.initialized)
|
|
50
|
+
return null;
|
|
46
51
|
return this.workerManager?.getStats() || null;
|
|
47
52
|
}
|
|
48
53
|
/**
|
|
49
|
-
* Shutdown worker threads
|
|
54
|
+
* Shutdown worker threads.
|
|
55
|
+
* A no-op when workers were never initialized — never spin up a pool
|
|
56
|
+
* just to tear it down.
|
|
50
57
|
*/
|
|
51
58
|
async shutdown() {
|
|
52
|
-
|
|
59
|
+
if (!this.initialized)
|
|
60
|
+
return;
|
|
53
61
|
await this.workerManager?.shutdown();
|
|
54
62
|
}
|
|
55
63
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"facade.js","sourceRoot":"","sources":["../../../src/core/workers/facade.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,oFAAoF;
|
|
1
|
+
{"version":3,"file":"facade.js","sourceRoot":"","sources":["../../../src/core/workers/facade.ts"],"names":[],"mappings":"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","sourcesContent":["// Worker Threads Facade - Clean API for optional worker thread functionality\n// Provides a clean interface that gracefully degrades when workers aren't available\n\nexport interface WorkerTask {\n id: string;\n type: string;\n data: any;\n priority?: 'low' | 'normal' | 'high';\n timeout?: number;\n}\n\nexport interface WorkerStats {\n workerCount: number;\n activeTasks: number;\n queuedTasks: number;\n isShuttingDown: boolean;\n}\n\nexport interface WorkerAPI {\n executeTask<T = any>(task: WorkerTask): Promise<T>;\n getStats(): WorkerStats;\n shutdown(): Promise<void>;\n}\n\nexport interface WorkerHelpers {\n verifyJWT(token: string, secret: string, options?: any): Promise<any>;\n signJWT(payload: any, secret: string, options?: any): Promise<string>;\n hash(data: string, algorithm?: string): Promise<string>;\n compress(\n data: string | Buffer | Uint8Array,\n options?: { format?: 'gzip' | 'deflate' | 'brotli' }\n ): Promise<Buffer>;\n decompress(\n data: Buffer | Uint8Array,\n options?: { format?: 'gzip' | 'deflate' | 'brotli' }\n ): Promise<Buffer>;\n heavyComputation(data: any): Promise<any>;\n transformJSON(data: any, transformer: (data: any) => any): Promise<any>;\n}\n\nexport interface WorkerPoolOptions {\n workerCount?: number;\n maxQueueSize?: number;\n}\n\n/**\n * Worker Threads Facade - Provides clean access to optional worker functionality\n */\nexport class WorkerThreadsFacade {\n private workerManager: WorkerAPI | null = null;\n private workerTasks: WorkerHelpers | null = null;\n private executeOnWorker: ((task: WorkerTask) => Promise<any>) | null = null;\n private initialized = false;\n\n /**\n * Lazy initialize worker threads.\n * Pool options only take effect on the first initialization (the underlying\n * manager is a singleton).\n */\n async ensureInitialized(options?: WorkerPoolOptions): Promise<void> {\n if (this.initialized) return;\n\n try {\n const workers = await import('./index.js');\n this.workerManager = workers.getWorkerManager(options);\n this.workerTasks = workers.workerTasks;\n this.executeOnWorker = workers.executeOnWorker;\n } catch {\n // Workers not available - graceful degradation\n this.workerManager = null;\n this.workerTasks = null;\n this.executeOnWorker = null;\n }\n\n this.initialized = true;\n }\n\n /**\n * Execute a task on worker threads\n */\n async executeTask<T = any>(task: WorkerTask): Promise<T> {\n await this.ensureInitialized();\n\n if (!this.workerManager) {\n throw new Error('Worker threads are not available in this environment');\n }\n\n return this.workerManager.executeTask<T>(task);\n }\n\n /**\n * Get worker thread statistics.\n * Returns null when workers were never initialized — observing stats\n * must not spawn a pool.\n */\n async getStats(): Promise<WorkerStats | null> {\n if (!this.initialized) return null;\n return this.workerManager?.getStats() || null;\n }\n\n /**\n * Shutdown worker threads.\n * A no-op when workers were never initialized — never spin up a pool\n * just to tear it down.\n */\n async shutdown(): Promise<void> {\n if (!this.initialized) return;\n await this.workerManager?.shutdown();\n }\n\n /**\n * JWT operations using worker threads\n */\n async getJwtWorker(): Promise<{\n verify: WorkerHelpers['verifyJWT'];\n sign: WorkerHelpers['signJWT'];\n } | null> {\n await this.ensureInitialized();\n\n if (!this.workerTasks) return null;\n\n return {\n verify: this.workerTasks.verifyJWT.bind(this.workerTasks),\n sign: this.workerTasks.signJWT.bind(this.workerTasks),\n };\n }\n\n /**\n * Crypto operations using worker threads\n */\n async getCryptoWorker(): Promise<{ hash: WorkerHelpers['hash'] } | null> {\n await this.ensureInitialized();\n\n if (!this.workerTasks) return null;\n\n return {\n hash: this.workerTasks.hash.bind(this.workerTasks),\n };\n }\n\n /**\n * Heavy computation operations using worker threads\n */\n async getComputeWorker(): Promise<{\n heavy: WorkerHelpers['heavyComputation'];\n transformJSON: WorkerHelpers['transformJSON'];\n } | null> {\n await this.ensureInitialized();\n\n if (!this.workerTasks) return null;\n\n return {\n heavy: this.workerTasks.heavyComputation.bind(this.workerTasks),\n transformJSON: this.workerTasks.transformJSON.bind(this.workerTasks),\n };\n }\n\n /**\n * Check if worker threads are available\n */\n async isAvailable(): Promise<boolean> {\n await this.ensureInitialized();\n return this.workerManager !== null;\n }\n}\n"]}
|
|
@@ -134,6 +134,18 @@ export declare const workerTasks: {
|
|
|
134
134
|
* Crypto hash (CPU-intensive)
|
|
135
135
|
*/
|
|
136
136
|
hash(data: string, algorithm?: string): Promise<string>;
|
|
137
|
+
/**
|
|
138
|
+
* Data compression (CPU-intensive for large payloads)
|
|
139
|
+
*/
|
|
140
|
+
compress(data: string | Buffer | Uint8Array, options?: {
|
|
141
|
+
format?: "gzip" | "deflate" | "brotli";
|
|
142
|
+
}): Promise<Buffer>;
|
|
143
|
+
/**
|
|
144
|
+
* Data decompression (CPU-intensive for large payloads)
|
|
145
|
+
*/
|
|
146
|
+
decompress(data: Buffer | Uint8Array, options?: {
|
|
147
|
+
format?: "gzip" | "deflate" | "brotli";
|
|
148
|
+
}): Promise<Buffer>;
|
|
137
149
|
/**
|
|
138
150
|
* Heavy computation example
|
|
139
151
|
*/
|
|
@@ -372,6 +372,33 @@ export const workerTasks = {
|
|
|
372
372
|
timeout: 10000,
|
|
373
373
|
});
|
|
374
374
|
},
|
|
375
|
+
/**
|
|
376
|
+
* Data compression (CPU-intensive for large payloads)
|
|
377
|
+
*/
|
|
378
|
+
async compress(data, options) {
|
|
379
|
+
const result = await executeOnWorker({
|
|
380
|
+
id: `data-compress-${Date.now()}-${++taskIdCounter}`,
|
|
381
|
+
type: WORKER_TASKS.DATA_COMPRESS,
|
|
382
|
+
data: { input: data, format: options?.format ?? 'gzip' },
|
|
383
|
+
priority: 'normal',
|
|
384
|
+
timeout: 30000,
|
|
385
|
+
});
|
|
386
|
+
// Buffers cross the thread boundary as plain Uint8Array
|
|
387
|
+
return Buffer.isBuffer(result) ? result : Buffer.from(result);
|
|
388
|
+
},
|
|
389
|
+
/**
|
|
390
|
+
* Data decompression (CPU-intensive for large payloads)
|
|
391
|
+
*/
|
|
392
|
+
async decompress(data, options) {
|
|
393
|
+
const result = await executeOnWorker({
|
|
394
|
+
id: `data-decompress-${Date.now()}-${++taskIdCounter}`,
|
|
395
|
+
type: WORKER_TASKS.DATA_DECOMPRESS,
|
|
396
|
+
data: { input: data, format: options?.format ?? 'gzip' },
|
|
397
|
+
priority: 'normal',
|
|
398
|
+
timeout: 30000,
|
|
399
|
+
});
|
|
400
|
+
return Buffer.isBuffer(result) ? result : Buffer.from(result);
|
|
401
|
+
},
|
|
375
402
|
/**
|
|
376
403
|
* Heavy computation example
|
|
377
404
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker-manager.js","sourceRoot":"","sources":["../../../src/core/workers/worker-manager.ts"],"names":[],"mappings":"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","sourcesContent":["// Worker Thread Manager - Offload CPU-intensive operations\nimport { Worker } from 'worker_threads';\nimport { createFrameworkLogger } from '../logger/index.js';\nimport { cpus } from 'os';\nimport { isPackageAvailable } from '../utilities/package-utils.js';\n// WORKER_ENTRY resolves to worker.js, this file's compiled sibling in dist/**,\n// via import.meta in ./worker-entry.js. That ESM-only syntax is isolated in its\n// own module (mapped to a stub in jest.config) so importing WorkerManager under\n// ts-jest's CommonJS transform never hits a load-time import.meta SyntaxError.\nimport { WORKER_ENTRY } from './worker-entry.js';\n\n// Optional JWT import\nconst jwtAvailable = isPackageAvailable('jsonwebtoken');\n\nconst logger = createFrameworkLogger('WorkerManager');\n\n// Upper bound on the exponential restart backoff\nconst MAX_RESTART_BACKOFF_MS = 5000;\n\n// Hoisted constants — avoids object allocation inside sort comparator on every call\nconst PRIORITY_ORDER: Record<string, number> = { high: 3, normal: 2, low: 1 };\n\n// Simple counter for task IDs — avoids expensive crypto.randomBytes for non-security IDs\nlet taskIdCounter = 0;\n\n/**\n * Worker task definitions\n */\nexport interface WorkerTask {\n id: string;\n type: string;\n data: any;\n priority?: 'low' | 'normal' | 'high';\n timeout?: number;\n}\n\n/**\n * Worker result\n */\nexport interface WorkerResult {\n taskId: string;\n success: boolean;\n data?: any;\n error?: string;\n executionTime: number;\n}\n\n/**\n * Active task tracking\n */\ninterface ActiveTask {\n resolve: CallableFunction;\n reject: CallableFunction;\n timeout: NodeJS.Timeout | null;\n // The worker a task was dispatched to (set once it leaves the queue). Used so a\n // crashed worker only rejects its own in-flight tasks, not everyone else's.\n assignedWorker?: Worker;\n}\n\n/**\n * Built-in worker tasks\n */\nexport const WORKER_TASKS = {\n JWT_VERIFY: 'jwt:verify',\n JWT_SIGN: 'jwt:sign',\n CRYPTO_HASH: 'crypto:hash',\n CRYPTO_ENCRYPT: 'crypto:encrypt',\n CRYPTO_DECRYPT: 'crypto:decrypt',\n DATA_COMPRESS: 'data:compress',\n DATA_DECOMPRESS: 'data:decompress',\n IMAGE_PROCESS: 'image:process',\n HEAVY_COMPUTATION: 'computation:heavy',\n JSON_TRANSFORM: 'json:transform',\n} as const;\n\n/**\n * Worker Thread Manager\n * Manages a pool of worker threads for CPU-intensive operations\n */\nexport class WorkerManager {\n private workers: Map<number, Worker> = new Map();\n private taskQueue: WorkerTask[] = [];\n private activeTasks: Map<string, ActiveTask> = new Map();\n private workerCount: number;\n private maxQueueSize: number;\n private isShuttingDown = false;\n private maxRestartAttempts: number;\n private restartBackoffMs: number;\n private restartAttempts = 0;\n private restartTimers = new Set<NodeJS.Timeout>();\n private handledFailures = new WeakSet<Worker>();\n private poolFailed = false;\n\n constructor(\n options: {\n workerCount?: number;\n maxQueueSize?: number;\n maxRestartAttempts?: number;\n restartBackoffMs?: number;\n } = {}\n ) {\n this.workerCount = options.workerCount || Math.max(1, cpus().length - 1); // Leave 1 core for main thread\n this.maxQueueSize = options.maxQueueSize || 1000;\n this.maxRestartAttempts = options.maxRestartAttempts ?? 10;\n this.restartBackoffMs = options.restartBackoffMs ?? 100;\n\n this.initializeWorkers();\n }\n\n /**\n * Initialize worker threads\n */\n private initializeWorkers(): void {\n for (let i = 0; i < this.workerCount; i++) {\n this.createWorker();\n }\n\n logger.info(`Initialized ${this.workerCount} worker threads`, 'WorkerInit', {\n totalWorkers: this.workerCount,\n maxQueueSize: this.maxQueueSize,\n });\n }\n\n /**\n * Create a single worker thread\n */\n private createWorker(): void {\n if (this.isShuttingDown || this.poolFailed) {\n return;\n }\n\n let worker: Worker;\n try {\n worker = new Worker(WORKER_ENTRY, {\n workerData: { type: 'worker' },\n });\n } catch (error) {\n // Spawning can fail synchronously (e.g. a missing entry file). Treat it the\n // same as a runtime failure so we back off instead of throwing.\n logger.error('Failed to spawn worker thread', 'WorkerSpawn', {\n error: error instanceof Error ? error.message : String(error),\n });\n this.scheduleRestart();\n return;\n }\n\n worker.on('message', (result: WorkerResult) => {\n // A successful message proves the pool is healthy; reset the restart budget.\n this.restartAttempts = 0;\n this.handleWorkerResult(result);\n });\n\n worker.on('error', error => {\n logger.error('Worker thread error', 'WorkerError', { error: error.message });\n this.handleWorkerFailure(worker);\n });\n\n worker.on('exit', code => {\n if (code !== 0 && !this.isShuttingDown) {\n logger.warn(`Worker exited with code ${code}, restarting`, 'WorkerExit');\n this.handleWorkerFailure(worker);\n }\n });\n\n this.workers.set(worker.threadId, worker);\n logger.debug(`Created worker thread ${worker.threadId}`, 'WorkerCreate');\n }\n\n /**\n * Handle a crashed worker: reject only the tasks that were assigned to it and\n * schedule a backed-off restart. A failed worker emits both 'error' and 'exit',\n * so this is guarded to run at most once per worker.\n */\n private handleWorkerFailure(worker: Worker): void {\n if (this.handledFailures.has(worker)) {\n return;\n }\n this.handledFailures.add(worker);\n\n this.workers.delete(worker.threadId);\n\n if (this.isShuttingDown) {\n return;\n }\n\n // Reject only the tasks that were dispatched to this specific worker. Tasks\n // still queued (or running on other workers) are intentionally left alone.\n for (const [taskId, taskInfo] of this.activeTasks.entries()) {\n if (taskInfo.assignedWorker === worker) {\n if (taskInfo.timeout) {\n clearTimeout(taskInfo.timeout);\n }\n taskInfo.reject(new Error('Worker thread failed'));\n this.activeTasks.delete(taskId);\n }\n }\n\n this.scheduleRestart();\n }\n\n /**\n * Schedule a replacement worker with exponential backoff, capping the number of\n * consecutive restart attempts so a persistently broken worker entry can never\n * spin into an unbounded restart loop.\n */\n private scheduleRestart(): void {\n if (this.isShuttingDown || this.poolFailed) {\n return;\n }\n\n this.restartAttempts++;\n\n if (this.restartAttempts > this.maxRestartAttempts) {\n this.failPool();\n return;\n }\n\n const delay = Math.min(\n this.restartBackoffMs * 2 ** (this.restartAttempts - 1),\n MAX_RESTART_BACKOFF_MS\n );\n\n logger.warn(\n `Scheduling worker restart in ${delay}ms (attempt ${this.restartAttempts}/${this.maxRestartAttempts})`,\n 'WorkerRestart'\n );\n\n const timer = setTimeout(() => {\n this.restartTimers.delete(timer);\n this.createWorker();\n }, delay);\n\n // Don't keep the process alive purely for a pending restart\n timer.unref();\n this.restartTimers.add(timer);\n }\n\n /**\n * Give up after too many failed restarts: fail every outstanding task cleanly\n * (rejecting their promises) instead of looping forever.\n */\n private failPool(): void {\n if (this.poolFailed) {\n return;\n }\n this.poolFailed = true;\n\n logger.error(\n `Worker pool failed to recover after ${this.maxRestartAttempts} restart attempts`,\n 'WorkerPoolFailed'\n );\n\n const error = new Error(\n `Worker pool is unavailable after ${this.maxRestartAttempts} failed restart attempts`\n );\n\n // Every queued task also has an activeTasks entry, so this rejects both\n // in-flight and queued work.\n for (const [taskId, taskInfo] of this.activeTasks.entries()) {\n if (taskInfo.timeout) {\n clearTimeout(taskInfo.timeout);\n }\n taskInfo.reject(error);\n this.activeTasks.delete(taskId);\n }\n\n this.taskQueue.length = 0;\n }\n\n /**\n * Execute a task on a worker thread\n */\n async executeTask<T = any>(task: WorkerTask): Promise<T> {\n if (this.isShuttingDown) {\n throw new Error('Worker manager is shutting down');\n }\n\n if (this.poolFailed) {\n throw new Error('Worker pool is unavailable (too many worker failures)');\n }\n\n return new Promise<T>((resolve, reject) => {\n // Check queue size limit\n if (this.taskQueue.length >= this.maxQueueSize) {\n reject(new Error('Worker queue is full'));\n return;\n }\n\n // Add to queue\n this.taskQueue.push(task);\n\n // Set up promise handlers\n const timeout = task.timeout\n ? setTimeout(() => {\n this.activeTasks.delete(task.id);\n reject(new Error(`Task ${task.id} timed out`));\n }, task.timeout)\n : null;\n\n // Don't keep process alive for worker timeouts\n if (timeout) {\n timeout.unref();\n }\n\n this.activeTasks.set(task.id, { resolve, reject, timeout });\n\n // Try to assign task to available worker\n this.processQueue();\n });\n }\n\n /**\n * Process the task queue\n */\n private processQueue(): void {\n // Sort queue by priority (high first)\n this.taskQueue.sort(\n (a, b) =>\n (PRIORITY_ORDER[b.priority || 'normal'] ?? 0) -\n (PRIORITY_ORDER[a.priority || 'normal'] ?? 0)\n );\n\n // Assign tasks to available workers\n for (const [threadId, worker] of this.workers.entries()) {\n if (this.taskQueue.length === 0) break;\n\n // Check if worker is available (not currently processing)\n // For simplicity, we'll send tasks and let workers handle queuing\n const task = this.taskQueue.shift();\n if (task) {\n // Record the assignment so a crashed worker only rejects its own tasks.\n const taskInfo = this.activeTasks.get(task.id);\n if (taskInfo) {\n taskInfo.assignedWorker = worker;\n }\n worker.postMessage(task);\n logger.debug(`Assigned task ${task.id} to worker ${threadId}`, 'TaskAssigned');\n }\n }\n }\n\n /**\n * Handle result from worker thread\n */\n private handleWorkerResult(result: WorkerResult): void {\n const taskInfo = this.activeTasks.get(result.taskId);\n if (!taskInfo) {\n logger.warn(`Received result for unknown task ${result.taskId}`, 'UnknownTaskResult');\n return;\n }\n\n // Clear timeout\n if (taskInfo.timeout) {\n clearTimeout(taskInfo.timeout);\n }\n\n // Remove from active tasks\n this.activeTasks.delete(result.taskId);\n\n // Handle result\n if (result.success) {\n logger.debug(`Task ${result.taskId} completed in ${result.executionTime}ms`, 'TaskCompleted');\n taskInfo.resolve(result.data);\n } else {\n logger.error(`Task ${result.taskId} failed: ${result.error}`, 'TaskFailed');\n taskInfo.reject(new Error(result.error || 'Task failed'));\n }\n\n // Process next task in queue\n this.processQueue();\n }\n\n /**\n * Shutdown all workers\n */\n async shutdown(): Promise<void> {\n this.isShuttingDown = true;\n\n // Cancel any pending worker restarts\n for (const timer of this.restartTimers) {\n clearTimeout(timer);\n }\n this.restartTimers.clear();\n\n // Reject all pending tasks\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n for (const [taskId, taskInfo] of this.activeTasks.entries()) {\n if (taskInfo.timeout) {\n clearTimeout(taskInfo.timeout);\n }\n taskInfo.reject(new Error('Worker manager shutting down'));\n }\n\n // Terminate all workers\n const shutdownPromises = Array.from(this.workers.values()).map(\n worker =>\n new Promise<void>(resolve => {\n worker.once('exit', () => resolve());\n void worker.terminate();\n })\n );\n\n await Promise.all(shutdownPromises);\n this.workers.clear();\n this.activeTasks.clear();\n this.taskQueue.length = 0;\n\n logger.info('Worker manager shutdown complete', 'WorkerShutdown');\n }\n\n /**\n * Get worker statistics\n */\n getStats() {\n return {\n workerCount: this.workers.size,\n activeTasks: this.activeTasks.size,\n queuedTasks: this.taskQueue.length,\n isShuttingDown: this.isShuttingDown,\n };\n }\n}\n\n// Singleton instance\nlet workerManagerInstance: WorkerManager | null = null;\n\n/**\n * Get or create the worker manager instance\n */\nexport function getWorkerManager(options?: {\n workerCount?: number;\n maxQueueSize?: number;\n}): WorkerManager {\n if (!workerManagerInstance) {\n workerManagerInstance = new WorkerManager(options);\n }\n return workerManagerInstance;\n}\n\n/**\n * Execute task on worker thread (convenience function)\n */\nexport async function executeOnWorker<T = any>(task: WorkerTask): Promise<T> {\n const manager = getWorkerManager();\n return manager.executeTask<T>(task);\n}\n\n/**\n * Built-in task helpers\n */\nexport const workerTasks = {\n /**\n * JWT verification (CPU-intensive)\n */\n async verifyJWT(token: string, secret: string, options?: any): Promise<any> {\n if (!jwtAvailable) {\n throw new Error(\n 'JWT verification requires the \"jsonwebtoken\" package. Please install it with: npm install jsonwebtoken @types/jsonwebtoken'\n );\n }\n return executeOnWorker({\n id: `jwt-verify-${Date.now()}-${++taskIdCounter}`,\n type: WORKER_TASKS.JWT_VERIFY,\n data: { token, secret, options },\n priority: 'high',\n timeout: 5000,\n });\n },\n\n /**\n * JWT signing (CPU-intensive)\n */\n async signJWT(payload: any, secret: string, options?: any): Promise<string> {\n if (!jwtAvailable) {\n throw new Error(\n 'JWT signing requires the \"jsonwebtoken\" package. Please install it with: npm install jsonwebtoken @types/jsonwebtoken'\n );\n }\n return executeOnWorker({\n id: `jwt-sign-${Date.now()}-${++taskIdCounter}`,\n type: WORKER_TASKS.JWT_SIGN,\n data: { payload, secret, options },\n priority: 'high',\n timeout: 5000,\n });\n },\n\n /**\n * Crypto hash (CPU-intensive)\n */\n async hash(data: string, algorithm = 'sha256'): Promise<string> {\n return executeOnWorker({\n id: `crypto-hash-${Date.now()}-${++taskIdCounter}`,\n type: WORKER_TASKS.CRYPTO_HASH,\n data: { data, algorithm },\n priority: 'normal',\n timeout: 10000,\n });\n },\n\n /**\n * Heavy computation example\n */\n async heavyComputation(data: any): Promise<any> {\n return executeOnWorker({\n id: `computation-${Date.now()}-${++taskIdCounter}`,\n type: WORKER_TASKS.HEAVY_COMPUTATION,\n data,\n priority: 'normal',\n timeout: 30000,\n });\n },\n\n /**\n * JSON transformation (can be CPU-intensive for large objects)\n */\n async transformJSON(data: any, transformer: (data: any) => any): Promise<any> {\n return executeOnWorker({\n id: `json-transform-${Date.now()}-${++taskIdCounter}`,\n type: WORKER_TASKS.JSON_TRANSFORM,\n data: { data, transformer: transformer.toString() },\n priority: 'normal',\n timeout: 15000,\n });\n },\n};\n"]}
|
|
1
|
+
{"version":3,"file":"worker-manager.js","sourceRoot":"","sources":["../../../src/core/workers/worker-manager.ts"],"names":[],"mappings":"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","sourcesContent":["// Worker Thread Manager - Offload CPU-intensive operations\nimport { Worker } from 'worker_threads';\nimport { createFrameworkLogger } from '../logger/index.js';\nimport { cpus } from 'os';\nimport { isPackageAvailable } from '../utilities/package-utils.js';\n// WORKER_ENTRY resolves to worker.js, this file's compiled sibling in dist/**,\n// via import.meta in ./worker-entry.js. That ESM-only syntax is isolated in its\n// own module (mapped to a stub in jest.config) so importing WorkerManager under\n// ts-jest's CommonJS transform never hits a load-time import.meta SyntaxError.\nimport { WORKER_ENTRY } from './worker-entry.js';\n\n// Optional JWT import\nconst jwtAvailable = isPackageAvailable('jsonwebtoken');\n\nconst logger = createFrameworkLogger('WorkerManager');\n\n// Upper bound on the exponential restart backoff\nconst MAX_RESTART_BACKOFF_MS = 5000;\n\n// Hoisted constants — avoids object allocation inside sort comparator on every call\nconst PRIORITY_ORDER: Record<string, number> = { high: 3, normal: 2, low: 1 };\n\n// Simple counter for task IDs — avoids expensive crypto.randomBytes for non-security IDs\nlet taskIdCounter = 0;\n\n/**\n * Worker task definitions\n */\nexport interface WorkerTask {\n id: string;\n type: string;\n data: any;\n priority?: 'low' | 'normal' | 'high';\n timeout?: number;\n}\n\n/**\n * Worker result\n */\nexport interface WorkerResult {\n taskId: string;\n success: boolean;\n data?: any;\n error?: string;\n executionTime: number;\n}\n\n/**\n * Active task tracking\n */\ninterface ActiveTask {\n resolve: CallableFunction;\n reject: CallableFunction;\n timeout: NodeJS.Timeout | null;\n // The worker a task was dispatched to (set once it leaves the queue). Used so a\n // crashed worker only rejects its own in-flight tasks, not everyone else's.\n assignedWorker?: Worker;\n}\n\n/**\n * Built-in worker tasks\n */\nexport const WORKER_TASKS = {\n JWT_VERIFY: 'jwt:verify',\n JWT_SIGN: 'jwt:sign',\n CRYPTO_HASH: 'crypto:hash',\n CRYPTO_ENCRYPT: 'crypto:encrypt',\n CRYPTO_DECRYPT: 'crypto:decrypt',\n DATA_COMPRESS: 'data:compress',\n DATA_DECOMPRESS: 'data:decompress',\n IMAGE_PROCESS: 'image:process',\n HEAVY_COMPUTATION: 'computation:heavy',\n JSON_TRANSFORM: 'json:transform',\n} as const;\n\n/**\n * Worker Thread Manager\n * Manages a pool of worker threads for CPU-intensive operations\n */\nexport class WorkerManager {\n private workers: Map<number, Worker> = new Map();\n private taskQueue: WorkerTask[] = [];\n private activeTasks: Map<string, ActiveTask> = new Map();\n private workerCount: number;\n private maxQueueSize: number;\n private isShuttingDown = false;\n private maxRestartAttempts: number;\n private restartBackoffMs: number;\n private restartAttempts = 0;\n private restartTimers = new Set<NodeJS.Timeout>();\n private handledFailures = new WeakSet<Worker>();\n private poolFailed = false;\n\n constructor(\n options: {\n workerCount?: number;\n maxQueueSize?: number;\n maxRestartAttempts?: number;\n restartBackoffMs?: number;\n } = {}\n ) {\n this.workerCount = options.workerCount || Math.max(1, cpus().length - 1); // Leave 1 core for main thread\n this.maxQueueSize = options.maxQueueSize || 1000;\n this.maxRestartAttempts = options.maxRestartAttempts ?? 10;\n this.restartBackoffMs = options.restartBackoffMs ?? 100;\n\n this.initializeWorkers();\n }\n\n /**\n * Initialize worker threads\n */\n private initializeWorkers(): void {\n for (let i = 0; i < this.workerCount; i++) {\n this.createWorker();\n }\n\n logger.info(`Initialized ${this.workerCount} worker threads`, 'WorkerInit', {\n totalWorkers: this.workerCount,\n maxQueueSize: this.maxQueueSize,\n });\n }\n\n /**\n * Create a single worker thread\n */\n private createWorker(): void {\n if (this.isShuttingDown || this.poolFailed) {\n return;\n }\n\n let worker: Worker;\n try {\n worker = new Worker(WORKER_ENTRY, {\n workerData: { type: 'worker' },\n });\n } catch (error) {\n // Spawning can fail synchronously (e.g. a missing entry file). Treat it the\n // same as a runtime failure so we back off instead of throwing.\n logger.error('Failed to spawn worker thread', 'WorkerSpawn', {\n error: error instanceof Error ? error.message : String(error),\n });\n this.scheduleRestart();\n return;\n }\n\n worker.on('message', (result: WorkerResult) => {\n // A successful message proves the pool is healthy; reset the restart budget.\n this.restartAttempts = 0;\n this.handleWorkerResult(result);\n });\n\n worker.on('error', error => {\n logger.error('Worker thread error', 'WorkerError', { error: error.message });\n this.handleWorkerFailure(worker);\n });\n\n worker.on('exit', code => {\n if (code !== 0 && !this.isShuttingDown) {\n logger.warn(`Worker exited with code ${code}, restarting`, 'WorkerExit');\n this.handleWorkerFailure(worker);\n }\n });\n\n this.workers.set(worker.threadId, worker);\n logger.debug(`Created worker thread ${worker.threadId}`, 'WorkerCreate');\n }\n\n /**\n * Handle a crashed worker: reject only the tasks that were assigned to it and\n * schedule a backed-off restart. A failed worker emits both 'error' and 'exit',\n * so this is guarded to run at most once per worker.\n */\n private handleWorkerFailure(worker: Worker): void {\n if (this.handledFailures.has(worker)) {\n return;\n }\n this.handledFailures.add(worker);\n\n this.workers.delete(worker.threadId);\n\n if (this.isShuttingDown) {\n return;\n }\n\n // Reject only the tasks that were dispatched to this specific worker. Tasks\n // still queued (or running on other workers) are intentionally left alone.\n for (const [taskId, taskInfo] of this.activeTasks.entries()) {\n if (taskInfo.assignedWorker === worker) {\n if (taskInfo.timeout) {\n clearTimeout(taskInfo.timeout);\n }\n taskInfo.reject(new Error('Worker thread failed'));\n this.activeTasks.delete(taskId);\n }\n }\n\n this.scheduleRestart();\n }\n\n /**\n * Schedule a replacement worker with exponential backoff, capping the number of\n * consecutive restart attempts so a persistently broken worker entry can never\n * spin into an unbounded restart loop.\n */\n private scheduleRestart(): void {\n if (this.isShuttingDown || this.poolFailed) {\n return;\n }\n\n this.restartAttempts++;\n\n if (this.restartAttempts > this.maxRestartAttempts) {\n this.failPool();\n return;\n }\n\n const delay = Math.min(\n this.restartBackoffMs * 2 ** (this.restartAttempts - 1),\n MAX_RESTART_BACKOFF_MS\n );\n\n logger.warn(\n `Scheduling worker restart in ${delay}ms (attempt ${this.restartAttempts}/${this.maxRestartAttempts})`,\n 'WorkerRestart'\n );\n\n const timer = setTimeout(() => {\n this.restartTimers.delete(timer);\n this.createWorker();\n }, delay);\n\n // Don't keep the process alive purely for a pending restart\n timer.unref();\n this.restartTimers.add(timer);\n }\n\n /**\n * Give up after too many failed restarts: fail every outstanding task cleanly\n * (rejecting their promises) instead of looping forever.\n */\n private failPool(): void {\n if (this.poolFailed) {\n return;\n }\n this.poolFailed = true;\n\n logger.error(\n `Worker pool failed to recover after ${this.maxRestartAttempts} restart attempts`,\n 'WorkerPoolFailed'\n );\n\n const error = new Error(\n `Worker pool is unavailable after ${this.maxRestartAttempts} failed restart attempts`\n );\n\n // Every queued task also has an activeTasks entry, so this rejects both\n // in-flight and queued work.\n for (const [taskId, taskInfo] of this.activeTasks.entries()) {\n if (taskInfo.timeout) {\n clearTimeout(taskInfo.timeout);\n }\n taskInfo.reject(error);\n this.activeTasks.delete(taskId);\n }\n\n this.taskQueue.length = 0;\n }\n\n /**\n * Execute a task on a worker thread\n */\n async executeTask<T = any>(task: WorkerTask): Promise<T> {\n if (this.isShuttingDown) {\n throw new Error('Worker manager is shutting down');\n }\n\n if (this.poolFailed) {\n throw new Error('Worker pool is unavailable (too many worker failures)');\n }\n\n return new Promise<T>((resolve, reject) => {\n // Check queue size limit\n if (this.taskQueue.length >= this.maxQueueSize) {\n reject(new Error('Worker queue is full'));\n return;\n }\n\n // Add to queue\n this.taskQueue.push(task);\n\n // Set up promise handlers\n const timeout = task.timeout\n ? setTimeout(() => {\n this.activeTasks.delete(task.id);\n reject(new Error(`Task ${task.id} timed out`));\n }, task.timeout)\n : null;\n\n // Don't keep process alive for worker timeouts\n if (timeout) {\n timeout.unref();\n }\n\n this.activeTasks.set(task.id, { resolve, reject, timeout });\n\n // Try to assign task to available worker\n this.processQueue();\n });\n }\n\n /**\n * Process the task queue\n */\n private processQueue(): void {\n // Sort queue by priority (high first)\n this.taskQueue.sort(\n (a, b) =>\n (PRIORITY_ORDER[b.priority || 'normal'] ?? 0) -\n (PRIORITY_ORDER[a.priority || 'normal'] ?? 0)\n );\n\n // Assign tasks to available workers\n for (const [threadId, worker] of this.workers.entries()) {\n if (this.taskQueue.length === 0) break;\n\n // Check if worker is available (not currently processing)\n // For simplicity, we'll send tasks and let workers handle queuing\n const task = this.taskQueue.shift();\n if (task) {\n // Record the assignment so a crashed worker only rejects its own tasks.\n const taskInfo = this.activeTasks.get(task.id);\n if (taskInfo) {\n taskInfo.assignedWorker = worker;\n }\n worker.postMessage(task);\n logger.debug(`Assigned task ${task.id} to worker ${threadId}`, 'TaskAssigned');\n }\n }\n }\n\n /**\n * Handle result from worker thread\n */\n private handleWorkerResult(result: WorkerResult): void {\n const taskInfo = this.activeTasks.get(result.taskId);\n if (!taskInfo) {\n logger.warn(`Received result for unknown task ${result.taskId}`, 'UnknownTaskResult');\n return;\n }\n\n // Clear timeout\n if (taskInfo.timeout) {\n clearTimeout(taskInfo.timeout);\n }\n\n // Remove from active tasks\n this.activeTasks.delete(result.taskId);\n\n // Handle result\n if (result.success) {\n logger.debug(`Task ${result.taskId} completed in ${result.executionTime}ms`, 'TaskCompleted');\n taskInfo.resolve(result.data);\n } else {\n logger.error(`Task ${result.taskId} failed: ${result.error}`, 'TaskFailed');\n taskInfo.reject(new Error(result.error || 'Task failed'));\n }\n\n // Process next task in queue\n this.processQueue();\n }\n\n /**\n * Shutdown all workers\n */\n async shutdown(): Promise<void> {\n this.isShuttingDown = true;\n\n // Cancel any pending worker restarts\n for (const timer of this.restartTimers) {\n clearTimeout(timer);\n }\n this.restartTimers.clear();\n\n // Reject all pending tasks\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n for (const [taskId, taskInfo] of this.activeTasks.entries()) {\n if (taskInfo.timeout) {\n clearTimeout(taskInfo.timeout);\n }\n taskInfo.reject(new Error('Worker manager shutting down'));\n }\n\n // Terminate all workers\n const shutdownPromises = Array.from(this.workers.values()).map(\n worker =>\n new Promise<void>(resolve => {\n worker.once('exit', () => resolve());\n void worker.terminate();\n })\n );\n\n await Promise.all(shutdownPromises);\n this.workers.clear();\n this.activeTasks.clear();\n this.taskQueue.length = 0;\n\n logger.info('Worker manager shutdown complete', 'WorkerShutdown');\n }\n\n /**\n * Get worker statistics\n */\n getStats() {\n return {\n workerCount: this.workers.size,\n activeTasks: this.activeTasks.size,\n queuedTasks: this.taskQueue.length,\n isShuttingDown: this.isShuttingDown,\n };\n }\n}\n\n// Singleton instance\nlet workerManagerInstance: WorkerManager | null = null;\n\n/**\n * Get or create the worker manager instance\n */\nexport function getWorkerManager(options?: {\n workerCount?: number;\n maxQueueSize?: number;\n}): WorkerManager {\n if (!workerManagerInstance) {\n workerManagerInstance = new WorkerManager(options);\n }\n return workerManagerInstance;\n}\n\n/**\n * Execute task on worker thread (convenience function)\n */\nexport async function executeOnWorker<T = any>(task: WorkerTask): Promise<T> {\n const manager = getWorkerManager();\n return manager.executeTask<T>(task);\n}\n\n/**\n * Built-in task helpers\n */\nexport const workerTasks = {\n /**\n * JWT verification (CPU-intensive)\n */\n async verifyJWT(token: string, secret: string, options?: any): Promise<any> {\n if (!jwtAvailable) {\n throw new Error(\n 'JWT verification requires the \"jsonwebtoken\" package. Please install it with: npm install jsonwebtoken @types/jsonwebtoken'\n );\n }\n return executeOnWorker({\n id: `jwt-verify-${Date.now()}-${++taskIdCounter}`,\n type: WORKER_TASKS.JWT_VERIFY,\n data: { token, secret, options },\n priority: 'high',\n timeout: 5000,\n });\n },\n\n /**\n * JWT signing (CPU-intensive)\n */\n async signJWT(payload: any, secret: string, options?: any): Promise<string> {\n if (!jwtAvailable) {\n throw new Error(\n 'JWT signing requires the \"jsonwebtoken\" package. Please install it with: npm install jsonwebtoken @types/jsonwebtoken'\n );\n }\n return executeOnWorker({\n id: `jwt-sign-${Date.now()}-${++taskIdCounter}`,\n type: WORKER_TASKS.JWT_SIGN,\n data: { payload, secret, options },\n priority: 'high',\n timeout: 5000,\n });\n },\n\n /**\n * Crypto hash (CPU-intensive)\n */\n async hash(data: string, algorithm = 'sha256'): Promise<string> {\n return executeOnWorker({\n id: `crypto-hash-${Date.now()}-${++taskIdCounter}`,\n type: WORKER_TASKS.CRYPTO_HASH,\n data: { data, algorithm },\n priority: 'normal',\n timeout: 10000,\n });\n },\n\n /**\n * Data compression (CPU-intensive for large payloads)\n */\n async compress(\n data: string | Buffer | Uint8Array,\n options?: { format?: 'gzip' | 'deflate' | 'brotli' }\n ): Promise<Buffer> {\n const result = await executeOnWorker<Uint8Array>({\n id: `data-compress-${Date.now()}-${++taskIdCounter}`,\n type: WORKER_TASKS.DATA_COMPRESS,\n data: { input: data, format: options?.format ?? 'gzip' },\n priority: 'normal',\n timeout: 30000,\n });\n // Buffers cross the thread boundary as plain Uint8Array\n return Buffer.isBuffer(result) ? result : Buffer.from(result);\n },\n\n /**\n * Data decompression (CPU-intensive for large payloads)\n */\n async decompress(\n data: Buffer | Uint8Array,\n options?: { format?: 'gzip' | 'deflate' | 'brotli' }\n ): Promise<Buffer> {\n const result = await executeOnWorker<Uint8Array>({\n id: `data-decompress-${Date.now()}-${++taskIdCounter}`,\n type: WORKER_TASKS.DATA_DECOMPRESS,\n data: { input: data, format: options?.format ?? 'gzip' },\n priority: 'normal',\n timeout: 30000,\n });\n return Buffer.isBuffer(result) ? result : Buffer.from(result);\n },\n\n /**\n * Heavy computation example\n */\n async heavyComputation(data: any): Promise<any> {\n return executeOnWorker({\n id: `computation-${Date.now()}-${++taskIdCounter}`,\n type: WORKER_TASKS.HEAVY_COMPUTATION,\n data,\n priority: 'normal',\n timeout: 30000,\n });\n },\n\n /**\n * JSON transformation (can be CPU-intensive for large objects)\n */\n async transformJSON(data: any, transformer: (data: any) => any): Promise<any> {\n return executeOnWorker({\n id: `json-transform-${Date.now()}-${++taskIdCounter}`,\n type: WORKER_TASKS.JSON_TRANSFORM,\n data: { data, transformer: transformer.toString() },\n priority: 'normal',\n timeout: 15000,\n });\n },\n};\n"]}
|
|
@@ -1 +1,17 @@
|
|
|
1
|
-
export
|
|
1
|
+
export type CompressionFormat = 'gzip' | 'deflate' | 'brotli';
|
|
2
|
+
/**
|
|
3
|
+
* Data compression handler
|
|
4
|
+
* Exported for direct unit testing; normally invoked via the worker task registry.
|
|
5
|
+
*/
|
|
6
|
+
export declare function handleDataCompress(data: {
|
|
7
|
+
input: string | Buffer | Uint8Array;
|
|
8
|
+
format?: CompressionFormat;
|
|
9
|
+
}): Promise<Buffer>;
|
|
10
|
+
/**
|
|
11
|
+
* Data decompression handler
|
|
12
|
+
* Exported for direct unit testing; normally invoked via the worker task registry.
|
|
13
|
+
*/
|
|
14
|
+
export declare function handleDataDecompress(data: {
|
|
15
|
+
input: Buffer | Uint8Array;
|
|
16
|
+
format?: CompressionFormat;
|
|
17
|
+
}): Promise<Buffer>;
|
|
@@ -14,6 +14,10 @@ let jwt = null;
|
|
|
14
14
|
const jwtAvailable = isPackageAvailable('jsonwebtoken');
|
|
15
15
|
const gzip = promisify(zlib.gzip);
|
|
16
16
|
const gunzip = promisify(zlib.gunzip);
|
|
17
|
+
const deflate = promisify(zlib.deflate);
|
|
18
|
+
const inflate = promisify(zlib.inflate);
|
|
19
|
+
const brotliCompress = promisify(zlib.brotliCompress);
|
|
20
|
+
const brotliDecompress = promisify(zlib.brotliDecompress);
|
|
17
21
|
// Import task types
|
|
18
22
|
import { WORKER_TASKS } from './worker-manager.js';
|
|
19
23
|
/**
|
|
@@ -165,40 +169,38 @@ async function handleCryptoDecrypt(data) {
|
|
|
165
169
|
}
|
|
166
170
|
/**
|
|
167
171
|
* Data compression handler
|
|
172
|
+
* Exported for direct unit testing; normally invoked via the worker task registry.
|
|
168
173
|
*/
|
|
169
|
-
async function handleDataCompress(data) {
|
|
174
|
+
export async function handleDataCompress(data) {
|
|
170
175
|
const { input, format = 'gzip' } = data;
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
});
|
|
182
|
-
});
|
|
176
|
+
const buffer = Buffer.from(input);
|
|
177
|
+
switch (format) {
|
|
178
|
+
case 'gzip':
|
|
179
|
+
return gzip(buffer);
|
|
180
|
+
case 'deflate':
|
|
181
|
+
return deflate(buffer);
|
|
182
|
+
case 'brotli':
|
|
183
|
+
return brotliCompress(buffer);
|
|
184
|
+
default:
|
|
185
|
+
throw new Error(`Unknown compression format: ${format}`);
|
|
183
186
|
}
|
|
184
187
|
}
|
|
185
188
|
/**
|
|
186
189
|
* Data decompression handler
|
|
190
|
+
* Exported for direct unit testing; normally invoked via the worker task registry.
|
|
187
191
|
*/
|
|
188
|
-
async function handleDataDecompress(data) {
|
|
192
|
+
export async function handleDataDecompress(data) {
|
|
189
193
|
const { input, format = 'gzip' } = data;
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
});
|
|
201
|
-
});
|
|
194
|
+
const buffer = Buffer.from(input);
|
|
195
|
+
switch (format) {
|
|
196
|
+
case 'gzip':
|
|
197
|
+
return gunzip(buffer);
|
|
198
|
+
case 'deflate':
|
|
199
|
+
return inflate(buffer);
|
|
200
|
+
case 'brotli':
|
|
201
|
+
return brotliDecompress(buffer);
|
|
202
|
+
default:
|
|
203
|
+
throw new Error(`Unknown compression format: ${format}`);
|
|
202
204
|
}
|
|
203
205
|
}
|
|
204
206
|
/**
|