@obov/mext 0.3.0 → 0.4.0
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/build.js +67 -4
- package/dist/build.js.map +1 -1
- package/dist/cli/ask-url.d.ts +16 -0
- package/dist/cli/ask-url.js +27 -0
- package/dist/cli/ask-url.js.map +1 -0
- package/dist/cli/build.js +7 -1
- package/dist/cli/build.js.map +1 -1
- package/dist/cli/dev-server.d.ts +7 -1
- package/dist/cli/dev-server.js +15 -2
- package/dist/cli/dev-server.js.map +1 -1
- package/dist/cli/dev.js +27 -7
- package/dist/cli/dev.js.map +1 -1
- package/dist/cli/login.d.ts +5 -0
- package/dist/cli/login.js +11 -7
- package/dist/cli/login.js.map +1 -1
- package/dist/cli/logout.js +4 -6
- package/dist/cli/logout.js.map +1 -1
- package/dist/cli/output.d.ts +1 -1
- package/dist/cli/output.js +1 -2
- package/dist/cli/output.js.map +1 -1
- package/dist/cli/run.js +21 -5
- package/dist/cli/run.js.map +1 -1
- package/dist/client/cache.d.ts +14 -4
- package/dist/client/cache.js +10 -3
- package/dist/client/cache.js.map +1 -1
- package/dist/client/main.js +11 -10
- package/dist/client/main.js.map +1 -1
- package/dist/client/manifest.d.ts +13 -1
- package/dist/client/manifest.js +43 -0
- package/dist/client/manifest.js.map +1 -1
- package/dist/client/runner.d.ts +3 -1
- package/dist/client/runner.js +80 -19
- package/dist/client/runner.js.map +1 -1
- package/dist/client/task.d.ts +47 -0
- package/dist/client/task.js +126 -0
- package/dist/client/task.js.map +1 -0
- package/dist/command.d.ts +30 -3
- package/dist/command.js +16 -0
- package/dist/command.js.map +1 -1
- package/dist/config.d.ts +40 -6
- package/dist/config.js +57 -8
- package/dist/config.js.map +1 -1
- package/dist/errors.d.ts +3 -1
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +17 -5
- package/dist/index.js +9 -2
- package/dist/index.js.map +1 -1
- package/dist/instrumentation.d.ts +14 -2
- package/dist/instrumentation.js +12 -4
- package/dist/instrumentation.js.map +1 -1
- package/dist/invoke.d.ts +38 -0
- package/dist/invoke.js +72 -3
- package/dist/invoke.js.map +1 -1
- package/dist/local-bin.js +17 -9
- package/dist/local-bin.js.map +1 -1
- package/dist/manifest.d.ts +48 -3
- package/dist/manifest.js +14 -3
- package/dist/manifest.js.map +1 -1
- package/dist/mcp/constants.d.ts +4 -0
- package/dist/mcp/constants.js +4 -0
- package/dist/mcp/constants.js.map +1 -1
- package/dist/mcp/dispatch.d.ts +21 -7
- package/dist/mcp/dispatch.js +42 -7
- package/dist/mcp/dispatch.js.map +1 -1
- package/dist/mcp/http.d.ts +23 -5
- package/dist/mcp/http.js +64 -9
- package/dist/mcp/http.js.map +1 -1
- package/dist/mcp/index.d.ts +14 -6
- package/dist/mcp/index.js +7 -3
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/mrtr.d.ts +40 -8
- package/dist/mcp/mrtr.js +32 -11
- package/dist/mcp/mrtr.js.map +1 -1
- package/dist/mcp/prompts.d.ts +25 -0
- package/dist/mcp/prompts.js +164 -0
- package/dist/mcp/prompts.js.map +1 -0
- package/dist/mcp/resources.d.ts +48 -0
- package/dist/mcp/resources.js +142 -0
- package/dist/mcp/resources.js.map +1 -0
- package/dist/mcp/server.d.ts +30 -5
- package/dist/mcp/server.js +143 -16
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/stdio.d.ts +5 -0
- package/dist/mcp/stdio.js +16 -3
- package/dist/mcp/stdio.js.map +1 -1
- package/dist/mcp/subscriptions.d.ts +61 -0
- package/dist/mcp/subscriptions.js +188 -0
- package/dist/mcp/subscriptions.js.map +1 -0
- package/dist/mcp/tasks.d.ts +127 -0
- package/dist/mcp/tasks.js +448 -0
- package/dist/mcp/tasks.js.map +1 -0
- package/dist/module-files.d.ts +24 -0
- package/dist/module-files.js +97 -0
- package/dist/module-files.js.map +1 -0
- package/dist/prompt.d.ts +133 -0
- package/dist/prompt.js +222 -0
- package/dist/prompt.js.map +1 -0
- package/dist/registry.d.ts +6 -0
- package/dist/registry.js.map +1 -1
- package/dist/remote/client.d.ts +17 -1
- package/dist/remote/client.js +18 -2
- package/dist/remote/client.js.map +1 -1
- package/dist/resource.d.ts +169 -0
- package/dist/resource.js +301 -0
- package/dist/resource.js.map +1 -0
- package/dist/route.d.ts +71 -0
- package/dist/route.js +280 -0
- package/dist/route.js.map +1 -0
- package/dist/start.d.ts +14 -3
- package/dist/start.js +76 -11
- package/dist/start.js.map +1 -1
- package/dist/state.d.ts +38 -0
- package/dist/state.js +98 -0
- package/dist/state.js.map +1 -0
- package/package.json +1 -1
package/dist/start.js
CHANGED
|
@@ -10,13 +10,15 @@ import { readFileSync } from "node:fs";
|
|
|
10
10
|
import { resolve, sep } from "node:path";
|
|
11
11
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
12
12
|
import { COMMAND, isCommand } from "./command.js";
|
|
13
|
-
import { mcpDeclarations, mcpStdioDeclarations, resolveLocalPrincipal } from "./config.js";
|
|
13
|
+
import { mcpDeclarations, mcpStdioDeclarations, resolveLocalPrincipal, resolveSecret, SECRET_ENV } from "./config.js";
|
|
14
14
|
import { loadInstrumentation } from "./instrumentation.js";
|
|
15
15
|
import { MANIFEST_SCHEMA_VERSION } from "./manifest.js";
|
|
16
16
|
import { DEFAULT_HOST, DEFAULT_PORT } from "./mcp/constants.js";
|
|
17
17
|
import { createMcpFetchHandler, startMcpHttpServer } from "./mcp/http.js";
|
|
18
18
|
import { redirectStdout, serveMcpStdio } from "./mcp/stdio.js";
|
|
19
19
|
import { createLazyRegistry } from "./registry.js";
|
|
20
|
+
import { createLazyPromptSet, isPrompt } from "./prompt.js";
|
|
21
|
+
import { createLazyResourceSet, isResource } from "./resource.js";
|
|
20
22
|
import { mextVersion } from "./version.js";
|
|
21
23
|
/**
|
|
22
24
|
* @obov/mext/start: .mext/ (mext build 산출) 실행 런타임. 소스 스캔 · TypeScript 없음.
|
|
@@ -52,7 +54,7 @@ export async function startFromBuild(dir, options = {}) {
|
|
|
52
54
|
principal: await resolveLocalPrincipal(build.config),
|
|
53
55
|
...(build.config.app ? { app: build.config.app } : {}),
|
|
54
56
|
...(build.config.tools ? { tools: build.config.tools } : {}),
|
|
55
|
-
...mcpStdioDeclarations(build.config),
|
|
57
|
+
...mcpStdioDeclarations(build.config, env),
|
|
56
58
|
stdout: redirect.wire,
|
|
57
59
|
onerror,
|
|
58
60
|
});
|
|
@@ -65,7 +67,10 @@ export async function startFromBuild(dir, options = {}) {
|
|
|
65
67
|
}
|
|
66
68
|
const port = args.port ?? envPort(env.PORT) ?? build.config.server?.port ?? DEFAULT_PORT;
|
|
67
69
|
const host = args.host ?? (env.HOST === undefined || env.HOST === "" ? undefined : env.HOST) ?? build.config.server?.host ?? DEFAULT_HOST;
|
|
68
|
-
const http = httpOptions(build, onerror);
|
|
70
|
+
const http = httpOptions(build, onerror, env);
|
|
71
|
+
if (resolveSecret(build.config, env) === undefined) {
|
|
72
|
+
stderr.write(`warning: no secret (mext.config.ts secret or ${SECRET_ENV}). ctx.ask retries after the first answer fail across instances and restarts\n`);
|
|
73
|
+
}
|
|
69
74
|
const server = await startMcpHttpServer({ ...http, server: { ...http.server, host, port } });
|
|
70
75
|
stderr.write(`MCP server (Streamable HTTP) listening on ${server.url} (buildId ${build.manifest.buildId})\n`);
|
|
71
76
|
await new Promise((done) => {
|
|
@@ -97,13 +102,13 @@ export function createFetchHandler(dir, options = {}) {
|
|
|
97
102
|
const onerror = (error) => console.error(`mcp: ${error.message}`);
|
|
98
103
|
let pending;
|
|
99
104
|
const init = () => (pending ??= loadBuild(base, options)
|
|
100
|
-
.then((build) => createMcpFetchHandler(httpOptions(build, onerror)))
|
|
105
|
+
.then((build) => createMcpFetchHandler({ ...httpOptions(build, onerror), taskExecution: "waitUntil" }))
|
|
101
106
|
.catch((error) => {
|
|
102
107
|
pending = undefined;
|
|
103
108
|
throw error;
|
|
104
109
|
}));
|
|
105
110
|
return {
|
|
106
|
-
async fetch(request) {
|
|
111
|
+
async fetch(request, ...rest) {
|
|
107
112
|
let handler;
|
|
108
113
|
try {
|
|
109
114
|
handler = await init();
|
|
@@ -114,10 +119,22 @@ export function createFetchHandler(dir, options = {}) {
|
|
|
114
119
|
const body = { jsonrpc: "2.0", id: null, error: { code: -32_603, message: "Server failed to start", data: { loadError: message } } };
|
|
115
120
|
return new Response(JSON.stringify(body), { status: 500, headers: { "Content-Type": "application/json" } });
|
|
116
121
|
}
|
|
117
|
-
|
|
122
|
+
const waitUntil = findWaitUntil(rest);
|
|
123
|
+
return handler.fetch(request, waitUntil ? { waitUntil } : undefined);
|
|
118
124
|
},
|
|
119
125
|
};
|
|
120
126
|
}
|
|
127
|
+
/** fetch(request, ...rest) 의 rest 에서 waitUntil 함수를 가진 객체 (this 유지) */
|
|
128
|
+
function findWaitUntil(rest) {
|
|
129
|
+
for (const value of rest) {
|
|
130
|
+
const holder = value;
|
|
131
|
+
if (typeof holder === "object" && holder !== null && typeof holder.waitUntil === "function") {
|
|
132
|
+
const fn = holder.waitUntil;
|
|
133
|
+
return (promise) => fn.call(holder, promise);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return undefined;
|
|
137
|
+
}
|
|
121
138
|
/** .mext/manifest.json 읽기 + 검증 (없음 · schemaVersion · mextVersion 불일치 = 오류) */
|
|
122
139
|
export function readBuildManifest(dir) {
|
|
123
140
|
const base = dirUrl(dir);
|
|
@@ -146,13 +163,29 @@ export async function loadBuild(dir, options = {}) {
|
|
|
146
163
|
? {}
|
|
147
164
|
: (await import(__rewriteRelativeImportExtension(new URL(manifest.config, base).href))).default;
|
|
148
165
|
const registry = registryFromManifest(manifest, base, options);
|
|
149
|
-
return { manifest, config, registry, instrumentation };
|
|
166
|
+
return { manifest, config, registry, instrumentation, routes: routesFromManifest(manifest, base, options) };
|
|
150
167
|
}
|
|
151
|
-
/** manifest →
|
|
168
|
+
/** manifest.routes → RouteEntry. 405 = manifest 의 methods 만, 모듈 (routes[].module) 은 load() 에서 import */
|
|
169
|
+
export function routesFromManifest(manifest, dir, options = {}) {
|
|
170
|
+
const base = dirUrl(dir);
|
|
171
|
+
const importModule = options.importModule ?? ((href) => import(__rewriteRelativeImportExtension(href)));
|
|
172
|
+
return (manifest.routes ?? []).map((r) => ({
|
|
173
|
+
path: r.path,
|
|
174
|
+
file: r.file,
|
|
175
|
+
methods: r.methods,
|
|
176
|
+
load: async () => (await importModule(new URL(r.module, base).href)),
|
|
177
|
+
}));
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* manifest → lazy Registry. 명령어 모듈 (manifest.commands[].module) · 자원 모듈 (resources[].module) ·
|
|
181
|
+
* 프롬프트 모듈 (prompts[].module) 은 load() 에서 import
|
|
182
|
+
*/
|
|
152
183
|
export function registryFromManifest(manifest, dir, options = {}) {
|
|
153
184
|
const base = dirUrl(dir);
|
|
154
185
|
const importModule = options.importModule ?? ((href) => import(__rewriteRelativeImportExtension(href)));
|
|
155
|
-
|
|
186
|
+
const resources = resourcesFromManifest(manifest, base, importModule);
|
|
187
|
+
const prompts = promptsFromManifest(manifest, base, importModule);
|
|
188
|
+
const registry = createLazyRegistry({
|
|
156
189
|
commands: manifest.commands.map((c) => ({
|
|
157
190
|
id: c.id,
|
|
158
191
|
command: metadataCommand(c),
|
|
@@ -173,6 +206,36 @@ export function registryFromManifest(manifest, dir, options = {}) {
|
|
|
173
206
|
...manifest.namespaces,
|
|
174
207
|
],
|
|
175
208
|
});
|
|
209
|
+
return { ...registry, ...(resources ? { resources } : {}), ...(prompts ? { prompts } : {}) };
|
|
210
|
+
}
|
|
211
|
+
/** manifest.prompts → lazy PromptSet. 없거나 비면 undefined (프롬프트 기능 없음) */
|
|
212
|
+
function promptsFromManifest(manifest, base, importModule) {
|
|
213
|
+
if (!manifest.prompts || manifest.prompts.length === 0)
|
|
214
|
+
return undefined;
|
|
215
|
+
return createLazyPromptSet(manifest.prompts.map(({ module, ...p }) => ({
|
|
216
|
+
...p,
|
|
217
|
+
async load() {
|
|
218
|
+
const mod = (await importModule(new URL(module, base).href));
|
|
219
|
+
if (!isPrompt(mod?.default))
|
|
220
|
+
throw new Error(`${module}: default export is not a definePrompt result (prompt ${p.name})`);
|
|
221
|
+
return mod.default;
|
|
222
|
+
},
|
|
223
|
+
})));
|
|
224
|
+
}
|
|
225
|
+
/** manifest.resources → lazy ResourceSet. 없거나 비면 undefined (자원 기능 없음) */
|
|
226
|
+
function resourcesFromManifest(manifest, base, importModule) {
|
|
227
|
+
if (!manifest.resources || manifest.resources.length === 0)
|
|
228
|
+
return undefined;
|
|
229
|
+
return createLazyResourceSet(manifest.resources.map(({ module, ...r }) => ({
|
|
230
|
+
...r,
|
|
231
|
+
async load() {
|
|
232
|
+
const mod = (await importModule(new URL(module, base).href));
|
|
233
|
+
if (!isResource(mod?.default) || mod.default.uri !== r.uri) {
|
|
234
|
+
throw new Error(`${module}: default export is not the defineResource result for ${r.uri}`);
|
|
235
|
+
}
|
|
236
|
+
return mod.default;
|
|
237
|
+
},
|
|
238
|
+
})));
|
|
176
239
|
}
|
|
177
240
|
/**
|
|
178
241
|
* manifest 메타데이터만 있는 Command (RegisteredCommand.command). input · execute 는 모듈 로드 전이라 접근 = 오류
|
|
@@ -197,10 +260,11 @@ function metadataCommand(c) {
|
|
|
197
260
|
examples: Object.freeze([...c.examples]),
|
|
198
261
|
positional: Object.freeze([...c.positional]),
|
|
199
262
|
aliases: Object.freeze(c.aliases.map((a) => (a.startsWith(parent) ? a.slice(parent.length) : a))),
|
|
263
|
+
...(c.task !== undefined ? { task: Object.freeze({ ttlMs: c.task.ttlMs }) } : {}),
|
|
200
264
|
execute: notLoaded,
|
|
201
265
|
});
|
|
202
266
|
}
|
|
203
|
-
function httpOptions(build, onerror) {
|
|
267
|
+
function httpOptions(build, onerror, env = process.env) {
|
|
204
268
|
const { config } = build;
|
|
205
269
|
return {
|
|
206
270
|
registry: build.registry,
|
|
@@ -210,7 +274,8 @@ function httpOptions(build, onerror) {
|
|
|
210
274
|
...(config.auth ? { auth: config.auth } : {}),
|
|
211
275
|
...(config.tools ? { tools: config.tools } : {}),
|
|
212
276
|
...(config.oauth ? { oauth: config.oauth } : {}),
|
|
213
|
-
...
|
|
277
|
+
...(build.routes.length > 0 ? { routes: build.routes } : {}),
|
|
278
|
+
...mcpDeclarations(config, env),
|
|
214
279
|
server: config.server?.allowedOrigins ? { allowedOrigins: config.server.allowedOrigins } : {},
|
|
215
280
|
onerror,
|
|
216
281
|
};
|
package/dist/start.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"start.js","sourceRoot":"","sources":["../src/start.ts"],"names":[],"mappings":"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","sourcesContent":["import { readFileSync } from \"node:fs\"\nimport { resolve, sep } from \"node:path\"\nimport { fileURLToPath, pathToFileURL } from \"node:url\"\nimport { COMMAND, isCommand, type Command } from \"./command.ts\"\nimport { mcpDeclarations, mcpStdioDeclarations, resolveLocalPrincipal, type MextConfig } from \"./config.ts\"\nimport { loadInstrumentation, type Instrumentation } from \"./instrumentation.ts\"\nimport { MANIFEST_SCHEMA_VERSION, type BuildManifest, type BuildManifestCommand } from \"./manifest.ts\"\nimport { DEFAULT_HOST, DEFAULT_PORT } from \"./mcp/constants.ts\"\nimport { createMcpFetchHandler, startMcpHttpServer, type McpFetchHandler, type McpHttpOptions } from \"./mcp/http.ts\"\nimport { redirectStdout, serveMcpStdio } from \"./mcp/stdio.ts\"\nimport { createLazyRegistry, type Registry } from \"./registry.ts\"\nimport { mextVersion } from \"./version.ts\"\n\n/**\n * @obov/mext/start: .mext/ (mext build 산출) 실행 런타임. 소스 스캔 · TypeScript 없음.\n * 생성 파일 계약 (mext build 가 쓰는 server.js · handler.js, 바꾸면 기존 빌드가 깨진다):\n * server.js process.exitCode = await startFromBuild(new URL(\".\", import.meta.url), { argv: process.argv.slice(2), env: process.env })\n * handler.js export default createFetchHandler(new URL(\".\", import.meta.url))\n *\n * 로드 순서 = manifest.json (검증) → instrumentation.js (register) → config.js → manifest 기반 lazy Registry.\n * 명령어 모듈은 그 명령어를 실행할 때 import (help · tools/list · UNKNOWN_COMMAND · 권한 거부는 import 없음)\n */\n\nexport { mainLocalBin, runLocalBin } from \"./local-bin.ts\"\nexport type { LocalBinOptions } from \"./local-bin.ts\"\n\nexport interface StartOptions {\n /** server.js · mext start 뒤 인자. --stdio · --port <n> · --host <h> */\n argv?: readonly string[]\n /** PORT · HOST. 기본 process.env */\n env?: Record<string, string | undefined>\n /** abort = 종료. 기본 SIGINT · SIGTERM */\n signal?: AbortSignal\n /** 기본 process.stderr */\n stderr?: { write(chunk: string): unknown }\n}\n\nexport interface FetchHandler {\n /** 거부하지 않는다. 초기화 실패 · 내부 오류 = 500 JSON-RPC 오류 */\n fetch(request: Request): Promise<Response>\n}\n\n/** .mext/ 로드 결과 */\nexport interface LoadedBuild {\n manifest: BuildManifest\n config: MextConfig\n registry: Registry\n instrumentation: Instrumentation\n}\n\nexport interface LoadBuildOptions {\n /** 명령어 모듈 import (테스트 계측). 기본 = 동적 import */\n importModule?: (href: string) => Promise<unknown>\n}\n\nconst USAGE = \"Usage: mext start [--stdio] [--port <n>] [--host <h>] (node .mext/server.js, PORT · HOST environment variables)\"\n\n/** .mext/ 실행 (mext start · node .mext/server.js). 반환 = exit code */\nexport async function startFromBuild(dir: string | URL, options: StartOptions = {}): Promise<number> {\n const stderr = options.stderr ?? process.stderr\n const env = options.env ?? process.env\n const args = parseStartArgs(options.argv ?? [])\n if (typeof args === \"string\") {\n stderr.write(`error: ${args}\\n${USAGE}\\n`)\n return 2\n }\n // stdio: 사용자 코드 import 전부터 그 외 stdout 쓰기를 stderr 로 (mext dev --stdio 와 같음)\n const redirect = args.stdio ? redirectStdout() : undefined\n const { signal, dispose } = options.signal ? { signal: options.signal, dispose: () => {} } : processSignal()\n try {\n const build = await loadBuild(dir)\n const onerror = (error: Error): void => void stderr.write(`mcp: ${error.message}\\n`)\n if (args.stdio) {\n const server = serveMcpStdio({\n registry: build.registry,\n instrumentation: build.instrumentation,\n manifestHash: build.manifest.manifestHash,\n principal: await resolveLocalPrincipal(build.config),\n ...(build.config.app ? { app: build.config.app } : {}),\n ...(build.config.tools ? { tools: build.config.tools } : {}),\n ...mcpStdioDeclarations(build.config),\n stdout: redirect!.wire,\n onerror,\n })\n const onAbort = (): void => void server.close()\n if (signal.aborted) onAbort()\n signal.addEventListener(\"abort\", onAbort, { once: true })\n await server.closed\n return 0\n }\n const port = args.port ?? envPort(env.PORT) ?? build.config.server?.port ?? DEFAULT_PORT\n const host = args.host ?? (env.HOST === undefined || env.HOST === \"\" ? undefined : env.HOST) ?? build.config.server?.host ?? DEFAULT_HOST\n const http = httpOptions(build, onerror)\n const server = await startMcpHttpServer({ ...http, server: { ...http.server, host, port } })\n stderr.write(`MCP server (Streamable HTTP) listening on ${server.url} (buildId ${build.manifest.buildId})\\n`)\n await new Promise<void>((done) => {\n if (signal.aborted) return done()\n signal.addEventListener(\"abort\", () => done(), { once: true })\n })\n await server.close()\n return 0\n } catch (error) {\n // 시작 실패 = stdout 원복 (stdio 서버를 띄우기 전)\n redirect?.restore()\n stderr.write(`error: ${error instanceof Error ? error.message : String(error)}\\n`)\n return 1\n } finally {\n dispose()\n }\n}\n\n/**\n * handler.js 의 Web fetch handler ({ fetch(request) → Response }). 동기 반환.\n * D7: 초기화 (manifest 검증 · instrumentation register · config · Registry) = 첫 요청에서 1회 (memoized promise).\n * 초기화 실패 = 그 요청 500 + JSON-RPC 오류 (data.loadError), 다음 요청에서 재시도.\n * MCP 처리 (Origin · auth · 헤더 검증 · SSE progress · MRTR) = node 서버와 같은 createMcpFetchHandler\n */\nexport function createFetchHandler(dir: string | URL, options: LoadBuildOptions = {}): FetchHandler {\n const base = dirUrl(dir)\n const onerror = (error: Error): void => console.error(`mcp: ${error.message}`)\n let pending: Promise<McpFetchHandler> | undefined\n const init = (): Promise<McpFetchHandler> =>\n (pending ??= loadBuild(base, options)\n .then((build) => createMcpFetchHandler(httpOptions(build, onerror)))\n .catch((error: unknown) => {\n pending = undefined\n throw error\n }))\n return {\n async fetch(request) {\n let handler: McpFetchHandler\n try {\n handler = await init()\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n onerror(error instanceof Error ? error : new Error(message))\n const body = { jsonrpc: \"2.0\", id: null, error: { code: -32_603, message: \"Server failed to start\", data: { loadError: message } } }\n return new Response(JSON.stringify(body), { status: 500, headers: { \"Content-Type\": \"application/json\" } })\n }\n return handler.fetch(request)\n },\n }\n}\n\n/** .mext/manifest.json 읽기 + 검증 (없음 · schemaVersion · mextVersion 불일치 = 오류) */\nexport function readBuildManifest(dir: string | URL): BuildManifest {\n const base = dirUrl(dir)\n let text: string\n try {\n text = readFileSync(new URL(\"manifest.json\", base), \"utf8\")\n } catch {\n throw new Error(`no build found in ${fileURLToPath(base)} (manifest.json missing). Run \"mext build\" first`)\n }\n const manifest = JSON.parse(text) as BuildManifest\n if (manifest.schemaVersion !== MANIFEST_SCHEMA_VERSION) {\n throw new Error(\n `${fileURLToPath(base)} was built with manifest schemaVersion ${String(manifest.schemaVersion)} (expected ${MANIFEST_SCHEMA_VERSION}). Run \"mext build\" again`,\n )\n }\n if (manifest.mextVersion !== mextVersion()) {\n throw new Error(\n `${fileURLToPath(base)} was built with @obov/mext ${manifest.mextVersion}, but ${mextVersion()} is installed. Run \"mext build\" again`,\n )\n }\n return manifest\n}\n\n/** manifest 검증 → instrumentation.js (register, 사용자 코드보다 먼저) → config.js → lazy Registry */\nexport async function loadBuild(dir: string | URL, options: LoadBuildOptions = {}): Promise<LoadedBuild> {\n const base = dirUrl(dir)\n const manifest = readBuildManifest(base)\n const instrumentation = await loadInstrumentation(\n manifest.instrumentation === undefined ? undefined : new URL(manifest.instrumentation, base),\n )\n const config =\n manifest.config === undefined\n ? {}\n : ((await import(new URL(manifest.config, base).href)) as { default: MextConfig }).default\n const registry = registryFromManifest(manifest, base, options)\n return { manifest, config, registry, instrumentation }\n}\n\n/** manifest → lazy Registry. 명령어 모듈 (manifest.commands[].module) 은 load() 에서 import */\nexport function registryFromManifest(manifest: BuildManifest, dir: string | URL, options: LoadBuildOptions = {}): Registry {\n const base = dirUrl(dir)\n const importModule = options.importModule ?? ((href: string) => import(href))\n return createLazyRegistry({\n commands: manifest.commands.map((c) => ({\n id: c.id,\n command: metadataCommand(c),\n aliases: c.aliases,\n ...(c.file !== undefined ? { file: c.file } : {}),\n inputSchema: c.inputSchema,\n ...(c.outputSchema !== undefined ? { outputSchema: c.outputSchema } : {}),\n async load() {\n const href = new URL(c.module, base).href\n const mod = (await importModule(href)) as { default?: unknown } | undefined\n if (!isCommand(mod?.default)) throw new Error(`${c.module}: default export is not a defineCommand result (command ${c.id})`)\n return mod.default\n },\n })),\n namespaces: [\n ...(manifest.description !== undefined ? [{ id: \"\", description: manifest.description }] : []),\n ...manifest.namespaces,\n ],\n })\n}\n\n/**\n * manifest 메타데이터만 있는 Command (RegisteredCommand.command). input · execute 는 모듈 로드 전이라 접근 = 오류\n * (invoke 는 loadCommand 결과를 쓴다)\n */\nfunction metadataCommand(c: BuildManifestCommand): Command {\n const parent = c.id.includes(\".\") ? c.id.slice(0, c.id.lastIndexOf(\".\") + 1) : \"\"\n const notLoaded = (): never => {\n throw new Error(`${c.id}: command module is not loaded (use loadCommand)`)\n }\n return Object.freeze({\n [COMMAND]: true as const,\n description: c.description,\n get input(): never {\n return notLoaded()\n },\n output: undefined,\n readOnly: c.readOnly,\n destructive: c.destructive,\n requiresConfirmation: c.requiresConfirmation,\n scopes: Object.freeze([...c.scopes]),\n examples: Object.freeze([...c.examples]) as Command[\"examples\"],\n positional: Object.freeze([...c.positional]),\n aliases: Object.freeze(c.aliases.map((a) => (a.startsWith(parent) ? a.slice(parent.length) : a))),\n execute: notLoaded,\n })\n}\n\nfunction httpOptions(build: LoadedBuild, onerror: (error: Error) => void): McpHttpOptions {\n const { config } = build\n return {\n registry: build.registry,\n instrumentation: build.instrumentation,\n manifestHash: build.manifest.manifestHash,\n ...(config.app ? { app: config.app } : {}),\n ...(config.auth ? { auth: config.auth } : {}),\n ...(config.tools ? { tools: config.tools } : {}),\n ...(config.oauth ? { oauth: config.oauth } : {}),\n ...mcpDeclarations(config),\n server: config.server?.allowedOrigins ? { allowedOrigins: config.server.allowedOrigins } : {},\n onerror,\n }\n}\n\ninterface StartArgs {\n stdio: boolean\n port?: number\n host?: string\n}\n\n/** 반환 문자열 = 사용법 오류 */\nexport function parseStartArgs(argv: readonly string[]): StartArgs | string {\n const args: StartArgs = { stdio: false }\n for (let i = 0; i < argv.length; i++) {\n const tok = argv[i]!\n if (tok === \"--stdio\") {\n args.stdio = true\n continue\n }\n if (!tok.startsWith(\"--\")) return `unexpected argument \"${tok}\"`\n const eq = tok.indexOf(\"=\")\n const name = eq < 0 ? tok.slice(2) : tok.slice(2, eq)\n if (name !== \"port\" && name !== \"host\") return `unknown flag --${name}`\n const value = eq < 0 ? argv[++i] : tok.slice(eq + 1)\n if (value === undefined || value === \"\") return `--${name} requires a value`\n if (name === \"port\") {\n const port = Number(value)\n if (!isPort(port)) return \"--port must be an integer between 0 and 65535\"\n args.port = port\n } else args.host = value\n }\n if (args.stdio && (args.port !== undefined || args.host !== undefined)) return \"--port and --host do not apply to --stdio\"\n return args\n}\n\nfunction envPort(value: string | undefined): number | undefined {\n if (value === undefined || value === \"\") return undefined\n const port = Number(value)\n if (!isPort(port)) throw new Error(`PORT must be an integer between 0 and 65535 (got \"${value}\")`)\n return port\n}\n\nfunction isPort(n: number): boolean {\n return Number.isInteger(n) && n >= 0 && n <= 65_535\n}\n\nfunction dirUrl(dir: string | URL): URL {\n if (typeof dir !== \"string\") return dir.href.endsWith(\"/\") ? dir : new URL(`${dir.href}/`)\n const abs = resolve(dir)\n return pathToFileURL(abs.endsWith(sep) ? abs : `${abs}${sep}`)\n}\n\nfunction processSignal(): { signal: AbortSignal; dispose(): void } {\n const controller = new AbortController()\n const abort = (): void => controller.abort()\n process.once(\"SIGINT\", abort)\n process.once(\"SIGTERM\", abort)\n return {\n signal: controller.signal,\n dispose() {\n process.off(\"SIGINT\", abort)\n process.off(\"SIGTERM\", abort)\n },\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"start.js","sourceRoot":"","sources":["../src/start.ts"],"names":[],"mappings":"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","sourcesContent":["import { readFileSync } from \"node:fs\"\nimport { resolve, sep } from \"node:path\"\nimport { fileURLToPath, pathToFileURL } from \"node:url\"\nimport { COMMAND, isCommand, type Command } from \"./command.ts\"\nimport { mcpDeclarations, mcpStdioDeclarations, resolveLocalPrincipal, resolveSecret, SECRET_ENV, type MextConfig } from \"./config.ts\"\nimport { loadInstrumentation, type Instrumentation } from \"./instrumentation.ts\"\nimport { MANIFEST_SCHEMA_VERSION, type BuildManifest, type BuildManifestCommand } from \"./manifest.ts\"\nimport { DEFAULT_HOST, DEFAULT_PORT } from \"./mcp/constants.ts\"\nimport { createMcpFetchHandler, startMcpHttpServer, type McpFetchHandler, type McpHttpOptions } from \"./mcp/http.ts\"\nimport { redirectStdout, serveMcpStdio } from \"./mcp/stdio.ts\"\nimport { createLazyRegistry, type Registry } from \"./registry.ts\"\nimport { createLazyPromptSet, isPrompt, type PromptSet } from \"./prompt.ts\"\nimport { createLazyResourceSet, isResource, type ResourceSet } from \"./resource.ts\"\nimport type { RouteEntry, RouteModule } from \"./route.ts\"\nimport { mextVersion } from \"./version.ts\"\n\n/**\n * @obov/mext/start: .mext/ (mext build 산출) 실행 런타임. 소스 스캔 · TypeScript 없음.\n * 생성 파일 계약 (mext build 가 쓰는 server.js · handler.js, 바꾸면 기존 빌드가 깨진다):\n * server.js process.exitCode = await startFromBuild(new URL(\".\", import.meta.url), { argv: process.argv.slice(2), env: process.env })\n * handler.js export default createFetchHandler(new URL(\".\", import.meta.url))\n *\n * 로드 순서 = manifest.json (검증) → instrumentation.js (register) → config.js → manifest 기반 lazy Registry.\n * 명령어 모듈은 그 명령어를 실행할 때 import (help · tools/list · UNKNOWN_COMMAND · 권한 거부는 import 없음)\n */\n\nexport { mainLocalBin, runLocalBin } from \"./local-bin.ts\"\nexport type { LocalBinOptions } from \"./local-bin.ts\"\n\nexport interface StartOptions {\n /** server.js · mext start 뒤 인자. --stdio · --port <n> · --host <h> */\n argv?: readonly string[]\n /** PORT · HOST. 기본 process.env */\n env?: Record<string, string | undefined>\n /** abort = 종료. 기본 SIGINT · SIGTERM */\n signal?: AbortSignal\n /** 기본 process.stderr */\n stderr?: { write(chunk: string): unknown }\n}\n\nexport interface FetchHandler {\n /**\n * 거부하지 않는다. 초기화 실패 · 내부 오류 = 500 JSON-RPC 오류.\n * rest 중 waitUntil 함수를 가진 객체 (Cloudflare ctx · Vercel 등) = 응답 후 task 실행 유지. 없으면 tasks 확장 미선언 (§10 · §12.6)\n */\n fetch(request: Request, ...rest: unknown[]): Promise<Response>\n}\n\n/** .mext/ 로드 결과 */\nexport interface LoadedBuild {\n manifest: BuildManifest\n config: MextConfig\n registry: Registry\n instrumentation: Instrumentation\n /** manifest.routes → lazy RouteEntry (모듈은 처음 요청에서 import) */\n routes: RouteEntry[]\n}\n\nexport interface LoadBuildOptions {\n /** 명령어 모듈 import (테스트 계측). 기본 = 동적 import */\n importModule?: (href: string) => Promise<unknown>\n}\n\nconst USAGE = \"Usage: mext start [--stdio] [--port <n>] [--host <h>] (node .mext/server.js, PORT · HOST environment variables)\"\n\n/** .mext/ 실행 (mext start · node .mext/server.js). 반환 = exit code */\nexport async function startFromBuild(dir: string | URL, options: StartOptions = {}): Promise<number> {\n const stderr = options.stderr ?? process.stderr\n const env = options.env ?? process.env\n const args = parseStartArgs(options.argv ?? [])\n if (typeof args === \"string\") {\n stderr.write(`error: ${args}\\n${USAGE}\\n`)\n return 2\n }\n // stdio: 사용자 코드 import 전부터 그 외 stdout 쓰기를 stderr 로 (mext dev --stdio 와 같음)\n const redirect = args.stdio ? redirectStdout() : undefined\n const { signal, dispose } = options.signal ? { signal: options.signal, dispose: () => {} } : processSignal()\n try {\n const build = await loadBuild(dir)\n const onerror = (error: Error): void => void stderr.write(`mcp: ${error.message}\\n`)\n if (args.stdio) {\n const server = serveMcpStdio({\n registry: build.registry,\n instrumentation: build.instrumentation,\n manifestHash: build.manifest.manifestHash,\n principal: await resolveLocalPrincipal(build.config),\n ...(build.config.app ? { app: build.config.app } : {}),\n ...(build.config.tools ? { tools: build.config.tools } : {}),\n ...mcpStdioDeclarations(build.config, env),\n stdout: redirect!.wire,\n onerror,\n })\n const onAbort = (): void => void server.close()\n if (signal.aborted) onAbort()\n signal.addEventListener(\"abort\", onAbort, { once: true })\n await server.closed\n return 0\n }\n const port = args.port ?? envPort(env.PORT) ?? build.config.server?.port ?? DEFAULT_PORT\n const host = args.host ?? (env.HOST === undefined || env.HOST === \"\" ? undefined : env.HOST) ?? build.config.server?.host ?? DEFAULT_HOST\n const http = httpOptions(build, onerror, env)\n if (resolveSecret(build.config, env) === undefined) {\n stderr.write(\n `warning: no secret (mext.config.ts secret or ${SECRET_ENV}). ctx.ask retries after the first answer fail across instances and restarts\\n`,\n )\n }\n const server = await startMcpHttpServer({ ...http, server: { ...http.server, host, port } })\n stderr.write(`MCP server (Streamable HTTP) listening on ${server.url} (buildId ${build.manifest.buildId})\\n`)\n await new Promise<void>((done) => {\n if (signal.aborted) return done()\n signal.addEventListener(\"abort\", () => done(), { once: true })\n })\n await server.close()\n return 0\n } catch (error) {\n // 시작 실패 = stdout 원복 (stdio 서버를 띄우기 전)\n redirect?.restore()\n stderr.write(`error: ${error instanceof Error ? error.message : String(error)}\\n`)\n return 1\n } finally {\n dispose()\n }\n}\n\n/**\n * handler.js 의 Web fetch handler ({ fetch(request) → Response }). 동기 반환.\n * D7: 초기화 (manifest 검증 · instrumentation register · config · Registry) = 첫 요청에서 1회 (memoized promise).\n * 초기화 실패 = 그 요청 500 + JSON-RPC 오류 (data.loadError), 다음 요청에서 재시도.\n * MCP 처리 (Origin · auth · 헤더 검증 · SSE progress · MRTR) = node 서버와 같은 createMcpFetchHandler\n */\nexport function createFetchHandler(dir: string | URL, options: LoadBuildOptions = {}): FetchHandler {\n const base = dirUrl(dir)\n const onerror = (error: Error): void => console.error(`mcp: ${error.message}`)\n let pending: Promise<McpFetchHandler> | undefined\n const init = (): Promise<McpFetchHandler> =>\n (pending ??= loadBuild(base, options)\n .then((build) => createMcpFetchHandler({ ...httpOptions(build, onerror), taskExecution: \"waitUntil\" }))\n .catch((error: unknown) => {\n pending = undefined\n throw error\n }))\n return {\n async fetch(request, ...rest) {\n let handler: McpFetchHandler\n try {\n handler = await init()\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n onerror(error instanceof Error ? error : new Error(message))\n const body = { jsonrpc: \"2.0\", id: null, error: { code: -32_603, message: \"Server failed to start\", data: { loadError: message } } }\n return new Response(JSON.stringify(body), { status: 500, headers: { \"Content-Type\": \"application/json\" } })\n }\n const waitUntil = findWaitUntil(rest)\n return handler.fetch(request, waitUntil ? { waitUntil } : undefined)\n },\n }\n}\n\n/** fetch(request, ...rest) 의 rest 에서 waitUntil 함수를 가진 객체 (this 유지) */\nfunction findWaitUntil(rest: readonly unknown[]): ((promise: Promise<unknown>) => void) | undefined {\n for (const value of rest) {\n const holder = value as { waitUntil?: unknown } | null\n if (typeof holder === \"object\" && holder !== null && typeof holder.waitUntil === \"function\") {\n const fn = holder.waitUntil as (promise: Promise<unknown>) => void\n return (promise) => fn.call(holder, promise)\n }\n }\n return undefined\n}\n\n/** .mext/manifest.json 읽기 + 검증 (없음 · schemaVersion · mextVersion 불일치 = 오류) */\nexport function readBuildManifest(dir: string | URL): BuildManifest {\n const base = dirUrl(dir)\n let text: string\n try {\n text = readFileSync(new URL(\"manifest.json\", base), \"utf8\")\n } catch {\n throw new Error(`no build found in ${fileURLToPath(base)} (manifest.json missing). Run \"mext build\" first`)\n }\n const manifest = JSON.parse(text) as BuildManifest\n if (manifest.schemaVersion !== MANIFEST_SCHEMA_VERSION) {\n throw new Error(\n `${fileURLToPath(base)} was built with manifest schemaVersion ${String(manifest.schemaVersion)} (expected ${MANIFEST_SCHEMA_VERSION}). Run \"mext build\" again`,\n )\n }\n if (manifest.mextVersion !== mextVersion()) {\n throw new Error(\n `${fileURLToPath(base)} was built with @obov/mext ${manifest.mextVersion}, but ${mextVersion()} is installed. Run \"mext build\" again`,\n )\n }\n return manifest\n}\n\n/** manifest 검증 → instrumentation.js (register, 사용자 코드보다 먼저) → config.js → lazy Registry */\nexport async function loadBuild(dir: string | URL, options: LoadBuildOptions = {}): Promise<LoadedBuild> {\n const base = dirUrl(dir)\n const manifest = readBuildManifest(base)\n const instrumentation = await loadInstrumentation(\n manifest.instrumentation === undefined ? undefined : new URL(manifest.instrumentation, base),\n )\n const config =\n manifest.config === undefined\n ? {}\n : ((await import(new URL(manifest.config, base).href)) as { default: MextConfig }).default\n const registry = registryFromManifest(manifest, base, options)\n return { manifest, config, registry, instrumentation, routes: routesFromManifest(manifest, base, options) }\n}\n\n/** manifest.routes → RouteEntry. 405 = manifest 의 methods 만, 모듈 (routes[].module) 은 load() 에서 import */\nexport function routesFromManifest(manifest: BuildManifest, dir: string | URL, options: LoadBuildOptions = {}): RouteEntry[] {\n const base = dirUrl(dir)\n const importModule = options.importModule ?? ((href: string) => import(href))\n return (manifest.routes ?? []).map((r) => ({\n path: r.path,\n file: r.file,\n methods: r.methods,\n load: async () => (await importModule(new URL(r.module, base).href)) as RouteModule,\n }))\n}\n\n/**\n * manifest → lazy Registry. 명령어 모듈 (manifest.commands[].module) · 자원 모듈 (resources[].module) ·\n * 프롬프트 모듈 (prompts[].module) 은 load() 에서 import\n */\nexport function registryFromManifest(manifest: BuildManifest, dir: string | URL, options: LoadBuildOptions = {}): Registry {\n const base = dirUrl(dir)\n const importModule = options.importModule ?? ((href: string) => import(href))\n const resources = resourcesFromManifest(manifest, base, importModule)\n const prompts = promptsFromManifest(manifest, base, importModule)\n const registry = createLazyRegistry({\n commands: manifest.commands.map((c) => ({\n id: c.id,\n command: metadataCommand(c),\n aliases: c.aliases,\n ...(c.file !== undefined ? { file: c.file } : {}),\n inputSchema: c.inputSchema,\n ...(c.outputSchema !== undefined ? { outputSchema: c.outputSchema } : {}),\n async load() {\n const href = new URL(c.module, base).href\n const mod = (await importModule(href)) as { default?: unknown } | undefined\n if (!isCommand(mod?.default)) throw new Error(`${c.module}: default export is not a defineCommand result (command ${c.id})`)\n return mod.default\n },\n })),\n namespaces: [\n ...(manifest.description !== undefined ? [{ id: \"\", description: manifest.description }] : []),\n ...manifest.namespaces,\n ],\n })\n return { ...registry, ...(resources ? { resources } : {}), ...(prompts ? { prompts } : {}) }\n}\n\n/** manifest.prompts → lazy PromptSet. 없거나 비면 undefined (프롬프트 기능 없음) */\nfunction promptsFromManifest(\n manifest: BuildManifest,\n base: URL,\n importModule: (href: string) => Promise<unknown>,\n): PromptSet | undefined {\n if (!manifest.prompts || manifest.prompts.length === 0) return undefined\n return createLazyPromptSet(\n manifest.prompts.map(({ module, ...p }) => ({\n ...p,\n async load() {\n const mod = (await importModule(new URL(module, base).href)) as { default?: unknown } | undefined\n if (!isPrompt(mod?.default)) throw new Error(`${module}: default export is not a definePrompt result (prompt ${p.name})`)\n return mod.default\n },\n })),\n )\n}\n\n/** manifest.resources → lazy ResourceSet. 없거나 비면 undefined (자원 기능 없음) */\nfunction resourcesFromManifest(\n manifest: BuildManifest,\n base: URL,\n importModule: (href: string) => Promise<unknown>,\n): ResourceSet | undefined {\n if (!manifest.resources || manifest.resources.length === 0) return undefined\n return createLazyResourceSet(\n manifest.resources.map(({ module, ...r }) => ({\n ...r,\n async load() {\n const mod = (await importModule(new URL(module, base).href)) as { default?: unknown } | undefined\n if (!isResource(mod?.default) || mod.default.uri !== r.uri) {\n throw new Error(`${module}: default export is not the defineResource result for ${r.uri}`)\n }\n return mod.default\n },\n })),\n )\n}\n\n/**\n * manifest 메타데이터만 있는 Command (RegisteredCommand.command). input · execute 는 모듈 로드 전이라 접근 = 오류\n * (invoke 는 loadCommand 결과를 쓴다)\n */\nfunction metadataCommand(c: BuildManifestCommand): Command {\n const parent = c.id.includes(\".\") ? c.id.slice(0, c.id.lastIndexOf(\".\") + 1) : \"\"\n const notLoaded = (): never => {\n throw new Error(`${c.id}: command module is not loaded (use loadCommand)`)\n }\n return Object.freeze({\n [COMMAND]: true as const,\n description: c.description,\n get input(): never {\n return notLoaded()\n },\n output: undefined,\n readOnly: c.readOnly,\n destructive: c.destructive,\n requiresConfirmation: c.requiresConfirmation,\n scopes: Object.freeze([...c.scopes]),\n examples: Object.freeze([...c.examples]) as Command[\"examples\"],\n positional: Object.freeze([...c.positional]),\n aliases: Object.freeze(c.aliases.map((a) => (a.startsWith(parent) ? a.slice(parent.length) : a))),\n ...(c.task !== undefined ? { task: Object.freeze({ ttlMs: c.task.ttlMs }) } : {}),\n execute: notLoaded,\n })\n}\n\nfunction httpOptions(\n build: LoadedBuild,\n onerror: (error: Error) => void,\n env: Record<string, string | undefined> = process.env,\n): McpHttpOptions {\n const { config } = build\n return {\n registry: build.registry,\n instrumentation: build.instrumentation,\n manifestHash: build.manifest.manifestHash,\n ...(config.app ? { app: config.app } : {}),\n ...(config.auth ? { auth: config.auth } : {}),\n ...(config.tools ? { tools: config.tools } : {}),\n ...(config.oauth ? { oauth: config.oauth } : {}),\n ...(build.routes.length > 0 ? { routes: build.routes } : {}),\n ...mcpDeclarations(config, env),\n server: config.server?.allowedOrigins ? { allowedOrigins: config.server.allowedOrigins } : {},\n onerror,\n }\n}\n\ninterface StartArgs {\n stdio: boolean\n port?: number\n host?: string\n}\n\n/** 반환 문자열 = 사용법 오류 */\nexport function parseStartArgs(argv: readonly string[]): StartArgs | string {\n const args: StartArgs = { stdio: false }\n for (let i = 0; i < argv.length; i++) {\n const tok = argv[i]!\n if (tok === \"--stdio\") {\n args.stdio = true\n continue\n }\n if (!tok.startsWith(\"--\")) return `unexpected argument \"${tok}\"`\n const eq = tok.indexOf(\"=\")\n const name = eq < 0 ? tok.slice(2) : tok.slice(2, eq)\n if (name !== \"port\" && name !== \"host\") return `unknown flag --${name}`\n const value = eq < 0 ? argv[++i] : tok.slice(eq + 1)\n if (value === undefined || value === \"\") return `--${name} requires a value`\n if (name === \"port\") {\n const port = Number(value)\n if (!isPort(port)) return \"--port must be an integer between 0 and 65535\"\n args.port = port\n } else args.host = value\n }\n if (args.stdio && (args.port !== undefined || args.host !== undefined)) return \"--port and --host do not apply to --stdio\"\n return args\n}\n\nfunction envPort(value: string | undefined): number | undefined {\n if (value === undefined || value === \"\") return undefined\n const port = Number(value)\n if (!isPort(port)) throw new Error(`PORT must be an integer between 0 and 65535 (got \"${value}\")`)\n return port\n}\n\nfunction isPort(n: number): boolean {\n return Number.isInteger(n) && n >= 0 && n <= 65_535\n}\n\nfunction dirUrl(dir: string | URL): URL {\n if (typeof dir !== \"string\") return dir.href.endsWith(\"/\") ? dir : new URL(`${dir.href}/`)\n const abs = resolve(dir)\n return pathToFileURL(abs.endsWith(sep) ? abs : `${abs}${sep}`)\n}\n\nfunction processSignal(): { signal: AbortSignal; dispose(): void } {\n const controller = new AbortController()\n const abort = (): void => controller.abort()\n process.once(\"SIGINT\", abort)\n process.once(\"SIGTERM\", abort)\n return {\n signal: controller.signal,\n dispose() {\n process.off(\"SIGINT\", abort)\n process.off(\"SIGTERM\", abort)\n },\n }\n}\n"]}
|
package/dist/state.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* State (§12.1): 도입 프로젝트가 mext.config.ts 의 state 로 주입하는 저장소 · 메시지 버스.
|
|
3
|
+
* 없으면 stateless. mext 는 인터페이스와 단일 프로세스용 memoryState() 만 제공한다 (Redis · DB 어댑터는 도입 프로젝트 몫).
|
|
4
|
+
*
|
|
5
|
+
* 값은 문자열 (mext 가 JSON 직렬화). mext 가 쓰는 키 · 채널은 "mext:" 접두.
|
|
6
|
+
* 키마다 writer 가 하나라서 compare-and-set 이 필요 없다.
|
|
7
|
+
*/
|
|
8
|
+
export interface MextStore {
|
|
9
|
+
get(key: string): Promise<string | undefined>;
|
|
10
|
+
/** ttlMs 후 만료 */
|
|
11
|
+
set(key: string, value: string, options: {
|
|
12
|
+
ttlMs: number;
|
|
13
|
+
}): Promise<void>;
|
|
14
|
+
delete(key: string): Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
export interface MextBus {
|
|
17
|
+
publish(channel: string, message: string): Promise<void>;
|
|
18
|
+
/** 반환 = 해제 */
|
|
19
|
+
subscribe(channel: string, onMessage: (message: string) => void): Promise<() => Promise<void>>;
|
|
20
|
+
}
|
|
21
|
+
export interface MextState {
|
|
22
|
+
store: MextStore;
|
|
23
|
+
/** 선택. 없으면 인스턴스 간 전달 = store 폴링, 자원 구독 = 같은 프로세스만 */
|
|
24
|
+
bus?: MextBus;
|
|
25
|
+
}
|
|
26
|
+
/** mext 가 쓰는 store 키 · bus 채널 접두 */
|
|
27
|
+
export declare const STATE_KEY_PREFIX = "mext:";
|
|
28
|
+
export interface MemoryStateOptions {
|
|
29
|
+
/** 시계 (테스트). 기본 Date.now */
|
|
30
|
+
now?: () => number;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* 단일 프로세스용 state (mext dev · stdio · 인스턴스 1개). 프로세스가 끝나면 사라진다.
|
|
34
|
+
* 만료 = 읽을 때 판정 + set 때 주기적으로 정리
|
|
35
|
+
*/
|
|
36
|
+
export declare function memoryState(options?: MemoryStateOptions): Required<MextState>;
|
|
37
|
+
/** state 형식 검사. 틀리면 이유 문자열 */
|
|
38
|
+
export declare function stateProblem(value: unknown): string | undefined;
|
package/dist/state.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* State (§12.1): 도입 프로젝트가 mext.config.ts 의 state 로 주입하는 저장소 · 메시지 버스.
|
|
3
|
+
* 없으면 stateless. mext 는 인터페이스와 단일 프로세스용 memoryState() 만 제공한다 (Redis · DB 어댑터는 도입 프로젝트 몫).
|
|
4
|
+
*
|
|
5
|
+
* 값은 문자열 (mext 가 JSON 직렬화). mext 가 쓰는 키 · 채널은 "mext:" 접두.
|
|
6
|
+
* 키마다 writer 가 하나라서 compare-and-set 이 필요 없다.
|
|
7
|
+
*/
|
|
8
|
+
/** mext 가 쓰는 store 키 · bus 채널 접두 */
|
|
9
|
+
export const STATE_KEY_PREFIX = "mext:";
|
|
10
|
+
/**
|
|
11
|
+
* 단일 프로세스용 state (mext dev · stdio · 인스턴스 1개). 프로세스가 끝나면 사라진다.
|
|
12
|
+
* 만료 = 읽을 때 판정 + set 때 주기적으로 정리
|
|
13
|
+
*/
|
|
14
|
+
export function memoryState(options = {}) {
|
|
15
|
+
const now = options.now ?? Date.now;
|
|
16
|
+
const entries = new Map();
|
|
17
|
+
const channels = new Map();
|
|
18
|
+
let writes = 0;
|
|
19
|
+
const sweep = () => {
|
|
20
|
+
const t = now();
|
|
21
|
+
for (const [key, entry] of entries)
|
|
22
|
+
if (entry.expiresAt <= t)
|
|
23
|
+
entries.delete(key);
|
|
24
|
+
};
|
|
25
|
+
const store = {
|
|
26
|
+
async get(key) {
|
|
27
|
+
const entry = entries.get(key);
|
|
28
|
+
if (entry === undefined)
|
|
29
|
+
return undefined;
|
|
30
|
+
if (entry.expiresAt <= now()) {
|
|
31
|
+
entries.delete(key);
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
return entry.value;
|
|
35
|
+
},
|
|
36
|
+
async set(key, value, { ttlMs }) {
|
|
37
|
+
if (!(ttlMs > 0))
|
|
38
|
+
throw new RangeError("ttlMs must be a positive number");
|
|
39
|
+
entries.set(key, { value, expiresAt: now() + ttlMs });
|
|
40
|
+
if (++writes % 256 === 0)
|
|
41
|
+
sweep();
|
|
42
|
+
},
|
|
43
|
+
async delete(key) {
|
|
44
|
+
entries.delete(key);
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
const bus = {
|
|
48
|
+
async publish(channel, message) {
|
|
49
|
+
for (const handler of [...(channels.get(channel) ?? [])]) {
|
|
50
|
+
try {
|
|
51
|
+
handler(message);
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
// 구독자 예외는 발행자에게 전파하지 않는다 (다른 인스턴스의 구독자와 같은 의미)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
async subscribe(channel, onMessage) {
|
|
59
|
+
let set = channels.get(channel);
|
|
60
|
+
if (set === undefined)
|
|
61
|
+
channels.set(channel, (set = new Set()));
|
|
62
|
+
const handler = (message) => onMessage(message);
|
|
63
|
+
set.add(handler);
|
|
64
|
+
return async () => {
|
|
65
|
+
set.delete(handler);
|
|
66
|
+
if (set.size === 0)
|
|
67
|
+
channels.delete(channel);
|
|
68
|
+
};
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
return { store, bus };
|
|
72
|
+
}
|
|
73
|
+
/** state 형식 검사. 틀리면 이유 문자열 */
|
|
74
|
+
export function stateProblem(value) {
|
|
75
|
+
if (!isObject(value))
|
|
76
|
+
return "state must be an object ({ store, bus? }), e.g. memoryState()";
|
|
77
|
+
const { store, bus } = value;
|
|
78
|
+
if (!isObject(store))
|
|
79
|
+
return "state.store must be an object with get · set · delete functions";
|
|
80
|
+
const missing = ["get", "set", "delete"].filter((k) => typeof store[k] !== "function");
|
|
81
|
+
if (missing.length > 0)
|
|
82
|
+
return `state.store.${missing.join(" · ")} must be a function`;
|
|
83
|
+
if (bus !== undefined) {
|
|
84
|
+
if (!isObject(bus))
|
|
85
|
+
return "state.bus must be an object with publish · subscribe functions";
|
|
86
|
+
const missingBus = ["publish", "subscribe"].filter((k) => typeof bus[k] !== "function");
|
|
87
|
+
if (missingBus.length > 0)
|
|
88
|
+
return `state.bus.${missingBus.join(" · ")} must be a function`;
|
|
89
|
+
}
|
|
90
|
+
const extra = Object.keys(value).filter((k) => k !== "store" && k !== "bus");
|
|
91
|
+
if (extra.length > 0)
|
|
92
|
+
return `unknown state key${extra.length === 1 ? "" : "s"}: ${extra.join(", ")}`;
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
95
|
+
function isObject(value) {
|
|
96
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * State (§12.1): 도입 프로젝트가 mext.config.ts 의 state 로 주입하는 저장소 · 메시지 버스.\n * 없으면 stateless. mext 는 인터페이스와 단일 프로세스용 memoryState() 만 제공한다 (Redis · DB 어댑터는 도입 프로젝트 몫).\n *\n * 값은 문자열 (mext 가 JSON 직렬화). mext 가 쓰는 키 · 채널은 \"mext:\" 접두.\n * 키마다 writer 가 하나라서 compare-and-set 이 필요 없다.\n */\n\nexport interface MextStore {\n get(key: string): Promise<string | undefined>\n /** ttlMs 후 만료 */\n set(key: string, value: string, options: { ttlMs: number }): Promise<void>\n delete(key: string): Promise<void>\n}\n\nexport interface MextBus {\n publish(channel: string, message: string): Promise<void>\n /** 반환 = 해제 */\n subscribe(channel: string, onMessage: (message: string) => void): Promise<() => Promise<void>>\n}\n\nexport interface MextState {\n store: MextStore\n /** 선택. 없으면 인스턴스 간 전달 = store 폴링, 자원 구독 = 같은 프로세스만 */\n bus?: MextBus\n}\n\n/** mext 가 쓰는 store 키 · bus 채널 접두 */\nexport const STATE_KEY_PREFIX = \"mext:\"\n\nexport interface MemoryStateOptions {\n /** 시계 (테스트). 기본 Date.now */\n now?: () => number\n}\n\n/**\n * 단일 프로세스용 state (mext dev · stdio · 인스턴스 1개). 프로세스가 끝나면 사라진다.\n * 만료 = 읽을 때 판정 + set 때 주기적으로 정리\n */\nexport function memoryState(options: MemoryStateOptions = {}): Required<MextState> {\n const now = options.now ?? Date.now\n const entries = new Map<string, { value: string; expiresAt: number }>()\n const channels = new Map<string, Set<(message: string) => void>>()\n let writes = 0\n\n const sweep = (): void => {\n const t = now()\n for (const [key, entry] of entries) if (entry.expiresAt <= t) entries.delete(key)\n }\n\n const store: MextStore = {\n async get(key) {\n const entry = entries.get(key)\n if (entry === undefined) return undefined\n if (entry.expiresAt <= now()) {\n entries.delete(key)\n return undefined\n }\n return entry.value\n },\n async set(key, value, { ttlMs }) {\n if (!(ttlMs > 0)) throw new RangeError(\"ttlMs must be a positive number\")\n entries.set(key, { value, expiresAt: now() + ttlMs })\n if (++writes % 256 === 0) sweep()\n },\n async delete(key) {\n entries.delete(key)\n },\n }\n\n const bus: MextBus = {\n async publish(channel, message) {\n for (const handler of [...(channels.get(channel) ?? [])]) {\n try {\n handler(message)\n } catch {\n // 구독자 예외는 발행자에게 전파하지 않는다 (다른 인스턴스의 구독자와 같은 의미)\n }\n }\n },\n async subscribe(channel, onMessage) {\n let set = channels.get(channel)\n if (set === undefined) channels.set(channel, (set = new Set()))\n const handler = (message: string): void => onMessage(message)\n set.add(handler)\n return async () => {\n set.delete(handler)\n if (set.size === 0) channels.delete(channel)\n }\n },\n }\n\n return { store, bus }\n}\n\n/** state 형식 검사. 틀리면 이유 문자열 */\nexport function stateProblem(value: unknown): string | undefined {\n if (!isObject(value)) return \"state must be an object ({ store, bus? }), e.g. memoryState()\"\n const { store, bus } = value as { store?: unknown; bus?: unknown }\n if (!isObject(store)) return \"state.store must be an object with get · set · delete functions\"\n const missing = [\"get\", \"set\", \"delete\"].filter((k) => typeof (store as Record<string, unknown>)[k] !== \"function\")\n if (missing.length > 0) return `state.store.${missing.join(\" · \")} must be a function`\n if (bus !== undefined) {\n if (!isObject(bus)) return \"state.bus must be an object with publish · subscribe functions\"\n const missingBus = [\"publish\", \"subscribe\"].filter((k) => typeof (bus as Record<string, unknown>)[k] !== \"function\")\n if (missingBus.length > 0) return `state.bus.${missingBus.join(\" · \")} must be a function`\n }\n const extra = Object.keys(value).filter((k) => k !== \"store\" && k !== \"bus\")\n if (extra.length > 0) return `unknown state key${extra.length === 1 ? \"\" : \"s\"}: ${extra.join(\", \")}`\n return undefined\n}\n\nfunction isObject(value: unknown): value is object {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n}\n"]}
|