@simplysm/service-server 13.0.69 → 13.0.71

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/README.md +48 -249
  2. package/dist/auth/jwt-manager.js +2 -2
  3. package/dist/auth/jwt-manager.js.map +1 -1
  4. package/dist/core/define-service.js +2 -2
  5. package/dist/core/define-service.js.map +1 -1
  6. package/dist/core/service-executor.js +5 -5
  7. package/dist/core/service-executor.js.map +1 -1
  8. package/dist/legacy/v1-auto-update-handler.d.ts +2 -2
  9. package/dist/legacy/v1-auto-update-handler.js +2 -2
  10. package/dist/legacy/v1-auto-update-handler.js.map +1 -1
  11. package/dist/service-server.js +11 -11
  12. package/dist/service-server.js.map +1 -1
  13. package/dist/services/auto-update-service.js +1 -1
  14. package/dist/services/auto-update-service.js.map +1 -1
  15. package/dist/services/orm-service.js +6 -6
  16. package/dist/services/orm-service.js.map +1 -1
  17. package/dist/transport/http/http-request-handler.js +1 -1
  18. package/dist/transport/http/http-request-handler.js.map +1 -1
  19. package/dist/transport/http/static-file-handler.js +3 -3
  20. package/dist/transport/http/upload-handler.js +2 -2
  21. package/dist/transport/http/upload-handler.js.map +1 -1
  22. package/dist/transport/socket/service-socket.js +2 -2
  23. package/dist/transport/socket/service-socket.js.map +1 -1
  24. package/dist/transport/socket/websocket-handler.d.ts.map +1 -1
  25. package/dist/transport/socket/websocket-handler.js +11 -9
  26. package/dist/transport/socket/websocket-handler.js.map +1 -1
  27. package/dist/utils/config-manager.js +7 -7
  28. package/dist/utils/config-manager.js.map +1 -1
  29. package/package.json +9 -9
  30. package/src/auth/jwt-manager.ts +2 -2
  31. package/src/core/define-service.ts +2 -2
  32. package/src/core/service-executor.ts +13 -13
  33. package/src/legacy/v1-auto-update-handler.ts +8 -8
  34. package/src/service-server.ts +28 -28
  35. package/src/services/auto-update-service.ts +1 -1
  36. package/src/services/orm-service.ts +6 -6
  37. package/src/transport/http/http-request-handler.ts +5 -5
  38. package/src/transport/http/static-file-handler.ts +7 -7
  39. package/src/transport/http/upload-handler.ts +3 -3
  40. package/src/transport/socket/service-socket.ts +4 -4
  41. package/src/transport/socket/websocket-handler.ts +12 -10
  42. package/src/utils/config-manager.ts +11 -11
  43. package/tests/define-service.spec.ts +85 -0
  44. package/tests/orm-service.spec.ts +83 -0
  45. package/tests/service-executor.spec.ts +114 -0
  46. package/docs/authentication.md +0 -114
  47. package/docs/built-in-services.md +0 -100
  48. package/docs/server.md +0 -374
  49. package/docs/transport.md +0 -273
package/README.md CHANGED
@@ -1,279 +1,78 @@
1
1
  # @simplysm/service-server
2
2
 
3
- A Fastify-based HTTP/WebSocket server package. Provides server features needed for full-stack applications, including RPC-style service invocation, JWT authentication, file upload, static file serving, and real-time events.
4
-
5
- Used together with `@simplysm/service-client` to configure WebSocket/HTTP communication between client and server.
3
+ Simplysm package - service module (server)
6
4
 
7
5
  ## Installation
8
6
 
9
- ```bash
10
- npm install @simplysm/service-server
11
- # or
12
7
  pnpm add @simplysm/service-server
13
- ```
14
-
15
- ## Main Modules
16
-
17
- ### Core Functions and Classes
18
-
19
- - [`createServiceServer`](#basic-server-configuration) - Factory function for creating a `ServiceServer` instance
20
- - [`ServiceServer`](docs/server.md#serviceserver) - Main server class. Creates a Fastify instance and configures routes/plugins
21
- - [`defineService`](#custom-services) - Defines a service with a name and factory function
22
- - [`ServiceContext`](docs/server.md#servicecontext) - Context object passed to service factory functions
23
- - [`createServiceContext`](docs/server.md#createservicecontext) - Factory function that creates a `ServiceContext` (exported for advanced use)
24
- - [`runServiceMethod`](docs/server.md#runservicemethod) - Dispatches a service method call with auth checks and execution
25
- - [`ServiceDefinition`](docs/server.md#servicedefinition) - Type describing a registered service (name + factory + authPermissions)
26
- - [`ServiceMethods`](docs/server.md#servicemethods) - Type utility that extracts method signatures from a `ServiceDefinition`
27
-
28
- ### Authentication
29
-
30
- - [`auth`](#authentication) - Wrapper that sets authentication requirements at service or method level
31
- - [`getServiceAuthPermissions`](docs/authentication.md#getserviceauthpermissions) - Reads auth permissions from an `auth()`-wrapped function
32
- - [`signJwt`](docs/authentication.md#jwt-functions) - Generate a JWT token (HS256, 12-hour expiration)
33
- - [`verifyJwt`](docs/authentication.md#jwt-functions) - Verify and decode a JWT token
34
- - [`decodeJwt`](docs/authentication.md#jwt-functions) - Decode a JWT token without verification (synchronous)
35
- - [`AuthTokenPayload`](docs/authentication.md#authtokenpayload) - JWT payload interface (includes `roles`, `data`)
36
-
37
- ### Transport Layer - WebSocket
38
-
39
- - [`WebSocketHandler`](docs/transport.md#websockethandler) - Interface for managing multiple WebSocket connections, routing messages, and broadcasting events
40
- - `createWebSocketHandler` - Factory function that creates a `WebSocketHandler` instance
41
- - [`ServiceSocket`](docs/transport.md#servicesocket) - Interface wrapping a single WebSocket connection. Manages ping/pong, protocol encoding/decoding, event listener management
42
- - `createServiceSocket` - Factory function that creates a `ServiceSocket` instance
43
-
44
- ### Transport Layer - HTTP
45
-
46
- - `handleHttpRequest` - Handles service method calls via HTTP at `/api/:service/:method`
47
- - `handleUpload` - Handles multipart file upload at `/upload` (auth required)
48
- - `handleStaticFile` - Serves static files from `rootPath/www/`. Prevents path traversal and blocks hidden files
49
-
50
- ### Protocol
51
-
52
- - [`ProtocolWrapper`](docs/transport.md#protocolwrapper) - Interface for message encoding/decoding. Messages over 30KB are processed in worker threads
53
- - `createProtocolWrapper` - Factory function that creates a `ProtocolWrapper` instance
54
-
55
- ### Built-in Services
56
-
57
- - [`OrmService`](docs/built-in-services.md#ormservice) - DB connection/transaction/query execution (WebSocket only, auth required)
58
- - `OrmServiceType` - Type alias for `OrmService` method signatures (for client-side type sharing)
59
- - [`AutoUpdateService`](docs/built-in-services.md#autoupdateservice) - App auto-update (provides latest version query and download path)
60
- - `AutoUpdateServiceType` - Type alias for `AutoUpdateService` method signatures (for client-side type sharing)
61
-
62
- ### Utilities
63
-
64
- - [`getConfig`](docs/server.md#getconfig) - JSON config file loading with caching and real-time file watching
65
-
66
- ### Legacy
67
-
68
- - [`handleV1Connection`](docs/transport.md#legacy-handlev1connection) - V1 protocol client compatibility handling (supports auto-update only)
69
-
70
- ## Usage
71
-
72
- ### Basic Server Configuration
73
-
74
- ```typescript
75
- import { createServiceServer } from "@simplysm/service-server";
76
-
77
- const server = createServiceServer({
78
- port: 8080,
79
- rootPath: "/app/data",
80
- services: [MyService],
81
- });
82
-
83
- // Start server
84
- await server.listen();
85
-
86
- // Receive events
87
- server.on("ready", () => {
88
- console.log("Server ready");
89
- });
90
-
91
- server.on("close", () => {
92
- console.log("Server closed");
93
- });
94
-
95
- // Close server
96
- await server.close();
97
- ```
98
-
99
- ### Server Options
100
8
 
101
- See [`ServiceServerOptions`](docs/server.md#server-options-serviceserveroptions) for detailed configuration options including SSL, authentication, and directory structure.
9
+ ## Source Index
102
10
 
103
- ### Custom Services
11
+ ### Types
104
12
 
105
- Services are defined using the `defineService` function. Service methods are called via RPC from the client.
13
+ | Source | Exports | Description | Test |
14
+ |--------|---------|-------------|------|
15
+ | `src/types/server-options.ts` | `ServiceServerOptions` | Configuration interface for the service server (port, SSL, auth, services) | - |
106
16
 
107
- ```typescript
108
- import { defineService } from "@simplysm/service-server";
17
+ ### Auth
109
18
 
110
- export const MyService = defineService("My", (ctx) => ({
111
- hello: async (name: string): Promise<string> => {
112
- return `Hello, ${name}!`;
113
- },
19
+ | Source | Exports | Description | Test |
20
+ |--------|---------|-------------|------|
21
+ | `src/auth/auth-token-payload.ts` | `AuthTokenPayload` | JWT payload interface extending JWTPayload with roles and auth data | - |
22
+ | `src/auth/jwt-manager.ts` | `signJwt`, `verifyJwt`, `decodeJwt` | Sign, verify, and decode HS256 JWT tokens using the jose library | - |
114
23
 
115
- getServerTime: async (): Promise<Date> => {
116
- return new Date();
117
- },
118
- }));
24
+ ### Core
119
25
 
120
- // Export type for client-side type sharing
121
- export type MyServiceMethods = import("@simplysm/service-server").ServiceMethods<typeof MyService>;
122
- ```
26
+ | Source | Exports | Description | Test |
27
+ |--------|---------|-------------|------|
28
+ | `src/core/define-service.ts` | `ServiceContext`, `createServiceContext`, `getServiceAuthPermissions`, `auth`, `ServiceDefinition`, `defineService`, `ServiceMethods` | Define services with typed context, auth wrappers, and method type extraction | `define-service.spec.ts` |
29
+ | `src/core/service-executor.ts` | `runServiceMethod` | Resolve a service method call and enforce auth permission checks | `service-executor.spec.ts` |
123
30
 
124
- #### ServiceContext
31
+ ### Transport - Socket
125
32
 
126
- The `ctx` parameter provides access to server resources:
33
+ | Source | Exports | Description | Test |
34
+ |--------|---------|-------------|------|
35
+ | `src/transport/socket/websocket-handler.ts` | `WebSocketHandler`, `createWebSocketHandler` | Manage multiple WebSocket connections, route messages, and broadcast events | - |
36
+ | `src/transport/socket/service-socket.ts` | `ServiceSocket`, `createServiceSocket` | Manage a single WebSocket connection with protocol encoding and keep-alive | - |
127
37
 
128
- - `ctx.server` - ServiceServer instance
129
- - `ctx.socket` - ServiceSocket instance (WebSocket only, undefined for HTTP)
130
- - `ctx.http` - HTTP request/reply objects (HTTP only, undefined for WebSocket)
131
- - `ctx.authInfo` - Authentication info (set via JWT token)
132
- - `ctx.clientName` - Client identifier
133
- - `ctx.clientPath` - Resolved per-client directory path (`rootPath/www/{clientName}`)
134
- - `ctx.getConfig(section)` - Get server config by section name
38
+ ### Transport - HTTP
135
39
 
136
- ### Authentication
40
+ | Source | Exports | Description | Test |
41
+ |--------|---------|-------------|------|
42
+ | `src/transport/http/http-request-handler.ts` | `handleHttpRequest` | Handle HTTP GET/POST API requests with JWT auth and parameter parsing | - |
43
+ | `src/transport/http/upload-handler.ts` | `handleUpload` | Handle multipart file uploads with JWT auth and UUID-based storage | - |
44
+ | `src/transport/http/static-file-handler.ts` | `handleStaticFile` | Serve static files from the www directory with path traversal protection | - |
137
45
 
138
- Use the `auth()` wrapper to set authentication requirements at service or method level:
139
-
140
- ```typescript
141
- import { defineService, auth } from "@simplysm/service-server";
142
-
143
- interface UserAuthInfo {
144
- userId: number;
145
- role: string;
146
- }
147
-
148
- // Service-level auth: all methods require authentication
149
- export const UserService = defineService("User", auth((ctx) => ({
150
- getProfile: async (): Promise<unknown> => {
151
- const userId = (ctx.authInfo as UserAuthInfo)?.userId;
152
- // ...
153
- },
154
-
155
- deleteUser: auth(["admin"], async (targetId: number): Promise<void> => {
156
- // Only users with admin role can call
157
- }),
158
- })));
159
-
160
- export type UserServiceMethods = import("@simplysm/service-server").ServiceMethods<typeof UserService>;
161
- ```
162
-
163
- #### Auth Patterns
164
-
165
- **Method-level auth only:**
166
- ```typescript
167
- export const MyService = defineService("My", (ctx) => ({
168
- publicMethod: async (): Promise<void> => {
169
- // No auth required
170
- },
171
-
172
- protectedMethod: auth(async (): Promise<void> => {
173
- // Auth required
174
- }),
175
-
176
- adminMethod: auth(["admin"], async (): Promise<void> => {
177
- // Auth + admin role required
178
- }),
179
- }));
180
- ```
181
-
182
- **Service-level auth with method override:**
183
- ```typescript
184
- // All methods require authentication by default
185
- export const SecureService = defineService("Secure", auth((ctx) => ({
186
- normalMethod: async (): Promise<void> => {
187
- // Auth required (inherited from service level)
188
- },
189
-
190
- adminMethod: auth(["admin"], async (): Promise<void> => {
191
- // Auth + admin role required
192
- }),
193
- })));
194
- ```
195
-
196
- See [Authentication](docs/authentication.md) for JWT token management and permission handling.
197
-
198
- ### HTTP/WebSocket Communication
199
-
200
- Service methods can be called via HTTP or WebSocket:
201
-
202
- ```
203
- GET /api/My/hello?json=["World"]
204
- POST /api/My/hello
205
- ```
206
-
207
- See [HTTP API Call](docs/transport.md#http-api-call) and [ServiceSocket](docs/transport.md#servicesocket) for transport layer details.
208
-
209
- ### File Upload
210
-
211
- Upload files via multipart request to the `/upload` endpoint:
212
-
213
- ```typescript
214
- const formData = new FormData();
215
- formData.append("file", file);
216
-
217
- const response = await fetch("/upload", {
218
- method: "POST",
219
- headers: { Authorization: `Bearer ${token}` },
220
- body: formData,
221
- });
222
- ```
223
-
224
- See [File Upload](docs/transport.md#file-upload) for more details.
225
-
226
- ### Event Publishing
227
-
228
- Publish real-time events to connected WebSocket clients:
229
-
230
- ```typescript
231
- import { defineEvent } from "@simplysm/service-common";
232
-
233
- export const OrderUpdatedEvent = defineEvent<
234
- { orderId: number },
235
- { status: string }
236
- >("OrderUpdatedEvent");
237
-
238
- await server.emitEvent(
239
- OrderUpdatedEvent,
240
- (info) => info.orderId === 123,
241
- { status: "completed" },
242
- );
243
- ```
244
-
245
- See [Real-time Event Publishing](docs/transport.md#real-time-event-publishing) for more details.
46
+ ### Protocol
246
47
 
247
- ### Built-in Services
48
+ | Source | Exports | Description | Test |
49
+ |--------|---------|-------------|------|
50
+ | `src/protocol/protocol-wrapper.ts` | `ProtocolWrapper`, `createProtocolWrapper` | Encode/decode service messages with automatic worker thread offloading | - |
248
51
 
249
- The package provides several built-in services:
52
+ ### Services
250
53
 
251
- - [`OrmService`](docs/built-in-services.md#ormservice) - Database operations (MySQL, MSSQL, PostgreSQL)
252
- - [`AutoUpdateService`](docs/built-in-services.md#autoupdateservice) - Client app auto-updates
54
+ | Source | Exports | Description | Test |
55
+ |--------|---------|-------------|------|
56
+ | `src/services/orm-service.ts` | `OrmService`, `OrmServiceType` | Built-in service exposing ORM database operations over WebSocket | `orm-service.spec.ts` |
57
+ | `src/services/auto-update-service.ts` | `AutoUpdateService`, `AutoUpdateServiceType` | Built-in service for serving the latest app update package by platform | - |
253
58
 
254
- Register them like any other service:
59
+ ### Utils
255
60
 
256
- ```typescript
257
- import { createServiceServer, OrmService } from "@simplysm/service-server";
61
+ | Source | Exports | Description | Test |
62
+ |--------|---------|-------------|------|
63
+ | `src/utils/config-manager.ts` | `getConfig` | Load and cache JSON config files with live-reload via file watcher | - |
258
64
 
259
- const server = createServiceServer({
260
- port: 8080,
261
- rootPath: "/app/data",
262
- auth: { jwtSecret: "secret" },
263
- services: [OrmService],
264
- });
265
- ```
65
+ ### Legacy
266
66
 
267
- ## Security
67
+ | Source | Exports | Description | Test |
68
+ |--------|---------|-------------|------|
69
+ | `src/legacy/v1-auto-update-handler.ts` | `handleV1Connection` | Handle V1 legacy WebSocket clients for auto-update only | - |
268
70
 
269
- - **Helmet**: `@fastify/helmet` plugin automatically sets security headers like CSP, HSTS
270
- - **CORS**: `@fastify/cors` plugin configures CORS
271
- - **Path Traversal Prevention**: Static file handler and client name validation block `..`, `/`, `\` characters
272
- - **Hidden File Blocking**: Files starting with `.` return a 403 response
273
- - **Directory Trailing Slash Redirect**: Directory requests without a trailing slash are redirected to the same path with a trailing slash (standard web server behavior)
274
- - **Graceful Shutdown**: Detects `SIGINT`/`SIGTERM` signals to safely close WebSocket connections and server (10-second timeout)
71
+ ### Main
275
72
 
276
- See [Security](docs/server.md#security) for more details.
73
+ | Source | Exports | Description | Test |
74
+ |--------|---------|-------------|------|
75
+ | `src/service-server.ts` | `ServiceServer`, `createServiceServer` | Main Fastify-based HTTP/WebSocket server with routing and graceful shutdown | - |
277
76
 
278
77
  ## License
279
78
 
@@ -10,9 +10,9 @@ async function verifyJwt(jwtSecret, token) {
10
10
  return payload;
11
11
  } catch (err) {
12
12
  if (err != null && typeof err === "object" && "code" in err && err.code === "ERR_JWT_EXPIRED") {
13
- throw new Error("\uD1A0\uD070\uC774 \uB9CC\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");
13
+ throw new Error("Token has expired.");
14
14
  }
15
- throw new Error("\uC720\uD6A8\uD558\uC9C0 \uC54A\uC740 \uD1A0\uD070\uC785\uB2C8\uB2E4.");
15
+ throw new Error("Invalid token.");
16
16
  }
17
17
  }
18
18
  function decodeJwt(token) {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/auth/jwt-manager.ts"],
4
- "mappings": "AAAA,YAAY,UAAU;AAGtB,eAAsB,QACpB,WACA,SACiB;AACjB,QAAM,SAAS,IAAI,YAAY,EAAE,OAAO,SAAS;AAEjD,SAAO,IAAI,KAAK,QAAQ,OAAO,EAC5B,mBAAmB,EAAE,KAAK,QAAQ,CAAC,EACnC,YAAY,EACZ,kBAAkB,KAAK,EACvB,KAAK,MAAM;AAChB;AAEA,eAAsB,UACpB,WACA,OACsC;AACtC,QAAM,SAAS,IAAI,YAAY,EAAE,OAAO,SAAS;AAEjD,MAAI;AACF,UAAM,EAAE,QAAQ,IAAI,MAAM,KAAK,UAAU,OAAO,MAAM;AACtD,WAAO;AAAA,EACT,SAAS,KAAK;AACZ,QAAI,OAAO,QAAQ,OAAO,QAAQ,YAAY,UAAU,OAAO,IAAI,SAAS,mBAAmB;AAC7F,YAAM,IAAI,MAAM,gEAAc;AAAA,IAChC;AACA,UAAM,IAAI,MAAM,uEAAgB;AAAA,EAClC;AACF;AAEO,SAAS,UAA+B,OAA4C;AACzF,SAAO,KAAK,UAAU,KAAK;AAC7B;",
4
+ "mappings": "AAAA,YAAY,UAAU;AAGtB,eAAsB,QACpB,WACA,SACiB;AACjB,QAAM,SAAS,IAAI,YAAY,EAAE,OAAO,SAAS;AAEjD,SAAO,IAAI,KAAK,QAAQ,OAAO,EAC5B,mBAAmB,EAAE,KAAK,QAAQ,CAAC,EACnC,YAAY,EACZ,kBAAkB,KAAK,EACvB,KAAK,MAAM;AAChB;AAEA,eAAsB,UACpB,WACA,OACsC;AACtC,QAAM,SAAS,IAAI,YAAY,EAAE,OAAO,SAAS;AAEjD,MAAI;AACF,UAAM,EAAE,QAAQ,IAAI,MAAM,KAAK,UAAU,OAAO,MAAM;AACtD,WAAO;AAAA,EACT,SAAS,KAAK;AACZ,QAAI,OAAO,QAAQ,OAAO,QAAQ,YAAY,UAAU,OAAO,IAAI,SAAS,mBAAmB;AAC7F,YAAM,IAAI,MAAM,oBAAoB;AAAA,IACtC;AACA,UAAM,IAAI,MAAM,gBAAgB;AAAA,EAClC;AACF;AAEO,SAAS,UAA+B,OAA4C;AACzF,SAAO,KAAK,UAAU,KAAK;AAC7B;",
5
5
  "names": []
6
6
  }
@@ -14,7 +14,7 @@ function createServiceContext(server, socket, http, legacy) {
14
14
  const name = socket?.clientName ?? http?.clientName ?? legacy?.clientName;
15
15
  if (name == null) return void 0;
16
16
  if (name === "" || name.includes("..") || name.includes("/") || name.includes("\\")) {
17
- throw new Error(`\uC720\uD6A8\uD558\uC9C0 \uC54A\uC740 \uD074\uB77C\uC774\uC5B8\uD2B8 \uBA85\uC785\uB2C8\uB2E4: ${name}`);
17
+ throw new Error(`Invalid client name: ${name}`);
18
18
  }
19
19
  return name;
20
20
  },
@@ -38,7 +38,7 @@ function createServiceContext(server, socket, http, legacy) {
38
38
  }
39
39
  }
40
40
  const config = configParent[section];
41
- if (config == null) throw new Error(`\uC124\uC815 \uC139\uC158\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${section}`);
41
+ if (config == null) throw new Error(`Configuration section not found: ${section}`);
42
42
  return config;
43
43
  }
44
44
  };
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/core/define-service.ts"],
4
- "mappings": "AAGA,SAAS,gBAAgB;AACzB,SAAS,iBAAiB;AAC1B,OAAO,UAAU;AAuBV,SAAS,qBACd,QACA,QACA,MACA,QAC2B;AAC3B,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IAEA,IAAI,WAAkC;AACpC,aAAQ,QAAQ,kBAAkB,QAAQ,MAAM,kBAAkB;AAAA,IAGpE;AAAA,IAEA,IAAI,aAAiC;AACnC,YAAM,OAAO,QAAQ,cAAc,MAAM,cAAc,QAAQ;AAC/D,UAAI,QAAQ,KAAM,QAAO;AAEzB,UAAI,SAAS,MAAM,KAAK,SAAS,IAAI,KAAK,KAAK,SAAS,GAAG,KAAK,KAAK,SAAS,IAAI,GAAG;AACnF,cAAM,IAAI,MAAM,kGAAuB,IAAI,EAAE;AAAA,MAC/C;AAEA,aAAO;AAAA,IACT;AAAA,IAEA,IAAI,aAAiC;AACnC,YAAM,OAAO,KAAK;AAClB,aAAO,QAAQ,OAAO,SAAY,KAAK,QAAQ,OAAO,QAAQ,UAAU,OAAO,IAAI;AAAA,IACrF;AAAA,IAEA,MAAM,UAAa,SAA6B;AAC9C,UAAI,eAA8C,CAAC;AAEnD,YAAM,eAAe,KAAK,QAAQ,OAAO,QAAQ,UAAU,cAAc;AACzE,YAAM,aAAa,MAAM,UAA6B,YAAY;AAClE,UAAI,cAAc,MAAM;AACtB,uBAAe;AAAA,MACjB;AAEA,YAAM,aAAa,KAAK;AACxB,UAAI,cAAc,MAAM;AACtB,cAAM,iBAAiB,KAAK,QAAQ,YAAY,cAAc;AAC9D,cAAM,eAAe,MAAM,UAA6B,cAAc;AACtE,YAAI,gBAAgB,MAAM;AACxB,yBAAe,SAAS,cAAc,YAAY;AAAA,QACpD;AAAA,MACF;AAEA,YAAM,SAAS,aAAa,OAAO;AACnC,UAAI,UAAU,KAAM,OAAM,IAAI,MAAM,iFAAqB,OAAO,EAAE;AAClE,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAIA,MAAM,mBAAmB,uBAAO,iBAAiB;AAG1C,SAAS,0BAA0B,IAAoC;AAC5E,SAAQ,GAA0C,gBAAgB;AACpE;AAeO,SAAS,KAAK,iBAAsC,SAA8B;AACvF,QAAM,cAAc,MAAM,QAAQ,eAAe,IAAI,kBAAkB,CAAC;AACxE,QAAM,KAAK,MAAM,QAAQ,eAAe,IAAI,UAAW;AAGvD,QAAM,UAAU,IAAI,SAAoB,GAAG,GAAG,IAAI;AAClD,EAAC,QAA+C,gBAAgB,IAAI;AAEpE,SAAO;AACT;AAyBO,SAAS,cACd,MACA,SAC6B;AAC7B,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,iBAAiB,0BAA0B,OAAO;AAAA,EACpD;AACF;",
4
+ "mappings": "AAGA,SAAS,gBAAgB;AACzB,SAAS,iBAAiB;AAC1B,OAAO,UAAU;AAuBV,SAAS,qBACd,QACA,QACA,MACA,QAC2B;AAC3B,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IAEA,IAAI,WAAkC;AACpC,aAAQ,QAAQ,kBAAkB,QAAQ,MAAM,kBAAkB;AAAA,IAGpE;AAAA,IAEA,IAAI,aAAiC;AACnC,YAAM,OAAO,QAAQ,cAAc,MAAM,cAAc,QAAQ;AAC/D,UAAI,QAAQ,KAAM,QAAO;AAEzB,UAAI,SAAS,MAAM,KAAK,SAAS,IAAI,KAAK,KAAK,SAAS,GAAG,KAAK,KAAK,SAAS,IAAI,GAAG;AACnF,cAAM,IAAI,MAAM,wBAAwB,IAAI,EAAE;AAAA,MAChD;AAEA,aAAO;AAAA,IACT;AAAA,IAEA,IAAI,aAAiC;AACnC,YAAM,OAAO,KAAK;AAClB,aAAO,QAAQ,OAAO,SAAY,KAAK,QAAQ,OAAO,QAAQ,UAAU,OAAO,IAAI;AAAA,IACrF;AAAA,IAEA,MAAM,UAAa,SAA6B;AAC9C,UAAI,eAA8C,CAAC;AAEnD,YAAM,eAAe,KAAK,QAAQ,OAAO,QAAQ,UAAU,cAAc;AACzE,YAAM,aAAa,MAAM,UAA6B,YAAY;AAClE,UAAI,cAAc,MAAM;AACtB,uBAAe;AAAA,MACjB;AAEA,YAAM,aAAa,KAAK;AACxB,UAAI,cAAc,MAAM;AACtB,cAAM,iBAAiB,KAAK,QAAQ,YAAY,cAAc;AAC9D,cAAM,eAAe,MAAM,UAA6B,cAAc;AACtE,YAAI,gBAAgB,MAAM;AACxB,yBAAe,SAAS,cAAc,YAAY;AAAA,QACpD;AAAA,MACF;AAEA,YAAM,SAAS,aAAa,OAAO;AACnC,UAAI,UAAU,KAAM,OAAM,IAAI,MAAM,oCAAoC,OAAO,EAAE;AACjF,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAIA,MAAM,mBAAmB,uBAAO,iBAAiB;AAG1C,SAAS,0BAA0B,IAAoC;AAC5E,SAAQ,GAA0C,gBAAgB;AACpE;AAeO,SAAS,KAAK,iBAAsC,SAA8B;AACvF,QAAM,cAAc,MAAM,QAAQ,eAAe,IAAI,kBAAkB,CAAC;AACxE,QAAM,KAAK,MAAM,QAAQ,eAAe,IAAI,UAAW;AAGvD,QAAM,UAAU,IAAI,SAAoB,GAAG,GAAG,IAAI;AAClD,EAAC,QAA+C,gBAAgB,IAAI;AAEpE,SAAO;AACT;AAyBO,SAAS,cACd,MACA,SAC6B;AAC7B,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,iBAAiB,0BAA0B,OAAO;AAAA,EACpD;AACF;",
5
5
  "names": []
6
6
  }
@@ -2,19 +2,19 @@ import { createServiceContext, getServiceAuthPermissions } from "./define-servic
2
2
  async function runServiceMethod(server, def) {
3
3
  const serviceDef = server.options.services.find((item) => item.name === def.serviceName);
4
4
  if (serviceDef == null) {
5
- throw new Error(`\uC11C\uBE44\uC2A4[${def.serviceName}]\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.`);
5
+ throw new Error(`Service [${def.serviceName}] not found.`);
6
6
  }
7
7
  const clientName = def.socket?.clientName ?? def.http?.clientName;
8
8
  if (clientName != null) {
9
9
  if (clientName.includes("..") || clientName.includes("/") || clientName.includes("\\")) {
10
- throw new Error(`[Security] \uC720\uD6A8\uD558\uC9C0 \uC54A\uC740 \uD074\uB77C\uC774\uC5B8\uD2B8\uBA85\uC785\uB2C8\uB2E4: ${clientName}`);
10
+ throw new Error(`[Security] Invalid client name: ${clientName}`);
11
11
  }
12
12
  }
13
13
  const ctx = createServiceContext(server, def.socket, def.http);
14
14
  const methods = serviceDef.factory(ctx);
15
15
  const method = methods[def.methodName];
16
16
  if (typeof method !== "function") {
17
- throw new Error(`\uBA54\uC18C\uB4DC[${def.serviceName}.${def.methodName}]\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.`);
17
+ throw new Error(`Method [${def.serviceName}.${def.methodName}] not found.`);
18
18
  }
19
19
  if (server.options.auth != null) {
20
20
  const methodPerms = getServiceAuthPermissions(method);
@@ -22,12 +22,12 @@ async function runServiceMethod(server, def) {
22
22
  if (requiredPerms != null) {
23
23
  const authTokenPayload = def.socket?.authTokenPayload ?? def.http?.authTokenPayload;
24
24
  if (authTokenPayload == null) {
25
- throw new Error("\uB85C\uADF8\uC778\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.");
25
+ throw new Error("Login is required.");
26
26
  }
27
27
  if (requiredPerms.length > 0) {
28
28
  const hasPerm = requiredPerms.some((perm) => authTokenPayload.roles.includes(perm));
29
29
  if (!hasPerm) {
30
- throw new Error("\uAD8C\uD55C\uC774 \uBD80\uC871\uD569\uB2C8\uB2E4.");
30
+ throw new Error("Insufficient permissions.");
31
31
  }
32
32
  }
33
33
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/core/service-executor.ts"],
4
- "mappings": "AAGA,SAAS,sBAAsB,iCAAiC;AAEhE,eAAsB,iBACpB,QACA,KAOkB;AAElB,QAAM,aAAa,OAAO,QAAQ,SAAS,KAAK,CAAC,SAAS,KAAK,SAAS,IAAI,WAAW;AAEvF,MAAI,cAAc,MAAM;AACtB,UAAM,IAAI,MAAM,sBAAO,IAAI,WAAW,uDAAe;AAAA,EACvD;AAGA,QAAM,aAAa,IAAI,QAAQ,cAAc,IAAI,MAAM;AACvD,MAAI,cAAc,MAAM;AACtB,QAAI,WAAW,SAAS,IAAI,KAAK,WAAW,SAAS,GAAG,KAAK,WAAW,SAAS,IAAI,GAAG;AACtF,YAAM,IAAI,MAAM,4GAAiC,UAAU,EAAE;AAAA,IAC/D;AAAA,EACF;AAGA,QAAM,MAAM,qBAAqB,QAAQ,IAAI,QAAQ,IAAI,IAAI;AAG7D,QAAM,UAAU,WAAW,QAAQ,GAAG;AAGtC,QAAM,SAAU,QAAoC,IAAI,UAAU;AAClE,MAAI,OAAO,WAAW,YAAY;AAChC,UAAM,IAAI,MAAM,sBAAO,IAAI,WAAW,IAAI,IAAI,UAAU,uDAAe;AAAA,EACzE;AAGA,MAAI,OAAO,QAAQ,QAAQ,MAAM;AAE/B,UAAM,cAAc,0BAA0B,MAAM;AACpD,UAAM,gBAAgB,eAAe,WAAW;AAEhD,QAAI,iBAAiB,MAAM;AACzB,YAAM,mBAAmB,IAAI,QAAQ,oBAAoB,IAAI,MAAM;AAEnE,UAAI,oBAAoB,MAAM;AAC5B,cAAM,IAAI,MAAM,0DAAa;AAAA,MAC/B;AAEA,UAAI,cAAc,SAAS,GAAG;AAC5B,cAAM,UAAU,cAAc,KAAK,CAAC,SAAS,iBAAiB,MAAM,SAAS,IAAI,CAAC;AAClF,YAAI,CAAC,SAAS;AACZ,gBAAM,IAAI,MAAM,oDAAY;AAAA,QAC9B;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,SAAO,MAAM,OAAO,GAAG,IAAI,MAAM;AACnC;",
4
+ "mappings": "AAGA,SAAS,sBAAsB,iCAAiC;AAEhE,eAAsB,iBACpB,QACA,KAOkB;AAElB,QAAM,aAAa,OAAO,QAAQ,SAAS,KAAK,CAAC,SAAS,KAAK,SAAS,IAAI,WAAW;AAEvF,MAAI,cAAc,MAAM;AACtB,UAAM,IAAI,MAAM,YAAY,IAAI,WAAW,cAAc;AAAA,EAC3D;AAGA,QAAM,aAAa,IAAI,QAAQ,cAAc,IAAI,MAAM;AACvD,MAAI,cAAc,MAAM;AACtB,QAAI,WAAW,SAAS,IAAI,KAAK,WAAW,SAAS,GAAG,KAAK,WAAW,SAAS,IAAI,GAAG;AACtF,YAAM,IAAI,MAAM,mCAAmC,UAAU,EAAE;AAAA,IACjE;AAAA,EACF;AAGA,QAAM,MAAM,qBAAqB,QAAQ,IAAI,QAAQ,IAAI,IAAI;AAG7D,QAAM,UAAU,WAAW,QAAQ,GAAG;AAGtC,QAAM,SAAU,QAAoC,IAAI,UAAU;AAClE,MAAI,OAAO,WAAW,YAAY;AAChC,UAAM,IAAI,MAAM,WAAW,IAAI,WAAW,IAAI,IAAI,UAAU,cAAc;AAAA,EAC5E;AAGA,MAAI,OAAO,QAAQ,QAAQ,MAAM;AAE/B,UAAM,cAAc,0BAA0B,MAAM;AACpD,UAAM,gBAAgB,eAAe,WAAW;AAEhD,QAAI,iBAAiB,MAAM;AACzB,YAAM,mBAAmB,IAAI,QAAQ,oBAAoB,IAAI,MAAM;AAEnE,UAAI,oBAAoB,MAAM;AAC5B,cAAM,IAAI,MAAM,oBAAoB;AAAA,MACtC;AAEA,UAAI,cAAc,SAAS,GAAG;AAC5B,cAAM,UAAU,cAAc,KAAK,CAAC,SAAS,iBAAiB,MAAM,SAAS,IAAI,CAAC;AAClF,YAAI,CAAC,SAAS;AACZ,gBAAM,IAAI,MAAM,2BAA2B;AAAA,QAC7C;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,SAAO,MAAM,OAAO,GAAG,IAAI,MAAM;AACnC;",
5
5
  "names": []
6
6
  }
@@ -1,7 +1,7 @@
1
1
  import type { WebSocket } from "ws";
2
2
  /**
3
- * V1 레거시 클라이언트 처리 (auto-update 지원)
4
- * 다른 모든 요청은 업그레이드 유도 에러를 반환합니다.
3
+ * V1 legacy client handler (only auto-update supported).
4
+ * All other requests return an upgrade-required error.
5
5
  */
6
6
  export declare function handleV1Connection(socket: WebSocket, autoUpdateMethods: {
7
7
  getLastVersion: (platform: string) => Promise<any>;
@@ -21,14 +21,14 @@ function handleV1Connection(socket, autoUpdateMethods, clientNameSetter) {
21
21
  reqUuid: msg.uuid,
22
22
  state: "error",
23
23
  body: {
24
- message: "\uC571 \uC5C5\uB370\uC774\uD2B8\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.",
24
+ message: "App upgrade is required.",
25
25
  code: "UPGRADE_REQUIRED"
26
26
  }
27
27
  };
28
28
  socket.send(JSON.stringify(response));
29
29
  }
30
30
  } catch (err) {
31
- logger.warn("V1 \uBA54\uC2DC\uC9C0 \uCC98\uB9AC \uC624\uB958", err);
31
+ logger.warn("V1 message processing error", err);
32
32
  }
33
33
  });
34
34
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/legacy/v1-auto-update-handler.ts"],
4
- "mappings": "AACA,OAAO,aAAa;AAEpB,MAAM,SAAS,QAAQ,QAAQ,oCAAoC;AAoB5D,SAAS,mBACd,QACA,mBACA,kBACA;AAEA,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,2BAAmB,IAAI,UAAU;AAEjC,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
+ "mappings": "AACA,OAAO,aAAa;AAEpB,MAAM,SAAS,QAAQ,QAAQ,oCAAoC;AAoB5D,SAAS,mBACd,QACA,mBACA,kBACA;AAEA,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,2BAAmB,IAAI,UAAU;AAEjC,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,+BAA+B,GAAG;AAAA,IAChD;AAAA,EACF,CAAC;AACH;",
5
5
  "names": []
6
6
  }
@@ -32,7 +32,7 @@ class ServiceServer extends EventEmitter {
32
32
  _wsHandler;
33
33
  fastify;
34
34
  async listen() {
35
- logger.info(`\uC11C\uBC84 \uC2DC\uC791... ${env.VER ?? ""}`);
35
+ logger.info(`Server starting... ${env.VER ?? ""}`);
36
36
  await this.fastify.register(fastifyWebsocket);
37
37
  await this.fastify.register(fastifyHelmet, {
38
38
  global: true,
@@ -123,23 +123,23 @@ class ServiceServer extends EventEmitter {
123
123
  }
124
124
  });
125
125
  this.fastify.server.on("error", (err) => {
126
- logger.error("HTTP \uC11C\uBC84 \uC624\uB958 \uBC1C\uC0DD", err);
126
+ logger.error("HTTP server error", err);
127
127
  });
128
128
  await this.fastify.listen({ port: this.options.port, host: "0.0.0.0" });
129
129
  this._registerGracefulShutdown();
130
130
  this.isOpen = true;
131
- logger.info(`\uC11C\uBC84 \uC2DC\uC791\uB428 (port: ${this.options.port})`);
131
+ logger.info(`Server started (port: ${this.options.port})`);
132
132
  this.emit("ready");
133
133
  }
134
134
  async close() {
135
135
  this._wsHandler.closeAll();
136
136
  await this.fastify.close();
137
137
  this.isOpen = false;
138
- logger.debug("\uC11C\uBC84 \uC885\uB8CC\uB428");
138
+ logger.debug("Server closed");
139
139
  this.emit("close");
140
140
  }
141
141
  async broadcastReload(clientName, changedFileSet) {
142
- logger.debug("\uC11C\uBC84\uB0B4 \uBAA8\uB4E0 \uD074\uB77C\uC774\uC5B8\uD2B8 RELOAD \uBA85\uB839 \uC804\uC1A1");
142
+ logger.debug("Broadcasting RELOAD to all server clients");
143
143
  await this._wsHandler.broadcastReload(clientName, changedFileSet);
144
144
  }
145
145
  async emitEvent(eventDef, infoSelector, data) {
@@ -147,30 +147,30 @@ class ServiceServer extends EventEmitter {
147
147
  }
148
148
  async generateAuthToken(payload) {
149
149
  const jwtSecret = this.options.auth?.jwtSecret;
150
- if (jwtSecret == null) throw new Error("JWT Secret\uC774 \uC815\uC758\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.");
150
+ if (jwtSecret == null) throw new Error("JWT Secret is not defined.");
151
151
  return signJwt(jwtSecret, payload);
152
152
  }
153
153
  async verifyAuthToken(token) {
154
154
  const jwtSecret = this.options.auth?.jwtSecret;
155
- if (jwtSecret == null) throw new Error("JWT Secret\uC774 \uC815\uC758\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.");
155
+ if (jwtSecret == null) throw new Error("JWT Secret is not defined.");
156
156
  return verifyJwt(jwtSecret, token);
157
157
  }
158
158
  _registerGracefulShutdown() {
159
159
  const shutdownHandler = async (signal) => {
160
- logger.info(`${signal} \uC2DC\uADF8\uB110 \uAC10\uC9C0. \uC11C\uBC84 \uC885\uB8CC \uD504\uB85C\uC138\uC2A4 \uC2DC\uC791...`);
160
+ logger.info(`${signal} signal received. Starting server shutdown...`);
161
161
  const forceExitTimer = setTimeout(() => {
162
- logger.error("\uC11C\uBC84 \uC885\uB8CC \uC2DC\uAC04 \uCD08\uACFC (10\uCD08). \uAC15\uC81C \uC885\uB8CC\uD569\uB2C8\uB2E4.");
162
+ logger.error("Server shutdown timed out (10s). Forcing exit.");
163
163
  process.exit(1);
164
164
  }, 1e4);
165
165
  try {
166
166
  if (this.isOpen) {
167
167
  await this.close();
168
168
  }
169
- logger.info("\uC11C\uBC84\uAC00 \uC548\uC804\uD558\uAC8C \uC885\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");
169
+ logger.info("Server shut down gracefully.");
170
170
  clearTimeout(forceExitTimer);
171
171
  process.exit(0);
172
172
  } catch (err) {
173
- logger.error("\uC11C\uBC84 \uC885\uB8CC \uC911 \uC624\uB958 \uBC1C\uC0DD", err);
173
+ logger.error("Error during server shutdown", err);
174
174
  process.exit(1);
175
175
  }
176
176
  };
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/service-server.ts"],
4
- "mappings": "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",
4
+ "mappings": "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",
5
5
  "names": []
6
6
  }
@@ -5,7 +5,7 @@ import { defineService } from "../core/define-service.js";
5
5
  const AutoUpdateService = defineService("AutoUpdate", (ctx) => ({
6
6
  async getLastVersion(platform) {
7
7
  const clientPath = ctx.clientPath;
8
- if (clientPath == null) throw new Error("\uD074\uB77C\uC774\uC5B8\uD2B8 \uACBD\uB85C\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
8
+ if (clientPath == null) throw new Error("Client path not found.");
9
9
  if (!await fsExists(path.resolve(clientPath, platform, "updates"))) return void 0;
10
10
  const updates = await fsReaddir(path.resolve(clientPath, platform, "updates"));
11
11
  const versions = updates.map((item) => ({
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/services/auto-update-service.ts"],
4
- "mappings": "AAAA,OAAO,UAAU;AACjB,OAAO,YAAY;AACnB,SAAS,UAAU,WAAW,iBAAiB;AAC/C,SAAS,qBAA0C;AAE5C,MAAM,oBAAoB,cAAc,cAAc,CAAC,SAAS;AAAA,EACrE,MAAM,eAAe,UAMnB;AACA,UAAM,aAAa,IAAI;AACvB,QAAI,cAAc,KAAM,OAAM,IAAI,MAAM,iGAAsB;AAE9D,QAAI,CAAE,MAAM,SAAS,KAAK,QAAQ,YAAY,UAAU,SAAS,CAAC,EAAI,QAAO;AAE7E,UAAM,UAAU,MAAM,UAAU,KAAK,QAAQ,YAAY,UAAU,SAAS,CAAC;AAC7E,UAAM,WAAW,QACd,IAAI,CAAC,UAAU;AAAA,MACd,UAAU;AAAA,MACV,SAAS,KAAK,SAAS,MAAM,KAAK,QAAQ,IAAI,CAAC;AAAA,MAC/C,SAAS,KAAK,QAAQ,IAAI;AAAA,IAC5B,EAAE,EACD,OAAO,CAAC,SAAS;AAChB,UAAI,aAAa,WAAW;AAC1B,eAAO,KAAK,YAAY,UAAU,YAAY,KAAK,KAAK,OAAO;AAAA,MACjE,OAAO;AACL,eAAO,KAAK,YAAY,UAAU,YAAY,KAAK,KAAK,OAAO;AAAA,MACjE;AAAA,IACF,CAAC;AAEH,UAAM,UAAU,OAAO;AAAA,MACrB,SAAS,IAAI,CAAC,SAAS,KAAK,OAAO;AAAA,MACnC;AAAA,IACF;AAEA,QAAI,WAAW,KAAM,QAAO;AAE5B,UAAM,cAAc,SAAS,KAAK,CAAC,SAAS,KAAK,YAAY,OAAO;AACpE,QAAI,eAAe,KAAM,QAAO;AAEhC,UAAM,eACJ,MAAM,UAAU,IAAI,cAAc,IAAI,UAAU,WAAW,YAAY,QAAQ;AAEjF,WAAO;AAAA,MACL,SAAS,QAAQ,SAAS;AAAA,MAC1B;AAAA,IACF;AAAA,EACF;AACF,EAAE;",
4
+ "mappings": "AAAA,OAAO,UAAU;AACjB,OAAO,YAAY;AACnB,SAAS,UAAU,WAAW,iBAAiB;AAC/C,SAAS,qBAA0C;AAE5C,MAAM,oBAAoB,cAAc,cAAc,CAAC,SAAS;AAAA,EACrE,MAAM,eAAe,UAMnB;AACA,UAAM,aAAa,IAAI;AACvB,QAAI,cAAc,KAAM,OAAM,IAAI,MAAM,wBAAwB;AAEhE,QAAI,CAAE,MAAM,SAAS,KAAK,QAAQ,YAAY,UAAU,SAAS,CAAC,EAAI,QAAO;AAE7E,UAAM,UAAU,MAAM,UAAU,KAAK,QAAQ,YAAY,UAAU,SAAS,CAAC;AAC7E,UAAM,WAAW,QACd,IAAI,CAAC,UAAU;AAAA,MACd,UAAU;AAAA,MACV,SAAS,KAAK,SAAS,MAAM,KAAK,QAAQ,IAAI,CAAC;AAAA,MAC/C,SAAS,KAAK,QAAQ,IAAI;AAAA,IAC5B,EAAE,EACD,OAAO,CAAC,SAAS;AAChB,UAAI,aAAa,WAAW;AAC1B,eAAO,KAAK,YAAY,UAAU,YAAY,KAAK,KAAK,OAAO;AAAA,MACjE,OAAO;AACL,eAAO,KAAK,YAAY,UAAU,YAAY,KAAK,KAAK,OAAO;AAAA,MACjE;AAAA,IACF,CAAC;AAEH,UAAM,UAAU,OAAO;AAAA,MACrB,SAAS,IAAI,CAAC,SAAS,KAAK,OAAO;AAAA,MACnC;AAAA,IACF;AAEA,QAAI,WAAW,KAAM,QAAO;AAE5B,UAAM,cAAc,SAAS,KAAK,CAAC,SAAS,KAAK,YAAY,OAAO;AACpE,QAAI,eAAe,KAAM,QAAO;AAEhC,UAAM,eACJ,MAAM,UAAU,IAAI,cAAc,IAAI,UAAU,WAAW,YAAY,QAAQ;AAEjF,WAAO;AAAA,MACL,SAAS,QAAQ,SAAS;AAAA,MAC1B;AAAA,IACF;AAAA,EACF;AACF,EAAE;",
5
5
  "names": []
6
6
  }