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,82 @@
1
+ /**
2
+ * @typedef {object} RedisSessionConfig
3
+ * @property {string} [driver] - 'redis' (팩토리가 사용 — 어댑터는 무시).
4
+ * @property {string} [url] - `redis://[:pw@]host:port[/db]` (discrete 와 배타).
5
+ * @property {string} [connectionString] - `url` 의 deprecated 별칭.
6
+ * @property {string} [host] @property {number} [port] @property {string} [user] @property {string} [password]
7
+ * @property {number} [db] - 논리 DB 번호 0~15.
8
+ * @property {string} [keyPrefix] - 세션 키 prefix(기본 'mega:sess:').
9
+ * @property {number} [ttlMs] - save() 가 적용할 기본 TTL(ms). 미지정 시 24시간.
10
+ * @property {Record<string, any>} [options] - ioredis passthrough.
11
+ */
12
+ export class MegaRedisSessionAdapter extends MegaSessionAdapter {
13
+ /**
14
+ * @param {RedisSessionConfig} [config]
15
+ * @throws {MegaValidationError} `adapter.connection_required` / `adapter.connection_conflict` / `session.invalid_option`
16
+ */
17
+ constructor(config?: RedisSessionConfig);
18
+ /**
19
+ * raw ioredis handle (ADR-009).
20
+ * @protected
21
+ * @returns {import('ioredis').Redis}
22
+ */
23
+ protected _native(): import("ioredis").Redis;
24
+ /**
25
+ * 헬스 체크 — 실제 ping. 비밀번호/url 은 노출하지 않는다.
26
+ * @returns {Promise<{ ok: boolean, driver: 'redis', state: string, db?: number, error?: string }>}
27
+ */
28
+ healthCheck(): Promise<{
29
+ ok: boolean;
30
+ driver: "redis";
31
+ state: string;
32
+ db?: number;
33
+ error?: string;
34
+ }>;
35
+ /**
36
+ * 누적 통계 + redis 세션 특화.
37
+ * @returns {ReturnType<import('./mega-adapter.js').MegaAdapter['getStats']> & { driver: string, db: number | undefined, keyPrefix: string, ttlMs: number, status: string | undefined }}
38
+ */
39
+ getStats(): ReturnType<import("./mega-adapter.js").MegaAdapter["getStats"]> & {
40
+ driver: string;
41
+ db: number | undefined;
42
+ keyPrefix: string;
43
+ ttlMs: number;
44
+ status: string | undefined;
45
+ };
46
+ #private;
47
+ }
48
+ export type RedisSessionConfig = {
49
+ /**
50
+ * - 'redis' (팩토리가 사용 — 어댑터는 무시).
51
+ */
52
+ driver?: string;
53
+ /**
54
+ * - `redis://[:pw@]host:port[/db]` (discrete 와 배타).
55
+ */
56
+ url?: string;
57
+ /**
58
+ * - `url` 의 deprecated 별칭.
59
+ */
60
+ connectionString?: string;
61
+ host?: string;
62
+ port?: number;
63
+ user?: string;
64
+ password?: string;
65
+ /**
66
+ * - 논리 DB 번호 0~15.
67
+ */
68
+ db?: number;
69
+ /**
70
+ * - 세션 키 prefix(기본 'mega:sess:').
71
+ */
72
+ keyPrefix?: string;
73
+ /**
74
+ * - save() 가 적용할 기본 TTL(ms). 미지정 시 24시간.
75
+ */
76
+ ttlMs?: number;
77
+ /**
78
+ * - ioredis passthrough.
79
+ */
80
+ options?: Record<string, any>;
81
+ };
82
+ import { MegaSessionAdapter } from './mega-session-adapter.js';
@@ -0,0 +1,149 @@
1
+ /**
2
+ * @typedef {object} RedlockConfig
3
+ * @property {string} [driver] - 'redlock' (매니저가 사용 — 어댑터는 무시).
4
+ * @property {string} redis - 참조할 Redis 캐시 어댑터 key (services.caches.<key>). 필수.
5
+ * @property {Partial<RedlockSettings>} [options] - redlock Settings passthrough(driftFactor/retryCount/retryDelay/retryJitter/automaticExtensionThreshold).
6
+ */
7
+ export class MegaRedlockAdapter extends MegaLockAdapter {
8
+ /**
9
+ * redlock Settings 검증·정규화. options 없으면 빈 객체(=redlock 디폴트 사용). 알 수 없는 키는 오타로
10
+ * 보고 거부, 숫자 4종은 음 아닌 정수, driftFactor 는 [0,1) 유한수.
11
+ * @param {unknown} options @returns {Partial<RedlockSettings>}
12
+ */
13
+ static "__#private@#normalizeSettings"(options: unknown): Partial<RedlockSettings>;
14
+ /**
15
+ * @param {RedlockConfig} [config] - services.locks.<key> 설정.
16
+ * @throws {MegaValidationError} `lock.redis_required` - `redis` 키 누락/비문자열.
17
+ * @throws {MegaValidationError} `adapter.invalid_option` - options 타입/알 수 없는 settings 키/음수.
18
+ */
19
+ constructor(config?: RedlockConfig);
20
+ /**
21
+ * raw redlock handle (ADR-009). 베이스 `native` getter 가 connected 상태에서만 호출한다.
22
+ * @protected
23
+ * @returns {import('redlock').default}
24
+ */
25
+ protected _native(): import("redlock").default;
26
+ /**
27
+ * 헬스 체크 — 락 가용성은 곧 참조 Redis 의 가용성이라 그 어댑터의 healthCheck 에 위임한다.
28
+ * 실패는 throw 없이 `ok:false` + 사유(베이스 계약).
29
+ * @returns {Promise<{ ok: boolean, driver: 'redlock', state: string, redis: string, redisOk?: boolean, error?: string }>}
30
+ */
31
+ healthCheck(): Promise<{
32
+ ok: boolean;
33
+ driver: "redlock";
34
+ state: string;
35
+ redis: string;
36
+ redisOk?: boolean;
37
+ error?: string;
38
+ }>;
39
+ /**
40
+ * 누적 통계 + redlock 특화(driver/redis 키/settings). settings 는 숫자 계수뿐이라 시크릿 없음.
41
+ * @returns {ReturnType<import('./mega-adapter.js').MegaAdapter['getStats']> & { driver: string, redis: string, settings: Partial<RedlockSettings> }}
42
+ */
43
+ getStats(): ReturnType<import("./mega-adapter.js").MegaAdapter["getStats"]> & {
44
+ driver: string;
45
+ redis: string;
46
+ settings: Partial<RedlockSettings>;
47
+ };
48
+ /**
49
+ * 락 획득 — `redlock.acquire([key], ttl, settings)`. 경합 시 retry(opts) 소진 후 실패하면 redlock 이
50
+ * `ExecutionError` 를 throw(정상 도메인 결과 — 호출부가 처리).
51
+ *
52
+ * @param {string} key - 락 자원 키.
53
+ * @param {{ ttl?: number, retryCount?: number, retryDelay?: number, retryJitter?: number }} [opts]
54
+ * - `ttl`(ms, 양의 정수 필수). retry 3종은 이번 호출 한정 override(미지정 시 생성자 settings 사용).
55
+ * @returns {Promise<import('redlock').Lock>} redlock Lock 핸들.
56
+ */
57
+ acquire(key: string, opts?: {
58
+ ttl?: number;
59
+ retryCount?: number;
60
+ retryDelay?: number;
61
+ retryJitter?: number;
62
+ }): Promise<import("redlock").Lock>;
63
+ /**
64
+ * 락 해제 — `lock.release()`. 이미 만료/탈취된 락 release 는 redlock 이 'error' 로 표면화하거나
65
+ * throw 할 수 있다(비치명 — 락은 어차피 만료됨). 본 메서드는 정상 해제 경로를 instrument 한다.
66
+ *
67
+ * @param {import('redlock').Lock} lock - {@link acquire}/{@link extend} 가 돌려준 핸들.
68
+ * @returns {Promise<void>}
69
+ */
70
+ release(lock: import("redlock").Lock): Promise<void>;
71
+ /**
72
+ * 락 TTL 연장 — `redlock.extend(lock, ttl)`. **새 Lock 핸들을 반환**한다(redlock 이 연장 시 새 핸들을
73
+ * 만듦) — 이후 release/extend 는 반환된 핸들을 써야 한다(기존 핸들 무효, ADR-113).
74
+ *
75
+ * @param {import('redlock').Lock} lock @param {number} ttl - 추가 보유 시간(ms, 양의 정수).
76
+ * @returns {Promise<import('redlock').Lock>} 연장된 새 Lock 핸들.
77
+ */
78
+ extend(lock: import("redlock").Lock, ttl: number): Promise<import("redlock").Lock>;
79
+ /**
80
+ * convenience — `redlock.using([key], ttl, settings, routine)`. 락 획득 + **자동 연장**
81
+ * (automaticExtensionThreshold 임박 시 자동 extend) + 종료 시 자동 release(routine 이 throw 해도 보장).
82
+ *
83
+ * routine 은 `(signal)` 을 받는다 — `signal.aborted` 가 true 면 자동 연장이 실패해 더는 배타성을
84
+ * 보장할 수 없는 상태다(`signal.error` 에 사유). routine 은 이때 즉시 중단하고 예외 상황으로 처리해야
85
+ * 한다(베이스 `withLock` 의 `(lock)` 시그니처와 다름 — auto-extension 모델 차이, ADR-113).
86
+ *
87
+ * @template T
88
+ * @param {string} key
89
+ * @param {{ ttl?: number, retryCount?: number, retryDelay?: number, retryJitter?: number }} opts - `ttl`(ms) 필수.
90
+ * @param {(signal: RedlockAbortSignal) => Promise<T>} fn - 임계구역 routine.
91
+ * @returns {Promise<T>} routine 반환값.
92
+ */
93
+ withLock<T>(key: string, opts: {
94
+ ttl?: number;
95
+ retryCount?: number;
96
+ retryDelay?: number;
97
+ retryJitter?: number;
98
+ }, fn: (signal: RedlockAbortSignal) => Promise<T>): Promise<T>;
99
+ #private;
100
+ }
101
+ /**
102
+ * redlock Settings 부분집합. redlock 패키지의 `Settings` interface 는 **type-only export** 라 패키지
103
+ * `exports` 맵(→ .d.ts 없는 esm .js)을 통과하면 TS 에 안 보인다(런타임 값 있는 class 만 보임). 그래서
104
+ * 같은 shape 를 로컬 typedef 로 둔다(redlock 정의와 1:1, dist/index.d.ts 확인).
105
+ */
106
+ export type RedlockSettings = {
107
+ /**
108
+ * - 시계 드리프트 보정 계수 [0,1).
109
+ */
110
+ driftFactor?: number;
111
+ /**
112
+ * - 경합 시 재시도 횟수.
113
+ */
114
+ retryCount?: number;
115
+ /**
116
+ * - 재시도 간 지연(ms).
117
+ */
118
+ retryDelay?: number;
119
+ /**
120
+ * - 재시도 지연 지터(ms).
121
+ */
122
+ retryJitter?: number;
123
+ /**
124
+ * - `using` 자동 연장 임계(ms).
125
+ */
126
+ automaticExtensionThreshold?: number;
127
+ };
128
+ /**
129
+ * redlock `using` routine 이 받는 중단 신호 (redlock 의 `RedlockAbortSignal` 과 동일 shape — 위와 같은
130
+ * type-only export 사유로 로컬 정의). `aborted` 가 true 면 자동 연장 실패로 배타성 상실, `error` 에 사유.
131
+ */
132
+ export type RedlockAbortSignal = AbortSignal & {
133
+ error?: Error;
134
+ };
135
+ export type RedlockConfig = {
136
+ /**
137
+ * - 'redlock' (매니저가 사용 — 어댑터는 무시).
138
+ */
139
+ driver?: string;
140
+ /**
141
+ * - 참조할 Redis 캐시 어댑터 key (services.caches.<key>). 필수.
142
+ */
143
+ redis: string;
144
+ /**
145
+ * - redlock Settings passthrough(driftFactor/retryCount/retryDelay/retryJitter/automaticExtensionThreshold).
146
+ */
147
+ options?: Partial<RedlockSettings>;
148
+ };
149
+ import { MegaLockAdapter } from './mega-lock-adapter.js';
@@ -0,0 +1,46 @@
1
+ /**
2
+ * driver → 어댑터 클래스 등록. 이미 같은 driver 가 **다른 클래스**로 등록돼 있으면 throw
3
+ * (silent override 방지). 같은 클래스 재등록은 idempotent no-op.
4
+ *
5
+ * @param {string} driver - driver 이름 (예: 'postgres').
6
+ * @param {typeof MegaAdapter} AdapterClass - MegaAdapter 를 상속한 어댑터 클래스.
7
+ * @returns {void}
8
+ */
9
+ export function register(driver: string, AdapterClass: typeof MegaAdapter): void;
10
+ /**
11
+ * `config.adapters.register` 맵을 일괄 등록 (ADR-044 3rd party). 빌트인 예약어 점유 시 throw.
12
+ *
13
+ * @param {Record<string, typeof MegaAdapter>} [registerMap]
14
+ * @returns {void}
15
+ */
16
+ export function registerFromConfig(registerMap?: Record<string, typeof MegaAdapter>): void;
17
+ /**
18
+ * driver 이름으로 등록된 어댑터 클래스 조회. 없으면 `adapter.unknown_driver` throw.
19
+ *
20
+ * @param {string} driver
21
+ * @returns {typeof MegaAdapter}
22
+ */
23
+ export function resolve(driver: string): typeof MegaAdapter;
24
+ /**
25
+ * driver 가 등록돼 있는지 (Boolean — `has*`, ADR-036).
26
+ * @param {string} driver
27
+ * @returns {boolean}
28
+ */
29
+ export function has(driver: string): boolean;
30
+ /**
31
+ * 등록된 driver 이름 목록.
32
+ * @returns {string[]}
33
+ */
34
+ export function list(): string[];
35
+ /**
36
+ * 테스트용 reset — 등록 전부 비움.
37
+ * @returns {void}
38
+ */
39
+ export function _reset(): void;
40
+ /**
41
+ * 빌트인 driver 예약어 (ADR-044, ADR-082 file 포함, ADR-113 redlock 포함). 구체 클래스는 각 Step 에서 등록.
42
+ * 3rd party 가 이 이름을 점유하지 못하도록 예약 — `registerFromConfig` 가 거부.
43
+ * @type {ReadonlySet<string>}
44
+ */
45
+ export const BUILTIN_DRIVERS: ReadonlySet<string>;
46
+ import { MegaAdapter } from './mega-adapter.js';
@@ -0,0 +1,106 @@
1
+ /**
2
+ * @typedef {object} SqliteConfig
3
+ * @property {string} [driver] - 'sqlite' (매니저가 사용 — 어댑터는 무시).
4
+ * @property {string} filename - DB 파일 경로 또는 ':memory:' (필수).
5
+ * @property {boolean} [readonly] - 읽기 전용 연결.
6
+ * @property {boolean} [fileMustExist] - 파일이 없으면 connect 시 throw.
7
+ * @property {number} [timeout] - 잠긴 DB 대기 ms (SQLITE_BUSY 전, 기본 5000).
8
+ * @property {boolean} [wal] - true 면 connect 후 `journal_mode = WAL` 적용.
9
+ * @property {Record<string, string | number>} [pragmas] - connect 후 적용할 추가 PRAGMA 맵.
10
+ */
11
+ export class MegaSqliteAdapter extends MegaDbAdapter {
12
+ /**
13
+ * @param {SqliteConfig} [config] - services.databases.<key> 설정.
14
+ * @throws {MegaValidationError} `sqlite.filename_required` - filename 누락/빈 문자열.
15
+ * @throws {MegaValidationError} `sqlite.invalid_option` - 옵션 타입 오류.
16
+ */
17
+ constructor(config?: SqliteConfig);
18
+ /** driver 식별자 — dialect 디스패치(getDialect)·CRUD 의 단일 출처(ADR-212). @returns {'sqlite'} */
19
+ get driver(): "sqlite";
20
+ /**
21
+ * raw Database handle (ADR-009). `connect()` 후에만 베이스 `native` getter 가 호출한다.
22
+ * @protected
23
+ * @returns {import('better-sqlite3').Database}
24
+ */
25
+ protected _native(): import("better-sqlite3").Database;
26
+ /**
27
+ * 헬스 체크 — 실제 `SELECT 1` 으로 응답성 확인 (베이스 디폴트는 상태만 반영).
28
+ * connect 전이거나 쿼리 실패면 `ok:false` + 사유. `/health/ready` 가 모든 어댑터 ok 를 AND.
29
+ *
30
+ * @returns {Promise<{ ok: boolean, driver: 'sqlite', state: string, filename?: string, error?: string }>}
31
+ */
32
+ healthCheck(): Promise<{
33
+ ok: boolean;
34
+ driver: "sqlite";
35
+ state: string;
36
+ filename?: string;
37
+ error?: string;
38
+ }>;
39
+ /**
40
+ * 누적 통계 + sqlite 특화 필드.
41
+ * @returns {ReturnType<import('./mega-adapter.js').MegaAdapter['getStats']> & { driver: string, filename: string, inMemory: boolean, readonly: boolean, journalMode: string | undefined }}
42
+ */
43
+ getStats(): ReturnType<import("./mega-adapter.js").MegaAdapter["getStats"]> & {
44
+ driver: string;
45
+ filename: string;
46
+ inMemory: boolean;
47
+ readonly: boolean;
48
+ journalMode: string | undefined;
49
+ };
50
+ /**
51
+ * 명시적 트랜잭션 경계 (ADR-010, ADR-105). manual `BEGIN/COMMIT/ROLLBACK` 으로
52
+ * async `fn` 과 better-sqlite3 의 동기 트랜잭션 모델을 정합시킨다(모듈 docstring 참조).
53
+ *
54
+ * `fn` 은 **트랜잭션 컨텍스트 native handle**(= 같은 Database 인스턴스)을 인자로 받는다.
55
+ * 성공 시 COMMIT 후 `fn` 반환값을 그대로 돌려주고, `fn` 이 throw 하면 ROLLBACK 후 원본 에러를
56
+ * re-throw 한다. nested / 동시 호출은 `db.inTransaction` 으로 감지해 거부(ADR-105).
57
+ *
58
+ * `opts.isolation`(ADR-190) — SQLite 트랜잭션은 항상 SERIALIZABLE 동작(단일 writer, 공식 문서)이라
59
+ * `'serializable'` 만 수용(no-op)하고 다른 값은 `adapter.invalid_option` 으로 명시 거부한다
60
+ * (조용히 무시하면 사용자가 다른 격리수준이 적용된 줄 오인 — P4).
61
+ *
62
+ * hook(`onCallStart/onCallEnd`) + 상태 검증 + stats 누적은 `_instrument` 가 처리한다(ADR-077).
63
+ *
64
+ * @template T
65
+ * @param {(db: import('better-sqlite3').Database) => Promise<T> | T} fn
66
+ * @param {{ isolation?: 'serializable' }} [opts] - 트랜잭션 옵션(ADR-190).
67
+ * @returns {Promise<T>}
68
+ * @throws {MegaInternalError} `adapter.nested_transaction_unsupported` - 이미 트랜잭션 진행 중.
69
+ * @throws {MegaValidationError} `adapter.invalid_option` - 'serializable' 외 isolation 값.
70
+ */
71
+ withTransaction<T>(fn: (db: import("better-sqlite3").Database) => Promise<T> | T, opts?: {
72
+ isolation?: "serializable";
73
+ }): Promise<T>;
74
+ #private;
75
+ }
76
+ export type SqliteConfig = {
77
+ /**
78
+ * - 'sqlite' (매니저가 사용 — 어댑터는 무시).
79
+ */
80
+ driver?: string;
81
+ /**
82
+ * - DB 파일 경로 또는 ':memory:' (필수).
83
+ */
84
+ filename: string;
85
+ /**
86
+ * - 읽기 전용 연결.
87
+ */
88
+ readonly?: boolean;
89
+ /**
90
+ * - 파일이 없으면 connect 시 throw.
91
+ */
92
+ fileMustExist?: boolean;
93
+ /**
94
+ * - 잠긴 DB 대기 ms (SQLITE_BUSY 전, 기본 5000).
95
+ */
96
+ timeout?: number;
97
+ /**
98
+ * - true 면 connect 후 `journal_mode = WAL` 적용.
99
+ */
100
+ wal?: boolean;
101
+ /**
102
+ * - connect 후 적용할 추가 PRAGMA 맵.
103
+ */
104
+ pragmas?: Record<string, string | number>;
105
+ };
106
+ import { MegaDbAdapter } from './mega-db-adapter.js';
@@ -0,0 +1,24 @@
1
+ /**
2
+ * 로그인(세션 `userId` 존재)을 요구하는 `before` 가드. 통과 시 `req.user`(`{ id, roles }`)를 채운다.
3
+ * 실패 시 401 `auth.required`.
4
+ *
5
+ * @param {import('fastify').FastifyRequest} req
6
+ * @param {import('fastify').FastifyReply} _reply
7
+ * @param {Record<string, any>} [ctx] - 글로벌 미들웨어 경로에서만 주입(라우트 before 에선 undefined).
8
+ * @returns {Promise<void>}
9
+ * @throws {MegaAuthError} 세션·userId 부재 시 401.
10
+ * @example
11
+ * router.http.get('/api/me', MeController.show, { before: [requireAuth] })
12
+ */
13
+ export function requireAuth(req: import("fastify").FastifyRequest, _reply: import("fastify").FastifyReply, ctx?: Record<string, any>): Promise<void>;
14
+ /**
15
+ * 지정한 역할 중 하나 이상을 가진 로그인 사용자를 요구하는 `before` 가드 팩토리. 먼저 인증을
16
+ * 확정(`requireAuth` 동일 로직)한 뒤 역할 교집합을 검사한다.
17
+ *
18
+ * @param {...string} roles - 허용 역할 목록(하나라도 보유 시 통과). 최소 1개 필수.
19
+ * @returns {(req: import('fastify').FastifyRequest, reply: import('fastify').FastifyReply, ctx?: Record<string, any>) => Promise<void>}
20
+ * @throws {TypeError} 역할 인자가 비었거나 문자열이 아니면(설정 실수 fail-fast).
21
+ * @example
22
+ * router.http.post('/api/users', UsersController.create, { before: [requireRole('admin')] })
23
+ */
24
+ export function requireRole(...roles: string[]): (req: import("fastify").FastifyRequest, reply: import("fastify").FastifyReply, ctx?: Record<string, any>) => Promise<void>;
@@ -0,0 +1,37 @@
1
+ /**
2
+ * 앱 컨텍스트를 로딩하고 REPL 을 연다.
3
+ * @param {string} projectRoot
4
+ * @param {object} [deps]
5
+ * @param {{ debug?: Function, info?: Function, warn?: Function }} [deps.logger]
6
+ * @param {() => { context: Record<string, any>, on?: (event: string, listener: (...args: any[]) => void) => void }} [deps.replFactory] -
7
+ * 주입용(테스트). context 객체를 가진 REPL-유사 객체를 반환해야 한다('exit' 이벤트용 `on` 은 선택).
8
+ * @param {(msg: string) => void} [deps.out]
9
+ * @param {() => (Promise<void> | void)} [deps.shutdown] - 주입용(테스트). REPL 종료 시 호출하는 graceful
10
+ * shutdown 트리거. 기본 {@link MegaShutdown.now}(등록 hook 실행 후 process.exit).
11
+ * @param {(opts: { signals?: string[], globalErrorHandlers?: boolean }) => void} [deps.setupSignals] - 주입용(테스트). 시그널 핸들러 등록.
12
+ * 기본 {@link MegaShutdown.setupSignals}.
13
+ * @returns {Promise<{ ctx: Record<string, any>, config: object, server: { context: Record<string, any> } }>}
14
+ */
15
+ export function startConsole(projectRoot: string, { logger, replFactory, out, shutdown, setupSignals }?: {
16
+ logger?: {
17
+ debug?: Function;
18
+ info?: Function;
19
+ warn?: Function;
20
+ };
21
+ replFactory?: () => {
22
+ context: Record<string, any>;
23
+ on?: (event: string, listener: (...args: any[]) => void) => void;
24
+ };
25
+ out?: (msg: string) => void;
26
+ shutdown?: () => (Promise<void> | void);
27
+ setupSignals?: (opts: {
28
+ signals?: string[];
29
+ globalErrorHandlers?: boolean;
30
+ }) => void;
31
+ }): Promise<{
32
+ ctx: Record<string, any>;
33
+ config: object;
34
+ server: {
35
+ context: Record<string, any>;
36
+ };
37
+ }>;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * 프로젝트를 스캐폴드한다(순수 — prompts 없이 opts 로만 동작, 테스트 가능).
3
+ * @param {string} targetDir - 프로젝트 루트 절대/상대 경로.
4
+ * @param {object} [opts]
5
+ * @param {string} [opts.name] - 프로젝트 이름(기본: targetDir 의 마지막 세그먼트).
6
+ * @param {boolean} [opts.force] - 기존 파일 덮어쓰기(기본 false — 건너뜀).
7
+ * @returns {{ root: string, written: string[], skipped: string[] }}
8
+ */
9
+ export function scaffoldProject(targetDir: string, { name, force }?: {
10
+ name?: string;
11
+ force?: boolean;
12
+ }): {
13
+ root: string;
14
+ written: string[];
15
+ skipped: string[];
16
+ };
@@ -0,0 +1,36 @@
1
+ /**
2
+ * 프로젝트의 앱별 라우트를 수집한다.
3
+ * @param {string} projectRoot
4
+ * @returns {Promise<Array<{ app: string, hosts: string[], routes: Array<{ method: string, path: string, file: string }> }>>}
5
+ */
6
+ export function collectRoutes(projectRoot: string): Promise<Array<{
7
+ app: string;
8
+ hosts: string[];
9
+ routes: Array<{
10
+ method: string;
11
+ path: string;
12
+ file: string;
13
+ }>;
14
+ }>>;
15
+ /**
16
+ * 수집한 라우트를 사람이 읽는 트리 문자열로 포맷.
17
+ * @param {Array<{ app: string, hosts: string[], routes: Array<{ method: string, path: string }> }>} data
18
+ * @returns {string}
19
+ */
20
+ export function formatRoutes(data: Array<{
21
+ app: string;
22
+ hosts: string[];
23
+ routes: Array<{
24
+ method: string;
25
+ path: string;
26
+ }>;
27
+ }>): string;
28
+ /**
29
+ * `mega routes` 명령 본체.
30
+ * @param {string} projectRoot
31
+ * @param {{ out?: (msg: string) => void }} [deps]
32
+ * @returns {Promise<number>} exit code.
33
+ */
34
+ export function runRoutesCommand(projectRoot: string, { out }?: {
35
+ out?: (msg: string) => void;
36
+ }): Promise<number>;
@@ -0,0 +1,78 @@
1
+ /**
2
+ * scaffold/dev 명령 5종을 commander program 에 등록한다 — 명령 정의의 단일 정본(ADR-195).
3
+ * action 은 `process.exit` 를 부르지 않고 `setExit(code)` 로 종료 코드를 보고한다(runCli 계약).
4
+ *
5
+ * @param {import('commander').Command} program - 등록 대상 program.
6
+ * @param {object} deps
7
+ * @param {(msg: string) => void} deps.out
8
+ * @param {string} deps.projectRoot - 이미 `--root` 해석된 기준 디렉토리.
9
+ * @param {{ debug?: Function, info?: Function, warn?: Function }} [deps.logger]
10
+ * @param {(kind: string) => Promise<{ dir: string, files: Array<{ path: string, template: string }> } | undefined>} [deps.resolvePluginGenerator] -
11
+ * 빌트인이 아닌 kind 의 플러그인 scaffold manifest 조회(`mega.scaffold.register`, 03-api-spec §11).
12
+ * 호출측(runCli)이 config 로드 + 플러그인 install 을 감싼 함수를 주입한다 — 본 모듈이 cli/index.js 를
13
+ * import 하면 순환이라 주입식으로 푼다. 미주입/미발견이면 unknown kind 에러.
14
+ * @param {(code: number) => void} deps.setExit - 명령 종료 코드 보고 콜백.
15
+ * @returns {void}
16
+ */
17
+ export function registerScaffoldCommands(program: import("commander").Command, { out, projectRoot, logger, resolvePluginGenerator, setExit }: {
18
+ out: (msg: string) => void;
19
+ projectRoot: string;
20
+ logger?: {
21
+ debug?: Function;
22
+ info?: Function;
23
+ warn?: Function;
24
+ };
25
+ resolvePluginGenerator?: (kind: string) => Promise<{
26
+ dir: string;
27
+ files: Array<{
28
+ path: string;
29
+ template: string;
30
+ }>;
31
+ } | undefined>;
32
+ setExit: (code: number) => void;
33
+ }): void;
34
+ /**
35
+ * commander 의 exitOverride 예외를 exit code 로 환산한다 — help/version 출력은 정상 종료(0),
36
+ * CommanderError 는 자체 exitCode, 그 외 에러는 메시지 출력 후 1. commander 가 아닌 에러를 그대로
37
+ * 삼키지 않도록 `rethrowUnknown` 옵션을 둔다(runCli 가 부팅·config 에러를 bin 으로 전파할 때 사용).
38
+ *
39
+ * @param {unknown} e - parseAsync 가 던진 예외.
40
+ * @param {(msg: string) => void} err
41
+ * @param {{ rethrowUnknown?: boolean }} [opts] - true 면 CommanderError 가 아닌 예외를 재throw.
42
+ * @returns {number} exit code.
43
+ */
44
+ export function commanderErrorToExitCode(e: unknown, err: (msg: string) => void, { rethrowUnknown }?: {
45
+ rethrowUnknown?: boolean;
46
+ }): number;
47
+ /**
48
+ * scaffold/dev 명령만 담은 독립 program 으로 실행한다(하위호환 진입점 — 단위 테스트 경계 유지).
49
+ * commander 로 파싱하되 `process.exit` 를 부르지 않고 exit code 를 반환한다(runCli 계약 정합).
50
+ *
51
+ * @param {string[]} argv - `process.argv.slice(2)` (첫 토큰 = 명령).
52
+ * @param {object} deps
53
+ * @param {(msg: string) => void} deps.out
54
+ * @param {(msg: string) => void} deps.err
55
+ * @param {string} deps.projectRoot - 이미 `--root` 해석된 기준 디렉토리.
56
+ * @param {{ debug?: Function, info?: Function, warn?: Function }} [deps.logger]
57
+ * @param {(kind: string) => Promise<{ dir: string, files: Array<{ path: string, template: string }> } | undefined>} [deps.resolvePluginGenerator]
58
+ * @returns {Promise<number>} exit code.
59
+ */
60
+ export function runScaffoldCommand(argv: string[], { out, err, projectRoot, logger, resolvePluginGenerator }: {
61
+ out: (msg: string) => void;
62
+ err: (msg: string) => void;
63
+ projectRoot: string;
64
+ logger?: {
65
+ debug?: Function;
66
+ info?: Function;
67
+ warn?: Function;
68
+ };
69
+ resolvePluginGenerator?: (kind: string) => Promise<{
70
+ dir: string;
71
+ files: Array<{
72
+ path: string;
73
+ template: string;
74
+ }>;
75
+ } | undefined>;
76
+ }): Promise<number>;
77
+ /** scaffold/dev 명령 이름(별칭 포함). */
78
+ export const SCAFFOLD_COMMANDS: Set<string>;
@@ -0,0 +1,14 @@
1
+ /**
2
+ * vitest 를 자식 프로세스로 실행한다.
3
+ * @param {string} projectRoot - 실행 cwd.
4
+ * @param {string[]} [args] - vitest 에 넘길 추가 인자.
5
+ * @param {object} [deps]
6
+ * @param {typeof nodeSpawn} [deps.spawn] - 주입용(테스트).
7
+ * @param {(msg: string) => void} [deps.out]
8
+ * @returns {Promise<number>} vitest exit code.
9
+ */
10
+ export function runTestCommand(projectRoot: string, args?: string[], { spawn, out }?: {
11
+ spawn?: typeof nodeSpawn;
12
+ out?: (msg: string) => void;
13
+ }): Promise<number>;
14
+ import { spawn as nodeSpawn } from 'node:child_process';