mega-framework 0.1.5 → 0.1.7
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/bin/mega-ws-hub.js +2 -2
- package/package.json +32 -8
- package/sample/crud/.env +156 -8
- package/sample/crud/.env.example +153 -28
- package/sample/crud/.mega/journal/history/20260612092543-create-users.json +261 -0
- package/sample/crud/.mega/journal/snapshot.json +261 -0
- package/sample/crud/apps/main/controllers/auth-controller.js +22 -14
- package/sample/crud/apps/main/controllers/web-controller.js +7 -5
- package/sample/crud/apps/main/migrations/20260606000001-create-users.js +91 -13
- package/sample/crud/apps/main/migrations/20260606000002-create-boards.js +165 -0
- package/sample/crud/apps/main/migrations/20260606000003-create-logs.js +107 -0
- package/sample/crud/apps/main/models/log-partition-model.js +105 -0
- package/sample/crud/apps/main/models/note-model.js +79 -0
- package/sample/crud/apps/main/models/user-level-model.js +24 -0
- package/sample/crud/apps/main/models/user-model.js +146 -0
- package/sample/crud/apps/main/models/user-type-model.js +21 -0
- package/sample/crud/apps/main/models/wallet-model.js +24 -0
- package/sample/crud/apps/main/routes/users.js +55 -10
- package/sample/crud/apps/main/schedules/log-partition-schedule.js +33 -0
- package/sample/crud/apps/main/services/auth-service.js +39 -24
- package/sample/crud/apps/main/services/log-partition-service.js +101 -0
- package/sample/crud/apps/main/services/note-service.js +6 -6
- package/sample/crud/apps/main/services/redis-demo-service.js +3 -3
- package/sample/crud/apps/main/services/user-service.js +62 -21
- package/sample/crud/apps/main/views/auth/login.ejs +6 -6
- package/sample/crud/apps/main/views/auth/register.ejs +46 -5
- package/sample/crud/apps/main/views/users/edit.ejs +42 -5
- package/sample/crud/apps/main/views/users/list.ejs +6 -2
- package/sample/crud/apps/main/views/users/new.ejs +56 -4
- package/sample/crud/docs/log_partition_design.mm.md +23 -0
- package/sample/crud/mega.config.js +63 -3
- package/sample/crud/package.json +3 -3
- package/sample/crud/scripts/start-ws-hub.sh +2 -2
- package/sample/simple/package.json +2 -2
- package/src/adapters/adapter-manager.js +2 -1
- package/src/adapters/adapter-options.js +30 -0
- package/src/adapters/maria-adapter.js +26 -3
- package/src/adapters/mega-db-adapter.js +7 -1
- package/src/adapters/mongo-adapter.js +19 -1
- package/src/adapters/postgres-adapter.js +25 -2
- package/src/adapters/sqlite-adapter.js +20 -1
- package/src/cli/commands/new.js +13 -3
- package/src/cli/commands/scaffold.js +137 -33
- package/src/cli/generators/index.js +82 -2
- package/src/cli/index.js +478 -104
- package/src/core/ajv-mapper.js +27 -2
- package/src/core/boot.js +485 -237
- package/src/core/cluster-metrics.js +13 -4
- package/src/core/config-validator.js +25 -0
- package/src/core/ctx-builder.js +6 -2
- package/src/core/envelope.js +112 -12
- package/src/core/hub-link.js +65 -4
- package/src/core/i18n.js +11 -1
- package/src/core/index.js +6 -2
- package/src/core/mega-app.js +223 -481
- package/src/core/mega-cluster.js +54 -13
- package/src/core/mega-server.js +40 -9
- package/src/core/migration/dialect-registry.js +107 -0
- package/src/core/migration/dialects/README.md +62 -0
- package/src/core/migration/dialects/maria.js +496 -0
- package/src/core/migration/dialects/mongo.js +824 -0
- package/src/core/migration/dialects/postgres.js +563 -0
- package/src/core/migration/dialects/sqlite.js +476 -0
- package/src/core/migration/differ.js +456 -0
- package/src/core/migration/generate.js +508 -0
- package/src/core/migration/journal.js +167 -0
- package/src/core/migration/model-scan.js +84 -0
- package/src/core/migration/mongo-migration-db.js +97 -0
- package/src/core/migration/schema-builder.js +400 -0
- package/src/core/migration/schema-validator.js +315 -0
- package/src/core/migration-lock.js +205 -0
- package/src/core/migration-runner.js +166 -38
- package/src/core/multipart.js +28 -5
- package/src/core/pipeline.js +129 -0
- package/src/core/router.js +70 -65
- package/src/core/scope-registry.js +0 -1
- package/src/core/security.js +67 -9
- package/src/core/workers-manager.js +12 -1
- package/src/core/ws-cluster.js +10 -3
- package/src/core/ws-message.js +48 -4
- package/src/core/ws-presence.js +624 -0
- package/src/core/ws-roster.js +4 -1
- package/src/core/ws-upgrade.js +118 -12
- package/src/index.js +1 -1
- package/src/lib/hub-protocol.js +29 -0
- package/src/lib/mega-health.js +25 -4
- package/src/lib/mega-job-queue.js +98 -21
- package/src/lib/mega-job.js +29 -0
- package/src/lib/mega-logger.js +1 -1
- package/src/lib/mega-metrics.js +3 -12
- package/src/lib/mega-plugin.js +34 -3
- package/src/lib/mega-schedule.js +40 -22
- package/src/lib/mega-shutdown.js +162 -49
- package/src/lib/mega-tracing.js +66 -19
- package/src/lib/mega-worker.js +5 -1
- package/src/lib/otel-resource.js +36 -0
- package/src/{cli → lib}/ws-hub.js +51 -8
- package/src/models/crud-sql-builder.js +133 -0
- package/src/models/mega-model.js +82 -2
- package/src/models/model-crud.js +483 -0
- package/src/models/mongo-crud.js +285 -0
- package/templates/model/code-mongo.tpl +35 -0
- package/templates/model/code.tpl +15 -1
- package/templates/model/test-mongo.tpl +38 -0
- package/templates/model/test.tpl +4 -0
- package/types/adapters/adapter-manager.d.ts +95 -0
- package/types/adapters/adapter-options.d.ts +91 -0
- package/types/adapters/file-adapter.d.ts +94 -0
- package/types/adapters/file-session-adapter.d.ts +101 -0
- package/types/adapters/index.d.ts +20 -0
- package/types/adapters/maria-adapter.d.ts +115 -0
- package/types/adapters/mega-adapter.d.ts +215 -0
- package/types/adapters/mega-bus-adapter.d.ts +45 -0
- package/types/adapters/mega-cache-adapter.d.ts +47 -0
- package/types/adapters/mega-db-adapter.d.ts +47 -0
- package/types/adapters/mega-lock-adapter.d.ts +62 -0
- package/types/adapters/mega-log-sink-adapter.d.ts +15 -0
- package/types/adapters/mega-session-adapter.d.ts +32 -0
- package/types/adapters/mongo-adapter.d.ts +139 -0
- package/types/adapters/nats-adapter.d.ts +108 -0
- package/types/adapters/postgres-adapter.d.ts +139 -0
- package/types/adapters/redis-adapter.d.ts +70 -0
- package/types/adapters/redis-session-adapter.d.ts +82 -0
- package/types/adapters/redlock-adapter.d.ts +149 -0
- package/types/adapters/registry.d.ts +46 -0
- package/types/adapters/sqlite-adapter.d.ts +106 -0
- package/types/auth/index.d.ts +24 -0
- package/types/cli/commands/console-cmd.d.ts +37 -0
- package/types/cli/commands/new.d.ts +16 -0
- package/types/cli/commands/routes.d.ts +36 -0
- package/types/cli/commands/scaffold.d.ts +78 -0
- package/types/cli/commands/test-cmd.d.ts +14 -0
- package/types/cli/generators/index.d.ts +112 -0
- package/types/cli/index.d.ts +249 -0
- package/types/cli/template-engine.d.ts +40 -0
- package/types/core/ajv-mapper.d.ts +27 -0
- package/types/core/boot.d.ts +233 -0
- package/types/core/cluster-metrics.d.ts +52 -0
- package/types/core/config-loader.d.ts +13 -0
- package/types/core/config-validator.d.ts +30 -0
- package/types/core/ctx-builder.d.ts +80 -0
- package/types/core/envelope.d.ts +79 -0
- package/types/core/error-mapper.d.ts +17 -0
- package/types/core/formbody.d.ts +41 -0
- package/types/core/hub-link.d.ts +264 -0
- package/types/core/i18n.d.ts +178 -0
- package/types/core/index.d.ts +28 -0
- package/types/core/mega-app.d.ts +529 -0
- package/types/core/mega-cluster.d.ts +104 -0
- package/types/core/mega-server.d.ts +91 -0
- package/types/core/mega-service.d.ts +31 -0
- package/types/core/migration/dialect-registry.d.ts +22 -0
- package/types/core/migration/dialects/maria.d.ts +99 -0
- package/types/core/migration/dialects/mongo.d.ts +89 -0
- package/types/core/migration/dialects/postgres.d.ts +117 -0
- package/types/core/migration/dialects/sqlite.d.ts +111 -0
- package/types/core/migration/differ.d.ts +47 -0
- package/types/core/migration/generate.d.ts +56 -0
- package/types/core/migration/journal.d.ts +52 -0
- package/types/core/migration/model-scan.d.ts +19 -0
- package/types/core/migration/mongo-migration-db.d.ts +7 -0
- package/types/core/migration/schema-builder.d.ts +197 -0
- package/types/core/migration/schema-validator.d.ts +20 -0
- package/types/core/migration-lock.d.ts +33 -0
- package/types/core/migration-runner.d.ts +101 -0
- package/types/core/multipart.d.ts +86 -0
- package/types/core/openapi.d.ts +62 -0
- package/types/core/pipeline.d.ts +92 -0
- package/types/core/router.d.ts +159 -0
- package/types/core/routes-loader.d.ts +21 -0
- package/types/core/scope-registry.d.ts +14 -0
- package/types/core/security.d.ts +77 -0
- package/types/core/services-loader.d.ts +27 -0
- package/types/core/session-cleanup-schedule.d.ts +19 -0
- package/types/core/session-store.d.ts +18 -0
- package/types/core/session.d.ts +77 -0
- package/types/core/static-assets.d.ts +73 -0
- package/types/core/template.d.ts +106 -0
- package/types/core/workers-manager.d.ts +79 -0
- package/types/core/ws-cluster.d.ts +208 -0
- package/types/core/ws-compression.d.ts +112 -0
- package/types/core/ws-controller.d.ts +65 -0
- package/types/core/ws-message.d.ts +106 -0
- package/types/core/ws-presence.d.ts +273 -0
- package/types/core/ws-roster.d.ts +96 -0
- package/types/core/ws-upgrade.d.ts +231 -0
- package/types/errors/config-error.d.ts +10 -0
- package/types/errors/http-errors.d.ts +120 -0
- package/types/errors/index.d.ts +3 -0
- package/types/errors/mega-error.d.ts +32 -0
- package/types/index.d.ts +39 -0
- package/types/lib/asp/config.d.ts +49 -0
- package/types/lib/asp/crypto.d.ts +43 -0
- package/types/lib/asp/errors.d.ts +30 -0
- package/types/lib/asp/nonce-cache.d.ts +52 -0
- package/types/lib/asp/plugin.d.ts +30 -0
- package/types/lib/asp/ws-terminator.d.ts +45 -0
- package/types/lib/env-mapper.d.ts +14 -0
- package/types/lib/hub-protocol.d.ts +106 -0
- package/types/lib/index.d.ts +22 -0
- package/types/lib/logger/telegram-core.d.ts +104 -0
- package/types/lib/logger/telegram-transport.d.ts +45 -0
- package/types/lib/mega-brute-force.d.ts +66 -0
- package/types/lib/mega-circuit-breaker.d.ts +241 -0
- package/types/lib/mega-cron.d.ts +66 -0
- package/types/lib/mega-hash.d.ts +32 -0
- package/types/lib/mega-health.d.ts +41 -0
- package/types/lib/mega-job-queue.d.ts +176 -0
- package/types/lib/mega-job-worker.d.ts +130 -0
- package/types/lib/mega-job.d.ts +138 -0
- package/types/lib/mega-logger.d.ts +45 -0
- package/types/lib/mega-metrics.d.ts +285 -0
- package/types/lib/mega-plugin.d.ts +245 -0
- package/types/lib/mega-retry.d.ts +85 -0
- package/types/lib/mega-schedule.d.ts +260 -0
- package/types/lib/mega-shutdown.d.ts +135 -0
- package/types/lib/mega-tracing.d.ts +224 -0
- package/types/lib/mega-worker.d.ts +127 -0
- package/types/lib/otel-resource.d.ts +16 -0
- package/types/lib/worker-runner/process-entry.d.ts +1 -0
- package/types/lib/worker-runner/task-dispatch.d.ts +28 -0
- package/types/lib/worker-runner/thread-entry.d.ts +1 -0
- package/types/lib/ws-hub.d.ts +234 -0
- package/types/models/crud-sql-builder.d.ts +48 -0
- package/types/models/index.d.ts +1 -0
- package/types/models/mega-model.d.ts +138 -0
- package/types/models/model-crud.d.ts +82 -0
- package/types/models/mongo-crud.d.ts +59 -0
- package/types/test/index.d.ts +84 -0
- package/.env +0 -127
- package/sample/crud/apps/main/migrations/20260606000002-add-auth-to-users.js +0 -30
- package/sample/crud/apps/main/models/note.js +0 -71
- package/sample/crud/apps/main/models/user.js +0 -86
- package/sample/crud/package-lock.json +0 -5665
- package/sample/crud/yarn.lock +0 -2142
- package/sample/simple/package-lock.json +0 -1851
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {object} Artifact
|
|
3
|
+
* @property {string} outAbs - 쓸 파일 절대경로.
|
|
4
|
+
* @property {string} content - 렌더된 내용.
|
|
5
|
+
* @property {'code'|'test'|'task'|'route'} role
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* kind 별로 생성할 artifact 목록을 계획한다(아직 디스크에 쓰지 않음).
|
|
9
|
+
* @param {string} kind
|
|
10
|
+
* @param {string} rawName
|
|
11
|
+
* @param {Record<string, any>} opts - { app, version, kind(adapter), lng, ns }
|
|
12
|
+
* @param {string} projectRoot
|
|
13
|
+
* @returns {Artifact[]}
|
|
14
|
+
*/
|
|
15
|
+
export function planArtifacts(kind: string, rawName: string, opts: Record<string, any>, projectRoot: string): Artifact[];
|
|
16
|
+
/**
|
|
17
|
+
* 계획된 artifact 를 디스크에 쓴다. 이미 있으면 건너뛴다(force 면 덮어씀).
|
|
18
|
+
* @param {Artifact[]} artifacts
|
|
19
|
+
* @param {{ force?: boolean }} [opts]
|
|
20
|
+
* @returns {{ written: string[], skipped: string[] }}
|
|
21
|
+
*/
|
|
22
|
+
export function writeArtifacts(artifacts: Artifact[], { force }?: {
|
|
23
|
+
force?: boolean;
|
|
24
|
+
}): {
|
|
25
|
+
written: string[];
|
|
26
|
+
skipped: string[];
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* 플러그인 scaffold manifest(`mega.scaffold.register(name, { dir, files, description? })`,
|
|
30
|
+
* 03-api-spec §11 / ADR-199)를 artifact 목록으로 계획한다 — 빌트인 13종과 같은 plan→write 2단 분리.
|
|
31
|
+
* 토큰 계약은 {@link SCAFFOLD_TOKENS} 가 정본이며 미정의 토큰은 renderTemplate 가 throw(P4).
|
|
32
|
+
* `files[].path` 에도 토큰을 쓸 수 있다(예 `services/{{name}}-service.js`).
|
|
33
|
+
*
|
|
34
|
+
* @param {{ dir: string, files: Array<{ path: string, template: string }> }} def - 플러그인 등록 정의.
|
|
35
|
+
* @param {string} rawName - `mega g <kind> <name>` 의 name.
|
|
36
|
+
* @param {Record<string, any>} opts - { app }.
|
|
37
|
+
* @param {string} projectRoot - 출력 기준 루트. `def.dir` 는 이 루트 상대.
|
|
38
|
+
* @returns {Artifact[]}
|
|
39
|
+
* @throws {Error} def 파일 항목이 `{ path, template }` 문자열 쌍이 아니거나, 출력 경로가 projectRoot 를
|
|
40
|
+
* 벗어나면(경로 탐색 차단 — template.js resolveViewPath 정합) fail-fast.
|
|
41
|
+
*/
|
|
42
|
+
export function planScaffoldDef(def: {
|
|
43
|
+
dir: string;
|
|
44
|
+
files: Array<{
|
|
45
|
+
path: string;
|
|
46
|
+
template: string;
|
|
47
|
+
}>;
|
|
48
|
+
}, rawName: string, opts: Record<string, any>, projectRoot: string): Artifact[];
|
|
49
|
+
/**
|
|
50
|
+
* 플러그인 등록 scaffold generator 실행 — `mega g <plugin-generator> <name>` 의 본체. 빌트인 `generate`
|
|
51
|
+
* 와 같은 계획 → 쓰기 → 결과 계약(존재 파일 skip, `--force` 덮어쓰기).
|
|
52
|
+
* @param {string} kindName - 플러그인이 등록한 generator 이름(결과 보고용).
|
|
53
|
+
* @param {{ dir: string, files: Array<{ path: string, template: string }> }} def
|
|
54
|
+
* @param {string} rawName
|
|
55
|
+
* @param {object} [opts] - { app, force }
|
|
56
|
+
* @param {string} [projectRoot]
|
|
57
|
+
* @returns {{ kind: string, name: string, written: string[], skipped: string[] }}
|
|
58
|
+
*/
|
|
59
|
+
export function generateFromScaffoldDef(kindName: string, def: {
|
|
60
|
+
dir: string;
|
|
61
|
+
files: Array<{
|
|
62
|
+
path: string;
|
|
63
|
+
template: string;
|
|
64
|
+
}>;
|
|
65
|
+
}, rawName: string, opts?: object, projectRoot?: string): {
|
|
66
|
+
kind: string;
|
|
67
|
+
name: string;
|
|
68
|
+
written: string[];
|
|
69
|
+
skipped: string[];
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* `mega g <kind> <name>` 실행 — 계획 → 쓰기 → 결과 반환.
|
|
73
|
+
* @param {string} kind
|
|
74
|
+
* @param {string} rawName
|
|
75
|
+
* @param {object} [opts] - { app, version, kind(adapter), lng, force }
|
|
76
|
+
* @param {string} [projectRoot]
|
|
77
|
+
* @returns {{ kind: string, name: string, written: string[], skipped: string[] }}
|
|
78
|
+
*/
|
|
79
|
+
export function generate(kind: string, rawName: string, opts?: object, projectRoot?: string): {
|
|
80
|
+
kind: string;
|
|
81
|
+
name: string;
|
|
82
|
+
written: string[];
|
|
83
|
+
skipped: string[];
|
|
84
|
+
};
|
|
85
|
+
/** 지원 generator 종류(roadmap §337 — 13종). */
|
|
86
|
+
export const GENERATOR_KINDS: readonly ["app", "controller", "channel", "service", "model", "middleware", "route", "schedule", "job", "worker", "locale", "adapter", "migration"];
|
|
87
|
+
/**
|
|
88
|
+
* 플러그인 scaffold manifest 의 토큰 계약(ADR-199) — `files[].path`/`files[].template` 의 `{{token}}`
|
|
89
|
+
* 에 쓸 수 있는 이름과 의미. 빌트인 generator 의 base 토큰과 동일 집합이라 템플릿 작성 관례가 하나다.
|
|
90
|
+
* 미정의 토큰은 renderTemplate 가 throw 한다(P4 — silent 치환 누락 방지).
|
|
91
|
+
* @type {Readonly<Record<string, string>>}
|
|
92
|
+
*/
|
|
93
|
+
export const SCAFFOLD_TOKENS: Readonly<Record<string, string>>;
|
|
94
|
+
export type Artifact = {
|
|
95
|
+
/**
|
|
96
|
+
* - 쓸 파일 절대경로.
|
|
97
|
+
*/
|
|
98
|
+
outAbs: string;
|
|
99
|
+
/**
|
|
100
|
+
* - 렌더된 내용.
|
|
101
|
+
*/
|
|
102
|
+
content: string;
|
|
103
|
+
role: "code" | "test" | "task" | "route";
|
|
104
|
+
};
|
|
105
|
+
export type Variants = {
|
|
106
|
+
kebab: string;
|
|
107
|
+
pascal: string;
|
|
108
|
+
camel: string;
|
|
109
|
+
snake: string;
|
|
110
|
+
words: string[];
|
|
111
|
+
};
|
|
112
|
+
export type BaseVars = Record<string, string>;
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 프로젝트 루트의 `.env` 를 `process.env` 로 로드한다(파일이 있을 때만). Node 내장
|
|
3
|
+
* `process.loadEnvFile`(20.6+) 사용 — 신규 dep 0. **이미 설정된 실제 환경변수는 덮어쓰지 않는다**
|
|
4
|
+
* (`--env-file` 과 동일 우선순위 — 실 env 우선). config(`mega.config.js`)들이 `process.env.X` 를
|
|
5
|
+
* 참조하고 비밀은 `.env` 에만 두는 컨벤션(CLAUDE.md)을 CLI 가 보장한다(ADR-152). config 로드보다 먼저
|
|
6
|
+
* 호출해야 `process.env` 참조가 채워진다.
|
|
7
|
+
*
|
|
8
|
+
* @param {string} projectRoot - `.env` 를 찾을 프로젝트 루트(`--root` 또는 cwd).
|
|
9
|
+
* @param {{ debug?: Function }} [logger]
|
|
10
|
+
* @returns {boolean} 로드했으면 true, `.env` 부재면 false.
|
|
11
|
+
* @throws {Error} `.env` 가 존재하나 파싱 실패 시(fail-fast — silent 무시 X).
|
|
12
|
+
*/
|
|
13
|
+
export function loadProjectEnv(projectRoot: string, logger?: {
|
|
14
|
+
debug?: Function;
|
|
15
|
+
}): boolean;
|
|
16
|
+
/**
|
|
17
|
+
* 인자 토큰을 `{ _: positionals[], flags: {} }` 로 파싱. `--key=value` / `--key value` / `--flag`(=true).
|
|
18
|
+
* commander 일원화(ADR-195) 이후에도 두 용도로 남는다 — ① runCli 의 사전 스캔(`--root`·명령어 판별,
|
|
19
|
+
* commander 진입 전), ② 플러그인 CLI 명령 핸들러 인자 계약(`handler({ _, flags })`, 03-api-spec §11).
|
|
20
|
+
* @param {string[]} argv - `process.argv.slice(2)` 형태.
|
|
21
|
+
* @returns {{ _: string[], flags: Record<string, string | boolean> }}
|
|
22
|
+
*/
|
|
23
|
+
export function parseArgs(argv: string[]): {
|
|
24
|
+
_: string[];
|
|
25
|
+
flags: Record<string, string | boolean>;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* cluster 워커 수 설정값을 실제 워커 수로 해석한다(ADR-154 / 04-data-models §MegaServerConfig).
|
|
29
|
+
*
|
|
30
|
+
* 유효 도메인: **양의 정수** 또는 **'max'**(= CPU 코어 수). 그 외(0·음수·소수·'max' 아닌 문자열)는
|
|
31
|
+
* fail-closed 로 throw 한다 — 잘못된 값을 1로 조용히 강등하면 운영자가 클러스터가 안 뜬 줄 모른다(P4/P7).
|
|
32
|
+
* 워커가 1개로 해석되면(설정 `1`, 또는 단일 코어의 'max') 마스터+워커 2프로세스는 오버헤드만 더하므로
|
|
33
|
+
* **단일 프로세스(클러스터 비활성)** 로 본다 → `null` 반환.
|
|
34
|
+
*
|
|
35
|
+
* @param {string | number | boolean | undefined | null} setting - `--cluster` 플래그 / `MEGA_CLUSTER_WORKERS`
|
|
36
|
+
* env / `server.cluster` config 값. 미지정(`undefined`/`null`/`''`)은 단일 프로세스. 베어 `--cluster`(=true)는 'max'.
|
|
37
|
+
* @param {() => number} [cpuCount] - CPU 코어 수 공급자(테스트 주입용). 기본 {@link defaultCpuCount}.
|
|
38
|
+
* @returns {number | null} 워커 수(≥2) 또는 단일 프로세스면 `null`.
|
|
39
|
+
* @throws {MegaConfigError} `config.invalid_cluster` — 양의 정수도 'max' 도 아닌 값.
|
|
40
|
+
*/
|
|
41
|
+
export function resolveClusterWorkers(setting: string | number | boolean | undefined | null, cpuCount?: () => number): number | null;
|
|
42
|
+
/**
|
|
43
|
+
* `--port` 플래그를 검증된 listen 포트로 해석한다(fail-closed — {@link resolveClusterWorkers} 와 동형).
|
|
44
|
+
*
|
|
45
|
+
* 유효 도메인: **0~65535 정수**. 미지정(`undefined`)은 config/기본값에 위임하려 `undefined` 를 돌려준다.
|
|
46
|
+
* 값 없는 베어 `--port`(=`true`)·빈 값 `--port=`(=`''`)·정수 아님·범위 밖은 throw 한다 — 잘못된 값을
|
|
47
|
+
* 조용히 강등하면(`Number(true)=1` 특권포트, `Number('')=0` 랜덤포트, `Number('abc')=NaN` 은 어댑터
|
|
48
|
+
* connect 까지 부팅한 뒤 Node 가 `ERR_SOCKET_BAD_PORT` 로 늦게 throw) 운영자가 의도와 다른 포트를 쓰거나
|
|
49
|
+
* 늦은 cryptic 에러를 만난다(P4/P7). 명시적 `--port 0`(OS 랜덤 포트)은 정상 값으로 허용한다.
|
|
50
|
+
*
|
|
51
|
+
* @param {string | boolean | undefined | null} setting - `--port` 플래그 값.
|
|
52
|
+
* @returns {number | undefined} 검증된 포트, 또는 미지정이면 `undefined`(config/기본 위임).
|
|
53
|
+
* @throws {MegaConfigError} `config.invalid_port` — 값 없음/빈 값/정수 아님/범위 밖.
|
|
54
|
+
*/
|
|
55
|
+
export function resolvePort(setting: string | boolean | undefined | null): number | undefined;
|
|
56
|
+
/**
|
|
57
|
+
* `--host` 플래그를 검증된 listen 호스트로 해석한다(fail-closed). 미지정은 config/기본값에 위임하려
|
|
58
|
+
* `undefined`. 값 없는 베어 `--host`·빈 값 `--host=`는 throw — 빈 호스트를 `MegaServer` 로 흘리면
|
|
59
|
+
* Node 가 전 인터페이스(`::`)에 silent bind 해 운영자 의도와 달라진다(P4). 비어 있지 않은 문자열은 그대로.
|
|
60
|
+
*
|
|
61
|
+
* @param {string | boolean | undefined | null} setting - `--host` 플래그 값.
|
|
62
|
+
* @returns {string | undefined} 검증된 호스트, 또는 미지정이면 `undefined`(config/기본 위임).
|
|
63
|
+
* @throws {MegaConfigError} `config.invalid_host` — 값 없음/빈 값.
|
|
64
|
+
*/
|
|
65
|
+
export function resolveHost(setting: string | boolean | undefined | null): string | undefined;
|
|
66
|
+
/**
|
|
67
|
+
* `--root` 플래그를 검증된 프로젝트 루트로 해석한다(fail-closed — {@link resolveHost} 와 동형, OQ-029②).
|
|
68
|
+
*
|
|
69
|
+
* 미지정은 cwd 폴백에 위임하려 `undefined`. 값 없는 베어 `--root`(=`true`)·빈 값 `--root=`(=`''`)은
|
|
70
|
+
* throw — 빈 루트를 통과시키면 `join('', '.env')`/`loadAndValidateConfig('')` 가 cwd 상대로 silent
|
|
71
|
+
* 오동작해 운영자가 의도한 루트 지정 실패를 모른다(P4/P7). 비어 있지 않은 문자열은 그대로.
|
|
72
|
+
*
|
|
73
|
+
* @param {string | boolean | undefined | null} setting - `--root` 플래그 값.
|
|
74
|
+
* @returns {string | undefined} 검증된 루트, 또는 미지정이면 `undefined`(cwd 폴백 위임).
|
|
75
|
+
* @throws {MegaConfigError} `config.invalid_root` — 값 없음/빈 값.
|
|
76
|
+
*/
|
|
77
|
+
export function resolveRoot(setting: string | boolean | undefined | null): string | undefined;
|
|
78
|
+
/**
|
|
79
|
+
* `--db` 플래그를 검증된 마이그레이션 대상 키로 해석한다(fail-closed — {@link resolveRoot} 와 동형, OQ-029②).
|
|
80
|
+
*
|
|
81
|
+
* 미지정은 자동 선택(`resolveMigrationAdapter` 의 유일 db/primary 규칙)에 위임하려 `undefined`. 값 없는
|
|
82
|
+
* 베어 `--db`(=`true`)·빈 값 `--db=`(=`''`)은 throw — 빈 키가 자동 선택으로 silent 강등되면 운영자가
|
|
83
|
+
* 지정 실패를 모른 채 다른 db 에 마이그레이션을 적용할 수 있다(P4/P7).
|
|
84
|
+
*
|
|
85
|
+
* @param {string | boolean | undefined | null} setting - `--db` 플래그 값.
|
|
86
|
+
* @returns {string | undefined} 검증된 db 키, 또는 미지정이면 `undefined`(자동 선택 위임).
|
|
87
|
+
* @throws {MegaConfigError} `config.invalid_db` — 값 없음/빈 값.
|
|
88
|
+
*/
|
|
89
|
+
export function resolveDb(setting: string | boolean | undefined | null): string | undefined;
|
|
90
|
+
/**
|
|
91
|
+
* `mega start --watch` 가 자신을 `node --watch` 로 재실행해야 하는지 (ADR-182). `--watch` 플래그가 있고
|
|
92
|
+
* 아직 watch 하에 재실행되지 않았을 때만 true — 가드 env(`MEGA_WATCH_REEXEC`)로 무한재귀를 막는다.
|
|
93
|
+
* @param {Record<string, string|boolean>} flags
|
|
94
|
+
* @param {Record<string, string|undefined>} env
|
|
95
|
+
* @returns {boolean}
|
|
96
|
+
*/
|
|
97
|
+
export function shouldReexecForWatch(flags: Record<string, string | boolean>, env: Record<string, string | undefined>): boolean;
|
|
98
|
+
/**
|
|
99
|
+
* `mega start --watch` → `node --watch … <self> start … --cluster 1` 재실행 명령을 빌드한다 (ADR-182).
|
|
100
|
+
*
|
|
101
|
+
* - `--watch` 인자는 **node 플래그**로 옮기고 mega 인자에선 제거한다.
|
|
102
|
+
* - **단일 프로세스 강제**(`--cluster 1`) — 멀티워커 watch 카오스 방지(기존 `--cluster` 값은 무시).
|
|
103
|
+
* - watchPaths 가 있으면 `--watch-path=…`(이게 모듈 그래프 watch 를 **대체**하므로 앱 소스·전역설정 경로를
|
|
104
|
+
* 명시해야 한다 — 실측 확인). 없으면 plain `--watch`(모듈 그래프 폴백).
|
|
105
|
+
*
|
|
106
|
+
* @param {Object} o
|
|
107
|
+
* @param {string[]} o.argv - 원본 mega argv(예: `['start','--watch','--port','3000']`).
|
|
108
|
+
* @param {string[]} o.watchPaths - 감시할 절대경로(존재하는 것만).
|
|
109
|
+
* @param {string} o.selfPath - mega 진입 스크립트(`process.argv[1]`).
|
|
110
|
+
* @param {string} o.execPath - node 바이너리(`process.execPath`).
|
|
111
|
+
* @returns {{ command: string, args: string[] }}
|
|
112
|
+
*/
|
|
113
|
+
export function buildWatchCommand({ argv, watchPaths, selfPath, execPath }: {
|
|
114
|
+
argv: string[];
|
|
115
|
+
watchPaths: string[];
|
|
116
|
+
selfPath: string;
|
|
117
|
+
execPath: string;
|
|
118
|
+
}): {
|
|
119
|
+
command: string;
|
|
120
|
+
args: string[];
|
|
121
|
+
};
|
|
122
|
+
/**
|
|
123
|
+
* `mega` CLI 진입점. 파싱 → 명령 분기. **이 함수는 process.exit 를 호출하지 않는다**(테스트 가능) —
|
|
124
|
+
* exit code 를 반환하고, bin 래퍼가 `process.exitCode` 로 반영한다.
|
|
125
|
+
*
|
|
126
|
+
* @param {string[]} argv - `process.argv.slice(2)`.
|
|
127
|
+
* @param {Object} [deps] - 테스트 주입용.
|
|
128
|
+
* @param {(msg: string) => void} [deps.out] - stdout writer(기본 console.log).
|
|
129
|
+
* @param {(msg: string) => void} [deps.err] - stderr writer(기본 console.error).
|
|
130
|
+
* @param {string} [deps.cwd] - 기본 projectRoot(기본 process.cwd()).
|
|
131
|
+
* @param {{ debug?: Function, info?: Function, warn?: Function }} [deps.logger]
|
|
132
|
+
* @param {Function} [deps.spawn] - child_process.spawn 주입(기본 node:child_process). `--watch` 재실행 테스트용.
|
|
133
|
+
* @param {string} [deps.selfPath] - mega 진입 스크립트 경로(기본 `process.argv[1]`). `--watch` 재실행 대상.
|
|
134
|
+
* @returns {Promise<number>} exit code(0=성공, 1=실패/미지정 명령).
|
|
135
|
+
*/
|
|
136
|
+
export function runCli(argv: string[], { out, err, cwd, logger, spawn, selfPath }?: {
|
|
137
|
+
out?: (msg: string) => void;
|
|
138
|
+
err?: (msg: string) => void;
|
|
139
|
+
cwd?: string;
|
|
140
|
+
logger?: {
|
|
141
|
+
debug?: Function;
|
|
142
|
+
info?: Function;
|
|
143
|
+
warn?: Function;
|
|
144
|
+
};
|
|
145
|
+
spawn?: Function;
|
|
146
|
+
selfPath?: string;
|
|
147
|
+
}): Promise<number>;
|
|
148
|
+
/**
|
|
149
|
+
* 플러그인 CLI 명령을 dispatch 한다 — config 로드 → 플러그인 install → `host.getCommand(name)` 조회.
|
|
150
|
+
* 어댑터 connect 는 하지 않는다(명령 핸들러가 필요하면 자체 처리 — 골격은 가볍게 유지, ADR-123).
|
|
151
|
+
*
|
|
152
|
+
* @param {string} projectRoot
|
|
153
|
+
* @param {string} name - 명령 이름.
|
|
154
|
+
* @param {{ _: string[], flags: Record<string, string | boolean> }} args - 핸들러에 그대로 전달.
|
|
155
|
+
* @param {{ debug?: Function }} [logger]
|
|
156
|
+
* @returns {Promise<{ found: boolean, code: number }>}
|
|
157
|
+
*/
|
|
158
|
+
export function dispatchPluginCommand(projectRoot: string, name: string, args: {
|
|
159
|
+
_: string[];
|
|
160
|
+
flags: Record<string, string | boolean>;
|
|
161
|
+
}, logger?: {
|
|
162
|
+
debug?: Function;
|
|
163
|
+
}): Promise<{
|
|
164
|
+
found: boolean;
|
|
165
|
+
code: number;
|
|
166
|
+
}>;
|
|
167
|
+
/**
|
|
168
|
+
* 잡/스케줄 **등록 소스 흡수**(ADR-123) — `config.<key>`(정적) + 플러그인 `host.list*()`(동적)을 합친다.
|
|
169
|
+
* 명시 등록만(auto-discovery X, ADR-079 정합). 순수 함수라 단위 검증 가능(register 부작용 분리).
|
|
170
|
+
* @param {Object} global - global config(`jobs`/`schedules` 배열 보유 가능).
|
|
171
|
+
* @param {import('../lib/mega-plugin.js').MegaPluginHost} host
|
|
172
|
+
* @param {'jobs' | 'schedules'} kind
|
|
173
|
+
* @returns {Function[]} 등록할 클래스 목록(config 먼저, 플러그인 등록분 뒤).
|
|
174
|
+
*/
|
|
175
|
+
export function collectRegistrations(global: Object, host: import("../lib/mega-plugin.js").MegaPluginHost, kind: "jobs" | "schedules"): Function[];
|
|
176
|
+
/**
|
|
177
|
+
* `mega worker` 호스트 골격 — config + 어댑터 connect + ctx + `MegaJobWorker` 인스턴스 + graceful.
|
|
178
|
+
* 등록 소스 = `config.jobs` + 플러그인 `mega.jobs.register` 분(`collectRegistrations`, ADR-123).
|
|
179
|
+
* @param {string} projectRoot
|
|
180
|
+
* @param {{ debug?: Function, info?: Function, warn?: Function }} [logger]
|
|
181
|
+
* @returns {Promise<MegaJobWorker>}
|
|
182
|
+
*/
|
|
183
|
+
export function runWorkerHost(projectRoot: string, logger?: {
|
|
184
|
+
debug?: Function;
|
|
185
|
+
info?: Function;
|
|
186
|
+
warn?: Function;
|
|
187
|
+
}): Promise<MegaJobWorker>;
|
|
188
|
+
/**
|
|
189
|
+
* `mega scheduler` 호스트 골격 — config + 어댑터 connect + ctx + `MegaScheduler` 인스턴스 + graceful.
|
|
190
|
+
* @param {string} projectRoot
|
|
191
|
+
* @param {{ debug?: Function, info?: Function, warn?: Function }} [logger]
|
|
192
|
+
* @returns {Promise<MegaScheduler>}
|
|
193
|
+
*/
|
|
194
|
+
export function runSchedulerHost(projectRoot: string, logger?: {
|
|
195
|
+
debug?: Function;
|
|
196
|
+
info?: Function;
|
|
197
|
+
warn?: Function;
|
|
198
|
+
}): Promise<MegaScheduler>;
|
|
199
|
+
/**
|
|
200
|
+
* 마이그레이션 대상 DB 어댑터 해석 — `services.databases` 의 globalKey 로 조회한다. `--db <key>` 미지정
|
|
201
|
+
* 시 유일 선언 db, 그게 아니면 `primary`, 둘 다 아니면(다중·미선언) fail-fast 로 명시를 요구한다.
|
|
202
|
+
*
|
|
203
|
+
* 러너는 SQL `query` 기반이라(ADR-149 ⑥) `query` 도메인 메서드를 구현하지 않은 어댑터(mongodb 등
|
|
204
|
+
* Document DB)는 대상이 될 수 없다 — 베이스의 `adapter.not_implemented` 가 늦게 터지는 대신 여기서
|
|
205
|
+
* `migrate.unsupported_driver` 로 명시 fail-fast 한다(ADR-190).
|
|
206
|
+
*
|
|
207
|
+
* @param {Object} global - global config.
|
|
208
|
+
* @param {string} [dbKey] - `--db` 플래그.
|
|
209
|
+
* @returns {import('../adapters/mega-adapter.js').MegaAdapter}
|
|
210
|
+
*/
|
|
211
|
+
export function resolveMigrationAdapter(global: Object, dbKey?: string): import("../adapters/mega-adapter.js").MegaAdapter;
|
|
212
|
+
/**
|
|
213
|
+
* `mega migrate` 일회성 호스트 — config 로드 → 플러그인 install → DB build/connect → 러너 실행 →
|
|
214
|
+
* disconnect. 워커/wsHub/메트릭은 띄우지 않는다(마이그레이션엔 불필요·이벤트루프 유지 회피).
|
|
215
|
+
* `MegaShutdown.now`(process.exit)를 쓰지 않고 직접 disconnect 해 반환값으로 결과를 돌려준다(테스트 가능).
|
|
216
|
+
*
|
|
217
|
+
* up/down 은 driver 별 마이그레이션 락({@link module:core/migration-lock}, ADR-190)으로 직렬화한다 —
|
|
218
|
+
* 동시 `mega migrate`(멀티 인스턴스 배포 훅)의 중복 적용 방지. status 는 읽기 전용이라 락 없이 실행.
|
|
219
|
+
*
|
|
220
|
+
* @param {string} projectRoot
|
|
221
|
+
* @param {{ direction?: 'up'|'down'|'status', dbKey?: string, logger?: { debug?: Function, info?: Function, warn?: Function }, out?: (msg: string) => void }} [opts]
|
|
222
|
+
* @returns {Promise<{ applied: string[] } | { rolledBack: string|null } | { applied: string[], pending: string[], modified: string[] }>}
|
|
223
|
+
*/
|
|
224
|
+
export function runMigrateHost(projectRoot: string, { direction, dbKey, logger, out }?: {
|
|
225
|
+
direction?: "up" | "down" | "status";
|
|
226
|
+
dbKey?: string;
|
|
227
|
+
logger?: {
|
|
228
|
+
debug?: Function;
|
|
229
|
+
info?: Function;
|
|
230
|
+
warn?: Function;
|
|
231
|
+
};
|
|
232
|
+
out?: (msg: string) => void;
|
|
233
|
+
}): Promise<{
|
|
234
|
+
applied: string[];
|
|
235
|
+
} | {
|
|
236
|
+
rolledBack: string | null;
|
|
237
|
+
} | {
|
|
238
|
+
applied: string[];
|
|
239
|
+
pending: string[];
|
|
240
|
+
modified: string[];
|
|
241
|
+
}>;
|
|
242
|
+
/** 빌트인 명령 이름·별칭 전체 — 이 표 밖의 첫 positional 은 플러그인 명령 dispatch 로 fallthrough 한다
|
|
243
|
+
* (ADR-123 계약 유지). `buildProgram` 의 commander 등록과 동기를 유지할 것. */
|
|
244
|
+
export const BUILTIN_COMMANDS: Set<string>;
|
|
245
|
+
/** CLI 사용법 텍스트 — commander 자동 생성(ADR-195) + 플러그인 명령 안내. 명령·옵션 정의가 곧 도움말의
|
|
246
|
+
* 단일 정본이라 수기 USAGE 와의 드리프트가 없다. */
|
|
247
|
+
export const USAGE: string;
|
|
248
|
+
import { MegaJobWorker } from '../lib/mega-job-worker.js';
|
|
249
|
+
import { MegaScheduler } from '../lib/mega-schedule.js';
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* zero-dep 템플릿 엔진 + 이름 변형 유틸 (ADR-142).
|
|
3
|
+
*
|
|
4
|
+
* `templates/<kind>/*.tpl` 파일의 `{{token}}` 자리를 vars 로 치환한다. 외부 템플릿 dep(handlebars 등)
|
|
5
|
+
* 없이 `process.argv` 파싱(ADR-123)과 같은 정책으로 단순 토큰 치환만 한다 — generator 가 만드는 코드는
|
|
6
|
+
* 정적 골격이라 조건/루프 같은 복잡한 템플릿 기능이 필요 없다.
|
|
7
|
+
*
|
|
8
|
+
* 토큰 형식은 `{{word}}`(이중 중괄호)라 생성 코드의 JSDoc `@param {string}`·객체 리터럴 `{ x }`
|
|
9
|
+
* (단일 중괄호)와 충돌하지 않는다. 미정의 토큰은 즉시 throw(silent 치환 누락 방지, P4).
|
|
10
|
+
*
|
|
11
|
+
* @module cli/template-engine
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* 입력 이름을 단어 배열로 분해한다. camelCase 경계와 구분자(`-`, `_`, 공백, `.`)를 모두 단어 경계로
|
|
15
|
+
* 본다. 예: `'UserProfile'`/`'user-profile'`/`'user_profile'` → `['user','profile']`.
|
|
16
|
+
* @param {string} raw
|
|
17
|
+
* @returns {string[]}
|
|
18
|
+
*/
|
|
19
|
+
export function toWords(raw: string): string[];
|
|
20
|
+
/**
|
|
21
|
+
* 입력 이름에서 표준 변형 4종을 만든다.
|
|
22
|
+
* @param {string} raw
|
|
23
|
+
* @returns {{ kebab: string, pascal: string, camel: string, snake: string, words: string[] }}
|
|
24
|
+
* @throws {Error} 영숫자 단어가 하나도 없으면(빈/특수문자만) fail-fast.
|
|
25
|
+
*/
|
|
26
|
+
export function nameVariants(raw: string): {
|
|
27
|
+
kebab: string;
|
|
28
|
+
pascal: string;
|
|
29
|
+
camel: string;
|
|
30
|
+
snake: string;
|
|
31
|
+
words: string[];
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* 템플릿 문자열의 `{{token}}` 을 vars 값으로 치환한다.
|
|
35
|
+
* @param {string} tpl - 템플릿 본문.
|
|
36
|
+
* @param {Record<string, string>} vars - 토큰 → 값.
|
|
37
|
+
* @returns {string}
|
|
38
|
+
* @throws {Error} 템플릿에 vars 에 없는 토큰이 있으면(오타·누락 방지).
|
|
39
|
+
*/
|
|
40
|
+
export function renderTemplate(tpl: string, vars: Record<string, string>): string;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fastify 가 던진 AJV 검증 에러 객체 → MegaValidationError 로 매핑.
|
|
3
|
+
*
|
|
4
|
+
* Fastify 의 AJV 에러는 `err.validation: AjvErrorObject[]` + `err.validationContext: string`
|
|
5
|
+
* 형태. AjvErrorObject 는 { instancePath, schemaPath, keyword, message, params } 가짐.
|
|
6
|
+
*
|
|
7
|
+
* envelope details 형식 (ADR-075 배열):
|
|
8
|
+
* [{ field: string, rule: string, value?: any, message: string }, ...]
|
|
9
|
+
*
|
|
10
|
+
* @param {Error & { validation?: any[], validationContext?: string }} err
|
|
11
|
+
* @returns {MegaValidationError | null}
|
|
12
|
+
* AJV 에러가 아니면 null (호출자가 그대로 throw).
|
|
13
|
+
*/
|
|
14
|
+
export function ajvErrorToValidationError(err: Error & {
|
|
15
|
+
validation?: any[];
|
|
16
|
+
validationContext?: string;
|
|
17
|
+
}): MegaValidationError | null;
|
|
18
|
+
/**
|
|
19
|
+
* envelope `details` 배열 상한 (ADR-193 — allErrors DoS 방어의 응답측 bound).
|
|
20
|
+
*
|
|
21
|
+
* allErrors:true 는 위반을 전수 수집하므로(@fastify/ajv-compiler 디폴트가 allErrors:false 인 이유 =
|
|
22
|
+
* DoS 가능성 명시) 악의적 페이로드가 수천 개 위반을 만들 수 있다. 입력측은 Fastify bodyLimit
|
|
23
|
+
* (기본 1 MiB)이 막고, 응답·로그측은 이 cap 이 막는다 — 초과분은 잘라내되 silent 가 아니라
|
|
24
|
+
* `rule:'truncated'` 합성 항목으로 생략 개수를 명시한다.
|
|
25
|
+
*/
|
|
26
|
+
export const MAX_VALIDATION_DETAILS: 20;
|
|
27
|
+
import { MegaValidationError } from '../errors/http-errors.js';
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* boot/CLI 컨텍스트 — `db/cache/bus/lock` 을 글로벌 키로 직접 조회하고, `workers` 는 `static name` 으로
|
|
3
|
+
* lookup 한다(앱 별명 변환 없음 — 둘 다 글로벌 자원). worker/scheduler CLI 도 같은 형태를 재사용한다
|
|
4
|
+
* (잡/스케줄의 `static bus`/`static lock` = 글로벌 키; 잡이 CPU 작업을 `ctx.workers` 로 오프로드 가능).
|
|
5
|
+
* @param {Object} global - global config.
|
|
6
|
+
* @param {{ debug?: Function, info?: Function, warn?: Function }} [logger]
|
|
7
|
+
* @returns {BootContext}
|
|
8
|
+
*/
|
|
9
|
+
export function buildBootContext(global: Object, logger?: {
|
|
10
|
+
debug?: Function;
|
|
11
|
+
info?: Function;
|
|
12
|
+
warn?: Function;
|
|
13
|
+
}): BootContext;
|
|
14
|
+
/**
|
|
15
|
+
* 공유 어댑터 전수의 `healthCheck()` 를 `MegaHealth` 에 `<domain>:<globalKey>` 이름으로 등록한다.
|
|
16
|
+
* `/health/ready` 가 어댑터 생사를 실제로 반영하게 하는 배선 — `prepareRuntime` 이 connect 직후
|
|
17
|
+
* 호출한다(`health.autoChecks:false` 옵트아웃). 등록은 이름 기준 덮어쓰기라 재부팅(테스트)에도 멱등.
|
|
18
|
+
*
|
|
19
|
+
* @param {Array<{ domain: string, key: string, adapter: { healthCheck: () => Promise<{ ok: boolean }> } }>} [entries] -
|
|
20
|
+
* 대상 어댑터 엔트리(기본: 어댑터 매니저의 전체 등록분). 테스트 주입용.
|
|
21
|
+
* @returns {string[]} 등록한 체크 이름 목록.
|
|
22
|
+
*/
|
|
23
|
+
export function registerAdapterHealthChecks(entries?: Array<{
|
|
24
|
+
domain: string;
|
|
25
|
+
key: string;
|
|
26
|
+
adapter: {
|
|
27
|
+
healthCheck: () => Promise<{
|
|
28
|
+
ok: boolean;
|
|
29
|
+
}>;
|
|
30
|
+
};
|
|
31
|
+
}>): string[];
|
|
32
|
+
/**
|
|
33
|
+
* 부트 step 정의 — 부팅 시퀀스의 한 단계.
|
|
34
|
+
* @typedef {Object} BootStep
|
|
35
|
+
* @property {string} name - step 이름(로그·prerequisite 에러 식별자).
|
|
36
|
+
* @property {string[]} [needs] - 선행 step 이 state 에 만들어 둬야 하는 키(prerequisite). 누락 시
|
|
37
|
+
* `boot.step_prerequisite` throw — step 순서 변경·누락 같은 배선 실수를 즉시 드러낸다.
|
|
38
|
+
* @property {'abort'|'warn'} [onFail] - 실패 정책. `'abort'`(기본) = fail-fast throw(M-1 정리 경로),
|
|
39
|
+
* `'warn'` = best-effort(warn 로그 후 다음 step 계속 — 부팅을 막으면 안 되는 부가 단계용).
|
|
40
|
+
* @property {(state: Record<string, any>) => Promise<void>|void} run - 단계 본체. 산출물은 state 에 쓴다.
|
|
41
|
+
*/
|
|
42
|
+
/**
|
|
43
|
+
* step 배열 실행기 — 각 step 의 prerequisite 검증 → 실행 → 길목 debug 로그(start/done/tookMs).
|
|
44
|
+
* 실패는 step 의 `onFail` 정책을 따른다(기본 abort — 현재 부트 시퀀스 전 단계가 fail-fast).
|
|
45
|
+
*
|
|
46
|
+
* @param {BootStep[]} steps - 실행할 step 정의(순서 = 시퀀스 정본).
|
|
47
|
+
* @param {Record<string, any>} state - step 간 공유 상태(산출물 버스).
|
|
48
|
+
* @param {{ debug?: Function, warn?: Function }} [logger]
|
|
49
|
+
* @returns {Promise<void>}
|
|
50
|
+
* @throws {MegaConfigError} prerequisite 누락(`boot.step_prerequisite`) — 배선 오류는 즉시 abort.
|
|
51
|
+
*/
|
|
52
|
+
export function runBootSteps(steps: BootStep[], state: Record<string, any>, logger?: {
|
|
53
|
+
debug?: Function;
|
|
54
|
+
warn?: Function;
|
|
55
|
+
}): Promise<void>;
|
|
56
|
+
/**
|
|
57
|
+
* 런타임 공통 준비 — {@link PREPARE_STEPS}(config → plugins → adapters → health-auto-checks →
|
|
58
|
+
* metrics → tracing → workers → ws-hub → boot-context)를 {@link runBootSteps} 로 실행한다.
|
|
59
|
+
* `bootApp`(서버)·`mega worker`/`mega scheduler`(CLI 호스트)가 **같은 순서**를 공유한다.
|
|
60
|
+
*
|
|
61
|
+
* @param {string} projectRoot
|
|
62
|
+
* @param {{ ping?: boolean, logger?: { debug?: Function, info?: Function, warn?: Function } }} [opts]
|
|
63
|
+
* @returns {Promise<{ global: Object, apps: Array<{ name: string, config: Object }>, host: MegaPluginHost, ctx: BootContext, wsHub: (MegaWsHub | null) }>}
|
|
64
|
+
*/
|
|
65
|
+
export function prepareRuntime(projectRoot: string, { ping, logger }?: {
|
|
66
|
+
ping?: boolean;
|
|
67
|
+
logger?: {
|
|
68
|
+
debug?: Function;
|
|
69
|
+
info?: Function;
|
|
70
|
+
warn?: Function;
|
|
71
|
+
};
|
|
72
|
+
}): Promise<{
|
|
73
|
+
global: Object;
|
|
74
|
+
apps: Array<{
|
|
75
|
+
name: string;
|
|
76
|
+
config: Object;
|
|
77
|
+
}>;
|
|
78
|
+
host: MegaPluginHost;
|
|
79
|
+
ctx: BootContext;
|
|
80
|
+
wsHub: (MegaWsHub | null);
|
|
81
|
+
}>;
|
|
82
|
+
/**
|
|
83
|
+
* `global.server` 의 운영 옵션을 각 앱 Fastify 인스턴스 옵션으로 매핑한다(ADR-181, 04-data-models
|
|
84
|
+
* §MegaServerConfig). 미지정 키는 생략해 Fastify 기본값을 따른다. boot 가 모든 MegaApp 에 동일 주입한다
|
|
85
|
+
* (port/host 는 MegaServer.listen 이, 아래 런타임 옵션은 Fastify 인스턴스가 소비).
|
|
86
|
+
* - trustProxy / trustedProxies → Fastify `trustProxy`(프록시/LB 뒤 req.ip·X-Forwarded-* 신뢰).
|
|
87
|
+
* trustedProxies(목록)가 있으면 그것을, 없으면 trustProxy(boolean/number/string)를 그대로 넘긴다.
|
|
88
|
+
* - timeouts.requestMs → Fastify `requestTimeout`(요청 수신 제한, slow-loris 보호).
|
|
89
|
+
* - keepAliveMs → Fastify `keepAliveTimeout`(keep-alive 소켓 idle 제한, ALB 정합).
|
|
90
|
+
*
|
|
91
|
+
* 프로덕션(`NODE_ENV==='production'`)에서 trustProxy/trustedProxies 미설정이면 **부팅 warn 1회**(ADR-186).
|
|
92
|
+
* 프록시/LB 뒤에서 미설정 시 `req.protocol`/`req.ip` 가 프록시 기준으로 잡혀 secure 쿠키 누락·rate-limit
|
|
93
|
+
* 키 왜곡·CSRF Origin 오판으로 번진다 — 직접 listen 배포면 무시해도 되는 안내성 경고다.
|
|
94
|
+
*
|
|
95
|
+
* @param {any} server - `global.server` config(없으면 빈 객체).
|
|
96
|
+
* @param {{ logger?: { warn?: Function }, env?: Record<string, string|undefined> }} [opts] - warn 출력용
|
|
97
|
+
* logger 와 환경(테스트 주입용, 기본 `process.env`).
|
|
98
|
+
* @returns {{ trustProxy?: any, requestTimeout?: number, keepAliveTimeout?: number }}
|
|
99
|
+
*/
|
|
100
|
+
export function serverFastifyOptions(server: any, { logger, env }?: {
|
|
101
|
+
logger?: {
|
|
102
|
+
warn?: Function;
|
|
103
|
+
};
|
|
104
|
+
env?: Record<string, string | undefined>;
|
|
105
|
+
}): {
|
|
106
|
+
trustProxy?: any;
|
|
107
|
+
requestTimeout?: number;
|
|
108
|
+
keepAliveTimeout?: number;
|
|
109
|
+
};
|
|
110
|
+
/**
|
|
111
|
+
* 프로젝트를 부팅한다 — {@link BOOT_STEPS}(runtime → before-boot-hook → logger → server → apps →
|
|
112
|
+
* cluster-transport → listen → after-boot-hook → shutdown-bridge)를 {@link runBootSteps} 로 실행한다.
|
|
113
|
+
*
|
|
114
|
+
* 어느 step 이든 실패하면 그대로 throw(fail-fast, 전 step onFail='abort'). 어댑터 connect 실패는
|
|
115
|
+
* 매니저가 LIFO cleanup 하고, 그 외 단계 실패(예: server.listen EADDRINUSE, beforeBoot hook throw)는
|
|
116
|
+
* 어댑터가 이미 connect 돼 `'adapters:disconnect'` MegaShutdown hook 이 등록된 상태라, 호출자가
|
|
117
|
+
* `MegaShutdown.now` 로 그 hook 을 실행해 정리해야 한다 — `bin/mega.js` 의 catch 가 이 정리 경로를
|
|
118
|
+
* 배선한다(M-1). 그러지 않으면 연결된 어댑터가 이벤트루프를 살려 프로세스가 hang 한다.
|
|
119
|
+
*
|
|
120
|
+
* @param {string} projectRoot - 프로젝트 루트 절대 경로(mega.config.js 가 있는 곳).
|
|
121
|
+
* @param {Object} [opts]
|
|
122
|
+
* @param {boolean} [opts.listen=true] - false 면 mount 까지만(테스트·검증용).
|
|
123
|
+
* @param {number} [opts.port] - listen 포트(미지정 시 server/global 기본).
|
|
124
|
+
* @param {string} [opts.host] - listen 호스트.
|
|
125
|
+
* @param {boolean} [opts.ping=false] - connectAll 시 healthCheck 까지 검증.
|
|
126
|
+
* @param {{ debug?: Function, info?: Function, warn?: Function }} [opts.logger] - 길목 debug 로그(선택).
|
|
127
|
+
* @returns {Promise<BootResult>}
|
|
128
|
+
*/
|
|
129
|
+
export function bootApp(projectRoot: string, { listen, port, host: listenHost, ping, logger }?: {
|
|
130
|
+
listen?: boolean;
|
|
131
|
+
port?: number;
|
|
132
|
+
host?: string;
|
|
133
|
+
ping?: boolean;
|
|
134
|
+
logger?: {
|
|
135
|
+
debug?: Function;
|
|
136
|
+
info?: Function;
|
|
137
|
+
warn?: Function;
|
|
138
|
+
};
|
|
139
|
+
}): Promise<BootResult>;
|
|
140
|
+
/** prepareRuntime step 이름 시퀀스(정본) — introspection·테스트용. */
|
|
141
|
+
export const PREPARE_STEP_NAMES: readonly string[];
|
|
142
|
+
/** bootApp step 이름 시퀀스(정본) — introspection·테스트용. */
|
|
143
|
+
export const BOOT_STEP_NAMES: readonly string[];
|
|
144
|
+
/**
|
|
145
|
+
* 부팅 결과 핸들.
|
|
146
|
+
*/
|
|
147
|
+
export type BootResult = {
|
|
148
|
+
/**
|
|
149
|
+
* - mount 된 MegaServer(listen=false 면 미-listen 상태).
|
|
150
|
+
*/
|
|
151
|
+
server: MegaServer;
|
|
152
|
+
/**
|
|
153
|
+
* - 플러그인 호스트(install 완료, queryable).
|
|
154
|
+
*/
|
|
155
|
+
host: MegaPluginHost;
|
|
156
|
+
/**
|
|
157
|
+
* - mega.config.js default export(global).
|
|
158
|
+
*/
|
|
159
|
+
config: Object;
|
|
160
|
+
/**
|
|
161
|
+
* - 로드된 앱 config 목록.
|
|
162
|
+
*/
|
|
163
|
+
apps: Array<{
|
|
164
|
+
name: string;
|
|
165
|
+
config: Object;
|
|
166
|
+
}>;
|
|
167
|
+
/**
|
|
168
|
+
* - 생성된 MegaApp 인스턴스(등록 순서).
|
|
169
|
+
*/
|
|
170
|
+
megaApps: MegaApp[];
|
|
171
|
+
/**
|
|
172
|
+
* - lifecycle hook 에 넘긴 boot context.
|
|
173
|
+
*/
|
|
174
|
+
ctx: BootContext;
|
|
175
|
+
/**
|
|
176
|
+
* - embedded wsHub(ADR-137, `wsHub.enabled` OFF 면 null).
|
|
177
|
+
*/
|
|
178
|
+
wsHub: import("../lib/ws-hub.js").MegaWsHub | null;
|
|
179
|
+
/**
|
|
180
|
+
* - 공유 pino 로거(ADR-141, logger 비활성이면 null). CLI 시작 메시지 등에 재사용.
|
|
181
|
+
*/
|
|
182
|
+
appLogger: import("pino").Logger | null;
|
|
183
|
+
};
|
|
184
|
+
/**
|
|
185
|
+
* lifecycle hook(beforeBoot/afterBoot/beforeShutdown)이 받는 boot context (L-2/ADR-123).
|
|
186
|
+
* `db/cache/bus/lock` 은 **글로벌 키 직접 lookup**(앱 별명 변환 없음 — boot 레벨은 별명 스코프 밖).
|
|
187
|
+
*/
|
|
188
|
+
export type BootContext = {
|
|
189
|
+
/**
|
|
190
|
+
* - global config.
|
|
191
|
+
*/
|
|
192
|
+
config: Object;
|
|
193
|
+
log?: {
|
|
194
|
+
debug?: Function;
|
|
195
|
+
info?: Function;
|
|
196
|
+
warn?: Function;
|
|
197
|
+
};
|
|
198
|
+
db: (globalKey: string) => import("../adapters/mega-adapter.js").MegaAdapter;
|
|
199
|
+
cache: (globalKey: string) => import("../adapters/mega-adapter.js").MegaAdapter;
|
|
200
|
+
bus: (globalKey: string) => import("../adapters/mega-adapter.js").MegaAdapter;
|
|
201
|
+
lock: (globalKey: string) => import("../adapters/mega-adapter.js").MegaAdapter;
|
|
202
|
+
/**
|
|
203
|
+
* - `ctx.workers.<name>.run(task)` (ADR-124).
|
|
204
|
+
*/
|
|
205
|
+
workers: Record<string, import("../lib/mega-worker.js").MegaWorker>;
|
|
206
|
+
};
|
|
207
|
+
/**
|
|
208
|
+
* 부트 step 정의 — 부팅 시퀀스의 한 단계.
|
|
209
|
+
*/
|
|
210
|
+
export type BootStep = {
|
|
211
|
+
/**
|
|
212
|
+
* - step 이름(로그·prerequisite 에러 식별자).
|
|
213
|
+
*/
|
|
214
|
+
name: string;
|
|
215
|
+
/**
|
|
216
|
+
* - 선행 step 이 state 에 만들어 둬야 하는 키(prerequisite). 누락 시
|
|
217
|
+
* `boot.step_prerequisite` throw — step 순서 변경·누락 같은 배선 실수를 즉시 드러낸다.
|
|
218
|
+
*/
|
|
219
|
+
needs?: string[];
|
|
220
|
+
/**
|
|
221
|
+
* - 실패 정책. `'abort'`(기본) = fail-fast throw(M-1 정리 경로),
|
|
222
|
+
* `'warn'` = best-effort(warn 로그 후 다음 step 계속 — 부팅을 막으면 안 되는 부가 단계용).
|
|
223
|
+
*/
|
|
224
|
+
onFail?: "abort" | "warn";
|
|
225
|
+
/**
|
|
226
|
+
* - 단계 본체. 산출물은 state 에 쓴다.
|
|
227
|
+
*/
|
|
228
|
+
run: (state: Record<string, any>) => Promise<void> | void;
|
|
229
|
+
};
|
|
230
|
+
import { MegaPluginHost } from '../lib/mega-plugin.js';
|
|
231
|
+
import { MegaWsHub } from '../lib/ws-hub.js';
|
|
232
|
+
import { MegaServer } from './mega-server.js';
|
|
233
|
+
import { MegaApp } from './mega-app.js';
|