mega-framework 0.1.5 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/mega-ws-hub.js +2 -2
- package/package.json +32 -8
- package/sample/crud/.env +156 -8
- package/sample/crud/.env.example +153 -28
- package/sample/crud/.mega/journal/history/20260612092543-create-users.json +261 -0
- package/sample/crud/.mega/journal/snapshot.json +261 -0
- package/sample/crud/apps/main/controllers/auth-controller.js +22 -14
- package/sample/crud/apps/main/controllers/web-controller.js +7 -5
- package/sample/crud/apps/main/migrations/20260606000001-create-users.js +91 -13
- package/sample/crud/apps/main/migrations/20260606000002-create-boards.js +165 -0
- package/sample/crud/apps/main/migrations/20260606000003-create-logs.js +107 -0
- package/sample/crud/apps/main/models/log-partition-model.js +105 -0
- package/sample/crud/apps/main/models/note-model.js +79 -0
- package/sample/crud/apps/main/models/user-level-model.js +24 -0
- package/sample/crud/apps/main/models/user-model.js +146 -0
- package/sample/crud/apps/main/models/user-type-model.js +21 -0
- package/sample/crud/apps/main/models/wallet-model.js +24 -0
- package/sample/crud/apps/main/routes/users.js +55 -10
- package/sample/crud/apps/main/schedules/log-partition-schedule.js +33 -0
- package/sample/crud/apps/main/services/auth-service.js +39 -24
- package/sample/crud/apps/main/services/log-partition-service.js +101 -0
- package/sample/crud/apps/main/services/note-service.js +6 -6
- package/sample/crud/apps/main/services/redis-demo-service.js +3 -3
- package/sample/crud/apps/main/services/user-service.js +62 -21
- package/sample/crud/apps/main/views/auth/login.ejs +6 -6
- package/sample/crud/apps/main/views/auth/register.ejs +46 -5
- package/sample/crud/apps/main/views/users/edit.ejs +42 -5
- package/sample/crud/apps/main/views/users/list.ejs +6 -2
- package/sample/crud/apps/main/views/users/new.ejs +56 -4
- package/sample/crud/docs/log_partition_design.mm.md +23 -0
- package/sample/crud/mega.config.js +63 -3
- package/sample/crud/package.json +3 -3
- package/sample/crud/scripts/start-ws-hub.sh +2 -2
- package/sample/simple/package.json +2 -2
- package/src/adapters/adapter-manager.js +2 -1
- package/src/adapters/adapter-options.js +30 -0
- package/src/adapters/maria-adapter.js +26 -3
- package/src/adapters/mega-db-adapter.js +7 -1
- package/src/adapters/mongo-adapter.js +19 -1
- package/src/adapters/postgres-adapter.js +25 -2
- package/src/adapters/sqlite-adapter.js +20 -1
- package/src/cli/commands/new.js +13 -3
- package/src/cli/commands/scaffold.js +137 -33
- package/src/cli/generators/index.js +82 -2
- package/src/cli/index.js +478 -104
- package/src/core/ajv-mapper.js +27 -2
- package/src/core/boot.js +485 -237
- package/src/core/cluster-metrics.js +13 -4
- package/src/core/config-validator.js +25 -0
- package/src/core/ctx-builder.js +6 -2
- package/src/core/envelope.js +112 -12
- package/src/core/hub-link.js +65 -4
- package/src/core/i18n.js +11 -1
- package/src/core/index.js +6 -2
- package/src/core/mega-app.js +223 -481
- package/src/core/mega-cluster.js +54 -13
- package/src/core/mega-server.js +40 -9
- package/src/core/migration/dialect-registry.js +107 -0
- package/src/core/migration/dialects/README.md +62 -0
- package/src/core/migration/dialects/maria.js +496 -0
- package/src/core/migration/dialects/mongo.js +824 -0
- package/src/core/migration/dialects/postgres.js +563 -0
- package/src/core/migration/dialects/sqlite.js +476 -0
- package/src/core/migration/differ.js +456 -0
- package/src/core/migration/generate.js +508 -0
- package/src/core/migration/journal.js +167 -0
- package/src/core/migration/model-scan.js +84 -0
- package/src/core/migration/mongo-migration-db.js +97 -0
- package/src/core/migration/schema-builder.js +400 -0
- package/src/core/migration/schema-validator.js +315 -0
- package/src/core/migration-lock.js +205 -0
- package/src/core/migration-runner.js +166 -38
- package/src/core/multipart.js +28 -5
- package/src/core/pipeline.js +129 -0
- package/src/core/router.js +70 -65
- package/src/core/scope-registry.js +0 -1
- package/src/core/security.js +67 -9
- package/src/core/workers-manager.js +12 -1
- package/src/core/ws-cluster.js +10 -3
- package/src/core/ws-message.js +48 -4
- package/src/core/ws-presence.js +624 -0
- package/src/core/ws-roster.js +4 -1
- package/src/core/ws-upgrade.js +118 -12
- package/src/index.js +1 -1
- package/src/lib/hub-protocol.js +29 -0
- package/src/lib/mega-health.js +25 -4
- package/src/lib/mega-job-queue.js +98 -21
- package/src/lib/mega-job.js +29 -0
- package/src/lib/mega-logger.js +1 -1
- package/src/lib/mega-metrics.js +3 -12
- package/src/lib/mega-plugin.js +34 -3
- package/src/lib/mega-schedule.js +40 -22
- package/src/lib/mega-shutdown.js +162 -49
- package/src/lib/mega-tracing.js +66 -19
- package/src/lib/mega-worker.js +5 -1
- package/src/lib/otel-resource.js +36 -0
- package/src/{cli → lib}/ws-hub.js +51 -8
- package/src/models/crud-sql-builder.js +133 -0
- package/src/models/mega-model.js +82 -2
- package/src/models/model-crud.js +483 -0
- package/src/models/mongo-crud.js +285 -0
- package/templates/model/code-mongo.tpl +35 -0
- package/templates/model/code.tpl +15 -1
- package/templates/model/test-mongo.tpl +38 -0
- package/templates/model/test.tpl +4 -0
- package/types/adapters/adapter-manager.d.ts +95 -0
- package/types/adapters/adapter-options.d.ts +91 -0
- package/types/adapters/file-adapter.d.ts +94 -0
- package/types/adapters/file-session-adapter.d.ts +101 -0
- package/types/adapters/index.d.ts +20 -0
- package/types/adapters/maria-adapter.d.ts +115 -0
- package/types/adapters/mega-adapter.d.ts +215 -0
- package/types/adapters/mega-bus-adapter.d.ts +45 -0
- package/types/adapters/mega-cache-adapter.d.ts +47 -0
- package/types/adapters/mega-db-adapter.d.ts +47 -0
- package/types/adapters/mega-lock-adapter.d.ts +62 -0
- package/types/adapters/mega-log-sink-adapter.d.ts +15 -0
- package/types/adapters/mega-session-adapter.d.ts +32 -0
- package/types/adapters/mongo-adapter.d.ts +139 -0
- package/types/adapters/nats-adapter.d.ts +108 -0
- package/types/adapters/postgres-adapter.d.ts +139 -0
- package/types/adapters/redis-adapter.d.ts +70 -0
- package/types/adapters/redis-session-adapter.d.ts +82 -0
- package/types/adapters/redlock-adapter.d.ts +149 -0
- package/types/adapters/registry.d.ts +46 -0
- package/types/adapters/sqlite-adapter.d.ts +106 -0
- package/types/auth/index.d.ts +24 -0
- package/types/cli/commands/console-cmd.d.ts +37 -0
- package/types/cli/commands/new.d.ts +16 -0
- package/types/cli/commands/routes.d.ts +36 -0
- package/types/cli/commands/scaffold.d.ts +78 -0
- package/types/cli/commands/test-cmd.d.ts +14 -0
- package/types/cli/generators/index.d.ts +112 -0
- package/types/cli/index.d.ts +249 -0
- package/types/cli/template-engine.d.ts +40 -0
- package/types/core/ajv-mapper.d.ts +27 -0
- package/types/core/boot.d.ts +233 -0
- package/types/core/cluster-metrics.d.ts +52 -0
- package/types/core/config-loader.d.ts +13 -0
- package/types/core/config-validator.d.ts +30 -0
- package/types/core/ctx-builder.d.ts +80 -0
- package/types/core/envelope.d.ts +79 -0
- package/types/core/error-mapper.d.ts +17 -0
- package/types/core/formbody.d.ts +41 -0
- package/types/core/hub-link.d.ts +264 -0
- package/types/core/i18n.d.ts +178 -0
- package/types/core/index.d.ts +28 -0
- package/types/core/mega-app.d.ts +529 -0
- package/types/core/mega-cluster.d.ts +104 -0
- package/types/core/mega-server.d.ts +91 -0
- package/types/core/mega-service.d.ts +31 -0
- package/types/core/migration/dialect-registry.d.ts +22 -0
- package/types/core/migration/dialects/maria.d.ts +99 -0
- package/types/core/migration/dialects/mongo.d.ts +89 -0
- package/types/core/migration/dialects/postgres.d.ts +117 -0
- package/types/core/migration/dialects/sqlite.d.ts +111 -0
- package/types/core/migration/differ.d.ts +47 -0
- package/types/core/migration/generate.d.ts +56 -0
- package/types/core/migration/journal.d.ts +52 -0
- package/types/core/migration/model-scan.d.ts +19 -0
- package/types/core/migration/mongo-migration-db.d.ts +7 -0
- package/types/core/migration/schema-builder.d.ts +197 -0
- package/types/core/migration/schema-validator.d.ts +20 -0
- package/types/core/migration-lock.d.ts +33 -0
- package/types/core/migration-runner.d.ts +101 -0
- package/types/core/multipart.d.ts +86 -0
- package/types/core/openapi.d.ts +62 -0
- package/types/core/pipeline.d.ts +92 -0
- package/types/core/router.d.ts +159 -0
- package/types/core/routes-loader.d.ts +21 -0
- package/types/core/scope-registry.d.ts +14 -0
- package/types/core/security.d.ts +77 -0
- package/types/core/services-loader.d.ts +27 -0
- package/types/core/session-cleanup-schedule.d.ts +19 -0
- package/types/core/session-store.d.ts +18 -0
- package/types/core/session.d.ts +77 -0
- package/types/core/static-assets.d.ts +73 -0
- package/types/core/template.d.ts +106 -0
- package/types/core/workers-manager.d.ts +79 -0
- package/types/core/ws-cluster.d.ts +208 -0
- package/types/core/ws-compression.d.ts +112 -0
- package/types/core/ws-controller.d.ts +65 -0
- package/types/core/ws-message.d.ts +106 -0
- package/types/core/ws-presence.d.ts +273 -0
- package/types/core/ws-roster.d.ts +96 -0
- package/types/core/ws-upgrade.d.ts +231 -0
- package/types/errors/config-error.d.ts +10 -0
- package/types/errors/http-errors.d.ts +120 -0
- package/types/errors/index.d.ts +3 -0
- package/types/errors/mega-error.d.ts +32 -0
- package/types/index.d.ts +39 -0
- package/types/lib/asp/config.d.ts +49 -0
- package/types/lib/asp/crypto.d.ts +43 -0
- package/types/lib/asp/errors.d.ts +30 -0
- package/types/lib/asp/nonce-cache.d.ts +52 -0
- package/types/lib/asp/plugin.d.ts +30 -0
- package/types/lib/asp/ws-terminator.d.ts +45 -0
- package/types/lib/env-mapper.d.ts +14 -0
- package/types/lib/hub-protocol.d.ts +106 -0
- package/types/lib/index.d.ts +22 -0
- package/types/lib/logger/telegram-core.d.ts +104 -0
- package/types/lib/logger/telegram-transport.d.ts +45 -0
- package/types/lib/mega-brute-force.d.ts +66 -0
- package/types/lib/mega-circuit-breaker.d.ts +241 -0
- package/types/lib/mega-cron.d.ts +66 -0
- package/types/lib/mega-hash.d.ts +32 -0
- package/types/lib/mega-health.d.ts +41 -0
- package/types/lib/mega-job-queue.d.ts +176 -0
- package/types/lib/mega-job-worker.d.ts +130 -0
- package/types/lib/mega-job.d.ts +138 -0
- package/types/lib/mega-logger.d.ts +45 -0
- package/types/lib/mega-metrics.d.ts +285 -0
- package/types/lib/mega-plugin.d.ts +245 -0
- package/types/lib/mega-retry.d.ts +85 -0
- package/types/lib/mega-schedule.d.ts +260 -0
- package/types/lib/mega-shutdown.d.ts +135 -0
- package/types/lib/mega-tracing.d.ts +224 -0
- package/types/lib/mega-worker.d.ts +127 -0
- package/types/lib/otel-resource.d.ts +16 -0
- package/types/lib/worker-runner/process-entry.d.ts +1 -0
- package/types/lib/worker-runner/task-dispatch.d.ts +28 -0
- package/types/lib/worker-runner/thread-entry.d.ts +1 -0
- package/types/lib/ws-hub.d.ts +234 -0
- package/types/models/crud-sql-builder.d.ts +48 -0
- package/types/models/index.d.ts +1 -0
- package/types/models/mega-model.d.ts +138 -0
- package/types/models/model-crud.d.ts +82 -0
- package/types/models/mongo-crud.d.ts +59 -0
- package/types/test/index.d.ts +84 -0
- package/.env +0 -127
- package/sample/crud/apps/main/migrations/20260606000002-add-auth-to-users.js +0 -30
- package/sample/crud/apps/main/models/note.js +0 -71
- package/sample/crud/apps/main/models/user.js +0 -86
- package/sample/crud/package-lock.json +0 -5665
- package/sample/crud/yarn.lock +0 -2142
- package/sample/simple/package-lock.json +0 -1851
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {object} FileConfig
|
|
3
|
+
* @property {string} [driver] - 'file' (매니저가 사용 — 어댑터는 무시).
|
|
4
|
+
* @property {string} [basePath] - 캐시 파일 저장 디렉토리 (필수).
|
|
5
|
+
* @property {string} [dir] - `basePath` 의 별칭 (ADR-082 정합, 하위 호환).
|
|
6
|
+
* @property {{ serializer?: 'json' | 'raw', extension?: string }} [options]
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* @typedef {object} CacheEnvelope - 디스크에 저장되는 단일 파일 포맷.
|
|
10
|
+
* @property {number} v - 스키마 버전.
|
|
11
|
+
* @property {string} key - 원본 캐시 key (디버깅용 — 파일명은 해시라 역추적 불가).
|
|
12
|
+
* @property {any} value - 저장 값(serializer='raw' 면 문자열).
|
|
13
|
+
* @property {number | null} expiresAt - 만료 epoch ms (무한이면 null).
|
|
14
|
+
*/
|
|
15
|
+
export class MegaFileAdapter extends MegaCacheAdapter {
|
|
16
|
+
/**
|
|
17
|
+
* @param {FileConfig} [config] - services.caches.<key> 설정.
|
|
18
|
+
* @throws {MegaValidationError} `adapter.basepath_required` - basePath/dir 누락.
|
|
19
|
+
* @throws {MegaValidationError} `adapter.invalid_option` - 옵션 타입/미지원 키 오류.
|
|
20
|
+
*/
|
|
21
|
+
constructor(config?: FileConfig);
|
|
22
|
+
/**
|
|
23
|
+
* raw "디렉토리 핸들" (ADR-009). 파일 어댑터는 native driver 가 없어 basePath 정보를 노출한다.
|
|
24
|
+
* @protected
|
|
25
|
+
* @returns {{ basePath: string }}
|
|
26
|
+
*/
|
|
27
|
+
protected _native(): {
|
|
28
|
+
basePath: string;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* 헬스 체크 — basePath 에 probe 파일을 write→read→unlink 해 실제 읽기/쓰기 가능 확인
|
|
32
|
+
* (베이스 디폴트는 상태만 반영). 실패는 throw 없이 `ok:false` + 사유(베이스 계약).
|
|
33
|
+
*
|
|
34
|
+
* @returns {Promise<{ ok: boolean, driver: 'file', state: string, basePath?: string, error?: string }>}
|
|
35
|
+
*/
|
|
36
|
+
healthCheck(): Promise<{
|
|
37
|
+
ok: boolean;
|
|
38
|
+
driver: "file";
|
|
39
|
+
state: string;
|
|
40
|
+
basePath?: string;
|
|
41
|
+
error?: string;
|
|
42
|
+
}>;
|
|
43
|
+
/**
|
|
44
|
+
* 누적 통계 + file 특화(basePath/serializer/extension).
|
|
45
|
+
* @returns {ReturnType<import('./mega-adapter.js').MegaAdapter['getStats']> & { driver: string, basePath: string, serializer: string, extension: string }}
|
|
46
|
+
*/
|
|
47
|
+
getStats(): ReturnType<import("./mega-adapter.js").MegaAdapter["getStats"]> & {
|
|
48
|
+
driver: string;
|
|
49
|
+
basePath: string;
|
|
50
|
+
serializer: string;
|
|
51
|
+
extension: string;
|
|
52
|
+
};
|
|
53
|
+
#private;
|
|
54
|
+
}
|
|
55
|
+
export type FileConfig = {
|
|
56
|
+
/**
|
|
57
|
+
* - 'file' (매니저가 사용 — 어댑터는 무시).
|
|
58
|
+
*/
|
|
59
|
+
driver?: string;
|
|
60
|
+
/**
|
|
61
|
+
* - 캐시 파일 저장 디렉토리 (필수).
|
|
62
|
+
*/
|
|
63
|
+
basePath?: string;
|
|
64
|
+
/**
|
|
65
|
+
* - `basePath` 의 별칭 (ADR-082 정합, 하위 호환).
|
|
66
|
+
*/
|
|
67
|
+
dir?: string;
|
|
68
|
+
options?: {
|
|
69
|
+
serializer?: "json" | "raw";
|
|
70
|
+
extension?: string;
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* - 디스크에 저장되는 단일 파일 포맷.
|
|
75
|
+
*/
|
|
76
|
+
export type CacheEnvelope = {
|
|
77
|
+
/**
|
|
78
|
+
* - 스키마 버전.
|
|
79
|
+
*/
|
|
80
|
+
v: number;
|
|
81
|
+
/**
|
|
82
|
+
* - 원본 캐시 key (디버깅용 — 파일명은 해시라 역추적 불가).
|
|
83
|
+
*/
|
|
84
|
+
key: string;
|
|
85
|
+
/**
|
|
86
|
+
* - 저장 값(serializer='raw' 면 문자열).
|
|
87
|
+
*/
|
|
88
|
+
value: any;
|
|
89
|
+
/**
|
|
90
|
+
* - 만료 epoch ms (무한이면 null).
|
|
91
|
+
*/
|
|
92
|
+
expiresAt: number | null;
|
|
93
|
+
};
|
|
94
|
+
import { MegaCacheAdapter } from './mega-cache-adapter.js';
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {object} FileSessionConfig
|
|
3
|
+
* @property {string} [driver] - 'file' (팩토리가 사용 — 어댑터는 무시).
|
|
4
|
+
* @property {string} [basePath] - 세션 파일 저장 디렉토리 (필수).
|
|
5
|
+
* @property {string} [dir] - `basePath` 의 별칭 (하위 호환).
|
|
6
|
+
* @property {number} [ttlMs] - save() 가 적용할 기본 TTL(ms). 미지정 시 24시간.
|
|
7
|
+
* @property {number} [cleanupIntervalMs] - 내부 cleanup 타이머 주기(ms). 미지정/0 이면 타이머 없음(단일 dev 편의).
|
|
8
|
+
* @property {string} [extension] - 파일 확장자 (기본 '.json').
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* @typedef {object} SessionEnvelope - 디스크에 저장되는 단일 파일 포맷.
|
|
12
|
+
* @property {number} v - 스키마 버전.
|
|
13
|
+
* @property {string} sid - 원본 세션 id(ULID — 파일명은 해시라 역추적 불가).
|
|
14
|
+
* @property {object} data - 세션 레코드.
|
|
15
|
+
* @property {number | null} expiresAt - 만료 epoch ms (무한이면 null).
|
|
16
|
+
*/
|
|
17
|
+
export class MegaFileSessionAdapter extends MegaSessionAdapter {
|
|
18
|
+
/**
|
|
19
|
+
* @param {FileSessionConfig} [config]
|
|
20
|
+
* @throws {MegaValidationError} `session.basepath_required` - basePath/dir 누락.
|
|
21
|
+
* @throws {MegaValidationError} `session.invalid_option` - 옵션 타입 오류.
|
|
22
|
+
*/
|
|
23
|
+
constructor(config?: FileSessionConfig);
|
|
24
|
+
/**
|
|
25
|
+
* raw "디렉토리 핸들" (ADR-009).
|
|
26
|
+
* @protected
|
|
27
|
+
* @returns {{ basePath: string }}
|
|
28
|
+
*/
|
|
29
|
+
protected _native(): {
|
|
30
|
+
basePath: string;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* 헬스 체크 — basePath 에 probe write→read→unlink 로 실제 읽기/쓰기 가능 확인.
|
|
34
|
+
* @returns {Promise<{ ok: boolean, driver: 'file', state: string, basePath?: string, error?: string }>}
|
|
35
|
+
*/
|
|
36
|
+
healthCheck(): Promise<{
|
|
37
|
+
ok: boolean;
|
|
38
|
+
driver: "file";
|
|
39
|
+
state: string;
|
|
40
|
+
basePath?: string;
|
|
41
|
+
error?: string;
|
|
42
|
+
}>;
|
|
43
|
+
/**
|
|
44
|
+
* 누적 통계 + file 세션 특화.
|
|
45
|
+
* @returns {ReturnType<import('./mega-adapter.js').MegaAdapter['getStats']> & { driver: string, basePath: string, ttlMs: number }}
|
|
46
|
+
*/
|
|
47
|
+
getStats(): ReturnType<import("./mega-adapter.js").MegaAdapter["getStats"]> & {
|
|
48
|
+
driver: string;
|
|
49
|
+
basePath: string;
|
|
50
|
+
ttlMs: number;
|
|
51
|
+
};
|
|
52
|
+
#private;
|
|
53
|
+
}
|
|
54
|
+
export type FileSessionConfig = {
|
|
55
|
+
/**
|
|
56
|
+
* - 'file' (팩토리가 사용 — 어댑터는 무시).
|
|
57
|
+
*/
|
|
58
|
+
driver?: string;
|
|
59
|
+
/**
|
|
60
|
+
* - 세션 파일 저장 디렉토리 (필수).
|
|
61
|
+
*/
|
|
62
|
+
basePath?: string;
|
|
63
|
+
/**
|
|
64
|
+
* - `basePath` 의 별칭 (하위 호환).
|
|
65
|
+
*/
|
|
66
|
+
dir?: string;
|
|
67
|
+
/**
|
|
68
|
+
* - save() 가 적용할 기본 TTL(ms). 미지정 시 24시간.
|
|
69
|
+
*/
|
|
70
|
+
ttlMs?: number;
|
|
71
|
+
/**
|
|
72
|
+
* - 내부 cleanup 타이머 주기(ms). 미지정/0 이면 타이머 없음(단일 dev 편의).
|
|
73
|
+
*/
|
|
74
|
+
cleanupIntervalMs?: number;
|
|
75
|
+
/**
|
|
76
|
+
* - 파일 확장자 (기본 '.json').
|
|
77
|
+
*/
|
|
78
|
+
extension?: string;
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* - 디스크에 저장되는 단일 파일 포맷.
|
|
82
|
+
*/
|
|
83
|
+
export type SessionEnvelope = {
|
|
84
|
+
/**
|
|
85
|
+
* - 스키마 버전.
|
|
86
|
+
*/
|
|
87
|
+
v: number;
|
|
88
|
+
/**
|
|
89
|
+
* - 원본 세션 id(ULID — 파일명은 해시라 역추적 불가).
|
|
90
|
+
*/
|
|
91
|
+
sid: string;
|
|
92
|
+
/**
|
|
93
|
+
* - 세션 레코드.
|
|
94
|
+
*/
|
|
95
|
+
data: object;
|
|
96
|
+
/**
|
|
97
|
+
* - 만료 epoch ms (무한이면 null).
|
|
98
|
+
*/
|
|
99
|
+
expiresAt: number | null;
|
|
100
|
+
};
|
|
101
|
+
import { MegaSessionAdapter } from './mega-session-adapter.js';
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export { MegaAdapter } from "./mega-adapter.js";
|
|
2
|
+
export { MegaDbAdapter } from "./mega-db-adapter.js";
|
|
3
|
+
export { MegaCacheAdapter } from "./mega-cache-adapter.js";
|
|
4
|
+
export { MegaBusAdapter } from "./mega-bus-adapter.js";
|
|
5
|
+
export { MegaLockAdapter } from "./mega-lock-adapter.js";
|
|
6
|
+
export { MegaLogSinkAdapter } from "./mega-log-sink-adapter.js";
|
|
7
|
+
export { MegaSessionAdapter } from "./mega-session-adapter.js";
|
|
8
|
+
export { MegaSqliteAdapter } from "./sqlite-adapter.js";
|
|
9
|
+
export { MegaPostgresAdapter } from "./postgres-adapter.js";
|
|
10
|
+
export { MegaMariaAdapter } from "./maria-adapter.js";
|
|
11
|
+
export { MegaMongoAdapter } from "./mongo-adapter.js";
|
|
12
|
+
export { MegaRedisAdapter } from "./redis-adapter.js";
|
|
13
|
+
export { MegaFileAdapter } from "./file-adapter.js";
|
|
14
|
+
export { MegaNatsAdapter } from "./nats-adapter.js";
|
|
15
|
+
export { MegaRedlockAdapter } from "./redlock-adapter.js";
|
|
16
|
+
export { MegaFileSessionAdapter } from "./file-session-adapter.js";
|
|
17
|
+
export { MegaRedisSessionAdapter } from "./redis-session-adapter.js";
|
|
18
|
+
export * as MegaAdapterRegistry from "./registry.js";
|
|
19
|
+
export { BUILTIN_DRIVERS } from "./registry.js";
|
|
20
|
+
export * as MegaAdapterManager from "./adapter-manager.js";
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
export class MegaMariaAdapter extends MegaDbAdapter {
|
|
2
|
+
/**
|
|
3
|
+
* @param {MariaConfig} [config] - services.databases.<key> 설정.
|
|
4
|
+
* @throws {MegaValidationError} `adapter.connection_required` - url·discrete 둘 다 없음.
|
|
5
|
+
* @throws {MegaValidationError} `adapter.connection_conflict` - url + discrete 동시 지정.
|
|
6
|
+
* @throws {MegaValidationError} `adapter.invalid_option` - 옵션 타입/범위 오류(bigIntStrategy 포함).
|
|
7
|
+
*/
|
|
8
|
+
constructor(config?: MariaConfig);
|
|
9
|
+
/** driver 식별자 — dialect 디스패치(getDialect)·CRUD 의 단일 출처(ADR-212). @returns {'mariadb'} */
|
|
10
|
+
get driver(): "mariadb";
|
|
11
|
+
/**
|
|
12
|
+
* raw Pool handle (ADR-009). `connect()` 후에만 베이스 `native` getter 가 호출한다.
|
|
13
|
+
* @protected
|
|
14
|
+
* @returns {import('mariadb').Pool}
|
|
15
|
+
*/
|
|
16
|
+
protected _native(): import("mariadb").Pool;
|
|
17
|
+
/**
|
|
18
|
+
* 헬스 체크 — 실제 `SELECT 1` 으로 응답성 확인. 실패는 throw 없이 `ok:false` + 사유(베이스 계약).
|
|
19
|
+
* 비밀번호/connectionString 은 노출하지 않는다.
|
|
20
|
+
*
|
|
21
|
+
* @returns {Promise<{ ok: boolean, driver: 'mariadb', state: string, error?: string }>}
|
|
22
|
+
*/
|
|
23
|
+
healthCheck(): Promise<{
|
|
24
|
+
ok: boolean;
|
|
25
|
+
driver: "mariadb";
|
|
26
|
+
state: string;
|
|
27
|
+
error?: string;
|
|
28
|
+
}>;
|
|
29
|
+
/**
|
|
30
|
+
* 누적 통계 + 풀 통계(total/idle/active/queue). 연결 전이면 풀 통계는 0.
|
|
31
|
+
* @returns {ReturnType<import('./mega-adapter.js').MegaAdapter['getStats']> & { driver: string, pool: { total: number, idle: number, active: number, queue: number } }}
|
|
32
|
+
*/
|
|
33
|
+
getStats(): ReturnType<import("./mega-adapter.js").MegaAdapter["getStats"]> & {
|
|
34
|
+
driver: string;
|
|
35
|
+
pool: {
|
|
36
|
+
total: number;
|
|
37
|
+
idle: number;
|
|
38
|
+
active: number;
|
|
39
|
+
queue: number;
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* 명시적 트랜잭션 경계 (ADR-010, ADR-107). top-level 은 풀 연결 1개 위
|
|
44
|
+
* `beginTransaction/commit/rollback`, nested 는 같은 연결 위 `SAVEPOINT`(모듈 docstring 참조).
|
|
45
|
+
*
|
|
46
|
+
* `fn` 은 **트랜잭션 컨텍스트 연결**(mariadb PoolConnection)을 인자로 받는다. 성공 시 commit(또는
|
|
47
|
+
* RELEASE SAVEPOINT) 후 반환값을 그대로 돌려주고, throw 시 rollback(또는 ROLLBACK TO SAVEPOINT)
|
|
48
|
+
* 후 원본 에러 re-throw.
|
|
49
|
+
*
|
|
50
|
+
* `opts.isolation`(ADR-190) — top-level 이면 `beginTransaction()` **직전에** 같은 연결에서
|
|
51
|
+
* `SET TRANSACTION ISOLATION LEVEL` 을 실행한다(MariaDB 의 `SET TRANSACTION` 은 같은 세션의
|
|
52
|
+
* **다음** 트랜잭션 1회에만 적용 — 공식 문서). 격리수준은 트랜잭션 시작 시 고정되므로
|
|
53
|
+
* nested(SAVEPOINT) 호출에 지정하면 `adapter.nested_isolation_unsupported` 로 거부한다.
|
|
54
|
+
*
|
|
55
|
+
* hook(`onCallStart/onCallEnd`) + 상태 검증 + stats 누적은 `_instrument` 가 처리한다(ADR-077).
|
|
56
|
+
*
|
|
57
|
+
* @template T
|
|
58
|
+
* @param {(conn: import('mariadb').PoolConnection) => Promise<T> | T} fn
|
|
59
|
+
* @param {{ isolation?: 'read uncommitted' | 'read committed' | 'repeatable read' | 'serializable' }} [opts] - 트랜잭션 옵션(ADR-190).
|
|
60
|
+
* @returns {Promise<T>}
|
|
61
|
+
* @throws {MegaInternalError} `adapter.nested_isolation_unsupported` - nested 호출에 isolation 지정.
|
|
62
|
+
*/
|
|
63
|
+
withTransaction<T>(fn: (conn: import("mariadb").PoolConnection) => Promise<T> | T, opts?: {
|
|
64
|
+
isolation?: "read uncommitted" | "read committed" | "repeatable read" | "serializable";
|
|
65
|
+
}): Promise<T>;
|
|
66
|
+
#private;
|
|
67
|
+
}
|
|
68
|
+
export type MariaConfig = {
|
|
69
|
+
/**
|
|
70
|
+
* - 'mariadb' (매니저가 사용 — 어댑터는 무시).
|
|
71
|
+
*/
|
|
72
|
+
driver?: string;
|
|
73
|
+
/**
|
|
74
|
+
* - `mariadb://user:pw@host:port/db` (discrete 필드와 배타, query string 미지원).
|
|
75
|
+
*/
|
|
76
|
+
url?: string;
|
|
77
|
+
/**
|
|
78
|
+
* - `url` 의 deprecated 별칭 (하위 호환).
|
|
79
|
+
*/
|
|
80
|
+
connectionString?: string;
|
|
81
|
+
host?: string;
|
|
82
|
+
port?: number;
|
|
83
|
+
user?: string;
|
|
84
|
+
password?: string;
|
|
85
|
+
database?: string;
|
|
86
|
+
/**
|
|
87
|
+
* - 공통 풀 인터페이스.
|
|
88
|
+
*/
|
|
89
|
+
pool?: {
|
|
90
|
+
min?: number;
|
|
91
|
+
max?: number;
|
|
92
|
+
idleTimeoutMs?: number;
|
|
93
|
+
acquireTimeoutMs?: number;
|
|
94
|
+
};
|
|
95
|
+
/**
|
|
96
|
+
* - mariadb passthrough + bigIntStrategy.
|
|
97
|
+
*/
|
|
98
|
+
options?: Record<string, any> & {
|
|
99
|
+
bigIntStrategy?: "number" | "bigint" | "string";
|
|
100
|
+
};
|
|
101
|
+
};
|
|
102
|
+
/**
|
|
103
|
+
* - AsyncLocalStorage 에 담기는 트랜잭션 컨텍스트.
|
|
104
|
+
*/
|
|
105
|
+
export type MariaTxContext = {
|
|
106
|
+
/**
|
|
107
|
+
* - 이 트랜잭션을 소유한 풀 연결.
|
|
108
|
+
*/
|
|
109
|
+
conn: import("mariadb").PoolConnection;
|
|
110
|
+
/**
|
|
111
|
+
* - nesting 깊이 (top-level=0, 첫 nested=1, ...).
|
|
112
|
+
*/
|
|
113
|
+
depth: number;
|
|
114
|
+
};
|
|
115
|
+
import { MegaDbAdapter } from './mega-db-adapter.js';
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 어댑터 lifecycle 상태.
|
|
3
|
+
* @typedef {'created' | 'connected' | 'disconnecting' | 'disconnected' | 'failed'} AdapterState
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* 관찰성 hook 리스너 (ADR-077 보강 + span 중첩 seam).
|
|
7
|
+
* - `onCallStart(callName, attrs)` — **스코프 토큰을 반환할 수 있다**(예: 트레이서의 OTel span
|
|
8
|
+
* context). 반환하면 베이스가 도메인 `fn` 을 그 토큰으로 `run()` 안에서 실행해, 중첩 호출이
|
|
9
|
+
* 토큰을 부모로 보게 한다(span 계층 정확). 반환 안 하면(`undefined`) 래핑 없이 실행(0 비용).
|
|
10
|
+
* - `onCallEnd(callName, attrs, err?, scope?)` — `scope` 는 짝이 되는 `onCallStart` 의 반환 토큰.
|
|
11
|
+
* 계약: **throw 금지**(베이스가 격리하지만 리스너 측도 자체 보호 권장). 도메인 결과·통계 영향 X.
|
|
12
|
+
* @typedef {(callName: string, attrs?: object, err?: Error, scope?: any) => any} HookListener
|
|
13
|
+
*/
|
|
14
|
+
export class MegaAdapter {
|
|
15
|
+
/**
|
|
16
|
+
* 도메인 호출 스코프 토큰 저장소 (ADR-077 보강, span 중첩 seam). `onCallStart` 이 반환한
|
|
17
|
+
* 토큰을 도메인 `fn` 실행 동안 전파해, 중첩 호출(트랜잭션 안의 query)이 부모 토큰을 보게 한다.
|
|
18
|
+
* `AsyncLocalStorage.run()` 격리라 동시 top-level 호출도 서로 섞이지 않는다(`enterWith` 누수 회피).
|
|
19
|
+
* **전 어댑터 공유**(static) — "현재 호출 컨텍스트"는 async 실행 흐름 전역이라, 어댑터 A 의
|
|
20
|
+
* 트랜잭션 안에서 어댑터 B 를 호출하면 B 의 span 이 A 의 span 밑으로 정확히 묶인다.
|
|
21
|
+
* 토큰이 없으면(옵트인 OFF) 아예 쓰이지 않아 0 비용.
|
|
22
|
+
* @type {AsyncLocalStorage<any>}
|
|
23
|
+
*/
|
|
24
|
+
static "__#private@#callScope": AsyncLocalStorage<any>;
|
|
25
|
+
/**
|
|
26
|
+
* @param {object} [config] - driver 별 설정 (url / pool / file 등).
|
|
27
|
+
*/
|
|
28
|
+
constructor(config?: object);
|
|
29
|
+
/**
|
|
30
|
+
* 현재 lifecycle 상태 (읽기 전용). 테스트·헬스체크용.
|
|
31
|
+
* @returns {AdapterState}
|
|
32
|
+
*/
|
|
33
|
+
get state(): AdapterState;
|
|
34
|
+
/**
|
|
35
|
+
* driver 설정 (서브클래스 전용 — `_` 접두사 = framework-internal).
|
|
36
|
+
* @protected
|
|
37
|
+
* @returns {object}
|
|
38
|
+
*/
|
|
39
|
+
protected get _config(): object;
|
|
40
|
+
/**
|
|
41
|
+
* 연결 수립. 부팅 시퀀스 6번째 단계에서 호출 (Fastify 인스턴스 생성 직전, ADR-045).
|
|
42
|
+
* 이미 connected 면 idempotent no-op. disconnecting 중이면 throw.
|
|
43
|
+
* `_connect()` 가 throw 하면 상태 `failed` 로 두고 원본 에러 전파 (부팅 abort).
|
|
44
|
+
*
|
|
45
|
+
* 동시에 두 번 호출되면(아직 첫 호출이 resolve 되기 전) 첫 호출만 `_connect()` 를 실행하고
|
|
46
|
+
* 나머지는 같은 promise 를 await 한다 — 이중 연결/이중 pool 생성을 막는다(L1).
|
|
47
|
+
*
|
|
48
|
+
* @returns {Promise<void>}
|
|
49
|
+
*/
|
|
50
|
+
connect(): Promise<void>;
|
|
51
|
+
/**
|
|
52
|
+
* 연결 해제. graceful shutdown 시 등록 역순으로 호출 (07-sequence-diagrams §6).
|
|
53
|
+
* 아직 연결 안 했거나 이미 끊긴 상태면 idempotent no-op. disconnecting 중 재호출은 throw.
|
|
54
|
+
* `_disconnect()` 가 throw 하면 상태 `failed` 로 두고 원본 에러 전파(L4) — 정리 실패를
|
|
55
|
+
* `disconnected`(정상)로 덮지 않는다.
|
|
56
|
+
*
|
|
57
|
+
* @returns {Promise<void>}
|
|
58
|
+
*/
|
|
59
|
+
disconnect(): Promise<void>;
|
|
60
|
+
/**
|
|
61
|
+
* 헬스 체크. 디폴트는 연결 상태 반영 — 구체 어댑터가 실제 ping 으로 override 권장.
|
|
62
|
+
* @returns {Promise<{ ok: boolean, [k: string]: any }>}
|
|
63
|
+
*/
|
|
64
|
+
healthCheck(): Promise<{
|
|
65
|
+
ok: boolean;
|
|
66
|
+
[k: string]: any;
|
|
67
|
+
}>;
|
|
68
|
+
/**
|
|
69
|
+
* 누적 통계 스냅샷 (동기). Prometheus `/metrics` 가 수집 (옵트인, 후속 Phase).
|
|
70
|
+
* @returns {{ state: AdapterState, requests: number, errors: number, totalLatencyMs: number, avgLatencyMs: number }}
|
|
71
|
+
*/
|
|
72
|
+
getStats(): {
|
|
73
|
+
state: AdapterState;
|
|
74
|
+
requests: number;
|
|
75
|
+
errors: number;
|
|
76
|
+
totalLatencyMs: number;
|
|
77
|
+
avgLatencyMs: number;
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* driver native handle (pg Pool / MongoClient / ioredis Client / NATS Connection 등, ADR-009).
|
|
81
|
+
* `connect()` 후에만 유효 — 그 외엔 throw (08-class-specs §3.2 불변식).
|
|
82
|
+
* @returns {any}
|
|
83
|
+
*/
|
|
84
|
+
get native(): any;
|
|
85
|
+
/**
|
|
86
|
+
* 현재 호출 스코프 토큰(부모) — 트레이서(`MegaTracing`)가 `onCallStart` 에서 읽어 새 span 의 parent
|
|
87
|
+
* 로 삼는다. 진행 중인 바깥 도메인 호출이 없으면 `undefined`(= 루트). {@link _instrument} 가 `run()`
|
|
88
|
+
* 으로 설정. `_` 접두사 = framework-internal(외부 트레이서 lib 가 읽어야 해 OOP protected 는 아님).
|
|
89
|
+
* @returns {any}
|
|
90
|
+
*/
|
|
91
|
+
get _currentCallScope(): any;
|
|
92
|
+
/**
|
|
93
|
+
* 도메인 메서드 호출 시작 hook. 디폴트 동작 = 등록된 hook 리스너(ADR-077 보강)로 디스패치.
|
|
94
|
+
* 구체 어댑터의 도메인 메서드(`query`/`publish`/`get` 등) before 에서 호출됨(또는 `_instrument`).
|
|
95
|
+
* 리스너가 없으면(옵트인 OFF) 즉시 빠져나간다(0 비용). 트레이싱(`MegaTracing`)이
|
|
96
|
+
* `addHookListener('onCallStart', fn)` 으로 구독해 span 시작으로 변환 (ADR-077).
|
|
97
|
+
*
|
|
98
|
+
* **스코프 토큰**: 리스너가 값을 반환하면 그 중 **첫 정의된 반환**을 스코프 토큰으로 돌려준다.
|
|
99
|
+
* `_instrument` 는 이 토큰으로 도메인 `fn` 을 `run()` 안에서 실행해 span 중첩을 정확히 만든다.
|
|
100
|
+
*
|
|
101
|
+
* @param {string} callName - 'query' | 'publish' | 'get' | ...
|
|
102
|
+
* @param {object} [attrs] - span 속성. 예: `{ key, statement, args }`.
|
|
103
|
+
* @returns {any} 스코프 토큰(트레이서의 span context) 또는 `undefined`(중첩 래핑 없음).
|
|
104
|
+
*/
|
|
105
|
+
onCallStart(callName: string, attrs?: object): any;
|
|
106
|
+
/**
|
|
107
|
+
* 도메인 메서드 호출 종료 hook. 디폴트 동작 = 등록된 hook 리스너로 디스패치(`onCallStart` 대칭).
|
|
108
|
+
*
|
|
109
|
+
* @param {string} callName
|
|
110
|
+
* @param {object} [attrs] - 결과 속성. 예: `{ rowCount, latencyMs, hit }`.
|
|
111
|
+
* @param {Error} [err] - 있으면 호출 실패 — span status = ERROR.
|
|
112
|
+
* @param {any} [scope] - 짝이 되는 `onCallStart` 가 반환한 스코프 토큰(트레이서가 span 종료에 사용).
|
|
113
|
+
* @returns {void}
|
|
114
|
+
*/
|
|
115
|
+
onCallEnd(callName: string, attrs?: object, err?: Error, scope?: any): void;
|
|
116
|
+
/**
|
|
117
|
+
* 관찰성 hook 리스너 등록 (옵션 B — `_instrument` 무변경, 베이스에 구독 채널만 추가).
|
|
118
|
+
*
|
|
119
|
+
* `MegaTracing` 같은 외부 트레이서가 어댑터 코드를 건드리지 않고 `onCallStart`/`onCallEnd`
|
|
120
|
+
* 발화를 구독한다. 같은 리스너 함수의 중복 등록은 `Set` 이라 1회로 합쳐진다.
|
|
121
|
+
*
|
|
122
|
+
* @param {'onCallStart' | 'onCallEnd'} hookName
|
|
123
|
+
* @param {HookListener} listener
|
|
124
|
+
* @returns {() => void} 등록 해제 함수 (구독 취소 시 호출).
|
|
125
|
+
* @throws {MegaInternalError} `adapter.invalid_hook` - hookName/listener 가 잘못된 타입.
|
|
126
|
+
*/
|
|
127
|
+
addHookListener(hookName: "onCallStart" | "onCallEnd", listener: HookListener): () => void;
|
|
128
|
+
/**
|
|
129
|
+
* 관찰성 hook 리스너 해제. 마지막 리스너가 빠지면 Set 을 `null` 로 되돌려 0 비용 fast path 복구.
|
|
130
|
+
*
|
|
131
|
+
* @param {'onCallStart' | 'onCallEnd'} hookName
|
|
132
|
+
* @param {HookListener} listener
|
|
133
|
+
* @returns {boolean} 실제로 제거됐으면 true (없던 리스너면 false).
|
|
134
|
+
*/
|
|
135
|
+
removeHookListener(hookName: "onCallStart" | "onCallEnd", listener: HookListener): boolean;
|
|
136
|
+
/**
|
|
137
|
+
* 해당 hook 에 리스너가 1개 이상 붙어 있는지 (Boolean — `has*`, ADR-036).
|
|
138
|
+
* @param {'onCallStart' | 'onCallEnd'} hookName
|
|
139
|
+
* @returns {boolean}
|
|
140
|
+
*/
|
|
141
|
+
hasHookListeners(hookName: "onCallStart" | "onCallEnd"): boolean;
|
|
142
|
+
/**
|
|
143
|
+
* 실제 연결 수립. 디폴트 no-op (예: 로그 sink 는 연결 개념 없음).
|
|
144
|
+
* DB/cache/bus 구체 어댑터는 driver 연결 로직으로 override.
|
|
145
|
+
* @protected
|
|
146
|
+
* @returns {Promise<void>}
|
|
147
|
+
*/
|
|
148
|
+
protected _connect(): Promise<void>;
|
|
149
|
+
/**
|
|
150
|
+
* 실제 연결 해제. 디폴트 no-op. 구체 어댑터가 driver close 로 override.
|
|
151
|
+
* @protected
|
|
152
|
+
* @returns {Promise<void>}
|
|
153
|
+
*/
|
|
154
|
+
protected _disconnect(): Promise<void>;
|
|
155
|
+
/**
|
|
156
|
+
* native handle 반환. 디폴트는 미구현 throw — 구체 어댑터가 override.
|
|
157
|
+
* @protected
|
|
158
|
+
* @returns {any}
|
|
159
|
+
*/
|
|
160
|
+
protected _native(): any;
|
|
161
|
+
/**
|
|
162
|
+
* 도메인 메서드를 hook + 상태 검증 + stats 누적으로 감싸는 표준 보일러플레이트 (roadmap, ADR-077).
|
|
163
|
+
*
|
|
164
|
+
* connect 전 호출이면 `adapter.not_connected` throw. 성공/실패 모두 `onCallEnd` 호출 후
|
|
165
|
+
* 결과 반환 / 원본 에러 re-throw (08-class-specs §3.2 "도메인 메서드 throw → onCallEnd(.., err) 후 re-throw").
|
|
166
|
+
*
|
|
167
|
+
* **hook 격리(M1)**: `onCallStart`/`onCallEnd` 는 관찰성 hook 일 뿐 도메인 결과·통계에
|
|
168
|
+
* 영향을 주면 안 된다. hook 은 **throw 금지**가 계약이지만, 위반(트레이서 버그 등) 시에도
|
|
169
|
+
* 도메인 호출이 깨지지 않도록 hook 호출을 별도 try/catch 로 격리해 `console.warn` 후 무시한다.
|
|
170
|
+
* 통계(requests/errors/latency)는 항상 fn 본체의 성공/실패 기준으로만 누적된다.
|
|
171
|
+
*
|
|
172
|
+
* **결과 기반 종료 속성**(`extractEndAttrs`): 도메인 호출 결과에서 span 종료 속성을 뽑아야 하는
|
|
173
|
+
* 경우(예: `query` 의 `rows_affected`)에 쓴다. 성공 시 `extractEndAttrs(result)` 의 반환 객체를
|
|
174
|
+
* 종료 attrs 에 머지한다. 결과 의존 attr 이 없으면 생략 — 기존 호출부(`withTransaction` 등)는
|
|
175
|
+
* 4번째 인자 없이 그대로 동작한다(0 변경). 추출기 throw 는 도메인 결과를 깨지 않도록 격리(M1 정합).
|
|
176
|
+
*
|
|
177
|
+
* @protected
|
|
178
|
+
* @template T
|
|
179
|
+
* @param {string} callName - 도메인 호출 이름 (span 이름 기반).
|
|
180
|
+
* @param {object} attrs - 시작 span 속성 (`{ key, statement, ... }`).
|
|
181
|
+
* @param {() => Promise<T>} fn - 실제 driver 호출.
|
|
182
|
+
* @param {(result: T) => object} [extractEndAttrs] - 결과에서 종료 span 속성 추출(선택). 성공 시만 호출.
|
|
183
|
+
* @returns {Promise<T>}
|
|
184
|
+
*/
|
|
185
|
+
protected _instrument<T>(callName: string, attrs: object, fn: () => Promise<T>, extractEndAttrs?: (result: T) => object): Promise<T>;
|
|
186
|
+
/**
|
|
187
|
+
* 도메인 메서드가 connect 전 호출됐는지 검증. 아니면 `adapter.not_connected` throw.
|
|
188
|
+
* @protected
|
|
189
|
+
* @param {string} callName
|
|
190
|
+
* @returns {void}
|
|
191
|
+
*/
|
|
192
|
+
protected _assertConnected(callName: string): void;
|
|
193
|
+
/**
|
|
194
|
+
* 미구현 도메인 메서드 stub 용 — 명확한 `adapter.not_implemented` throw.
|
|
195
|
+
* @protected
|
|
196
|
+
* @param {string} method
|
|
197
|
+
* @returns {never}
|
|
198
|
+
*/
|
|
199
|
+
protected _notImplemented(method: string): never;
|
|
200
|
+
#private;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* 어댑터 lifecycle 상태.
|
|
204
|
+
*/
|
|
205
|
+
export type AdapterState = "created" | "connected" | "disconnecting" | "disconnected" | "failed";
|
|
206
|
+
/**
|
|
207
|
+
* 관찰성 hook 리스너 (ADR-077 보강 + span 중첩 seam).
|
|
208
|
+
* - `onCallStart(callName, attrs)` — **스코프 토큰을 반환할 수 있다**(예: 트레이서의 OTel span
|
|
209
|
+
* context). 반환하면 베이스가 도메인 `fn` 을 그 토큰으로 `run()` 안에서 실행해, 중첩 호출이
|
|
210
|
+
* 토큰을 부모로 보게 한다(span 계층 정확). 반환 안 하면(`undefined`) 래핑 없이 실행(0 비용).
|
|
211
|
+
* - `onCallEnd(callName, attrs, err?, scope?)` — `scope` 는 짝이 되는 `onCallStart` 의 반환 토큰.
|
|
212
|
+
* 계약: **throw 금지**(베이스가 격리하지만 리스너 측도 자체 보호 권장). 도메인 결과·통계 영향 X.
|
|
213
|
+
*/
|
|
214
|
+
export type HookListener = (callName: string, attrs?: object, err?: Error, scope?: any) => any;
|
|
215
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export class MegaBusAdapter extends MegaAdapter {
|
|
2
|
+
/**
|
|
3
|
+
* fire-and-forget 발행 (ack X).
|
|
4
|
+
* @param {string} _subject
|
|
5
|
+
* @param {any} _payload
|
|
6
|
+
* @returns {Promise<void>}
|
|
7
|
+
*/
|
|
8
|
+
publish(_subject: string, _payload: any): Promise<void>;
|
|
9
|
+
/**
|
|
10
|
+
* 구독. handler 는 `async (msg, replyFn) => void`. 반환된 핸들로 cleanup.
|
|
11
|
+
* @param {string} _subject
|
|
12
|
+
* @param {(msg: any, replyFn?: (payload: any) => void) => any} _handler
|
|
13
|
+
* @returns {Promise<{ unsubscribe: () => Promise<void> }>}
|
|
14
|
+
*/
|
|
15
|
+
subscribe(_subject: string, _handler: (msg: any, replyFn?: (payload: any) => void) => any): Promise<{
|
|
16
|
+
unsubscribe: () => Promise<void>;
|
|
17
|
+
}>;
|
|
18
|
+
/**
|
|
19
|
+
* req/reply 패턴. timeout 초과 시 `bus.request_timeout` throw.
|
|
20
|
+
* @param {string} _subject
|
|
21
|
+
* @param {any} _payload
|
|
22
|
+
* @param {{ timeout?: number }} [_opts]
|
|
23
|
+
* @returns {Promise<any>} reply.
|
|
24
|
+
*/
|
|
25
|
+
request(_subject: string, _payload: any, _opts?: {
|
|
26
|
+
timeout?: number;
|
|
27
|
+
}): Promise<any>;
|
|
28
|
+
/**
|
|
29
|
+
* 잡 enqueue (MegaJob 백엔드, ADR-028).
|
|
30
|
+
* @param {string} _jobName
|
|
31
|
+
* @param {any} _payload
|
|
32
|
+
* @param {object} [_opts]
|
|
33
|
+
* @returns {Promise<void>}
|
|
34
|
+
*/
|
|
35
|
+
enqueue(_jobName: string, _payload: any, _opts?: object): Promise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* 잡 처리 등록 (MegaJob 백엔드, ADR-028).
|
|
38
|
+
* @param {string} _jobName
|
|
39
|
+
* @param {(payload: any) => any} _handler
|
|
40
|
+
* @param {object} [_opts]
|
|
41
|
+
* @returns {Promise<void>}
|
|
42
|
+
*/
|
|
43
|
+
process(_jobName: string, _handler: (payload: any) => any, _opts?: object): Promise<void>;
|
|
44
|
+
}
|
|
45
|
+
import { MegaAdapter } from './mega-adapter.js';
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export class MegaCacheAdapter extends MegaAdapter {
|
|
2
|
+
/**
|
|
3
|
+
* @param {string} _key
|
|
4
|
+
* @returns {Promise<any>} 값 — 없으면 `null` (throw X).
|
|
5
|
+
*/
|
|
6
|
+
get(_key: string): Promise<any>;
|
|
7
|
+
/**
|
|
8
|
+
* @param {string} _key
|
|
9
|
+
* @param {any} _value
|
|
10
|
+
* @param {{ ttl?: number }} [_opts] - `ttl` 미지정 시 무한 (초 단위).
|
|
11
|
+
* @returns {Promise<void>}
|
|
12
|
+
*/
|
|
13
|
+
set(_key: string, _value: any, _opts?: {
|
|
14
|
+
ttl?: number;
|
|
15
|
+
}): Promise<void>;
|
|
16
|
+
/**
|
|
17
|
+
* @param {string} _key
|
|
18
|
+
* @returns {Promise<void>}
|
|
19
|
+
*/
|
|
20
|
+
del(_key: string): Promise<void>;
|
|
21
|
+
/**
|
|
22
|
+
* 키 존재 여부 (Boolean — `has*` 접두사, ADR-036). `get` 과 race 가능 — 보장 X.
|
|
23
|
+
* @param {string} _key
|
|
24
|
+
* @returns {Promise<boolean>}
|
|
25
|
+
*/
|
|
26
|
+
has(_key: string): Promise<boolean>;
|
|
27
|
+
/**
|
|
28
|
+
* ttl 값 검증 헬퍼 (구체 어댑터 `set` 에서 사용). 초 단위 양의 정수만 통과(L3).
|
|
29
|
+
*
|
|
30
|
+
* `undefined` = 무한(검증 통과, no-expiry). 그 외엔 다음을 거부하고 `cache.invalid_ttl` throw:
|
|
31
|
+
* - 숫자 아님 / `NaN`
|
|
32
|
+
* - `Infinity`(무한은 `undefined` 로 표현 — 옵션 `allowInfinity` 로 driver override 가능)
|
|
33
|
+
* - 정수 아님(소수 초 — Redis `EX` 등 대부분 정수 초만 허용)
|
|
34
|
+
* - 음수
|
|
35
|
+
* - `0`(즉시 만료 의미가 driver 마다 달라 모호 — 옵션 `allowZero` 로 override 가능)
|
|
36
|
+
*
|
|
37
|
+
* @protected
|
|
38
|
+
* @param {number} [ttl] - 초 단위 TTL.
|
|
39
|
+
* @param {{ allowZero?: boolean, allowInfinity?: boolean }} [opts] - driver 별 완화 옵션.
|
|
40
|
+
* @returns {void}
|
|
41
|
+
*/
|
|
42
|
+
protected _assertTtl(ttl?: number, { allowZero, allowInfinity }?: {
|
|
43
|
+
allowZero?: boolean;
|
|
44
|
+
allowInfinity?: boolean;
|
|
45
|
+
}): void;
|
|
46
|
+
}
|
|
47
|
+
import { MegaAdapter } from './mega-adapter.js';
|