nmtjs 0.16.0 → 0.17.0-beta.1
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/LICENSE.md +1 -1
- package/README.md +41 -1
- package/dist/index.d.ts +22 -121
- package/dist/index.js +24 -53
- package/dist/index.js.map +1 -1
- package/package.json +11 -63
- package/src/index.ts +71 -91
- package/bin/cli.js +0 -2
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +0 -137
- package/dist/cli.js.map +0 -1
- package/dist/codegen.d.ts +0 -5
- package/dist/codegen.js +0 -18
- package/dist/codegen.js.map +0 -1
- package/dist/config.d.ts +0 -47
- package/dist/config.js +0 -16
- package/dist/config.js.map +0 -1
- package/dist/entrypoints/cli.d.ts +0 -1
- package/dist/entrypoints/cli.js +0 -12
- package/dist/entrypoints/cli.js.map +0 -1
- package/dist/entrypoints/main.d.ts +0 -5
- package/dist/entrypoints/main.js +0 -248
- package/dist/entrypoints/main.js.map +0 -1
- package/dist/entrypoints/thread.d.ts +0 -16
- package/dist/entrypoints/thread.js +0 -182
- package/dist/entrypoints/thread.js.map +0 -1
- package/dist/entrypoints/worker.d.ts +0 -9
- package/dist/entrypoints/worker.js +0 -143
- package/dist/entrypoints/worker.js.map +0 -1
- package/dist/resolver.d.ts +0 -2
- package/dist/resolver.js +0 -7
- package/dist/resolver.js.map +0 -1
- package/dist/runtime/application/index.d.ts +0 -1
- package/dist/runtime/application/index.js +0 -2
- package/dist/runtime/application/index.js.map +0 -1
- package/dist/runtime/constants.d.ts +0 -8
- package/dist/runtime/constants.js +0 -5
- package/dist/runtime/constants.js.map +0 -1
- package/dist/runtime/enums.d.ts +0 -10
- package/dist/runtime/enums.js +0 -13
- package/dist/runtime/enums.js.map +0 -1
- package/dist/runtime/hooks.d.ts +0 -1
- package/dist/runtime/hooks.js +0 -2
- package/dist/runtime/hooks.js.map +0 -1
- package/dist/runtime/index.d.ts +0 -28
- package/dist/runtime/index.js +0 -29
- package/dist/runtime/index.js.map +0 -1
- package/dist/runtime/injectables.d.ts +0 -28
- package/dist/runtime/injectables.js +0 -24
- package/dist/runtime/injectables.js.map +0 -1
- package/dist/runtime/jobs/job.d.ts +0 -146
- package/dist/runtime/jobs/job.js +0 -89
- package/dist/runtime/jobs/job.js.map +0 -1
- package/dist/runtime/jobs/manager.d.ts +0 -131
- package/dist/runtime/jobs/manager.js +0 -309
- package/dist/runtime/jobs/manager.js.map +0 -1
- package/dist/runtime/jobs/router.d.ts +0 -296
- package/dist/runtime/jobs/router.js +0 -458
- package/dist/runtime/jobs/router.js.map +0 -1
- package/dist/runtime/jobs/runner.d.ts +0 -103
- package/dist/runtime/jobs/runner.js +0 -425
- package/dist/runtime/jobs/runner.js.map +0 -1
- package/dist/runtime/jobs/step.d.ts +0 -26
- package/dist/runtime/jobs/step.js +0 -18
- package/dist/runtime/jobs/step.js.map +0 -1
- package/dist/runtime/jobs/types.d.ts +0 -86
- package/dist/runtime/jobs/types.js +0 -5
- package/dist/runtime/jobs/types.js.map +0 -1
- package/dist/runtime/metrics/metric.d.ts +0 -8
- package/dist/runtime/metrics/metric.js +0 -11
- package/dist/runtime/metrics/metric.js.map +0 -1
- package/dist/runtime/metrics/registry.d.ts +0 -3
- package/dist/runtime/metrics/registry.js +0 -5
- package/dist/runtime/metrics/registry.js.map +0 -1
- package/dist/runtime/metrics/server.d.ts +0 -7
- package/dist/runtime/metrics/server.js +0 -53
- package/dist/runtime/metrics/server.js.map +0 -1
- package/dist/runtime/plugin.d.ts +0 -2
- package/dist/runtime/plugin.js +0 -2
- package/dist/runtime/plugin.js.map +0 -1
- package/dist/runtime/runtime.d.ts +0 -27
- package/dist/runtime/runtime.js +0 -77
- package/dist/runtime/runtime.js.map +0 -1
- package/dist/runtime/scheduler/index.d.ts +0 -22
- package/dist/runtime/scheduler/index.js +0 -20
- package/dist/runtime/scheduler/index.js.map +0 -1
- package/dist/runtime/server/applications.d.ts +0 -91
- package/dist/runtime/server/applications.js +0 -171
- package/dist/runtime/server/applications.js.map +0 -1
- package/dist/runtime/server/config.d.ts +0 -148
- package/dist/runtime/server/config.js +0 -33
- package/dist/runtime/server/config.js.map +0 -1
- package/dist/runtime/server/environment.d.ts +0 -43
- package/dist/runtime/server/environment.js +0 -33
- package/dist/runtime/server/environment.js.map +0 -1
- package/dist/runtime/server/error-policy.d.ts +0 -62
- package/dist/runtime/server/error-policy.js +0 -73
- package/dist/runtime/server/error-policy.js.map +0 -1
- package/dist/runtime/server/hmr-coordinator.d.ts +0 -37
- package/dist/runtime/server/hmr-coordinator.js +0 -94
- package/dist/runtime/server/hmr-coordinator.js.map +0 -1
- package/dist/runtime/server/jobs.d.ts +0 -54
- package/dist/runtime/server/jobs.js +0 -176
- package/dist/runtime/server/jobs.js.map +0 -1
- package/dist/runtime/server/lifecycle.d.ts +0 -85
- package/dist/runtime/server/lifecycle.js +0 -177
- package/dist/runtime/server/lifecycle.js.map +0 -1
- package/dist/runtime/server/managed-worker.d.ts +0 -158
- package/dist/runtime/server/managed-worker.js +0 -420
- package/dist/runtime/server/managed-worker.js.map +0 -1
- package/dist/runtime/server/pool-manager.d.ts +0 -85
- package/dist/runtime/server/pool-manager.js +0 -129
- package/dist/runtime/server/pool-manager.js.map +0 -1
- package/dist/runtime/server/proxy.d.ts +0 -21
- package/dist/runtime/server/proxy.js +0 -76
- package/dist/runtime/server/proxy.js.map +0 -1
- package/dist/runtime/server/server.d.ts +0 -60
- package/dist/runtime/server/server.js +0 -163
- package/dist/runtime/server/server.js.map +0 -1
- package/dist/runtime/server/types.d.ts +0 -31
- package/dist/runtime/server/types.js +0 -2
- package/dist/runtime/server/types.js.map +0 -1
- package/dist/runtime/server/worker-pool.d.ts +0 -121
- package/dist/runtime/server/worker-pool.js +0 -171
- package/dist/runtime/server/worker-pool.js.map +0 -1
- package/dist/runtime/store/index.d.ts +0 -3
- package/dist/runtime/store/index.js +0 -23
- package/dist/runtime/store/index.js.map +0 -1
- package/dist/runtime/subscription/manager.d.ts +0 -49
- package/dist/runtime/subscription/manager.js +0 -170
- package/dist/runtime/subscription/manager.js.map +0 -1
- package/dist/runtime/subscription/redis.d.ts +0 -18
- package/dist/runtime/subscription/redis.js +0 -120
- package/dist/runtime/subscription/redis.js.map +0 -1
- package/dist/runtime/types.d.ts +0 -95
- package/dist/runtime/types.js +0 -2
- package/dist/runtime/types.js.map +0 -1
- package/dist/runtime/workers/application.d.ts +0 -29
- package/dist/runtime/workers/application.js +0 -77
- package/dist/runtime/workers/application.js.map +0 -1
- package/dist/runtime/workers/base.d.ts +0 -16
- package/dist/runtime/workers/base.js +0 -46
- package/dist/runtime/workers/base.js.map +0 -1
- package/dist/runtime/workers/cli.d.ts +0 -1
- package/dist/runtime/workers/cli.js +0 -2
- package/dist/runtime/workers/cli.js.map +0 -1
- package/dist/runtime/workers/job.d.ts +0 -20
- package/dist/runtime/workers/job.js +0 -170
- package/dist/runtime/workers/job.js.map +0 -1
- package/dist/vite/builder.d.ts +0 -5
- package/dist/vite/builder.js +0 -79
- package/dist/vite/builder.js.map +0 -1
- package/dist/vite/config.d.ts +0 -28
- package/dist/vite/config.js +0 -22
- package/dist/vite/config.js.map +0 -1
- package/dist/vite/plugins.d.ts +0 -2
- package/dist/vite/plugins.js +0 -43
- package/dist/vite/plugins.js.map +0 -1
- package/dist/vite/runners/worker.d.ts +0 -3
- package/dist/vite/runners/worker.js +0 -34
- package/dist/vite/runners/worker.js.map +0 -1
- package/dist/vite/server.d.ts +0 -3
- package/dist/vite/server.js +0 -36
- package/dist/vite/server.js.map +0 -1
- package/dist/vite/servers/main.d.ts +0 -8
- package/dist/vite/servers/main.js +0 -24
- package/dist/vite/servers/main.js.map +0 -1
- package/dist/vite/servers/worker.d.ts +0 -13
- package/dist/vite/servers/worker.js +0 -124
- package/dist/vite/servers/worker.js.map +0 -1
- package/src/cli.ts +0 -162
- package/src/codegen.ts +0 -30
- package/src/config.ts +0 -69
- package/src/entrypoints/cli.ts +0 -13
- package/src/entrypoints/main.ts +0 -317
- package/src/entrypoints/thread.ts +0 -223
- package/src/entrypoints/worker.ts +0 -174
- package/src/resolver.ts +0 -7
- package/src/runtime/application/index.ts +0 -1
- package/src/runtime/constants.ts +0 -13
- package/src/runtime/enums.ts +0 -12
- package/src/runtime/hooks.ts +0 -1
- package/src/runtime/index.ts +0 -29
- package/src/runtime/injectables.ts +0 -72
- package/src/runtime/jobs/job.ts +0 -467
- package/src/runtime/jobs/manager.ts +0 -454
- package/src/runtime/jobs/router.ts +0 -967
- package/src/runtime/jobs/runner.ts +0 -583
- package/src/runtime/jobs/step.ts +0 -66
- package/src/runtime/jobs/types.ts +0 -116
- package/src/runtime/metrics/metric.ts +0 -18
- package/src/runtime/metrics/registry.ts +0 -11
- package/src/runtime/metrics/server.ts +0 -69
- package/src/runtime/plugin.ts +0 -2
- package/src/runtime/runtime.ts +0 -103
- package/src/runtime/scheduler/index.ts +0 -39
- package/src/runtime/server/applications.ts +0 -264
- package/src/runtime/server/config.ts +0 -199
- package/src/runtime/server/environment.ts +0 -71
- package/src/runtime/server/error-policy.ts +0 -132
- package/src/runtime/server/hmr-coordinator.ts +0 -116
- package/src/runtime/server/jobs.ts +0 -266
- package/src/runtime/server/lifecycle.ts +0 -234
- package/src/runtime/server/managed-worker.ts +0 -546
- package/src/runtime/server/pool-manager.ts +0 -187
- package/src/runtime/server/proxy.ts +0 -119
- package/src/runtime/server/server.ts +0 -218
- package/src/runtime/server/types.ts +0 -32
- package/src/runtime/server/worker-pool.ts +0 -275
- package/src/runtime/store/index.ts +0 -30
- package/src/runtime/subscription/manager.ts +0 -310
- package/src/runtime/subscription/redis.ts +0 -157
- package/src/runtime/types.ts +0 -84
- package/src/runtime/workers/application.ts +0 -133
- package/src/runtime/workers/base.ts +0 -71
- package/src/runtime/workers/cli.ts +0 -0
- package/src/runtime/workers/job.ts +0 -142
- package/src/vite/builder.ts +0 -94
- package/src/vite/config.ts +0 -45
- package/src/vite/plugins.ts +0 -53
- package/src/vite/runners/worker.ts +0 -55
- package/src/vite/server.ts +0 -55
- package/src/vite/servers/main.ts +0 -41
- package/src/vite/servers/worker.ts +0 -177
package/src/entrypoints/main.ts
DELETED
|
@@ -1,317 +0,0 @@
|
|
|
1
|
-
import type { MessagePort, Worker } from 'node:worker_threads'
|
|
2
|
-
import EventEmitter from 'node:events'
|
|
3
|
-
import { fileURLToPath } from 'node:url'
|
|
4
|
-
|
|
5
|
-
import type { ViteDevServer } from 'vite'
|
|
6
|
-
import { createLogger } from '@nmtjs/core'
|
|
7
|
-
|
|
8
|
-
import type { ServerConfig } from '../runtime/index.ts'
|
|
9
|
-
import type { WorkerServerEventMap } from '../vite/servers/worker.ts'
|
|
10
|
-
import {
|
|
11
|
-
ApplicationServer,
|
|
12
|
-
defaultPoolFactory,
|
|
13
|
-
defaultWorkerFactory,
|
|
14
|
-
isServerConfig,
|
|
15
|
-
} from '../runtime/index.ts'
|
|
16
|
-
import { createRuntimeEnvironment } from '../runtime/server/environment.ts'
|
|
17
|
-
import { getErrorPolicy } from '../runtime/server/error-policy.ts'
|
|
18
|
-
import { HMRCoordinator } from '../runtime/server/hmr-coordinator.ts'
|
|
19
|
-
import { ServerLifecycle } from '../runtime/server/lifecycle.ts'
|
|
20
|
-
|
|
21
|
-
declare global {
|
|
22
|
-
const __VITE_CONFIG__: string
|
|
23
|
-
const __APPLICATIONS_CONFIG__: string
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
class InvalidServerConfigError extends Error {
|
|
27
|
-
constructor() {
|
|
28
|
-
super(
|
|
29
|
-
`Server config file does not have a default export, or it is not a valid server config. Please, make sure the server config is defined using defineServer().`,
|
|
30
|
-
)
|
|
31
|
-
this.name = 'InvalidServerConfigError'
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const _ext = new URL(import.meta.url).pathname.endsWith('.ts') ? '.ts' : '.js'
|
|
36
|
-
const _vite = __VITE_CONFIG__ ? JSON.parse(__VITE_CONFIG__) : undefined
|
|
37
|
-
const applicationsConfig: Record<
|
|
38
|
-
string,
|
|
39
|
-
{ type: 'neemata' | 'custom'; specifier: string }
|
|
40
|
-
> = __APPLICATIONS_CONFIG__ ? JSON.parse(__APPLICATIONS_CONFIG__) : {}
|
|
41
|
-
|
|
42
|
-
// Runtime environment setup
|
|
43
|
-
const mode = _vite?.mode === 'development' ? 'development' : 'production'
|
|
44
|
-
const isDev = mode === 'development'
|
|
45
|
-
const errorPolicy = getErrorPolicy(mode)
|
|
46
|
-
const bootstrapLogger = createLogger(
|
|
47
|
-
{ pinoOptions: { level: isDev ? 'debug' : 'info' } },
|
|
48
|
-
'Main',
|
|
49
|
-
)
|
|
50
|
-
|
|
51
|
-
// Logger for main process (created lazily with config-based level)
|
|
52
|
-
let logger: ReturnType<typeof createLogger> = bootstrapLogger
|
|
53
|
-
|
|
54
|
-
// Vite server and events (dev only)
|
|
55
|
-
let _viteServerEvents: EventEmitter<WorkerServerEventMap> | undefined
|
|
56
|
-
let _viteServer: ViteDevServer | undefined
|
|
57
|
-
|
|
58
|
-
// Server lifecycle management
|
|
59
|
-
let lifecycle: ServerLifecycle | undefined
|
|
60
|
-
let hmrCoordinator: HMRCoordinator | undefined
|
|
61
|
-
|
|
62
|
-
// Current server config (updated on HMR)
|
|
63
|
-
let currentServerConfig: ServerConfig | undefined
|
|
64
|
-
|
|
65
|
-
// Track termination state
|
|
66
|
-
let isTerminating = false
|
|
67
|
-
|
|
68
|
-
function resolveViteRunnerTimeoutMs(): number | undefined {
|
|
69
|
-
const raw = process.env.NMTJS_VITE_RUNNER_TIMEOUT_MS
|
|
70
|
-
if (!raw) return undefined
|
|
71
|
-
|
|
72
|
-
const parsed = Number.parseInt(raw, 10)
|
|
73
|
-
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
74
|
-
logger.warn(
|
|
75
|
-
{ value: raw },
|
|
76
|
-
'Invalid NMTJS_VITE_RUNNER_TIMEOUT_MS, falling back to default',
|
|
77
|
-
)
|
|
78
|
-
return undefined
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
return parsed
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Create the ApplicationServer instance using currentServerConfig.
|
|
86
|
-
*/
|
|
87
|
-
function createServer(): ApplicationServer {
|
|
88
|
-
if (!currentServerConfig) {
|
|
89
|
-
throw new Error('Server config not initialized')
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
const workerConfig = {
|
|
93
|
-
path: fileURLToPath(new URL(`./thread${_ext}`, import.meta.url)),
|
|
94
|
-
workerData: {
|
|
95
|
-
vite: _vite?.mode,
|
|
96
|
-
viteModuleRunnerTimeoutMs: resolveViteRunnerTimeoutMs(),
|
|
97
|
-
},
|
|
98
|
-
worker: _viteServerEvents
|
|
99
|
-
? ({ worker, vitePort }: { worker: Worker; vitePort?: MessagePort }) => {
|
|
100
|
-
_viteServerEvents!.emit('worker', { worker, vitePort })
|
|
101
|
-
}
|
|
102
|
-
: undefined,
|
|
103
|
-
events: _viteServerEvents,
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
return new ApplicationServer(
|
|
107
|
-
currentServerConfig,
|
|
108
|
-
applicationsConfig,
|
|
109
|
-
workerConfig,
|
|
110
|
-
undefined, // runOptions
|
|
111
|
-
errorPolicy,
|
|
112
|
-
defaultWorkerFactory,
|
|
113
|
-
defaultPoolFactory,
|
|
114
|
-
)
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Initialize Vite dev server (dev mode only).
|
|
119
|
-
*/
|
|
120
|
-
async function initializeVite() {
|
|
121
|
-
if (!_vite) return
|
|
122
|
-
|
|
123
|
-
const { createViteServer } = await import('../vite/servers/worker.ts')
|
|
124
|
-
const neemataConfig = await import(
|
|
125
|
-
/* @vite-ignore */
|
|
126
|
-
_vite.options.configPath
|
|
127
|
-
).then((m) => m.default as import('../config.ts').NeemataConfig)
|
|
128
|
-
|
|
129
|
-
_viteServerEvents = new EventEmitter<WorkerServerEventMap>()
|
|
130
|
-
_viteServerEvents.on('hmr-update', handleHMRUpdate)
|
|
131
|
-
|
|
132
|
-
_viteServer = await createViteServer(
|
|
133
|
-
_vite.options,
|
|
134
|
-
_vite.mode,
|
|
135
|
-
neemataConfig,
|
|
136
|
-
_viteServerEvents,
|
|
137
|
-
)
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Initialize the server lifecycle (called once at startup).
|
|
142
|
-
*/
|
|
143
|
-
function initializeLifecycle(configValue: ServerConfig) {
|
|
144
|
-
if (!isServerConfig(configValue)) throw new InvalidServerConfigError()
|
|
145
|
-
|
|
146
|
-
// Store initial config
|
|
147
|
-
currentServerConfig = configValue
|
|
148
|
-
const loggerOptions = currentServerConfig?.logger ?? {
|
|
149
|
-
pinoOptions: { level: isDev ? 'debug' : 'info' },
|
|
150
|
-
}
|
|
151
|
-
logger = createLogger(loggerOptions, 'Main')
|
|
152
|
-
|
|
153
|
-
// Create runtime environment
|
|
154
|
-
const env = createRuntimeEnvironment(mode, {
|
|
155
|
-
vite: _viteServer ?? undefined,
|
|
156
|
-
hmr: undefined, // hmrCoordinator created after lifecycle
|
|
157
|
-
})
|
|
158
|
-
|
|
159
|
-
// Create lifecycle (singleton)
|
|
160
|
-
lifecycle = new ServerLifecycle(env, createServer, logger)
|
|
161
|
-
|
|
162
|
-
// Create HMR coordinator (dev only, singleton)
|
|
163
|
-
if (isDev) {
|
|
164
|
-
hmrCoordinator = new HMRCoordinator(lifecycle, logger)
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// Listen for lifecycle errors (once)
|
|
168
|
-
lifecycle.on('error', (error, handled) => {
|
|
169
|
-
if (!handled) {
|
|
170
|
-
logger.error(new Error('Unhandled lifecycle error', { cause: error }))
|
|
171
|
-
}
|
|
172
|
-
})
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* Set up HMR acceptance for server config changes.
|
|
177
|
-
*/
|
|
178
|
-
function setupHMR() {
|
|
179
|
-
if (!import.meta.env.DEV || !import.meta.hot) return
|
|
180
|
-
|
|
181
|
-
import.meta.hot.accept('#server', async (module) => {
|
|
182
|
-
if (!module) return
|
|
183
|
-
if (!isServerConfig(module.default)) throw new InvalidServerConfigError()
|
|
184
|
-
|
|
185
|
-
// Update the config (createServer will use this on next reload)
|
|
186
|
-
currentServerConfig = module.default
|
|
187
|
-
|
|
188
|
-
// Use HMR coordinator to handle the reload
|
|
189
|
-
if (hmrCoordinator) {
|
|
190
|
-
try {
|
|
191
|
-
await hmrCoordinator.scheduleReload()
|
|
192
|
-
} catch (cause) {
|
|
193
|
-
logger.error(new Error('Error during HMR reload', { cause }))
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
})
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* Handle HMR update event.
|
|
201
|
-
* When an application file is updated and there are failed workers, restart them.
|
|
202
|
-
*/
|
|
203
|
-
async function handleHMRUpdate(_event: { file: string }) {
|
|
204
|
-
// If server is in failed state, try to start it
|
|
205
|
-
if (lifecycle?.currentState === 'failed') {
|
|
206
|
-
try {
|
|
207
|
-
await lifecycle.start()
|
|
208
|
-
} catch {
|
|
209
|
-
// Error will be handled by lifecycle
|
|
210
|
-
}
|
|
211
|
-
return
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
// If server is running, restart any failed workers
|
|
215
|
-
const server = lifecycle?.getServer()
|
|
216
|
-
if (server) {
|
|
217
|
-
try {
|
|
218
|
-
const restarted = await server.restartFailedWorkers()
|
|
219
|
-
if (restarted > 0) {
|
|
220
|
-
logger.info(
|
|
221
|
-
{ count: restarted },
|
|
222
|
-
'Restarted failed workers after HMR update',
|
|
223
|
-
)
|
|
224
|
-
}
|
|
225
|
-
} catch (error) {
|
|
226
|
-
logger.error(
|
|
227
|
-
new Error('Failed to restart workers after HMR update', {
|
|
228
|
-
cause: error,
|
|
229
|
-
}),
|
|
230
|
-
)
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
/**
|
|
236
|
-
* Handle startup error.
|
|
237
|
-
*/
|
|
238
|
-
function handleStartupError(error: unknown) {
|
|
239
|
-
const normalized = error instanceof Error ? error : new Error(String(error))
|
|
240
|
-
logger.error(
|
|
241
|
-
new Error('Failed to start application server', { cause: normalized }),
|
|
242
|
-
)
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
/**
|
|
246
|
-
* Handle process termination signals.
|
|
247
|
-
*/
|
|
248
|
-
async function handleTermination() {
|
|
249
|
-
if (isTerminating) return
|
|
250
|
-
isTerminating = true
|
|
251
|
-
|
|
252
|
-
logger.info('Shutting down...')
|
|
253
|
-
|
|
254
|
-
try {
|
|
255
|
-
await lifecycle?.stop()
|
|
256
|
-
} catch (error) {
|
|
257
|
-
logger.error(new Error('Failed to stop server', { cause: error as Error }))
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
try {
|
|
261
|
-
await _viteServer?.close()
|
|
262
|
-
} catch (error) {
|
|
263
|
-
logger.error(new Error('Failed to close Vite server', { cause: error }))
|
|
264
|
-
}
|
|
265
|
-
process.exit(0)
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
/**
|
|
269
|
-
* Handle unexpected errors.
|
|
270
|
-
*/
|
|
271
|
-
function handleUnexpectedError(error: unknown) {
|
|
272
|
-
const normalized = error instanceof Error ? error : new Error(String(error))
|
|
273
|
-
logger.error(new Error('Unexpected Error', { cause: normalized }))
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
/**
|
|
277
|
-
* Main entry point.
|
|
278
|
-
*/
|
|
279
|
-
async function main() {
|
|
280
|
-
// Set up process handlers
|
|
281
|
-
process.once('SIGTERM', handleTermination)
|
|
282
|
-
process.once('SIGINT', handleTermination)
|
|
283
|
-
process.on('uncaughtException', handleUnexpectedError)
|
|
284
|
-
process.on('unhandledRejection', handleUnexpectedError)
|
|
285
|
-
|
|
286
|
-
// Initialize Vite (dev mode only)
|
|
287
|
-
await initializeVite()
|
|
288
|
-
|
|
289
|
-
// Load server config
|
|
290
|
-
const serverConfig = await import(
|
|
291
|
-
// @ts-expect-error
|
|
292
|
-
'#server'
|
|
293
|
-
).then((m) => m.default)
|
|
294
|
-
|
|
295
|
-
// Initialize lifecycle (sync, creates singletons)
|
|
296
|
-
initializeLifecycle(serverConfig)
|
|
297
|
-
|
|
298
|
-
// Set up HMR
|
|
299
|
-
setupHMR()
|
|
300
|
-
|
|
301
|
-
// Start the server
|
|
302
|
-
try {
|
|
303
|
-
await lifecycle!.start()
|
|
304
|
-
} catch (error) {
|
|
305
|
-
handleStartupError(error)
|
|
306
|
-
if (!isDev) {
|
|
307
|
-
process.exit(1)
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
main().catch((error) => {
|
|
313
|
-
logger.fatal(new Error('Fatal error during startup', { cause: error }))
|
|
314
|
-
if (!isDev) {
|
|
315
|
-
process.exit(1)
|
|
316
|
-
}
|
|
317
|
-
})
|
|
@@ -1,223 +0,0 @@
|
|
|
1
|
-
import type { MessagePort } from 'node:worker_threads'
|
|
2
|
-
import { fileURLToPath } from 'node:url'
|
|
3
|
-
import { workerData as _workerData } from 'node:worker_threads'
|
|
4
|
-
|
|
5
|
-
import type { ModuleRunner } from 'vite/module-runner'
|
|
6
|
-
import { createLogger } from '@nmtjs/core'
|
|
7
|
-
|
|
8
|
-
import type {
|
|
9
|
-
ThreadErrorMessage,
|
|
10
|
-
ThreadPortMessage,
|
|
11
|
-
WorkerThreadErrorOrigin,
|
|
12
|
-
} from '../runtime/index.ts'
|
|
13
|
-
|
|
14
|
-
export type RunWorkerOptions = {
|
|
15
|
-
port: MessagePort
|
|
16
|
-
vitePort?: MessagePort
|
|
17
|
-
runtime:
|
|
18
|
-
| { type: 'application'; name: string; path: string; transportsData: any }
|
|
19
|
-
| { type: 'jobs'; jobWorkerPool: string }
|
|
20
|
-
vite?: 'development' | 'production'
|
|
21
|
-
viteModuleRunnerTimeoutMs?: number
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const workerData = _workerData as RunWorkerOptions
|
|
25
|
-
|
|
26
|
-
const logger = createLogger(
|
|
27
|
-
{
|
|
28
|
-
pinoOptions: {
|
|
29
|
-
level: workerData.vite === 'development' ? 'debug' : 'info',
|
|
30
|
-
},
|
|
31
|
-
},
|
|
32
|
-
'Thread',
|
|
33
|
-
)
|
|
34
|
-
|
|
35
|
-
const ext = new URL(import.meta.url).pathname.endsWith('.ts') ? '.ts' : '.js'
|
|
36
|
-
const workerPath = fileURLToPath(new URL(`./worker${ext}`, import.meta.url))
|
|
37
|
-
|
|
38
|
-
type WorkerModule = typeof import('./worker.ts')
|
|
39
|
-
type WorkerRuntime = Awaited<ReturnType<WorkerModule['run']>>
|
|
40
|
-
|
|
41
|
-
const kReportedError = Symbol.for('nmtjs.worker.reported-error')
|
|
42
|
-
|
|
43
|
-
let runner: ModuleRunner | undefined
|
|
44
|
-
let workerModule: WorkerModule
|
|
45
|
-
let runtime: WorkerRuntime | undefined
|
|
46
|
-
let runtimeStarted = false
|
|
47
|
-
let cleanupPromise: Promise<void> | null = null
|
|
48
|
-
|
|
49
|
-
process.on('uncaughtException', (error) => {
|
|
50
|
-
reportError(error, 'runtime', { fatal: true })
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
process.on('unhandledRejection', (error) => {
|
|
54
|
-
reportError(error, 'runtime', { fatal: true })
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
process.once('SIGTERM', () => {
|
|
58
|
-
void terminate(0)
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
process.once('SIGINT', () => {
|
|
62
|
-
void terminate(0)
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
process.once('beforeExit', () => {
|
|
66
|
-
if (!cleanupPromise && (runtimeStarted || runner)) {
|
|
67
|
-
void cleanup()
|
|
68
|
-
}
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
async function cleanup() {
|
|
72
|
-
if (cleanupPromise) return cleanupPromise
|
|
73
|
-
|
|
74
|
-
cleanupPromise = (async () => {
|
|
75
|
-
await stopRuntime()
|
|
76
|
-
await closeRunner()
|
|
77
|
-
})().finally(() => {
|
|
78
|
-
cleanupPromise = null
|
|
79
|
-
})
|
|
80
|
-
|
|
81
|
-
return cleanupPromise
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
async function terminate(code: number) {
|
|
85
|
-
await cleanup()
|
|
86
|
-
process.exit(code)
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
async function closeRunner() {
|
|
90
|
-
if (!runner) return
|
|
91
|
-
try {
|
|
92
|
-
await runner.close()
|
|
93
|
-
} catch (error) {
|
|
94
|
-
reportError(error, 'runtime', { fatal: false })
|
|
95
|
-
} finally {
|
|
96
|
-
runner = undefined
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
async function stopRuntime() {
|
|
101
|
-
if (!runtime) return
|
|
102
|
-
try {
|
|
103
|
-
if (runtimeStarted) {
|
|
104
|
-
await runtime.stop()
|
|
105
|
-
}
|
|
106
|
-
} catch (error) {
|
|
107
|
-
reportError(error, 'runtime', { fatal: false })
|
|
108
|
-
} finally {
|
|
109
|
-
runtimeStarted = false
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
function normalizeError(value: unknown): Error {
|
|
114
|
-
if (value instanceof Error) return value
|
|
115
|
-
if (typeof value === 'string') return new Error(value)
|
|
116
|
-
if (value && typeof value === 'object') {
|
|
117
|
-
try {
|
|
118
|
-
return new Error(JSON.stringify(value))
|
|
119
|
-
} catch {}
|
|
120
|
-
}
|
|
121
|
-
return new Error(String(value))
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
function serializeError(
|
|
125
|
-
error: Error,
|
|
126
|
-
origin: WorkerThreadErrorOrigin,
|
|
127
|
-
fatal: boolean,
|
|
128
|
-
): ThreadErrorMessage {
|
|
129
|
-
return {
|
|
130
|
-
message: error.message,
|
|
131
|
-
name: error.name,
|
|
132
|
-
stack: error.stack,
|
|
133
|
-
origin,
|
|
134
|
-
fatal,
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
function reportError(
|
|
139
|
-
value: unknown,
|
|
140
|
-
origin: WorkerThreadErrorOrigin,
|
|
141
|
-
options: { fatal?: boolean } = {},
|
|
142
|
-
): Error {
|
|
143
|
-
const fatal = options.fatal ?? origin !== 'runtime'
|
|
144
|
-
const error = normalizeError(value)
|
|
145
|
-
if (!(error as any)[kReportedError]) {
|
|
146
|
-
try {
|
|
147
|
-
workerData.port.postMessage({
|
|
148
|
-
type: 'error',
|
|
149
|
-
data: serializeError(error, origin, fatal),
|
|
150
|
-
} satisfies ThreadPortMessage)
|
|
151
|
-
} catch {}
|
|
152
|
-
logger.error(new Error(`Worker thread ${origin} error`, { cause: error }))
|
|
153
|
-
;(error as any)[kReportedError] = true
|
|
154
|
-
}
|
|
155
|
-
return error
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
async function loadWorkerModule() {
|
|
159
|
-
try {
|
|
160
|
-
if (workerData.vite) {
|
|
161
|
-
const { createModuleRunner } = (await import(
|
|
162
|
-
'../vite/runners/worker.ts'
|
|
163
|
-
)) as typeof import('../vite/runners/worker.ts')
|
|
164
|
-
|
|
165
|
-
runner = createModuleRunner(
|
|
166
|
-
workerData.vitePort,
|
|
167
|
-
workerData.vite,
|
|
168
|
-
workerData.viteModuleRunnerTimeoutMs,
|
|
169
|
-
)
|
|
170
|
-
workerModule = await runner.import(workerPath)
|
|
171
|
-
} else {
|
|
172
|
-
runner = undefined
|
|
173
|
-
workerModule = await import(
|
|
174
|
-
/* @vite-ignore */
|
|
175
|
-
workerPath
|
|
176
|
-
)
|
|
177
|
-
}
|
|
178
|
-
} catch (error) {
|
|
179
|
-
throw reportError(error, 'bootstrap')
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
async function initializeRuntime() {
|
|
184
|
-
try {
|
|
185
|
-
runtime = await workerModule.run(workerData.runtime)
|
|
186
|
-
} catch (error) {
|
|
187
|
-
throw reportError(error, 'bootstrap')
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
workerData.port.on('message', async (msg) => {
|
|
191
|
-
if (msg.type === 'stop') {
|
|
192
|
-
await terminate(0)
|
|
193
|
-
}
|
|
194
|
-
})
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
async function startRuntime() {
|
|
198
|
-
if (!runtime) return
|
|
199
|
-
try {
|
|
200
|
-
const hosts = (await runtime.start()) || undefined
|
|
201
|
-
runtimeStarted = true
|
|
202
|
-
workerData.port.postMessage({
|
|
203
|
-
type: 'ready',
|
|
204
|
-
data: { hosts },
|
|
205
|
-
} satisfies ThreadPortMessage)
|
|
206
|
-
} catch (error) {
|
|
207
|
-
throw reportError(error, 'start')
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
async function main() {
|
|
212
|
-
await loadWorkerModule()
|
|
213
|
-
await initializeRuntime()
|
|
214
|
-
await startRuntime()
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
main().catch(async (error) => {
|
|
218
|
-
const normalized = error instanceof Error ? error : normalizeError(error)
|
|
219
|
-
if (!(normalized as any)[kReportedError]) {
|
|
220
|
-
reportError(normalized, 'bootstrap')
|
|
221
|
-
}
|
|
222
|
-
await terminate(1)
|
|
223
|
-
})
|
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
import { workerData } from 'node:worker_threads'
|
|
2
|
-
|
|
3
|
-
import type { ServerConfig } from '../runtime/index.ts'
|
|
4
|
-
import type { RunWorkerOptions } from './thread.ts'
|
|
5
|
-
import {
|
|
6
|
-
ApplicationWorkerRuntime,
|
|
7
|
-
isApplicationHostDefinition,
|
|
8
|
-
JobWorkerRuntime,
|
|
9
|
-
} from '../runtime/index.ts'
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Worker entry point.
|
|
13
|
-
*
|
|
14
|
-
* Handles initialization of application or job worker runtimes.
|
|
15
|
-
* Includes HMR supersede logic for application workers.
|
|
16
|
-
*/
|
|
17
|
-
export async function run(options: RunWorkerOptions['runtime']) {
|
|
18
|
-
const serverConfig: ServerConfig = await import(
|
|
19
|
-
// @ts-expect-error
|
|
20
|
-
'#server'
|
|
21
|
-
).then((m) => m.default)
|
|
22
|
-
|
|
23
|
-
if (options.type === 'application') {
|
|
24
|
-
return initializeApplicationWorker(options, serverConfig)
|
|
25
|
-
} else if (options.type === 'jobs') {
|
|
26
|
-
return initializeJobWorker(options, serverConfig)
|
|
27
|
-
} else {
|
|
28
|
-
throw new Error(`Unknown runtime type: ${(options as any).type}`)
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Initialize an application worker with HMR support.
|
|
34
|
-
*/
|
|
35
|
-
async function initializeApplicationWorker(
|
|
36
|
-
options: Extract<RunWorkerOptions['runtime'], { type: 'application' }>,
|
|
37
|
-
serverConfig: ServerConfig,
|
|
38
|
-
) {
|
|
39
|
-
const { name, path, transportsData } = options
|
|
40
|
-
|
|
41
|
-
// Load initial application host definition
|
|
42
|
-
const hostDefinition = await import(
|
|
43
|
-
/* @vite-ignore */
|
|
44
|
-
path
|
|
45
|
-
).then((m) => m.default)
|
|
46
|
-
|
|
47
|
-
if (!isApplicationHostDefinition(hostDefinition)) {
|
|
48
|
-
throw new Error(`Invalid application host definition: ${name}`)
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// Create runtime
|
|
52
|
-
const runtime = new ApplicationWorkerRuntime(
|
|
53
|
-
serverConfig,
|
|
54
|
-
{ name, path, transports: transportsData },
|
|
55
|
-
hostDefinition,
|
|
56
|
-
)
|
|
57
|
-
|
|
58
|
-
// Set up HMR with supersede logic
|
|
59
|
-
setupApplicationHMR(runtime)
|
|
60
|
-
|
|
61
|
-
return runtime
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Set up HMR acceptance for application host definition changes with supersede logic.
|
|
66
|
-
*
|
|
67
|
-
* When a reload is in progress and another HMR event arrives, the pending
|
|
68
|
-
* reload is superseded - only the most recent config is applied.
|
|
69
|
-
*/
|
|
70
|
-
function setupApplicationHMR(runtime: ApplicationWorkerRuntime) {
|
|
71
|
-
const logger = runtime.logger.child({ component: 'HMR' })
|
|
72
|
-
|
|
73
|
-
// Track active reload
|
|
74
|
-
let activeReload: Promise<void> | null = null
|
|
75
|
-
|
|
76
|
-
// Track pending reload (supersedes previous pending)
|
|
77
|
-
let pendingConfig: unknown | null = null
|
|
78
|
-
let pendingResolve: (() => void) | null = null
|
|
79
|
-
let pendingReject: ((e: Error) => void) | null = null
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Execute a reload with the given config.
|
|
83
|
-
*/
|
|
84
|
-
const executeReload = async (config: any): Promise<void> => {
|
|
85
|
-
activeReload = doReload(config)
|
|
86
|
-
|
|
87
|
-
try {
|
|
88
|
-
await activeReload
|
|
89
|
-
} finally {
|
|
90
|
-
activeReload = null
|
|
91
|
-
|
|
92
|
-
// If there's a pending reload, execute it now
|
|
93
|
-
if (pendingConfig !== null) {
|
|
94
|
-
const config = pendingConfig
|
|
95
|
-
const resolve = pendingResolve!
|
|
96
|
-
const reject = pendingReject!
|
|
97
|
-
|
|
98
|
-
pendingConfig = null
|
|
99
|
-
pendingResolve = null
|
|
100
|
-
pendingReject = null
|
|
101
|
-
|
|
102
|
-
executeReload(config).then(resolve, reject)
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Perform the actual reload.
|
|
109
|
-
*/
|
|
110
|
-
const doReload = async (config: any): Promise<void> => {
|
|
111
|
-
try {
|
|
112
|
-
logger.debug('Reloading application...')
|
|
113
|
-
await runtime.reload(config)
|
|
114
|
-
logger.info('Application reloaded successfully')
|
|
115
|
-
} catch (error) {
|
|
116
|
-
// Log error but keep worker alive for next HMR update
|
|
117
|
-
logger.error(new Error('Error during HMR reload', { cause: error }))
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Schedule a reload. If reload is in progress, supersedes any pending.
|
|
123
|
-
*/
|
|
124
|
-
const scheduleReload = (config: any): Promise<void> => {
|
|
125
|
-
// If no active reload, execute immediately
|
|
126
|
-
if (!activeReload) {
|
|
127
|
-
return executeReload(config)
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
logger.debug('Reload in progress, queuing update...')
|
|
131
|
-
// Supersede any existing pending reload
|
|
132
|
-
if (pendingResolve) {
|
|
133
|
-
logger.debug('Superseding previous pending reload')
|
|
134
|
-
pendingResolve() // Resolve old pending (it's superseded)
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// Create new pending
|
|
138
|
-
return new Promise((resolve, reject) => {
|
|
139
|
-
pendingConfig = config
|
|
140
|
-
pendingResolve = resolve
|
|
141
|
-
pendingReject = reject
|
|
142
|
-
})
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// Register global hot accept handler
|
|
146
|
-
globalThis._hotAccept = async (module: any) => {
|
|
147
|
-
logger.debug('Received HMR update')
|
|
148
|
-
if (!module) return
|
|
149
|
-
|
|
150
|
-
if (!isApplicationHostDefinition(module.default)) {
|
|
151
|
-
logger.error(
|
|
152
|
-
new Error('Invalid application host definition during HMR reload'),
|
|
153
|
-
)
|
|
154
|
-
return
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
await scheduleReload(module.default)
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* Initialize a job worker.
|
|
163
|
-
*/
|
|
164
|
-
async function initializeJobWorker(
|
|
165
|
-
options: Extract<RunWorkerOptions['runtime'], { type: 'jobs' }>,
|
|
166
|
-
serverConfig: ServerConfig,
|
|
167
|
-
) {
|
|
168
|
-
const { jobWorkerPool } = options
|
|
169
|
-
const runtime = new JobWorkerRuntime(serverConfig, {
|
|
170
|
-
poolName: jobWorkerPool,
|
|
171
|
-
port: workerData.port,
|
|
172
|
-
})
|
|
173
|
-
return runtime
|
|
174
|
-
}
|