mega-framework 0.1.6 → 0.1.8

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 (248) hide show
  1. package/README.md +9 -0
  2. package/bin/mega-ws-hub.js +2 -2
  3. package/package.json +33 -9
  4. package/sample/crud/.env +10 -1
  5. package/sample/crud/.env.example +10 -1
  6. package/sample/crud/.mega/journal/history/20260612092543-create-users.json +261 -0
  7. package/sample/crud/.mega/journal/snapshot.json +261 -0
  8. package/sample/crud/apps/main/controllers/auth-controller.js +22 -14
  9. package/sample/crud/apps/main/controllers/web-controller.js +7 -5
  10. package/sample/crud/apps/main/locales/server/en.json +12 -1
  11. package/sample/crud/apps/main/locales/server/ko.json +12 -1
  12. package/sample/crud/apps/main/migrations/20260606000001-create-users.js +91 -13
  13. package/sample/crud/apps/main/migrations/20260606000002-create-boards.js +165 -0
  14. package/sample/crud/apps/main/migrations/20260606000003-create-logs.js +107 -0
  15. package/sample/crud/apps/main/models/log-partition-model.js +105 -0
  16. package/sample/crud/apps/main/models/note-model.js +79 -0
  17. package/sample/crud/apps/main/models/user-level-model.js +24 -0
  18. package/sample/crud/apps/main/models/user-model.js +146 -0
  19. package/sample/crud/apps/main/models/user-type-model.js +21 -0
  20. package/sample/crud/apps/main/models/wallet-model.js +24 -0
  21. package/sample/crud/apps/main/routes/users.js +55 -10
  22. package/sample/crud/apps/main/schedules/log-partition-schedule.js +33 -0
  23. package/sample/crud/apps/main/services/auth-service.js +39 -24
  24. package/sample/crud/apps/main/services/log-partition-service.js +101 -0
  25. package/sample/crud/apps/main/services/note-service.js +6 -6
  26. package/sample/crud/apps/main/services/redis-demo-service.js +3 -3
  27. package/sample/crud/apps/main/services/user-service.js +62 -21
  28. package/sample/crud/apps/main/views/auth/login.ejs +6 -6
  29. package/sample/crud/apps/main/views/auth/register.ejs +46 -5
  30. package/sample/crud/apps/main/views/users/edit.ejs +42 -5
  31. package/sample/crud/apps/main/views/users/list.ejs +6 -2
  32. package/sample/crud/apps/main/views/users/new.ejs +56 -4
  33. package/sample/crud/docs/log_partition_design.mm.md +23 -0
  34. package/sample/crud/mega.config.js +10 -2
  35. package/sample/crud/package.json +3 -3
  36. package/sample/crud/scripts/start-ws-hub.sh +20 -6
  37. package/sample/simple/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  38. package/sample/simple/package.json +2 -2
  39. package/src/adapters/adapter-manager.js +2 -1
  40. package/src/adapters/adapter-options.js +44 -3
  41. package/src/adapters/file-adapter.js +9 -5
  42. package/src/adapters/file-session-adapter.js +4 -3
  43. package/src/adapters/maria-adapter.js +33 -7
  44. package/src/adapters/mega-cache-adapter.js +83 -6
  45. package/src/adapters/mega-db-adapter.js +10 -1
  46. package/src/adapters/mongo-adapter.js +40 -8
  47. package/src/adapters/postgres-adapter.js +33 -6
  48. package/src/adapters/redis-adapter.js +7 -3
  49. package/src/adapters/sqlite-adapter.js +26 -3
  50. package/src/cli/commands/console-cmd.js +3 -1
  51. package/src/cli/commands/new.js +13 -3
  52. package/src/cli/commands/scaffold.js +173 -33
  53. package/src/cli/generators/index.js +140 -3
  54. package/src/cli/index.js +437 -155
  55. package/src/cli/watch.js +188 -0
  56. package/src/core/ajv-mapper.js +30 -3
  57. package/src/core/boot.js +464 -245
  58. package/src/core/cluster-metrics.js +13 -4
  59. package/src/core/ctx-builder.js +65 -3
  60. package/src/core/envelope.js +119 -12
  61. package/src/core/hub-link.js +89 -18
  62. package/src/core/i18n.js +11 -1
  63. package/src/core/index.js +7 -3
  64. package/src/core/mega-app.js +253 -505
  65. package/src/core/mega-cluster.js +4 -1
  66. package/src/core/mega-server.js +40 -9
  67. package/src/core/migration/dialect-registry.js +107 -0
  68. package/src/core/migration/dialects/README.md +62 -0
  69. package/src/core/migration/dialects/maria.js +496 -0
  70. package/src/core/migration/dialects/mongo.js +824 -0
  71. package/src/core/migration/dialects/postgres.js +563 -0
  72. package/src/core/migration/dialects/sqlite.js +476 -0
  73. package/src/core/migration/differ.js +456 -0
  74. package/src/core/migration/generate.js +508 -0
  75. package/src/core/migration/journal.js +167 -0
  76. package/src/core/migration/model-scan.js +84 -0
  77. package/src/core/migration/mongo-migration-db.js +97 -0
  78. package/src/core/migration/schema-builder.js +400 -0
  79. package/src/core/migration/schema-validator.js +315 -0
  80. package/src/core/migration-lock.js +205 -0
  81. package/src/core/migration-runner.js +166 -38
  82. package/src/core/multipart.js +28 -5
  83. package/src/core/pipeline.js +131 -0
  84. package/src/core/router.js +70 -65
  85. package/src/core/scope-registry.js +1 -0
  86. package/src/core/security.js +70 -12
  87. package/src/core/session-store.js +14 -1
  88. package/src/core/workers-manager.js +12 -1
  89. package/src/core/ws-cluster.js +10 -3
  90. package/src/core/ws-message.js +48 -4
  91. package/src/core/ws-presence.js +636 -0
  92. package/src/core/ws-roster.js +50 -8
  93. package/src/core/ws-upgrade.js +223 -12
  94. package/src/index.js +1 -1
  95. package/src/lib/hub-protocol.js +29 -0
  96. package/src/lib/mega-circuit-breaker.js +5 -3
  97. package/src/lib/mega-health.js +35 -4
  98. package/src/lib/mega-job-queue.js +151 -34
  99. package/src/lib/mega-job.js +37 -1
  100. package/src/lib/mega-metrics.js +31 -13
  101. package/src/lib/mega-plugin.js +34 -3
  102. package/src/lib/mega-schedule.js +40 -22
  103. package/src/lib/mega-shutdown.js +114 -39
  104. package/src/lib/mega-tracing.js +66 -19
  105. package/src/lib/mega-worker.js +33 -6
  106. package/src/lib/otel-resource.js +36 -0
  107. package/src/{cli → lib}/ws-hub.js +139 -15
  108. package/src/models/crud-sql-builder.js +133 -0
  109. package/src/models/mega-model.js +82 -2
  110. package/src/models/model-crud.js +483 -0
  111. package/src/models/mongo-crud.js +285 -0
  112. package/templates/adr/code.tpl +23 -0
  113. package/templates/model/code-mongo.tpl +35 -0
  114. package/templates/model/code.tpl +15 -1
  115. package/templates/model/test-mongo.tpl +38 -0
  116. package/templates/model/test.tpl +4 -0
  117. package/types/adapters/adapter-manager.d.ts +95 -0
  118. package/types/adapters/adapter-options.d.ts +93 -0
  119. package/types/adapters/file-adapter.d.ts +105 -0
  120. package/types/adapters/file-session-adapter.d.ts +103 -0
  121. package/types/adapters/index.d.ts +20 -0
  122. package/types/adapters/maria-adapter.d.ts +117 -0
  123. package/types/adapters/mega-adapter.d.ts +215 -0
  124. package/types/adapters/mega-bus-adapter.d.ts +45 -0
  125. package/types/adapters/mega-cache-adapter.d.ts +73 -0
  126. package/types/adapters/mega-db-adapter.d.ts +50 -0
  127. package/types/adapters/mega-lock-adapter.d.ts +62 -0
  128. package/types/adapters/mega-log-sink-adapter.d.ts +15 -0
  129. package/types/adapters/mega-session-adapter.d.ts +32 -0
  130. package/types/adapters/mongo-adapter.d.ts +150 -0
  131. package/types/adapters/nats-adapter.d.ts +108 -0
  132. package/types/adapters/postgres-adapter.d.ts +141 -0
  133. package/types/adapters/redis-adapter.d.ts +78 -0
  134. package/types/adapters/redis-session-adapter.d.ts +82 -0
  135. package/types/adapters/redlock-adapter.d.ts +149 -0
  136. package/types/adapters/registry.d.ts +46 -0
  137. package/types/adapters/sqlite-adapter.d.ts +112 -0
  138. package/types/auth/index.d.ts +24 -0
  139. package/types/cli/commands/console-cmd.d.ts +37 -0
  140. package/types/cli/commands/new.d.ts +16 -0
  141. package/types/cli/commands/routes.d.ts +36 -0
  142. package/types/cli/commands/scaffold.d.ts +78 -0
  143. package/types/cli/commands/test-cmd.d.ts +14 -0
  144. package/types/cli/generators/index.d.ts +122 -0
  145. package/types/cli/index.d.ts +234 -0
  146. package/types/cli/template-engine.d.ts +40 -0
  147. package/types/cli/watch.d.ts +59 -0
  148. package/types/core/ajv-mapper.d.ts +27 -0
  149. package/types/core/boot.d.ts +233 -0
  150. package/types/core/cluster-metrics.d.ts +52 -0
  151. package/types/core/config-loader.d.ts +13 -0
  152. package/types/core/config-validator.d.ts +30 -0
  153. package/types/core/ctx-builder.d.ts +103 -0
  154. package/types/core/envelope.d.ts +79 -0
  155. package/types/core/error-mapper.d.ts +17 -0
  156. package/types/core/formbody.d.ts +41 -0
  157. package/types/core/hub-link.d.ts +266 -0
  158. package/types/core/i18n.d.ts +178 -0
  159. package/types/core/index.d.ts +28 -0
  160. package/types/core/mega-app.d.ts +529 -0
  161. package/types/core/mega-cluster.d.ts +104 -0
  162. package/types/core/mega-server.d.ts +91 -0
  163. package/types/core/mega-service.d.ts +31 -0
  164. package/types/core/migration/dialect-registry.d.ts +22 -0
  165. package/types/core/migration/dialects/maria.d.ts +99 -0
  166. package/types/core/migration/dialects/mongo.d.ts +89 -0
  167. package/types/core/migration/dialects/postgres.d.ts +117 -0
  168. package/types/core/migration/dialects/sqlite.d.ts +111 -0
  169. package/types/core/migration/differ.d.ts +47 -0
  170. package/types/core/migration/generate.d.ts +56 -0
  171. package/types/core/migration/journal.d.ts +52 -0
  172. package/types/core/migration/model-scan.d.ts +19 -0
  173. package/types/core/migration/mongo-migration-db.d.ts +7 -0
  174. package/types/core/migration/schema-builder.d.ts +197 -0
  175. package/types/core/migration/schema-validator.d.ts +20 -0
  176. package/types/core/migration-lock.d.ts +33 -0
  177. package/types/core/migration-runner.d.ts +101 -0
  178. package/types/core/multipart.d.ts +86 -0
  179. package/types/core/openapi.d.ts +62 -0
  180. package/types/core/pipeline.d.ts +93 -0
  181. package/types/core/router.d.ts +159 -0
  182. package/types/core/routes-loader.d.ts +21 -0
  183. package/types/core/scope-registry.d.ts +14 -0
  184. package/types/core/security.d.ts +77 -0
  185. package/types/core/services-loader.d.ts +27 -0
  186. package/types/core/session-cleanup-schedule.d.ts +19 -0
  187. package/types/core/session-store.d.ts +25 -0
  188. package/types/core/session.d.ts +77 -0
  189. package/types/core/static-assets.d.ts +73 -0
  190. package/types/core/template.d.ts +106 -0
  191. package/types/core/workers-manager.d.ts +79 -0
  192. package/types/core/ws-cluster.d.ts +208 -0
  193. package/types/core/ws-compression.d.ts +112 -0
  194. package/types/core/ws-controller.d.ts +65 -0
  195. package/types/core/ws-message.d.ts +106 -0
  196. package/types/core/ws-presence.d.ts +273 -0
  197. package/types/core/ws-roster.d.ts +108 -0
  198. package/types/core/ws-upgrade.d.ts +260 -0
  199. package/types/errors/config-error.d.ts +10 -0
  200. package/types/errors/http-errors.d.ts +120 -0
  201. package/types/errors/index.d.ts +3 -0
  202. package/types/errors/mega-error.d.ts +32 -0
  203. package/types/index.d.ts +39 -0
  204. package/types/lib/asp/config.d.ts +49 -0
  205. package/types/lib/asp/crypto.d.ts +43 -0
  206. package/types/lib/asp/errors.d.ts +30 -0
  207. package/types/lib/asp/nonce-cache.d.ts +52 -0
  208. package/types/lib/asp/plugin.d.ts +30 -0
  209. package/types/lib/asp/ws-terminator.d.ts +45 -0
  210. package/types/lib/env-mapper.d.ts +14 -0
  211. package/types/lib/hub-protocol.d.ts +106 -0
  212. package/types/lib/index.d.ts +22 -0
  213. package/types/lib/logger/telegram-core.d.ts +104 -0
  214. package/types/lib/logger/telegram-transport.d.ts +45 -0
  215. package/types/lib/mega-brute-force.d.ts +66 -0
  216. package/types/lib/mega-circuit-breaker.d.ts +243 -0
  217. package/types/lib/mega-cron.d.ts +66 -0
  218. package/types/lib/mega-hash.d.ts +32 -0
  219. package/types/lib/mega-health.d.ts +48 -0
  220. package/types/lib/mega-job-queue.d.ts +188 -0
  221. package/types/lib/mega-job-worker.d.ts +130 -0
  222. package/types/lib/mega-job.d.ts +145 -0
  223. package/types/lib/mega-logger.d.ts +45 -0
  224. package/types/lib/mega-metrics.d.ts +285 -0
  225. package/types/lib/mega-plugin.d.ts +245 -0
  226. package/types/lib/mega-retry.d.ts +85 -0
  227. package/types/lib/mega-schedule.d.ts +260 -0
  228. package/types/lib/mega-shutdown.d.ts +135 -0
  229. package/types/lib/mega-tracing.d.ts +224 -0
  230. package/types/lib/mega-worker.d.ts +129 -0
  231. package/types/lib/otel-resource.d.ts +16 -0
  232. package/types/lib/worker-runner/process-entry.d.ts +1 -0
  233. package/types/lib/worker-runner/task-dispatch.d.ts +28 -0
  234. package/types/lib/worker-runner/thread-entry.d.ts +1 -0
  235. package/types/lib/ws-hub.d.ts +259 -0
  236. package/types/models/crud-sql-builder.d.ts +48 -0
  237. package/types/models/index.d.ts +1 -0
  238. package/types/models/mega-model.d.ts +138 -0
  239. package/types/models/model-crud.d.ts +82 -0
  240. package/types/models/mongo-crud.d.ts +59 -0
  241. package/types/test/index.d.ts +84 -0
  242. package/.env +0 -127
  243. package/sample/crud/apps/main/migrations/20260606000002-add-auth-to-users.js +0 -30
  244. package/sample/crud/apps/main/models/note.js +0 -71
  245. package/sample/crud/apps/main/models/user.js +0 -86
  246. package/sample/crud/package-lock.json +0 -5665
  247. package/sample/crud/yarn.lock +0 -2142
  248. package/sample/simple/package-lock.json +0 -1851
@@ -0,0 +1,266 @@
1
+ export class MegaHubLink {
2
+ /**
3
+ * 링크 라이프사이클 이벤트 (wire 타입과 충돌하지 않도록 `link.*` reserved). {@link MegaHubLink#on}
4
+ * 으로 구독한다. **핸들러 인자는 이벤트마다 다르다**(L-2):
5
+ * - `RECONNECTED` → `{ hubId: string }` — 재연결 성공(새 등록 완료). hubId 는 새 hub 의 식별자.
6
+ * - `DISCONNECTED` → `{ code: number, reason: string, isDrain: boolean }` — 등록 후 절단.
7
+ * `isDrain` 은 close code 가 4503(DRAIN)인지(다른 hub 로 회전 신호, ADR-098).
8
+ * - `RECONNECT_FAILED`→ `{ error: Error }` — 재연결 재시도 소진(더 이상 자동 재시도 없음).
9
+ * @type {Readonly<{ RECONNECTED: string, DISCONNECTED: string, RECONNECT_FAILED: string }>}
10
+ */
11
+ static EVENTS: Readonly<{
12
+ RECONNECTED: string;
13
+ DISCONNECTED: string;
14
+ RECONNECT_FAILED: string;
15
+ }>;
16
+ /**
17
+ * @param {Object} [opts]
18
+ * @param {string} [opts.url] - hub URL (예: 'ws://hub1.internal:19991/_hub'). 누락 시 throw.
19
+ * @param {string} [opts.token] - Bearer 토큰 (wsHub.acceptedTokens 중 하나). 누락 시 throw.
20
+ * @param {string} [opts.bridgeId] - 운영 식별자 (예: 'main-1'). 누락 시 throw.
21
+ * @param {string} [opts.instanceId] - REGISTER instanceId. 기본 bridgeId.
22
+ * @param {string[]} [opts.capabilities] - 선언 capability 목록. 기본 [].
23
+ * @param {import('../lib/mega-retry.js').MegaRetryOptions} [opts.retry] - 지정 시 재연결 활성(ADR-098).
24
+ * `{ retries, minTimeout, maxTimeout, factor, jitter }`. 미지정 → 재연결 끔(기본 동작).
25
+ * @param {number} [opts.connectTimeoutMs=10000] - register_ok 미수신 시 attempt reject 까지(M4).
26
+ * @param {import('./ws-compression.js').WsCompressionConfig} [opts.compression] - Bridge↔Hub link
27
+ * per-message deflate 압축(ADR-078). Global `wsHub.compression` 블록과 동일
28
+ * 스키마 — hub 서버와 양쪽이 협상해야 활성(RFC 7692). 디폴트 OFF. 잘못된 값은 즉시 throw.
29
+ * @param {{ warn?: Function, debug?: Function, info?: Function, error?: Function }} [opts.logger]
30
+ * @param {typeof import('ws').WebSocket} [opts.WebSocketCtor] - 테스트 주입용 ws 생성자.
31
+ * @param {number} [opts.maxBufferedBytes=16777216] - 송신 버퍼(bufferedAmount) 상한(바이트). 초과 시
32
+ * 백프레셔로 보고 소켓을 닫고(1013) 송신을 명시 실패시킨다 — hub 가 느릴 때 bridge 힙이 무한
33
+ * 적재되는 것을 막는다. 재연결(retry) 설정 시 자동 회복.
34
+ */
35
+ constructor({ url, token, bridgeId, instanceId, capabilities, retry, connectTimeoutMs, compression, logger, WebSocketCtor, maxBufferedBytes }?: {
36
+ url?: string;
37
+ token?: string;
38
+ bridgeId?: string;
39
+ instanceId?: string;
40
+ capabilities?: string[];
41
+ retry?: import("../lib/mega-retry.js").MegaRetryOptions;
42
+ connectTimeoutMs?: number;
43
+ compression?: import("./ws-compression.js").WsCompressionConfig;
44
+ logger?: {
45
+ warn?: Function;
46
+ debug?: Function;
47
+ info?: Function;
48
+ error?: Function;
49
+ };
50
+ WebSocketCtor?: typeof import("ws").WebSocket;
51
+ maxBufferedBytes?: number;
52
+ });
53
+ _url: string;
54
+ _token: string;
55
+ _bridgeId: string;
56
+ _instanceId: string;
57
+ _capabilities: string[];
58
+ _log: {
59
+ warn?: Function;
60
+ debug?: Function;
61
+ info?: Function;
62
+ error?: Function;
63
+ };
64
+ _WS: typeof WebSocket;
65
+ /** 재연결 옵션 (없으면 재연결 비활성). @type {import('../lib/mega-retry.js').MegaRetryOptions | null} */
66
+ _retry: import("../lib/mega-retry.js").MegaRetryOptions | null;
67
+ /** 한 attempt 의 register_ok 대기 한도(M4). reconnect 에서도 동일 적용. @type {number} */
68
+ _connectTimeoutMs: number;
69
+ /** 송신 버퍼(bufferedAmount) 상한 — 초과 시 백프레셔로 소켓을 닫는다(기본 16 MiB). @type {number} */
70
+ _maxBufferedBytes: number;
71
+ /** @type {false | Object} ws 클라이언트 perMessageDeflate 로 전달(_connectOnce). */
72
+ _perMessageDeflate: false | Object;
73
+ /** @type {import('ws').WebSocket | null} */
74
+ _ws: import("ws").WebSocket | null;
75
+ /** @type {boolean} register_ok 수신 여부. */
76
+ _isRegistered: boolean;
77
+ /** @type {string | null} hub 가 부여한 hubId. */
78
+ _hubId: string | null;
79
+ /** @type {number} register_ok 의 heartbeatMs(0 이면 heartbeat 끔). */
80
+ _heartbeatMs: number;
81
+ /** @type {ReturnType<typeof setInterval> | null} */
82
+ _hbTimer: ReturnType<typeof setInterval> | null;
83
+ /** type(wire)/lifecycle event → 핸들러 집합. @type {Map<string, Set<Function>>} */
84
+ _handlers: Map<string, Set<Function>>;
85
+ /** close() 로 의도적으로 닫는 중인지 — true 면 자동 재연결하지 않는다. @type {boolean} */
86
+ _isClosing: boolean;
87
+ /** 재연결 진행 중 가드(중복 reconnect 방지). @type {boolean} */
88
+ _isReconnecting: boolean;
89
+ /** close() 가 진행 중인 재시도(백오프 대기)를 취소하기 위한 컨트롤러. @type {AbortController | null} */
90
+ _abort: AbortController | null;
91
+ /** register_ok 로 협상된 hub 프로토콜 버전(등록 전 null, 레거시 hub 면 1). @type {number | null} */
92
+ _negotiatedProtocolVersion: number | null;
93
+ /**
94
+ * 레거시 hub 모드 — REGISTER 의 `protocolVersion` 필드를 모르는 구버전 hub(strict 스키마가
95
+ * `hub.invalid_message` 로 거부)로 판정되면 true. 이후 register 는 필드 없이(v1) 보낸다.
96
+ * @type {boolean}
97
+ */
98
+ _isLegacyHub: boolean;
99
+ /** hub 가 부여한 hubId (register 전엔 null). */
100
+ get hubId(): string;
101
+ /** register_ok 를 받아 사용 가능한 상태인지. */
102
+ get isRegistered(): boolean;
103
+ /** 협상된 hub 프로토콜 버전 (register 전엔 null, 레거시 hub 면 1). */
104
+ get negotiatedProtocolVersion(): number;
105
+ /** 소켓이 OPEN(=1) 인지. */
106
+ get isOpen(): boolean;
107
+ /** 재연결이 활성(retry 옵션 지정)인지. */
108
+ get canReconnect(): boolean;
109
+ /**
110
+ * 수신 메시지/라이프사이클 핸들러 등록. 같은 type 에 여러 개 등록 가능(모두 호출).
111
+ * @param {string} wireType - {@link HUB_MESSAGE_TYPES} 의 값(`hub.broadcast` 등) 또는
112
+ * {@link MegaHubLink.EVENTS} 의 라이프사이클 이벤트(`link.*`).
113
+ * @param {(msg: Object) => void} handler
114
+ * @returns {this}
115
+ */
116
+ on(wireType: string, handler: (msg: Object) => void): this;
117
+ /**
118
+ * hub 연결 + REGISTER 핸드셰이크. register_ok 수신 시 resolve.
119
+ *
120
+ * 초기 연결은 retry 유무와 무관하게 **단 1회** 시도한다. `retry` 옵션이 있으면 실패 시 백그라운드
121
+ * 재연결(지수 백오프)로 전환하고 reject 한다 — 성공 시 RECONNECTED, 소진 시 RECONNECT_FAILED emit.
122
+ * 호출부(boot)는 reject 를 warn 으로 받고 부팅을 계속한다(허브 다운이 부팅을 막지 않는 계약).
123
+ *
124
+ * @param {Object} [opts]
125
+ * @param {number} [opts.connectTimeoutMs] - register_ok 대기 한도 override(M4). **이 값은 인스턴스에
126
+ * 저장되어(`this._connectTimeoutMs`) 이후 자동 재연결 attempt 에도 동일하게 적용된다** — 이 한 번의
127
+ * connect() 에만 적용되는 것이 아니다(L-1). 재연결마다 같은 타임아웃을 쓰는 동작은 의도된 것이다.
128
+ * @returns {Promise<{ hubId: string, heartbeatMs: number }>}
129
+ * @throws register 전 에러/종료/타임아웃(재시도 소진 포함) 시 reject.
130
+ */
131
+ connect({ connectTimeoutMs }?: {
132
+ connectTimeoutMs?: number;
133
+ }): Promise<{
134
+ hubId: string;
135
+ heartbeatMs: number;
136
+ }>;
137
+ /**
138
+ * 단일 연결 시도 — ws open → REGISTER → register_ok. 한 attempt 의 Promise 를 돌려준다.
139
+ * 재시도/재연결은 호출부({@link MegaHubLink#connect}/{@link MegaHubLink#_reconnect})가 감싼다.
140
+ *
141
+ * @param {{ connectTimeoutMs: number }} args
142
+ * @returns {Promise<{ hubId: string, heartbeatMs: number }>}
143
+ * @private
144
+ */
145
+ private _connectOnce;
146
+ /**
147
+ * 등록 후 연결이 끊겼을 때 처리 — DISCONNECTED emit + (retry 활성·의도적 close 아님) 자동 재연결.
148
+ * @param {number} code - WS close code (4503=drain 등).
149
+ * @param {string} reason
150
+ * @private
151
+ */
152
+ private _handleEstablishedClose;
153
+ /**
154
+ * 자동 재연결 — 백오프로 _connectOnce 반복. 성공 시 RECONNECTED, 소진 시 RECONNECT_FAILED emit.
155
+ * @returns {Promise<void>}
156
+ * @private
157
+ */
158
+ private _reconnect;
159
+ /**
160
+ * 사용자 접속 알림 (JOIN). presence 등록.
161
+ * @param {{ userId: string, sessionId: string, channels: string[], metadata?: Object }} entry
162
+ * @returns {void}
163
+ */
164
+ join(entry: {
165
+ userId: string;
166
+ sessionId: string;
167
+ channels: string[];
168
+ metadata?: Object;
169
+ }): void;
170
+ /**
171
+ * 단일 세션 종료 (LEAVE).
172
+ * @param {string} sessionId
173
+ * @returns {void}
174
+ */
175
+ leave(sessionId: string): void;
176
+ /**
177
+ * 다수 세션 일괄 종료 (BULK_LEAVE) — 여러 세션의 presence LEAVE 를 한 프레임으로 보낸다.
178
+ *
179
+ * 공개 API 다(프레임워크 내부는 현재 hub 의 bridge-gone 자동 감지에 의존해 직접 호출하지 않음).
180
+ * 다음 같은 **대량 정리** 상황에서 애플리케이션이 직접 호출한다:
181
+ * - 대량 logout(한 사용자의 여러 세션을 한 번에 종료),
182
+ * - 클라이언트 풀/탭 정리(연결 다수를 묶어 종료),
183
+ * - bridge 가 자체 drain 으로 보유 세션을 능동적으로 비울 때(소켓 close 를 기다리지 않고 선통지).
184
+ * 세션 1건이면 {@link MegaHubLink#leave} 를 쓰는 편이 단순하다.
185
+ *
186
+ * @param {string[]} sessionIds
187
+ * @returns {void}
188
+ */
189
+ bulkLeave(sessionIds: string[]): void;
190
+ /**
191
+ * 채널 전체 푸시 (BROADCAST). hub 가 가입 bridge 들에 fan-out.
192
+ * @param {{ ns: string, channel: string, message: Object, exceptSessionIds?: string[] }} payload
193
+ * @returns {void}
194
+ */
195
+ broadcast(payload: {
196
+ ns: string;
197
+ channel: string;
198
+ message: Object;
199
+ exceptSessionIds?: string[];
200
+ }): void;
201
+ /**
202
+ * 특정 사용자에게 직접 (DIRECT). hub 가 userId→sessionIds[] fan-out (ADR-035).
203
+ * @param {{ userId: string, message: Object }} payload
204
+ * @returns {void}
205
+ */
206
+ direct(payload: {
207
+ userId: string;
208
+ message: Object;
209
+ }): void;
210
+ /**
211
+ * 세션 메타데이터 갱신 (METADATA) — 명시 필드만(ADR-059).
212
+ * @param {{ sessionId: string, metadata: Object }} payload
213
+ * @returns {void}
214
+ */
215
+ updateMetadata(payload: {
216
+ sessionId: string;
217
+ metadata: Object;
218
+ }): void;
219
+ /**
220
+ * 바이너리 메타 프레임 (BINARY). raw bytes 후속 프레임 전송은 본 Step 미포함(envelope 한정).
221
+ * @param {{ ref: string, mimeType: string, bytes: number }} payload
222
+ * @returns {void}
223
+ */
224
+ binary(payload: {
225
+ ref: string;
226
+ mimeType: string;
227
+ bytes: number;
228
+ }): void;
229
+ /** 연결 종료 — 의도적 close 표시 + 진행 중 재연결 취소 + heartbeat 정리 후 소켓 close. */
230
+ close(): void;
231
+ /**
232
+ * 타입별 송신 — register_ok 이후에만 허용. register 전 호출은 fail-closed throw.
233
+ * @param {string} type - wire type(`hub.*`).
234
+ * @param {Object} payload
235
+ * @returns {void}
236
+ * @private
237
+ */
238
+ private _send;
239
+ /**
240
+ * envelope 직렬화 후 소켓 송신.
241
+ * @param {Object} envelope
242
+ * @returns {void}
243
+ * @private
244
+ */
245
+ private _sendEnvelope;
246
+ /**
247
+ * 수신 메시지를 등록된 핸들러에 디스패치. 핸들러 throw 는 격리(다른 핸들러 보호).
248
+ * @param {import('../lib/hub-protocol.js').HubEnvelope} msg
249
+ * @returns {void}
250
+ * @private
251
+ */
252
+ private _dispatch;
253
+ /**
254
+ * 라이프사이클 이벤트 emit (RECONNECTED 등). 디스패치와 같은 핸들러 맵을 쓰되 인자는 이벤트 데이터.
255
+ * @param {string} event - {@link MegaHubLink.EVENTS} 값.
256
+ * @param {Object} data
257
+ * @returns {void}
258
+ * @private
259
+ */
260
+ private _emit;
261
+ /** heartbeat 루프 시작 (heartbeatMs>0 일 때만). 프로세스 종료 막지 않게 unref. @private */
262
+ private _startHeartbeat;
263
+ /** heartbeat 루프 정지. @private */
264
+ private _stopHeartbeat;
265
+ }
266
+ import { WebSocket } from 'ws';
@@ -0,0 +1,178 @@
1
+ /**
2
+ * i18n 등록 결과 요약(디버그·테스트용).
3
+ * @typedef {Object} I18nSummary
4
+ * @property {boolean} enabled - 등록 여부.
5
+ * @property {string} default - 기본 언어.
6
+ * @property {string} fallback - fallback 언어.
7
+ * @property {string[]} available - 지원 언어 목록.
8
+ * @property {string} cookieName - locale 쿠키 이름.
9
+ * @property {boolean} autoComplete - saveMissing(dev 자동 키 생성) 활성 여부.
10
+ * @property {import('i18next').i18n | null} instance - 생성된 i18next 인스턴스(미등록 시 null).
11
+ */
12
+ /**
13
+ * 정규화된 i18n 설정.
14
+ * @typedef {Object} NormalizedI18n
15
+ * @property {string} default
16
+ * @property {string} fallback
17
+ * @property {string[]} available
18
+ * @property {string} cookieName
19
+ * @property {{ enabled: boolean, dir: string|null, debounceMs: number }} autoComplete
20
+ * @property {string|null} localesDir
21
+ * @property {Record<string, any>} resources
22
+ * @property {boolean} exposeTranslations
23
+ * @property {string} translationsPath
24
+ */
25
+ /**
26
+ * 앱 `i18n` config 를 정규화한다. falsy 면 미옵트인(`null`).
27
+ *
28
+ * 잘못된 형태는 **fail-fast** 로 throw 한다(silent 보정 X). `available` 이 배열이 아니거나 비었으면
29
+ * 부팅 에러로 드러내, locale 미설정이 런타임에 조용히 fallback 으로 뭉개지지 않게 한다.
30
+ *
31
+ * @param {unknown} i18n - `MegaI18nAppConfig`(default/available/fallback/cookieName/autoComplete/...).
32
+ * @returns {NormalizedI18n | null}
33
+ * @throws {Error} `available` 가 비-배열/빈 배열 등 명백한 오설정.
34
+ */
35
+ export function normalizeI18n(i18n: unknown): NormalizedI18n | null;
36
+ /**
37
+ * `<dir>/<scope>/<lng>.json` 디렉터리 구조에서 locale 리소스를 로드한다(ADR-039 scope 분리 레이아웃,
38
+ * 04-data-models §768). 파일이 없으면 건너뛴다(빈 namespace). 부팅 시 1회 동기 읽기.
39
+ *
40
+ * @param {string|null} dir - locale 루트 디렉터리. null 이면 빈 리소스.
41
+ * @param {object} opts
42
+ * @param {string[]} opts.available - 로드할 언어 목록.
43
+ * @param {{ warn?: Function }} [opts.logger]
44
+ * @returns {Record<string, Record<string, object>>} `{ <lng>: { <scope>: {...} } }` i18next resources 형태.
45
+ */
46
+ export function loadLocaleResources(dir: string | null, { available, logger }?: {
47
+ available: string[];
48
+ logger?: {
49
+ warn?: Function;
50
+ };
51
+ }): Record<string, Record<string, object>>;
52
+ /**
53
+ * saveMissing 디바운스 writer 를 만든다 — axion 패턴(ADR-037).
54
+ *
55
+ * `(lng, scope, key, value)` 누락 키를 모아 `<dir>/<scope>/<lng>.json` 파일에 **기존 키 보존**하며
56
+ * 병합 저장한다. 같은 파일의 연속 호출은 `debounceMs` 동안 흡수(타이머 1개)하고, flush 시:
57
+ * 1. 기존 파일 읽어 base 로(없으면 {}),
58
+ * 2. 모아둔 누락 키를 dot-notation 으로 set(기존 키 안 건드림),
59
+ * 3. tmp 파일 작성 → `rename`(원자적 쓰기 — 부분 파일 노출 방지),
60
+ * 4. `timer.unref()` 라 보류 중 타이머가 프로세스 종료를 막지 않음.
61
+ *
62
+ * 쓰기 실패는 비치명적(dev 편의 기능) — warn 후 다음 호출에 재시도.
63
+ *
64
+ * @param {object} opts
65
+ * @param {string} opts.dir - locale 루트 디렉터리.
66
+ * @param {number} opts.debounceMs
67
+ * @param {{ debug?: Function, warn?: Function }} [opts.logger]
68
+ * @returns {{ enqueue: (lng: string, scope: string, key: string, value: string) => void, flushAll: () => Promise<void>, _pendingCount: () => number }}
69
+ */
70
+ export function createMissingKeyWriter({ dir, debounceMs, logger }: {
71
+ dir: string;
72
+ debounceMs: number;
73
+ logger?: {
74
+ debug?: Function;
75
+ warn?: Function;
76
+ };
77
+ }): {
78
+ enqueue: (lng: string, scope: string, key: string, value: string) => void;
79
+ flushAll: () => Promise<void>;
80
+ _pendingCount: () => number;
81
+ };
82
+ /**
83
+ * 요청 Cookie 헤더에서 locale 쿠키를 읽어 유효 언어로 결정한다(ADR-038 — 쿠키만).
84
+ *
85
+ * 쿠키가 없거나 `available` 에 없는 값이면 `default` 로 폴백한다(조용한 클램프 — 변조·구식 쿠키 방어).
86
+ *
87
+ * @param {string|undefined} cookieHeader - `req.headers.cookie`.
88
+ * @param {object} opts
89
+ * @param {string} opts.cookieName
90
+ * @param {string[]} opts.available
91
+ * @param {string} opts.default
92
+ * @returns {string} 결정된 언어.
93
+ */
94
+ export function detectLocale(cookieHeader: string | undefined, { cookieName, available, default: def }: {
95
+ cookieName: string;
96
+ available: string[];
97
+ default: string;
98
+ }): string;
99
+ /**
100
+ * Fastify 인스턴스에 i18n(`i18next`) 을 자동 등록한다 — 요청별 언어 결정·`req.t`·scope 번들·관측성.
101
+ *
102
+ * `i18n` 이 falsy 면 **미등록**(옵트인). session.js / multipart.js 형제 패턴. 호출 순서는 라우트 등록
103
+ * 이전 어디든 무방하다(onRequest hook + request 부착이라 라우트 순서와 무관).
104
+ *
105
+ * @param {import('fastify').FastifyInstance} fastify - 대상 앱 Fastify 인스턴스.
106
+ * @param {Object} opts
107
+ * @param {unknown} opts.i18n - `MegaI18nAppConfig`. falsy 면 미등록.
108
+ * @param {string} [opts.appName] - 앱 이름(메트릭 라벨·로그용).
109
+ * @param {{ debug?: Function, warn?: Function }} [opts.logger] - 흐름 길목 debug 로그(선택).
110
+ * @returns {I18nSummary}
111
+ */
112
+ export function registerI18n(fastify: import("fastify").FastifyInstance, { i18n, appName, logger }?: {
113
+ i18n: unknown;
114
+ appName?: string;
115
+ logger?: {
116
+ debug?: Function;
117
+ warn?: Function;
118
+ };
119
+ }): I18nSummary;
120
+ /** locale 쿠키 기본 이름 (04-data-models §394 `cookieName: 'mega.lang'`). */
121
+ export const DEFAULT_I18N_COOKIE: "mega.lang";
122
+ /** scope 분리 고정 namespace 2종 (ADR-039). server=에러·검증, client=SPA UI. */
123
+ export const I18N_SCOPES: readonly string[];
124
+ /** server scope = 기본 namespace — `ctx.t()` 가 자동 선택(ADR-039). */
125
+ export const DEFAULT_SCOPE: "server";
126
+ /** saveMissing 디바운스 기본값 (ms, ADR-037 axion 패턴). */
127
+ export const DEFAULT_DEBOUNCE_MS: 500;
128
+ /**
129
+ * i18n 등록 결과 요약(디버그·테스트용).
130
+ */
131
+ export type I18nSummary = {
132
+ /**
133
+ * - 등록 여부.
134
+ */
135
+ enabled: boolean;
136
+ /**
137
+ * - 기본 언어.
138
+ */
139
+ default: string;
140
+ /**
141
+ * - fallback 언어.
142
+ */
143
+ fallback: string;
144
+ /**
145
+ * - 지원 언어 목록.
146
+ */
147
+ available: string[];
148
+ /**
149
+ * - locale 쿠키 이름.
150
+ */
151
+ cookieName: string;
152
+ /**
153
+ * - saveMissing(dev 자동 키 생성) 활성 여부.
154
+ */
155
+ autoComplete: boolean;
156
+ /**
157
+ * - 생성된 i18next 인스턴스(미등록 시 null).
158
+ */
159
+ instance: import("i18next").i18n | null;
160
+ };
161
+ /**
162
+ * 정규화된 i18n 설정.
163
+ */
164
+ export type NormalizedI18n = {
165
+ default: string;
166
+ fallback: string;
167
+ available: string[];
168
+ cookieName: string;
169
+ autoComplete: {
170
+ enabled: boolean;
171
+ dir: string | null;
172
+ debounceMs: number;
173
+ };
174
+ localesDir: string | null;
175
+ resources: Record<string, any>;
176
+ exposeTranslations: boolean;
177
+ translationsPath: string;
178
+ };
@@ -0,0 +1,28 @@
1
+ export { MegaApp } from "./mega-app.js";
2
+ export { MegaWsPresence } from "./ws-presence.js";
3
+ export { MegaServer } from "./mega-server.js";
4
+ export { MegaService } from "./mega-service.js";
5
+ export { MegaCluster } from "./mega-cluster.js";
6
+ export { loadRoutes } from "./routes-loader.js";
7
+ export { buildErrorHandler } from "./error-mapper.js";
8
+ export { loadAndValidateConfig } from "./config-loader.js";
9
+ export { MegaWebSocketController } from "./ws-controller.js";
10
+ export { MegaHubLink } from "./hub-link.js";
11
+ export { createSessionCleanupSchedule } from "./session-cleanup-schedule.js";
12
+ export { Router, MegaRouteError } from "./router.js";
13
+ export { bootApp, buildBootContext } from "./boot.js";
14
+ export { wrapEnvelope, errorEnvelope, synthesizeEnvelopeResponseSchema, ENVELOPE_MARK } from "./envelope.js";
15
+ export { buildHttpPipeline, wrapPreHandler, composeTransform, composeAfter } from "./pipeline.js";
16
+ export { ajvErrorToValidationError, MAX_VALIDATION_DETAILS } from "./ajv-mapper.js";
17
+ export { buildHttpCtx, getHttpCtx, getLazyHttpCtx, buildAdapterAccessors } from "./ctx-builder.js";
18
+ export { createWsMessage, validateWsMessage, parseWsMessage, generateMessageId, WS_MESSAGE_SCHEMA, WS_PROTOCOL_VERSION, WS_TYPE_PATTERN } from "./ws-message.js";
19
+ export { MegaWsConnection, driveWsConnection, createPlainCodec, createAspCodec, rejectUpgrade, CLOSE_CODE_DECRYPT_FAILED, CLOSE_CODE_INTERNAL_ERROR } from "./ws-upgrade.js";
20
+ export { buildPerMessageDeflate, checkCompressionConfig, COMPRESSION_DEFAULTS } from "./ws-compression.js";
21
+ export { validateGlobalConfig, validateAppConfig, validateHostCollisions } from "./config-validator.js";
22
+ export { registerSecurityPlugins, DEFAULT_RATE_LIMIT } from "./security.js";
23
+ export { registerSession, generateSid, readSession } from "./session.js";
24
+ export { createSessionStore, SESSION_STORE_DRIVERS } from "./session-store.js";
25
+ export { registerI18n, normalizeI18n, detectLocale, loadLocaleResources, createMissingKeyWriter, DEFAULT_I18N_COOKIE, I18N_SCOPES } from "./i18n.js";
26
+ export { registerTemplate, MegaTemplate, normalizeViews, resolveViewPath, renderView, VIEW_ENGINE } from "./template.js";
27
+ export { registerStaticAssets, normalizeStaticAssets, DEFAULT_STATIC_PREFIX } from "./static-assets.js";
28
+ export { registerOpenapi, normalizeOpenapi, DEFAULT_OPENAPI_PATH } from "./openapi.js";