nmtjs 0.15.0-beta.2 → 0.15.0-beta.21
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/cli.d.ts +2 -0
- package/dist/cli.js +3 -2
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +51 -0
- package/dist/config.js +1 -0
- package/dist/config.js.map +1 -0
- package/dist/entrypoints/cli.d.ts +1 -0
- package/dist/entrypoints/cli.js +1 -0
- package/dist/entrypoints/cli.js.map +1 -0
- package/dist/entrypoints/main.d.ts +5 -0
- package/dist/entrypoints/main.js +83 -15
- package/dist/entrypoints/main.js.map +1 -0
- package/dist/entrypoints/thread.d.ts +14 -0
- package/dist/entrypoints/thread.js +130 -24
- package/dist/entrypoints/thread.js.map +1 -0
- package/dist/entrypoints/worker.d.ts +3 -0
- package/dist/entrypoints/worker.js +4 -3
- package/dist/entrypoints/worker.js.map +1 -0
- package/dist/index.d.ts +69 -0
- package/dist/{_exports/index.js → index.js} +9 -5
- package/dist/index.js.map +1 -0
- package/dist/resolver.d.ts +2 -0
- package/dist/resolver.js +1 -0
- package/dist/resolver.js.map +1 -0
- package/dist/runtime/application/api/api.d.ts +49 -0
- package/dist/runtime/application/api/api.js +193 -0
- package/dist/runtime/application/api/api.js.map +1 -0
- package/dist/runtime/application/api/constants.d.ts +14 -0
- package/dist/runtime/application/api/constants.js +8 -0
- package/dist/runtime/application/api/constants.js.map +1 -0
- package/dist/runtime/application/api/filters.d.ts +14 -0
- package/dist/runtime/application/api/filters.js +11 -0
- package/dist/runtime/application/api/filters.js.map +1 -0
- package/dist/runtime/application/api/guards.d.ts +13 -0
- package/dist/runtime/application/api/guards.js +8 -0
- package/dist/runtime/application/api/guards.js.map +1 -0
- package/dist/runtime/application/api/index.d.ts +8 -0
- package/dist/runtime/application/api/index.js +9 -0
- package/dist/runtime/application/api/index.js.map +1 -0
- package/dist/runtime/application/api/middlewares.d.ts +14 -0
- package/dist/runtime/application/api/middlewares.js +12 -0
- package/dist/runtime/application/api/middlewares.js.map +1 -0
- package/dist/runtime/application/api/procedure.d.ts +67 -0
- package/dist/runtime/application/api/procedure.js +50 -0
- package/dist/runtime/application/api/procedure.js.map +1 -0
- package/dist/runtime/application/api/router.d.ts +71 -0
- package/dist/runtime/application/api/router.js +51 -0
- package/dist/runtime/application/api/router.js.map +1 -0
- package/dist/runtime/application/api/types.d.ts +32 -0
- package/dist/runtime/application/api/types.js +2 -0
- package/dist/runtime/application/api/types.js.map +1 -0
- package/dist/runtime/application/config.d.ts +26 -0
- package/dist/runtime/application/config.js +21 -0
- package/dist/runtime/application/config.js.map +1 -0
- package/dist/runtime/application/constants.d.ts +2 -0
- package/dist/runtime/application/constants.js +2 -0
- package/dist/runtime/application/constants.js.map +1 -0
- package/dist/runtime/application/hook.d.ts +19 -0
- package/dist/runtime/application/hook.js +11 -0
- package/dist/runtime/application/hook.js.map +1 -0
- package/dist/runtime/application/hooks.d.ts +3 -0
- package/dist/runtime/application/hooks.js +4 -0
- package/dist/runtime/application/hooks.js.map +1 -0
- package/dist/runtime/application/index.d.ts +5 -0
- package/dist/runtime/application/index.js +6 -0
- package/dist/runtime/application/index.js.map +1 -0
- package/dist/runtime/constants.d.ts +8 -0
- package/dist/runtime/constants.js +5 -0
- package/dist/runtime/constants.js.map +1 -0
- package/dist/runtime/core/hooks.d.ts +4 -0
- package/dist/runtime/core/hooks.js +4 -0
- package/dist/runtime/core/hooks.js.map +1 -0
- package/dist/runtime/core/plugin.d.ts +8 -0
- package/dist/runtime/core/plugin.js +4 -0
- package/dist/runtime/core/plugin.js.map +1 -0
- package/dist/runtime/core/runtime.d.ts +27 -0
- package/dist/runtime/core/runtime.js +81 -0
- package/dist/runtime/core/runtime.js.map +1 -0
- package/dist/runtime/enums.d.ts +21 -0
- package/dist/runtime/enums.js +26 -0
- package/dist/runtime/enums.js.map +1 -0
- package/dist/runtime/index.d.ts +21 -0
- package/dist/runtime/index.js +22 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/injectables.d.ts +23 -0
- package/dist/runtime/injectables.js +20 -0
- package/dist/runtime/injectables.js.map +1 -0
- package/dist/runtime/jobs/job.d.ts +132 -0
- package/dist/runtime/jobs/job.js +68 -0
- package/dist/runtime/jobs/job.js.map +1 -0
- package/dist/runtime/jobs/manager.d.ts +113 -0
- package/dist/runtime/jobs/manager.js +210 -0
- package/dist/runtime/jobs/manager.js.map +1 -0
- package/dist/runtime/jobs/router.d.ts +266 -0
- package/dist/runtime/jobs/router.js +432 -0
- package/dist/runtime/jobs/router.js.map +1 -0
- package/dist/runtime/jobs/runner.d.ts +64 -0
- package/dist/runtime/jobs/runner.js +256 -0
- package/dist/runtime/jobs/runner.js.map +1 -0
- package/dist/runtime/jobs/step.d.ts +23 -0
- package/dist/runtime/jobs/step.js +18 -0
- package/dist/runtime/jobs/step.js.map +1 -0
- package/dist/runtime/jobs/ui.d.ts +3 -0
- package/dist/runtime/jobs/ui.js +17 -0
- package/dist/runtime/jobs/ui.js.map +1 -0
- package/dist/runtime/pubsub/manager.d.ts +48 -0
- package/dist/runtime/pubsub/manager.js +119 -0
- package/dist/runtime/pubsub/manager.js.map +1 -0
- package/dist/runtime/pubsub/redis.d.ts +16 -0
- package/dist/runtime/pubsub/redis.js +98 -0
- package/dist/runtime/pubsub/redis.js.map +1 -0
- package/dist/runtime/scheduler/index.d.ts +22 -0
- package/dist/runtime/scheduler/index.js +20 -0
- package/dist/runtime/scheduler/index.js.map +1 -0
- package/dist/runtime/server/applications.d.ts +52 -0
- package/dist/runtime/server/applications.js +133 -0
- package/dist/runtime/server/applications.js.map +1 -0
- package/dist/runtime/server/config.d.ts +121 -0
- package/dist/runtime/server/config.js +33 -0
- package/dist/runtime/server/config.js.map +1 -0
- package/dist/runtime/server/jobs.d.ts +41 -0
- package/dist/runtime/server/jobs.js +181 -0
- package/dist/runtime/server/jobs.js.map +1 -0
- package/dist/runtime/server/pool.d.ts +54 -0
- package/dist/runtime/server/pool.js +194 -0
- package/dist/runtime/server/pool.js.map +1 -0
- package/dist/runtime/server/proxy.d.ts +21 -0
- package/dist/runtime/server/proxy.js +79 -0
- package/dist/runtime/server/proxy.js.map +1 -0
- package/dist/runtime/server/server.d.ts +53 -0
- package/dist/runtime/server/server.js +90 -0
- package/dist/runtime/server/server.js.map +1 -0
- package/dist/runtime/store/index.d.ts +3 -0
- package/dist/runtime/store/index.js +23 -0
- package/dist/runtime/store/index.js.map +1 -0
- package/dist/runtime/types.d.ts +103 -0
- package/dist/runtime/types.js +2 -0
- package/dist/runtime/types.js.map +1 -0
- package/dist/runtime/workers/application.d.ts +47 -0
- package/dist/runtime/workers/application.js +162 -0
- package/dist/runtime/workers/application.js.map +1 -0
- package/dist/runtime/workers/base.d.ts +16 -0
- package/dist/runtime/workers/base.js +46 -0
- package/dist/runtime/workers/base.js.map +1 -0
- package/dist/runtime/workers/cli.d.ts +1 -0
- package/dist/runtime/workers/cli.js +2 -0
- package/dist/runtime/workers/cli.js.map +1 -0
- package/dist/runtime/workers/job.d.ts +20 -0
- package/dist/runtime/workers/job.js +172 -0
- package/dist/runtime/workers/job.js.map +1 -0
- package/dist/typings.d.ts +5 -0
- package/dist/typings.js +4 -3
- package/dist/typings.js.map +1 -0
- package/dist/vite/builder.d.ts +5 -0
- package/dist/vite/builder.js +5 -1
- package/dist/vite/builder.js.map +1 -0
- package/dist/vite/config.d.ts +28 -0
- package/dist/vite/config.js +1 -0
- package/dist/vite/config.js.map +1 -0
- package/dist/vite/plugins.d.ts +2 -0
- package/dist/vite/plugins.js +1 -0
- package/dist/vite/plugins.js.map +1 -0
- package/dist/vite/runners/worker.d.ts +4 -0
- package/dist/vite/runners/worker.js +1 -0
- package/dist/vite/runners/worker.js.map +1 -0
- package/dist/vite/server.d.ts +3 -0
- package/dist/vite/server.js +6 -1
- package/dist/vite/server.js.map +1 -0
- package/dist/vite/servers/main.d.ts +8 -0
- package/dist/vite/servers/main.js +1 -0
- package/dist/vite/servers/main.js.map +1 -0
- package/dist/vite/servers/worker.d.ts +11 -0
- package/dist/vite/servers/worker.js +28 -0
- package/dist/vite/servers/worker.js.map +1 -0
- package/package.json +31 -18
- package/src/cli.ts +144 -0
- package/src/config.ts +64 -0
- package/src/entrypoints/cli.ts +13 -0
- package/src/entrypoints/main.ts +200 -0
- package/src/entrypoints/thread.ts +184 -0
- package/src/entrypoints/worker.ts +48 -0
- package/src/index.ts +82 -0
- package/src/resolver.ts +16 -0
- package/src/runtime/application/api/api.ts +265 -0
- package/src/runtime/application/api/constants.ts +22 -0
- package/src/runtime/application/api/filters.ts +39 -0
- package/src/runtime/application/api/guards.ts +29 -0
- package/src/runtime/application/api/index.ts +8 -0
- package/src/runtime/application/api/middlewares.ts +37 -0
- package/src/runtime/application/api/procedure.ts +229 -0
- package/src/runtime/application/api/router.ts +193 -0
- package/src/runtime/application/api/types.ts +124 -0
- package/src/runtime/application/config.ts +69 -0
- package/src/runtime/application/constants.ts +4 -0
- package/src/runtime/application/hook.ts +51 -0
- package/src/runtime/application/hooks.ts +3 -0
- package/src/runtime/application/index.ts +5 -0
- package/src/runtime/constants.ts +13 -0
- package/src/runtime/core/hooks.ts +5 -0
- package/src/runtime/core/plugin.ts +13 -0
- package/src/runtime/core/runtime.ts +109 -0
- package/src/runtime/enums.ts +24 -0
- package/src/runtime/index.ts +21 -0
- package/src/runtime/injectables.ts +61 -0
- package/src/runtime/jobs/job.ts +370 -0
- package/src/runtime/jobs/manager.ts +348 -0
- package/src/runtime/jobs/router.ts +896 -0
- package/src/runtime/jobs/runner.ts +320 -0
- package/src/runtime/jobs/step.ts +66 -0
- package/src/runtime/jobs/ui.ts +21 -0
- package/src/runtime/pubsub/manager.ts +211 -0
- package/src/runtime/pubsub/redis.ts +108 -0
- package/src/runtime/scheduler/index.ts +39 -0
- package/src/runtime/server/applications.ts +210 -0
- package/src/runtime/server/config.ts +158 -0
- package/src/runtime/server/jobs.ts +250 -0
- package/src/runtime/server/pool.ts +260 -0
- package/src/runtime/server/proxy.ts +118 -0
- package/src/runtime/server/server.ts +155 -0
- package/src/runtime/store/index.ts +30 -0
- package/src/runtime/types.ts +93 -0
- package/src/runtime/workers/application.ts +209 -0
- package/src/runtime/workers/base.ts +68 -0
- package/src/runtime/workers/cli.ts +0 -0
- package/src/runtime/workers/job.ts +153 -0
- package/src/typings.ts +30 -0
- package/src/vite/builder.ts +122 -0
- package/src/vite/config.ts +45 -0
- package/src/vite/plugins.ts +26 -0
- package/src/vite/runners/worker.ts +57 -0
- package/src/vite/server.ts +39 -0
- package/src/vite/servers/main.ts +34 -0
- package/src/vite/servers/worker.ts +143 -0
- package/dist/_exports/application.js +0 -1
- package/dist/_exports/common.js +0 -1
- package/dist/_exports/contract.js +0 -2
- package/dist/_exports/core.js +0 -1
- package/dist/_exports/gateway.js +0 -1
- package/dist/_exports/http-transport/bun.js +0 -1
- package/dist/_exports/http-transport/deno.js +0 -1
- package/dist/_exports/http-transport/node.js +0 -1
- package/dist/_exports/http-transport.js +0 -1
- package/dist/_exports/json-format.js +0 -1
- package/dist/_exports/protocol/client.js +0 -1
- package/dist/_exports/protocol/server.js +0 -1
- package/dist/_exports/protocol.js +0 -1
- package/dist/_exports/runtime/types.js +0 -1
- package/dist/_exports/runtime.js +0 -1
- package/dist/_exports/type.js +0 -2
- package/dist/_exports/ws-transport/bun.js +0 -1
- package/dist/_exports/ws-transport/deno.js +0 -1
- package/dist/_exports/ws-transport/node.js +0 -1
- package/dist/_exports/ws-transport.js +0 -1
- package/dist/command.js +0 -30
package/src/cli.ts
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
#!/usr/bin/env node --enable-source-maps
|
|
2
|
+
|
|
3
|
+
import { once } from 'node:events'
|
|
4
|
+
import { relative, resolve } from 'node:path'
|
|
5
|
+
import process from 'node:process'
|
|
6
|
+
|
|
7
|
+
import type { ArgDef } from 'citty'
|
|
8
|
+
import { defineCommand, runMain } from 'citty'
|
|
9
|
+
import { config as dotenv } from 'dotenv'
|
|
10
|
+
|
|
11
|
+
import type { NeemataConfig } from './config.ts'
|
|
12
|
+
import type { ViteConfigOptions } from './vite/config.ts'
|
|
13
|
+
import { resolver } from './resolver.ts'
|
|
14
|
+
import { generateTypings } from './typings.ts'
|
|
15
|
+
import { createBuilder } from './vite/builder.ts'
|
|
16
|
+
import { baseViteConfigOptions } from './vite/config.ts'
|
|
17
|
+
import { createMainServer } from './vite/servers/main.ts'
|
|
18
|
+
|
|
19
|
+
// import { createMainRunner } from './vite/runner.ts'
|
|
20
|
+
|
|
21
|
+
const commonArgs = {
|
|
22
|
+
config: {
|
|
23
|
+
type: 'string',
|
|
24
|
+
alias: 'c',
|
|
25
|
+
default: './neemata.config.ts',
|
|
26
|
+
description: 'Path to Neemata config file',
|
|
27
|
+
required: false,
|
|
28
|
+
},
|
|
29
|
+
} satisfies Record<string, ArgDef>
|
|
30
|
+
|
|
31
|
+
let config: NeemataConfig
|
|
32
|
+
let viteConfigOptions: ViteConfigOptions
|
|
33
|
+
let applicationImports: Record<
|
|
34
|
+
string,
|
|
35
|
+
{ path: string; specifier: string; type: 'neemata' | 'custom' }
|
|
36
|
+
>
|
|
37
|
+
|
|
38
|
+
const mainCommand = defineCommand({
|
|
39
|
+
meta: { description: 'Neemata CLI' },
|
|
40
|
+
args: { ...commonArgs },
|
|
41
|
+
async setup(ctx) {
|
|
42
|
+
const configPath = resolve(ctx.args.config as string)
|
|
43
|
+
config = await import(configPath).then((m) => m.default)
|
|
44
|
+
|
|
45
|
+
for (const env of config.env) {
|
|
46
|
+
if (typeof env === 'string') {
|
|
47
|
+
const { error } = dotenv({ path: env })
|
|
48
|
+
if (error) console.warn(error)
|
|
49
|
+
} else if (typeof env === 'object') {
|
|
50
|
+
for (const key in env) {
|
|
51
|
+
process.env[key] = env[key]
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// const applicationEntryPaths: Record<string, string> = {}
|
|
57
|
+
applicationImports = {}
|
|
58
|
+
const currentPkg = resolver.sync(process.cwd(), './package.json')
|
|
59
|
+
|
|
60
|
+
for (const [appName, { specifier: appSpecifier, type }] of Object.entries(
|
|
61
|
+
config.applications,
|
|
62
|
+
)) {
|
|
63
|
+
const resolution = resolver.sync(process.cwd(), appSpecifier)
|
|
64
|
+
if (resolution.error)
|
|
65
|
+
throw new Error(
|
|
66
|
+
`Failed to resolve application path for ${appName}: ${resolution.error}`,
|
|
67
|
+
)
|
|
68
|
+
if (!resolution.path)
|
|
69
|
+
throw new Error(
|
|
70
|
+
`Failed to resolve application path for ${appName}: no path found`,
|
|
71
|
+
)
|
|
72
|
+
const specifier =
|
|
73
|
+
resolution.packageJsonPath === currentPkg.path
|
|
74
|
+
? relative(resolve('.neemata'), resolution.path)
|
|
75
|
+
: appSpecifier
|
|
76
|
+
applicationImports[appName] = { path: resolution.path, specifier, type }
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
viteConfigOptions = {
|
|
80
|
+
applicationImports,
|
|
81
|
+
serverEntryPath: resolve(config.serverPath),
|
|
82
|
+
...baseViteConfigOptions,
|
|
83
|
+
configPath,
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
subCommands: {
|
|
87
|
+
prepare: defineCommand({
|
|
88
|
+
async run(ctx) {
|
|
89
|
+
await generateTypings(applicationImports)
|
|
90
|
+
},
|
|
91
|
+
}),
|
|
92
|
+
dev: defineCommand({
|
|
93
|
+
async run(ctx) {
|
|
94
|
+
const { runner } = await createMainServer(
|
|
95
|
+
viteConfigOptions,
|
|
96
|
+
'development',
|
|
97
|
+
config,
|
|
98
|
+
)
|
|
99
|
+
await runner.import(viteConfigOptions.entrypointMainPath)
|
|
100
|
+
await once(process, 'beforeExit')
|
|
101
|
+
},
|
|
102
|
+
}),
|
|
103
|
+
preview: defineCommand({
|
|
104
|
+
async run(ctx) {
|
|
105
|
+
const { runner } = await createMainServer(
|
|
106
|
+
viteConfigOptions,
|
|
107
|
+
'production',
|
|
108
|
+
config,
|
|
109
|
+
)
|
|
110
|
+
await runner.import(viteConfigOptions.entrypointMainPath)
|
|
111
|
+
await once(process, 'beforeExit')
|
|
112
|
+
},
|
|
113
|
+
}),
|
|
114
|
+
build: defineCommand({
|
|
115
|
+
async run(ctx) {
|
|
116
|
+
const builder = await createBuilder(viteConfigOptions, config)
|
|
117
|
+
await builder.build()
|
|
118
|
+
},
|
|
119
|
+
}),
|
|
120
|
+
// command: defineCommand({
|
|
121
|
+
// async run(ctx) {
|
|
122
|
+
// const runner = await createRunner(
|
|
123
|
+
// viteConfigOptions,
|
|
124
|
+
// 'production',
|
|
125
|
+
// config,
|
|
126
|
+
// )
|
|
127
|
+
// const workerModule = await runner.import<
|
|
128
|
+
// typeof import('./entrypoints/worker.ts')
|
|
129
|
+
// >(import.meta.resolve('./entrypoints/worker.js'))
|
|
130
|
+
// const commandModule = await runner.import<
|
|
131
|
+
// typeof import('./command.ts')
|
|
132
|
+
// >(import.meta.resolve('./command.js'))
|
|
133
|
+
// const worker = await workerModule.default({
|
|
134
|
+
// applicationWorkerData: undefined,
|
|
135
|
+
// type: ApplicationType.Command,
|
|
136
|
+
// workerType: ApplicationWorkerType.Command,
|
|
137
|
+
// })
|
|
138
|
+
// await runMain(commandModule.default(worker), { rawArgs: ctx.rawArgs })
|
|
139
|
+
// },
|
|
140
|
+
// }),
|
|
141
|
+
},
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
runMain(mainCommand)
|
package/src/config.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { Plugin as VitePlugin } from 'vite'
|
|
2
|
+
|
|
3
|
+
export type ExtrernalDependency = string | RegExp
|
|
4
|
+
|
|
5
|
+
type DeepPartial<T> = {
|
|
6
|
+
[P in keyof T]?: T[P] extends Record<any, unknown> ? DeepPartial<T[P]> : T[P]
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface NeemataConfig {
|
|
10
|
+
/**
|
|
11
|
+
* Path to application entry point
|
|
12
|
+
*/
|
|
13
|
+
applications: {
|
|
14
|
+
/**
|
|
15
|
+
* Application name
|
|
16
|
+
*/
|
|
17
|
+
[appName: string]: { type: 'neemata' | 'custom'; specifier: string }
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Path to server entry point
|
|
21
|
+
*/
|
|
22
|
+
serverPath: string
|
|
23
|
+
/**
|
|
24
|
+
* External dependencies to exclude from application bundle
|
|
25
|
+
*
|
|
26
|
+
* 'prod' - exclude production dependencies from package.json
|
|
27
|
+
*
|
|
28
|
+
* 'all' - exclude all dependencies from package.json
|
|
29
|
+
*
|
|
30
|
+
* ExtrernalDependency[] - array of package names or regular expressions to match package names
|
|
31
|
+
*/
|
|
32
|
+
externalDependencies: 'prod' | 'all' | ExtrernalDependency[]
|
|
33
|
+
/**
|
|
34
|
+
* Timeout in milliseconds for graceful shutdown of application workers
|
|
35
|
+
*/
|
|
36
|
+
timeout: number
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Environment variables to set for application workers
|
|
40
|
+
*
|
|
41
|
+
* Strings are paths to .env files
|
|
42
|
+
* Records are key-value pairs to set directly
|
|
43
|
+
*/
|
|
44
|
+
env: (Record<string, string> | string)[]
|
|
45
|
+
|
|
46
|
+
build: { outDir: string; minify: boolean }
|
|
47
|
+
plugins: VitePlugin[]
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function defineConfig(
|
|
51
|
+
config: DeepPartial<NeemataConfig> = {},
|
|
52
|
+
): NeemataConfig {
|
|
53
|
+
return {
|
|
54
|
+
serverPath: './src/server.ts',
|
|
55
|
+
externalDependencies: 'prod',
|
|
56
|
+
timeout: 10000,
|
|
57
|
+
env: [],
|
|
58
|
+
plugins: [],
|
|
59
|
+
...config,
|
|
60
|
+
// @ts-expect-error
|
|
61
|
+
applications: config.applications || {},
|
|
62
|
+
build: { outDir: './dist', minify: true, ...config.build },
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// // import { ApplicationType, ApplicationWorkerType } from '@nmtjs/application'
|
|
2
|
+
// import { runMain } from 'citty'
|
|
3
|
+
|
|
4
|
+
// import command from '../command.ts'
|
|
5
|
+
// import createWorker from './worker.ts'
|
|
6
|
+
|
|
7
|
+
// const worker = await createWorker({
|
|
8
|
+
// applicationWorkerData: undefined,
|
|
9
|
+
// // type: ApplicationType.Command,
|
|
10
|
+
// // workerType: ApplicationWorkerType.Command,
|
|
11
|
+
// })
|
|
12
|
+
|
|
13
|
+
// runMain(command(worker))
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import type { Worker } from 'node:worker_threads'
|
|
2
|
+
import EventEmitter from 'node:events'
|
|
3
|
+
import { fileURLToPath } from 'node:url'
|
|
4
|
+
|
|
5
|
+
import type {
|
|
6
|
+
ApplicationWorkerErrorEvent,
|
|
7
|
+
ApplicationWorkerReadyEvent,
|
|
8
|
+
ServerConfig,
|
|
9
|
+
} from 'nmtjs/runtime'
|
|
10
|
+
import type { ViteDevServer } from 'vite'
|
|
11
|
+
import { ApplicationServer, isServerConfig } from 'nmtjs/runtime'
|
|
12
|
+
|
|
13
|
+
import type { WorkerServerEventMap as BaseWorkerServerEventMap } from '../vite/servers/worker.ts'
|
|
14
|
+
|
|
15
|
+
declare global {
|
|
16
|
+
const __VITE_CONFIG__: string
|
|
17
|
+
const __APPLICATIONS_CONFIG__: string
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
class InvalidServerConfigError extends Error {
|
|
21
|
+
constructor() {
|
|
22
|
+
super(
|
|
23
|
+
`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().`,
|
|
24
|
+
)
|
|
25
|
+
this.name = 'InvalidServerConfigError'
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const _ext = new URL(import.meta.url).pathname.endsWith('.ts') ? '.ts' : '.js'
|
|
30
|
+
const _vite = __VITE_CONFIG__ ? JSON.parse(__VITE_CONFIG__) : undefined
|
|
31
|
+
const applicationsConfig: Record<
|
|
32
|
+
string,
|
|
33
|
+
{ type: 'neemata' | 'custom'; specifier: string }
|
|
34
|
+
> = __APPLICATIONS_CONFIG__ ? JSON.parse(__APPLICATIONS_CONFIG__) : {}
|
|
35
|
+
|
|
36
|
+
type WorkerEventMap = BaseWorkerServerEventMap & {
|
|
37
|
+
'worker-error': [ApplicationWorkerErrorEvent]
|
|
38
|
+
'worker-ready': [ApplicationWorkerReadyEvent]
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
let _viteServerEvents: EventEmitter<WorkerEventMap> | undefined
|
|
42
|
+
let _viteWorkerServer: ViteDevServer | undefined
|
|
43
|
+
|
|
44
|
+
let server: ApplicationServer | undefined
|
|
45
|
+
let hasActiveWorkerError = false
|
|
46
|
+
const isDev = _vite?.mode === 'development'
|
|
47
|
+
|
|
48
|
+
if (import.meta.env.DEV && import.meta.hot) {
|
|
49
|
+
import.meta.hot.accept('#server', async (module) => {
|
|
50
|
+
await shutdownServer()
|
|
51
|
+
await bootWithHandling(module?.default)
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (_vite) {
|
|
56
|
+
const { createWorkerServer } = await import('../vite/servers/worker.ts')
|
|
57
|
+
const neemataConfig = await import(
|
|
58
|
+
/* @vite-ignore */
|
|
59
|
+
_vite.options.configPath
|
|
60
|
+
).then((m) => m.default as import('../config.ts').NeemataConfig)
|
|
61
|
+
_viteServerEvents = new EventEmitter<WorkerEventMap>()
|
|
62
|
+
_viteServerEvents.on('worker-error', handleWorkerError)
|
|
63
|
+
_viteServerEvents.on('worker-ready', handleWorkerReady)
|
|
64
|
+
_viteWorkerServer = await createWorkerServer(
|
|
65
|
+
_vite.options,
|
|
66
|
+
_vite.mode,
|
|
67
|
+
neemataConfig,
|
|
68
|
+
_viteServerEvents,
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async function bootServer(configValue: ServerConfig | undefined) {
|
|
73
|
+
if (!isServerConfig(configValue)) throw new InvalidServerConfigError()
|
|
74
|
+
const workerConfig = {
|
|
75
|
+
path: fileURLToPath(import.meta.resolve(`./thread${_ext}`)),
|
|
76
|
+
workerData: { vite: _vite?.mode },
|
|
77
|
+
worker: _viteServerEvents
|
|
78
|
+
? (worker: Worker) => {
|
|
79
|
+
_viteServerEvents.emit('worker', worker)
|
|
80
|
+
}
|
|
81
|
+
: undefined,
|
|
82
|
+
events: _viteServerEvents,
|
|
83
|
+
}
|
|
84
|
+
const appServer = new ApplicationServer(
|
|
85
|
+
configValue,
|
|
86
|
+
applicationsConfig,
|
|
87
|
+
workerConfig,
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
try {
|
|
91
|
+
await appServer.start()
|
|
92
|
+
server = appServer
|
|
93
|
+
clearWorkerErrorOverlay()
|
|
94
|
+
} catch (error) {
|
|
95
|
+
await appServer.stop().catch(() => {})
|
|
96
|
+
throw error
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async function bootWithHandling(configValue: ServerConfig | undefined) {
|
|
101
|
+
try {
|
|
102
|
+
await bootServer(configValue)
|
|
103
|
+
} catch (error) {
|
|
104
|
+
handleStartupError(error)
|
|
105
|
+
if (!isDev) throw error
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
let isTerminating = false
|
|
110
|
+
|
|
111
|
+
async function handleTermination() {
|
|
112
|
+
if (isTerminating) return
|
|
113
|
+
isTerminating = true
|
|
114
|
+
await shutdownServer()
|
|
115
|
+
_viteWorkerServer?.close()
|
|
116
|
+
process.exit(0)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function handleUnexpectedError(error: Error) {
|
|
120
|
+
console.error(new Error('Unexpected Error:', { cause: error }))
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async function shutdownServer() {
|
|
124
|
+
if (!server) return
|
|
125
|
+
try {
|
|
126
|
+
await server.stop()
|
|
127
|
+
} catch (error) {
|
|
128
|
+
console.error(
|
|
129
|
+
new Error('Failed to stop application server', { cause: error as Error }),
|
|
130
|
+
)
|
|
131
|
+
} finally {
|
|
132
|
+
server = undefined
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function handleWorkerError(event: ApplicationWorkerErrorEvent) {
|
|
137
|
+
hasActiveWorkerError = true
|
|
138
|
+
console.error(
|
|
139
|
+
new Error(`Worker ${event.application} thread ${event.threadId} error`, {
|
|
140
|
+
cause: event.error,
|
|
141
|
+
}),
|
|
142
|
+
)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function handleWorkerReady(_: ApplicationWorkerReadyEvent) {
|
|
146
|
+
clearWorkerErrorOverlay()
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function handleStartupError(error: unknown) {
|
|
150
|
+
const normalized = error instanceof Error ? error : new Error(String(error))
|
|
151
|
+
if (_viteServerEvents) {
|
|
152
|
+
_viteServerEvents.emit('worker-error', {
|
|
153
|
+
application: 'server',
|
|
154
|
+
threadId: -1,
|
|
155
|
+
error: normalized,
|
|
156
|
+
} as ApplicationWorkerErrorEvent)
|
|
157
|
+
} else {
|
|
158
|
+
hasActiveWorkerError = true
|
|
159
|
+
console.error(
|
|
160
|
+
new Error('Failed to start application server', { cause: normalized }),
|
|
161
|
+
)
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function clearWorkerErrorOverlay() {
|
|
166
|
+
if (!hasActiveWorkerError) return
|
|
167
|
+
hasActiveWorkerError = false
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
process.once('SIGTERM', handleTermination)
|
|
171
|
+
process.once('SIGINT', handleTermination)
|
|
172
|
+
process.on('uncaughtException', handleUnexpectedError)
|
|
173
|
+
process.on('unhandledRejection', handleUnexpectedError)
|
|
174
|
+
|
|
175
|
+
await bootWithHandling(
|
|
176
|
+
await import(
|
|
177
|
+
// @ts-expect-error
|
|
178
|
+
'#server'
|
|
179
|
+
).then((m) => m.default),
|
|
180
|
+
).catch(() => {
|
|
181
|
+
if (!isDev) process.exit(1)
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
const { format } = Intl.NumberFormat('en', {
|
|
185
|
+
notation: 'compact',
|
|
186
|
+
maximumFractionDigits: 2,
|
|
187
|
+
unit: 'byte',
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
const printMem = () => {
|
|
191
|
+
globalThis.gc?.()
|
|
192
|
+
// print memory usage every 10 seconds
|
|
193
|
+
const memoryUsage = process.memoryUsage()
|
|
194
|
+
console.log(
|
|
195
|
+
`Memory Usage: RSS=${format(memoryUsage.rss)}, HeapTotal=${format(memoryUsage.heapTotal)}, HeapUsed=${format(memoryUsage.heapUsed)}, External=${format(memoryUsage.external)}, ArrayBuffers=${format(memoryUsage.arrayBuffers)}`,
|
|
196
|
+
)
|
|
197
|
+
}
|
|
198
|
+
void printMem
|
|
199
|
+
// printMem()
|
|
200
|
+
// setInterval(printMem, 5000)
|
|
@@ -0,0 +1,184 @@
|
|
|
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 {
|
|
6
|
+
ThreadErrorMessage,
|
|
7
|
+
ThreadPortMessage,
|
|
8
|
+
WorkerThreadErrorOrigin,
|
|
9
|
+
} from 'nmtjs/runtime'
|
|
10
|
+
import type { ModuleRunner } from 'vite/module-runner'
|
|
11
|
+
|
|
12
|
+
export type RunWorkerOptions = {
|
|
13
|
+
port: MessagePort
|
|
14
|
+
runtime:
|
|
15
|
+
| { type: 'application'; name: string; path: string; transportsData: any }
|
|
16
|
+
| { type: 'jobs'; jobWorkerPool: string }
|
|
17
|
+
vite?: 'development' | 'production'
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const workerData = _workerData as RunWorkerOptions
|
|
21
|
+
|
|
22
|
+
const ext = new URL(import.meta.url).pathname.endsWith('.ts') ? '.ts' : '.js'
|
|
23
|
+
const workerPath = fileURLToPath(import.meta.resolve(`./worker${ext}`))
|
|
24
|
+
|
|
25
|
+
type WorkerModule = typeof import('./worker.ts')
|
|
26
|
+
type WorkerRuntime = Awaited<ReturnType<WorkerModule['run']>>
|
|
27
|
+
|
|
28
|
+
const kReportedError = Symbol.for('nmtjs.worker.reported-error')
|
|
29
|
+
|
|
30
|
+
let runner: ModuleRunner | undefined
|
|
31
|
+
let workerModule: WorkerModule
|
|
32
|
+
let runtime: WorkerRuntime | undefined
|
|
33
|
+
let runtimeStarted = false
|
|
34
|
+
|
|
35
|
+
process.on('uncaughtException', (error) => {
|
|
36
|
+
reportError(error, 'runtime', { fatal: true })
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
process.on('unhandledRejection', (error) => {
|
|
40
|
+
reportError(error, 'runtime', { fatal: true })
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
process.on('exit', () => {
|
|
44
|
+
void cleanup()
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
async function cleanup() {
|
|
48
|
+
await stopRuntime()
|
|
49
|
+
await closeRunner()
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async function closeRunner() {
|
|
53
|
+
if (!runner) return
|
|
54
|
+
try {
|
|
55
|
+
await runner.close()
|
|
56
|
+
} catch (error) {
|
|
57
|
+
reportError(error, 'runtime', { fatal: false })
|
|
58
|
+
} finally {
|
|
59
|
+
runner = undefined
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async function stopRuntime() {
|
|
64
|
+
if (!runtime) return
|
|
65
|
+
try {
|
|
66
|
+
if (runtimeStarted) {
|
|
67
|
+
await runtime.stop()
|
|
68
|
+
}
|
|
69
|
+
} catch (error) {
|
|
70
|
+
reportError(error, 'runtime', { fatal: false })
|
|
71
|
+
} finally {
|
|
72
|
+
runtimeStarted = false
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function normalizeError(value: unknown): Error {
|
|
77
|
+
if (value instanceof Error) return value
|
|
78
|
+
if (typeof value === 'string') return new Error(value)
|
|
79
|
+
if (value && typeof value === 'object') {
|
|
80
|
+
try {
|
|
81
|
+
return new Error(JSON.stringify(value))
|
|
82
|
+
} catch {}
|
|
83
|
+
}
|
|
84
|
+
return new Error(String(value))
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function serializeError(
|
|
88
|
+
error: Error,
|
|
89
|
+
origin: WorkerThreadErrorOrigin,
|
|
90
|
+
fatal: boolean,
|
|
91
|
+
): ThreadErrorMessage {
|
|
92
|
+
return {
|
|
93
|
+
message: error.message,
|
|
94
|
+
name: error.name,
|
|
95
|
+
stack: error.stack,
|
|
96
|
+
origin,
|
|
97
|
+
fatal,
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function reportError(
|
|
102
|
+
value: unknown,
|
|
103
|
+
origin: WorkerThreadErrorOrigin,
|
|
104
|
+
options: { fatal?: boolean } = {},
|
|
105
|
+
): Error {
|
|
106
|
+
const fatal = options.fatal ?? origin !== 'runtime'
|
|
107
|
+
const error = normalizeError(value)
|
|
108
|
+
if (!(error as any)[kReportedError]) {
|
|
109
|
+
try {
|
|
110
|
+
workerData.port.postMessage({
|
|
111
|
+
type: 'error',
|
|
112
|
+
data: serializeError(error, origin, fatal),
|
|
113
|
+
} satisfies ThreadPortMessage)
|
|
114
|
+
} catch {}
|
|
115
|
+
console.error(new Error(`Worker thread ${origin} error`, { cause: error }))
|
|
116
|
+
;(error as any)[kReportedError] = true
|
|
117
|
+
}
|
|
118
|
+
return error
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async function loadWorkerModule() {
|
|
122
|
+
try {
|
|
123
|
+
if (workerData.vite) {
|
|
124
|
+
const { createModuleRunner } = (await import(
|
|
125
|
+
'../vite/runners/worker.ts'
|
|
126
|
+
)) as typeof import('../vite/runners/worker.ts')
|
|
127
|
+
|
|
128
|
+
runner = createModuleRunner(workerData.vite)
|
|
129
|
+
workerModule = await runner.import(workerPath)
|
|
130
|
+
} else {
|
|
131
|
+
runner = undefined
|
|
132
|
+
workerModule = await import(
|
|
133
|
+
/* @vite-ignore */
|
|
134
|
+
workerPath
|
|
135
|
+
)
|
|
136
|
+
}
|
|
137
|
+
} catch (error) {
|
|
138
|
+
throw reportError(error, 'bootstrap')
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async function initializeRuntime() {
|
|
143
|
+
try {
|
|
144
|
+
runtime = await workerModule.run(workerData.runtime)
|
|
145
|
+
} catch (error) {
|
|
146
|
+
throw reportError(error, 'bootstrap')
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
workerData.port.on('message', async (msg) => {
|
|
150
|
+
if (msg.type === 'stop') {
|
|
151
|
+
await cleanup()
|
|
152
|
+
process.exit(0)
|
|
153
|
+
}
|
|
154
|
+
})
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
async function startRuntime() {
|
|
158
|
+
if (!runtime) return
|
|
159
|
+
try {
|
|
160
|
+
const hosts = (await runtime.start()) || undefined
|
|
161
|
+
runtimeStarted = true
|
|
162
|
+
workerData.port.postMessage({
|
|
163
|
+
type: 'ready',
|
|
164
|
+
data: { hosts },
|
|
165
|
+
} satisfies ThreadPortMessage)
|
|
166
|
+
} catch (error) {
|
|
167
|
+
throw reportError(error, 'start')
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
async function main() {
|
|
172
|
+
await loadWorkerModule()
|
|
173
|
+
await initializeRuntime()
|
|
174
|
+
await startRuntime()
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
main().catch(async (error) => {
|
|
178
|
+
const normalized = error instanceof Error ? error : normalizeError(error)
|
|
179
|
+
if (!(normalized as any)[kReportedError]) {
|
|
180
|
+
reportError(normalized, 'bootstrap')
|
|
181
|
+
}
|
|
182
|
+
await cleanup()
|
|
183
|
+
process.exit(1)
|
|
184
|
+
})
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { workerData } from 'node:worker_threads'
|
|
2
|
+
|
|
3
|
+
import type { ServerConfig } from 'nmtjs/runtime'
|
|
4
|
+
import {
|
|
5
|
+
ApplicationWorkerRuntime,
|
|
6
|
+
isApplicationConfig,
|
|
7
|
+
JobWorkerRuntime,
|
|
8
|
+
} from 'nmtjs/runtime'
|
|
9
|
+
|
|
10
|
+
import type { RunWorkerOptions } from './thread.ts'
|
|
11
|
+
|
|
12
|
+
export async function run(options: RunWorkerOptions['runtime']) {
|
|
13
|
+
const serverConfig: ServerConfig = await import(
|
|
14
|
+
// @ts-expect-error
|
|
15
|
+
'#server'
|
|
16
|
+
).then((m) => m.default)
|
|
17
|
+
if (options.type === 'application') {
|
|
18
|
+
globalThis._hotAccept = (module: any) => {
|
|
19
|
+
if (module) {
|
|
20
|
+
if (!isApplicationConfig(module.default))
|
|
21
|
+
throw new Error('Invalid application config')
|
|
22
|
+
runtime.reload(module.default)
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const { name, path, transportsData } = options
|
|
27
|
+
const appConfig = await import(
|
|
28
|
+
/* @vite-ignore */
|
|
29
|
+
path
|
|
30
|
+
).then((m) => m.default)
|
|
31
|
+
|
|
32
|
+
const runtime = new ApplicationWorkerRuntime(
|
|
33
|
+
serverConfig,
|
|
34
|
+
{ name, path, transports: transportsData },
|
|
35
|
+
appConfig,
|
|
36
|
+
)
|
|
37
|
+
return runtime
|
|
38
|
+
} else if (options.type === 'jobs') {
|
|
39
|
+
const { jobWorkerPool } = options
|
|
40
|
+
const runtime = new JobWorkerRuntime(serverConfig, {
|
|
41
|
+
poolName: jobWorkerPool,
|
|
42
|
+
port: workerData.port,
|
|
43
|
+
})
|
|
44
|
+
return runtime
|
|
45
|
+
} else {
|
|
46
|
+
throw new Error(`Unknown runtime type: ${(workerData.runtime as any).type}`)
|
|
47
|
+
}
|
|
48
|
+
}
|