@simplysm/service-server 13.0.0-beta.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +587 -0
- package/dist/auth/auth-token-payload.js +1 -0
- package/dist/auth/auth-token-payload.js.map +7 -0
- package/dist/auth/auth.decorators.js +46 -0
- package/dist/auth/auth.decorators.js.map +7 -0
- package/dist/auth/jwt-manager.js +35 -0
- package/dist/auth/jwt-manager.js.map +7 -0
- package/dist/core/service-base.js +47 -0
- package/dist/core/service-base.js.map +7 -0
- package/dist/core/service-executor.js +46 -0
- package/dist/core/service-executor.js.map +7 -0
- package/dist/core-common/src/common.types.d.ts +74 -0
- package/dist/core-common/src/common.types.d.ts.map +1 -0
- package/dist/core-common/src/env.d.ts +6 -0
- package/dist/core-common/src/env.d.ts.map +1 -0
- package/dist/core-common/src/errors/argument-error.d.ts +25 -0
- package/dist/core-common/src/errors/argument-error.d.ts.map +1 -0
- package/dist/core-common/src/errors/not-implemented-error.d.ts +29 -0
- package/dist/core-common/src/errors/not-implemented-error.d.ts.map +1 -0
- package/dist/core-common/src/errors/sd-error.d.ts +27 -0
- package/dist/core-common/src/errors/sd-error.d.ts.map +1 -0
- package/dist/core-common/src/errors/timeout-error.d.ts +31 -0
- package/dist/core-common/src/errors/timeout-error.d.ts.map +1 -0
- package/dist/core-common/src/extensions/arr-ext.d.ts +15 -0
- package/dist/core-common/src/extensions/arr-ext.d.ts.map +1 -0
- package/dist/core-common/src/extensions/arr-ext.helpers.d.ts +19 -0
- package/dist/core-common/src/extensions/arr-ext.helpers.d.ts.map +1 -0
- package/dist/core-common/src/extensions/arr-ext.types.d.ts +215 -0
- package/dist/core-common/src/extensions/arr-ext.types.d.ts.map +1 -0
- package/dist/core-common/src/extensions/map-ext.d.ts +57 -0
- package/dist/core-common/src/extensions/map-ext.d.ts.map +1 -0
- package/dist/core-common/src/extensions/set-ext.d.ts +36 -0
- package/dist/core-common/src/extensions/set-ext.d.ts.map +1 -0
- package/dist/core-common/src/features/debounce-queue.d.ts +53 -0
- package/dist/core-common/src/features/debounce-queue.d.ts.map +1 -0
- package/dist/core-common/src/features/event-emitter.d.ts +66 -0
- package/dist/core-common/src/features/event-emitter.d.ts.map +1 -0
- package/dist/core-common/src/features/serial-queue.d.ts +47 -0
- package/dist/core-common/src/features/serial-queue.d.ts.map +1 -0
- package/dist/core-common/src/index.d.ts +32 -0
- package/dist/core-common/src/index.d.ts.map +1 -0
- package/dist/core-common/src/types/date-only.d.ts +152 -0
- package/dist/core-common/src/types/date-only.d.ts.map +1 -0
- package/dist/core-common/src/types/date-time.d.ts +96 -0
- package/dist/core-common/src/types/date-time.d.ts.map +1 -0
- package/dist/core-common/src/types/lazy-gc-map.d.ts +80 -0
- package/dist/core-common/src/types/lazy-gc-map.d.ts.map +1 -0
- package/dist/core-common/src/types/time.d.ts +68 -0
- package/dist/core-common/src/types/time.d.ts.map +1 -0
- package/dist/core-common/src/types/uuid.d.ts +35 -0
- package/dist/core-common/src/types/uuid.d.ts.map +1 -0
- package/dist/core-common/src/utils/bytes.d.ts +51 -0
- package/dist/core-common/src/utils/bytes.d.ts.map +1 -0
- package/dist/core-common/src/utils/date-format.d.ts +90 -0
- package/dist/core-common/src/utils/date-format.d.ts.map +1 -0
- package/dist/core-common/src/utils/json.d.ts +34 -0
- package/dist/core-common/src/utils/json.d.ts.map +1 -0
- package/dist/core-common/src/utils/num.d.ts +60 -0
- package/dist/core-common/src/utils/num.d.ts.map +1 -0
- package/dist/core-common/src/utils/obj.d.ts +258 -0
- package/dist/core-common/src/utils/obj.d.ts.map +1 -0
- package/dist/core-common/src/utils/path.d.ts +23 -0
- package/dist/core-common/src/utils/path.d.ts.map +1 -0
- package/dist/core-common/src/utils/primitive.d.ts +18 -0
- package/dist/core-common/src/utils/primitive.d.ts.map +1 -0
- package/dist/core-common/src/utils/str.d.ts +103 -0
- package/dist/core-common/src/utils/str.d.ts.map +1 -0
- package/dist/core-common/src/utils/template-strings.d.ts +84 -0
- package/dist/core-common/src/utils/template-strings.d.ts.map +1 -0
- package/dist/core-common/src/utils/transferable.d.ts +47 -0
- package/dist/core-common/src/utils/transferable.d.ts.map +1 -0
- package/dist/core-common/src/utils/wait.d.ts +19 -0
- package/dist/core-common/src/utils/wait.d.ts.map +1 -0
- package/dist/core-common/src/utils/xml.d.ts +36 -0
- package/dist/core-common/src/utils/xml.d.ts.map +1 -0
- package/dist/core-common/src/zip/sd-zip.d.ts +80 -0
- package/dist/core-common/src/zip/sd-zip.d.ts.map +1 -0
- package/dist/core-node/src/features/fs-watcher.d.ts +70 -0
- package/dist/core-node/src/features/fs-watcher.d.ts.map +1 -0
- package/dist/core-node/src/index.d.ts +7 -0
- package/dist/core-node/src/index.d.ts.map +1 -0
- package/dist/core-node/src/utils/fs.d.ts +197 -0
- package/dist/core-node/src/utils/fs.d.ts.map +1 -0
- package/dist/core-node/src/utils/path.d.ts +75 -0
- package/dist/core-node/src/utils/path.d.ts.map +1 -0
- package/dist/core-node/src/worker/create-worker.d.ts +23 -0
- package/dist/core-node/src/worker/create-worker.d.ts.map +1 -0
- package/dist/core-node/src/worker/types.d.ts +67 -0
- package/dist/core-node/src/worker/types.d.ts.map +1 -0
- package/dist/core-node/src/worker/worker.d.ts +27 -0
- package/dist/core-node/src/worker/worker.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +7 -0
- package/dist/legacy/v1-auto-update-handler.js +38 -0
- package/dist/legacy/v1-auto-update-handler.js.map +7 -0
- package/dist/orm-common/src/db-context.d.ts +669 -0
- package/dist/orm-common/src/db-context.d.ts.map +1 -0
- package/dist/orm-common/src/errors/db-transaction-error.d.ts +51 -0
- package/dist/orm-common/src/errors/db-transaction-error.d.ts.map +1 -0
- package/dist/orm-common/src/exec/executable.d.ts +79 -0
- package/dist/orm-common/src/exec/executable.d.ts.map +1 -0
- package/dist/orm-common/src/exec/queryable.d.ts +708 -0
- package/dist/orm-common/src/exec/queryable.d.ts.map +1 -0
- package/dist/orm-common/src/exec/search-parser.d.ts +72 -0
- package/dist/orm-common/src/exec/search-parser.d.ts.map +1 -0
- package/dist/orm-common/src/expr/expr-unit.d.ts +25 -0
- package/dist/orm-common/src/expr/expr-unit.d.ts.map +1 -0
- package/dist/orm-common/src/expr/expr.d.ts +1369 -0
- package/dist/orm-common/src/expr/expr.d.ts.map +1 -0
- package/dist/orm-common/src/index.d.ts +32 -0
- package/dist/orm-common/src/index.d.ts.map +1 -0
- package/dist/orm-common/src/models/system-migration.d.ts +10 -0
- package/dist/orm-common/src/models/system-migration.d.ts.map +1 -0
- package/dist/orm-common/src/query-builder/base/expr-renderer-base.d.ts +95 -0
- package/dist/orm-common/src/query-builder/base/expr-renderer-base.d.ts.map +1 -0
- package/dist/orm-common/src/query-builder/base/query-builder-base.d.ts +66 -0
- package/dist/orm-common/src/query-builder/base/query-builder-base.d.ts.map +1 -0
- package/dist/orm-common/src/query-builder/mssql/mssql-expr-renderer.d.ts +84 -0
- package/dist/orm-common/src/query-builder/mssql/mssql-expr-renderer.d.ts.map +1 -0
- package/dist/orm-common/src/query-builder/mssql/mssql-query-builder.d.ts +45 -0
- package/dist/orm-common/src/query-builder/mssql/mssql-query-builder.d.ts.map +1 -0
- package/dist/orm-common/src/query-builder/mysql/mysql-expr-renderer.d.ts +84 -0
- package/dist/orm-common/src/query-builder/mysql/mysql-expr-renderer.d.ts.map +1 -0
- package/dist/orm-common/src/query-builder/mysql/mysql-query-builder.d.ts +54 -0
- package/dist/orm-common/src/query-builder/mysql/mysql-query-builder.d.ts.map +1 -0
- package/dist/orm-common/src/query-builder/postgresql/postgresql-expr-renderer.d.ts +84 -0
- package/dist/orm-common/src/query-builder/postgresql/postgresql-expr-renderer.d.ts.map +1 -0
- package/dist/orm-common/src/query-builder/postgresql/postgresql-query-builder.d.ts +52 -0
- package/dist/orm-common/src/query-builder/postgresql/postgresql-query-builder.d.ts.map +1 -0
- package/dist/orm-common/src/query-builder/query-builder.d.ts +7 -0
- package/dist/orm-common/src/query-builder/query-builder.d.ts.map +1 -0
- package/dist/orm-common/src/schema/factory/column-builder.d.ts +394 -0
- package/dist/orm-common/src/schema/factory/column-builder.d.ts.map +1 -0
- package/dist/orm-common/src/schema/factory/index-builder.d.ts +151 -0
- package/dist/orm-common/src/schema/factory/index-builder.d.ts.map +1 -0
- package/dist/orm-common/src/schema/factory/relation-builder.d.ts +337 -0
- package/dist/orm-common/src/schema/factory/relation-builder.d.ts.map +1 -0
- package/dist/orm-common/src/schema/procedure-builder.d.ts +202 -0
- package/dist/orm-common/src/schema/procedure-builder.d.ts.map +1 -0
- package/dist/orm-common/src/schema/table-builder.d.ts +259 -0
- package/dist/orm-common/src/schema/table-builder.d.ts.map +1 -0
- package/dist/orm-common/src/schema/view-builder.d.ts +183 -0
- package/dist/orm-common/src/schema/view-builder.d.ts.map +1 -0
- package/dist/orm-common/src/types/column.d.ts +172 -0
- package/dist/orm-common/src/types/column.d.ts.map +1 -0
- package/dist/orm-common/src/types/db.d.ts +175 -0
- package/dist/orm-common/src/types/db.d.ts.map +1 -0
- package/dist/orm-common/src/types/expr.d.ts +474 -0
- package/dist/orm-common/src/types/expr.d.ts.map +1 -0
- package/dist/orm-common/src/types/query-def.d.ts +351 -0
- package/dist/orm-common/src/types/query-def.d.ts.map +1 -0
- package/dist/orm-common/src/utils/result-parser.d.ts +38 -0
- package/dist/orm-common/src/utils/result-parser.d.ts.map +1 -0
- package/dist/orm-node/src/connections/mssql-db-conn.d.ts +44 -0
- package/dist/orm-node/src/connections/mssql-db-conn.d.ts.map +1 -0
- package/dist/orm-node/src/connections/mysql-db-conn.d.ts +38 -0
- package/dist/orm-node/src/connections/mysql-db-conn.d.ts.map +1 -0
- package/dist/orm-node/src/connections/postgresql-db-conn.d.ts +39 -0
- package/dist/orm-node/src/connections/postgresql-db-conn.d.ts.map +1 -0
- package/dist/orm-node/src/db-conn-factory.d.ts +25 -0
- package/dist/orm-node/src/db-conn-factory.d.ts.map +1 -0
- package/dist/orm-node/src/index.d.ts +9 -0
- package/dist/orm-node/src/index.d.ts.map +1 -0
- package/dist/orm-node/src/node-db-context-executor.d.ts +77 -0
- package/dist/orm-node/src/node-db-context-executor.d.ts.map +1 -0
- package/dist/orm-node/src/pooled-db-conn.d.ts +79 -0
- package/dist/orm-node/src/pooled-db-conn.d.ts.map +1 -0
- package/dist/orm-node/src/sd-orm.d.ts +78 -0
- package/dist/orm-node/src/sd-orm.d.ts.map +1 -0
- package/dist/orm-node/src/types/db-conn.d.ts +159 -0
- package/dist/orm-node/src/types/db-conn.d.ts.map +1 -0
- package/dist/protocol/protocol-wrapper.js +64 -0
- package/dist/protocol/protocol-wrapper.js.map +7 -0
- package/dist/service-common/src/index.d.ts +8 -0
- package/dist/service-common/src/index.d.ts.map +1 -0
- package/dist/service-common/src/protocol/protocol.types.d.ts +100 -0
- package/dist/service-common/src/protocol/protocol.types.d.ts.map +1 -0
- package/dist/service-common/src/protocol/service-protocol.d.ts +63 -0
- package/dist/service-common/src/protocol/service-protocol.d.ts.map +1 -0
- package/dist/service-common/src/service-types/auto-update-service.types.d.ts +17 -0
- package/dist/service-common/src/service-types/auto-update-service.types.d.ts.map +1 -0
- package/dist/service-common/src/service-types/crypto-service.types.d.ts +22 -0
- package/dist/service-common/src/service-types/crypto-service.types.d.ts.map +1 -0
- package/dist/service-common/src/service-types/orm-service.types.d.ts +30 -0
- package/dist/service-common/src/service-types/orm-service.types.d.ts.map +1 -0
- package/dist/service-common/src/service-types/smtp-service.types.d.ts +55 -0
- package/dist/service-common/src/service-types/smtp-service.types.d.ts.map +1 -0
- package/dist/service-common/src/types.d.ts +43 -0
- package/dist/service-common/src/types.d.ts.map +1 -0
- package/dist/service-server/src/auth/auth-token-payload.d.ts +6 -0
- package/dist/service-server/src/auth/auth-token-payload.d.ts.map +1 -0
- package/dist/service-server/src/auth/auth.decorators.d.ts +19 -0
- package/dist/service-server/src/auth/auth.decorators.d.ts.map +1 -0
- package/dist/service-server/src/auth/jwt-manager.d.ts +10 -0
- package/dist/service-server/src/auth/jwt-manager.d.ts.map +1 -0
- package/dist/service-server/src/core/service-base.d.ts +19 -0
- package/dist/service-server/src/core/service-base.d.ts.map +1 -0
- package/dist/service-server/src/core/service-executor.d.ts +18 -0
- package/dist/service-server/src/core/service-executor.d.ts.map +1 -0
- package/dist/service-server/src/index.d.ts +20 -0
- package/dist/service-server/src/index.d.ts.map +1 -0
- package/dist/service-server/src/legacy/v1-auto-update-handler.d.ts +8 -0
- package/dist/service-server/src/legacy/v1-auto-update-handler.d.ts.map +1 -0
- package/dist/service-server/src/protocol/protocol-wrapper.d.ts +25 -0
- package/dist/service-server/src/protocol/protocol-wrapper.d.ts.map +1 -0
- package/dist/service-server/src/service-server.d.ts +29 -0
- package/dist/service-server/src/service-server.d.ts.map +1 -0
- package/dist/service-server/src/services/auto-update-service.d.ts +9 -0
- package/dist/service-server/src/services/auto-update-service.d.ts.map +1 -0
- package/dist/service-server/src/services/crypto-service.d.ts +10 -0
- package/dist/service-server/src/services/crypto-service.d.ts.map +1 -0
- package/dist/service-server/src/services/orm-service.d.ts +28 -0
- package/dist/service-server/src/services/orm-service.d.ts.map +1 -0
- package/dist/service-server/src/services/smtp-service.d.ts +7 -0
- package/dist/service-server/src/services/smtp-service.d.ts.map +1 -0
- package/dist/service-server/src/transport/http/http-request-handler.d.ts +12 -0
- package/dist/service-server/src/transport/http/http-request-handler.d.ts.map +1 -0
- package/dist/service-server/src/transport/http/static-file-handler.d.ts +9 -0
- package/dist/service-server/src/transport/http/static-file-handler.d.ts.map +1 -0
- package/dist/service-server/src/transport/http/upload-handler.d.ts +10 -0
- package/dist/service-server/src/transport/http/upload-handler.d.ts.map +1 -0
- package/dist/service-server/src/transport/socket/service-socket.d.ts +41 -0
- package/dist/service-server/src/transport/socket/service-socket.d.ts.map +1 -0
- package/dist/service-server/src/transport/socket/websocket-handler.d.ts +18 -0
- package/dist/service-server/src/transport/socket/websocket-handler.d.ts.map +1 -0
- package/dist/service-server/src/types/server-options.d.ts +15 -0
- package/dist/service-server/src/types/server-options.d.ts.map +1 -0
- package/dist/service-server/src/utils/config-manager.d.ts +7 -0
- package/dist/service-server/src/utils/config-manager.d.ts.map +1 -0
- package/dist/service-server/src/workers/service-protocol.worker.d.ts +15 -0
- package/dist/service-server/src/workers/service-protocol.worker.d.ts.map +1 -0
- package/dist/service-server.js +165 -0
- package/dist/service-server.js.map +7 -0
- package/dist/services/auto-update-service.js +39 -0
- package/dist/services/auto-update-service.js.map +7 -0
- package/dist/services/crypto-service.js +32 -0
- package/dist/services/crypto-service.js.map +7 -0
- package/dist/services/orm-service.js +186 -0
- package/dist/services/orm-service.js.map +7 -0
- package/dist/services/smtp-service.js +47 -0
- package/dist/services/smtp-service.js.map +7 -0
- package/dist/transport/http/http-request-handler.js +57 -0
- package/dist/transport/http/http-request-handler.js.map +7 -0
- package/dist/transport/http/static-file-handler.js +57 -0
- package/dist/transport/http/static-file-handler.js.map +7 -0
- package/dist/transport/http/upload-handler.js +71 -0
- package/dist/transport/http/upload-handler.js.map +7 -0
- package/dist/transport/socket/service-socket.js +105 -0
- package/dist/transport/socket/service-socket.js.map +7 -0
- package/dist/transport/socket/websocket-handler.js +144 -0
- package/dist/transport/socket/websocket-handler.js.map +7 -0
- package/dist/types/server-options.js +1 -0
- package/dist/types/server-options.js.map +7 -0
- package/dist/utils/config-manager.js +62 -0
- package/dist/utils/config-manager.js.map +7 -0
- package/dist/workers/service-protocol.worker.js +15 -0
- package/dist/workers/service-protocol.worker.js.map +7 -0
- package/package.json +47 -0
package/README.md
ADDED
|
@@ -0,0 +1,587 @@
|
|
|
1
|
+
# @simplysm/service-server
|
|
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.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @simplysm/service-server
|
|
11
|
+
# or
|
|
12
|
+
pnpm add @simplysm/service-server
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Main Modules
|
|
16
|
+
|
|
17
|
+
### Core Classes
|
|
18
|
+
|
|
19
|
+
| Module | Path | Description |
|
|
20
|
+
|------|------|------|
|
|
21
|
+
| `ServiceServer` | `service-server.ts` | Main server class. Creates Fastify instance and configures routes/plugins |
|
|
22
|
+
| `ServiceBase` | `core/service-base.ts` | Service base abstract class. All custom services must inherit from this |
|
|
23
|
+
| `ServiceExecutor` | `core/service-executor.ts` | Internal executor that handles service method discovery, auth checks, and execution |
|
|
24
|
+
|
|
25
|
+
### Authentication
|
|
26
|
+
|
|
27
|
+
| Module | Path | Description |
|
|
28
|
+
|------|------|------|
|
|
29
|
+
| `JwtManager` | `auth/jwt-manager.ts` | JWT token generation/verification/decoding based on jose library (HS256, 12-hour expiration) |
|
|
30
|
+
| `Authorize` | `auth/auth.decorators.ts` | Stage 3 decorator. Sets authentication permissions at class or method level |
|
|
31
|
+
| `AuthTokenPayload` | `auth/auth-token-payload.ts` | JWT payload interface (includes `roles`, `data`) |
|
|
32
|
+
|
|
33
|
+
### Transport Layer - WebSocket
|
|
34
|
+
|
|
35
|
+
| Module | Path | Description |
|
|
36
|
+
|------|------|------|
|
|
37
|
+
| `WebSocketHandler` | `transport/socket/websocket-handler.ts` | Handles WebSocket connection management, message routing, and event distribution |
|
|
38
|
+
| `ServiceSocket` | `transport/socket/service-socket.ts` | Wraps individual WebSocket connections. Manages ping/pong, protocol encoding/decoding, event listener management |
|
|
39
|
+
|
|
40
|
+
### Transport Layer - HTTP
|
|
41
|
+
|
|
42
|
+
| Module | Path | Description |
|
|
43
|
+
|------|------|------|
|
|
44
|
+
| `HttpRequestHandler` | `transport/http/http-request-handler.ts` | Calls service methods via HTTP at `/api/:service/:method` route |
|
|
45
|
+
| `UploadHandler` | `transport/http/upload-handler.ts` | Handles multipart file upload at `/upload` route (auth required) |
|
|
46
|
+
| `StaticFileHandler` | `transport/http/static-file-handler.ts` | Serves static files. Prevents path traversal and blocks hidden files |
|
|
47
|
+
|
|
48
|
+
### Protocol
|
|
49
|
+
|
|
50
|
+
| Module | Path | Description |
|
|
51
|
+
|------|------|------|
|
|
52
|
+
| `ProtocolWrapper` | `protocol/protocol-wrapper.ts` | Message encoding/decoding wrapper. Messages over 30KB are processed in worker threads |
|
|
53
|
+
|
|
54
|
+
### Built-in Services
|
|
55
|
+
|
|
56
|
+
| Module | Path | Description |
|
|
57
|
+
|------|------|------|
|
|
58
|
+
| `OrmService` | `services/orm-service.ts` | DB connection/transaction/query execution (WebSocket only, auth required) |
|
|
59
|
+
| `CryptoService` | `services/crypto-service.ts` | SHA256 hash and AES-256-CBC encryption/decryption |
|
|
60
|
+
| `SmtpService` | `services/smtp-service.ts` | nodemailer-based email sending |
|
|
61
|
+
| `AutoUpdateService` | `services/auto-update-service.ts` | App auto-update (provides latest version query and download path) |
|
|
62
|
+
|
|
63
|
+
### Utilities
|
|
64
|
+
|
|
65
|
+
| Module | Path | Description |
|
|
66
|
+
|------|------|------|
|
|
67
|
+
| `ConfigManager` | `utils/config-manager.ts` | JSON config file loading/caching/real-time monitoring (auto expiration based on LazyGcMap) |
|
|
68
|
+
|
|
69
|
+
### Legacy
|
|
70
|
+
|
|
71
|
+
| Module | Path | Description |
|
|
72
|
+
|------|------|------|
|
|
73
|
+
| `handleV1Connection` | `legacy/v1-auto-update-handler.ts` | V1 protocol client compatibility handling (supports auto-update only) |
|
|
74
|
+
|
|
75
|
+
## Usage
|
|
76
|
+
|
|
77
|
+
### Basic Server Configuration
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
import { ServiceServer } from "@simplysm/service-server";
|
|
81
|
+
|
|
82
|
+
const server = new ServiceServer({
|
|
83
|
+
port: 8080,
|
|
84
|
+
rootPath: "/app/data",
|
|
85
|
+
services: [MyService],
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// Start server
|
|
89
|
+
await server.listen();
|
|
90
|
+
|
|
91
|
+
// Receive events
|
|
92
|
+
server.on("ready", () => {
|
|
93
|
+
console.log("Server ready");
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
server.on("close", () => {
|
|
97
|
+
console.log("Server closed");
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
// Close server
|
|
101
|
+
await server.close();
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Server Options (`ServiceServerOptions`)
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
interface ServiceServerOptions {
|
|
108
|
+
/** Server root path (base directory for static files and config files) */
|
|
109
|
+
rootPath: string;
|
|
110
|
+
/** Listen port */
|
|
111
|
+
port: number;
|
|
112
|
+
/** SSL/TLS config (enables HTTPS) */
|
|
113
|
+
ssl?: {
|
|
114
|
+
pfxBytes: Uint8Array;
|
|
115
|
+
passphrase: string;
|
|
116
|
+
};
|
|
117
|
+
/** JWT authentication config */
|
|
118
|
+
auth?: {
|
|
119
|
+
jwtSecret: string;
|
|
120
|
+
};
|
|
121
|
+
/** List of service classes to register */
|
|
122
|
+
services: Type<ServiceBase>[];
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
The following structure is expected under `rootPath`:
|
|
127
|
+
|
|
128
|
+
```
|
|
129
|
+
rootPath/
|
|
130
|
+
.config.json # Root config file
|
|
131
|
+
www/ # Static file root
|
|
132
|
+
uploads/ # Upload file storage directory
|
|
133
|
+
{clientName}/ # Per-client directory
|
|
134
|
+
.config.json # Per-client config file
|
|
135
|
+
index.html
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### SSL/HTTPS Server
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
import { fsReadFile } from "@simplysm/core-node";
|
|
142
|
+
|
|
143
|
+
const pfxBytes = await fsReadFile("/path/to/cert.pfx");
|
|
144
|
+
|
|
145
|
+
const server = new ServiceServer({
|
|
146
|
+
port: 443,
|
|
147
|
+
rootPath: "/app/data",
|
|
148
|
+
ssl: {
|
|
149
|
+
pfxBytes,
|
|
150
|
+
passphrase: "certificate-password",
|
|
151
|
+
},
|
|
152
|
+
auth: { jwtSecret: "my-secret-key" },
|
|
153
|
+
services: [],
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
await server.listen();
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Custom Service Definition
|
|
160
|
+
|
|
161
|
+
Define services by inheriting from `ServiceBase`. Service methods are called via RPC from the client.
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
import { ServiceBase } from "@simplysm/service-server";
|
|
165
|
+
|
|
166
|
+
class MyService extends ServiceBase {
|
|
167
|
+
async hello(name: string): Promise<string> {
|
|
168
|
+
return `Hello, ${name}!`;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
async getServerTime(): Promise<Date> {
|
|
172
|
+
return new Date();
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Context accessible within services:
|
|
178
|
+
|
|
179
|
+
| Property | Type | Description |
|
|
180
|
+
|------|------|------|
|
|
181
|
+
| `this.server` | `ServiceServer` | Server instance reference |
|
|
182
|
+
| `this.socket` | `ServiceSocket \| undefined` | WebSocket connection (`undefined` for HTTP calls) |
|
|
183
|
+
| `this.http` | `{ clientName, authTokenPayload? }` | HTTP request context |
|
|
184
|
+
| `this.authInfo` | `TAuthInfo \| undefined` | Authenticated user info |
|
|
185
|
+
| `this.clientName` | `string \| undefined` | Client app name |
|
|
186
|
+
| `this.clientPath` | `string \| undefined` | Per-client directory path |
|
|
187
|
+
|
|
188
|
+
### Config File Reference
|
|
189
|
+
|
|
190
|
+
Read sections from `.config.json` files using `ServiceBase.getConfig()`. Root and per-client configs are automatically merged.
|
|
191
|
+
|
|
192
|
+
```typescript
|
|
193
|
+
class MyService extends ServiceBase {
|
|
194
|
+
async getDbHost(): Promise<string> {
|
|
195
|
+
// Read "mySection" key from rootPath/.config.json or clientPath/.config.json
|
|
196
|
+
const config = await this.getConfig<{ host: string }>("mySection");
|
|
197
|
+
return config.host;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
`.config.json` example:
|
|
203
|
+
|
|
204
|
+
```json
|
|
205
|
+
{
|
|
206
|
+
"mySection": {
|
|
207
|
+
"host": "localhost"
|
|
208
|
+
},
|
|
209
|
+
"orm": {
|
|
210
|
+
"default": {
|
|
211
|
+
"dialect": "mysql",
|
|
212
|
+
"host": "localhost",
|
|
213
|
+
"port": 3306,
|
|
214
|
+
"database": "mydb",
|
|
215
|
+
"user": "root",
|
|
216
|
+
"password": "password"
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
`ConfigManager` caches config files and automatically refreshes the cache on file changes (LazyGcMap-based, auto expires after 1 hour).
|
|
223
|
+
|
|
224
|
+
### Authentication (`Authorize` Decorator)
|
|
225
|
+
|
|
226
|
+
Use Stage 3 decorators to set authentication requirements on services or methods. Only works when `ServiceServerOptions.auth` is configured.
|
|
227
|
+
|
|
228
|
+
```typescript
|
|
229
|
+
import { ServiceBase, Authorize } from "@simplysm/service-server";
|
|
230
|
+
|
|
231
|
+
// Class level: all methods require login
|
|
232
|
+
@Authorize()
|
|
233
|
+
class UserService extends ServiceBase<{ userId: number; role: string }> {
|
|
234
|
+
// Login only required (inherits from class level)
|
|
235
|
+
async getProfile(): Promise<unknown> {
|
|
236
|
+
const userId = this.authInfo?.userId;
|
|
237
|
+
// ...
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Method level: specific role required (overrides class level)
|
|
241
|
+
@Authorize(["admin"])
|
|
242
|
+
async deleteUser(targetId: number): Promise<void> {
|
|
243
|
+
// Only users with admin role can call
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// No authentication required (no decorator)
|
|
248
|
+
class PublicService extends ServiceBase {
|
|
249
|
+
async healthCheck(): Promise<string> {
|
|
250
|
+
return "OK";
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
Decorator behavior:
|
|
256
|
+
|
|
257
|
+
| Target | `@Authorize()` | `@Authorize(["admin"])` |
|
|
258
|
+
|-----------|----------------|-------------------------|
|
|
259
|
+
| Class | All methods require login | All methods require admin role |
|
|
260
|
+
| Method | Method requires login | Method requires admin role |
|
|
261
|
+
| None | No auth required (Public) | - |
|
|
262
|
+
|
|
263
|
+
Method-level decorators override class-level settings.
|
|
264
|
+
|
|
265
|
+
### JWT Token Management
|
|
266
|
+
|
|
267
|
+
Generate and verify JWT tokens through the `ServiceServer` instance.
|
|
268
|
+
|
|
269
|
+
```typescript
|
|
270
|
+
// Generate token (12-hour expiration, HS256 algorithm)
|
|
271
|
+
const token = await server.generateAuthToken({
|
|
272
|
+
roles: ["admin", "user"],
|
|
273
|
+
data: { userId: 1, name: "홍길동" },
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
// Verify token
|
|
277
|
+
const payload = await server.verifyAuthToken(token);
|
|
278
|
+
// payload.roles: ["admin", "user"]
|
|
279
|
+
// payload.data: { userId: 1, name: "홍길동" }
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
`AuthTokenPayload` interface:
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
interface AuthTokenPayload<TAuthInfo = unknown> extends JWTPayload {
|
|
286
|
+
/** User role list (used for permission check in Authorize decorator) */
|
|
287
|
+
roles: string[];
|
|
288
|
+
/** Custom auth info (generic type) */
|
|
289
|
+
data: TAuthInfo;
|
|
290
|
+
}
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### HTTP API Call
|
|
294
|
+
|
|
295
|
+
Service methods can also be called via HTTP through the `/api/:service/:method` path.
|
|
296
|
+
|
|
297
|
+
**GET Request:**
|
|
298
|
+
|
|
299
|
+
```
|
|
300
|
+
GET /api/MyService/hello?json=["World"]
|
|
301
|
+
Header: x-sd-client-name: my-app
|
|
302
|
+
Header: Authorization: Bearer <token> (optional)
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
**POST Request:**
|
|
306
|
+
|
|
307
|
+
```
|
|
308
|
+
POST /api/MyService/hello
|
|
309
|
+
Header: Content-Type: application/json
|
|
310
|
+
Header: x-sd-client-name: my-app
|
|
311
|
+
Header: Authorization: Bearer <token> (optional)
|
|
312
|
+
Body: ["World"]
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
- The `x-sd-client-name` header is required.
|
|
316
|
+
- Parameters are passed in array form (in the order of method arguments).
|
|
317
|
+
- For GET requests, pass a JSON-serialized array in the `json` query parameter.
|
|
318
|
+
|
|
319
|
+
### File Upload
|
|
320
|
+
|
|
321
|
+
Upload files via multipart request to the `/upload` endpoint. Auth token is required.
|
|
322
|
+
|
|
323
|
+
```typescript
|
|
324
|
+
// Client-side example
|
|
325
|
+
const formData = new FormData();
|
|
326
|
+
formData.append("file", file);
|
|
327
|
+
|
|
328
|
+
const response = await fetch("/upload", {
|
|
329
|
+
method: "POST",
|
|
330
|
+
headers: {
|
|
331
|
+
Authorization: `Bearer ${token}`,
|
|
332
|
+
},
|
|
333
|
+
body: formData,
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
// Response: ServiceUploadResult[]
|
|
337
|
+
const results = await response.json();
|
|
338
|
+
// [{ path: "uploads/uuid.ext", filename: "original-filename.ext", size: 12345 }]
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
Uploaded files are stored in the `rootPath/www/uploads/` directory with UUID-based filenames.
|
|
342
|
+
|
|
343
|
+
### Real-time Event Publishing
|
|
344
|
+
|
|
345
|
+
Publish events to connected clients from the server.
|
|
346
|
+
|
|
347
|
+
```typescript
|
|
348
|
+
import { ServiceEventListener } from "@simplysm/service-common";
|
|
349
|
+
|
|
350
|
+
// Event definition (from service-common)
|
|
351
|
+
class OrderUpdatedEvent extends ServiceEventListener<
|
|
352
|
+
{ orderId: number },
|
|
353
|
+
{ status: string }
|
|
354
|
+
> {
|
|
355
|
+
readonly eventName = "OrderUpdatedEvent";
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// Publish event from server
|
|
359
|
+
await server.emitEvent(
|
|
360
|
+
OrderUpdatedEvent,
|
|
361
|
+
(info) => info.orderId === 123, // Target filter
|
|
362
|
+
{ status: "completed" }, // Data to send
|
|
363
|
+
);
|
|
364
|
+
|
|
365
|
+
// Send reload command to all clients
|
|
366
|
+
await server.broadcastReload("my-app", new Set(["main.js"]));
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
### Built-in Service: OrmService
|
|
370
|
+
|
|
371
|
+
Provides database connection/query/transaction via WebSocket. `@Authorize()` decorator is applied, requiring login.
|
|
372
|
+
|
|
373
|
+
```typescript
|
|
374
|
+
const server = new ServiceServer({
|
|
375
|
+
port: 8080,
|
|
376
|
+
rootPath: "/app/data",
|
|
377
|
+
auth: { jwtSecret: "secret" },
|
|
378
|
+
services: [OrmService],
|
|
379
|
+
});
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
Define ORM config in `.config.json`:
|
|
383
|
+
|
|
384
|
+
```json
|
|
385
|
+
{
|
|
386
|
+
"orm": {
|
|
387
|
+
"default": {
|
|
388
|
+
"dialect": "mysql",
|
|
389
|
+
"host": "localhost",
|
|
390
|
+
"port": 3306,
|
|
391
|
+
"database": "mydb",
|
|
392
|
+
"user": "root",
|
|
393
|
+
"password": "password"
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
Methods provided by `OrmService`:
|
|
400
|
+
|
|
401
|
+
| Method | Description |
|
|
402
|
+
|--------|------|
|
|
403
|
+
| `getInfo(opt)` | Query DB connection info (dialect, database, schema) |
|
|
404
|
+
| `connect(opt)` | Create DB connection. Returns connection ID |
|
|
405
|
+
| `close(connId)` | Close DB connection |
|
|
406
|
+
| `beginTransaction(connId, isolationLevel?)` | Begin transaction |
|
|
407
|
+
| `commitTransaction(connId)` | Commit transaction |
|
|
408
|
+
| `rollbackTransaction(connId)` | Rollback transaction |
|
|
409
|
+
| `executeParametrized(connId, query, params?)` | Execute parameterized query |
|
|
410
|
+
| `executeDefs(connId, defs, options?)` | Execute QueryDef-based queries |
|
|
411
|
+
| `bulkInsert(connId, tableName, columnDefs, records)` | Bulk INSERT |
|
|
412
|
+
|
|
413
|
+
When a WebSocket connection is closed, all DB connections opened from that socket are automatically cleaned up.
|
|
414
|
+
|
|
415
|
+
### Built-in Service: CryptoService
|
|
416
|
+
|
|
417
|
+
Provides SHA256 hash and AES-256-CBC symmetric key encryption/decryption.
|
|
418
|
+
|
|
419
|
+
```typescript
|
|
420
|
+
const server = new ServiceServer({
|
|
421
|
+
port: 8080,
|
|
422
|
+
rootPath: "/app/data",
|
|
423
|
+
services: [CryptoService],
|
|
424
|
+
});
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
`.config.json` config:
|
|
428
|
+
|
|
429
|
+
```json
|
|
430
|
+
{
|
|
431
|
+
"crypto": {
|
|
432
|
+
"key": "your-32-byte-secret-key-here!!"
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
| Method | Description |
|
|
438
|
+
|--------|------|
|
|
439
|
+
| `encrypt(data)` | Generate SHA256 HMAC hash (one-way) |
|
|
440
|
+
| `encryptAes(data)` | AES-256-CBC encryption. Returns hex string in `iv:encrypted` format |
|
|
441
|
+
| `decryptAes(encText)` | AES-256-CBC decryption. Returns original binary |
|
|
442
|
+
|
|
443
|
+
### Built-in Service: SmtpService
|
|
444
|
+
|
|
445
|
+
A nodemailer-based email sending service. Can pass SMTP config directly or reference server config file.
|
|
446
|
+
|
|
447
|
+
```typescript
|
|
448
|
+
const server = new ServiceServer({
|
|
449
|
+
port: 8080,
|
|
450
|
+
rootPath: "/app/data",
|
|
451
|
+
services: [SmtpService],
|
|
452
|
+
});
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
`.config.json` config (when using config reference method):
|
|
456
|
+
|
|
457
|
+
```json
|
|
458
|
+
{
|
|
459
|
+
"smtp": {
|
|
460
|
+
"default": {
|
|
461
|
+
"host": "smtp.example.com",
|
|
462
|
+
"port": 587,
|
|
463
|
+
"secure": false,
|
|
464
|
+
"user": "user@example.com",
|
|
465
|
+
"pass": "password",
|
|
466
|
+
"senderName": "My App",
|
|
467
|
+
"senderEmail": "noreply@example.com"
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
| Method | Description |
|
|
474
|
+
|--------|------|
|
|
475
|
+
| `send(options)` | Send email by directly passing SMTP config |
|
|
476
|
+
| `sendByConfig(configName, options)` | Send email by referencing SMTP config in config file |
|
|
477
|
+
|
|
478
|
+
`send()` options:
|
|
479
|
+
|
|
480
|
+
```typescript
|
|
481
|
+
interface SmtpSendOption {
|
|
482
|
+
host: string;
|
|
483
|
+
port?: number;
|
|
484
|
+
secure?: boolean;
|
|
485
|
+
user?: string;
|
|
486
|
+
pass?: string;
|
|
487
|
+
from: string;
|
|
488
|
+
to: string;
|
|
489
|
+
cc?: string;
|
|
490
|
+
bcc?: string;
|
|
491
|
+
subject: string;
|
|
492
|
+
html: string;
|
|
493
|
+
attachments?: SmtpSendAttachment[];
|
|
494
|
+
}
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
### Built-in Service: AutoUpdateService
|
|
498
|
+
|
|
499
|
+
Supports auto-update for client apps. Searches for latest version files by platform in the client directory.
|
|
500
|
+
|
|
501
|
+
```typescript
|
|
502
|
+
const server = new ServiceServer({
|
|
503
|
+
port: 8080,
|
|
504
|
+
rootPath: "/app/data",
|
|
505
|
+
services: [AutoUpdateService],
|
|
506
|
+
});
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
Update file structure:
|
|
510
|
+
|
|
511
|
+
```
|
|
512
|
+
rootPath/www/{clientName}/{platform}/updates/
|
|
513
|
+
1.0.0.exe (Windows)
|
|
514
|
+
1.0.1.exe
|
|
515
|
+
1.0.0.apk (Android)
|
|
516
|
+
1.0.1.apk
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
| Method | Description |
|
|
520
|
+
|--------|------|
|
|
521
|
+
| `getLastVersion(platform)` | Returns latest version and download path for the platform. Returns `undefined` if no update |
|
|
522
|
+
|
|
523
|
+
Return value:
|
|
524
|
+
|
|
525
|
+
```typescript
|
|
526
|
+
{
|
|
527
|
+
version: string; // e.g., "1.0.1"
|
|
528
|
+
downloadPath: string; // e.g., "/my-app/android/updates/1.0.1.apk"
|
|
529
|
+
}
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
### ConfigManager
|
|
533
|
+
|
|
534
|
+
A static utility class that manages loading, caching, and real-time monitoring of JSON config files. Used internally by `ServiceBase.getConfig()`.
|
|
535
|
+
|
|
536
|
+
```typescript
|
|
537
|
+
import { ConfigManager } from "@simplysm/service-server";
|
|
538
|
+
|
|
539
|
+
const config = await ConfigManager.getConfig<MyConfig>("/path/to/.config.json");
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
Behavior:
|
|
543
|
+
- Caches file in `LazyGcMap` on first load.
|
|
544
|
+
- Registers file change watch (`FsWatcher`) to auto-refresh cache on changes.
|
|
545
|
+
- Cache auto-expires after 1 hour of no access, and associated watch is released.
|
|
546
|
+
|
|
547
|
+
### ProtocolWrapper
|
|
548
|
+
|
|
549
|
+
Handles encoding/decoding of WebSocket messages. Automatically branches between main thread and worker thread based on message size.
|
|
550
|
+
|
|
551
|
+
| Condition | Processing Method |
|
|
552
|
+
|------|-----------|
|
|
553
|
+
| 30KB or less | Processed directly in main thread |
|
|
554
|
+
| Over 30KB | Processed in worker thread (max 4GB memory allocation) |
|
|
555
|
+
|
|
556
|
+
Messages containing large binary data (Uint8Array) also branch to worker thread.
|
|
557
|
+
|
|
558
|
+
## Server Route Structure
|
|
559
|
+
|
|
560
|
+
The following routes are automatically registered when `ServiceServer.listen()` is called:
|
|
561
|
+
|
|
562
|
+
| Route | Method | Description |
|
|
563
|
+
|--------|--------|------|
|
|
564
|
+
| `/api/:service/:method` | GET, POST | Service method call via HTTP |
|
|
565
|
+
| `/upload` | POST | Multipart file upload (auth required) |
|
|
566
|
+
| `/` | WebSocket | WebSocket connection endpoint |
|
|
567
|
+
| `/ws` | WebSocket | WebSocket connection endpoint (alias) |
|
|
568
|
+
| `/*` | GET, etc. | Static file serving (based on `rootPath/www/`) |
|
|
569
|
+
|
|
570
|
+
## Security
|
|
571
|
+
|
|
572
|
+
- **Helmet**: `@fastify/helmet` plugin automatically sets security headers like CSP, HSTS.
|
|
573
|
+
- **CORS**: `@fastify/cors` plugin configures CORS.
|
|
574
|
+
- **Path Traversal Prevention**: Static file handler and client name validation block `..`, `/`, `\` characters.
|
|
575
|
+
- **Hidden File Blocking**: Files starting with `.` return a 403 response.
|
|
576
|
+
- **Graceful Shutdown**: Detects `SIGINT`/`SIGTERM` signals to safely close open WebSocket connections and server (10-second timeout).
|
|
577
|
+
|
|
578
|
+
## Caveats
|
|
579
|
+
|
|
580
|
+
- `OrmService` is WebSocket-only. Cannot be used via HTTP requests.
|
|
581
|
+
- Config files (`.config.json`) contain sensitive information (DB passwords, JWT secrets, etc.), so hidden files (starting with `.`) are automatically blocked by the static file handler.
|
|
582
|
+
- WebSocket connection requires query parameters `ver=2`, `clientId`, `clientName`. Without these parameters, it operates in V1 legacy mode.
|
|
583
|
+
- If SSL is not configured, the `upgrade-insecure-requests` CSP directive is disabled.
|
|
584
|
+
|
|
585
|
+
## License
|
|
586
|
+
|
|
587
|
+
Apache-2.0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=auth-token-payload.js.map
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
const classAuthMap = /* @__PURE__ */ new WeakMap();
|
|
2
|
+
const methodAuthMap = /* @__PURE__ */ new WeakMap();
|
|
3
|
+
const pendingMethodAuth = /* @__PURE__ */ new Map();
|
|
4
|
+
function Authorize(permissions = []) {
|
|
5
|
+
return function(target, context) {
|
|
6
|
+
if (context.kind === "class") {
|
|
7
|
+
classAuthMap.set(target, permissions);
|
|
8
|
+
const className = context.name ?? "";
|
|
9
|
+
const pending = pendingMethodAuth.get(className);
|
|
10
|
+
if (pending != null) {
|
|
11
|
+
let methodMap = methodAuthMap.get(target);
|
|
12
|
+
if (methodMap == null) {
|
|
13
|
+
methodMap = /* @__PURE__ */ new Map();
|
|
14
|
+
methodAuthMap.set(target, methodMap);
|
|
15
|
+
}
|
|
16
|
+
for (const { permissions: perms, methodName } of pending) {
|
|
17
|
+
methodMap.set(methodName, perms);
|
|
18
|
+
}
|
|
19
|
+
pendingMethodAuth.delete(className);
|
|
20
|
+
}
|
|
21
|
+
} else {
|
|
22
|
+
const methodName = String(context.name);
|
|
23
|
+
context.addInitializer(function() {
|
|
24
|
+
const ctor = this.constructor;
|
|
25
|
+
let methodMap = methodAuthMap.get(ctor);
|
|
26
|
+
if (methodMap == null) {
|
|
27
|
+
methodMap = /* @__PURE__ */ new Map();
|
|
28
|
+
methodAuthMap.set(ctor, methodMap);
|
|
29
|
+
}
|
|
30
|
+
methodMap.set(methodName, permissions);
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
function getAuthPermissions(ctor, methodName) {
|
|
36
|
+
if (methodName != null) {
|
|
37
|
+
const perms = methodAuthMap.get(ctor)?.get(methodName);
|
|
38
|
+
if (perms != null) return perms;
|
|
39
|
+
}
|
|
40
|
+
return classAuthMap.get(ctor);
|
|
41
|
+
}
|
|
42
|
+
export {
|
|
43
|
+
Authorize,
|
|
44
|
+
getAuthPermissions
|
|
45
|
+
};
|
|
46
|
+
//# sourceMappingURL=auth.decorators.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/auth/auth.decorators.ts"],
|
|
4
|
+
"sourcesContent": ["// WeakMap \uAE30\uBC18 \uBA54\uD0C0\uB370\uC774\uD130 \uC800\uC7A5 (reflect-metadata \uBBF8\uC0AC\uC6A9)\nconst classAuthMap = new WeakMap<Function, string[]>();\nconst methodAuthMap = new WeakMap<Function, Map<string, string[]>>();\n\n// \uBA54\uC18C\uB4DC \uB370\uCF54\uB808\uC774\uD130\uC5D0\uC11C \uD074\uB798\uC2A4 \uC0DD\uC131\uC790\uB97C \uB098\uC911\uC5D0 \uC5F0\uACB0\uD558\uAE30 \uC704\uD55C \uC784\uC2DC \uC800\uC7A5\uC18C\nconst pendingMethodAuth = new Map<string, { permissions: string[]; methodName: string }[]>();\n\n/**\n * \uC778\uC99D \uAD8C\uD55C\uC744 \uC124\uC815\uD558\uB294 \uB370\uCF54\uB808\uC774\uD130 (Stage 3 Decorators)\n * - \uD074\uB798\uC2A4 \uB808\uBCA8: \uBAA8\uB4E0 \uBA54\uC18C\uB4DC\uC5D0 \uAE30\uBCF8 \uAD8C\uD55C \uC801\uC6A9\n * - \uBA54\uC18C\uB4DC \uB808\uBCA8: \uD574\uB2F9 \uBA54\uC18C\uB4DC\uC5D0\uB9CC \uAD8C\uD55C \uC801\uC6A9 (\uD074\uB798\uC2A4 \uB808\uBCA8 \uC624\uBC84\uB77C\uC774\uB4DC)\n *\n * @param permissions \uD544\uC694\uD55C \uAD8C\uD55C \uBAA9\uB85D (\uBE48 \uBC30\uC5F4: \uB85C\uADF8\uC778\uB9CC \uD544\uC694)\n */\nexport function Authorize(permissions: string[] = []) {\n return function <T extends Function | ((...args: unknown[]) => unknown)>(\n target: T,\n context: ClassDecoratorContext | ClassMethodDecoratorContext,\n ): T | void {\n if (context.kind === \"class\") {\n // \uD074\uB798\uC2A4 \uB808\uBCA8\n classAuthMap.set(target as Function, permissions);\n\n // \uB300\uAE30 \uC911\uC778 \uBA54\uC18C\uB4DC \uAD8C\uD55C \uC5F0\uACB0\n const className = context.name ?? \"\";\n const pending = pendingMethodAuth.get(className);\n if (pending != null) {\n let methodMap = methodAuthMap.get(target as Function);\n if (methodMap == null) {\n methodMap = new Map();\n methodAuthMap.set(target as Function, methodMap);\n }\n for (const { permissions: perms, methodName } of pending) {\n methodMap.set(methodName, perms);\n }\n pendingMethodAuth.delete(className);\n }\n } else {\n // \uBA54\uC18C\uB4DC \uB808\uBCA8 - \uD074\uB798\uC2A4 \uB370\uCF54\uB808\uC774\uD130\uAC00 \uB098\uC911\uC5D0 \uC2E4\uD589\uB418\uBBC0\uB85C \uC784\uC2DC \uC800\uC7A5\n const methodName = String(context.name);\n\n // addInitializer\uB97C \uD1B5\uD574 \uD074\uB798\uC2A4 \uC0DD\uC131\uC790\uC5D0 \uC811\uADFC\n context.addInitializer(function (this: unknown) {\n const ctor = (this as object).constructor;\n let methodMap = methodAuthMap.get(ctor);\n if (methodMap == null) {\n methodMap = new Map();\n methodAuthMap.set(ctor, methodMap);\n }\n methodMap.set(methodName, permissions);\n });\n }\n };\n}\n\n/**\n * \uC778\uC99D \uAD8C\uD55C \uC870\uD68C\n * - \uBA54\uC18C\uB4DC \uB808\uBCA8 \uAD8C\uD55C \uC6B0\uC120\n * - \uC5C6\uC73C\uBA74 \uD074\uB798\uC2A4 \uB808\uBCA8 \uAD8C\uD55C \uBC18\uD658\n *\n * @param ctor \uC11C\uBE44\uC2A4 \uD074\uB798\uC2A4 \uC0DD\uC131\uC790\n * @param methodName \uBA54\uC18C\uB4DC \uC774\uB984 (\uC120\uD0DD)\n * @returns \uAD8C\uD55C \uBAA9\uB85D \uB610\uB294 undefined (Public API)\n */\nexport function getAuthPermissions(ctor: Function, methodName?: string): string[] | undefined {\n if (methodName != null) {\n const perms = methodAuthMap.get(ctor)?.get(methodName);\n if (perms != null) return perms;\n }\n return classAuthMap.get(ctor);\n}\n"],
|
|
5
|
+
"mappings": "AACA,MAAM,eAAe,oBAAI,QAA4B;AACrD,MAAM,gBAAgB,oBAAI,QAAyC;AAGnE,MAAM,oBAAoB,oBAAI,IAA6D;AASpF,SAAS,UAAU,cAAwB,CAAC,GAAG;AACpD,SAAO,SACL,QACA,SACU;AACV,QAAI,QAAQ,SAAS,SAAS;AAE5B,mBAAa,IAAI,QAAoB,WAAW;AAGhD,YAAM,YAAY,QAAQ,QAAQ;AAClC,YAAM,UAAU,kBAAkB,IAAI,SAAS;AAC/C,UAAI,WAAW,MAAM;AACnB,YAAI,YAAY,cAAc,IAAI,MAAkB;AACpD,YAAI,aAAa,MAAM;AACrB,sBAAY,oBAAI,IAAI;AACpB,wBAAc,IAAI,QAAoB,SAAS;AAAA,QACjD;AACA,mBAAW,EAAE,aAAa,OAAO,WAAW,KAAK,SAAS;AACxD,oBAAU,IAAI,YAAY,KAAK;AAAA,QACjC;AACA,0BAAkB,OAAO,SAAS;AAAA,MACpC;AAAA,IACF,OAAO;AAEL,YAAM,aAAa,OAAO,QAAQ,IAAI;AAGtC,cAAQ,eAAe,WAAyB;AAC9C,cAAM,OAAQ,KAAgB;AAC9B,YAAI,YAAY,cAAc,IAAI,IAAI;AACtC,YAAI,aAAa,MAAM;AACrB,sBAAY,oBAAI,IAAI;AACpB,wBAAc,IAAI,MAAM,SAAS;AAAA,QACnC;AACA,kBAAU,IAAI,YAAY,WAAW;AAAA,MACvC,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAWO,SAAS,mBAAmB,MAAgB,YAA2C;AAC5F,MAAI,cAAc,MAAM;AACtB,UAAM,QAAQ,cAAc,IAAI,IAAI,GAAG,IAAI,UAAU;AACrD,QAAI,SAAS,KAAM,QAAO;AAAA,EAC5B;AACA,SAAO,aAAa,IAAI,IAAI;AAC9B;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import * as jose from "jose";
|
|
2
|
+
class JwtManager {
|
|
3
|
+
constructor(_server) {
|
|
4
|
+
this._server = _server;
|
|
5
|
+
}
|
|
6
|
+
async sign(payload) {
|
|
7
|
+
const jwtSecret = this._server.options.auth?.jwtSecret;
|
|
8
|
+
if (jwtSecret == null) throw new Error("JWT Secret\uC774 \uC815\uC758\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.");
|
|
9
|
+
const secret = new TextEncoder().encode(jwtSecret);
|
|
10
|
+
return new jose.SignJWT(payload).setProtectedHeader({ alg: "HS256" }).setIssuedAt().setExpirationTime("12h").sign(secret);
|
|
11
|
+
}
|
|
12
|
+
async verify(token) {
|
|
13
|
+
const jwtSecret = this._server.options.auth?.jwtSecret;
|
|
14
|
+
if (jwtSecret == null) throw new Error("JWT Secret\uC774 \uC815\uC758\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.");
|
|
15
|
+
const secret = new TextEncoder().encode(jwtSecret);
|
|
16
|
+
try {
|
|
17
|
+
const { payload } = await jose.jwtVerify(token, secret);
|
|
18
|
+
return payload;
|
|
19
|
+
} catch (err) {
|
|
20
|
+
if (err != null && typeof err === "object" && "code" in err && err.code === "ERR_JWT_EXPIRED") {
|
|
21
|
+
throw new Error("\uD1A0\uD070\uC774 \uB9CC\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");
|
|
22
|
+
}
|
|
23
|
+
throw new Error("\uC720\uD6A8\uD558\uC9C0 \uC54A\uC740 \uD1A0\uD070\uC785\uB2C8\uB2E4.");
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
decode(token) {
|
|
27
|
+
const jwtSecret = this._server.options.auth?.jwtSecret;
|
|
28
|
+
if (jwtSecret == null) throw new Error("JWT Secret\uC774 \uC815\uC758\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.");
|
|
29
|
+
return jose.decodeJwt(token);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export {
|
|
33
|
+
JwtManager
|
|
34
|
+
};
|
|
35
|
+
//# sourceMappingURL=jwt-manager.js.map
|