@simplysm/service-server 13.0.0-beta.36 → 13.0.0-beta.41

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.
@@ -1,5 +1,5 @@
1
- import { createConsola } from "consola";
2
- const logger = createConsola().withTag("service-server:V1AutoUpdateHandler");
1
+ import consola from "consola";
2
+ const logger = consola.withTag("service-server:V1AutoUpdateHandler");
3
3
  function handleV1Connection(socket, autoUpdateService) {
4
4
  socket.send(JSON.stringify({ name: "connected" }));
5
5
  socket.on("message", (data) => {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/legacy/v1-auto-update-handler.ts"],
4
- "sourcesContent": ["import type { WebSocket } from \"ws\";\nimport type { AutoUpdateService } from \"../services/auto-update-service\";\nimport { createConsola } from \"consola\";\n\nconst logger = createConsola().withTag(\"service-server:V1AutoUpdateHandler\");\n\ninterface IV1Request {\n uuid: string;\n command: string;\n params: unknown[];\n clientName?: string;\n}\n\ninterface IV1Response {\n name: \"response\";\n reqUuid: string;\n state: \"success\" | \"error\";\n body: unknown;\n}\n\n/**\n * V1 \uB808\uAC70\uC2DC \uD074\uB77C\uC774\uC5B8\uD2B8 \uCC98\uB9AC (auto-update\uB9CC \uC9C0\uC6D0)\n * \uB2E4\uB978 \uBAA8\uB4E0 \uC694\uCCAD\uC740 \uC5C5\uADF8\uB808\uC774\uB4DC \uC720\uB3C4 \uC5D0\uB7EC\uB97C \uBC18\uD658\uD569\uB2C8\uB2E4.\n */\nexport function handleV1Connection(socket: WebSocket, autoUpdateService: AutoUpdateService) {\n // \uC5F0\uACB0 \uC644\uB8CC \uC54C\uB9BC\n socket.send(JSON.stringify({ name: \"connected\" }));\n\n socket.on(\"message\", (data) => {\n try {\n const msg = JSON.parse(data.toString()) as IV1Request;\n\n // SdAutoUpdateService.getLastVersion\uB9CC \uD5C8\uC6A9\n if (msg.command === \"SdAutoUpdateService.getLastVersion\") {\n // legacy \uCEE8\uD14D\uC2A4\uD2B8 \uC124\uC815\n autoUpdateService.legacy = { clientName: msg.clientName };\n\n const result = autoUpdateService.getLastVersion(msg.params[0] as string);\n\n const response: IV1Response = {\n name: \"response\",\n reqUuid: msg.uuid,\n state: \"success\",\n body: result,\n };\n socket.send(JSON.stringify(response));\n } else {\n // \uB2E4\uB978 \uBAA8\uB4E0 \uC694\uCCAD\uC740 \uC5C5\uADF8\uB808\uC774\uB4DC \uC720\uB3C4\n const response: IV1Response = {\n name: \"response\",\n reqUuid: msg.uuid,\n state: \"error\",\n body: {\n message: \"\uC571 \uC5C5\uB370\uC774\uD2B8\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.\",\n code: \"UPGRADE_REQUIRED\",\n },\n };\n socket.send(JSON.stringify(response));\n }\n } catch (err) {\n logger.warn(\"V1 \uBA54\uC2DC\uC9C0 \uCC98\uB9AC \uC624\uB958\", err);\n }\n });\n}\n"],
5
- "mappings": "AAEA,SAAS,qBAAqB;AAE9B,MAAM,SAAS,cAAc,EAAE,QAAQ,oCAAoC;AAoBpE,SAAS,mBAAmB,QAAmB,mBAAsC;AAE1F,SAAO,KAAK,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC,CAAC;AAEjD,SAAO,GAAG,WAAW,CAAC,SAAS;AAC7B,QAAI;AACF,YAAM,MAAM,KAAK,MAAM,KAAK,SAAS,CAAC;AAGtC,UAAI,IAAI,YAAY,sCAAsC;AAExD,0BAAkB,SAAS,EAAE,YAAY,IAAI,WAAW;AAExD,cAAM,SAAS,kBAAkB,eAAe,IAAI,OAAO,CAAC,CAAW;AAEvE,cAAM,WAAwB;AAAA,UAC5B,MAAM;AAAA,UACN,SAAS,IAAI;AAAA,UACb,OAAO;AAAA,UACP,MAAM;AAAA,QACR;AACA,eAAO,KAAK,KAAK,UAAU,QAAQ,CAAC;AAAA,MACtC,OAAO;AAEL,cAAM,WAAwB;AAAA,UAC5B,MAAM;AAAA,UACN,SAAS,IAAI;AAAA,UACb,OAAO;AAAA,UACP,MAAM;AAAA,YACJ,SAAS;AAAA,YACT,MAAM;AAAA,UACR;AAAA,QACF;AACA,eAAO,KAAK,KAAK,UAAU,QAAQ,CAAC;AAAA,MACtC;AAAA,IACF,SAAS,KAAK;AACZ,aAAO,KAAK,mDAAgB,GAAG;AAAA,IACjC;AAAA,EACF,CAAC;AACH;",
4
+ "sourcesContent": ["import type { WebSocket } from \"ws\";\nimport type { AutoUpdateService } from \"../services/auto-update-service\";\nimport consola from \"consola\";\n\nconst logger = consola.withTag(\"service-server:V1AutoUpdateHandler\");\n\ninterface IV1Request {\n uuid: string;\n command: string;\n params: unknown[];\n clientName?: string;\n}\n\ninterface IV1Response {\n name: \"response\";\n reqUuid: string;\n state: \"success\" | \"error\";\n body: unknown;\n}\n\n/**\n * V1 \uB808\uAC70\uC2DC \uD074\uB77C\uC774\uC5B8\uD2B8 \uCC98\uB9AC (auto-update\uB9CC \uC9C0\uC6D0)\n * \uB2E4\uB978 \uBAA8\uB4E0 \uC694\uCCAD\uC740 \uC5C5\uADF8\uB808\uC774\uB4DC \uC720\uB3C4 \uC5D0\uB7EC\uB97C \uBC18\uD658\uD569\uB2C8\uB2E4.\n */\nexport function handleV1Connection(socket: WebSocket, autoUpdateService: AutoUpdateService) {\n // \uC5F0\uACB0 \uC644\uB8CC \uC54C\uB9BC\n socket.send(JSON.stringify({ name: \"connected\" }));\n\n socket.on(\"message\", (data) => {\n try {\n const msg = JSON.parse(data.toString()) as IV1Request;\n\n // SdAutoUpdateService.getLastVersion\uB9CC \uD5C8\uC6A9\n if (msg.command === \"SdAutoUpdateService.getLastVersion\") {\n // legacy \uCEE8\uD14D\uC2A4\uD2B8 \uC124\uC815\n autoUpdateService.legacy = { clientName: msg.clientName };\n\n const result = autoUpdateService.getLastVersion(msg.params[0] as string);\n\n const response: IV1Response = {\n name: \"response\",\n reqUuid: msg.uuid,\n state: \"success\",\n body: result,\n };\n socket.send(JSON.stringify(response));\n } else {\n // \uB2E4\uB978 \uBAA8\uB4E0 \uC694\uCCAD\uC740 \uC5C5\uADF8\uB808\uC774\uB4DC \uC720\uB3C4\n const response: IV1Response = {\n name: \"response\",\n reqUuid: msg.uuid,\n state: \"error\",\n body: {\n message: \"\uC571 \uC5C5\uB370\uC774\uD2B8\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.\",\n code: \"UPGRADE_REQUIRED\",\n },\n };\n socket.send(JSON.stringify(response));\n }\n } catch (err) {\n logger.warn(\"V1 \uBA54\uC2DC\uC9C0 \uCC98\uB9AC \uC624\uB958\", err);\n }\n });\n}\n"],
5
+ "mappings": "AAEA,OAAO,aAAa;AAEpB,MAAM,SAAS,QAAQ,QAAQ,oCAAoC;AAoB5D,SAAS,mBAAmB,QAAmB,mBAAsC;AAE1F,SAAO,KAAK,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC,CAAC;AAEjD,SAAO,GAAG,WAAW,CAAC,SAAS;AAC7B,QAAI;AACF,YAAM,MAAM,KAAK,MAAM,KAAK,SAAS,CAAC;AAGtC,UAAI,IAAI,YAAY,sCAAsC;AAExD,0BAAkB,SAAS,EAAE,YAAY,IAAI,WAAW;AAExD,cAAM,SAAS,kBAAkB,eAAe,IAAI,OAAO,CAAC,CAAW;AAEvE,cAAM,WAAwB;AAAA,UAC5B,MAAM;AAAA,UACN,SAAS,IAAI;AAAA,UACb,OAAO;AAAA,UACP,MAAM;AAAA,QACR;AACA,eAAO,KAAK,KAAK,UAAU,QAAQ,CAAC;AAAA,MACtC,OAAO;AAEL,cAAM,WAAwB;AAAA,UAC5B,MAAM;AAAA,UACN,SAAS,IAAI;AAAA,UACb,OAAO;AAAA,UACP,MAAM;AAAA,YACJ,SAAS;AAAA,YACT,MAAM;AAAA,UACR;AAAA,QACF;AACA,eAAO,KAAK,KAAK,UAAU,QAAQ,CAAC;AAAA,MACtC;AAAA,IACF,SAAS,KAAK;AACZ,aAAO,KAAK,mDAAgB,GAAG;AAAA,IACjC;AAAA,EACF,CAAC;AACH;",
6
6
  "names": []
7
7
  }
@@ -15,8 +15,8 @@ import { WebSocketHandler } from "./transport/socket/websocket-handler.js";
15
15
  import { JwtManager } from "./auth/jwt-manager.js";
16
16
  import { handleV1Connection } from "./legacy/v1-auto-update-handler.js";
17
17
  import { AutoUpdateService } from "./services/auto-update-service.js";
18
- import { createConsola } from "consola";
19
- const logger = createConsola().withTag("service-server:ServiceServer");
18
+ import consola from "consola";
19
+ const logger = consola.withTag("service-server:ServiceServer");
20
20
  class ServiceServer extends EventEmitter {
21
21
  constructor(options) {
22
22
  super();
@@ -33,7 +33,7 @@ class ServiceServer extends EventEmitter {
33
33
  _wsHandler = new WebSocketHandler(this._serviceExecutor, this._jwt);
34
34
  fastify;
35
35
  async listen() {
36
- logger.debug(`\uC11C\uBC84 \uC2DC\uC791... ${env.VER ?? ""}`);
36
+ logger.info(`\uC11C\uBC84 \uC2DC\uC791... ${env.VER ?? ""}`);
37
37
  await this.fastify.register(fastifyWebsocket);
38
38
  await this.fastify.register(fastifyHelmet, {
39
39
  global: true,
@@ -113,7 +113,7 @@ class ServiceServer extends EventEmitter {
113
113
  await this.fastify.listen({ port: this.options.port, host: "0.0.0.0" });
114
114
  this._registerGracefulShutdown();
115
115
  this.isOpen = true;
116
- logger.debug("\uC11C\uBC84 \uC2DC\uC791\uB428");
116
+ logger.info(`\uC11C\uBC84 \uC2DC\uC791\uB428 (port: ${this.options.port})`);
117
117
  this.emit("ready");
118
118
  }
119
119
  async close() {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/service-server.ts"],
4
- "sourcesContent": ["import type { ServiceEventListener } from \"@simplysm/service-common\";\nimport { StaticFileHandler } from \"./transport/http/static-file-handler\";\nimport { HttpRequestHandler } from \"./transport/http/http-request-handler\";\nimport { ServiceExecutor } from \"./core/service-executor\";\nimport type { Type } from \"@simplysm/core-common\";\nimport { jsonStringify, jsonParse, EventEmitter, env } from \"@simplysm/core-common\";\nimport type { FastifyInstance, FastifyRequest } from \"fastify\";\nimport fastify from \"fastify\";\nimport fastifyWebsocket from \"@fastify/websocket\";\nimport fastifyStatic from \"@fastify/static\";\nimport fastifyMultipart from \"@fastify/multipart\";\nimport fastifyHelmet from \"@fastify/helmet\";\nimport fastifyCors from \"@fastify/cors\";\nimport path from \"path\";\nimport { Buffer } from \"node:buffer\";\nimport { UploadHandler } from \"./transport/http/upload-handler\";\nimport { WebSocketHandler } from \"./transport/socket/websocket-handler\";\nimport type { WebSocket } from \"ws\";\nimport { JwtManager } from \"./auth/jwt-manager\";\nimport type { AuthTokenPayload } from \"./auth/auth-token-payload\";\nimport type { ServiceServerOptions } from \"./types/server-options\";\nimport { handleV1Connection } from \"./legacy/v1-auto-update-handler\";\nimport { AutoUpdateService } from \"./services/auto-update-service\";\nimport { createConsola } from \"consola\";\n\nconst logger = createConsola().withTag(\"service-server:ServiceServer\");\n\nexport class ServiceServer<TAuthInfo = unknown> extends EventEmitter<{\n ready: void;\n close: void;\n}> {\n isOpen = false;\n\n private readonly _serviceExecutor = new ServiceExecutor(this);\n private readonly _jwt = new JwtManager<TAuthInfo>(this);\n\n private readonly _httpRequestHandler = new HttpRequestHandler(this, this._serviceExecutor, this._jwt);\n private readonly _staticFileHandler = new StaticFileHandler(this);\n private readonly _uploadHandler = new UploadHandler(this, this._jwt);\n\n private readonly _wsHandler = new WebSocketHandler(this._serviceExecutor, this._jwt);\n\n readonly fastify: FastifyInstance;\n\n constructor(readonly options: ServiceServerOptions) {\n super();\n\n // SSL \uC124\uC815 (\uB3D9\uAE30)\n // Note: Fastify HTTPS \uC124\uC815\uC740 Buffer \uD0C0\uC785\uC744 \uC694\uAD6C\uD568 (Uint8Array \uC9C1\uC811 \uC0AC\uC6A9 \uBD88\uAC00)\n const httpsConf = options.ssl\n ? { pfx: Buffer.from(options.ssl.pfxBytes), passphrase: options.ssl.passphrase }\n : null;\n\n this.fastify = fastify({ https: httpsConf });\n }\n\n async listen(): Promise<void> {\n logger.debug(`\uC11C\uBC84 \uC2DC\uC791... ${env.VER ?? \"\"}`);\n\n // Websocket \uD50C\uB7EC\uADF8\uC778\n await this.fastify.register(fastifyWebsocket);\n\n // \uBCF4\uC548 \uD50C\uB7EC\uADF8\uC778\n await this.fastify.register(fastifyHelmet, {\n global: true,\n contentSecurityPolicy: {\n directives: {\n ...fastifyHelmet.contentSecurityPolicy.getDefaultDirectives(),\n \"default-src\": [\"'self'\", \"data:\", \"blob:\", \"*\"],\n \"script-src-attr\": [\"'unsafe-inline'\"],\n \"script-src\": [\"'self'\", \"'unsafe-inline'\", \"data:\", \"blob:\", \"*\"],\n ...(this.options.ssl != null\n ? {}\n : {\n \"upgrade-insecure-requests\": null,\n }),\n },\n },\n hsts: this.options.ssl != null,\n crossOriginOpenerPolicy: this.options.ssl != null,\n originAgentCluster: false,\n });\n\n // \uC5C5\uB85C\uB4DC \uD50C\uB7EC\uADF8\uC778\n await this.fastify.register(fastifyMultipart);\n\n // @fastify/static \uB4F1\uB85D\n await this.fastify.register(fastifyStatic, {\n root: path.resolve(this.options.rootPath, \"www\"),\n wildcard: false,\n serve: false,\n });\n\n // CORS \uC124\uC815\n await this.fastify.register(fastifyCors, {\n origin: (_origin, cb) => {\n cb(null, true);\n },\n allowedHeaders: [\"Content-Type\", \"Authorization\", \"x-sd-client-name\"],\n exposedHeaders: [\"Content-Disposition\", \"Content-Length\"],\n });\n\n // JSON \uD30C\uC11C\n this.fastify.addContentTypeParser(\"application/json\", { parseAs: \"string\" }, (req, body, done) => {\n try {\n const json = jsonParse(body as string);\n done(null, json);\n } catch (err: unknown) {\n const error = err as Error & { statusCode?: number };\n error.statusCode = 400;\n done(error, undefined);\n }\n });\n\n // JSON \uC0DD\uC131\uAE30\n this.fastify.setSerializerCompiler(() => (data) => jsonStringify(data));\n\n // API \uB77C\uC6B0\uD2B8\n this.fastify.all(\"/api/:service/:method\", async (req, reply) => {\n await this._httpRequestHandler.handle(req, reply);\n });\n\n // \uC5C5\uB85C\uB4DC \uB77C\uC6B0\uD2B8\n this.fastify.all(\"/upload\", async (req, reply) => {\n await this._uploadHandler.handle(req, reply);\n });\n\n // WebSocket \uB77C\uC6B0\uD2B8\n const onWebSocketConnected = (socket: WebSocket, req: FastifyRequest) => {\n const { ver, clientId, clientName } = req.query as {\n ver: string | undefined;\n clientId: string | undefined;\n clientName: string | undefined;\n };\n\n if (ver === \"2\") {\n if (clientId == null || clientName == null) {\n socket.close(1008, \"Missing Client ID/NAME\");\n return;\n }\n this._wsHandler.addSocket(socket, clientId, clientName, req);\n } else {\n // V1 \uB808\uAC70\uC2DC \uC9C0\uC6D0 (auto-update\uB9CC)\n const autoUpdateService = new AutoUpdateService();\n autoUpdateService.server = this;\n handleV1Connection(socket, autoUpdateService);\n }\n };\n this.fastify.get(\"/\", { websocket: true }, onWebSocketConnected.bind(this));\n this.fastify.get(\"/ws\", { websocket: true }, onWebSocketConnected.bind(this));\n\n // \uC815\uC801 \uD30C\uC77C \uC640\uC77C\uB4DC\uCE74\uB4DC \uD578\uB4E4\uB7EC\n this.fastify.route({\n method: [\"GET\", \"POST\", \"PUT\", \"DELETE\", \"PATCH\", \"HEAD\"],\n url: \"/*\",\n handler: async (req, reply) => {\n const urlObj = new URL(req.raw.url!, \"http://localhost\");\n const urlPath = decodeURI(urlObj.pathname.slice(1));\n\n await this._staticFileHandler.handle(req, reply, urlPath);\n },\n });\n\n // HTTP \uC11C\uBC84 \uC218\uC900\uC758 \uC5D0\uB7EC \uD578\uB4E4\uB9C1\n this.fastify.server.on(\"error\", (err) => {\n logger.error(\"HTTP \uC11C\uBC84 \uC624\uB958 \uBC1C\uC0DD\", err);\n });\n\n // \uB9AC\uC2A8\n await this.fastify.listen({ port: this.options.port, host: \"0.0.0.0\" });\n\n // Graceful Shutdown \uD578\uB4E4\uB7EC \uB4F1\uB85D\n this._registerGracefulShutdown();\n\n this.isOpen = true;\n logger.debug(\"\uC11C\uBC84 \uC2DC\uC791\uB428\");\n this.emit(\"ready\");\n }\n\n async close(): Promise<void> {\n this._wsHandler.closeAll();\n await this.fastify.close();\n\n this.isOpen = false;\n logger.debug(\"\uC11C\uBC84 \uC885\uB8CC\uB428\");\n this.emit(\"close\");\n }\n\n async broadcastReload(clientName: string | undefined, changedFileSet: Set<string>) {\n logger.debug(\"\uC11C\uBC84\uB0B4 \uBAA8\uB4E0 \uD074\uB77C\uC774\uC5B8\uD2B8 RELOAD \uBA85\uB839 \uC804\uC1A1\");\n await this._wsHandler.broadcastReload(clientName, changedFileSet);\n }\n\n async emitEvent<T extends ServiceEventListener<unknown, unknown>>(\n eventType: Type<T>,\n infoSelector: (item: T[\"$info\"]) => boolean,\n data: T[\"$data\"],\n ) {\n await this._wsHandler.emitToServer(eventType, infoSelector, data);\n }\n\n async generateAuthToken(payload: AuthTokenPayload<TAuthInfo>) {\n return this._jwt.sign(payload);\n }\n\n async verifyAuthToken(token: string): Promise<AuthTokenPayload<TAuthInfo>> {\n return this._jwt.verify(token);\n }\n\n private _registerGracefulShutdown() {\n const shutdownHandler = async (signal: string) => {\n logger.info(`${signal} \uC2DC\uADF8\uB110 \uAC10\uC9C0. \uC11C\uBC84 \uC885\uB8CC \uD504\uB85C\uC138\uC2A4 \uC2DC\uC791...`);\n\n const forceExitTimer = setTimeout(() => {\n logger.error(\"\uC11C\uBC84 \uC885\uB8CC \uC2DC\uAC04 \uCD08\uACFC (10\uCD08). \uAC15\uC81C \uC885\uB8CC\uD569\uB2C8\uB2E4.\");\n process.exit(1);\n }, 10000);\n\n try {\n if (this.isOpen) {\n await this.close();\n }\n logger.info(\"\uC11C\uBC84\uAC00 \uC548\uC804\uD558\uAC8C \uC885\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.\");\n clearTimeout(forceExitTimer);\n process.exit(0);\n } catch (err) {\n logger.error(\"\uC11C\uBC84 \uC885\uB8CC \uC911 \uC624\uB958 \uBC1C\uC0DD\", err);\n process.exit(1);\n }\n };\n\n process.on(\"SIGINT\", () => shutdownHandler(\"SIGINT\"));\n process.on(\"SIGTERM\", () => shutdownHandler(\"SIGTERM\"));\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { ServiceEventListener } from \"@simplysm/service-common\";\nimport { StaticFileHandler } from \"./transport/http/static-file-handler\";\nimport { HttpRequestHandler } from \"./transport/http/http-request-handler\";\nimport { ServiceExecutor } from \"./core/service-executor\";\nimport type { Type } from \"@simplysm/core-common\";\nimport { jsonStringify, jsonParse, EventEmitter, env } from \"@simplysm/core-common\";\nimport type { FastifyInstance, FastifyRequest } from \"fastify\";\nimport fastify from \"fastify\";\nimport fastifyWebsocket from \"@fastify/websocket\";\nimport fastifyStatic from \"@fastify/static\";\nimport fastifyMultipart from \"@fastify/multipart\";\nimport fastifyHelmet from \"@fastify/helmet\";\nimport fastifyCors from \"@fastify/cors\";\nimport path from \"path\";\nimport { Buffer } from \"node:buffer\";\nimport { UploadHandler } from \"./transport/http/upload-handler\";\nimport { WebSocketHandler } from \"./transport/socket/websocket-handler\";\nimport type { WebSocket } from \"ws\";\nimport { JwtManager } from \"./auth/jwt-manager\";\nimport type { AuthTokenPayload } from \"./auth/auth-token-payload\";\nimport type { ServiceServerOptions } from \"./types/server-options\";\nimport { handleV1Connection } from \"./legacy/v1-auto-update-handler\";\nimport { AutoUpdateService } from \"./services/auto-update-service\";\nimport consola from \"consola\";\n\nconst logger = consola.withTag(\"service-server:ServiceServer\");\n\nexport class ServiceServer<TAuthInfo = unknown> extends EventEmitter<{\n ready: void;\n close: void;\n}> {\n isOpen = false;\n\n private readonly _serviceExecutor = new ServiceExecutor(this);\n private readonly _jwt = new JwtManager<TAuthInfo>(this);\n\n private readonly _httpRequestHandler = new HttpRequestHandler(this, this._serviceExecutor, this._jwt);\n private readonly _staticFileHandler = new StaticFileHandler(this);\n private readonly _uploadHandler = new UploadHandler(this, this._jwt);\n\n private readonly _wsHandler = new WebSocketHandler(this._serviceExecutor, this._jwt);\n\n readonly fastify: FastifyInstance;\n\n constructor(readonly options: ServiceServerOptions) {\n super();\n\n // SSL \uC124\uC815 (\uB3D9\uAE30)\n // Note: Fastify HTTPS \uC124\uC815\uC740 Buffer \uD0C0\uC785\uC744 \uC694\uAD6C\uD568 (Uint8Array \uC9C1\uC811 \uC0AC\uC6A9 \uBD88\uAC00)\n const httpsConf = options.ssl\n ? { pfx: Buffer.from(options.ssl.pfxBytes), passphrase: options.ssl.passphrase }\n : null;\n\n this.fastify = fastify({ https: httpsConf });\n }\n\n async listen(): Promise<void> {\n logger.info(`\uC11C\uBC84 \uC2DC\uC791... ${env.VER ?? \"\"}`);\n\n // Websocket \uD50C\uB7EC\uADF8\uC778\n await this.fastify.register(fastifyWebsocket);\n\n // \uBCF4\uC548 \uD50C\uB7EC\uADF8\uC778\n await this.fastify.register(fastifyHelmet, {\n global: true,\n contentSecurityPolicy: {\n directives: {\n ...fastifyHelmet.contentSecurityPolicy.getDefaultDirectives(),\n \"default-src\": [\"'self'\", \"data:\", \"blob:\", \"*\"],\n \"script-src-attr\": [\"'unsafe-inline'\"],\n \"script-src\": [\"'self'\", \"'unsafe-inline'\", \"data:\", \"blob:\", \"*\"],\n ...(this.options.ssl != null\n ? {}\n : {\n \"upgrade-insecure-requests\": null,\n }),\n },\n },\n hsts: this.options.ssl != null,\n crossOriginOpenerPolicy: this.options.ssl != null,\n originAgentCluster: false,\n });\n\n // \uC5C5\uB85C\uB4DC \uD50C\uB7EC\uADF8\uC778\n await this.fastify.register(fastifyMultipart);\n\n // @fastify/static \uB4F1\uB85D\n await this.fastify.register(fastifyStatic, {\n root: path.resolve(this.options.rootPath, \"www\"),\n wildcard: false,\n serve: false,\n });\n\n // CORS \uC124\uC815\n await this.fastify.register(fastifyCors, {\n origin: (_origin, cb) => {\n cb(null, true);\n },\n allowedHeaders: [\"Content-Type\", \"Authorization\", \"x-sd-client-name\"],\n exposedHeaders: [\"Content-Disposition\", \"Content-Length\"],\n });\n\n // JSON \uD30C\uC11C\n this.fastify.addContentTypeParser(\"application/json\", { parseAs: \"string\" }, (req, body, done) => {\n try {\n const json = jsonParse(body as string);\n done(null, json);\n } catch (err: unknown) {\n const error = err as Error & { statusCode?: number };\n error.statusCode = 400;\n done(error, undefined);\n }\n });\n\n // JSON \uC0DD\uC131\uAE30\n this.fastify.setSerializerCompiler(() => (data) => jsonStringify(data));\n\n // API \uB77C\uC6B0\uD2B8\n this.fastify.all(\"/api/:service/:method\", async (req, reply) => {\n await this._httpRequestHandler.handle(req, reply);\n });\n\n // \uC5C5\uB85C\uB4DC \uB77C\uC6B0\uD2B8\n this.fastify.all(\"/upload\", async (req, reply) => {\n await this._uploadHandler.handle(req, reply);\n });\n\n // WebSocket \uB77C\uC6B0\uD2B8\n const onWebSocketConnected = (socket: WebSocket, req: FastifyRequest) => {\n const { ver, clientId, clientName } = req.query as {\n ver: string | undefined;\n clientId: string | undefined;\n clientName: string | undefined;\n };\n\n if (ver === \"2\") {\n if (clientId == null || clientName == null) {\n socket.close(1008, \"Missing Client ID/NAME\");\n return;\n }\n this._wsHandler.addSocket(socket, clientId, clientName, req);\n } else {\n // V1 \uB808\uAC70\uC2DC \uC9C0\uC6D0 (auto-update\uB9CC)\n const autoUpdateService = new AutoUpdateService();\n autoUpdateService.server = this;\n handleV1Connection(socket, autoUpdateService);\n }\n };\n this.fastify.get(\"/\", { websocket: true }, onWebSocketConnected.bind(this));\n this.fastify.get(\"/ws\", { websocket: true }, onWebSocketConnected.bind(this));\n\n // \uC815\uC801 \uD30C\uC77C \uC640\uC77C\uB4DC\uCE74\uB4DC \uD578\uB4E4\uB7EC\n this.fastify.route({\n method: [\"GET\", \"POST\", \"PUT\", \"DELETE\", \"PATCH\", \"HEAD\"],\n url: \"/*\",\n handler: async (req, reply) => {\n const urlObj = new URL(req.raw.url!, \"http://localhost\");\n const urlPath = decodeURI(urlObj.pathname.slice(1));\n\n await this._staticFileHandler.handle(req, reply, urlPath);\n },\n });\n\n // HTTP \uC11C\uBC84 \uC218\uC900\uC758 \uC5D0\uB7EC \uD578\uB4E4\uB9C1\n this.fastify.server.on(\"error\", (err) => {\n logger.error(\"HTTP \uC11C\uBC84 \uC624\uB958 \uBC1C\uC0DD\", err);\n });\n\n // \uB9AC\uC2A8\n await this.fastify.listen({ port: this.options.port, host: \"0.0.0.0\" });\n\n // Graceful Shutdown \uD578\uB4E4\uB7EC \uB4F1\uB85D\n this._registerGracefulShutdown();\n\n this.isOpen = true;\n logger.info(`\uC11C\uBC84 \uC2DC\uC791\uB428 (port: ${this.options.port})`);\n this.emit(\"ready\");\n }\n\n async close(): Promise<void> {\n this._wsHandler.closeAll();\n await this.fastify.close();\n\n this.isOpen = false;\n logger.debug(\"\uC11C\uBC84 \uC885\uB8CC\uB428\");\n this.emit(\"close\");\n }\n\n async broadcastReload(clientName: string | undefined, changedFileSet: Set<string>) {\n logger.debug(\"\uC11C\uBC84\uB0B4 \uBAA8\uB4E0 \uD074\uB77C\uC774\uC5B8\uD2B8 RELOAD \uBA85\uB839 \uC804\uC1A1\");\n await this._wsHandler.broadcastReload(clientName, changedFileSet);\n }\n\n async emitEvent<T extends ServiceEventListener<unknown, unknown>>(\n eventType: Type<T>,\n infoSelector: (item: T[\"$info\"]) => boolean,\n data: T[\"$data\"],\n ) {\n await this._wsHandler.emitToServer(eventType, infoSelector, data);\n }\n\n async generateAuthToken(payload: AuthTokenPayload<TAuthInfo>) {\n return this._jwt.sign(payload);\n }\n\n async verifyAuthToken(token: string): Promise<AuthTokenPayload<TAuthInfo>> {\n return this._jwt.verify(token);\n }\n\n private _registerGracefulShutdown() {\n const shutdownHandler = async (signal: string) => {\n logger.info(`${signal} \uC2DC\uADF8\uB110 \uAC10\uC9C0. \uC11C\uBC84 \uC885\uB8CC \uD504\uB85C\uC138\uC2A4 \uC2DC\uC791...`);\n\n const forceExitTimer = setTimeout(() => {\n logger.error(\"\uC11C\uBC84 \uC885\uB8CC \uC2DC\uAC04 \uCD08\uACFC (10\uCD08). \uAC15\uC81C \uC885\uB8CC\uD569\uB2C8\uB2E4.\");\n process.exit(1);\n }, 10000);\n\n try {\n if (this.isOpen) {\n await this.close();\n }\n logger.info(\"\uC11C\uBC84\uAC00 \uC548\uC804\uD558\uAC8C \uC885\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.\");\n clearTimeout(forceExitTimer);\n process.exit(0);\n } catch (err) {\n logger.error(\"\uC11C\uBC84 \uC885\uB8CC \uC911 \uC624\uB958 \uBC1C\uC0DD\", err);\n process.exit(1);\n }\n };\n\n process.on(\"SIGINT\", () => shutdownHandler(\"SIGINT\"));\n process.on(\"SIGTERM\", () => shutdownHandler(\"SIGTERM\"));\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -53,8 +53,8 @@ import {
53
53
  } from "@simplysm/orm-common";
54
54
  import { ServiceBase } from "../core/service-base.js";
55
55
  import { Authorize } from "../auth/auth.decorators.js";
56
- import { createConsola } from "consola";
57
- const logger = createConsola().withTag("service-server:OrmService");
56
+ import consola from "consola";
57
+ const logger = consola.withTag("service-server:OrmService");
58
58
  _OrmService_decorators = [Authorize()];
59
59
  let _OrmService = class _OrmService extends (_a = ServiceBase) {
60
60
  static _socketConns = /* @__PURE__ */ new WeakMap();
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/services/orm-service.ts"],
4
- "sourcesContent": ["import { DbConnFactory, type DbConnConfig, type DbConn } from \"@simplysm/orm-node\";\nimport {\n type ColumnMeta,\n createQueryBuilder,\n type Dialect,\n type IsolationLevel,\n parseQueryResult,\n type QueryDef,\n type ResultMeta,\n} from \"@simplysm/orm-common\";\nimport { ServiceBase } from \"../core/service-base\";\nimport type { OrmService as OrmServiceType, DbConnOptions } from \"@simplysm/service-common\";\nimport type { ServiceSocket } from \"../transport/socket/service-socket\";\nimport { Authorize } from \"../auth/auth.decorators\";\nimport { createConsola } from \"consola\";\n\nconst logger = createConsola().withTag(\"service-server:OrmService\");\n\n@Authorize()\nexport class OrmService extends ServiceBase implements OrmServiceType {\n private static readonly _socketConns = new WeakMap<ServiceSocket, Map<number, DbConn>>();\n\n private async _getConf(opt: DbConnOptions & { configName: string }): Promise<DbConnConfig> {\n const config = (await this.getConfig<Record<string, DbConnConfig | undefined>>(\"orm\"))[opt.configName];\n if (config == null) {\n throw new Error(`ORM \uC124\uC815\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${opt.configName}`);\n }\n return { ...config, ...opt.config } as DbConnConfig;\n }\n\n get sock(): ServiceSocket {\n const socket = this.socket;\n if (socket == null) {\n throw new Error(\"WebSocket \uC5F0\uACB0\uC774 \uD544\uC694\uD569\uB2C8\uB2E4. HTTP\uB85C\uB294 ORM \uC11C\uBE44\uC2A4\uB97C \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.\");\n }\n return socket;\n }\n\n private _getConn(connId: number): DbConn {\n const myConns = OrmService._socketConns.get(this.sock);\n const conn = myConns?.get(connId);\n if (conn == null) {\n throw new Error(\"DB\uC5D0 \uC5F0\uACB0\uB418\uC5B4\uC788\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. (Invalid Connection ID)\");\n }\n return conn;\n }\n\n async getInfo(opt: DbConnOptions & { configName: string }): Promise<{\n dialect: Dialect;\n database?: string;\n schema?: string;\n }> {\n const config = await this._getConf(opt);\n return {\n dialect: config.dialect === \"mssql-azure\" ? \"mssql\" : config.dialect,\n database: config.database,\n schema: \"schema\" in config ? config.schema : undefined,\n };\n }\n\n async connect(opt: DbConnOptions & { configName: string }): Promise<number> {\n let myConns = OrmService._socketConns.get(this.sock);\n if (myConns == null) {\n myConns = new Map<number, DbConn>();\n OrmService._socketConns.set(this.sock, myConns);\n\n this.sock.on(\"close\", async () => {\n if (myConns == null) return;\n\n logger.debug(\"\uC18C\uCF13 \uC5F0\uACB0 \uC885\uB8CC \uAC10\uC9C0: \uC5F4\uB824\uC788\uB294 \uBAA8\uB4E0 DB \uC5F0\uACB0\uC744 \uC815\uB9AC\uD569\uB2C8\uB2E4.\");\n const conns = Array.from(myConns.values());\n\n await Promise.all(\n conns.map(async (conn) => {\n try {\n if (conn.isConnected) {\n await conn.close();\n }\n } catch (err) {\n logger.warn(\"DB \uC5F0\uACB0 \uAC15\uC81C \uC885\uB8CC \uC911 \uC624\uB958 \uBB34\uC2DC\uB428\", err);\n }\n }),\n );\n\n myConns.clear();\n });\n }\n\n const config = await this._getConf(opt);\n const dbConn = await DbConnFactory.create(config);\n await dbConn.connect();\n\n const lastConnId = Math.max(0, ...Array.from(myConns.keys()));\n const connId = lastConnId + 1;\n myConns.set(connId, dbConn);\n\n dbConn.on(\"close\", () => {\n myConns.delete(connId);\n });\n\n return connId;\n }\n\n async close(connId: number): Promise<void> {\n try {\n const conn = this._getConn(connId);\n await conn.close();\n } catch (err) {\n logger.warn(\"DB \uC5F0\uACB0 \uC885\uB8CC \uC911 \uC624\uB958 \uBB34\uC2DC\uB428\", err);\n }\n }\n\n async beginTransaction(connId: number, isolationLevel?: IsolationLevel): Promise<void> {\n const conn = this._getConn(connId);\n await conn.beginTransaction(isolationLevel);\n }\n\n async commitTransaction(connId: number): Promise<void> {\n const conn = this._getConn(connId);\n await conn.commitTransaction();\n }\n\n async rollbackTransaction(connId: number): Promise<void> {\n const conn = this._getConn(connId);\n await conn.rollbackTransaction();\n }\n\n async executeParametrized(connId: number, query: string, params?: unknown[]): Promise<unknown[][]> {\n const conn = this._getConn(connId);\n return conn.executeParametrized(query, params);\n }\n\n async executeDefs(connId: number, defs: QueryDef[], options?: (ResultMeta | undefined)[]): Promise<unknown[][]> {\n const conn = this._getConn(connId);\n const dialect: Dialect = conn.config.dialect === \"mssql-azure\" ? \"mssql\" : conn.config.dialect;\n const queryBuilder = createQueryBuilder(dialect);\n\n if (options == null || options.every((item) => item == null)) {\n return conn.execute([defs.map((def) => queryBuilder.build(def).sql).join(\"\\n\")]);\n } else {\n const queries = defs.flatMap((def) => {\n const query = queryBuilder.build(def);\n return Array.isArray(query) ? query : [query];\n });\n const result = await conn.execute(queries);\n\n const parsed: unknown[][] = [];\n for (let i = 0; i < result.length; i++) {\n const opt = options[i];\n if (opt != null) {\n const parsedResult = await parseQueryResult(result[i] as Record<string, unknown>[], opt);\n parsed.push(parsedResult ?? []);\n } else {\n parsed.push(result[i]);\n }\n }\n return parsed;\n }\n }\n\n async bulkInsert(\n connId: number,\n tableName: string,\n columnDefs: Record<string, ColumnMeta>,\n records: Record<string, unknown>[],\n ): Promise<void> {\n const conn = this._getConn(connId);\n await conn.bulkInsert(tableName, columnDefs, records);\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { DbConnFactory, type DbConnConfig, type DbConn } from \"@simplysm/orm-node\";\nimport {\n type ColumnMeta,\n createQueryBuilder,\n type Dialect,\n type IsolationLevel,\n parseQueryResult,\n type QueryDef,\n type ResultMeta,\n} from \"@simplysm/orm-common\";\nimport { ServiceBase } from \"../core/service-base\";\nimport type { OrmService as OrmServiceType, DbConnOptions } from \"@simplysm/service-common\";\nimport type { ServiceSocket } from \"../transport/socket/service-socket\";\nimport { Authorize } from \"../auth/auth.decorators\";\nimport consola from \"consola\";\n\nconst logger = consola.withTag(\"service-server:OrmService\");\n\n@Authorize()\nexport class OrmService extends ServiceBase implements OrmServiceType {\n private static readonly _socketConns = new WeakMap<ServiceSocket, Map<number, DbConn>>();\n\n private async _getConf(opt: DbConnOptions & { configName: string }): Promise<DbConnConfig> {\n const config = (await this.getConfig<Record<string, DbConnConfig | undefined>>(\"orm\"))[opt.configName];\n if (config == null) {\n throw new Error(`ORM \uC124\uC815\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${opt.configName}`);\n }\n return { ...config, ...opt.config } as DbConnConfig;\n }\n\n get sock(): ServiceSocket {\n const socket = this.socket;\n if (socket == null) {\n throw new Error(\"WebSocket \uC5F0\uACB0\uC774 \uD544\uC694\uD569\uB2C8\uB2E4. HTTP\uB85C\uB294 ORM \uC11C\uBE44\uC2A4\uB97C \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.\");\n }\n return socket;\n }\n\n private _getConn(connId: number): DbConn {\n const myConns = OrmService._socketConns.get(this.sock);\n const conn = myConns?.get(connId);\n if (conn == null) {\n throw new Error(\"DB\uC5D0 \uC5F0\uACB0\uB418\uC5B4\uC788\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. (Invalid Connection ID)\");\n }\n return conn;\n }\n\n async getInfo(opt: DbConnOptions & { configName: string }): Promise<{\n dialect: Dialect;\n database?: string;\n schema?: string;\n }> {\n const config = await this._getConf(opt);\n return {\n dialect: config.dialect === \"mssql-azure\" ? \"mssql\" : config.dialect,\n database: config.database,\n schema: \"schema\" in config ? config.schema : undefined,\n };\n }\n\n async connect(opt: DbConnOptions & { configName: string }): Promise<number> {\n let myConns = OrmService._socketConns.get(this.sock);\n if (myConns == null) {\n myConns = new Map<number, DbConn>();\n OrmService._socketConns.set(this.sock, myConns);\n\n this.sock.on(\"close\", async () => {\n if (myConns == null) return;\n\n logger.debug(\"\uC18C\uCF13 \uC5F0\uACB0 \uC885\uB8CC \uAC10\uC9C0: \uC5F4\uB824\uC788\uB294 \uBAA8\uB4E0 DB \uC5F0\uACB0\uC744 \uC815\uB9AC\uD569\uB2C8\uB2E4.\");\n const conns = Array.from(myConns.values());\n\n await Promise.all(\n conns.map(async (conn) => {\n try {\n if (conn.isConnected) {\n await conn.close();\n }\n } catch (err) {\n logger.warn(\"DB \uC5F0\uACB0 \uAC15\uC81C \uC885\uB8CC \uC911 \uC624\uB958 \uBB34\uC2DC\uB428\", err);\n }\n }),\n );\n\n myConns.clear();\n });\n }\n\n const config = await this._getConf(opt);\n const dbConn = await DbConnFactory.create(config);\n await dbConn.connect();\n\n const lastConnId = Math.max(0, ...Array.from(myConns.keys()));\n const connId = lastConnId + 1;\n myConns.set(connId, dbConn);\n\n dbConn.on(\"close\", () => {\n myConns.delete(connId);\n });\n\n return connId;\n }\n\n async close(connId: number): Promise<void> {\n try {\n const conn = this._getConn(connId);\n await conn.close();\n } catch (err) {\n logger.warn(\"DB \uC5F0\uACB0 \uC885\uB8CC \uC911 \uC624\uB958 \uBB34\uC2DC\uB428\", err);\n }\n }\n\n async beginTransaction(connId: number, isolationLevel?: IsolationLevel): Promise<void> {\n const conn = this._getConn(connId);\n await conn.beginTransaction(isolationLevel);\n }\n\n async commitTransaction(connId: number): Promise<void> {\n const conn = this._getConn(connId);\n await conn.commitTransaction();\n }\n\n async rollbackTransaction(connId: number): Promise<void> {\n const conn = this._getConn(connId);\n await conn.rollbackTransaction();\n }\n\n async executeParametrized(connId: number, query: string, params?: unknown[]): Promise<unknown[][]> {\n const conn = this._getConn(connId);\n return conn.executeParametrized(query, params);\n }\n\n async executeDefs(connId: number, defs: QueryDef[], options?: (ResultMeta | undefined)[]): Promise<unknown[][]> {\n const conn = this._getConn(connId);\n const dialect: Dialect = conn.config.dialect === \"mssql-azure\" ? \"mssql\" : conn.config.dialect;\n const queryBuilder = createQueryBuilder(dialect);\n\n if (options == null || options.every((item) => item == null)) {\n return conn.execute([defs.map((def) => queryBuilder.build(def).sql).join(\"\\n\")]);\n } else {\n const queries = defs.flatMap((def) => {\n const query = queryBuilder.build(def);\n return Array.isArray(query) ? query : [query];\n });\n const result = await conn.execute(queries);\n\n const parsed: unknown[][] = [];\n for (let i = 0; i < result.length; i++) {\n const opt = options[i];\n if (opt != null) {\n const parsedResult = await parseQueryResult(result[i] as Record<string, unknown>[], opt);\n parsed.push(parsedResult ?? []);\n } else {\n parsed.push(result[i]);\n }\n }\n return parsed;\n }\n }\n\n async bulkInsert(\n connId: number,\n tableName: string,\n columnDefs: Record<string, ColumnMeta>,\n records: Record<string, unknown>[],\n ): Promise<void> {\n const conn = this._getConn(connId);\n await conn.bulkInsert(tableName, columnDefs, records);\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  import path from "path";
2
2
  import { fsExists, fsStat } from "@simplysm/core-node";
3
- import { createConsola } from "consola";
4
- const logger = createConsola().withTag("service-server:StaticFileHandler");
3
+ import consola from "consola";
4
+ const logger = consola.withTag("service-server:StaticFileHandler");
5
5
  class StaticFileHandler {
6
6
  constructor(_server) {
7
7
  this._server = _server;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/transport/http/static-file-handler.ts"],
4
- "sourcesContent": ["import path from \"path\";\nimport { fsExists, fsStat } from \"@simplysm/core-node\";\nimport type { ServiceServer } from \"../../service-server\";\nimport type { FastifyReply, FastifyRequest } from \"fastify\";\nimport { createConsola } from \"consola\";\n\nconst logger = createConsola().withTag(\"service-server:StaticFileHandler\");\n\nexport class StaticFileHandler {\n constructor(private readonly _server: ServiceServer) {}\n\n async handle(req: FastifyRequest, reply: FastifyReply, urlPath: string): Promise<void> {\n let targetFilePath = path.resolve(this._server.options.rootPath, \"www\", urlPath);\n const allowedRootPath = path.resolve(this._server.options.rootPath, \"www\");\n\n // targetPath \uBCF4\uC548 \uBC29\uC5B4 (Path Traversal \uBC29\uC9C0)\n if (!targetFilePath.startsWith(allowedRootPath)) {\n throw new Error(\"Access denied\");\n }\n\n // \uB514\uB809\uD1A0\uB9AC\uBA74 index.html\uB85C\n if ((await fsExists(targetFilePath)) && (await fsStat(targetFilePath)).isDirectory()) {\n targetFilePath = path.resolve(targetFilePath, \"index.html\");\n }\n\n // \uAD8C\uD55C \uD655\uC778 (\uC228\uAE40 \uD30C\uC77C \uB4F1)\n if (path.basename(targetFilePath).startsWith(\".\")) {\n const errorMessage = \"\uD30C\uC77C\uC744 \uC0AC\uC6A9\uD560 \uAD8C\uD55C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.\";\n this._responseErrorHtml(reply, 403, errorMessage);\n logger.warn(`[403] ${errorMessage} (${targetFilePath})`);\n return;\n }\n\n // \uD30C\uC77C \uC804\uC1A1\n const filename = path.basename(targetFilePath);\n const directory = path.dirname(targetFilePath);\n\n try {\n return await reply.sendFile(filename, directory);\n } catch (err: unknown) {\n const error = err as { code?: string };\n if (error.code === \"ENOENT\") {\n const errorMessage = \"\uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.\";\n this._responseErrorHtml(reply, 404, errorMessage);\n logger.warn(`[404] ${errorMessage} (${targetFilePath})`);\n } else {\n const errorMessage = \"\uD30C\uC77C \uC804\uC1A1 \uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.\";\n this._responseErrorHtml(reply, 500, errorMessage);\n logger.error(`[500] ${errorMessage}`, err);\n }\n }\n }\n\n private _responseErrorHtml(reply: FastifyReply, code: number, message: string) {\n reply.status(code).type(\"text/html\").send(`\n<!DOCTYPE html>\n<html>\n<head>\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <meta charset=\"UTF-8\">\n <title>${code}: ${message}</title>\n</head>\n<body>${code}: ${message}</body>\n</html>`);\n }\n}\n"],
5
- "mappings": "AAAA,OAAO,UAAU;AACjB,SAAS,UAAU,cAAc;AAGjC,SAAS,qBAAqB;AAE9B,MAAM,SAAS,cAAc,EAAE,QAAQ,kCAAkC;AAElE,MAAM,kBAAkB;AAAA,EAC7B,YAA6B,SAAwB;AAAxB;AAAA,EAAyB;AAAA,EAEtD,MAAM,OAAO,KAAqB,OAAqB,SAAgC;AACrF,QAAI,iBAAiB,KAAK,QAAQ,KAAK,QAAQ,QAAQ,UAAU,OAAO,OAAO;AAC/E,UAAM,kBAAkB,KAAK,QAAQ,KAAK,QAAQ,QAAQ,UAAU,KAAK;AAGzE,QAAI,CAAC,eAAe,WAAW,eAAe,GAAG;AAC/C,YAAM,IAAI,MAAM,eAAe;AAAA,IACjC;AAGA,QAAK,MAAM,SAAS,cAAc,MAAO,MAAM,OAAO,cAAc,GAAG,YAAY,GAAG;AACpF,uBAAiB,KAAK,QAAQ,gBAAgB,YAAY;AAAA,IAC5D;AAGA,QAAI,KAAK,SAAS,cAAc,EAAE,WAAW,GAAG,GAAG;AACjD,YAAM,eAAe;AACrB,WAAK,mBAAmB,OAAO,KAAK,YAAY;AAChD,aAAO,KAAK,SAAS,YAAY,KAAK,cAAc,GAAG;AACvD;AAAA,IACF;AAGA,UAAM,WAAW,KAAK,SAAS,cAAc;AAC7C,UAAM,YAAY,KAAK,QAAQ,cAAc;AAE7C,QAAI;AACF,aAAO,MAAM,MAAM,SAAS,UAAU,SAAS;AAAA,IACjD,SAAS,KAAc;AACrB,YAAM,QAAQ;AACd,UAAI,MAAM,SAAS,UAAU;AAC3B,cAAM,eAAe;AACrB,aAAK,mBAAmB,OAAO,KAAK,YAAY;AAChD,eAAO,KAAK,SAAS,YAAY,KAAK,cAAc,GAAG;AAAA,MACzD,OAAO;AACL,cAAM,eAAe;AACrB,aAAK,mBAAmB,OAAO,KAAK,YAAY;AAChD,eAAO,MAAM,SAAS,YAAY,IAAI,GAAG;AAAA,MAC3C;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,mBAAmB,OAAqB,MAAc,SAAiB;AAC7E,UAAM,OAAO,IAAI,EAAE,KAAK,WAAW,EAAE,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,aAMjC,IAAI,KAAK,OAAO;AAAA;AAAA,QAErB,IAAI,KAAK,OAAO;AAAA,QAChB;AAAA,EACN;AACF;",
4
+ "sourcesContent": ["import path from \"path\";\nimport { fsExists, fsStat } from \"@simplysm/core-node\";\nimport type { ServiceServer } from \"../../service-server\";\nimport type { FastifyReply, FastifyRequest } from \"fastify\";\nimport consola from \"consola\";\n\nconst logger = consola.withTag(\"service-server:StaticFileHandler\");\n\nexport class StaticFileHandler {\n constructor(private readonly _server: ServiceServer) {}\n\n async handle(req: FastifyRequest, reply: FastifyReply, urlPath: string): Promise<void> {\n let targetFilePath = path.resolve(this._server.options.rootPath, \"www\", urlPath);\n const allowedRootPath = path.resolve(this._server.options.rootPath, \"www\");\n\n // targetPath \uBCF4\uC548 \uBC29\uC5B4 (Path Traversal \uBC29\uC9C0)\n if (!targetFilePath.startsWith(allowedRootPath)) {\n throw new Error(\"Access denied\");\n }\n\n // \uB514\uB809\uD1A0\uB9AC\uBA74 index.html\uB85C\n if ((await fsExists(targetFilePath)) && (await fsStat(targetFilePath)).isDirectory()) {\n targetFilePath = path.resolve(targetFilePath, \"index.html\");\n }\n\n // \uAD8C\uD55C \uD655\uC778 (\uC228\uAE40 \uD30C\uC77C \uB4F1)\n if (path.basename(targetFilePath).startsWith(\".\")) {\n const errorMessage = \"\uD30C\uC77C\uC744 \uC0AC\uC6A9\uD560 \uAD8C\uD55C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.\";\n this._responseErrorHtml(reply, 403, errorMessage);\n logger.warn(`[403] ${errorMessage} (${targetFilePath})`);\n return;\n }\n\n // \uD30C\uC77C \uC804\uC1A1\n const filename = path.basename(targetFilePath);\n const directory = path.dirname(targetFilePath);\n\n try {\n return await reply.sendFile(filename, directory);\n } catch (err: unknown) {\n const error = err as { code?: string };\n if (error.code === \"ENOENT\") {\n const errorMessage = \"\uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.\";\n this._responseErrorHtml(reply, 404, errorMessage);\n logger.warn(`[404] ${errorMessage} (${targetFilePath})`);\n } else {\n const errorMessage = \"\uD30C\uC77C \uC804\uC1A1 \uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.\";\n this._responseErrorHtml(reply, 500, errorMessage);\n logger.error(`[500] ${errorMessage}`, err);\n }\n }\n }\n\n private _responseErrorHtml(reply: FastifyReply, code: number, message: string) {\n reply.status(code).type(\"text/html\").send(`\n<!DOCTYPE html>\n<html>\n<head>\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <meta charset=\"UTF-8\">\n <title>${code}: ${message}</title>\n</head>\n<body>${code}: ${message}</body>\n</html>`);\n }\n}\n"],
5
+ "mappings": "AAAA,OAAO,UAAU;AACjB,SAAS,UAAU,cAAc;AAGjC,OAAO,aAAa;AAEpB,MAAM,SAAS,QAAQ,QAAQ,kCAAkC;AAE1D,MAAM,kBAAkB;AAAA,EAC7B,YAA6B,SAAwB;AAAxB;AAAA,EAAyB;AAAA,EAEtD,MAAM,OAAO,KAAqB,OAAqB,SAAgC;AACrF,QAAI,iBAAiB,KAAK,QAAQ,KAAK,QAAQ,QAAQ,UAAU,OAAO,OAAO;AAC/E,UAAM,kBAAkB,KAAK,QAAQ,KAAK,QAAQ,QAAQ,UAAU,KAAK;AAGzE,QAAI,CAAC,eAAe,WAAW,eAAe,GAAG;AAC/C,YAAM,IAAI,MAAM,eAAe;AAAA,IACjC;AAGA,QAAK,MAAM,SAAS,cAAc,MAAO,MAAM,OAAO,cAAc,GAAG,YAAY,GAAG;AACpF,uBAAiB,KAAK,QAAQ,gBAAgB,YAAY;AAAA,IAC5D;AAGA,QAAI,KAAK,SAAS,cAAc,EAAE,WAAW,GAAG,GAAG;AACjD,YAAM,eAAe;AACrB,WAAK,mBAAmB,OAAO,KAAK,YAAY;AAChD,aAAO,KAAK,SAAS,YAAY,KAAK,cAAc,GAAG;AACvD;AAAA,IACF;AAGA,UAAM,WAAW,KAAK,SAAS,cAAc;AAC7C,UAAM,YAAY,KAAK,QAAQ,cAAc;AAE7C,QAAI;AACF,aAAO,MAAM,MAAM,SAAS,UAAU,SAAS;AAAA,IACjD,SAAS,KAAc;AACrB,YAAM,QAAQ;AACd,UAAI,MAAM,SAAS,UAAU;AAC3B,cAAM,eAAe;AACrB,aAAK,mBAAmB,OAAO,KAAK,YAAY;AAChD,eAAO,KAAK,SAAS,YAAY,KAAK,cAAc,GAAG;AAAA,MACzD,OAAO;AACL,cAAM,eAAe;AACrB,aAAK,mBAAmB,OAAO,KAAK,YAAY;AAChD,eAAO,MAAM,SAAS,YAAY,IAAI,GAAG;AAAA,MAC3C;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,mBAAmB,OAAqB,MAAc,SAAiB;AAC7E,UAAM,OAAO,IAAI,EAAE,KAAK,WAAW,EAAE,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,aAMjC,IAAI,KAAK,OAAO;AAAA;AAAA,QAErB,IAAI,KAAK,OAAO;AAAA,QAChB;AAAA,EACN;AACF;",
6
6
  "names": []
7
7
  }
@@ -3,8 +3,8 @@ import { createWriteStream } from "fs";
3
3
  import { pipeline } from "stream/promises";
4
4
  import { Uuid } from "@simplysm/core-common";
5
5
  import { fsMkdir, fsStat, fsRm } from "@simplysm/core-node";
6
- import { createConsola } from "consola";
7
- const logger = createConsola().withTag("service-server:UploadHandler");
6
+ import consola from "consola";
7
+ const logger = consola.withTag("service-server:UploadHandler");
8
8
  class UploadHandler {
9
9
  constructor(_server, _jwt) {
10
10
  this._server = _server;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/transport/http/upload-handler.ts"],
4
- "sourcesContent": ["import path from \"path\";\nimport { createWriteStream } from \"fs\";\nimport { pipeline } from \"stream/promises\";\nimport { Uuid } from \"@simplysm/core-common\";\nimport { fsMkdir, fsStat, fsRm } from \"@simplysm/core-node\";\nimport type { ServiceServer } from \"../../service-server\";\nimport type { FastifyReply, FastifyRequest } from \"fastify\";\nimport type { ServiceUploadResult } from \"@simplysm/service-common\";\nimport type { JwtManager } from \"../../auth/jwt-manager\";\nimport { createConsola } from \"consola\";\n\nconst logger = createConsola().withTag(\"service-server:UploadHandler\");\n\nexport class UploadHandler {\n constructor(\n private readonly _server: ServiceServer,\n private readonly _jwt: JwtManager,\n ) {}\n\n async handle(req: FastifyRequest, reply: FastifyReply): Promise<void> {\n if (!req.isMultipart()) {\n reply.status(400).send(\"Multipart request expected\");\n return;\n }\n\n // \uC778\uC99D \uAC80\uC0AC\n try {\n const authHeader = req.headers.authorization;\n if (authHeader == null) {\n throw new Error(\"\uC778\uC99D \uD1A0\uD070\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.\");\n }\n const token = authHeader.split(\" \")[1];\n await this._jwt.verify(token);\n } catch (err) {\n reply.status(401).send({\n error: \"Unauthorized\",\n message: err instanceof Error ? err.message : String(err),\n });\n return;\n }\n\n const result: ServiceUploadResult[] = [];\n const uploadDir = path.resolve(this._server.options.rootPath, \"www\", \"uploads\");\n\n await fsMkdir(uploadDir);\n\n let currentSavePath: string | undefined;\n\n try {\n for await (const part of req.parts()) {\n if (part.type === \"file\") {\n const originalFilename = part.filename;\n const extension = path.extname(originalFilename);\n const saveName = `${Uuid.new().toString()}${extension}`;\n currentSavePath = path.join(uploadDir, saveName);\n\n await pipeline(part.file, createWriteStream(currentSavePath));\n\n if (part.file.truncated) {\n throw new Error(`File limit exceeded: ${originalFilename}`);\n }\n\n const stats = await fsStat(currentSavePath);\n\n result.push({\n path: `uploads/${saveName}`,\n filename: originalFilename,\n size: stats.size,\n });\n\n currentSavePath = undefined;\n }\n }\n\n reply.send(result);\n } catch (err) {\n logger.error(\"Upload Error\", err);\n\n if (currentSavePath != null) {\n await fsRm(currentSavePath).catch(() => {});\n logger.warn(`Incomplete file deleted: ${currentSavePath}`);\n }\n\n reply.code(500).send(\"Upload Failed\");\n }\n }\n}\n"],
5
- "mappings": "AAAA,OAAO,UAAU;AACjB,SAAS,yBAAyB;AAClC,SAAS,gBAAgB;AACzB,SAAS,YAAY;AACrB,SAAS,SAAS,QAAQ,YAAY;AAKtC,SAAS,qBAAqB;AAE9B,MAAM,SAAS,cAAc,EAAE,QAAQ,8BAA8B;AAE9D,MAAM,cAAc;AAAA,EACzB,YACmB,SACA,MACjB;AAFiB;AACA;AAAA,EAChB;AAAA,EAEH,MAAM,OAAO,KAAqB,OAAoC;AACpE,QAAI,CAAC,IAAI,YAAY,GAAG;AACtB,YAAM,OAAO,GAAG,EAAE,KAAK,4BAA4B;AACnD;AAAA,IACF;AAGA,QAAI;AACF,YAAM,aAAa,IAAI,QAAQ;AAC/B,UAAI,cAAc,MAAM;AACtB,cAAM,IAAI,MAAM,2DAAc;AAAA,MAChC;AACA,YAAM,QAAQ,WAAW,MAAM,GAAG,EAAE,CAAC;AACrC,YAAM,KAAK,KAAK,OAAO,KAAK;AAAA,IAC9B,SAAS,KAAK;AACZ,YAAM,OAAO,GAAG,EAAE,KAAK;AAAA,QACrB,OAAO;AAAA,QACP,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,MAC1D,CAAC;AACD;AAAA,IACF;AAEA,UAAM,SAAgC,CAAC;AACvC,UAAM,YAAY,KAAK,QAAQ,KAAK,QAAQ,QAAQ,UAAU,OAAO,SAAS;AAE9E,UAAM,QAAQ,SAAS;AAEvB,QAAI;AAEJ,QAAI;AACF,uBAAiB,QAAQ,IAAI,MAAM,GAAG;AACpC,YAAI,KAAK,SAAS,QAAQ;AACxB,gBAAM,mBAAmB,KAAK;AAC9B,gBAAM,YAAY,KAAK,QAAQ,gBAAgB;AAC/C,gBAAM,WAAW,GAAG,KAAK,IAAI,EAAE,SAAS,CAAC,GAAG,SAAS;AACrD,4BAAkB,KAAK,KAAK,WAAW,QAAQ;AAE/C,gBAAM,SAAS,KAAK,MAAM,kBAAkB,eAAe,CAAC;AAE5D,cAAI,KAAK,KAAK,WAAW;AACvB,kBAAM,IAAI,MAAM,wBAAwB,gBAAgB,EAAE;AAAA,UAC5D;AAEA,gBAAM,QAAQ,MAAM,OAAO,eAAe;AAE1C,iBAAO,KAAK;AAAA,YACV,MAAM,WAAW,QAAQ;AAAA,YACzB,UAAU;AAAA,YACV,MAAM,MAAM;AAAA,UACd,CAAC;AAED,4BAAkB;AAAA,QACpB;AAAA,MACF;AAEA,YAAM,KAAK,MAAM;AAAA,IACnB,SAAS,KAAK;AACZ,aAAO,MAAM,gBAAgB,GAAG;AAEhC,UAAI,mBAAmB,MAAM;AAC3B,cAAM,KAAK,eAAe,EAAE,MAAM,MAAM;AAAA,QAAC,CAAC;AAC1C,eAAO,KAAK,4BAA4B,eAAe,EAAE;AAAA,MAC3D;AAEA,YAAM,KAAK,GAAG,EAAE,KAAK,eAAe;AAAA,IACtC;AAAA,EACF;AACF;",
4
+ "sourcesContent": ["import path from \"path\";\nimport { createWriteStream } from \"fs\";\nimport { pipeline } from \"stream/promises\";\nimport { Uuid } from \"@simplysm/core-common\";\nimport { fsMkdir, fsStat, fsRm } from \"@simplysm/core-node\";\nimport type { ServiceServer } from \"../../service-server\";\nimport type { FastifyReply, FastifyRequest } from \"fastify\";\nimport type { ServiceUploadResult } from \"@simplysm/service-common\";\nimport type { JwtManager } from \"../../auth/jwt-manager\";\nimport consola from \"consola\";\n\nconst logger = consola.withTag(\"service-server:UploadHandler\");\n\nexport class UploadHandler {\n constructor(\n private readonly _server: ServiceServer,\n private readonly _jwt: JwtManager,\n ) {}\n\n async handle(req: FastifyRequest, reply: FastifyReply): Promise<void> {\n if (!req.isMultipart()) {\n reply.status(400).send(\"Multipart request expected\");\n return;\n }\n\n // \uC778\uC99D \uAC80\uC0AC\n try {\n const authHeader = req.headers.authorization;\n if (authHeader == null) {\n throw new Error(\"\uC778\uC99D \uD1A0\uD070\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.\");\n }\n const token = authHeader.split(\" \")[1];\n await this._jwt.verify(token);\n } catch (err) {\n reply.status(401).send({\n error: \"Unauthorized\",\n message: err instanceof Error ? err.message : String(err),\n });\n return;\n }\n\n const result: ServiceUploadResult[] = [];\n const uploadDir = path.resolve(this._server.options.rootPath, \"www\", \"uploads\");\n\n await fsMkdir(uploadDir);\n\n let currentSavePath: string | undefined;\n\n try {\n for await (const part of req.parts()) {\n if (part.type === \"file\") {\n const originalFilename = part.filename;\n const extension = path.extname(originalFilename);\n const saveName = `${Uuid.new().toString()}${extension}`;\n currentSavePath = path.join(uploadDir, saveName);\n\n await pipeline(part.file, createWriteStream(currentSavePath));\n\n if (part.file.truncated) {\n throw new Error(`File limit exceeded: ${originalFilename}`);\n }\n\n const stats = await fsStat(currentSavePath);\n\n result.push({\n path: `uploads/${saveName}`,\n filename: originalFilename,\n size: stats.size,\n });\n\n currentSavePath = undefined;\n }\n }\n\n reply.send(result);\n } catch (err) {\n logger.error(\"Upload Error\", err);\n\n if (currentSavePath != null) {\n await fsRm(currentSavePath).catch(() => {});\n logger.warn(`Incomplete file deleted: ${currentSavePath}`);\n }\n\n reply.code(500).send(\"Upload Failed\");\n }\n }\n}\n"],
5
+ "mappings": "AAAA,OAAO,UAAU;AACjB,SAAS,yBAAyB;AAClC,SAAS,gBAAgB;AACzB,SAAS,YAAY;AACrB,SAAS,SAAS,QAAQ,YAAY;AAKtC,OAAO,aAAa;AAEpB,MAAM,SAAS,QAAQ,QAAQ,8BAA8B;AAEtD,MAAM,cAAc;AAAA,EACzB,YACmB,SACA,MACjB;AAFiB;AACA;AAAA,EAChB;AAAA,EAEH,MAAM,OAAO,KAAqB,OAAoC;AACpE,QAAI,CAAC,IAAI,YAAY,GAAG;AACtB,YAAM,OAAO,GAAG,EAAE,KAAK,4BAA4B;AACnD;AAAA,IACF;AAGA,QAAI;AACF,YAAM,aAAa,IAAI,QAAQ;AAC/B,UAAI,cAAc,MAAM;AACtB,cAAM,IAAI,MAAM,2DAAc;AAAA,MAChC;AACA,YAAM,QAAQ,WAAW,MAAM,GAAG,EAAE,CAAC;AACrC,YAAM,KAAK,KAAK,OAAO,KAAK;AAAA,IAC9B,SAAS,KAAK;AACZ,YAAM,OAAO,GAAG,EAAE,KAAK;AAAA,QACrB,OAAO;AAAA,QACP,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,MAC1D,CAAC;AACD;AAAA,IACF;AAEA,UAAM,SAAgC,CAAC;AACvC,UAAM,YAAY,KAAK,QAAQ,KAAK,QAAQ,QAAQ,UAAU,OAAO,SAAS;AAE9E,UAAM,QAAQ,SAAS;AAEvB,QAAI;AAEJ,QAAI;AACF,uBAAiB,QAAQ,IAAI,MAAM,GAAG;AACpC,YAAI,KAAK,SAAS,QAAQ;AACxB,gBAAM,mBAAmB,KAAK;AAC9B,gBAAM,YAAY,KAAK,QAAQ,gBAAgB;AAC/C,gBAAM,WAAW,GAAG,KAAK,IAAI,EAAE,SAAS,CAAC,GAAG,SAAS;AACrD,4BAAkB,KAAK,KAAK,WAAW,QAAQ;AAE/C,gBAAM,SAAS,KAAK,MAAM,kBAAkB,eAAe,CAAC;AAE5D,cAAI,KAAK,KAAK,WAAW;AACvB,kBAAM,IAAI,MAAM,wBAAwB,gBAAgB,EAAE;AAAA,UAC5D;AAEA,gBAAM,QAAQ,MAAM,OAAO,eAAe;AAE1C,iBAAO,KAAK;AAAA,YACV,MAAM,WAAW,QAAQ;AAAA,YACzB,UAAU;AAAA,YACV,MAAM,MAAM;AAAA,UACd,CAAC;AAED,4BAAkB;AAAA,QACpB;AAAA,MACF;AAEA,YAAM,KAAK,MAAM;AAAA,IACnB,SAAS,KAAK;AACZ,aAAO,MAAM,gBAAgB,GAAG;AAEhC,UAAI,mBAAmB,MAAM;AAC3B,cAAM,KAAK,eAAe,EAAE,MAAM,MAAM;AAAA,QAAC,CAAC;AAC1C,eAAO,KAAK,4BAA4B,eAAe,EAAE;AAAA,MAC3D;AAEA,YAAM,KAAK,GAAG,EAAE,KAAK,eAAe;AAAA,IACtC;AAAA,EACF;AACF;",
6
6
  "names": []
7
7
  }
@@ -1,9 +1,9 @@
1
1
  import { DateTime, EventEmitter } from "@simplysm/core-common";
2
2
  import { clearInterval } from "node:timers";
3
- import { createConsola } from "consola";
3
+ import consola from "consola";
4
4
  import { WebSocket } from "ws";
5
5
  import { ProtocolWrapper } from "../../protocol/protocol-wrapper.js";
6
- const logger = createConsola().withTag("service-server:ServiceSocket");
6
+ const logger = consola.withTag("service-server:ServiceSocket");
7
7
  class ServiceSocket extends EventEmitter {
8
8
  constructor(_socket, _clientId, clientName, connReq) {
9
9
  super();
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/transport/socket/service-socket.ts"],
4
- "sourcesContent": ["import type { Bytes } from \"@simplysm/core-common\";\nimport { DateTime, EventEmitter } from \"@simplysm/core-common\";\nimport type { FastifyRequest } from \"fastify\";\nimport { clearInterval } from \"node:timers\";\nimport { createConsola } from \"consola\";\nimport { WebSocket } from \"ws\";\nimport type { AuthTokenPayload } from \"../../auth/auth-token-payload\";\nimport { ProtocolWrapper } from \"../../protocol/protocol-wrapper\";\nimport type { ServiceClientMessage, ServiceServerMessage, ServiceServerRawMessage } from \"@simplysm/service-common\";\n\nconst logger = createConsola().withTag(\"service-server:ServiceSocket\");\n\nexport class ServiceSocket extends EventEmitter<{\n error: Error;\n close: number;\n message: { uuid: string; msg: ServiceClientMessage };\n}> {\n private readonly _PING_INTERVAL = 5000; // 5\uCD08\uB9C8\uB2E4 \uD551 \uC804\uC1A1\n private readonly _PONG_PACKET = new Uint8Array([0x02]);\n\n private readonly _protocol = new ProtocolWrapper();\n private readonly _listenerInfos: { eventName: string; key: string; info: unknown }[] = [];\n\n private _isAlive = true;\n private readonly _pingTimer: NodeJS.Timeout;\n\n readonly connectedAtDateTime = new DateTime();\n\n authTokenPayload?: AuthTokenPayload;\n\n constructor(\n private readonly _socket: WebSocket,\n private readonly _clientId: string,\n public readonly clientName: string,\n public readonly connReq: FastifyRequest,\n ) {\n super();\n\n this._socket.on(\"close\", this._onClose.bind(this));\n this._socket.on(\"error\", this._onError.bind(this));\n this._socket.on(\"message\", this._onMessage.bind(this));\n\n this._socket.on(\"pong\", () => {\n this._isAlive = true;\n });\n\n this._pingTimer = setInterval(() => {\n if (!this._isAlive) {\n this.close();\n return;\n }\n\n this._isAlive = false;\n this._socket.ping();\n }, this._PING_INTERVAL);\n }\n\n close() {\n this._socket.terminate();\n }\n\n async send(uuid: string, msg: ServiceServerMessage) {\n return this._send(uuid, msg);\n }\n\n private async _send(uuid: string, msg: ServiceServerRawMessage) {\n if (this._socket.readyState !== WebSocket.OPEN) return 0;\n\n const { chunks } = await this._protocol.encode(uuid, msg);\n for (const chunk of chunks) {\n this._socket.send(chunk);\n }\n\n return chunks.reduce((acc, item) => acc + item.length, 0);\n }\n\n addEventListener(key: string, eventName: string, info: unknown) {\n this._listenerInfos.push({ key, eventName, info });\n }\n\n removeEventListener(key: string) {\n const idx = this._listenerInfos.findIndex((item) => item.key === key);\n if (idx >= 0) {\n this._listenerInfos.splice(idx, 1);\n }\n }\n\n getEventListeners(eventName: string) {\n return this._listenerInfos\n .filter((item) => item.eventName === eventName)\n .map((item) => ({ key: item.key, info: item.info }));\n }\n\n filterEventTargetKeys(targetKeys: string[]) {\n return this._listenerInfos.filter((item) => targetKeys.includes(item.key)).map((item) => item.key);\n }\n\n private _onError(err: Error) {\n logger.error(\"WebSocket \uD074\uB77C\uC774\uC5B8\uD2B8 \uC624\uB958 \uBC1C\uC0DD\", err);\n this.emit(\"error\", err);\n }\n\n private _onClose(code: number) {\n clearInterval(this._pingTimer);\n this._protocol.dispose();\n this.emit(\"close\", code);\n }\n\n private async _onMessage(msgBuffer: Bytes) {\n try {\n // ping\uC5D0 \uB300\uD55C pong\uCC98\uB9AC\n if (msgBuffer.length === 1 && msgBuffer[0] === 0x01) {\n if (this._socket.readyState === WebSocket.OPEN) {\n this._socket.send(this._PONG_PACKET);\n }\n return;\n }\n\n const decodeResult = await this._protocol.decode(msgBuffer);\n if (decodeResult.type === \"progress\") {\n await this._send(decodeResult.uuid, {\n name: \"progress\",\n body: {\n totalSize: decodeResult.totalSize,\n completedSize: decodeResult.completedSize,\n },\n });\n } else {\n const msg = decodeResult.message as ServiceClientMessage;\n this.emit(\"message\", { uuid: decodeResult.uuid, msg });\n }\n } catch (err) {\n logger.error(\"WebSocket \uBA54\uC2DC\uC9C0 \uCC98\uB9AC \uC911 \uC624\uB958 \uBC1C\uC0DD\", err);\n }\n }\n}\n"],
5
- "mappings": "AACA,SAAS,UAAU,oBAAoB;AAEvC,SAAS,qBAAqB;AAC9B,SAAS,qBAAqB;AAC9B,SAAS,iBAAiB;AAE1B,SAAS,uBAAuB;AAGhC,MAAM,SAAS,cAAc,EAAE,QAAQ,8BAA8B;AAE9D,MAAM,sBAAsB,aAIhC;AAAA,EAcD,YACmB,SACA,WACD,YACA,SAChB;AACA,UAAM;AALW;AACA;AACD;AACA;AAIhB,SAAK,QAAQ,GAAG,SAAS,KAAK,SAAS,KAAK,IAAI,CAAC;AACjD,SAAK,QAAQ,GAAG,SAAS,KAAK,SAAS,KAAK,IAAI,CAAC;AACjD,SAAK,QAAQ,GAAG,WAAW,KAAK,WAAW,KAAK,IAAI,CAAC;AAErD,SAAK,QAAQ,GAAG,QAAQ,MAAM;AAC5B,WAAK,WAAW;AAAA,IAClB,CAAC;AAED,SAAK,aAAa,YAAY,MAAM;AAClC,UAAI,CAAC,KAAK,UAAU;AAClB,aAAK,MAAM;AACX;AAAA,MACF;AAEA,WAAK,WAAW;AAChB,WAAK,QAAQ,KAAK;AAAA,IACpB,GAAG,KAAK,cAAc;AAAA,EACxB;AAAA,EAtCiB,iBAAiB;AAAA;AAAA,EACjB,eAAe,IAAI,WAAW,CAAC,CAAI,CAAC;AAAA,EAEpC,YAAY,IAAI,gBAAgB;AAAA,EAChC,iBAAsE,CAAC;AAAA,EAEhF,WAAW;AAAA,EACF;AAAA,EAER,sBAAsB,IAAI,SAAS;AAAA,EAE5C;AAAA,EA6BA,QAAQ;AACN,SAAK,QAAQ,UAAU;AAAA,EACzB;AAAA,EAEA,MAAM,KAAK,MAAc,KAA2B;AAClD,WAAO,KAAK,MAAM,MAAM,GAAG;AAAA,EAC7B;AAAA,EAEA,MAAc,MAAM,MAAc,KAA8B;AAC9D,QAAI,KAAK,QAAQ,eAAe,UAAU,KAAM,QAAO;AAEvD,UAAM,EAAE,OAAO,IAAI,MAAM,KAAK,UAAU,OAAO,MAAM,GAAG;AACxD,eAAW,SAAS,QAAQ;AAC1B,WAAK,QAAQ,KAAK,KAAK;AAAA,IACzB;AAEA,WAAO,OAAO,OAAO,CAAC,KAAK,SAAS,MAAM,KAAK,QAAQ,CAAC;AAAA,EAC1D;AAAA,EAEA,iBAAiB,KAAa,WAAmB,MAAe;AAC9D,SAAK,eAAe,KAAK,EAAE,KAAK,WAAW,KAAK,CAAC;AAAA,EACnD;AAAA,EAEA,oBAAoB,KAAa;AAC/B,UAAM,MAAM,KAAK,eAAe,UAAU,CAAC,SAAS,KAAK,QAAQ,GAAG;AACpE,QAAI,OAAO,GAAG;AACZ,WAAK,eAAe,OAAO,KAAK,CAAC;AAAA,IACnC;AAAA,EACF;AAAA,EAEA,kBAAkB,WAAmB;AACnC,WAAO,KAAK,eACT,OAAO,CAAC,SAAS,KAAK,cAAc,SAAS,EAC7C,IAAI,CAAC,UAAU,EAAE,KAAK,KAAK,KAAK,MAAM,KAAK,KAAK,EAAE;AAAA,EACvD;AAAA,EAEA,sBAAsB,YAAsB;AAC1C,WAAO,KAAK,eAAe,OAAO,CAAC,SAAS,WAAW,SAAS,KAAK,GAAG,CAAC,EAAE,IAAI,CAAC,SAAS,KAAK,GAAG;AAAA,EACnG;AAAA,EAEQ,SAAS,KAAY;AAC3B,WAAO,MAAM,sEAAyB,GAAG;AACzC,SAAK,KAAK,SAAS,GAAG;AAAA,EACxB;AAAA,EAEQ,SAAS,MAAc;AAC7B,kBAAc,KAAK,UAAU;AAC7B,SAAK,UAAU,QAAQ;AACvB,SAAK,KAAK,SAAS,IAAI;AAAA,EACzB;AAAA,EAEA,MAAc,WAAW,WAAkB;AACzC,QAAI;AAEF,UAAI,UAAU,WAAW,KAAK,UAAU,CAAC,MAAM,GAAM;AACnD,YAAI,KAAK,QAAQ,eAAe,UAAU,MAAM;AAC9C,eAAK,QAAQ,KAAK,KAAK,YAAY;AAAA,QACrC;AACA;AAAA,MACF;AAEA,YAAM,eAAe,MAAM,KAAK,UAAU,OAAO,SAAS;AAC1D,UAAI,aAAa,SAAS,YAAY;AACpC,cAAM,KAAK,MAAM,aAAa,MAAM;AAAA,UAClC,MAAM;AAAA,UACN,MAAM;AAAA,YACJ,WAAW,aAAa;AAAA,YACxB,eAAe,aAAa;AAAA,UAC9B;AAAA,QACF,CAAC;AAAA,MACH,OAAO;AACL,cAAM,MAAM,aAAa;AACzB,aAAK,KAAK,WAAW,EAAE,MAAM,aAAa,MAAM,IAAI,CAAC;AAAA,MACvD;AAAA,IACF,SAAS,KAAK;AACZ,aAAO,MAAM,8EAA4B,GAAG;AAAA,IAC9C;AAAA,EACF;AACF;",
4
+ "sourcesContent": ["import type { Bytes } from \"@simplysm/core-common\";\nimport { DateTime, EventEmitter } from \"@simplysm/core-common\";\nimport type { FastifyRequest } from \"fastify\";\nimport { clearInterval } from \"node:timers\";\nimport consola from \"consola\";\nimport { WebSocket } from \"ws\";\nimport type { AuthTokenPayload } from \"../../auth/auth-token-payload\";\nimport { ProtocolWrapper } from \"../../protocol/protocol-wrapper\";\nimport type { ServiceClientMessage, ServiceServerMessage, ServiceServerRawMessage } from \"@simplysm/service-common\";\n\nconst logger = consola.withTag(\"service-server:ServiceSocket\");\n\nexport class ServiceSocket extends EventEmitter<{\n error: Error;\n close: number;\n message: { uuid: string; msg: ServiceClientMessage };\n}> {\n private readonly _PING_INTERVAL = 5000; // 5\uCD08\uB9C8\uB2E4 \uD551 \uC804\uC1A1\n private readonly _PONG_PACKET = new Uint8Array([0x02]);\n\n private readonly _protocol = new ProtocolWrapper();\n private readonly _listenerInfos: { eventName: string; key: string; info: unknown }[] = [];\n\n private _isAlive = true;\n private readonly _pingTimer: NodeJS.Timeout;\n\n readonly connectedAtDateTime = new DateTime();\n\n authTokenPayload?: AuthTokenPayload;\n\n constructor(\n private readonly _socket: WebSocket,\n private readonly _clientId: string,\n public readonly clientName: string,\n public readonly connReq: FastifyRequest,\n ) {\n super();\n\n this._socket.on(\"close\", this._onClose.bind(this));\n this._socket.on(\"error\", this._onError.bind(this));\n this._socket.on(\"message\", this._onMessage.bind(this));\n\n this._socket.on(\"pong\", () => {\n this._isAlive = true;\n });\n\n this._pingTimer = setInterval(() => {\n if (!this._isAlive) {\n this.close();\n return;\n }\n\n this._isAlive = false;\n this._socket.ping();\n }, this._PING_INTERVAL);\n }\n\n close() {\n this._socket.terminate();\n }\n\n async send(uuid: string, msg: ServiceServerMessage) {\n return this._send(uuid, msg);\n }\n\n private async _send(uuid: string, msg: ServiceServerRawMessage) {\n if (this._socket.readyState !== WebSocket.OPEN) return 0;\n\n const { chunks } = await this._protocol.encode(uuid, msg);\n for (const chunk of chunks) {\n this._socket.send(chunk);\n }\n\n return chunks.reduce((acc, item) => acc + item.length, 0);\n }\n\n addEventListener(key: string, eventName: string, info: unknown) {\n this._listenerInfos.push({ key, eventName, info });\n }\n\n removeEventListener(key: string) {\n const idx = this._listenerInfos.findIndex((item) => item.key === key);\n if (idx >= 0) {\n this._listenerInfos.splice(idx, 1);\n }\n }\n\n getEventListeners(eventName: string) {\n return this._listenerInfos\n .filter((item) => item.eventName === eventName)\n .map((item) => ({ key: item.key, info: item.info }));\n }\n\n filterEventTargetKeys(targetKeys: string[]) {\n return this._listenerInfos.filter((item) => targetKeys.includes(item.key)).map((item) => item.key);\n }\n\n private _onError(err: Error) {\n logger.error(\"WebSocket \uD074\uB77C\uC774\uC5B8\uD2B8 \uC624\uB958 \uBC1C\uC0DD\", err);\n this.emit(\"error\", err);\n }\n\n private _onClose(code: number) {\n clearInterval(this._pingTimer);\n this._protocol.dispose();\n this.emit(\"close\", code);\n }\n\n private async _onMessage(msgBuffer: Bytes) {\n try {\n // ping\uC5D0 \uB300\uD55C pong\uCC98\uB9AC\n if (msgBuffer.length === 1 && msgBuffer[0] === 0x01) {\n if (this._socket.readyState === WebSocket.OPEN) {\n this._socket.send(this._PONG_PACKET);\n }\n return;\n }\n\n const decodeResult = await this._protocol.decode(msgBuffer);\n if (decodeResult.type === \"progress\") {\n await this._send(decodeResult.uuid, {\n name: \"progress\",\n body: {\n totalSize: decodeResult.totalSize,\n completedSize: decodeResult.completedSize,\n },\n });\n } else {\n const msg = decodeResult.message as ServiceClientMessage;\n this.emit(\"message\", { uuid: decodeResult.uuid, msg });\n }\n } catch (err) {\n logger.error(\"WebSocket \uBA54\uC2DC\uC9C0 \uCC98\uB9AC \uC911 \uC624\uB958 \uBC1C\uC0DD\", err);\n }\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  import { Uuid } from "@simplysm/core-common";
2
2
  import { ServiceSocket } from "./service-socket.js";
3
- import { createConsola } from "consola";
4
- const logger = createConsola().withTag("service-server:WebSocketHandler");
3
+ import consola from "consola";
4
+ const logger = consola.withTag("service-server:WebSocketHandler");
5
5
  class WebSocketHandler {
6
6
  constructor(_executor, _jwt) {
7
7
  this._executor = _executor;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/transport/socket/websocket-handler.ts"],
4
- "sourcesContent": ["import type { WebSocket } from \"ws\";\nimport type { Type } from \"@simplysm/core-common\";\nimport { Uuid } from \"@simplysm/core-common\";\nimport type { ServiceEventListener, ServiceClientMessage } from \"@simplysm/service-common\";\nimport type { ServiceExecutor } from \"../../core/service-executor\";\nimport { ServiceSocket } from \"./service-socket\";\nimport type { JwtManager } from \"../../auth/jwt-manager\";\nimport type { FastifyRequest } from \"fastify\";\nimport { createConsola } from \"consola\";\n\nconst logger = createConsola().withTag(\"service-server:WebSocketHandler\");\n\nexport class WebSocketHandler {\n private readonly _socketMap = new Map<string, ServiceSocket>();\n\n constructor(\n private readonly _executor: ServiceExecutor,\n private readonly _jwt: JwtManager,\n ) {}\n\n addSocket(socket: WebSocket, clientId: string, clientName: string, connReq: FastifyRequest) {\n try {\n const serviceSocket = new ServiceSocket(socket, clientId, clientName, connReq);\n\n // \uAE30\uC874 \uC5F0\uACB0 \uB04A\uAE30\n const prevServiceSocket = this._socketMap.get(clientId);\n if (prevServiceSocket != null) {\n prevServiceSocket.close();\n\n const connectionDateTimeText = prevServiceSocket.connectedAtDateTime.toFormatString(\"yyyy:MM:dd HH:mm:ss.fff\");\n logger.debug(`\uD074\uB77C\uC774\uC5B8\uD2B8 \uAE30\uC874\uC5F0\uACB0 \uB04A\uC74C: ${clientId}: ${connectionDateTimeText}`);\n }\n\n this._socketMap.set(clientId, serviceSocket);\n\n serviceSocket.on(\"close\", (code) => {\n logger.debug(`\uD074\uB77C\uC774\uC5B8\uD2B8 \uC5F0\uACB0 \uB04A\uAE40: (code: ${code})`);\n\n if (this._socketMap.get(clientId) !== serviceSocket) return;\n this._socketMap.delete(clientId);\n });\n\n serviceSocket.on(\"message\", async ({ uuid, msg }) => {\n logger.debug(\"\uC694\uCCAD \uC218\uC2E0\", msg);\n const sentSize = await this._processRequest(serviceSocket, uuid, msg);\n logger.debug(`\uC751\uB2F5 \uC804\uC1A1 (size: ${sentSize})`);\n });\n\n logger.debug(\"\uD074\uB77C\uC774\uC5B8\uD2B8 \uC5F0\uACB0\uB428\", {\n clientId,\n remoteAddress: connReq.socket.remoteAddress,\n socketSize: this._socketMap.size,\n });\n } catch (err) {\n logger.error(\"\uC5F0\uACB0 \uCC98\uB9AC \uC911 \uC624\uB958 \uBC1C\uC0DD\", err);\n socket.terminate();\n }\n }\n\n closeAll() {\n for (const serviceSocket of this._socketMap.values()) {\n serviceSocket.close();\n }\n }\n\n async broadcastReload(clientName: string | undefined, changedFileSet: Set<string>) {\n for (const serviceSocket of this._socketMap.values()) {\n await serviceSocket.send(Uuid.new().toString(), {\n name: \"reload\",\n body: {\n clientName,\n changedFileSet,\n },\n });\n }\n }\n\n async emitToServer<T extends ServiceEventListener<unknown, unknown>>(\n eventType: Type<T>,\n infoSelector: (item: T[\"$info\"]) => boolean,\n data: T[\"$data\"],\n ) {\n const eventName = eventType.prototype.eventName as string;\n const targetKeys = Array.from(this._socketMap.values())\n .flatMap((subSock) => subSock.getEventListeners(eventName))\n .filter((item) => infoSelector(item.info as T[\"$info\"]))\n .map((item) => item.key);\n\n for (const subSock of this._socketMap.values()) {\n const subTargetKeys = subSock.filterEventTargetKeys(targetKeys);\n if (subTargetKeys.length > 0) {\n await subSock.send(Uuid.new().toString(), {\n name: \"evt:on\",\n body: {\n keys: subTargetKeys,\n data,\n },\n });\n }\n }\n }\n\n private async _processRequest(\n serviceSocket: ServiceSocket,\n uuid: string,\n message: ServiceClientMessage,\n ): Promise<number> {\n try {\n if (message.name.includes(\".\") && Array.isArray(message.body)) {\n const [serviceName, methodName] = message.name.split(\".\");\n\n const result = await this._executor.runMethod({\n serviceName,\n methodName,\n params: message.body,\n socket: serviceSocket,\n });\n\n return await serviceSocket.send(uuid, { name: \"response\", body: result });\n } else if (message.name === \"evt:add\") {\n const { key, name, info } = message.body as { key: string; name: string; info: unknown };\n serviceSocket.addEventListener(key, name, info);\n return await serviceSocket.send(uuid, { name: \"response\" });\n } else if (message.name === \"evt:remove\") {\n const { key } = message.body as { key: string };\n serviceSocket.removeEventListener(key);\n return await serviceSocket.send(uuid, { name: \"response\" });\n } else if (message.name === \"evt:gets\") {\n const { name } = message.body as { name: string };\n const infos = Array.from(this._socketMap.values()).flatMap((subSock) => subSock.getEventListeners(name));\n return await serviceSocket.send(uuid, { name: \"response\", body: infos });\n } else if (message.name === \"evt:emit\") {\n const { keys, data } = message.body as { keys: string[]; data: unknown };\n\n for (const subSock of this._socketMap.values()) {\n const targetKeys = subSock.filterEventTargetKeys(keys);\n if (targetKeys.length > 0) {\n await subSock.send(uuid, {\n name: \"evt:on\",\n body: {\n keys: targetKeys,\n data,\n },\n });\n }\n }\n\n return await serviceSocket.send(uuid, { name: \"response\" });\n } else if (message.name === \"auth\") {\n const token = message.body;\n serviceSocket.authTokenPayload = await this._jwt.verify(token);\n return await serviceSocket.send(uuid, { name: \"response\" });\n } else {\n const err = new Error(\"\uC694\uCCAD\uC774 \uC798\uBABB\uB418\uC5C8\uC2B5\uB2C8\uB2E4.\");\n\n return await serviceSocket.send(uuid, {\n name: \"error\",\n body: {\n name: err.name,\n message: err.message,\n stack: err.stack,\n code: \"BAD_MESSAGE\",\n },\n });\n }\n } catch (err) {\n const error =\n err instanceof Error ? err : new Error(typeof err === \"string\" ? err : \"\uC54C \uC218 \uC5C6\uB294 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD558\uC600\uC2B5\uB2C8\uB2E4.\");\n\n return serviceSocket.send(uuid, {\n name: \"error\",\n body: {\n name: error.name,\n message: error.message,\n code: \"INTERNAL_ERROR\",\n stack: error.stack,\n },\n });\n }\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { WebSocket } from \"ws\";\nimport type { Type } from \"@simplysm/core-common\";\nimport { Uuid } from \"@simplysm/core-common\";\nimport type { ServiceEventListener, ServiceClientMessage } from \"@simplysm/service-common\";\nimport type { ServiceExecutor } from \"../../core/service-executor\";\nimport { ServiceSocket } from \"./service-socket\";\nimport type { JwtManager } from \"../../auth/jwt-manager\";\nimport type { FastifyRequest } from \"fastify\";\nimport consola from \"consola\";\n\nconst logger = consola.withTag(\"service-server:WebSocketHandler\");\n\nexport class WebSocketHandler {\n private readonly _socketMap = new Map<string, ServiceSocket>();\n\n constructor(\n private readonly _executor: ServiceExecutor,\n private readonly _jwt: JwtManager,\n ) {}\n\n addSocket(socket: WebSocket, clientId: string, clientName: string, connReq: FastifyRequest) {\n try {\n const serviceSocket = new ServiceSocket(socket, clientId, clientName, connReq);\n\n // \uAE30\uC874 \uC5F0\uACB0 \uB04A\uAE30\n const prevServiceSocket = this._socketMap.get(clientId);\n if (prevServiceSocket != null) {\n prevServiceSocket.close();\n\n const connectionDateTimeText = prevServiceSocket.connectedAtDateTime.toFormatString(\"yyyy:MM:dd HH:mm:ss.fff\");\n logger.debug(`\uD074\uB77C\uC774\uC5B8\uD2B8 \uAE30\uC874\uC5F0\uACB0 \uB04A\uC74C: ${clientId}: ${connectionDateTimeText}`);\n }\n\n this._socketMap.set(clientId, serviceSocket);\n\n serviceSocket.on(\"close\", (code) => {\n logger.debug(`\uD074\uB77C\uC774\uC5B8\uD2B8 \uC5F0\uACB0 \uB04A\uAE40: (code: ${code})`);\n\n if (this._socketMap.get(clientId) !== serviceSocket) return;\n this._socketMap.delete(clientId);\n });\n\n serviceSocket.on(\"message\", async ({ uuid, msg }) => {\n logger.debug(\"\uC694\uCCAD \uC218\uC2E0\", msg);\n const sentSize = await this._processRequest(serviceSocket, uuid, msg);\n logger.debug(`\uC751\uB2F5 \uC804\uC1A1 (size: ${sentSize})`);\n });\n\n logger.debug(\"\uD074\uB77C\uC774\uC5B8\uD2B8 \uC5F0\uACB0\uB428\", {\n clientId,\n remoteAddress: connReq.socket.remoteAddress,\n socketSize: this._socketMap.size,\n });\n } catch (err) {\n logger.error(\"\uC5F0\uACB0 \uCC98\uB9AC \uC911 \uC624\uB958 \uBC1C\uC0DD\", err);\n socket.terminate();\n }\n }\n\n closeAll() {\n for (const serviceSocket of this._socketMap.values()) {\n serviceSocket.close();\n }\n }\n\n async broadcastReload(clientName: string | undefined, changedFileSet: Set<string>) {\n for (const serviceSocket of this._socketMap.values()) {\n await serviceSocket.send(Uuid.new().toString(), {\n name: \"reload\",\n body: {\n clientName,\n changedFileSet,\n },\n });\n }\n }\n\n async emitToServer<T extends ServiceEventListener<unknown, unknown>>(\n eventType: Type<T>,\n infoSelector: (item: T[\"$info\"]) => boolean,\n data: T[\"$data\"],\n ) {\n const eventName = eventType.prototype.eventName as string;\n const targetKeys = Array.from(this._socketMap.values())\n .flatMap((subSock) => subSock.getEventListeners(eventName))\n .filter((item) => infoSelector(item.info as T[\"$info\"]))\n .map((item) => item.key);\n\n for (const subSock of this._socketMap.values()) {\n const subTargetKeys = subSock.filterEventTargetKeys(targetKeys);\n if (subTargetKeys.length > 0) {\n await subSock.send(Uuid.new().toString(), {\n name: \"evt:on\",\n body: {\n keys: subTargetKeys,\n data,\n },\n });\n }\n }\n }\n\n private async _processRequest(\n serviceSocket: ServiceSocket,\n uuid: string,\n message: ServiceClientMessage,\n ): Promise<number> {\n try {\n if (message.name.includes(\".\") && Array.isArray(message.body)) {\n const [serviceName, methodName] = message.name.split(\".\");\n\n const result = await this._executor.runMethod({\n serviceName,\n methodName,\n params: message.body,\n socket: serviceSocket,\n });\n\n return await serviceSocket.send(uuid, { name: \"response\", body: result });\n } else if (message.name === \"evt:add\") {\n const { key, name, info } = message.body as { key: string; name: string; info: unknown };\n serviceSocket.addEventListener(key, name, info);\n return await serviceSocket.send(uuid, { name: \"response\" });\n } else if (message.name === \"evt:remove\") {\n const { key } = message.body as { key: string };\n serviceSocket.removeEventListener(key);\n return await serviceSocket.send(uuid, { name: \"response\" });\n } else if (message.name === \"evt:gets\") {\n const { name } = message.body as { name: string };\n const infos = Array.from(this._socketMap.values()).flatMap((subSock) => subSock.getEventListeners(name));\n return await serviceSocket.send(uuid, { name: \"response\", body: infos });\n } else if (message.name === \"evt:emit\") {\n const { keys, data } = message.body as { keys: string[]; data: unknown };\n\n for (const subSock of this._socketMap.values()) {\n const targetKeys = subSock.filterEventTargetKeys(keys);\n if (targetKeys.length > 0) {\n await subSock.send(uuid, {\n name: \"evt:on\",\n body: {\n keys: targetKeys,\n data,\n },\n });\n }\n }\n\n return await serviceSocket.send(uuid, { name: \"response\" });\n } else if (message.name === \"auth\") {\n const token = message.body;\n serviceSocket.authTokenPayload = await this._jwt.verify(token);\n return await serviceSocket.send(uuid, { name: \"response\" });\n } else {\n const err = new Error(\"\uC694\uCCAD\uC774 \uC798\uBABB\uB418\uC5C8\uC2B5\uB2C8\uB2E4.\");\n\n return await serviceSocket.send(uuid, {\n name: \"error\",\n body: {\n name: err.name,\n message: err.message,\n stack: err.stack,\n code: \"BAD_MESSAGE\",\n },\n });\n }\n } catch (err) {\n const error =\n err instanceof Error ? err : new Error(typeof err === \"string\" ? err : \"\uC54C \uC218 \uC5C6\uB294 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD558\uC600\uC2B5\uB2C8\uB2E4.\");\n\n return serviceSocket.send(uuid, {\n name: \"error\",\n body: {\n name: error.name,\n message: error.message,\n code: \"INTERNAL_ERROR\",\n stack: error.stack,\n },\n });\n }\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,8 +1,8 @@
1
1
  import { LazyGcMap } from "@simplysm/core-common";
2
2
  import { fsExists, fsReadJson, FsWatcher } from "@simplysm/core-node";
3
3
  import path from "path";
4
- import { createConsola } from "consola";
5
- const logger = createConsola().withTag("service-server:ConfigManager");
4
+ import consola from "consola";
5
+ const logger = consola.withTag("service-server:ConfigManager");
6
6
  class ConfigManager {
7
7
  // 값: Config 객체, 키: 파일 경로
8
8
  static _cache = new LazyGcMap({
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/utils/config-manager.ts"],
4
- "sourcesContent": ["import { LazyGcMap } from \"@simplysm/core-common\";\nimport { fsExists, fsReadJson, FsWatcher } from \"@simplysm/core-node\";\nimport path from \"path\";\nimport { createConsola } from \"consola\";\n\nconst logger = createConsola().withTag(\"service-server:ConfigManager\");\n\nexport class ConfigManager {\n // \uAC12: Config \uAC1D\uCCB4, \uD0A4: \uD30C\uC77C \uACBD\uB85C\n private static readonly _cache = new LazyGcMap<string, unknown>({\n gcInterval: 10 * 60 * 1000, // 10\uBD84\uB9C8\uB2E4\n expireTime: 60 * 60 * 1000, // 1\uC2DC\uAC04 \uB9CC\uB8CC\n onExpire: async (filePath) => {\n logger.debug(`\uC124\uC815 \uCE90\uC2DC \uB9CC\uB8CC \uBC0F \uAC10\uC2DC \uD574\uC81C: ${path.basename(filePath)}`);\n await ConfigManager._closeWatcher(filePath);\n },\n });\n\n private static readonly _watchers = new Map<string, FsWatcher>();\n\n static async getConfig<T>(filePath: string): Promise<T | undefined> {\n // 1. \uCE90\uC2DC \uC801\uC911 (\uC2DC\uAC04 \uC790\uB3D9 \uAC31\uC2E0)\n if (this._cache.has(filePath)) {\n return this._cache.get(filePath) as T;\n }\n\n if (!(await fsExists(filePath))) return undefined;\n\n // 2. \uB85C\uB4DC \uBC0F \uCE90\uC2DC\n const config = await fsReadJson(filePath);\n this._cache.set(filePath, config);\n\n // 3. Watcher \uB4F1\uB85D\n if (!this._watchers.has(filePath)) {\n try {\n const watcher = await FsWatcher.watch([filePath]);\n this._watchers.set(filePath, watcher);\n\n watcher.onChange({ delay: 100 }, async () => {\n if (!(await fsExists(filePath))) {\n this._cache.delete(filePath);\n await this._closeWatcher(filePath);\n logger.debug(`\uC124\uC815 \uD30C\uC77C \uC0AD\uC81C\uB428: ${path.basename(filePath)}`);\n return;\n }\n\n try {\n const newConfig = await fsReadJson(filePath);\n this._cache.set(filePath, newConfig);\n logger.debug(`\uC124\uC815 \uD30C\uC77C \uC2E4\uC2DC\uAC04 \uAC31\uC2E0: ${path.basename(filePath)}`);\n } catch (err) {\n logger.warn(`\uC124\uC815 \uD30C\uC77C \uAC31\uC2E0 \uC2E4\uD328: ${filePath}`, err);\n }\n });\n } catch (err) {\n logger.error(`\uAC10\uC2DC \uC2E4\uD328: ${filePath}`, err);\n }\n }\n\n return config as T;\n }\n\n private static async _closeWatcher(filePath: string) {\n const watcher = this._watchers.get(filePath);\n if (watcher != null) {\n await watcher.close();\n this._watchers.delete(filePath);\n }\n }\n}\n"],
5
- "mappings": "AAAA,SAAS,iBAAiB;AAC1B,SAAS,UAAU,YAAY,iBAAiB;AAChD,OAAO,UAAU;AACjB,SAAS,qBAAqB;AAE9B,MAAM,SAAS,cAAc,EAAE,QAAQ,8BAA8B;AAE9D,MAAM,cAAc;AAAA;AAAA,EAEzB,OAAwB,SAAS,IAAI,UAA2B;AAAA,IAC9D,YAAY,KAAK,KAAK;AAAA;AAAA,IACtB,YAAY,KAAK,KAAK;AAAA;AAAA,IACtB,UAAU,OAAO,aAAa;AAC5B,aAAO,MAAM,4EAAqB,KAAK,SAAS,QAAQ,CAAC,EAAE;AAC3D,YAAM,cAAc,cAAc,QAAQ;AAAA,IAC5C;AAAA,EACF,CAAC;AAAA,EAED,OAAwB,YAAY,oBAAI,IAAuB;AAAA,EAE/D,aAAa,UAAa,UAA0C;AAElE,QAAI,KAAK,OAAO,IAAI,QAAQ,GAAG;AAC7B,aAAO,KAAK,OAAO,IAAI,QAAQ;AAAA,IACjC;AAEA,QAAI,CAAE,MAAM,SAAS,QAAQ,EAAI,QAAO;AAGxC,UAAM,SAAS,MAAM,WAAW,QAAQ;AACxC,SAAK,OAAO,IAAI,UAAU,MAAM;AAGhC,QAAI,CAAC,KAAK,UAAU,IAAI,QAAQ,GAAG;AACjC,UAAI;AACF,cAAM,UAAU,MAAM,UAAU,MAAM,CAAC,QAAQ,CAAC;AAChD,aAAK,UAAU,IAAI,UAAU,OAAO;AAEpC,gBAAQ,SAAS,EAAE,OAAO,IAAI,GAAG,YAAY;AAC3C,cAAI,CAAE,MAAM,SAAS,QAAQ,GAAI;AAC/B,iBAAK,OAAO,OAAO,QAAQ;AAC3B,kBAAM,KAAK,cAAc,QAAQ;AACjC,mBAAO,MAAM,iDAAc,KAAK,SAAS,QAAQ,CAAC,EAAE;AACpD;AAAA,UACF;AAEA,cAAI;AACF,kBAAM,YAAY,MAAM,WAAW,QAAQ;AAC3C,iBAAK,OAAO,IAAI,UAAU,SAAS;AACnC,mBAAO,MAAM,8DAAiB,KAAK,SAAS,QAAQ,CAAC,EAAE;AAAA,UACzD,SAAS,KAAK;AACZ,mBAAO,KAAK,wDAAgB,QAAQ,IAAI,GAAG;AAAA,UAC7C;AAAA,QACF,CAAC;AAAA,MACH,SAAS,KAAK;AACZ,eAAO,MAAM,8BAAU,QAAQ,IAAI,GAAG;AAAA,MACxC;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,aAAqB,cAAc,UAAkB;AACnD,UAAM,UAAU,KAAK,UAAU,IAAI,QAAQ;AAC3C,QAAI,WAAW,MAAM;AACnB,YAAM,QAAQ,MAAM;AACpB,WAAK,UAAU,OAAO,QAAQ;AAAA,IAChC;AAAA,EACF;AACF;",
4
+ "sourcesContent": ["import { LazyGcMap } from \"@simplysm/core-common\";\nimport { fsExists, fsReadJson, FsWatcher } from \"@simplysm/core-node\";\nimport path from \"path\";\nimport consola from \"consola\";\n\nconst logger = consola.withTag(\"service-server:ConfigManager\");\n\nexport class ConfigManager {\n // \uAC12: Config \uAC1D\uCCB4, \uD0A4: \uD30C\uC77C \uACBD\uB85C\n private static readonly _cache = new LazyGcMap<string, unknown>({\n gcInterval: 10 * 60 * 1000, // 10\uBD84\uB9C8\uB2E4\n expireTime: 60 * 60 * 1000, // 1\uC2DC\uAC04 \uB9CC\uB8CC\n onExpire: async (filePath) => {\n logger.debug(`\uC124\uC815 \uCE90\uC2DC \uB9CC\uB8CC \uBC0F \uAC10\uC2DC \uD574\uC81C: ${path.basename(filePath)}`);\n await ConfigManager._closeWatcher(filePath);\n },\n });\n\n private static readonly _watchers = new Map<string, FsWatcher>();\n\n static async getConfig<T>(filePath: string): Promise<T | undefined> {\n // 1. \uCE90\uC2DC \uC801\uC911 (\uC2DC\uAC04 \uC790\uB3D9 \uAC31\uC2E0)\n if (this._cache.has(filePath)) {\n return this._cache.get(filePath) as T;\n }\n\n if (!(await fsExists(filePath))) return undefined;\n\n // 2. \uB85C\uB4DC \uBC0F \uCE90\uC2DC\n const config = await fsReadJson(filePath);\n this._cache.set(filePath, config);\n\n // 3. Watcher \uB4F1\uB85D\n if (!this._watchers.has(filePath)) {\n try {\n const watcher = await FsWatcher.watch([filePath]);\n this._watchers.set(filePath, watcher);\n\n watcher.onChange({ delay: 100 }, async () => {\n if (!(await fsExists(filePath))) {\n this._cache.delete(filePath);\n await this._closeWatcher(filePath);\n logger.debug(`\uC124\uC815 \uD30C\uC77C \uC0AD\uC81C\uB428: ${path.basename(filePath)}`);\n return;\n }\n\n try {\n const newConfig = await fsReadJson(filePath);\n this._cache.set(filePath, newConfig);\n logger.debug(`\uC124\uC815 \uD30C\uC77C \uC2E4\uC2DC\uAC04 \uAC31\uC2E0: ${path.basename(filePath)}`);\n } catch (err) {\n logger.warn(`\uC124\uC815 \uD30C\uC77C \uAC31\uC2E0 \uC2E4\uD328: ${filePath}`, err);\n }\n });\n } catch (err) {\n logger.error(`\uAC10\uC2DC \uC2E4\uD328: ${filePath}`, err);\n }\n }\n\n return config as T;\n }\n\n private static async _closeWatcher(filePath: string) {\n const watcher = this._watchers.get(filePath);\n if (watcher != null) {\n await watcher.close();\n this._watchers.delete(filePath);\n }\n }\n}\n"],
5
+ "mappings": "AAAA,SAAS,iBAAiB;AAC1B,SAAS,UAAU,YAAY,iBAAiB;AAChD,OAAO,UAAU;AACjB,OAAO,aAAa;AAEpB,MAAM,SAAS,QAAQ,QAAQ,8BAA8B;AAEtD,MAAM,cAAc;AAAA;AAAA,EAEzB,OAAwB,SAAS,IAAI,UAA2B;AAAA,IAC9D,YAAY,KAAK,KAAK;AAAA;AAAA,IACtB,YAAY,KAAK,KAAK;AAAA;AAAA,IACtB,UAAU,OAAO,aAAa;AAC5B,aAAO,MAAM,4EAAqB,KAAK,SAAS,QAAQ,CAAC,EAAE;AAC3D,YAAM,cAAc,cAAc,QAAQ;AAAA,IAC5C;AAAA,EACF,CAAC;AAAA,EAED,OAAwB,YAAY,oBAAI,IAAuB;AAAA,EAE/D,aAAa,UAAa,UAA0C;AAElE,QAAI,KAAK,OAAO,IAAI,QAAQ,GAAG;AAC7B,aAAO,KAAK,OAAO,IAAI,QAAQ;AAAA,IACjC;AAEA,QAAI,CAAE,MAAM,SAAS,QAAQ,EAAI,QAAO;AAGxC,UAAM,SAAS,MAAM,WAAW,QAAQ;AACxC,SAAK,OAAO,IAAI,UAAU,MAAM;AAGhC,QAAI,CAAC,KAAK,UAAU,IAAI,QAAQ,GAAG;AACjC,UAAI;AACF,cAAM,UAAU,MAAM,UAAU,MAAM,CAAC,QAAQ,CAAC;AAChD,aAAK,UAAU,IAAI,UAAU,OAAO;AAEpC,gBAAQ,SAAS,EAAE,OAAO,IAAI,GAAG,YAAY;AAC3C,cAAI,CAAE,MAAM,SAAS,QAAQ,GAAI;AAC/B,iBAAK,OAAO,OAAO,QAAQ;AAC3B,kBAAM,KAAK,cAAc,QAAQ;AACjC,mBAAO,MAAM,iDAAc,KAAK,SAAS,QAAQ,CAAC,EAAE;AACpD;AAAA,UACF;AAEA,cAAI;AACF,kBAAM,YAAY,MAAM,WAAW,QAAQ;AAC3C,iBAAK,OAAO,IAAI,UAAU,SAAS;AACnC,mBAAO,MAAM,8DAAiB,KAAK,SAAS,QAAQ,CAAC,EAAE;AAAA,UACzD,SAAS,KAAK;AACZ,mBAAO,KAAK,wDAAgB,QAAQ,IAAI,GAAG;AAAA,UAC7C;AAAA,QACF,CAAC;AAAA,MACH,SAAS,KAAK;AACZ,eAAO,MAAM,8BAAU,QAAQ,IAAI,GAAG;AAAA,MACxC;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,aAAqB,cAAc,UAAkB;AACnD,UAAM,UAAU,KAAK,UAAU,IAAI,QAAQ;AAC3C,QAAI,WAAW,MAAM;AACnB,YAAM,QAAQ,MAAM;AACpB,WAAK,UAAU,OAAO,QAAQ;AAAA,IAChC;AAAA,EACF;AACF;",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@simplysm/service-server",
3
3
  "sideEffects": false,
4
- "version": "13.0.0-beta.36",
4
+ "version": "13.0.0-beta.41",
5
5
  "description": "심플리즘 패키지 - 서비스 모듈 (server)",
6
6
  "author": "김석래",
7
7
  "repository": {
@@ -34,11 +34,11 @@
34
34
  "semver": "^7.7.4",
35
35
  "utf-8-validate": "^6.0.6",
36
36
  "ws": "^8.19.0",
37
- "@simplysm/core-common": "13.0.0-beta.36",
38
- "@simplysm/orm-common": "13.0.0-beta.36",
39
- "@simplysm/core-node": "13.0.0-beta.36",
40
- "@simplysm/orm-node": "13.0.0-beta.36",
41
- "@simplysm/service-common": "13.0.0-beta.36"
37
+ "@simplysm/core-common": "13.0.0-beta.41",
38
+ "@simplysm/core-node": "13.0.0-beta.41",
39
+ "@simplysm/orm-common": "13.0.0-beta.41",
40
+ "@simplysm/orm-node": "13.0.0-beta.41",
41
+ "@simplysm/service-common": "13.0.0-beta.41"
42
42
  },
43
43
  "devDependencies": {
44
44
  "@types/nodemailer": "^7.0.9",