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,47 @@
|
|
|
1
|
+
export class MegaDbAdapter extends MegaAdapter {
|
|
2
|
+
/**
|
|
3
|
+
* 명시적 트랜잭션 경계 (ADR-010). 성공 시 commit, throw 시 rollback.
|
|
4
|
+
* driver 별 구현 (postgres `BEGIN/COMMIT/ROLLBACK`, MongoDB `session.withTransaction`).
|
|
5
|
+
* nested 호출은 driver 별 (postgres SAVEPOINT, MongoDB throw `adapter.nested_transaction_unsupported`).
|
|
6
|
+
*
|
|
7
|
+
* `opts.isolation`(ADR-190) — SQL 격리수준 옵트인. 미지정이면 driver 디폴트. driver 별 지원:
|
|
8
|
+
* postgres/maria 는 top-level 트랜잭션에 `SET TRANSACTION ISOLATION LEVEL` 로 반영(nested 엔 불가 —
|
|
9
|
+
* `adapter.nested_isolation_unsupported`), sqlite 는 항상 SERIALIZABLE 동작이라 'serializable' 만 수용,
|
|
10
|
+
* mongodb 는 SQL 격리수준 개념이 없어 지정 시 `adapter.invalid_option`.
|
|
11
|
+
*
|
|
12
|
+
* @template T
|
|
13
|
+
* @param {(db: any) => Promise<T>} _fn - 트랜잭션 컨텍스트의 `db` 를 받는 콜백.
|
|
14
|
+
* @param {{ isolation?: 'read uncommitted' | 'read committed' | 'repeatable read' | 'serializable' }} [_opts] - 트랜잭션 옵션(ADR-190).
|
|
15
|
+
* @returns {Promise<T>}
|
|
16
|
+
*/
|
|
17
|
+
withTransaction<T>(_fn: (db: any) => Promise<T>, _opts?: {
|
|
18
|
+
isolation?: "read uncommitted" | "read committed" | "repeatable read" | "serializable";
|
|
19
|
+
}): Promise<T>;
|
|
20
|
+
/**
|
|
21
|
+
* 계측된 SQL 쿼리 실행 (ADR-138). `_instrument('query', …)` 로 감싸므로 자동 span(`<driver>.query`,
|
|
22
|
+
* `db.system.name`/`db.query.text`/`mega.rows_affected`)·stats·상태 검증이 한 번에 처리된다.
|
|
23
|
+
* `MegaModel.db.query`(native handle 직접 호출)와 달리 트레이싱/메트릭에 잡힌다.
|
|
24
|
+
*
|
|
25
|
+
* 진행 중 트랜잭션이 있으면 **같은 connection** 위에서 실행해 격리를 유지한다(구체 어댑터가
|
|
26
|
+
* 트랜잭션 컨텍스트를 인식) — 트랜잭션 밖이면 풀/단일 연결. 결과 형태는 driver native 를 그대로
|
|
27
|
+
* 돌려준다(ADR-009 — 어댑터별 차이 허용). SQL 어댑터(postgres/maria/sqlite) 만 구현하며,
|
|
28
|
+
* Document DB(mongo) 는 SQL `query` 개념이 없어 미구현(`adapter.not_implemented`).
|
|
29
|
+
*
|
|
30
|
+
* @param {string} _sql - 파라미터화된 SQL(placeholder `$1`/`?` 보존 — 값 인터폴레이션 금지).
|
|
31
|
+
* @param {any[]} [_params] - placeholder 바인딩 값.
|
|
32
|
+
* @returns {Promise<any>} driver native 쿼리 결과.
|
|
33
|
+
*/
|
|
34
|
+
query(_sql: string, _params?: any[]): Promise<any>;
|
|
35
|
+
/**
|
|
36
|
+
* `query` span 시작 속성 — 파라미터화된 SQL 만 `statement` 로 싣는다(트레이서가 `db.query.text` 로
|
|
37
|
+
* 매핑). 문자열이 아니면(쿼리 빌더 객체 등) `mega.query_unparam:true` 로 폴백 — 원본 페이로드
|
|
38
|
+
* 노출·추측 정제를 피한다(ADR-138). placeholder(`$1`/`?`)는 보존되고 바인딩 값은 싣지 않으므로
|
|
39
|
+
* 시크릿 누출·라벨 카디널리티 폭증이 없다.
|
|
40
|
+
*
|
|
41
|
+
* @protected
|
|
42
|
+
* @param {unknown} sql
|
|
43
|
+
* @returns {object}
|
|
44
|
+
*/
|
|
45
|
+
protected _queryStartAttrs(sql: unknown): object;
|
|
46
|
+
}
|
|
47
|
+
import { MegaAdapter } from './mega-adapter.js';
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
export class MegaLockAdapter extends MegaAdapter {
|
|
2
|
+
/**
|
|
3
|
+
* 락 획득. `key` 에 대한 상호배제 락을 `opts.ttl`(ms) 동안 잡는다. 이미 다른 곳이 잡고 있으면
|
|
4
|
+
* retry 설정(opts)만큼 재시도하고, 그래도 못 잡으면 throw(경합은 정상 도메인 결과 — 호출부가 처리).
|
|
5
|
+
*
|
|
6
|
+
* @param {string} _key - 락 자원 키.
|
|
7
|
+
* @param {{ ttl?: number, retryCount?: number, retryDelay?: number, retryJitter?: number }} [_opts]
|
|
8
|
+
* - `ttl`(ms, 필수에 준함) 보유 시간. `retryCount/retryDelay/retryJitter` 는 경합 시 재시도 정책(driver 별).
|
|
9
|
+
* @returns {Promise<any>} 락 핸들(release/extend 에 전달).
|
|
10
|
+
*/
|
|
11
|
+
acquire(_key: string, _opts?: {
|
|
12
|
+
ttl?: number;
|
|
13
|
+
retryCount?: number;
|
|
14
|
+
retryDelay?: number;
|
|
15
|
+
retryJitter?: number;
|
|
16
|
+
}): Promise<any>;
|
|
17
|
+
/**
|
|
18
|
+
* 락 해제. 이미 만료/해제됐어도 비치명적(자동 만료가 안전망) — 구체 어댑터는 best-effort 로 처리.
|
|
19
|
+
* @param {any} _lock - {@link acquire} 가 돌려준 핸들.
|
|
20
|
+
* @returns {Promise<void>}
|
|
21
|
+
*/
|
|
22
|
+
release(_lock: any): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* 락 TTL 연장. 임계구역이 길어질 때 만료 전에 보유 시간을 늘린다.
|
|
25
|
+
*
|
|
26
|
+
* **반환된 핸들을 이후 release/extend 에 써야 한다** — 구체 driver(redlock)가 연장 시 **새 핸들**을
|
|
27
|
+
* 만들 수 있어, 기존 핸들은 무효가 될 수 있다(ADR-113). 그래서 베이스 계약을 `Promise<void>` 가
|
|
28
|
+
* 아니라 연장된 핸들 반환으로 둔다.
|
|
29
|
+
*
|
|
30
|
+
* @param {any} _lock @param {number} _ttl - 추가 보유 시간(ms).
|
|
31
|
+
* @returns {Promise<any>} 연장된 락 핸들.
|
|
32
|
+
*/
|
|
33
|
+
extend(_lock: any, _ttl: number): Promise<any>;
|
|
34
|
+
/**
|
|
35
|
+
* convenience — 락을 잡고 `fn` 을 실행한 뒤 **반드시 해제**한다(fn 이 throw 해도 release 보장).
|
|
36
|
+
*
|
|
37
|
+
* 구체 driver 가 자동 연장을 지원하면(redlock `using`) fn 실행 중 만료가 임박할 때 자동으로 TTL 을
|
|
38
|
+
* 늘리고, 연장 실패 시 fn 에 중단 신호(abort signal)를 전달한다 — 이 경우 fn 시그니처는 `(signal)`
|
|
39
|
+
* 이고, 자동 연장이 없는 단순 구현이면 `(lock)` 을 받는다(구체 어댑터 JSDoc 참조).
|
|
40
|
+
*
|
|
41
|
+
* @template T
|
|
42
|
+
* @param {string} _key @param {{ ttl?: number }} _opts @param {(arg: any) => Promise<T>} _fn
|
|
43
|
+
* @returns {Promise<T>}
|
|
44
|
+
*/
|
|
45
|
+
withLock<T>(_key: string, _opts: {
|
|
46
|
+
ttl?: number;
|
|
47
|
+
}, _fn: (arg: any) => Promise<T>): Promise<T>;
|
|
48
|
+
/**
|
|
49
|
+
* 락 ttl 검증 헬퍼 (구체 어댑터의 acquire/extend/withLock 에서 사용). **밀리초** 양의 정수만 통과.
|
|
50
|
+
*
|
|
51
|
+
* cache 의 `_assertTtl`(초 단위, undefined=무한 허용)과 달리 락 ttl 은:
|
|
52
|
+
* - **필수** — 무한 락은 데드락 위험이라 허용하지 않는다(undefined 거부).
|
|
53
|
+
* - **밀리초** 양의 정수 — 0/음수/소수/비숫자 거부.
|
|
54
|
+
*
|
|
55
|
+
* @protected
|
|
56
|
+
* @param {number} [ttl] - 보유 시간(ms).
|
|
57
|
+
* @returns {void}
|
|
58
|
+
* @throws {MegaValidationError} `lock.invalid_ttl`
|
|
59
|
+
*/
|
|
60
|
+
protected _assertLockTtl(ttl?: number): void;
|
|
61
|
+
}
|
|
62
|
+
import { MegaAdapter } from './mega-adapter.js';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export class MegaLogSinkAdapter extends MegaAdapter {
|
|
2
|
+
/**
|
|
3
|
+
* 로그 레코드 기록 (동기). 비동기 IO 가 필요하면 내부 큐잉 + worker thread (구체별).
|
|
4
|
+
* @param {object} _record - pino 표준 record.
|
|
5
|
+
* @returns {void}
|
|
6
|
+
*/
|
|
7
|
+
write(_record: object): void;
|
|
8
|
+
/**
|
|
9
|
+
* 큐 drain + flush 보장. shutdown 마지막 단계 (07-sequence-diagrams §6).
|
|
10
|
+
* 디폴트는 `disconnect()` 위임 — 구체가 큐 drain 으로 override.
|
|
11
|
+
* @returns {Promise<void>}
|
|
12
|
+
*/
|
|
13
|
+
close(): Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
import { MegaAdapter } from './mega-adapter.js';
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export class MegaSessionAdapter extends MegaAdapter {
|
|
2
|
+
/**
|
|
3
|
+
* @param {string} _sessionId
|
|
4
|
+
* @returns {Promise<object | null>} 세션 record — 없으면 `null`.
|
|
5
|
+
*/
|
|
6
|
+
load(_sessionId: string): Promise<object | null>;
|
|
7
|
+
/**
|
|
8
|
+
* @param {string} _sessionId
|
|
9
|
+
* @param {object} _record
|
|
10
|
+
* @returns {Promise<void>}
|
|
11
|
+
*/
|
|
12
|
+
save(_sessionId: string, _record: object): Promise<void>;
|
|
13
|
+
/**
|
|
14
|
+
* @param {string} _sessionId
|
|
15
|
+
* @returns {Promise<void>}
|
|
16
|
+
*/
|
|
17
|
+
destroy(_sessionId: string): Promise<void>;
|
|
18
|
+
/**
|
|
19
|
+
* rolling TTL 갱신 (매 요청, ADR-046).
|
|
20
|
+
* @param {string} _sessionId
|
|
21
|
+
* @param {number} _ttlMs
|
|
22
|
+
* @returns {Promise<void>}
|
|
23
|
+
*/
|
|
24
|
+
touch(_sessionId: string, _ttlMs: number): Promise<void>;
|
|
25
|
+
/**
|
|
26
|
+
* 만료 세션 정리. file 드라이버는 스캔 후 삭제, Redis 는 TTL 자동(no-op). `MegaSchedule` 로 자동 등록
|
|
27
|
+
* 가능(ADR-129/046).
|
|
28
|
+
* @returns {Promise<number>} 정리된(삭제된) 세션 수.
|
|
29
|
+
*/
|
|
30
|
+
cleanup(): Promise<number>;
|
|
31
|
+
}
|
|
32
|
+
import { MegaAdapter } from './mega-adapter.js';
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {object} MongoTxContext - AsyncLocalStorage 에 담기는 트랜잭션 컨텍스트.
|
|
3
|
+
* @property {import('mongodb').ClientSession} session - 진행 중 트랜잭션을 소유한 세션.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* CMAP(Connection Monitoring and Pooling) 이벤트 누적 카운터. mongodb driver 는 풀 통계를
|
|
7
|
+
* 직접 노출하는 공개 API 가 없어(`topology` 는 비공개 내부), 표준 CMAP 이벤트(기본 발생)를
|
|
8
|
+
* 구독해 누적한다. open=created-closed, inUse=checkedOut-checkedIn 으로 파생.
|
|
9
|
+
* @typedef {object} PoolCounters
|
|
10
|
+
* @property {number} created @property {number} closed
|
|
11
|
+
* @property {number} checkedOut @property {number} checkedIn
|
|
12
|
+
*/
|
|
13
|
+
export class MegaMongoAdapter extends MegaDbAdapter {
|
|
14
|
+
/**
|
|
15
|
+
* @param {MongoConfig} [config] - services.databases.<key> 설정.
|
|
16
|
+
* @throws {MegaValidationError} `adapter.connection_required` - url·discrete 둘 다 없음.
|
|
17
|
+
* @throws {MegaValidationError} `adapter.connection_conflict` - url + discrete 동시 지정.
|
|
18
|
+
* @throws {MegaValidationError} `adapter.dbname_required` - dbName 누락 + url path 에도 없음.
|
|
19
|
+
* @throws {MegaValidationError} `adapter.invalid_option` - 옵션 타입/범위 오류.
|
|
20
|
+
*/
|
|
21
|
+
constructor(config?: MongoConfig);
|
|
22
|
+
/** driver 식별자 — dialect 디스패치·CRUD 의 단일 출처(ADR-212). mongo 는 SQL CRUD 미지원(P3). @returns {'mongodb'} */
|
|
23
|
+
get driver(): "mongodb";
|
|
24
|
+
/**
|
|
25
|
+
* raw Db handle (ADR-009). `connect()` 후에만 베이스 `native` getter 가 호출한다.
|
|
26
|
+
* @protected
|
|
27
|
+
* @returns {import('mongodb').Db}
|
|
28
|
+
*/
|
|
29
|
+
protected _native(): import("mongodb").Db;
|
|
30
|
+
/**
|
|
31
|
+
* 헬스 체크 — 실제 `ping` 으로 응답성 확인 (베이스 디폴트는 상태만 반영).
|
|
32
|
+
* 실패는 throw 없이 `ok:false` + 사유(베이스 계약). 비밀번호/connectionString 은 노출하지 않는다.
|
|
33
|
+
*
|
|
34
|
+
* @returns {Promise<{ ok: boolean, driver: 'mongodb', state: string, dbName?: string, error?: string }>}
|
|
35
|
+
*/
|
|
36
|
+
healthCheck(): Promise<{
|
|
37
|
+
ok: boolean;
|
|
38
|
+
driver: "mongodb";
|
|
39
|
+
state: string;
|
|
40
|
+
dbName?: string;
|
|
41
|
+
error?: string;
|
|
42
|
+
}>;
|
|
43
|
+
/**
|
|
44
|
+
* 누적 통계 + mongo 특화(driver/dbName + CMAP 풀 카운터). 연결 전이면 카운터는 0.
|
|
45
|
+
* @returns {ReturnType<import('./mega-adapter.js').MegaAdapter['getStats']> & { driver: string, dbName: string, pool: { created: number, closed: number, checkedOut: number, checkedIn: number, open: number, inUse: number } }}
|
|
46
|
+
*/
|
|
47
|
+
getStats(): ReturnType<import("./mega-adapter.js").MegaAdapter["getStats"]> & {
|
|
48
|
+
driver: string;
|
|
49
|
+
dbName: string;
|
|
50
|
+
pool: {
|
|
51
|
+
created: number;
|
|
52
|
+
closed: number;
|
|
53
|
+
checkedOut: number;
|
|
54
|
+
checkedIn: number;
|
|
55
|
+
open: number;
|
|
56
|
+
inUse: number;
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* 명시적 트랜잭션 경계 (ADR-010, ADR-108). `session.withTransaction` 에 위임한다 —
|
|
61
|
+
* driver 가 commit/abort + transient 에러 자동 retry 를 관리(모듈 docstring 참조).
|
|
62
|
+
*
|
|
63
|
+
* `fn` 은 `(db, session)` 을 받는다. 성공 시 driver 가 commit 후 `fn` 반환값을 그대로 돌려주고,
|
|
64
|
+
* throw 시 abort 후 원본 에러를 re-throw 한다. nested 호출은 ALS 로 감지해 거부(Sqlite 와 동일).
|
|
65
|
+
* `session.endSession()` 은 `finally` 에서 반드시 호출(leak 방지).
|
|
66
|
+
*
|
|
67
|
+
* `opts.isolation`(ADR-190) — MongoDB 트랜잭션에는 SQL 격리수준 개념이 없다(snapshot 의미는 driver/
|
|
68
|
+
* readConcern 관할). 지정 시 `adapter.invalid_option` 으로 명시 거부한다(조용히 무시 X — P4).
|
|
69
|
+
*
|
|
70
|
+
* hook(`onCallStart/onCallEnd`) + 상태 검증 + stats 누적은 `_instrument` 가 처리한다(ADR-077).
|
|
71
|
+
*
|
|
72
|
+
* @template T
|
|
73
|
+
* @param {(db: import('mongodb').Db, session: import('mongodb').ClientSession) => Promise<T> | T} fn
|
|
74
|
+
* @param {{ isolation?: never }} [opts] - 트랜잭션 옵션(ADR-190) — mongodb 는 isolation 미지원.
|
|
75
|
+
* @returns {Promise<T>}
|
|
76
|
+
* @throws {MegaInternalError} `adapter.nested_transaction_unsupported` - 이미 트랜잭션 진행 중.
|
|
77
|
+
* @throws {MegaValidationError} `adapter.invalid_option` - isolation 지정(미지원).
|
|
78
|
+
*/
|
|
79
|
+
withTransaction<T>(fn: (db: import("mongodb").Db, session: import("mongodb").ClientSession) => Promise<T> | T, opts?: {
|
|
80
|
+
isolation?: never;
|
|
81
|
+
}): Promise<T>;
|
|
82
|
+
#private;
|
|
83
|
+
}
|
|
84
|
+
export type MongoConfig = {
|
|
85
|
+
/**
|
|
86
|
+
* - 'mongodb' (매니저가 사용 — 어댑터는 무시).
|
|
87
|
+
*/
|
|
88
|
+
driver?: string;
|
|
89
|
+
/**
|
|
90
|
+
* - `mongodb://...` 연결 문자열 (discrete 와 배타).
|
|
91
|
+
*/
|
|
92
|
+
url?: string;
|
|
93
|
+
/**
|
|
94
|
+
* - `url` 의 deprecated 별칭 (하위 호환).
|
|
95
|
+
*/
|
|
96
|
+
connectionString?: string;
|
|
97
|
+
host?: string;
|
|
98
|
+
port?: number;
|
|
99
|
+
user?: string;
|
|
100
|
+
password?: string;
|
|
101
|
+
/**
|
|
102
|
+
* - 선택할 DB (url path 에서 추출 가능, 명시 우선).
|
|
103
|
+
*/
|
|
104
|
+
dbName?: string;
|
|
105
|
+
/**
|
|
106
|
+
* - 공통 풀 인터페이스.
|
|
107
|
+
*/
|
|
108
|
+
pool?: {
|
|
109
|
+
min?: number;
|
|
110
|
+
max?: number;
|
|
111
|
+
idleTimeoutMs?: number;
|
|
112
|
+
acquireTimeoutMs?: number;
|
|
113
|
+
};
|
|
114
|
+
/**
|
|
115
|
+
* - MongoClient passthrough (authSource, replicaSet, tls, readPreference, serverSelectionTimeoutMS, …).
|
|
116
|
+
*/
|
|
117
|
+
options?: Record<string, any>;
|
|
118
|
+
};
|
|
119
|
+
/**
|
|
120
|
+
* - AsyncLocalStorage 에 담기는 트랜잭션 컨텍스트.
|
|
121
|
+
*/
|
|
122
|
+
export type MongoTxContext = {
|
|
123
|
+
/**
|
|
124
|
+
* - 진행 중 트랜잭션을 소유한 세션.
|
|
125
|
+
*/
|
|
126
|
+
session: import("mongodb").ClientSession;
|
|
127
|
+
};
|
|
128
|
+
/**
|
|
129
|
+
* CMAP(Connection Monitoring and Pooling) 이벤트 누적 카운터. mongodb driver 는 풀 통계를
|
|
130
|
+
* 직접 노출하는 공개 API 가 없어(`topology` 는 비공개 내부), 표준 CMAP 이벤트(기본 발생)를
|
|
131
|
+
* 구독해 누적한다. open=created-closed, inUse=checkedOut-checkedIn 으로 파생.
|
|
132
|
+
*/
|
|
133
|
+
export type PoolCounters = {
|
|
134
|
+
created: number;
|
|
135
|
+
closed: number;
|
|
136
|
+
checkedOut: number;
|
|
137
|
+
checkedIn: number;
|
|
138
|
+
};
|
|
139
|
+
import { MegaDbAdapter } from './mega-db-adapter.js';
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {object} NatsConfig
|
|
3
|
+
* @property {string} [driver] - 'nats' (매니저가 사용 — 어댑터는 무시).
|
|
4
|
+
* @property {string} [url] - `nats://host:port` 연결 문자열 (discrete 와 배타).
|
|
5
|
+
* @property {string} [connectionString] - `url` 의 deprecated 별칭 (하위 호환).
|
|
6
|
+
* @property {string} [host] @property {number} [port] @property {string} [user] @property {string} [password]
|
|
7
|
+
* @property {string} [token] - 토큰 인증 (별도 축 — url/discrete 어느 쪽과도 조합 가능).
|
|
8
|
+
* @property {any} [pool] - 미지원 — 지정 시 `adapter.invalid_option` throw (NATS 는 단일 연결, ADR-112).
|
|
9
|
+
* @property {Record<string, any>} [options] - connect() passthrough (name, reconnect, maxReconnectAttempts, pingInterval, tls, jwt, nkey, …).
|
|
10
|
+
*/
|
|
11
|
+
export class MegaNatsAdapter extends MegaBusAdapter {
|
|
12
|
+
/**
|
|
13
|
+
* @param {NatsConfig} [config] - services.buses.<key> 설정.
|
|
14
|
+
* @throws {MegaValidationError} `adapter.connection_required` - url·discrete 둘 다 없음.
|
|
15
|
+
* @throws {MegaValidationError} `adapter.connection_conflict` - url + discrete 동시 지정.
|
|
16
|
+
* @throws {MegaValidationError} `adapter.invalid_option` - pool 지정/옵션 타입 오류.
|
|
17
|
+
*/
|
|
18
|
+
constructor(config?: NatsConfig);
|
|
19
|
+
/**
|
|
20
|
+
* raw NatsConnection handle (ADR-009). `connect()` 후에만 베이스 `native` getter 가 호출한다.
|
|
21
|
+
* @protected
|
|
22
|
+
* @returns {import('nats').NatsConnection}
|
|
23
|
+
*/
|
|
24
|
+
protected _native(): import("nats").NatsConnection;
|
|
25
|
+
/**
|
|
26
|
+
* 헬스 체크 — 실제 `rtt`(서버 왕복 ping)로 응답성 확인. 실패는 throw 없이 `ok:false` + 사유.
|
|
27
|
+
* @returns {Promise<{ ok: boolean, driver: 'nats', state: string, server?: string, rttMs?: number, error?: string }>}
|
|
28
|
+
*/
|
|
29
|
+
healthCheck(): Promise<{
|
|
30
|
+
ok: boolean;
|
|
31
|
+
driver: "nats";
|
|
32
|
+
state: string;
|
|
33
|
+
server?: string;
|
|
34
|
+
rttMs?: number;
|
|
35
|
+
error?: string;
|
|
36
|
+
}>;
|
|
37
|
+
/**
|
|
38
|
+
* 누적 통계 + nats 특화(server + 연결 stats). 연결 전이면 server/stats 는 undefined.
|
|
39
|
+
* @returns {ReturnType<import('./mega-adapter.js').MegaAdapter['getStats']> & { driver: string, server: string | undefined, nats: import('nats').Stats | undefined }}
|
|
40
|
+
*/
|
|
41
|
+
getStats(): ReturnType<import("./mega-adapter.js").MegaAdapter["getStats"]> & {
|
|
42
|
+
driver: string;
|
|
43
|
+
server: string | undefined;
|
|
44
|
+
nats: import("nats").Stats | undefined;
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* 잡 enqueue — 단순 publish (queue group 분배는 `process` 측 책임, ADR-112).
|
|
48
|
+
* @param {string} jobName
|
|
49
|
+
* @param {any} payload
|
|
50
|
+
* @returns {Promise<void>}
|
|
51
|
+
*/
|
|
52
|
+
enqueue(jobName: string, payload: any): Promise<void>;
|
|
53
|
+
/**
|
|
54
|
+
* 잡 처리 등록 — **queue group** 구독(같은 queue 구독자끼리 load-balance). 기본 queue 이름은 jobName
|
|
55
|
+
* (같은 잡의 모든 워커가 한 그룹).
|
|
56
|
+
*
|
|
57
|
+
* ⚠️ **전달 보장 = at-most-once(비영속, H5)**: 이건 **core NATS** queue group 이라 메시지가 디스크에
|
|
58
|
+
* 남지 않는다 — 구독자가 없거나 처리 중 죽으면 그 메시지는 **유실**된다(재시도·DLQ 없음). 유실이
|
|
59
|
+
* 치명적이거나 영속 큐/재시도/DLQ 가 필요하면 **`MegaJobQueue`(JetStream, at-least-once, ADR-028/112)**
|
|
60
|
+
* 를 쓴다. `ctx.bus(x).process` 와 `mega worker`(JetStream) 는 **전달 보장이 다르므로 혼용 금지**.
|
|
61
|
+
*
|
|
62
|
+
* **subscription 핸들을 반환하지 않는 건 의도적**(L-2): worker 는 앱 수명 동안 상주하는 것이
|
|
63
|
+
* 정상이고(개별 잡 처리 등록을 런타임에 떼었다 붙였다 하는 패턴은 비표준), 정리는 disconnect 시
|
|
64
|
+
* `_disconnect()` 의 `nc.drain()` 이 **모든 구독을 일괄 비우며** 처리한다. 개별 unsubscribe 가
|
|
65
|
+
* 필요한 일시 구독은 `subscribe()`(핸들 반환)를 쓴다 — `process` 는 fire-and-forget `enqueue` 와
|
|
66
|
+
* 대칭인 상주 worker 용이다.
|
|
67
|
+
*
|
|
68
|
+
* @param {string} jobName
|
|
69
|
+
* @param {(payload: any) => any} handler
|
|
70
|
+
* @param {{ queue?: string }} [opts]
|
|
71
|
+
* @returns {Promise<void>}
|
|
72
|
+
*/
|
|
73
|
+
process(jobName: string, handler: (payload: any) => any, { queue }?: {
|
|
74
|
+
queue?: string;
|
|
75
|
+
}): Promise<void>;
|
|
76
|
+
#private;
|
|
77
|
+
}
|
|
78
|
+
export type NatsConfig = {
|
|
79
|
+
/**
|
|
80
|
+
* - 'nats' (매니저가 사용 — 어댑터는 무시).
|
|
81
|
+
*/
|
|
82
|
+
driver?: string;
|
|
83
|
+
/**
|
|
84
|
+
* - `nats://host:port` 연결 문자열 (discrete 와 배타).
|
|
85
|
+
*/
|
|
86
|
+
url?: string;
|
|
87
|
+
/**
|
|
88
|
+
* - `url` 의 deprecated 별칭 (하위 호환).
|
|
89
|
+
*/
|
|
90
|
+
connectionString?: string;
|
|
91
|
+
host?: string;
|
|
92
|
+
port?: number;
|
|
93
|
+
user?: string;
|
|
94
|
+
password?: string;
|
|
95
|
+
/**
|
|
96
|
+
* - 토큰 인증 (별도 축 — url/discrete 어느 쪽과도 조합 가능).
|
|
97
|
+
*/
|
|
98
|
+
token?: string;
|
|
99
|
+
/**
|
|
100
|
+
* - 미지원 — 지정 시 `adapter.invalid_option` throw (NATS 는 단일 연결, ADR-112).
|
|
101
|
+
*/
|
|
102
|
+
pool?: any;
|
|
103
|
+
/**
|
|
104
|
+
* - connect() passthrough (name, reconnect, maxReconnectAttempts, pingInterval, tls, jwt, nkey, …).
|
|
105
|
+
*/
|
|
106
|
+
options?: Record<string, any>;
|
|
107
|
+
};
|
|
108
|
+
import { MegaBusAdapter } from './mega-bus-adapter.js';
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {object} PostgresConfig
|
|
3
|
+
* @property {string} [driver] - 'postgres' (매니저가 사용 — 어댑터는 무시).
|
|
4
|
+
* @property {string} [url] - `postgres://user:pw@host:port/db` (discrete 필드와 배타).
|
|
5
|
+
* @property {string} [connectionString] - `url` 의 deprecated 별칭 (하위 호환).
|
|
6
|
+
* @property {string} [host] @property {number} [port] @property {string} [user]
|
|
7
|
+
* @property {string} [password] @property {string} [database]
|
|
8
|
+
* @property {{ min?: number, max?: number, idleTimeoutMs?: number, acquireTimeoutMs?: number, maxLifetimeMs?: number }} [pool] - 공통 풀 인터페이스.
|
|
9
|
+
* @property {Record<string, any>} [options] - pg.Pool passthrough (ssl, statement_timeout, application_name, keepAlive, query_timeout, …).
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* @typedef {object} PgTxContext - AsyncLocalStorage 에 담기는 트랜잭션 컨텍스트.
|
|
13
|
+
* @property {import('pg').PoolClient} client - 이 트랜잭션을 소유한 풀 클라이언트.
|
|
14
|
+
* @property {number} depth - nesting 깊이 (top-level=0, 첫 nested=1, ...).
|
|
15
|
+
*/
|
|
16
|
+
export class MegaPostgresAdapter extends MegaDbAdapter {
|
|
17
|
+
/**
|
|
18
|
+
* @param {PostgresConfig} [config] - services.databases.<key> 설정.
|
|
19
|
+
* @throws {import('../errors/http-errors.js').MegaValidationError} `adapter.connection_required` - url·discrete 둘 다 없음.
|
|
20
|
+
* @throws {import('../errors/http-errors.js').MegaValidationError} `adapter.connection_conflict` - url + discrete 동시 지정.
|
|
21
|
+
* @throws {import('../errors/http-errors.js').MegaValidationError} `adapter.invalid_option` - 옵션 타입/범위 오류.
|
|
22
|
+
*/
|
|
23
|
+
constructor(config?: PostgresConfig);
|
|
24
|
+
/** driver 식별자 — dialect 디스패치(getDialect)·CRUD 의 단일 출처(ADR-212). @returns {'postgres'} */
|
|
25
|
+
get driver(): "postgres";
|
|
26
|
+
/**
|
|
27
|
+
* raw Pool handle (ADR-009). `connect()` 후에만 베이스 `native` getter 가 호출한다.
|
|
28
|
+
* @protected
|
|
29
|
+
* @returns {import('pg').Pool}
|
|
30
|
+
*/
|
|
31
|
+
protected _native(): import("pg").Pool;
|
|
32
|
+
/**
|
|
33
|
+
* 헬스 체크 — 실제 `SELECT 1` 으로 응답성 확인 (베이스 디폴트는 상태만 반영).
|
|
34
|
+
* 실패는 throw 없이 `ok:false` + 사유(베이스 계약). 비밀번호/connectionString 은 노출하지 않는다.
|
|
35
|
+
*
|
|
36
|
+
* @returns {Promise<{ ok: boolean, driver: 'postgres', state: string, error?: string }>}
|
|
37
|
+
*/
|
|
38
|
+
healthCheck(): Promise<{
|
|
39
|
+
ok: boolean;
|
|
40
|
+
driver: "postgres";
|
|
41
|
+
state: string;
|
|
42
|
+
error?: string;
|
|
43
|
+
}>;
|
|
44
|
+
/**
|
|
45
|
+
* 누적 통계 + 풀 통계(total/idle/waiting). 연결 전이면 풀 통계는 0.
|
|
46
|
+
* @returns {ReturnType<import('./mega-adapter.js').MegaAdapter['getStats']> & { driver: string, pool: { total: number, idle: number, waiting: number } }}
|
|
47
|
+
*/
|
|
48
|
+
getStats(): ReturnType<import("./mega-adapter.js").MegaAdapter["getStats"]> & {
|
|
49
|
+
driver: string;
|
|
50
|
+
pool: {
|
|
51
|
+
total: number;
|
|
52
|
+
idle: number;
|
|
53
|
+
waiting: number;
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* 명시적 트랜잭션 경계 (ADR-010, ADR-106). top-level 은 풀 클라이언트 1개 위 manual
|
|
58
|
+
* `BEGIN/COMMIT/ROLLBACK`, nested 는 같은 클라이언트 위 `SAVEPOINT`(모듈 docstring 참조).
|
|
59
|
+
*
|
|
60
|
+
* `fn` 은 **트랜잭션 컨텍스트 클라이언트**(pg PoolClient)를 인자로 받는다. 성공 시 COMMIT(또는
|
|
61
|
+
* RELEASE SAVEPOINT) 후 `fn` 반환값을 그대로 돌려주고, throw 시 ROLLBACK(또는 ROLLBACK TO
|
|
62
|
+
* SAVEPOINT) 후 원본 에러를 re-throw 한다.
|
|
63
|
+
*
|
|
64
|
+
* `opts.isolation`(ADR-190) — top-level 이면 `BEGIN` 직후 `SET TRANSACTION ISOLATION LEVEL` 로
|
|
65
|
+
* 반영한다(PostgreSQL 은 트랜잭션 첫 쿼리 전이라 유효). 격리수준은 트랜잭션 시작 시 고정되므로
|
|
66
|
+
* nested(SAVEPOINT) 호출에 지정하면 `adapter.nested_isolation_unsupported` 로 거부한다.
|
|
67
|
+
*
|
|
68
|
+
* hook(`onCallStart/onCallEnd`) + 상태 검증 + stats 누적은 `_instrument` 가 처리한다(ADR-077).
|
|
69
|
+
*
|
|
70
|
+
* @template T
|
|
71
|
+
* @param {(client: import('pg').PoolClient) => Promise<T> | T} fn
|
|
72
|
+
* @param {{ isolation?: 'read uncommitted' | 'read committed' | 'repeatable read' | 'serializable' }} [opts] - 트랜잭션 옵션(ADR-190).
|
|
73
|
+
* @returns {Promise<T>}
|
|
74
|
+
* @throws {MegaInternalError} `adapter.nested_isolation_unsupported` - nested 호출에 isolation 지정.
|
|
75
|
+
*/
|
|
76
|
+
withTransaction<T>(fn: (client: import("pg").PoolClient) => Promise<T> | T, opts?: {
|
|
77
|
+
isolation?: "read uncommitted" | "read committed" | "repeatable read" | "serializable";
|
|
78
|
+
}): Promise<T>;
|
|
79
|
+
/**
|
|
80
|
+
* 계측된 SQL 쿼리 (ADR-138). 진행 중 트랜잭션이 있으면 그 컨텍스트의 클라이언트를, 없으면 풀을
|
|
81
|
+
* 통해 실행한다 — 트랜잭션 안에서 호출해도 같은 connection 을 써 격리가 유지된다(풀의 다른
|
|
82
|
+
* 커넥션을 잡아 트랜잭션 밖으로 새지 않음). `_instrument('query', …)` 가 자동 span(`postgres.query`,
|
|
83
|
+
* `db.system.name`/`db.query.text`/`mega.rows_affected`)·stats·상태 검증을 처리한다. 결과는 pg 의
|
|
84
|
+
* `QueryResult`(`{ rows, rowCount, … }`)를 그대로 돌려준다(ADR-009).
|
|
85
|
+
*
|
|
86
|
+
* @param {string} sql - 파라미터화된 SQL(placeholder `$1` 보존).
|
|
87
|
+
* @param {any[]} [params] - placeholder 바인딩 값.
|
|
88
|
+
* @returns {Promise<import('pg').QueryResult>}
|
|
89
|
+
*/
|
|
90
|
+
query(sql: string, params?: any[]): Promise<import("pg").QueryResult>;
|
|
91
|
+
#private;
|
|
92
|
+
}
|
|
93
|
+
export type PostgresConfig = {
|
|
94
|
+
/**
|
|
95
|
+
* - 'postgres' (매니저가 사용 — 어댑터는 무시).
|
|
96
|
+
*/
|
|
97
|
+
driver?: string;
|
|
98
|
+
/**
|
|
99
|
+
* - `postgres://user:pw@host:port/db` (discrete 필드와 배타).
|
|
100
|
+
*/
|
|
101
|
+
url?: string;
|
|
102
|
+
/**
|
|
103
|
+
* - `url` 의 deprecated 별칭 (하위 호환).
|
|
104
|
+
*/
|
|
105
|
+
connectionString?: string;
|
|
106
|
+
host?: string;
|
|
107
|
+
port?: number;
|
|
108
|
+
user?: string;
|
|
109
|
+
password?: string;
|
|
110
|
+
database?: string;
|
|
111
|
+
/**
|
|
112
|
+
* - 공통 풀 인터페이스.
|
|
113
|
+
*/
|
|
114
|
+
pool?: {
|
|
115
|
+
min?: number;
|
|
116
|
+
max?: number;
|
|
117
|
+
idleTimeoutMs?: number;
|
|
118
|
+
acquireTimeoutMs?: number;
|
|
119
|
+
maxLifetimeMs?: number;
|
|
120
|
+
};
|
|
121
|
+
/**
|
|
122
|
+
* - pg.Pool passthrough (ssl, statement_timeout, application_name, keepAlive, query_timeout, …).
|
|
123
|
+
*/
|
|
124
|
+
options?: Record<string, any>;
|
|
125
|
+
};
|
|
126
|
+
/**
|
|
127
|
+
* - AsyncLocalStorage 에 담기는 트랜잭션 컨텍스트.
|
|
128
|
+
*/
|
|
129
|
+
export type PgTxContext = {
|
|
130
|
+
/**
|
|
131
|
+
* - 이 트랜잭션을 소유한 풀 클라이언트.
|
|
132
|
+
*/
|
|
133
|
+
client: import("pg").PoolClient;
|
|
134
|
+
/**
|
|
135
|
+
* - nesting 깊이 (top-level=0, 첫 nested=1, ...).
|
|
136
|
+
*/
|
|
137
|
+
depth: number;
|
|
138
|
+
};
|
|
139
|
+
import { MegaDbAdapter } from './mega-db-adapter.js';
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
export class MegaRedisAdapter extends MegaCacheAdapter {
|
|
2
|
+
/**
|
|
3
|
+
* @param {RedisConfig} [config] - services.caches.<key> 설정.
|
|
4
|
+
* @throws {MegaValidationError} `adapter.connection_required` - url·discrete 둘 다 없음.
|
|
5
|
+
* @throws {MegaValidationError} `adapter.connection_conflict` - url + discrete 동시 지정.
|
|
6
|
+
* @throws {MegaValidationError} `adapter.invalid_option` - pool 지정/옵션 타입 오류/db 범위 오류.
|
|
7
|
+
*/
|
|
8
|
+
constructor(config?: RedisConfig);
|
|
9
|
+
/**
|
|
10
|
+
* raw ioredis handle (ADR-009). `connect()` 후에만 베이스 `native` getter 가 호출한다.
|
|
11
|
+
* @protected
|
|
12
|
+
* @returns {import('ioredis').Redis}
|
|
13
|
+
*/
|
|
14
|
+
protected _native(): import("ioredis").Redis;
|
|
15
|
+
/**
|
|
16
|
+
* 헬스 체크 — 실제 `ping` 으로 응답성 확인 (베이스 디폴트는 상태만 반영).
|
|
17
|
+
* 실패는 throw 없이 `ok:false` + 사유(베이스 계약). 비밀번호/url 은 노출하지 않는다.
|
|
18
|
+
*
|
|
19
|
+
* @returns {Promise<{ ok: boolean, driver: 'redis', state: string, db?: number, error?: string }>}
|
|
20
|
+
*/
|
|
21
|
+
healthCheck(): Promise<{
|
|
22
|
+
ok: boolean;
|
|
23
|
+
driver: "redis";
|
|
24
|
+
state: string;
|
|
25
|
+
db?: number;
|
|
26
|
+
error?: string;
|
|
27
|
+
}>;
|
|
28
|
+
/**
|
|
29
|
+
* 누적 통계 + redis 특화(driver/db/연결 status). 연결 status 는 ioredis 의 connection 상태 문자열
|
|
30
|
+
* ('wait'|'connecting'|'connect'|'ready'|'close'|'end' 등) — 풀이 없어 이걸 노출한다.
|
|
31
|
+
* @returns {ReturnType<import('./mega-adapter.js').MegaAdapter['getStats']> & { driver: string, db: number | undefined, status: string | undefined }}
|
|
32
|
+
*/
|
|
33
|
+
getStats(): ReturnType<import("./mega-adapter.js").MegaAdapter["getStats"]> & {
|
|
34
|
+
driver: string;
|
|
35
|
+
db: number | undefined;
|
|
36
|
+
status: string | undefined;
|
|
37
|
+
};
|
|
38
|
+
#private;
|
|
39
|
+
}
|
|
40
|
+
export type RedisConfig = {
|
|
41
|
+
/**
|
|
42
|
+
* - 'redis' (매니저가 사용 — 어댑터는 무시).
|
|
43
|
+
*/
|
|
44
|
+
driver?: string;
|
|
45
|
+
/**
|
|
46
|
+
* - `redis://[:pw@]host:port[/db]` 연결 문자열 (discrete 와 배타).
|
|
47
|
+
*/
|
|
48
|
+
url?: string;
|
|
49
|
+
/**
|
|
50
|
+
* - `url` 의 deprecated 별칭 (하위 호환).
|
|
51
|
+
*/
|
|
52
|
+
connectionString?: string;
|
|
53
|
+
host?: string;
|
|
54
|
+
port?: number;
|
|
55
|
+
user?: string;
|
|
56
|
+
password?: string;
|
|
57
|
+
/**
|
|
58
|
+
* - 논리 DB 번호 0~15 (connection 과 별개 축, url path 보다 우선).
|
|
59
|
+
*/
|
|
60
|
+
db?: number;
|
|
61
|
+
/**
|
|
62
|
+
* - 미지원 — 지정 시 `adapter.invalid_option` throw (Redis 는 풀 모델 아님, ADR-110).
|
|
63
|
+
*/
|
|
64
|
+
pool?: any;
|
|
65
|
+
/**
|
|
66
|
+
* - ioredis passthrough (keyPrefix, commandTimeout, tls, retryStrategy, keepAlive, …).
|
|
67
|
+
*/
|
|
68
|
+
options?: Record<string, any>;
|
|
69
|
+
};
|
|
70
|
+
import { MegaCacheAdapter } from './mega-cache-adapter.js';
|