mega-framework 0.1.6 → 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.
Files changed (233) hide show
  1. package/bin/mega-ws-hub.js +2 -2
  2. package/package.json +32 -8
  3. package/sample/crud/.env +1 -1
  4. package/sample/crud/.env.example +1 -1
  5. package/sample/crud/.mega/journal/history/20260612092543-create-users.json +261 -0
  6. package/sample/crud/.mega/journal/snapshot.json +261 -0
  7. package/sample/crud/apps/main/controllers/auth-controller.js +22 -14
  8. package/sample/crud/apps/main/controllers/web-controller.js +7 -5
  9. package/sample/crud/apps/main/migrations/20260606000001-create-users.js +91 -13
  10. package/sample/crud/apps/main/migrations/20260606000002-create-boards.js +165 -0
  11. package/sample/crud/apps/main/migrations/20260606000003-create-logs.js +107 -0
  12. package/sample/crud/apps/main/models/log-partition-model.js +105 -0
  13. package/sample/crud/apps/main/models/note-model.js +79 -0
  14. package/sample/crud/apps/main/models/user-level-model.js +24 -0
  15. package/sample/crud/apps/main/models/user-model.js +146 -0
  16. package/sample/crud/apps/main/models/user-type-model.js +21 -0
  17. package/sample/crud/apps/main/models/wallet-model.js +24 -0
  18. package/sample/crud/apps/main/routes/users.js +55 -10
  19. package/sample/crud/apps/main/schedules/log-partition-schedule.js +33 -0
  20. package/sample/crud/apps/main/services/auth-service.js +39 -24
  21. package/sample/crud/apps/main/services/log-partition-service.js +101 -0
  22. package/sample/crud/apps/main/services/note-service.js +6 -6
  23. package/sample/crud/apps/main/services/redis-demo-service.js +3 -3
  24. package/sample/crud/apps/main/services/user-service.js +62 -21
  25. package/sample/crud/apps/main/views/auth/login.ejs +6 -6
  26. package/sample/crud/apps/main/views/auth/register.ejs +46 -5
  27. package/sample/crud/apps/main/views/users/edit.ejs +42 -5
  28. package/sample/crud/apps/main/views/users/list.ejs +6 -2
  29. package/sample/crud/apps/main/views/users/new.ejs +56 -4
  30. package/sample/crud/docs/log_partition_design.mm.md +23 -0
  31. package/sample/crud/mega.config.js +3 -2
  32. package/sample/crud/package.json +1 -1
  33. package/sample/crud/scripts/start-ws-hub.sh +2 -2
  34. package/sample/simple/package.json +2 -2
  35. package/src/adapters/adapter-manager.js +2 -1
  36. package/src/adapters/adapter-options.js +30 -0
  37. package/src/adapters/maria-adapter.js +26 -3
  38. package/src/adapters/mega-db-adapter.js +7 -1
  39. package/src/adapters/mongo-adapter.js +19 -1
  40. package/src/adapters/postgres-adapter.js +25 -2
  41. package/src/adapters/sqlite-adapter.js +20 -1
  42. package/src/cli/commands/new.js +13 -3
  43. package/src/cli/commands/scaffold.js +137 -33
  44. package/src/cli/generators/index.js +82 -2
  45. package/src/cli/index.js +353 -100
  46. package/src/core/ajv-mapper.js +27 -2
  47. package/src/core/boot.js +464 -245
  48. package/src/core/cluster-metrics.js +13 -4
  49. package/src/core/ctx-builder.js +6 -2
  50. package/src/core/envelope.js +112 -12
  51. package/src/core/hub-link.js +65 -4
  52. package/src/core/i18n.js +11 -1
  53. package/src/core/index.js +6 -2
  54. package/src/core/mega-app.js +201 -463
  55. package/src/core/mega-cluster.js +4 -1
  56. package/src/core/mega-server.js +40 -9
  57. package/src/core/migration/dialect-registry.js +107 -0
  58. package/src/core/migration/dialects/README.md +62 -0
  59. package/src/core/migration/dialects/maria.js +496 -0
  60. package/src/core/migration/dialects/mongo.js +824 -0
  61. package/src/core/migration/dialects/postgres.js +563 -0
  62. package/src/core/migration/dialects/sqlite.js +476 -0
  63. package/src/core/migration/differ.js +456 -0
  64. package/src/core/migration/generate.js +508 -0
  65. package/src/core/migration/journal.js +167 -0
  66. package/src/core/migration/model-scan.js +84 -0
  67. package/src/core/migration/mongo-migration-db.js +97 -0
  68. package/src/core/migration/schema-builder.js +400 -0
  69. package/src/core/migration/schema-validator.js +315 -0
  70. package/src/core/migration-lock.js +205 -0
  71. package/src/core/migration-runner.js +166 -38
  72. package/src/core/multipart.js +28 -5
  73. package/src/core/pipeline.js +129 -0
  74. package/src/core/router.js +70 -65
  75. package/src/core/security.js +67 -9
  76. package/src/core/workers-manager.js +12 -1
  77. package/src/core/ws-cluster.js +10 -3
  78. package/src/core/ws-message.js +48 -4
  79. package/src/core/ws-presence.js +624 -0
  80. package/src/core/ws-roster.js +4 -1
  81. package/src/core/ws-upgrade.js +118 -12
  82. package/src/index.js +1 -1
  83. package/src/lib/hub-protocol.js +29 -0
  84. package/src/lib/mega-health.js +25 -4
  85. package/src/lib/mega-job-queue.js +98 -21
  86. package/src/lib/mega-job.js +29 -0
  87. package/src/lib/mega-metrics.js +3 -12
  88. package/src/lib/mega-plugin.js +34 -3
  89. package/src/lib/mega-schedule.js +40 -22
  90. package/src/lib/mega-shutdown.js +114 -39
  91. package/src/lib/mega-tracing.js +66 -19
  92. package/src/lib/mega-worker.js +5 -1
  93. package/src/lib/otel-resource.js +36 -0
  94. package/src/{cli → lib}/ws-hub.js +51 -8
  95. package/src/models/crud-sql-builder.js +133 -0
  96. package/src/models/mega-model.js +82 -2
  97. package/src/models/model-crud.js +483 -0
  98. package/src/models/mongo-crud.js +285 -0
  99. package/templates/model/code-mongo.tpl +35 -0
  100. package/templates/model/code.tpl +15 -1
  101. package/templates/model/test-mongo.tpl +38 -0
  102. package/templates/model/test.tpl +4 -0
  103. package/types/adapters/adapter-manager.d.ts +95 -0
  104. package/types/adapters/adapter-options.d.ts +91 -0
  105. package/types/adapters/file-adapter.d.ts +94 -0
  106. package/types/adapters/file-session-adapter.d.ts +101 -0
  107. package/types/adapters/index.d.ts +20 -0
  108. package/types/adapters/maria-adapter.d.ts +115 -0
  109. package/types/adapters/mega-adapter.d.ts +215 -0
  110. package/types/adapters/mega-bus-adapter.d.ts +45 -0
  111. package/types/adapters/mega-cache-adapter.d.ts +47 -0
  112. package/types/adapters/mega-db-adapter.d.ts +47 -0
  113. package/types/adapters/mega-lock-adapter.d.ts +62 -0
  114. package/types/adapters/mega-log-sink-adapter.d.ts +15 -0
  115. package/types/adapters/mega-session-adapter.d.ts +32 -0
  116. package/types/adapters/mongo-adapter.d.ts +139 -0
  117. package/types/adapters/nats-adapter.d.ts +108 -0
  118. package/types/adapters/postgres-adapter.d.ts +139 -0
  119. package/types/adapters/redis-adapter.d.ts +70 -0
  120. package/types/adapters/redis-session-adapter.d.ts +82 -0
  121. package/types/adapters/redlock-adapter.d.ts +149 -0
  122. package/types/adapters/registry.d.ts +46 -0
  123. package/types/adapters/sqlite-adapter.d.ts +106 -0
  124. package/types/auth/index.d.ts +24 -0
  125. package/types/cli/commands/console-cmd.d.ts +37 -0
  126. package/types/cli/commands/new.d.ts +16 -0
  127. package/types/cli/commands/routes.d.ts +36 -0
  128. package/types/cli/commands/scaffold.d.ts +78 -0
  129. package/types/cli/commands/test-cmd.d.ts +14 -0
  130. package/types/cli/generators/index.d.ts +112 -0
  131. package/types/cli/index.d.ts +249 -0
  132. package/types/cli/template-engine.d.ts +40 -0
  133. package/types/core/ajv-mapper.d.ts +27 -0
  134. package/types/core/boot.d.ts +233 -0
  135. package/types/core/cluster-metrics.d.ts +52 -0
  136. package/types/core/config-loader.d.ts +13 -0
  137. package/types/core/config-validator.d.ts +30 -0
  138. package/types/core/ctx-builder.d.ts +80 -0
  139. package/types/core/envelope.d.ts +79 -0
  140. package/types/core/error-mapper.d.ts +17 -0
  141. package/types/core/formbody.d.ts +41 -0
  142. package/types/core/hub-link.d.ts +264 -0
  143. package/types/core/i18n.d.ts +178 -0
  144. package/types/core/index.d.ts +28 -0
  145. package/types/core/mega-app.d.ts +529 -0
  146. package/types/core/mega-cluster.d.ts +104 -0
  147. package/types/core/mega-server.d.ts +91 -0
  148. package/types/core/mega-service.d.ts +31 -0
  149. package/types/core/migration/dialect-registry.d.ts +22 -0
  150. package/types/core/migration/dialects/maria.d.ts +99 -0
  151. package/types/core/migration/dialects/mongo.d.ts +89 -0
  152. package/types/core/migration/dialects/postgres.d.ts +117 -0
  153. package/types/core/migration/dialects/sqlite.d.ts +111 -0
  154. package/types/core/migration/differ.d.ts +47 -0
  155. package/types/core/migration/generate.d.ts +56 -0
  156. package/types/core/migration/journal.d.ts +52 -0
  157. package/types/core/migration/model-scan.d.ts +19 -0
  158. package/types/core/migration/mongo-migration-db.d.ts +7 -0
  159. package/types/core/migration/schema-builder.d.ts +197 -0
  160. package/types/core/migration/schema-validator.d.ts +20 -0
  161. package/types/core/migration-lock.d.ts +33 -0
  162. package/types/core/migration-runner.d.ts +101 -0
  163. package/types/core/multipart.d.ts +86 -0
  164. package/types/core/openapi.d.ts +62 -0
  165. package/types/core/pipeline.d.ts +92 -0
  166. package/types/core/router.d.ts +159 -0
  167. package/types/core/routes-loader.d.ts +21 -0
  168. package/types/core/scope-registry.d.ts +14 -0
  169. package/types/core/security.d.ts +77 -0
  170. package/types/core/services-loader.d.ts +27 -0
  171. package/types/core/session-cleanup-schedule.d.ts +19 -0
  172. package/types/core/session-store.d.ts +18 -0
  173. package/types/core/session.d.ts +77 -0
  174. package/types/core/static-assets.d.ts +73 -0
  175. package/types/core/template.d.ts +106 -0
  176. package/types/core/workers-manager.d.ts +79 -0
  177. package/types/core/ws-cluster.d.ts +208 -0
  178. package/types/core/ws-compression.d.ts +112 -0
  179. package/types/core/ws-controller.d.ts +65 -0
  180. package/types/core/ws-message.d.ts +106 -0
  181. package/types/core/ws-presence.d.ts +273 -0
  182. package/types/core/ws-roster.d.ts +96 -0
  183. package/types/core/ws-upgrade.d.ts +231 -0
  184. package/types/errors/config-error.d.ts +10 -0
  185. package/types/errors/http-errors.d.ts +120 -0
  186. package/types/errors/index.d.ts +3 -0
  187. package/types/errors/mega-error.d.ts +32 -0
  188. package/types/index.d.ts +39 -0
  189. package/types/lib/asp/config.d.ts +49 -0
  190. package/types/lib/asp/crypto.d.ts +43 -0
  191. package/types/lib/asp/errors.d.ts +30 -0
  192. package/types/lib/asp/nonce-cache.d.ts +52 -0
  193. package/types/lib/asp/plugin.d.ts +30 -0
  194. package/types/lib/asp/ws-terminator.d.ts +45 -0
  195. package/types/lib/env-mapper.d.ts +14 -0
  196. package/types/lib/hub-protocol.d.ts +106 -0
  197. package/types/lib/index.d.ts +22 -0
  198. package/types/lib/logger/telegram-core.d.ts +104 -0
  199. package/types/lib/logger/telegram-transport.d.ts +45 -0
  200. package/types/lib/mega-brute-force.d.ts +66 -0
  201. package/types/lib/mega-circuit-breaker.d.ts +241 -0
  202. package/types/lib/mega-cron.d.ts +66 -0
  203. package/types/lib/mega-hash.d.ts +32 -0
  204. package/types/lib/mega-health.d.ts +41 -0
  205. package/types/lib/mega-job-queue.d.ts +176 -0
  206. package/types/lib/mega-job-worker.d.ts +130 -0
  207. package/types/lib/mega-job.d.ts +138 -0
  208. package/types/lib/mega-logger.d.ts +45 -0
  209. package/types/lib/mega-metrics.d.ts +285 -0
  210. package/types/lib/mega-plugin.d.ts +245 -0
  211. package/types/lib/mega-retry.d.ts +85 -0
  212. package/types/lib/mega-schedule.d.ts +260 -0
  213. package/types/lib/mega-shutdown.d.ts +135 -0
  214. package/types/lib/mega-tracing.d.ts +224 -0
  215. package/types/lib/mega-worker.d.ts +127 -0
  216. package/types/lib/otel-resource.d.ts +16 -0
  217. package/types/lib/worker-runner/process-entry.d.ts +1 -0
  218. package/types/lib/worker-runner/task-dispatch.d.ts +28 -0
  219. package/types/lib/worker-runner/thread-entry.d.ts +1 -0
  220. package/types/lib/ws-hub.d.ts +234 -0
  221. package/types/models/crud-sql-builder.d.ts +48 -0
  222. package/types/models/index.d.ts +1 -0
  223. package/types/models/mega-model.d.ts +138 -0
  224. package/types/models/model-crud.d.ts +82 -0
  225. package/types/models/mongo-crud.d.ts +59 -0
  226. package/types/test/index.d.ts +84 -0
  227. package/.env +0 -127
  228. package/sample/crud/apps/main/migrations/20260606000002-add-auth-to-users.js +0 -30
  229. package/sample/crud/apps/main/models/note.js +0 -71
  230. package/sample/crud/apps/main/models/user.js +0 -86
  231. package/sample/crud/package-lock.json +0 -5665
  232. package/sample/crud/yarn.lock +0 -2142
  233. package/sample/simple/package-lock.json +0 -1851
@@ -0,0 +1,127 @@
1
+ /**
2
+ * @typedef {object} WorkerHandle - 풀 안의 워커 1개 핸들.
3
+ * @property {number} id - 핸들 식별자(로그/디버그).
4
+ * @property {Worker | import('node:child_process').ChildProcess} native - 실제 thread/process.
5
+ * @property {number | null} current - 처리 중인 taskId(없으면 null).
6
+ * @property {boolean} down - 종료/크래시 처리됨(중복 처리 가드).
7
+ */
8
+ /**
9
+ * @typedef {object} WorkerTask - 디스패치 대기/진행 중인 task 1건.
10
+ * @property {number} taskId
11
+ * @property {string} taskName
12
+ * @property {any} args
13
+ * @property {{ timeoutMs?: number }} opts
14
+ * @property {(value: any) => void} resolve
15
+ * @property {(err: Error) => void} reject
16
+ * @property {WorkerHandle | null} handle - 배정된 워커(미배정 null).
17
+ * @property {ReturnType<typeof setTimeout> | null} timer - 타임아웃 타이머.
18
+ * @property {boolean} isSettled
19
+ * @property {(() => void) | null} _notify - stop() 의 완료 대기 깨우기.
20
+ */
21
+ /**
22
+ * CPU 워커 풀. 서브클래스가 `static name`/`static taskFile`/`static mode`/`static poolSize` 를 선언하고,
23
+ * 호출자는 `run(taskName, args, opts)` 로 task 를 디스패치한다.
24
+ */
25
+ export class MegaWorker extends EventEmitter<any> {
26
+ /**
27
+ * @param {object} [args]
28
+ * @param {string} [args.projectRoot] - `static taskFile` 상대경로 해석 기준(디폴트 process.cwd()).
29
+ * @throws {MegaConfigError} static 설정(taskFile/mode/poolSize)이 잘못됐을 때 — 부팅 fail-fast.
30
+ */
31
+ constructor({ projectRoot }?: {
32
+ projectRoot?: string;
33
+ });
34
+ /** @returns {string} 등록 키(= `static name` 오버라이드 또는 클래스명). */
35
+ get name(): string;
36
+ /** @returns {'thread' | 'process'} 실행 모드(디폴트 'thread'). */
37
+ get mode(): "thread" | "process";
38
+ /** @returns {number} 풀 크기. */
39
+ get poolSize(): number;
40
+ /** @returns {number} crash 교체 허용 총량. */
41
+ get maxRestarts(): number;
42
+ /** @returns {boolean} start() 후 stop() 전이면 true. */
43
+ get isStarted(): boolean;
44
+ /** @param {'dispatch'|'done'|'fail'|'crash'|'stopped'} event @param {(payload: any) => void} listener @returns {this} */
45
+ on(event: "dispatch" | "done" | "fail" | "crash" | "stopped", listener: (payload: any) => void): this;
46
+ /** @param {'dispatch'|'done'|'fail'|'crash'|'stopped'} event @param {(payload: any) => void} listener @returns {this} */
47
+ once(event: "dispatch" | "done" | "fail" | "crash" | "stopped", listener: (payload: any) => void): this;
48
+ /** @param {'dispatch'|'done'|'fail'|'crash'|'stopped'} event @param {(payload: any) => void} listener @returns {this} */
49
+ off(event: "dispatch" | "done" | "fail" | "crash" | "stopped", listener: (payload: any) => void): this;
50
+ /**
51
+ * 워커 풀을 띄운다(`poolSize` 개). 각 워커가 taskFile 을 로드해 `{ ready:true }` 를 보낼 때까지 대기한다
52
+ * (race 방지). 멱등 — 이미 start 됐으면 무시. taskFile 로드 실패는 spawn 핸드셰이크에서 fail-fast.
53
+ * @returns {Promise<this>}
54
+ * @throws {MegaError} 전원 spawn 실패 시 근본 원인(`worker.spawn_failed`)을 전파. 풀 **일부만** 떠도
55
+ * 성공분을 terminate 한 뒤 `worker.start_partial` 로 fail-fast(M-1 — 누수 방지).
56
+ */
57
+ start(): Promise<this>;
58
+ /**
59
+ * task 를 워커에 디스패치한다. 유휴 워커가 있으면 즉시, 없으면 큐 대기 후 가용 시 디스패치.
60
+ * @param {string} taskName - taskFile 이 export 한 함수명.
61
+ * @param {any} [args] - 함수 인자(structured clone/IPC 가능한 데이터만 — 함수·클래스 인스턴스 X). 직렬화
62
+ * 불가 인자는 디스패치 시점에 `worker.invalid_args` 로 reject 된다(fail-fast — H-1/M-2, ADR-124 보강).
63
+ * @param {{ timeoutMs?: number }} [opts] - timeoutMs 초과 시 `worker.task_timeout` reject + 워커 교체.
64
+ * @returns {Promise<any>} task 함수 반환값.
65
+ * @throws {MegaError} not_started / stopped / invalid_task / pool_exhausted (즉시 reject) /
66
+ * invalid_args (직렬화 불가 인자 — 디스패치 시점 reject).
67
+ */
68
+ run(taskName: string, args?: any, opts?: {
69
+ timeoutMs?: number;
70
+ }): Promise<any>;
71
+ /**
72
+ * graceful shutdown — 새 run() 거부 + 큐 대기분 `worker.stopped` reject + in-flight 완료 대기 → terminate.
73
+ * `MegaShutdown` 정리 경로에서 호출된다(workers-manager 가 `register('workers:stop', ...)` 배선).
74
+ * @returns {Promise<this>}
75
+ */
76
+ stop(): Promise<this>;
77
+ #private;
78
+ }
79
+ /**
80
+ * - 풀 안의 워커 1개 핸들.
81
+ */
82
+ export type WorkerHandle = {
83
+ /**
84
+ * - 핸들 식별자(로그/디버그).
85
+ */
86
+ id: number;
87
+ /**
88
+ * - 실제 thread/process.
89
+ */
90
+ native: Worker | import("node:child_process").ChildProcess;
91
+ /**
92
+ * - 처리 중인 taskId(없으면 null).
93
+ */
94
+ current: number | null;
95
+ /**
96
+ * - 종료/크래시 처리됨(중복 처리 가드).
97
+ */
98
+ down: boolean;
99
+ };
100
+ /**
101
+ * - 디스패치 대기/진행 중인 task 1건.
102
+ */
103
+ export type WorkerTask = {
104
+ taskId: number;
105
+ taskName: string;
106
+ args: any;
107
+ opts: {
108
+ timeoutMs?: number;
109
+ };
110
+ resolve: (value: any) => void;
111
+ reject: (err: Error) => void;
112
+ /**
113
+ * - 배정된 워커(미배정 null).
114
+ */
115
+ handle: WorkerHandle | null;
116
+ /**
117
+ * - 타임아웃 타이머.
118
+ */
119
+ timer: ReturnType<typeof setTimeout> | null;
120
+ isSettled: boolean;
121
+ /**
122
+ * - stop() 의 완료 대기 깨우기.
123
+ */
124
+ _notify: (() => void) | null;
125
+ };
126
+ import { EventEmitter } from 'node:events';
127
+ import { Worker } from 'node:worker_threads';
@@ -0,0 +1,16 @@
1
+ /**
2
+ * 공통 입력 → OTel Resource. 시크릿은 attributes 에 싣지 말 것(exporter 로 평문 전송됨).
3
+ *
4
+ * @param {object} opts
5
+ * @param {string} opts.serviceName - **필수**(호출부가 선검증). `service.name` 속성.
6
+ * @param {string} [opts.version] - `service.version`.
7
+ * @param {string} [opts.environment] - `deployment.environment.name`.
8
+ * @param {Record<string, any>} [opts.attributes] - 추가 resource 속성(머지).
9
+ * @returns {import('@opentelemetry/resources').Resource}
10
+ */
11
+ export function buildOtelResource({ serviceName, version, environment, attributes }: {
12
+ serviceName: string;
13
+ version?: string;
14
+ environment?: string;
15
+ attributes?: Record<string, any>;
16
+ }): import("@opentelemetry/resources").Resource;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,28 @@
1
+ /**
2
+ * taskFile 모듈을 동적 import 한다. 절대경로를 file:// URL 로 변환해 OS·ESM 호환성을 보장한다.
3
+ * @param {string} taskFile - 워커 진입 모듈 절대경로.
4
+ * @returns {Promise<Record<string, any>>} 모듈 네임스페이스(task 함수들).
5
+ */
6
+ export function loadTaskModule(taskFile: string): Promise<Record<string, any>>;
7
+ /**
8
+ * Error 를 스레드/프로세스 경계 너머로 보낼 수 있게 평탄화한다 (structuredClone/IPC 는 Error 인스턴스의
9
+ * name/message/stack 을 보존하지 않으므로 명시 직렬화). 부모가 이를 받아 다시 Error 로 복원한다.
10
+ * @param {unknown} err
11
+ * @returns {{ name: string, message: string, stack?: string, code?: string }}
12
+ */
13
+ export function serializeError(err: unknown): {
14
+ name: string;
15
+ message: string;
16
+ stack?: string;
17
+ code?: string;
18
+ };
19
+ /**
20
+ * 부모가 보낸 task 디스패치 메시지 1건을 처리한다 — 모듈에서 `taskName` 함수를 찾아 실행하고 결과/에러를
21
+ * 부모로 돌려보낸다. 미존재 task·실행 실패를 묵살하지 않고 `{ ok:false, error }` 로 명시 보고.
22
+ *
23
+ * @param {Record<string, any>} mod - loadTaskModule 결과.
24
+ * @param {any} msg - 부모 메시지 `{ id, taskName, args }`.
25
+ * @param {(reply: any) => void} send - 부모로 회신하는 채널(`parentPort.postMessage` / `process.send`).
26
+ * @returns {Promise<void>}
27
+ */
28
+ export function handleTaskMessage(mod: Record<string, any>, msg: any, send: (reply: any) => void): Promise<void>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,234 @@
1
+ /**
2
+ * CLI 진입점 — env 로 설정 읽어 hub 기동 (bin/mega-ws-hub.js 에서 호출).
3
+ *
4
+ * env: MEGA_WSHUB_TOKENS (필수, 콤마구분 acceptedTokens), MEGA_WSHUB_PORT (기본 3100),
5
+ * MEGA_WSHUB_HOST (기본 0.0.0.0), MEGA_WSHUB_HEARTBEAT_MS (선택), MEGA_WSHUB_MAX_PAYLOAD (선택, bytes),
6
+ * MEGA_WSHUB_COMPRESSION ('true' 면 압축 ON, ADR-078 디폴트값으로),
7
+ * MEGA_WSHUB_COMPRESSION_THRESHOLD (선택, bytes — 압축 ON 일 때만 적용).
8
+ * 향후 mega.config.js 의 wsHub 블록 로딩으로 대체 (ADR-068) — 그 시점에 6 필드 전체가
9
+ * config 로 전달된다. 지금 CLI 는 env 한정이라 enabled + threshold 만 노출(나머지는 ADR-078 디폴트).
10
+ *
11
+ * SIGTERM/SIGINT 시 MegaShutdown 이 hub.stop({ drain: true })(bridge 소켓 4503 + wss.close)을
12
+ * 실행한다(L2 + drain) — 독립 hub 종료는 "다른 인스턴스로 재연결" 신호(4503)가 맞다(ADR-098).
13
+ *
14
+ * @returns {Promise<MegaWsHub>}
15
+ */
16
+ export function runWsHubCli(): Promise<MegaWsHub>;
17
+ /** 기본 heartbeat 주기 (ms, 04-data-models MegaWsHubConfig.heartbeatMs 기본값). */
18
+ export const DEFAULT_HEARTBEAT_MS: 25000;
19
+ /** 기본 최대 프레임 크기 (bytes, L3). 1 MiB — 정상 envelope 은 수 KB 이므로 넉넉하다. */
20
+ export const DEFAULT_MAX_PAYLOAD_BYTES: 1048576;
21
+ /**
22
+ * bridge 별 송신 버퍼(bufferedAmount) 기본 상한(바이트) — 16 MiB. 초과 = 느린 bridge 가 fan-out 을 못
23
+ * 따라오는 것 → terminate(백프레셔). 클라↔bridge 종단(`ws-upgrade.js` DEFAULT_MAX_BUFFERED_BYTES)과 대칭.
24
+ */
25
+ export const DEFAULT_MAX_BUFFERED_BYTES: number;
26
+ export class MegaWsHub {
27
+ /**
28
+ * @param {Object} [opts]
29
+ * @param {string[]} [opts.acceptedTokens] - Bridge Bearer 토큰 화이트리스트 (비거나 누락 시 throw).
30
+ * @param {number} [opts.heartbeatMs=25000] - register_ok 로 알려줄 heartbeat 주기.
31
+ * @param {number} [opts.maxPayloadBytes=1048576] - WS 프레임 최대 크기(L3). 초과 시 ws 가 1009 close.
32
+ * @param {number} [opts.maxBufferedBytes=16777216] - bridge 별 송신 버퍼(bufferedAmount) 상한(바이트).
33
+ * 초과한 bridge 는 느린 소비자로 보고 terminate 한다 — fan-out 허브에서 bridge 1개가 느려도 모든
34
+ * 채널 메시지가 그 소켓 버퍼(힙)에 무한 적재돼 OOM 으로 가는 것을 막는다(백프레셔).
35
+ * @param {string} [opts.hubId] - hub 식별자. 기본 ULID 자동 생성.
36
+ * @param {import('../core/ws-compression.js').WsCompressionConfig} [opts.compression] - Bridge↔Hub
37
+ * link per-message deflate 압축(ADR-078 / wsHub.compression). 디폴트 OFF.
38
+ * bridge(MegaHubLink)와 양쪽이 협상해야 활성. 잘못된 threshold/windowBits 면 즉시 throw.
39
+ * @param {{ warn?: Function, debug?: Function, info?: Function, error?: Function }} [opts.logger]
40
+ */
41
+ constructor({ acceptedTokens, heartbeatMs, maxPayloadBytes, maxBufferedBytes, hubId, compression, logger }?: {
42
+ acceptedTokens?: string[];
43
+ heartbeatMs?: number;
44
+ maxPayloadBytes?: number;
45
+ maxBufferedBytes?: number;
46
+ hubId?: string;
47
+ compression?: import("../core/ws-compression.js").WsCompressionConfig;
48
+ logger?: {
49
+ warn?: Function;
50
+ debug?: Function;
51
+ info?: Function;
52
+ error?: Function;
53
+ };
54
+ });
55
+ _acceptedTokens: string[];
56
+ _heartbeatMs: number;
57
+ _maxPayloadBytes: number;
58
+ _maxBufferedBytes: number;
59
+ _hubId: string;
60
+ /** @type {false | Object} WebSocketServer perMessageDeflate 로 전달(start). */
61
+ _perMessageDeflate: false | Object;
62
+ _log: {
63
+ warn?: Function;
64
+ debug?: Function;
65
+ info?: Function;
66
+ error?: Function;
67
+ };
68
+ /** @type {WebSocketServer | null} */
69
+ _wss: WebSocketServer | null;
70
+ /** heartbeat liveness 체크 interval (M3). @type {ReturnType<typeof setInterval> | null} */
71
+ _livenessTimer: ReturnType<typeof setInterval> | null;
72
+ /** 등록된 bridge 연결. connId → { socket, lastSeen, protocolVersion }. @type {Map<string, { socket: import('ws').WebSocket, lastSeen: number, protocolVersion?: number }>} */
73
+ _bridges: Map<string, {
74
+ socket: import("ws").WebSocket;
75
+ lastSeen: number;
76
+ protocolVersion?: number;
77
+ }>;
78
+ /** presence. sessionId → { bridgeConnId, userId, channels:Set, metadata }. @type {Map<string, { bridgeConnId: string, userId: string, channels: Set<string>, metadata: Object }>} */
79
+ _sessions: Map<string, {
80
+ bridgeConnId: string;
81
+ userId: string;
82
+ channels: Set<string>;
83
+ metadata: Object;
84
+ }>;
85
+ /** channel → sessionId 집합. @type {Map<string, Set<string>>} */
86
+ _channelSessions: Map<string, Set<string>>;
87
+ /** userId → sessionId 집합 (DIRECT fan-out, ADR-035). @type {Map<string, Set<string>>} */
88
+ _userSessions: Map<string, Set<string>>;
89
+ /** hub 식별자. */
90
+ get hubId(): string;
91
+ /** 등록된 bridge 수 (테스트/관측용). */
92
+ get bridgeCount(): number;
93
+ /** 현재 presence 세션 수 (테스트/관측용). */
94
+ get sessionCount(): number;
95
+ /**
96
+ * hub 시작.
97
+ * @param {{ port?: number, host?: string }} [opts]
98
+ * @returns {Promise<{ port: number, host: string }>} 실제 바인딩 주소.
99
+ */
100
+ start({ port, host }?: {
101
+ port?: number;
102
+ host?: string;
103
+ }): Promise<{
104
+ port: number;
105
+ host: string;
106
+ }>;
107
+ /** 현재 바인딩 주소 (테스트용). */
108
+ address(): {
109
+ port: number;
110
+ host: string;
111
+ };
112
+ /**
113
+ * 연결 1건 처리. register 전엔 hub.register 만 허용. 인증 통과 시 presence 라우팅 활성.
114
+ * @param {import('ws').WebSocket} socket
115
+ * @param {import('node:http').IncomingMessage} _req
116
+ * @private
117
+ */
118
+ private _onConnection;
119
+ /**
120
+ * hub.register 처리 — Bearer 검증(timing-safe). 성공 시 bridge 등록 + register_ok.
121
+ * @param {string} connId
122
+ * @param {import('ws').WebSocket} socket
123
+ * @param {Object} msg - 검증된 hub.register envelope.
124
+ * @returns {boolean} 등록 성공 여부(연결의 isRegistered 갱신용).
125
+ * @private
126
+ */
127
+ private _handleRegister;
128
+ /**
129
+ * 등록된 bridge 의 수신 메시지 라우팅 (12-타입).
130
+ * @param {string} connId
131
+ * @param {import('ws').WebSocket} socket
132
+ * @param {Object} msg - 검증된 hub 메시지.
133
+ * @returns {void}
134
+ * @private
135
+ */
136
+ private _route;
137
+ /**
138
+ * presence 에 세션 추가.
139
+ *
140
+ * sessionId 가 이미 존재하면(같은 세션 재JOIN, 또는 채널 변경) 먼저 옛 매핑을 정리한 뒤 재삽입한다
141
+ * — 그러지 않으면 옛 채널 인덱스(`_channelSessions`)에 stale 엔트리가 남는다(채널이 바뀐 경우).
142
+ * 옛 매핑이 **다른 bridge** 소속이면 "sessionId 전역 유일" 계약(ADR-059) 위반이므로 warn 로그를 남기고
143
+ * last-writer 로 재배정한다 — silent 덮어쓰기 금지(L-3). 이렇게 하면 옛 bridge 의 채널 인덱스가
144
+ * 제거되어, 옛 bridge 의 `_handleBridgeGone` 이 재배정된 세션을 잘못 지우는 일도 없어진다.
145
+ *
146
+ * @param {string} connId
147
+ * @param {{ userId: string, sessionId: string, channels: string[], metadata?: Object }} entry
148
+ * @private
149
+ */
150
+ private _addSession;
151
+ /**
152
+ * presence 에서 세션 제거. 빈 인덱스는 정리.
153
+ * @param {string} sessionId
154
+ * @returns {boolean} 실제 제거 여부.
155
+ * @private
156
+ */
157
+ private _removeSession;
158
+ /**
159
+ * bridge 연결 종료 시 — 그 bridge 의 모든 세션 제거 + 다른 bridge 에 bulk_leave 통지.
160
+ * @param {string} connId
161
+ * @private
162
+ */
163
+ private _handleBridgeGone;
164
+ /**
165
+ * origin 을 제외한 모든 등록 bridge 로 송신 (presence 공유용). envelope 는 1회만 직렬화(L5).
166
+ * @param {string} exceptConnId
167
+ * @param {Object} envelope
168
+ * @private
169
+ */
170
+ private _fanOutToOthers;
171
+ /**
172
+ * 한 채널의 세션을 가진 bridge 들로 fan-out (origin 제외, 중복 bridge 1회). 직렬화 1회(L5).
173
+ *
174
+ * `exceptSessionIds` 가 있으면 해당 세션은 bridge 선정에서 제외한다(ADR-098). 어떤 bridge 의
175
+ * 채널 세션이 **전부** 제외 대상이면 그 bridge 는 통째로 스킵된다(불필요한 전송 절약). 일부만 제외면
176
+ * bridge 는 받아서 로컬에서 해당 세션만 건너뛴다(envelope 의 payload.exceptSessionIds 가 그대로 전달됨).
177
+ *
178
+ * @param {string} channel
179
+ * @param {string} exceptConnId
180
+ * @param {Object} envelope
181
+ * @param {string[]} [exceptSessionIds] - fan-out 에서 뺄 세션 목록(BROADCAST payload).
182
+ * @private
183
+ */
184
+ private _fanOutChannel;
185
+ /**
186
+ * 한 user 의 세션을 가진 bridge 들로 fan-out (DIRECT, ADR-035). origin 제외(L7) — origin 은
187
+ * local 직접 전달하므로 hub 가 되돌리지 않는다(BROADCAST 와 동일 패턴). 직렬화 1회(L5).
188
+ * @param {string} userId
189
+ * @param {Object} envelope
190
+ * @param {string} [exceptConnId] - 제외할 origin bridge connId.
191
+ * @private
192
+ */
193
+ private _fanOutUser;
194
+ /**
195
+ * connId 로 직렬화된 프레임 송신 (등록된 bridge 한정).
196
+ * @param {string} connId
197
+ * @param {string} serialized - 이미 JSON.stringify 된 envelope.
198
+ * @private
199
+ */
200
+ private _sendTo;
201
+ /**
202
+ * 단일 envelope 송신 — 직렬화 후 위임 (register_ok/error/heartbeat 등 1:1 송신용).
203
+ * @param {import('ws').WebSocket} socket
204
+ * @param {Object} envelope
205
+ * @private
206
+ */
207
+ private _safeSend;
208
+ /**
209
+ * 직렬화된 프레임 소켓 송신 — 닫히는 중 등 실패는 비치명적(이유+로그).
210
+ * @param {import('ws').WebSocket} socket
211
+ * @param {string} serialized
212
+ * @private
213
+ */
214
+ private _sendSerialized;
215
+ /**
216
+ * heartbeat liveness 감시(M3) — heartbeatMs*2 이상 HEARTBEAT 미수신 bridge 를 정리 후 terminate.
217
+ * half-open 연결(TCP 는 살아있으나 상대가 죽음)이 presence 에 영구 잔존하는 것을 막는다.
218
+ * @private
219
+ */
220
+ private _checkLiveness;
221
+ /**
222
+ * hub 종료 — liveness 타이머 정리 + 모든 bridge 연결 닫고 서버 close.
223
+ *
224
+ * `drain: true` 면 bridge 소켓을 close code **4503**(DRAIN, ADR-098) 로 닫는다 — bridge 가 "다른 hub
225
+ * 인스턴스로 재연결하라" 로 해석한다(LB/mesh 회전). 기본(false)은 1001(GOING_AWAY) — 일반 종료.
226
+ *
227
+ * @param {{ drain?: boolean }} [opts]
228
+ * @returns {Promise<void>}
229
+ */
230
+ stop({ drain }?: {
231
+ drain?: boolean;
232
+ }): Promise<void>;
233
+ }
234
+ import { WebSocketServer } from 'ws';
@@ -0,0 +1,48 @@
1
+ /**
2
+ * @typedef {Object} CrudDialect - dialect 모듈의 DML facet(ADR-212) 일부.
3
+ * @property {(name: string) => string} quoteIdent
4
+ * @property {(i: number) => string} placeholder
5
+ */
6
+ /** 컬럼이 schema 화이트리스트에 있는지 — 없으면 throw. @param {string} col @param {Set<string>} cols @param {string} model @param {string} where */
7
+ export function assertColumn(col: string, cols: Set<string>, model: string, where: string): void;
8
+ /** limit/offset 정수 검증 — 음수/비정수 throw, 통과하면 그 정수 반환. @param {unknown} v @param {string} name @param {string} model @returns {number} */
9
+ export function assertNonNegInt(v: unknown, name: string, model: string): number;
10
+ /**
11
+ * filter → WHERE 조각(접두 'WHERE' 없음) + params + 다음 placeholder 인덱스.
12
+ * 등호 AND + `IN`(배열) + `IS NULL`(null) 만(ADR-212 경계). `undefined` 값은 throw, 빈 배열은 `1=0`(매칭 0).
13
+ *
14
+ * @param {Record<string, any>} filter
15
+ * @param {Set<string>} cols - schema 컬럼 화이트리스트
16
+ * @param {CrudDialect} dialect
17
+ * @param {string} model - 에러 메시지용
18
+ * @param {number} [startIndex=1] - placeholder 시작 인덱스(SET 뒤 WHERE 처럼 이어붙일 때)
19
+ * @returns {{ clause: string, params: any[], nextIndex: number }}
20
+ */
21
+ export function buildWhere(filter: Record<string, any>, cols: Set<string>, dialect: CrudDialect, model: string, startIndex?: number): {
22
+ clause: string;
23
+ params: any[];
24
+ nextIndex: number;
25
+ };
26
+ /**
27
+ * orderBy 옵션 → `ORDER BY ...` 조각(없으면 ''). 컬럼 화이트리스트 + dir enum.
28
+ * @param {string | Array<{ column: string, dir?: 'asc'|'desc' }> | undefined} orderBy
29
+ * @param {Set<string>} cols @param {CrudDialect} dialect @param {string} model
30
+ * @returns {string}
31
+ */
32
+ export function buildOrderBy(orderBy: string | Array<{
33
+ column: string;
34
+ dir?: "asc" | "desc";
35
+ }> | undefined, cols: Set<string>, dialect: CrudDialect, model: string): string;
36
+ /**
37
+ * select 옵션 → 컬럼 목록 조각(`*` 또는 인용 컬럼). 화이트리스트 검증.
38
+ * @param {string[] | undefined} select @param {Set<string>} cols @param {CrudDialect} dialect @param {string} model
39
+ * @returns {string}
40
+ */
41
+ export function buildSelectList(select: string[] | undefined, cols: Set<string>, dialect: CrudDialect, model: string): string;
42
+ /**
43
+ * - dialect 모듈의 DML facet(ADR-212) 일부.
44
+ */
45
+ export type CrudDialect = {
46
+ quoteIdent: (name: string) => string;
47
+ placeholder: (i: number) => string;
48
+ };
@@ -0,0 +1 @@
1
+ export { MegaModel } from "./mega-model.js";
@@ -0,0 +1,138 @@
1
+ export class MegaModel {
2
+ /**
3
+ * 어댑터 globalKey — `mega.config.js` 의 `services.databases.<key>` 와 정확히 일치 (ADR-061).
4
+ * 서브클래스가 박는다. 비어 있으면 db/withTransaction 접근 시 throw.
5
+ * @type {string}
6
+ */
7
+ static adapter: string;
8
+ /**
9
+ * 데이터 소스 식별자. SQL 의 table 또는 MongoDB 의 collection 모두 본 필드에 명시 (ADR-081).
10
+ * 어댑터별 native 호출 시 의미는 동일. 비어 있으면 db/withTransaction 접근 시 throw.
11
+ * @type {string}
12
+ */
13
+ static table: string;
14
+ /**
15
+ * 자동 lookup — `adapter` 키로 어댑터의 driver native handle 반환
16
+ * (pg Pool / MongoClient / mariadb Pool / better-sqlite3 Database, ADR-009).
17
+ *
18
+ * 어댑터가 아직 `connect()` 전이면 어댑터 베이스가 `adapter.not_connected` 를 throw 한다
19
+ * (08-class-specs §3.2 불변식 — native 는 연결 후에만 유효).
20
+ *
21
+ * @returns {any} driver native handle.
22
+ */
23
+ static get db(): any;
24
+ /**
25
+ * 명시적 트랜잭션 경계 (ADR-010). 어댑터의 `withTransaction` 에 위임한다 — 성공 시 commit,
26
+ * `fn` 이 throw 하면 driver native rollback 후 원본 에러 re-throw. **자동 request-scoped
27
+ * 트랜잭션은 만들지 않는다** (ADR-010).
28
+ *
29
+ * `fn` 이 받는 인자는 **트랜잭션 컨텍스트의 native handle**(예: pg client) 이다. 같은 모델의
30
+ * 다른 메서드(`this.db.query`)는 트랜잭션 **밖** 글로벌 handle 을 쓰므로, 트랜잭션 안에서는
31
+ * `fn` 인자를 명시적으로 써야 격리가 유지된다 (08-class-specs §3.1 — 사용자 책임).
32
+ *
33
+ * nested 트랜잭션 정책(postgres SAVEPOINT / Mongo throw)은 **구체 어댑터 책임**이다.
34
+ * 베이스는 위임만 한다.
35
+ *
36
+ * `fn` 인자 수는 어댑터별로 다르다 — SQL 어댑터는 `(client)` 1개, Mongo 어댑터는 `(db, session)`
37
+ * 2개를 넘긴다(ADR-108). 따라서 가변 인자로 타입을 둔다(어댑터가 인자 형태의 정본).
38
+ *
39
+ * `opts.isolation`(ADR-190) — SQL 격리수준 옵트인. driver 별 지원·제약은 어댑터가 정본
40
+ * (postgres/maria=top-level 만, sqlite='serializable' 만, mongodb=미지원 throw).
41
+ *
42
+ * @template T
43
+ * @param {(...args: any[]) => Promise<T>} fn - 트랜잭션 컨텍스트 native handle(들)을 받는 콜백.
44
+ * @param {{ isolation?: 'read uncommitted' | 'read committed' | 'repeatable read' | 'serializable' }} [opts] - 트랜잭션 옵션(ADR-190).
45
+ * @returns {Promise<T>}
46
+ */
47
+ static withTransaction<T>(fn: (...args: any[]) => Promise<T>, opts?: {
48
+ isolation?: "read uncommitted" | "read committed" | "repeatable read" | "serializable";
49
+ }): Promise<T>;
50
+ /**
51
+ * **계측된 쿼리** — `this.db.query`(native handle 직접 호출, 트레이싱 미통과)와 달리 어댑터의
52
+ * `query` 도메인 메서드에 위임해 자동 span(`<driver>.query`)·메트릭·stats 에 잡힌다(ADR-138).
53
+ * 진행 중 트랜잭션이 있으면 어댑터가 같은 connection 으로 실행하므로, `withTransaction(async (tx) => …)`
54
+ * 콜백 안에서 `Model.query(sql, params)` 를 부르면 격리가 유지되고 span 도 트랜잭션 span 의 자식이 된다
55
+ * (native `tx.query`는 계측 미통과 escape hatch). SQL 어댑터(postgres/maria/sqlite) 전용 — Document
56
+ * DB(mongo)는 `adapter.not_implemented`.
57
+ *
58
+ * @param {string} sql - 파라미터화된 SQL(placeholder 보존 — 값 인터폴레이션 금지).
59
+ * @param {any[]} [params] - placeholder 바인딩 값.
60
+ * @returns {Promise<any>} driver native 쿼리 결과(어댑터별 형태 — ADR-009).
61
+ */
62
+ static query(sql: string, params?: any[]): Promise<any>;
63
+ /** 단건 조회(없으면 null). filter 는 등호 AND + 배열 IN + null IS NULL. @param {Record<string, any>} filter @param {{ select?: string[] }} [opts] @returns {Promise<any|null>} */
64
+ static findOne(filter: Record<string, any>, opts?: {
65
+ select?: string[];
66
+ }): Promise<any | null>;
67
+ /** PK 단건 조회(단일 PK 필요, 없으면 model.no_primary_key). @param {any} id @param {{ select?: string[] }} [opts] @returns {Promise<any|null>} */
68
+ static findById(id: any, opts?: {
69
+ select?: string[];
70
+ }): Promise<any | null>;
71
+ /** 다건 조회(기본 limit 없음 — 명시할 때만, ADR-212 #2). @param {Record<string, any>} [filter] @param {{ select?: string[], orderBy?: string | Array<{ column: string, dir?: 'asc'|'desc' }>, limit?: number, offset?: number }} [opts] @returns {Promise<any[]>} */
72
+ static findMany(filter?: Record<string, any>, opts?: {
73
+ select?: string[];
74
+ orderBy?: string | Array<{
75
+ column: string;
76
+ dir?: "asc" | "desc";
77
+ }>;
78
+ limit?: number;
79
+ offset?: number;
80
+ }): Promise<any[]>;
81
+ /** 조건 매칭 행 수. @param {Record<string, any>} [filter] @returns {Promise<number>} */
82
+ static count(filter?: Record<string, any>): Promise<number>;
83
+ /** 조건 매칭 행 존재 여부. @param {Record<string, any>} filter @returns {Promise<boolean>} */
84
+ static exists(filter: Record<string, any>): Promise<boolean>;
85
+ /** 페이지 조회. total 은 `{ withTotal: true }` 일 때만 추가 count(ADR-212 #4). @param {Record<string, any>} filter @param {{ select?: string[], orderBy?: any, limit: number, offset?: number, withTotal?: boolean }} opts @returns {Promise<{ rows: any[], limit: number, offset: number, total?: number }>} */
86
+ static paginate(filter: Record<string, any>, opts: {
87
+ select?: string[];
88
+ orderBy?: any;
89
+ limit: number;
90
+ offset?: number;
91
+ withTotal?: boolean;
92
+ }): Promise<{
93
+ rows: any[];
94
+ limit: number;
95
+ offset: number;
96
+ total?: number;
97
+ }>;
98
+ /** 단건 삽입. 기본 새 id 반환, `{ returning: true }` 면 레코드(ADR-212 #1). @param {Record<string, any>} data @param {{ returning?: boolean }} [opts] @returns {Promise<any>} */
99
+ static insertOne(data: Record<string, any>, opts?: {
100
+ returning?: boolean;
101
+ }): Promise<any>;
102
+ /** 다건 삽입. 기본 `{ count }`, `{ returning: true }` 면 레코드 배열(maria 미지원→throw). @param {Record<string, any>[]} rows @param {{ returning?: boolean }} [opts] @returns {Promise<{ count: number } | any[]>} */
103
+ static insertMany(rows: Record<string, any>[], opts?: {
104
+ returning?: boolean;
105
+ }): Promise<{
106
+ count: number;
107
+ } | any[]>;
108
+ /** 정확히 한 행 갱신(>1 매칭→롤백 후 model.multiple_matches, ADR-212 #3). 변경 행 수 반환. @param {Record<string, any>} filter @param {Record<string, any>} patch @returns {Promise<number>} */
109
+ static updateOne(filter: Record<string, any>, patch: Record<string, any>): Promise<number>;
110
+ /** 다건 갱신. 빈 filter 는 차단 — 전체 갱신은 `{ all: true }`. @param {Record<string, any>} filter @param {Record<string, any>} patch @param {{ all?: boolean }} [opts] @returns {Promise<number>} */
111
+ static updateMany(filter: Record<string, any>, patch: Record<string, any>, opts?: {
112
+ all?: boolean;
113
+ }): Promise<number>;
114
+ /** 정확히 한 행 삭제(>1 매칭→롤백 후 model.multiple_matches). 삭제 행 수 반환. @param {Record<string, any>} filter @returns {Promise<number>} */
115
+ static deleteOne(filter: Record<string, any>): Promise<number>;
116
+ /** 다건 삭제. 빈 filter 는 차단 — 전체 삭제는 `{ all: true }`. @param {Record<string, any>} filter @param {{ all?: boolean }} [opts] @returns {Promise<number>} */
117
+ static deleteMany(filter: Record<string, any>, opts?: {
118
+ all?: boolean;
119
+ }): Promise<number>;
120
+ /** upsert(INSERT … ON CONFLICT/DUPLICATE KEY UPDATE). `opts.conflict` 는 PK/unique 컬럼 필수. @param {Record<string, any>} data @param {{ conflict: string[], update?: string[], returning?: boolean }} opts @returns {Promise<any>} */
121
+ static upsert(data: Record<string, any>, opts: {
122
+ conflict: string[];
123
+ update?: string[];
124
+ returning?: boolean;
125
+ }): Promise<any>;
126
+ /**
127
+ * `adapter`/`table` 정합성을 검증하고 글로벌 매니저에서 어댑터(MegaDbAdapter)를 잡아 반환한다.
128
+ *
129
+ * 정본은 "부팅 시 검증"(08-class-specs §3.1 라이프사이클, ADR-067)을 말하지만, 중앙 부팅
130
+ * 오케스트레이터(`mega serve` CLI)가 아직 미배선이라(ADR-102 미결 항목) **접근 시점 lazy 검증**
131
+ * 으로 둔다 — `ctx.db(alias)` 가 미등록 별명을 즉시 throw 하는 것과 같은 패턴(ADR-102).
132
+ * 오케스트레이터가 생기면 부팅 시 일괄 검증을 추가한다(ADR-104).
133
+ *
134
+ * @protected
135
+ * @returns {import('../adapters/mega-db-adapter.js').MegaDbAdapter}
136
+ */
137
+ protected static _resolveAdapter(): import("../adapters/mega-db-adapter.js").MegaDbAdapter;
138
+ }