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.
- package/bin/mega-ws-hub.js +2 -2
- package/package.json +32 -8
- package/sample/crud/.env +1 -1
- package/sample/crud/.env.example +1 -1
- 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 +3 -2
- package/sample/crud/package.json +1 -1
- 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 +353 -100
- package/src/core/ajv-mapper.js +27 -2
- package/src/core/boot.js +464 -245
- package/src/core/cluster-metrics.js +13 -4
- 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 +201 -463
- package/src/core/mega-cluster.js +4 -1
- 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/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-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 +114 -39
- 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,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* μ± `views` config λ₯Ό μ κ·ννλ€. `dir` μ΄ μμΌλ©΄ null(μ΅νΈμΈ λ―Ένμ± β i18n normalizeI18n ν¨ν΄ μ ν©).
|
|
3
|
+
*
|
|
4
|
+
* @param {unknown} views - μ± config μ `views` ν€.
|
|
5
|
+
* @returns {{ dir: string, layoutDir: string, partialsDir: string, defaultLayout: string|null, cache: boolean }|null}
|
|
6
|
+
*/
|
|
7
|
+
export function normalizeViews(views: unknown): {
|
|
8
|
+
dir: string;
|
|
9
|
+
layoutDir: string;
|
|
10
|
+
partialsDir: string;
|
|
11
|
+
defaultLayout: string | null;
|
|
12
|
+
cache: boolean;
|
|
13
|
+
} | null;
|
|
14
|
+
/**
|
|
15
|
+
* view/layout μ΄λ¦μ λ·° λ£¨νΈ κΈ°μ€ μ λ κ²½λ‘λ‘ νκ³ , κ·Έ κ²½λ‘κ° **λ·° λ£¨νΈ λ΄λΆ**μΈμ§ κ²μ¦νλ€(κ²½λ‘ νμ μ°¨λ¨).
|
|
16
|
+
* νμ₯μκ° μμΌλ©΄ `.ejs` λ₯Ό λΆμΈλ€. 루νΈλ₯Ό λ²μ΄λλ©΄ 400 throw(LFI λ°©μ΄ β multipart sanitize μ΄μ€ λ°©μ΄ μ ν©).
|
|
17
|
+
*
|
|
18
|
+
* @param {string} dir - λ·° 루νΈ(μ λκ²½λ‘).
|
|
19
|
+
* @param {string} name - view λλ layout μλ μ΄λ¦(μ 'posts/show', 'layouts/main').
|
|
20
|
+
* @param {'view'|'layout'} kind - μλ¬ λ©μμ§ κ΅¬λΆμ©.
|
|
21
|
+
* @returns {string} κ²μ¦λ μ λ κ²½λ‘.
|
|
22
|
+
* @throws {MegaValidationError} λ·° 루νΈλ₯Ό λ²μ΄λλ©΄ `template.invalid_view`.
|
|
23
|
+
*/
|
|
24
|
+
export function resolveViewPath(dir: string, name: string, kind?: "view" | "layout"): string;
|
|
25
|
+
/**
|
|
26
|
+
* μμ λ λ β λ·°λ₯Ό HTML λ¬Έμμ΄λ‘ λ§λ λ€(send μμ΄). `MegaTemplate#render` 본체μ΄μ reply.render μ μ½μ΄.
|
|
27
|
+
* νΈλ μ΄μ± span + λ©νΈλ¦μ μ¬κΈ°μ 1ν κΈ°λ‘νλ€(reply.renderΒ·ctx.render κ° κ³΅μ ).
|
|
28
|
+
*
|
|
29
|
+
* @param {{ dir: string, layoutDir: string, partialsDir: string, defaultLayout: string|null, cache: boolean }} cfg
|
|
30
|
+
* @param {string} view - λ·° λ£¨νΈ κΈ°μ€ μλ μ΄λ¦(μ 'posts/show').
|
|
31
|
+
* @param {object} [data] - ν
νλ¦Ώ λ‘컬(λ°μ΄ν°). μμ½ ν€ `t`/`lang`/`settings`/`cache` λ νλ μμν¬κ° μ±μ΄λ€.
|
|
32
|
+
* @param {{ layout?: string|false }} [opts] - `layout` μΌλ‘ λ μ΄μμ override(false λ©΄ λ μ΄μμ κ°μ ν΄μ ).
|
|
33
|
+
* @param {{ app?: string }} [meta] - λ©νΈλ¦ app λΌλ²¨.
|
|
34
|
+
* @returns {Promise<string>} λ λλ HTML.
|
|
35
|
+
* @throws {MegaValidationError} κ²½λ‘ νμ κ±°λΆ(400). @throws {MegaInternalError} λ λ μ€ν¨(500).
|
|
36
|
+
*/
|
|
37
|
+
export function renderView(cfg: {
|
|
38
|
+
dir: string;
|
|
39
|
+
layoutDir: string;
|
|
40
|
+
partialsDir: string;
|
|
41
|
+
defaultLayout: string | null;
|
|
42
|
+
cache: boolean;
|
|
43
|
+
}, view: string, data?: object, opts?: {
|
|
44
|
+
layout?: string | false;
|
|
45
|
+
}, meta?: {
|
|
46
|
+
app?: string;
|
|
47
|
+
}): Promise<string>;
|
|
48
|
+
/**
|
|
49
|
+
* MegaApp μ ν
νλ¦Ώμ μ΅νΈμΈ λ±λ‘νλ€. `views.dir` μ΄ μμ λλ§ `reply.render` λ°μ½λ μ΄ν°λ₯Ό λ¨λ€(μμΌλ©΄
|
|
50
|
+
* λ―Έλ±λ‘ β render νΈμΆ μ Fastify κ° 'reply.render is not a function' μΌλ‘ fail-fast, μ΅νΈμΈ λͺ
μ).
|
|
51
|
+
*
|
|
52
|
+
* `reply.render` λ μ λ³Έ `res.render(view, data, { layout })`(docs/03 Β§618):
|
|
53
|
+
* - μμ²λ³ i18n `t`/`lang`(`req.t`/`req.lang`, i18n λ―Έλ±λ‘μ΄λ©΄ passthrough)μ data μ μλ λ³ν©.
|
|
54
|
+
* - λ λ ν `Content-Type: text/html; charset=utf-8` λ‘ send. 체μ΄λμ©μΌλ‘ reply λ°ν.
|
|
55
|
+
*
|
|
56
|
+
* @param {import('fastify').FastifyInstance} fastify
|
|
57
|
+
* @param {object} args
|
|
58
|
+
* @param {unknown} [args.views] - μ± `views` config(`{ dir, layoutDir, partialsDir, defaultLayout, cache }`).
|
|
59
|
+
* @param {string} [args.appName] - λ©νΈλ¦Β·λ‘κ·Έ λΌλ²¨.
|
|
60
|
+
* @param {{ debug?: Function }} [args.logger]
|
|
61
|
+
* @returns {{ enabled: boolean, template: MegaTemplate|null }}
|
|
62
|
+
*/
|
|
63
|
+
export function registerTemplate(fastify: import("fastify").FastifyInstance, { views, appName, logger }?: {
|
|
64
|
+
views?: unknown;
|
|
65
|
+
appName?: string;
|
|
66
|
+
logger?: {
|
|
67
|
+
debug?: Function;
|
|
68
|
+
};
|
|
69
|
+
}): {
|
|
70
|
+
enabled: boolean;
|
|
71
|
+
template: MegaTemplate | null;
|
|
72
|
+
};
|
|
73
|
+
/** κ³ μ λ·° μμ§Β·νμ₯μ (ADR-011 β EJS). ejs-mate `settings['view engine']` κ³Ό μΌμΉμν¨λ€. */
|
|
74
|
+
export const VIEW_ENGINE: "ejs";
|
|
75
|
+
/** λ μ΄μμ λλ ν°λ¦¬ κΈ°λ³Έ κ΄λ‘ (02-architecture Β§11 β `views/layouts/`). */
|
|
76
|
+
export const DEFAULT_LAYOUT_DIR: "layouts";
|
|
77
|
+
/** νμ
λλ ν°λ¦¬ κΈ°λ³Έ κ΄λ‘ (02-architecture Β§11 β `views/partials/`). */
|
|
78
|
+
export const DEFAULT_PARTIALS_DIR: "partials";
|
|
79
|
+
/**
|
|
80
|
+
* μ λ³Έ `MegaTemplate`(docs/03 Β§892 / 06-class-diagrams) β μ΅νΈμΈ λ·° config λ₯Ό κ°μΌ thin wrapper.
|
|
81
|
+
* registerTemplate κ° μ±λΉ 1κ° λ§λ€μ΄ reply.render κ° μμνλ€. i18n/MegaTracing μ²λΌ 본체λ λͺ¨λ ν¨μν.
|
|
82
|
+
*/
|
|
83
|
+
export class MegaTemplate {
|
|
84
|
+
/** @param {unknown} views - μ± `views` config. @param {string} [appName] - λ©νΈλ¦ app λΌλ²¨. */
|
|
85
|
+
constructor(views: unknown, appName?: string);
|
|
86
|
+
/** @type {{ dir: string, layoutDir: string, partialsDir: string, defaultLayout: string|null, cache: boolean }} */
|
|
87
|
+
_cfg: {
|
|
88
|
+
dir: string;
|
|
89
|
+
layoutDir: string;
|
|
90
|
+
partialsDir: string;
|
|
91
|
+
defaultLayout: string | null;
|
|
92
|
+
cache: boolean;
|
|
93
|
+
};
|
|
94
|
+
/** @type {string|undefined} */
|
|
95
|
+
_app: string | undefined;
|
|
96
|
+
/**
|
|
97
|
+
* λ·°λ₯Ό HTML λ¬Έμμ΄λ‘ λ λ(send μμ΄) β docs/03 Β§892.
|
|
98
|
+
* @param {string} viewPath - λ·° λ£¨νΈ κΈ°μ€ μλ μ΄λ¦(μ 'posts/show').
|
|
99
|
+
* @param {object} [data]
|
|
100
|
+
* @param {{ layout?: string|false }} [opts]
|
|
101
|
+
* @returns {Promise<string>}
|
|
102
|
+
*/
|
|
103
|
+
render(viewPath: string, data?: object, opts?: {
|
|
104
|
+
layout?: string | false;
|
|
105
|
+
}): Promise<string>;
|
|
106
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `config.workers`(MegaWorker μλΈν΄λμ€ λ°°μ΄)λ‘λΆν° μ컀 ν μΈμ€ν΄μ€λ₯Ό λ§λ λ€(μμ§ start μ ν¨).
|
|
3
|
+
* config-validator κ° λ°°μ΄Β·ν΄λμ€ shape λ₯Ό λ¨Όμ κ²μ¦νμ§λ§, μ¬κΈ°μλ MegaWorker μλΈν΄λμ€Β·μ΄λ¦ μ€λ³΅μ
|
|
4
|
+
* λΆν
μμ μ fail-fast(νμ register ν¨ν΄).
|
|
5
|
+
*
|
|
6
|
+
* @param {{ workers?: Array<typeof MegaWorker> }} [globalConfig] - mega.config.js default export.
|
|
7
|
+
* @param {{ projectRoot?: string, registerShutdownHook?: boolean }} [opts]
|
|
8
|
+
* @returns {void}
|
|
9
|
+
* @throws {MegaConfigError} MegaWorker μλΈν΄λμ€κ° μλκ±°λ `static name` μ€λ³΅μΌ λ.
|
|
10
|
+
*/
|
|
11
|
+
export function buildWorkers(globalConfig?: {
|
|
12
|
+
workers?: Array<typeof MegaWorker>;
|
|
13
|
+
}, { projectRoot, registerShutdownHook }?: {
|
|
14
|
+
projectRoot?: string;
|
|
15
|
+
registerShutdownHook?: boolean;
|
|
16
|
+
}): void;
|
|
17
|
+
/**
|
|
18
|
+
* λͺ¨λ μ컀 νμ start νλ€(μ€λ λ/νλ‘μΈμ€ spawn). νλλΌλ μ€ν¨νλ©΄ μ΄λ―Έ start λ νμ λ±λ‘ μμ(LIFO)μΌλ‘
|
|
19
|
+
* stop ν λ€ μλ μλ¬λ₯Ό throw(fail-fast + leak λ°©μ§ β adapter-manager connectAll ν¨ν΄).
|
|
20
|
+
*
|
|
21
|
+
* @param {{ logger?: { debug?: Function, info?: Function, warn?: Function } }} [opts]
|
|
22
|
+
* @returns {Promise<void>}
|
|
23
|
+
*/
|
|
24
|
+
export function startAll({ logger }?: {
|
|
25
|
+
logger?: {
|
|
26
|
+
debug?: Function;
|
|
27
|
+
info?: Function;
|
|
28
|
+
warn?: Function;
|
|
29
|
+
};
|
|
30
|
+
}): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* `static name` μΌλ‘ μ컀 ν μ‘°ν. λ―Έλ±λ‘μ΄λ©΄ fail-fast(silent X β adapter-manager.get μ ν©).
|
|
33
|
+
* @param {string} name @returns {MegaWorker} @throws {MegaConfigError}
|
|
34
|
+
*/
|
|
35
|
+
export function get(name: string): MegaWorker;
|
|
36
|
+
/**
|
|
37
|
+
* λ±λ‘ μ¬λΆ(Boolean β has*, 컨벀μ
). @param {string} name @returns {boolean}
|
|
38
|
+
*/
|
|
39
|
+
export function has(name: string): boolean;
|
|
40
|
+
/**
|
|
41
|
+
* λ±λ‘λ μ컀 λ©ν μ€λ
μ·(λλ²κ·Έ/CLI). @returns {Array<{ name: string, mode: string, poolSize: number, started: boolean }>}
|
|
42
|
+
*/
|
|
43
|
+
export function list(): Array<{
|
|
44
|
+
name: string;
|
|
45
|
+
mode: string;
|
|
46
|
+
poolSize: number;
|
|
47
|
+
started: boolean;
|
|
48
|
+
}>;
|
|
49
|
+
/**
|
|
50
|
+
* `ctx.workers` λ‘ μ€ κ°μ²΄ β `ctx.workers.<name>.run(task)`. λ―Έλ±λ‘ μ΄λ¦ μ κ·Όμ fail-fast.
|
|
51
|
+
* λμΌ Proxy λ₯Ό boot ctxΒ·μμ² ctx κ° κ³΅μ νλ€(μ컀λ κΈλ‘λ² μμμ΄λΌ μμ²Β·μ± 무κ΄).
|
|
52
|
+
* @returns {Record<string, MegaWorker>}
|
|
53
|
+
*/
|
|
54
|
+
export function contextProxy(): Record<string, MegaWorker>;
|
|
55
|
+
/**
|
|
56
|
+
* λͺ¨λ μ컀 νμ graceful stop νλ€ β λ±λ‘ **μμ(LIFO)**. κ°λ³ μ€ν¨λ λΉμΉλͺ
μ (warn ν κ³μ).
|
|
57
|
+
* @param {{ logger?: { debug?: Function, warn?: Function } }} [opts]
|
|
58
|
+
* @returns {Promise<void>}
|
|
59
|
+
*/
|
|
60
|
+
export function stopAll({ logger }?: {
|
|
61
|
+
logger?: {
|
|
62
|
+
debug?: Function;
|
|
63
|
+
warn?: Function;
|
|
64
|
+
};
|
|
65
|
+
}): Promise<void>;
|
|
66
|
+
/**
|
|
67
|
+
* ν
μ€νΈμ© reset β μΈμ€ν΄μ€ λΉμ°κ³ shutdown hook ν΄μ (μ컀λ stop μ ν¨ β νΈμΆμκ° λ¨Όμ stopAll).
|
|
68
|
+
* @returns {void}
|
|
69
|
+
*/
|
|
70
|
+
export function _reset(): void;
|
|
71
|
+
/**
|
|
72
|
+
* Proxy get νΈλ©μ΄ throw νλ©΄ μ λλ "μ묡 μ‘°ν" string ν€ λͺ¨μ. `await`(then)Β·`JSON.stringify`(toJSON)Β·
|
|
73
|
+
* λ¬Έμμ΄/μμκ° λ³ν(toString/valueOf)Β·inspect λ₯(constructor/inspect)κ° μΌλ° κ°μ²΄μ μΌλ μ‘°ννλ ν€λΌ,
|
|
74
|
+
* λ―Έλ±λ‘ fail-fast λμ(μ€ν)κ³Ό ꡬλΆν΄ undefined λ₯Ό λλ €μ€λ€. κ°μ μ΄λ¦μ΄ μ€μ λ‘ λ±λ‘λΌ μμΌλ©΄ κ·Έλλ‘
|
|
75
|
+
* ν΄μνλ€. `then` μ Symbol μ΄ μλλΌ **string ν€**λ€ β Promise resolution μ΄ string 'then' μ μ‘°ννλ―λ‘
|
|
76
|
+
* μ΄ κ°λκ° μμΌλ©΄ `await ctx.workers`/`await ctx.services` κ° not_registered λ‘ μ£½λλ€.
|
|
77
|
+
*/
|
|
78
|
+
export const PROXY_PROTOCOL_KEYS: Set<string>;
|
|
79
|
+
import { MegaWorker } from '../lib/mega-worker.js';
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NATS κΈ°λ° WS ν΄λ¬μ€ν° fan-out + roster.
|
|
3
|
+
*
|
|
4
|
+
* μ± 1κ°λΉ 1 μΈμ€ν΄μ€. boot κ° μμ±Β·startΒ·shutdown μ κ΄λ¦¬νλ€(μλ λ°°μ ). subject λ μ± μ΄λ¦μΌλ‘
|
|
5
|
+
* 격리λμ΄(`<prefix>.<appName>.*`) λ€μ€ μ±μ΄ ν NATS λ₯Ό 곡μ ν΄λ μμ΄μ§ μλλ€.
|
|
6
|
+
*/
|
|
7
|
+
export class MegaWsCluster {
|
|
8
|
+
/**
|
|
9
|
+
* @param {Object} opts
|
|
10
|
+
* @param {import('../adapters/mega-bus-adapter.js').MegaBusAdapter} opts.bus - μ°κ²°λ NATS λ²μ€ μ΄λν°.
|
|
11
|
+
* @param {string} opts.appName - μ± μ΄λ¦(subject 격리 + λ‘κ·Έ).
|
|
12
|
+
* @param {(payload: { ns: string, channel?: string, message: { type: string, payload?: Object }, exceptSessionIds?: string[] }) => void} opts.deliverBroadcast -
|
|
13
|
+
* μμ ν broadcast λ₯Ό λ‘컬 μ°κ²°μ μ λ¬νλ μ½λ°±(λ³΄ν΅ `app._deliverBroadcast`).
|
|
14
|
+
* @param {(payload: { userId: string, message: { type: string, payload?: Object } }) => void} opts.deliverDirect -
|
|
15
|
+
* μμ ν direct λ₯Ό λ‘컬 μ°κ²°μ μ λ¬νλ μ½λ°±(λ³΄ν΅ `app._deliverDirect`).
|
|
16
|
+
* @param {{ debug?: Function, info?: Function, warn?: Function, error?: Function }} [opts.logger]
|
|
17
|
+
* @param {string} [opts.subjectPrefix] - subject μ λ(κΈ°λ³Έ 'mega.ws').
|
|
18
|
+
* @param {{ driver?: 'nats'|'none', ttlMs?: number }} [opts.roster] - roster λκΈ°ν μ€μ .
|
|
19
|
+
*/
|
|
20
|
+
constructor({ bus, appName, deliverBroadcast, deliverDirect, logger, subjectPrefix, roster }?: {
|
|
21
|
+
bus: import("../adapters/mega-bus-adapter.js").MegaBusAdapter;
|
|
22
|
+
appName: string;
|
|
23
|
+
deliverBroadcast: (payload: {
|
|
24
|
+
ns: string;
|
|
25
|
+
channel?: string;
|
|
26
|
+
message: {
|
|
27
|
+
type: string;
|
|
28
|
+
payload?: Object;
|
|
29
|
+
};
|
|
30
|
+
exceptSessionIds?: string[];
|
|
31
|
+
}) => void;
|
|
32
|
+
deliverDirect: (payload: {
|
|
33
|
+
userId: string;
|
|
34
|
+
message: {
|
|
35
|
+
type: string;
|
|
36
|
+
payload?: Object;
|
|
37
|
+
};
|
|
38
|
+
}) => void;
|
|
39
|
+
logger?: {
|
|
40
|
+
debug?: Function;
|
|
41
|
+
info?: Function;
|
|
42
|
+
warn?: Function;
|
|
43
|
+
error?: Function;
|
|
44
|
+
};
|
|
45
|
+
subjectPrefix?: string;
|
|
46
|
+
roster?: {
|
|
47
|
+
driver?: "nats" | "none";
|
|
48
|
+
ttlMs?: number;
|
|
49
|
+
};
|
|
50
|
+
});
|
|
51
|
+
/** @type {import('../adapters/mega-bus-adapter.js').MegaBusAdapter} */
|
|
52
|
+
_bus: import("../adapters/mega-bus-adapter.js").MegaBusAdapter;
|
|
53
|
+
_appName: string;
|
|
54
|
+
_deliverBroadcast: (payload: {
|
|
55
|
+
ns: string;
|
|
56
|
+
channel?: string;
|
|
57
|
+
message: {
|
|
58
|
+
type: string;
|
|
59
|
+
payload?: Object;
|
|
60
|
+
};
|
|
61
|
+
exceptSessionIds?: string[];
|
|
62
|
+
}) => void;
|
|
63
|
+
_deliverDirect: (payload: {
|
|
64
|
+
userId: string;
|
|
65
|
+
message: {
|
|
66
|
+
type: string;
|
|
67
|
+
payload?: Object;
|
|
68
|
+
};
|
|
69
|
+
}) => void;
|
|
70
|
+
_log: {
|
|
71
|
+
debug?: Function;
|
|
72
|
+
info?: Function;
|
|
73
|
+
warn?: Function;
|
|
74
|
+
error?: Function;
|
|
75
|
+
};
|
|
76
|
+
/** μ΄ νλ‘μΈμ€μ κ³ μ μλ³μ β echo ꡬλΆ. */
|
|
77
|
+
instanceId: string;
|
|
78
|
+
_subjBroadcast: string;
|
|
79
|
+
_subjDirect: string;
|
|
80
|
+
_subjRoster: string;
|
|
81
|
+
_rosterDriver: string;
|
|
82
|
+
_rosterTtlMs: number;
|
|
83
|
+
/** μ΄ μΈμ€ν΄μ€κ° 보μ ν λ‘컬 λ©€λ². sessionId β RosterMember. */
|
|
84
|
+
_localMembers: Map<any, any>;
|
|
85
|
+
/** ν΄λ¬μ€ν° μ μ view. sessionId β RosterMember & { instanceId, expiresAt }. */
|
|
86
|
+
_view: Map<any, any>;
|
|
87
|
+
/** @type {Array<{ unsubscribe: () => Promise<void> }>} νμ± κ΅¬λ
νΈλ€. */
|
|
88
|
+
_subs: Array<{
|
|
89
|
+
unsubscribe: () => Promise<void>;
|
|
90
|
+
}>;
|
|
91
|
+
/** @type {ReturnType<typeof setInterval>|null} */
|
|
92
|
+
_heartbeatTimer: ReturnType<typeof setInterval> | null;
|
|
93
|
+
/** @type {ReturnType<typeof setInterval>|null} */
|
|
94
|
+
_sweepTimer: ReturnType<typeof setInterval> | null;
|
|
95
|
+
_isStarted: boolean;
|
|
96
|
+
/** μμλλμ§. @returns {boolean} */
|
|
97
|
+
get isStarted(): boolean;
|
|
98
|
+
/**
|
|
99
|
+
* ꡬλ
μμ β broadcast/direct subject + (roster:'nats' λ©΄) roster subject λ₯Ό subscribe νκ³ , roster
|
|
100
|
+
* λκΈ°ν νμ΄λ¨Έ(heartbeat/sweep)λ₯Ό μΌκ³ , μ κ· μΈμ€ν΄μ€ sync_request λ₯Ό 보λΈλ€. λ©±λ±(μ€λ³΅ νΈμΆ 무μ).
|
|
101
|
+
* @returns {Promise<void>}
|
|
102
|
+
*/
|
|
103
|
+
start(): Promise<void>;
|
|
104
|
+
/**
|
|
105
|
+
* broadcast λ₯Ό ν΄λ¬μ€ν°λ‘ publish. μ‘μ μΈ‘μ μ΄λ―Έ λ‘컬 μ λ¬νμΌλ―λ‘ `o`(origin)λ‘ μκΈ° echo λ₯Ό νμνλ€.
|
|
106
|
+
* @param {{ ns: string, channel?: string, message: { type: string, payload?: Object }, exceptSessionIds?: string[] }} payload
|
|
107
|
+
* @returns {Promise<void>}
|
|
108
|
+
*/
|
|
109
|
+
publishBroadcast(payload: {
|
|
110
|
+
ns: string;
|
|
111
|
+
channel?: string;
|
|
112
|
+
message: {
|
|
113
|
+
type: string;
|
|
114
|
+
payload?: Object;
|
|
115
|
+
};
|
|
116
|
+
exceptSessionIds?: string[];
|
|
117
|
+
}): Promise<void>;
|
|
118
|
+
/**
|
|
119
|
+
* direct(νΉμ userId)λ₯Ό ν΄λ¬μ€ν°λ‘ publish β λ€λ₯Έ μΈμ€ν΄μ€μ κ°μ userId μΈμ
κΉμ§ λΏκ² νλ€.
|
|
120
|
+
* @param {string} userId
|
|
121
|
+
* @param {{ type: string, payload?: Object }} message
|
|
122
|
+
* @returns {Promise<void>}
|
|
123
|
+
*/
|
|
124
|
+
publishDirect(userId: string, message: {
|
|
125
|
+
type: string;
|
|
126
|
+
payload?: Object;
|
|
127
|
+
}): Promise<void>;
|
|
128
|
+
/**
|
|
129
|
+
* roster μ λ©€λ² μΆκ°(joinSession ν
). λ‘컬 보μ + μ μ view λ°μ + λΈν publish. roster:'none' μ΄λ©΄
|
|
130
|
+
* λ‘μ»¬λ§ κ°±μ νλ€.
|
|
131
|
+
* @param {RosterMember} member
|
|
132
|
+
* @returns {void}
|
|
133
|
+
*/
|
|
134
|
+
rosterAdd(member: RosterMember): void;
|
|
135
|
+
/**
|
|
136
|
+
* roster μμ λ©€λ² μ κ±°(disconnect ν
). λ‘컬 μ κ±° + μ μ view μ κ±° + λΈν publish.
|
|
137
|
+
* @param {string} sessionId
|
|
138
|
+
* @returns {void}
|
|
139
|
+
*/
|
|
140
|
+
rosterRemove(sessionId: string): void;
|
|
141
|
+
/**
|
|
142
|
+
* ν΄λΉ ns μ ν΄λ¬μ€ν° μ μ μ μμ λͺ©λ‘. roster:'none' μ΄λ©΄ λ‘컬 λ©€λ²λ§.
|
|
143
|
+
* @param {string} ns
|
|
144
|
+
* @returns {Array<{ sessionId: string, userId: string, metadata?: Object }>}
|
|
145
|
+
*/
|
|
146
|
+
roster(ns: string): Array<{
|
|
147
|
+
sessionId: string;
|
|
148
|
+
userId: string;
|
|
149
|
+
metadata?: Object;
|
|
150
|
+
}>;
|
|
151
|
+
/**
|
|
152
|
+
* μ 리 β νμ΄λ¨Έ ν΄μ + ꡬλ
ν΄μ + μκΈ° λ©€λ² LEAVE 곡μ§(graceful μ’
λ£ μ λ€λ₯Έ μΈμ€ν΄μ€ roster μ¦μ μ 리).
|
|
153
|
+
* @returns {Promise<void>}
|
|
154
|
+
*/
|
|
155
|
+
stop(): Promise<void>;
|
|
156
|
+
/**
|
|
157
|
+
* roster subject μμ μ²λ¦¬. μκΈ° echo λ 건λλ°λ, sync_request λ§μ μκΈ° μμ²μ΄μ΄λ 무κ΄(μλκ° μλ΅).
|
|
158
|
+
* @param {any} msg
|
|
159
|
+
* @returns {void}
|
|
160
|
+
* @private
|
|
161
|
+
*/
|
|
162
|
+
private _onRosterMessage;
|
|
163
|
+
/**
|
|
164
|
+
* view μ λ©€λ² upsert + λ§λ£μκ° κ°±μ . λ©€λ² μΆμ² instanceId λ₯Ό ν¨κ» μ μ₯(sweep νλ¨Β·μκΈ°λ©€λ² κ΅¬λΆ).
|
|
165
|
+
* @param {RosterMember} member @param {string} instanceId @returns {void}
|
|
166
|
+
* @private
|
|
167
|
+
*/
|
|
168
|
+
private _upsertView;
|
|
169
|
+
/**
|
|
170
|
+
* λ§λ£(heartbeat λκΈ΄ crash μΈμ€ν΄μ€) λ©€λ²λ₯Ό view μμ μ κ±°. μκΈ° λ©€λ²λ νμ fresh νλ―λ‘ μν₯ μμ.
|
|
171
|
+
* @returns {void}
|
|
172
|
+
* @private
|
|
173
|
+
*/
|
|
174
|
+
private _sweepExpired;
|
|
175
|
+
/**
|
|
176
|
+
* μκΈ° λ‘컬 λ©€λ² μ 체λ₯Ό heartbeat λ‘ κ³΅μ§(λ€λ₯Έ μΈμ€ν΄μ€μ TTL κ°±μ ) + μκΈ° view λ fresh μ μ§.
|
|
177
|
+
* @returns {Promise<void>}
|
|
178
|
+
* @private
|
|
179
|
+
*/
|
|
180
|
+
private _publishHeartbeat;
|
|
181
|
+
/**
|
|
182
|
+
* roster subject λ‘ λ©μμ§ publish(μκΈ° instanceId λ₯Ό origin μΌλ‘).
|
|
183
|
+
* @param {Object} body @returns {Promise<void>}
|
|
184
|
+
* @private
|
|
185
|
+
*/
|
|
186
|
+
private _publishRoster;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* roster λ©€λ²(ν΄λ¬μ€ν° 곡μ ). sessionId λ joinSession μ μ μ μΌ κ³μ½(ADR-098)μΌλ‘ ν€κ° λλ€.
|
|
190
|
+
*/
|
|
191
|
+
export type RosterMember = {
|
|
192
|
+
/**
|
|
193
|
+
* - WS namespace(μ±λ κ²½λ‘, μ: '/ws/chat').
|
|
194
|
+
*/
|
|
195
|
+
ns: string;
|
|
196
|
+
/**
|
|
197
|
+
* - μΈμ
μλ³μ(μ μ μ μΌ).
|
|
198
|
+
*/
|
|
199
|
+
sessionId: string;
|
|
200
|
+
/**
|
|
201
|
+
* - μ¬μ©μ μλ³μ.
|
|
202
|
+
*/
|
|
203
|
+
userId: string;
|
|
204
|
+
/**
|
|
205
|
+
* - presence λ©ν(λͺ
μ νλλ§).
|
|
206
|
+
*/
|
|
207
|
+
metadata?: Object;
|
|
208
|
+
};
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* μμΆ μ€μ κ²μ¦ β μλ° μ μ¬λμ΄ μ½μ μλ¬ λ©μμ§, ν΅κ³Ό μ null λ°ν(throw μ ν¨).
|
|
3
|
+
*
|
|
4
|
+
* νΈμΆλΆκ° 컨ν
μ€νΈ(MegaConfigError vs μΌλ° Error)μ λ§κ² wrap νλ€ β config-validator λ
|
|
5
|
+
* MegaConfigError λ‘, MegaApp/MegaWsHub μ§μ μμ± κ²½λ‘λ μΌλ° Error λ‘.
|
|
6
|
+
*
|
|
7
|
+
* @param {Partial<WsCompressionConfig>} [config] - MegaWebsocketCompressionConfig | MegaWsHubCompressionConfig.
|
|
8
|
+
* @param {string} [label='websocket.compression'] - μλ¬ λ©μμ§ prefix (μ: 'wsHub.compression').
|
|
9
|
+
* @returns {string | null} μλ° λ©μμ§ λλ null.
|
|
10
|
+
*/
|
|
11
|
+
export function checkCompressionConfig(config?: Partial<WsCompressionConfig>, label?: string): string | null;
|
|
12
|
+
/**
|
|
13
|
+
* μμΆ μ€μ β `ws` WebSocket(Server) μ `perMessageDeflate` κ°μΌλ‘ λ³ν.
|
|
14
|
+
*
|
|
15
|
+
* - `enabled !== true` β `false` (μμΆ λΉνμ±, ws κΈ°λ³Έκ°κ³Ό λμΌ).
|
|
16
|
+
* - `enabled === true` β 5 νλλ₯Ό λν΄νΈλ‘ μ±μ΄ perMessageDeflate μ΅μ
κ°μ²΄.
|
|
17
|
+
*
|
|
18
|
+
* λΆν
(config-validator)μμ μ΄λ―Έ κ²μ¦λμ§λ§, μ§μ μμ± κ²½λ‘(single λͺ¨λΒ·ν
μ€νΈ)λ₯Ό μν΄ μ¬κΈ°μλ
|
|
19
|
+
* λ°©μ΄μ μΌλ‘ κ²μ¦νλ€ β μλ° μ throw(silent κΈμ§).
|
|
20
|
+
*
|
|
21
|
+
* @param {Partial<WsCompressionConfig>} [config] - MegaWebsocketCompressionConfig | MegaWsHubCompressionConfig.
|
|
22
|
+
* @param {string} [label='websocket.compression'] - throw λ©μμ§ prefix.
|
|
23
|
+
* @returns {false | { threshold: number, serverNoContextTakeover: boolean, clientNoContextTakeover: boolean, serverMaxWindowBits: number, concurrencyLimit: number }}
|
|
24
|
+
* @throws {Error} threshold μμ / serverMaxWindowBits λ²μ μλ°.
|
|
25
|
+
*/
|
|
26
|
+
export function buildPerMessageDeflate(config?: Partial<WsCompressionConfig>, label?: string): false | {
|
|
27
|
+
threshold: number;
|
|
28
|
+
serverNoContextTakeover: boolean;
|
|
29
|
+
clientNoContextTakeover: boolean;
|
|
30
|
+
serverMaxWindowBits: number;
|
|
31
|
+
concurrencyLimit: number;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* WebSocket per-message deflate μμΆ μ΅μ
μ κ·ν (ADR-078).
|
|
35
|
+
*
|
|
36
|
+
* λ κ³³μ΄ κ°μ μ€ν€λ§λ₯Ό μ΄λ€(04-data-models Β§1.1/Β§2.1):
|
|
37
|
+
* - App-only `websocket.compression` β λΈλΌμ°μ βBridge(embedded WS, MegaApp `_ensureWss`)
|
|
38
|
+
* - Global `wsHub.compression` β BridgeβHub link (MegaWsHub μλ² + MegaHubLink ν΄λΌ)
|
|
39
|
+
*
|
|
40
|
+
* λ typedef(`MegaWebsocketCompressionConfig` / `MegaWsHubCompressionConfig`)μ 6 νλλ
|
|
41
|
+
* κ·Έλλ‘ `ws` ν¨ν€μ§μ `perMessageDeflate` μ΅μ
λͺ
κ³Ό 1:1 λ§€νλλ€(κ²μ¦: node_modules/ws/lib/
|
|
42
|
+
* permessage-deflate.js β threshold/serverNoContextTakeover/clientNoContextTakeover/
|
|
43
|
+
* serverMaxWindowBits/concurrencyLimit). `enabled` λ§ μ°λ¦¬ κ²μ΄νΈ β false λ©΄ μμΆ λΉνμ±
|
|
44
|
+
* (`perMessageDeflate: false`, ws κΈ°λ³Έκ°).
|
|
45
|
+
*
|
|
46
|
+
* # threshold μλ―Έ (ws μμ€ νμΈ)
|
|
47
|
+
* threshold λ **context takeover κ° λΉνμ±μΌ λλ§** μ μ©λλ€(sender.js: no_context_takeover
|
|
48
|
+
* negotiate μ `rsv1 = byteLength >= threshold`). ADR-078 μ΄ λ NoContextTakeover λν΄νΈλ₯Ό true λ‘
|
|
49
|
+
* λ μ΄μ β threshold κ° μ€μ λ‘ λμνκ³ μ°κ²°λΉ λ©λͺ¨λ¦¬λ μ κ°.
|
|
50
|
+
*
|
|
51
|
+
* # negotiate μ€ν¨ = μλ raw fallback
|
|
52
|
+
* `permessage-deflate` νμ₯μ μμͺ½μ΄ λͺ¨λ νμν΄μΌ νμ±(RFC 7692). νμͺ½μ΄ OFF(`false`)λ©΄ νμλμ§
|
|
53
|
+
* μμ μλμΌλ‘ raw ν΅μ μΌλ‘ λ¨μ΄μ§λ€ β λ³λ fallback μ½λ λΆνμ(ws λ΄μ₯ λμ).
|
|
54
|
+
*
|
|
55
|
+
* @module core/ws-compression
|
|
56
|
+
*/
|
|
57
|
+
/**
|
|
58
|
+
* μμΆ μ€μ β App `websocket.compression` κ³Ό Global `wsHub.compression` κ³΅ν΅ μ€ν€λ§ (ADR-078).
|
|
59
|
+
* 04-data-models μ `MegaWebsocketCompressionConfig` / `MegaWsHubCompressionConfig` μ λμΌ.
|
|
60
|
+
* @typedef {Object} WsCompressionConfig
|
|
61
|
+
* @property {boolean} enabled - λν΄νΈ false. μ΅νΈμΈ κ²μ΄νΈ.
|
|
62
|
+
* @property {number} [threshold] - byte. λν΄νΈ 1024. λ―Έλ§μ μμΆ μ°ν(NoContextTakeover μ).
|
|
63
|
+
* @property {boolean} [serverNoContextTakeover] - λν΄νΈ true (μ°κ²°λΉ λ©λͺ¨λ¦¬ μ κ°).
|
|
64
|
+
* @property {boolean} [clientNoContextTakeover] - λν΄νΈ true.
|
|
65
|
+
* @property {number} [serverMaxWindowBits] - λν΄νΈ 10. λ²μ 9~15 (λ²μ΄λλ©΄ λΆν
throw).
|
|
66
|
+
* @property {number} [concurrencyLimit] - λν΄νΈ 10.
|
|
67
|
+
*/
|
|
68
|
+
/**
|
|
69
|
+
* ADR-078 λν΄νΈκ°. `enabled` μΈ 5 νλλ `ws` perMessageDeflate μ κ·Έλλ‘ μ λ¬λλ€.
|
|
70
|
+
* @type {Readonly<{ enabled: boolean, threshold: number, serverNoContextTakeover: boolean, clientNoContextTakeover: boolean, serverMaxWindowBits: number, concurrencyLimit: number }>}
|
|
71
|
+
*/
|
|
72
|
+
export const COMPRESSION_DEFAULTS: Readonly<{
|
|
73
|
+
enabled: boolean;
|
|
74
|
+
threshold: number;
|
|
75
|
+
serverNoContextTakeover: boolean;
|
|
76
|
+
clientNoContextTakeover: boolean;
|
|
77
|
+
serverMaxWindowBits: number;
|
|
78
|
+
concurrencyLimit: number;
|
|
79
|
+
}>;
|
|
80
|
+
/** serverMaxWindowBits νμ© λ²μ (zlib windowBits μ΅μ 9 ~ RFC 7692 μ΅λ 15, ADR-078). */
|
|
81
|
+
export const SERVER_MAX_WINDOW_BITS_MIN: 9;
|
|
82
|
+
export const SERVER_MAX_WINDOW_BITS_MAX: 15;
|
|
83
|
+
/**
|
|
84
|
+
* μμΆ μ€μ β App `websocket.compression` κ³Ό Global `wsHub.compression` κ³΅ν΅ μ€ν€λ§ (ADR-078).
|
|
85
|
+
* 04-data-models μ `MegaWebsocketCompressionConfig` / `MegaWsHubCompressionConfig` μ λμΌ.
|
|
86
|
+
*/
|
|
87
|
+
export type WsCompressionConfig = {
|
|
88
|
+
/**
|
|
89
|
+
* - λν΄νΈ false. μ΅νΈμΈ κ²μ΄νΈ.
|
|
90
|
+
*/
|
|
91
|
+
enabled: boolean;
|
|
92
|
+
/**
|
|
93
|
+
* - byte. λν΄νΈ 1024. λ―Έλ§μ μμΆ μ°ν(NoContextTakeover μ).
|
|
94
|
+
*/
|
|
95
|
+
threshold?: number;
|
|
96
|
+
/**
|
|
97
|
+
* - λν΄νΈ true (μ°κ²°λΉ λ©λͺ¨λ¦¬ μ κ°).
|
|
98
|
+
*/
|
|
99
|
+
serverNoContextTakeover?: boolean;
|
|
100
|
+
/**
|
|
101
|
+
* - λν΄νΈ true.
|
|
102
|
+
*/
|
|
103
|
+
clientNoContextTakeover?: boolean;
|
|
104
|
+
/**
|
|
105
|
+
* - λν΄νΈ 10. λ²μ 9~15 (λ²μ΄λλ©΄ λΆν
throw).
|
|
106
|
+
*/
|
|
107
|
+
serverMaxWindowBits?: number;
|
|
108
|
+
/**
|
|
109
|
+
* - λν΄νΈ 10.
|
|
110
|
+
*/
|
|
111
|
+
concurrencyLimit?: number;
|
|
112
|
+
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
export class MegaWebSocketController {
|
|
2
|
+
/** @type {any} */ _ctxRef: any;
|
|
3
|
+
/** @type {any} */ _appRef: any;
|
|
4
|
+
/** @type {any} */ _logRef: any;
|
|
5
|
+
/** @type {any} */ _servicesRef: any;
|
|
6
|
+
/**
|
|
7
|
+
* νλ μμν¬κ° μ±λ μΈμ€ν΄μ€μ 컨ν
μ€νΈλ₯Ό λ°μΈλ©νλ€ (νμ Step μ upgrade μ²λ¦¬μμ νΈμΆ).
|
|
8
|
+
* **μ¬μ©μ μ½λλ νΈμΆνμ§ μλλ€** (framework-internal).
|
|
9
|
+
*
|
|
10
|
+
* @param {{ ctx?: any, app?: any, log?: any, services?: any }} [binding]
|
|
11
|
+
* @returns {void}
|
|
12
|
+
*/
|
|
13
|
+
_bind(binding?: {
|
|
14
|
+
ctx?: any;
|
|
15
|
+
app?: any;
|
|
16
|
+
log?: any;
|
|
17
|
+
services?: any;
|
|
18
|
+
}): void;
|
|
19
|
+
/** νμ¬ μ±λ 컨ν
μ€νΈ (λ―Έλ°μΈλ© μ null). */
|
|
20
|
+
get ctx(): any;
|
|
21
|
+
/** μμ MegaApp (λ―Έλ°μΈλ© μ null). */
|
|
22
|
+
get app(): any;
|
|
23
|
+
/** request_id μλ μ£Όμ
λ‘κ±° (λ―Έλ°μΈλ© μ null). */
|
|
24
|
+
get log(): any;
|
|
25
|
+
/** μλ DI νΈλ€ β `ctx.services` μ λμΌ (λ―Έλ°μΈλ© μ null). */
|
|
26
|
+
get services(): any;
|
|
27
|
+
/**
|
|
28
|
+
* μ°κ²° μ립 μ 1ν νΈμΆ. κΈ°λ³Έ no-op β μλΈν΄λμ€κ° override.
|
|
29
|
+
* @param {any} _sock - WS μμΌ.
|
|
30
|
+
* @param {any} _ctx - μ±λ 컨ν
μ€νΈ.
|
|
31
|
+
* @returns {Promise<void>}
|
|
32
|
+
*/
|
|
33
|
+
onConnect(_sock: any, _ctx: any): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* λμ€ν¨μΉλμ§ μμ λ©μμ§μ ν΄λ°± νΈλ€λ¬. κΈ°λ³Έ no-op β μλΈν΄λμ€κ° override.
|
|
36
|
+
* @param {any} _sock - WS μμΌ.
|
|
37
|
+
* @param {Object} _msg - κ²μ¦λ WS envelope.
|
|
38
|
+
* @param {any} _ctx - μ±λ 컨ν
μ€νΈ.
|
|
39
|
+
* @returns {Promise<any>}
|
|
40
|
+
*/
|
|
41
|
+
onMessage(_sock: any, _msg: Object, _ctx: any): Promise<any>;
|
|
42
|
+
/**
|
|
43
|
+
* μ°κ²° μ’
λ£ μ νΈμΆ. κΈ°λ³Έ no-op β μλΈν΄λμ€κ° override.
|
|
44
|
+
* @param {any} _sock - WS μμΌ.
|
|
45
|
+
* @param {any} _ctx - μ±λ 컨ν
μ€νΈ.
|
|
46
|
+
* @returns {Promise<void>}
|
|
47
|
+
*/
|
|
48
|
+
onDisconnect(_sock: any, _ctx: any): Promise<void>;
|
|
49
|
+
/**
|
|
50
|
+
* μμ λ©μμ§ μλ λμ€ν¨μΉ (ADR-015). νλ μμν¬(νμ Step)κ° μμΌ message λ§λ€ νΈμΆνλ€.
|
|
51
|
+
*
|
|
52
|
+
* `msg.type` μ΄ `domain.action` ν¨ν΄({@link WS_TYPE_PATTERN}) μ΄κ³ λλͺ
λ©μλκ° μμΌλ©΄ κ·Έ
|
|
53
|
+
* λ©μλλ₯Ό, μλλ©΄ {@link MegaWebSocketController#onMessage} ν΄λ°±μ νΈμΆνλ€. ν¨ν΄μ΄ μ (`.`)μ
|
|
54
|
+
* κ°μ νλ―λ‘ `constructor` / `onMessage` κ°μ λ² μ΄μ€ λ©€λ²λͺ
μ type μΌλ‘ λ§€μΉλ μ μλ€ β
|
|
55
|
+
* prototype μ€μΌ / μλμΉ μμ λ² μ΄μ€ νΈμΆμ ꡬ쑰μ μΌλ‘ μ°¨λ¨.
|
|
56
|
+
*
|
|
57
|
+
* @param {any} sock - WS μμΌ.
|
|
58
|
+
* @param {{ type?: string }} msg - κ²μ¦λ WS envelope (ws-message.js).
|
|
59
|
+
* @param {any} ctx - μ±λ 컨ν
μ€νΈ.
|
|
60
|
+
* @returns {Promise<any>} νΈλ€λ¬ λ°νκ°.
|
|
61
|
+
*/
|
|
62
|
+
dispatch(sock: any, msg: {
|
|
63
|
+
type?: string;
|
|
64
|
+
}, ctx: any): Promise<any>;
|
|
65
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sec-WebSocket-Protocol μ μ λͺ©λ‘μμ envelope νλ‘ν μ½ λ²μ μ νμνλ€.
|
|
3
|
+
*
|
|
4
|
+
* κ·μΉ (ꡬλ²μ ν΄λΌ/μλ² νΌν© λ‘€λ§ λ°°ν¬ μμ ):
|
|
5
|
+
* - `mega.v<N>` ν ν°μ΄ νλλ μμΌλ©΄ β **λ κ±°μ ν΄λ°± v1** (`{ version: 1, subprotocol: undefined }`)
|
|
6
|
+
* β subprotocol λ―Έμ¬μ© ν΄λΌ(ν WASM MegaSocketΒ·λΈλΌμ°μ κΈ°λ³Έ)λ μ λΆ v1 λ‘ μ·¨κΈνλ€.
|
|
7
|
+
* - μνΈ μ§μ λ²μ μ΄ μμΌλ©΄ μ΅κ³ λ²μ μ±ν β `{ version: N, subprotocol: 'mega.v<N>' }`
|
|
8
|
+
* (μλ²κ° νΈλμ
°μ΄ν¬ μλ΅ `Sec-WebSocket-Protocol` λ‘ νμ ν΅μ§ β ν΄λΌλ `WebSocket.protocol` λ‘ μ½λλ€).
|
|
9
|
+
* - `mega.v*` λ₯Ό μ μνμ§λ§ μνΈ λ²μ μ΄ μμΌλ©΄(ν΄λΌκ° λ―Έλ λ²μ λ§ μ§μ) β `null`
|
|
10
|
+
* β νΈμΆλΆλ subprotocol μμ΄ μλ½νλ€(ν΄λΌ μ
μ₯μμ "μλ²κ° λ΄ λ²μ μ λͺ» ν¨" = v1 ν΄λ°± μ νΈ.
|
|
11
|
+
* v1 μ λͺ» νλ ν΄λΌμ΄μΈνΈλ μ€μ€λ‘ λ«λλ€). νΈλμ
°μ΄ν¬λ₯Ό κ±°λΆνμ§ μμ νμνΈνμ΄ μ λ κΉ¨μ§μ§ μλλ€.
|
|
12
|
+
*
|
|
13
|
+
* @param {Iterable<string>} offered - ν΄λΌμ΄μΈνΈκ° μ μν subprotocol ν ν°λ€(ws λ Set μ μ λ¬).
|
|
14
|
+
* @param {ReadonlyArray<number>} [supported] - μλ² μ§μ λ²μ λͺ©λ‘.
|
|
15
|
+
* @returns {{ version: number, subprotocol: string | undefined } | null} νμ κ²°κ³Ό, μνΈ λ²μ μμΌλ©΄ null.
|
|
16
|
+
*/
|
|
17
|
+
export function negotiateWsProtocol(offered: Iterable<string>, supported?: ReadonlyArray<number>): {
|
|
18
|
+
version: number;
|
|
19
|
+
subprotocol: string | undefined;
|
|
20
|
+
} | null;
|
|
21
|
+
/**
|
|
22
|
+
* λ©μμ§ id μμ± β ULID (48-bit timestamp + 80-bit randomness = 26μ Crockford base32).
|
|
23
|
+
*
|
|
24
|
+
* μ μ `MegaIdGen` λΌμ΄λΈλ¬λ¦¬νλ OQ-014 λ‘ μμ½ β λ³Έ helper λ envelope μ μ© zero-dep ꡬν.
|
|
25
|
+
*
|
|
26
|
+
* @param {number} [timestamp] - epoch ms (ν
μ€νΈ μ£Όμ
μ©; λ―Έμ§μ μ `Date.now()`).
|
|
27
|
+
* @returns {string} 26μ ULID (μ 10μ = μκ°, λ€ 16μ = λλ€).
|
|
28
|
+
*/
|
|
29
|
+
export function generateMessageId(timestamp?: number): string;
|
|
30
|
+
/**
|
|
31
|
+
* WS λ©μμ§ envelope μμ±. `v` / `id` / `ts` μλ μ±μ (Β§6.2).
|
|
32
|
+
*
|
|
33
|
+
* @param {Object} [fields]
|
|
34
|
+
* @param {string} [fields.type] - `domain.action` ν¨ν΄ (κ²μ¦λ¨, μλ° μ throw). λλ½ μ throw.
|
|
35
|
+
* @param {string} [fields.ns] - μ±λ namespace (μ: `'chat'`).
|
|
36
|
+
* @param {Object} [fields.payload] - νμ΄λ‘λ.
|
|
37
|
+
* @param {Object} [fields.error] - μλ¬ κ°μ²΄ (Β§6.3 λͺ¨μ κΆμ₯).
|
|
38
|
+
* @param {string} [fields.ref] - μμ²-μλ΅ λ§€μΉμ©. μλ² νΈμλ μλ΅.
|
|
39
|
+
* @param {{ id?: string, ts?: number }} [opts] - ν
μ€νΈ/μ¬νμ© μ£Όμ
(λ―Έμ§μ μ μλ).
|
|
40
|
+
* @returns {{ v: number, id: string, type: string, ts: number }} μμ±λ envelope.
|
|
41
|
+
* @throws {Error} `type` μ΄ {@link WS_TYPE_PATTERN} μλ°.
|
|
42
|
+
* @example
|
|
43
|
+
* createWsMessage({ type: 'chat.send', ns: 'chat', payload: { text: 'hi' } })
|
|
44
|
+
* // β { v: 1, id: '01HV...', type: 'chat.send', ts: 1735..., ns: 'chat', payload: { text: 'hi' } }
|
|
45
|
+
*/
|
|
46
|
+
export function createWsMessage({ type, ns, payload, error, ref }?: {
|
|
47
|
+
type?: string;
|
|
48
|
+
ns?: string;
|
|
49
|
+
payload?: Object;
|
|
50
|
+
error?: Object;
|
|
51
|
+
ref?: string;
|
|
52
|
+
}, opts?: {
|
|
53
|
+
id?: string;
|
|
54
|
+
ts?: number;
|
|
55
|
+
}): {
|
|
56
|
+
v: number;
|
|
57
|
+
id: string;
|
|
58
|
+
type: string;
|
|
59
|
+
ts: number;
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* WS λ©μμ§ envelope κ²μ¦ (Β§6.2 schema). μλ° μ¬μ λ°°μ΄μ λ°ννλ€ (λΉ λ°°μ΄ = μ ν¨).
|
|
63
|
+
*
|
|
64
|
+
* λμ§μ§ μκ³ μ¬μ λͺ©λ‘μ λλ €μ£Όλ μ΄μ : νΈμΆλΆ(λμ€ν¨μ²/hub)κ° μ¬μ λ₯Ό ERROR envelope μ
|
|
65
|
+
* `details` λ‘ κ·Έλλ‘ μ€μ΄ λ³΄λΌ μ μλλ‘ (ADR-075 λ°°μ΄ νμ€).
|
|
66
|
+
*
|
|
67
|
+
* @param {any} msg
|
|
68
|
+
* @param {{ version?: number }} [opts] - `version` = μ΄ μ°κ²°μμ νμλ envelope λ²μ
|
|
69
|
+
* ({@link negotiateWsProtocol}). λ―Έμ§μ μ v1 β νμ μλ κΈ°μ‘΄ νΈμΆλΆμ νμνΈν.
|
|
70
|
+
* @returns {string[]} μλ° λ©μμ§ λͺ©λ‘ (μμΌλ©΄ λΉ λ°°μ΄).
|
|
71
|
+
*/
|
|
72
|
+
export function validateWsMessage(msg: any, { version }?: {
|
|
73
|
+
version?: number;
|
|
74
|
+
}): string[];
|
|
75
|
+
/**
|
|
76
|
+
* JSON λ¬Έμμ΄ β κ²μ¦λ WS λ©μμ§ envelope. νμ±/κ²μ¦ μ€ν¨ μ throw (silent κΈμ§).
|
|
77
|
+
*
|
|
78
|
+
* @param {string} json - wire νλ¬Έ JSON (ASP 볡νΈν ν λλ `P:` νλ¬Έ).
|
|
79
|
+
* @param {{ version?: number }} [opts] - νμλ envelope λ²μ (λ―Έμ§μ μ v1, {@link validateWsMessage}).
|
|
80
|
+
* @returns {Object} κ²μ¦ ν΅κ³Όν envelope.
|
|
81
|
+
* @throws {Error} JSON νμ± μ€ν¨ λλ schema μλ° (λ©μμ§μ μ¬μ ν¬ν¨).
|
|
82
|
+
*/
|
|
83
|
+
export function parseWsMessage(json: string, opts?: {
|
|
84
|
+
version?: number;
|
|
85
|
+
}): Object;
|
|
86
|
+
/** ν νλ‘ν μ½ λ²μ (04-data-models Β§6.2 `v: { const: 1 }`). */
|
|
87
|
+
export const WS_PROTOCOL_VERSION: 1;
|
|
88
|
+
/**
|
|
89
|
+
* μ΄ μλ²κ° μ§μνλ WS envelope νλ‘ν μ½ λ²μ λͺ©λ‘. λ²μ μ μ ν λμ κ³μ½ β vN μ§μ = v1..vN μ λΆ
|
|
90
|
+
* μ§μ. νμμ ν΄λΌμ΄μΈνΈ μ μκ³Όμ **μ΅κ³ μνΈ λ²μ **μ μ±ννλ€(v2 λμ
μ [1, 2] λ‘ νμ₯).
|
|
91
|
+
* @type {ReadonlyArray<number>}
|
|
92
|
+
*/
|
|
93
|
+
export const SUPPORTED_WS_PROTOCOL_VERSIONS: ReadonlyArray<number>;
|
|
94
|
+
/** WS λ²μ νμ subprotocol ν ν° νμ β `mega.v<μμ μ μ>` (μ: 'mega.v1'). */
|
|
95
|
+
export const WS_SUBPROTOCOL_PATTERN: RegExp;
|
|
96
|
+
/**
|
|
97
|
+
* λ©μμ§ `type` / `error.code` ν¨ν΄ β `domain.action[.result]` (ADR-016, Β§6.2/Β§6.3).
|
|
98
|
+
* μ (`.`)μ΄ μ΅μ 1κ° κ°μ β λ² μ΄μ€ λ©μλλͺ
(`onMessage` λ±, μ μμ) κ³Ό μ λ μΆ©λνμ§ μμ.
|
|
99
|
+
*/
|
|
100
|
+
export const WS_TYPE_PATTERN: RegExp;
|
|
101
|
+
/**
|
|
102
|
+
* WS λ©μμ§ JSON Schema (04-data-models Β§6.2 μ λ³Έ κ·Έλλ‘).
|
|
103
|
+
* νμ λ¨κ³(bridgeβhub, AJV μ»΄νμΌ)μμ μ¬μ¬μ©ν μ μλλ‘ export.
|
|
104
|
+
* @type {Object}
|
|
105
|
+
*/
|
|
106
|
+
export const WS_MESSAGE_SCHEMA: Object;
|