@simplysm/service-server 14.0.23 → 14.0.25
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/package.json +7 -8
- package/README.md +0 -174
- package/docs/auth.md +0 -74
- package/docs/built-in-services.md +0 -61
- package/docs/config-manager.md +0 -24
- package/docs/http-handlers.md +0 -83
- package/docs/legacy-v1.md +0 -25
- package/docs/protocol-wrapper.md +0 -37
- package/docs/server-options.md +0 -31
- package/docs/service-definition.md +0 -151
- package/docs/service-executor.md +0 -42
- package/docs/service-server.md +0 -80
- package/docs/service-socket.md +0 -73
- package/docs/websocket-handler.md +0 -58
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@simplysm/service-server",
|
|
3
|
-
"version": "14.0.
|
|
3
|
+
"version": "14.0.25",
|
|
4
4
|
"description": "심플리즘 패키지 - 서비스 (server)",
|
|
5
5
|
"author": "심플리즘",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -14,8 +14,7 @@
|
|
|
14
14
|
"types": "./dist/index.d.ts",
|
|
15
15
|
"files": [
|
|
16
16
|
"dist",
|
|
17
|
-
"src"
|
|
18
|
-
"docs"
|
|
17
|
+
"src"
|
|
19
18
|
],
|
|
20
19
|
"sideEffects": false,
|
|
21
20
|
"dependencies": {
|
|
@@ -31,11 +30,11 @@
|
|
|
31
30
|
"semver": "^7.7.4",
|
|
32
31
|
"utf-8-validate": "^6.0.6",
|
|
33
32
|
"ws": "^8.20.0",
|
|
34
|
-
"@simplysm/
|
|
35
|
-
"@simplysm/core-common": "14.0.
|
|
36
|
-
"@simplysm/orm-node": "14.0.
|
|
37
|
-
"@simplysm/
|
|
38
|
-
"@simplysm/service-common": "14.0.
|
|
33
|
+
"@simplysm/core-node": "14.0.25",
|
|
34
|
+
"@simplysm/core-common": "14.0.25",
|
|
35
|
+
"@simplysm/orm-node": "14.0.25",
|
|
36
|
+
"@simplysm/orm-common": "14.0.25",
|
|
37
|
+
"@simplysm/service-common": "14.0.25"
|
|
39
38
|
},
|
|
40
39
|
"devDependencies": {
|
|
41
40
|
"@types/semver": "^7.7.1",
|
package/README.md
DELETED
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
# @simplysm/service-server
|
|
2
|
-
|
|
3
|
-
Fastify-based RPC server with WebSocket support, JWT authentication, service definitions, file upload/download, static file serving, and built-in ORM/auto-update services. Depends on `@simplysm/service-common` for shared protocol and types.
|
|
4
|
-
|
|
5
|
-
## Installation
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npm install @simplysm/service-server
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## API Overview
|
|
12
|
-
|
|
13
|
-
### Server Options
|
|
14
|
-
| API | Type | Description |
|
|
15
|
-
|-----|------|-------------|
|
|
16
|
-
| `ServiceServerOptions` | `interface` | Server configuration (rootPath, port, SSL, auth, services) |
|
|
17
|
-
|
|
18
|
-
→ See [docs/server-options.md](./docs/server-options.md) for details.
|
|
19
|
-
|
|
20
|
-
### Authentication (JWT)
|
|
21
|
-
| API | Type | Description |
|
|
22
|
-
|-----|------|-------------|
|
|
23
|
-
| `AuthTokenPayload` | `interface` | JWT token payload with roles and custom data |
|
|
24
|
-
| `signJwt` | `function` | Signs a JWT token (HS256, 12h expiry) |
|
|
25
|
-
| `verifyJwt` | `function` | Verifies a JWT token |
|
|
26
|
-
| `decodeJwt` | `function` | Decodes a JWT token without verification |
|
|
27
|
-
|
|
28
|
-
→ See [docs/auth.md](./docs/auth.md) for details.
|
|
29
|
-
|
|
30
|
-
### Service Definition/Context
|
|
31
|
-
| API | Type | Description |
|
|
32
|
-
|-----|------|-------------|
|
|
33
|
-
| `ServiceContext` | `interface` | Service execution context (server, socket, auth, config) |
|
|
34
|
-
| `createServiceContext` | `function` | Creates a service context instance |
|
|
35
|
-
| `getServiceAuthPermissions` | `function` | Reads auth permissions from an auth-wrapped function |
|
|
36
|
-
| `auth` | `function` | Authentication wrapper for service factories and methods |
|
|
37
|
-
| `ServiceDefinition` | `interface` | Service definition with name and factory |
|
|
38
|
-
| `defineService` | `function` | Defines a named service with a factory function |
|
|
39
|
-
| `ServiceMethods` | `type` | Extracts method signatures from a ServiceDefinition |
|
|
40
|
-
|
|
41
|
-
→ See [docs/service-definition.md](./docs/service-definition.md) for details.
|
|
42
|
-
|
|
43
|
-
### Service Executor
|
|
44
|
-
| API | Type | Description |
|
|
45
|
-
|-----|------|-------------|
|
|
46
|
-
| `executeServiceMethod` | `function` | Executes a service method with auth checking |
|
|
47
|
-
|
|
48
|
-
→ See [docs/service-executor.md](./docs/service-executor.md) for details.
|
|
49
|
-
|
|
50
|
-
### WebSocket Handler
|
|
51
|
-
| API | Type | Description |
|
|
52
|
-
|-----|------|-------------|
|
|
53
|
-
| `WebSocketHandler` | `interface` | Multi-connection WebSocket handler with event broadcasting |
|
|
54
|
-
| `createWebSocketHandler` | `function` | Creates a WebSocket handler instance |
|
|
55
|
-
|
|
56
|
-
→ See [docs/websocket-handler.md](./docs/websocket-handler.md) for details.
|
|
57
|
-
|
|
58
|
-
### Service Socket
|
|
59
|
-
| API | Type | Description |
|
|
60
|
-
|-----|------|-------------|
|
|
61
|
-
| `ServiceSocket` | `interface` | Single WebSocket connection with protocol and events |
|
|
62
|
-
| `createServiceSocket` | `function` | Creates a service socket instance |
|
|
63
|
-
|
|
64
|
-
→ See [docs/service-socket.md](./docs/service-socket.md) for details.
|
|
65
|
-
|
|
66
|
-
### HTTP Handlers
|
|
67
|
-
| API | Type | Description |
|
|
68
|
-
|-----|------|-------------|
|
|
69
|
-
| `handleHttpRequest` | `function` | Handles HTTP RPC requests (GET/POST) |
|
|
70
|
-
| `handleUpload` | `function` | Handles multipart file uploads |
|
|
71
|
-
| `handleStaticFile` | `function` | Serves static files with security guards |
|
|
72
|
-
|
|
73
|
-
→ See [docs/http-handlers.md](./docs/http-handlers.md) for details.
|
|
74
|
-
|
|
75
|
-
### Protocol Wrapper
|
|
76
|
-
| API | Type | Description |
|
|
77
|
-
|-----|------|-------------|
|
|
78
|
-
| `ServerProtocolWrapper` | `interface` | Server-side protocol wrapper with worker thread offloading |
|
|
79
|
-
| `createServerProtocolWrapper` | `function` | Creates a server protocol wrapper instance |
|
|
80
|
-
|
|
81
|
-
→ See [docs/protocol-wrapper.md](./docs/protocol-wrapper.md) for details.
|
|
82
|
-
|
|
83
|
-
### ORM/AutoUpdate Services
|
|
84
|
-
| API | Type | Description |
|
|
85
|
-
|-----|------|-------------|
|
|
86
|
-
| `OrmService` | `const (ServiceDefinition)` | Built-in ORM service definition |
|
|
87
|
-
| `OrmServiceType` | `type` | ORM service method signatures |
|
|
88
|
-
| `AutoUpdateService` | `const (ServiceDefinition)` | Built-in auto-update service definition |
|
|
89
|
-
| `AutoUpdateServiceType` | `type` | Auto-update service method signatures |
|
|
90
|
-
|
|
91
|
-
→ See [docs/built-in-services.md](./docs/built-in-services.md) for details.
|
|
92
|
-
|
|
93
|
-
### Config Manager
|
|
94
|
-
| API | Type | Description |
|
|
95
|
-
|-----|------|-------------|
|
|
96
|
-
| `getConfig` | `function` | Loads JSON config with file-watching and caching |
|
|
97
|
-
|
|
98
|
-
→ See [docs/config-manager.md](./docs/config-manager.md) for details.
|
|
99
|
-
|
|
100
|
-
### Legacy V1
|
|
101
|
-
| API | Type | Description |
|
|
102
|
-
|-----|------|-------------|
|
|
103
|
-
| `handleV1Connection` | `function` | V1 legacy WebSocket handler (auto-update only) |
|
|
104
|
-
|
|
105
|
-
→ See [docs/legacy-v1.md](./docs/legacy-v1.md) for details.
|
|
106
|
-
|
|
107
|
-
### Main ServiceServer
|
|
108
|
-
| API | Type | Description |
|
|
109
|
-
|-----|------|-------------|
|
|
110
|
-
| `ServiceServer` | `class` | Main server class (Fastify + WebSocket + auth) |
|
|
111
|
-
| `createServiceServer` | `function` | Factory function to create a ServiceServer |
|
|
112
|
-
|
|
113
|
-
→ See [docs/service-server.md](./docs/service-server.md) for details.
|
|
114
|
-
|
|
115
|
-
## Usage Examples
|
|
116
|
-
|
|
117
|
-
### Basic Server Setup
|
|
118
|
-
|
|
119
|
-
```typescript
|
|
120
|
-
import { createServiceServer, defineService, auth } from "@simplysm/service-server";
|
|
121
|
-
|
|
122
|
-
const GreetService = defineService("Greet", (ctx) => ({
|
|
123
|
-
hello(name: string) {
|
|
124
|
-
return \`Hello, \${name}!\`;
|
|
125
|
-
},
|
|
126
|
-
secret: auth(["admin"], (msg: string) => {
|
|
127
|
-
return \`Secret for \${ctx.authInfo}: \${msg}\`;
|
|
128
|
-
}),
|
|
129
|
-
}));
|
|
130
|
-
|
|
131
|
-
const server = createServiceServer({
|
|
132
|
-
rootPath: process.cwd(),
|
|
133
|
-
port: 3000,
|
|
134
|
-
auth: { jwtSecret: "my-secret" },
|
|
135
|
-
services: [GreetService],
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
await server.listen();
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
### JWT Authentication
|
|
142
|
-
|
|
143
|
-
```typescript
|
|
144
|
-
import { signJwt, verifyJwt } from "@simplysm/service-server";
|
|
145
|
-
|
|
146
|
-
const token = await signJwt("my-secret", {
|
|
147
|
-
roles: ["admin"],
|
|
148
|
-
data: { userId: 1 },
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
const payload = await verifyJwt("my-secret", token);
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
### Event Broadcasting
|
|
155
|
-
|
|
156
|
-
```typescript
|
|
157
|
-
import { defineEvent } from "@simplysm/service-common";
|
|
158
|
-
|
|
159
|
-
const NotifyEvent = defineEvent<{ userId: number }, { text: string }>("Notify");
|
|
160
|
-
await server.emitEvent(NotifyEvent, (info) => info.userId === 42, { text: "Hello!" });
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
### Built-in ORM Service
|
|
164
|
-
|
|
165
|
-
```typescript
|
|
166
|
-
import { createServiceServer, OrmService } from "@simplysm/service-server";
|
|
167
|
-
|
|
168
|
-
const server = createServiceServer({
|
|
169
|
-
rootPath: process.cwd(),
|
|
170
|
-
port: 3000,
|
|
171
|
-
auth: { jwtSecret: "my-secret" },
|
|
172
|
-
services: [OrmService],
|
|
173
|
-
});
|
|
174
|
-
```
|
package/docs/auth.md
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
# Authentication (JWT)
|
|
2
|
-
|
|
3
|
-
## `AuthTokenPayload`
|
|
4
|
-
|
|
5
|
-
JWT token payload extending `JWTPayload` from `jose`. Contains roles and custom authentication data.
|
|
6
|
-
|
|
7
|
-
```typescript
|
|
8
|
-
export interface AuthTokenPayload<TAuthInfo = unknown> extends JWTPayload {
|
|
9
|
-
roles: string[];
|
|
10
|
-
data: TAuthInfo;
|
|
11
|
-
}
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
| Field | Type | Description |
|
|
15
|
-
|-------|------|-------------|
|
|
16
|
-
| `roles` | `string[]` | User roles for permission checking |
|
|
17
|
-
| `data` | `TAuthInfo` | Custom authentication data (user info, etc.) |
|
|
18
|
-
| *(inherited from JWTPayload)* | | Standard JWT claims (`iss`, `sub`, `aud`, `exp`, `nbf`, `iat`, `jti`) |
|
|
19
|
-
|
|
20
|
-
## `signJwt`
|
|
21
|
-
|
|
22
|
-
Signs a JWT token using HS256 algorithm with 12-hour expiration.
|
|
23
|
-
|
|
24
|
-
```typescript
|
|
25
|
-
export async function signJwt<TAuthInfo = unknown>(
|
|
26
|
-
jwtSecret: string,
|
|
27
|
-
payload: AuthTokenPayload<TAuthInfo>,
|
|
28
|
-
): Promise<string>;
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
| Parameter | Type | Description |
|
|
32
|
-
|-----------|------|-------------|
|
|
33
|
-
| `jwtSecret` | `string` | JWT signing secret |
|
|
34
|
-
| `payload` | `AuthTokenPayload<TAuthInfo>` | Token payload with roles and data |
|
|
35
|
-
|
|
36
|
-
**Returns:** `Promise<string>` -- Signed JWT token string.
|
|
37
|
-
|
|
38
|
-
## `verifyJwt`
|
|
39
|
-
|
|
40
|
-
Verifies a JWT token and returns the decoded payload. Throws on expired or invalid tokens.
|
|
41
|
-
|
|
42
|
-
```typescript
|
|
43
|
-
export async function verifyJwt<TAuthInfo = unknown>(
|
|
44
|
-
jwtSecret: string,
|
|
45
|
-
token: string,
|
|
46
|
-
): Promise<AuthTokenPayload<TAuthInfo>>;
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
| Parameter | Type | Description |
|
|
50
|
-
|-----------|------|-------------|
|
|
51
|
-
| `jwtSecret` | `string` | JWT verification secret |
|
|
52
|
-
| `token` | `string` | JWT token string to verify |
|
|
53
|
-
|
|
54
|
-
**Returns:** `Promise<AuthTokenPayload<TAuthInfo>>` -- Decoded token payload.
|
|
55
|
-
|
|
56
|
-
**Throws:**
|
|
57
|
-
- `Error("토큰이 만료되었습니다.")` when the token has expired
|
|
58
|
-
- `Error("유효하지 않은 토큰입니다.")` for any other verification failure
|
|
59
|
-
|
|
60
|
-
## `decodeJwt`
|
|
61
|
-
|
|
62
|
-
Decodes a JWT token without verification. Useful for reading claims before verification.
|
|
63
|
-
|
|
64
|
-
```typescript
|
|
65
|
-
export function decodeJwt<TAuthInfo = unknown>(
|
|
66
|
-
token: string,
|
|
67
|
-
): AuthTokenPayload<TAuthInfo>;
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
| Parameter | Type | Description |
|
|
71
|
-
|-----------|------|-------------|
|
|
72
|
-
| `token` | `string` | JWT token string to decode |
|
|
73
|
-
|
|
74
|
-
**Returns:** `AuthTokenPayload<TAuthInfo>` -- Decoded token payload (not verified).
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
# ORM/AutoUpdate Services
|
|
2
|
-
|
|
3
|
-
## `OrmService`
|
|
4
|
-
|
|
5
|
-
Built-in ORM service definition. Provides database connection, transaction management, and query execution over the WebSocket RPC layer. Requires authentication (wrapped with `auth()`).
|
|
6
|
-
|
|
7
|
-
```typescript
|
|
8
|
-
export const OrmService: ServiceDefinition;
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
The ORM service is registered with the name `"Orm"` and requires WebSocket transport (HTTP is not supported).
|
|
12
|
-
|
|
13
|
-
Database connections are tracked per socket. When a WebSocket connection closes, all associated DB connections are automatically cleaned up.
|
|
14
|
-
|
|
15
|
-
Methods (matching the `OrmService` interface from `@simplysm/service-common`):
|
|
16
|
-
|
|
17
|
-
| Method | Parameters | Return | Description |
|
|
18
|
-
|--------|-----------|--------|-------------|
|
|
19
|
-
| `getInfo` | `opt: DbConnOptions & { configName: string }` | `Promise<{ dialect: Dialect; database?: string; schema?: string }>` | Gets database info from server config |
|
|
20
|
-
| `connect` | `opt: DbConnOptions & { configName: string }` | `Promise<number>` | Opens a DB connection. Returns connection ID |
|
|
21
|
-
| `close` | `connId: number` | `Promise<void>` | Closes a DB connection |
|
|
22
|
-
| `beginTransaction` | `connId: number, isolationLevel?: IsolationLevel` | `Promise<void>` | Begins a transaction |
|
|
23
|
-
| `commitTransaction` | `connId: number` | `Promise<void>` | Commits a transaction |
|
|
24
|
-
| `rollbackTransaction` | `connId: number` | `Promise<void>` | Rolls back a transaction |
|
|
25
|
-
| `executeParametrized` | `connId: number, query: string, params?: unknown[]` | `Promise<unknown[][]>` | Executes a parameterized query |
|
|
26
|
-
| `executeDefs` | `connId: number, defs: QueryDef[], options?: (ResultMeta \| undefined)[]` | `Promise<unknown[][]>` | Executes query definitions with optional result parsing |
|
|
27
|
-
| `bulkInsert` | `connId: number, tableName: string, columnDefs: Record<string, ColumnMeta>, records: Record<string, unknown>[]` | `Promise<void>` | Performs bulk insert |
|
|
28
|
-
|
|
29
|
-
Configuration: Reads from the `"orm"` section of the server config file (`.config.json`).
|
|
30
|
-
|
|
31
|
-
## `OrmServiceType`
|
|
32
|
-
|
|
33
|
-
Type alias for the ORM service methods. Useful for client-side type sharing.
|
|
34
|
-
|
|
35
|
-
```typescript
|
|
36
|
-
export type OrmServiceType = ServiceMethods<typeof OrmService>;
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
## `AutoUpdateService`
|
|
40
|
-
|
|
41
|
-
Built-in auto-update service definition. Provides version lookup for client applications. Does not require authentication.
|
|
42
|
-
|
|
43
|
-
```typescript
|
|
44
|
-
export const AutoUpdateService: ServiceDefinition;
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
Registered with the name `"AutoUpdate"`. Scans `{clientPath}/{platform}/updates/` for versioned files (`.exe` for desktop, `.apk` for Android).
|
|
48
|
-
|
|
49
|
-
Methods:
|
|
50
|
-
|
|
51
|
-
| Method | Parameters | Return | Description |
|
|
52
|
-
|--------|-----------|--------|-------------|
|
|
53
|
-
| `getLastVersion` | `platform: string` | `Promise<{ version: string; downloadPath: string } \| undefined>` | Returns the latest version info for the given platform. Uses `semver.maxSatisfying` to find the highest version |
|
|
54
|
-
|
|
55
|
-
## `AutoUpdateServiceType`
|
|
56
|
-
|
|
57
|
-
Type alias for the auto-update service methods.
|
|
58
|
-
|
|
59
|
-
```typescript
|
|
60
|
-
export type AutoUpdateServiceType = ServiceMethods<typeof AutoUpdateService>;
|
|
61
|
-
```
|
package/docs/config-manager.md
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
# Config Manager
|
|
2
|
-
|
|
3
|
-
## `getConfig`
|
|
4
|
-
|
|
5
|
-
Loads a JSON configuration file with automatic caching and file-watching for live reload.
|
|
6
|
-
|
|
7
|
-
```typescript
|
|
8
|
-
export async function getConfig<TConfig>(
|
|
9
|
-
filePath: string,
|
|
10
|
-
): Promise<TConfig | undefined>;
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
| Parameter | Type | Description |
|
|
14
|
-
|-----------|------|-------------|
|
|
15
|
-
| `filePath` | `string` | Absolute path to the JSON config file |
|
|
16
|
-
|
|
17
|
-
**Returns:** `Promise<TConfig | undefined>` -- Parsed config object, or `undefined` if the file does not exist.
|
|
18
|
-
|
|
19
|
-
Behavior:
|
|
20
|
-
- **Caching:** Uses `LazyGcMap` with 10-minute GC interval and 1-hour expiry
|
|
21
|
-
- **File watching:** Registers a file watcher on first load. Config is automatically reloaded when the file changes
|
|
22
|
-
- **Expiry:** When a cache entry expires, the associated file watcher is cleaned up
|
|
23
|
-
- **Deletion:** If the config file is deleted, the cache entry and watcher are removed
|
|
24
|
-
- Used internally by `ServiceContext.getConfig()` to load root and client config files
|
package/docs/http-handlers.md
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
# HTTP Handlers
|
|
2
|
-
|
|
3
|
-
## `handleHttpRequest`
|
|
4
|
-
|
|
5
|
-
Handles HTTP RPC requests. Supports both GET (with JSON query parameter) and POST (with JSON array body) methods.
|
|
6
|
-
|
|
7
|
-
```typescript
|
|
8
|
-
export async function handleHttpRequest<TAuthInfo = unknown>(
|
|
9
|
-
req: FastifyRequest,
|
|
10
|
-
reply: FastifyReply,
|
|
11
|
-
jwtSecret: string | undefined,
|
|
12
|
-
runMethod: (def: {
|
|
13
|
-
serviceName: string;
|
|
14
|
-
methodName: string;
|
|
15
|
-
params: unknown[];
|
|
16
|
-
http: { clientName: string; authTokenPayload?: AuthTokenPayload<TAuthInfo> };
|
|
17
|
-
}) => Promise<unknown>,
|
|
18
|
-
): Promise<void>;
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
| Parameter | Type | Description |
|
|
22
|
-
|-----------|------|-------------|
|
|
23
|
-
| `req` | `FastifyRequest` | Fastify request (expects `/:service/:method` route params) |
|
|
24
|
-
| `reply` | `FastifyReply` | Fastify reply |
|
|
25
|
-
| `jwtSecret` | `string \| undefined` | JWT secret for token verification |
|
|
26
|
-
| `runMethod` | callback | Service method executor |
|
|
27
|
-
|
|
28
|
-
Request requirements:
|
|
29
|
-
- Header `x-sd-client-name` is required
|
|
30
|
-
- GET: requires `?json=<encoded-params>` query parameter
|
|
31
|
-
- POST: requires JSON array body
|
|
32
|
-
- Authorization header (optional): `Bearer <token>`
|
|
33
|
-
|
|
34
|
-
## `handleUpload`
|
|
35
|
-
|
|
36
|
-
Handles multipart file uploads. Saves files to `{rootPath}/www/uploads/` with UUID-based filenames.
|
|
37
|
-
|
|
38
|
-
```typescript
|
|
39
|
-
export async function handleUpload(
|
|
40
|
-
req: FastifyRequest,
|
|
41
|
-
reply: FastifyReply,
|
|
42
|
-
rootPath: string,
|
|
43
|
-
jwtSecret: string | undefined,
|
|
44
|
-
): Promise<void>;
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
| Parameter | Type | Description |
|
|
48
|
-
|-----------|------|-------------|
|
|
49
|
-
| `req` | `FastifyRequest` | Fastify multipart request |
|
|
50
|
-
| `reply` | `FastifyReply` | Fastify reply |
|
|
51
|
-
| `rootPath` | `string` | Server root path |
|
|
52
|
-
| `jwtSecret` | `string \| undefined` | JWT secret for authentication |
|
|
53
|
-
|
|
54
|
-
Behavior:
|
|
55
|
-
- Requires multipart request and valid Authorization header
|
|
56
|
-
- Saves each file with a UUID filename preserving the original extension
|
|
57
|
-
- Returns `ServiceUploadResult[]` on success
|
|
58
|
-
- Cleans up all files on error (both partially written and already saved)
|
|
59
|
-
|
|
60
|
-
## `handleStaticFile`
|
|
61
|
-
|
|
62
|
-
Serves static files from `{rootPath}/www/` with security guards.
|
|
63
|
-
|
|
64
|
-
```typescript
|
|
65
|
-
export async function handleStaticFile(
|
|
66
|
-
req: FastifyRequest,
|
|
67
|
-
reply: FastifyReply,
|
|
68
|
-
rootPath: string,
|
|
69
|
-
urlPath: string,
|
|
70
|
-
): Promise<void>;
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
| Parameter | Type | Description |
|
|
74
|
-
|-----------|------|-------------|
|
|
75
|
-
| `req` | `FastifyRequest` | Fastify request |
|
|
76
|
-
| `reply` | `FastifyReply` | Fastify reply |
|
|
77
|
-
| `rootPath` | `string` | Server root path |
|
|
78
|
-
| `urlPath` | `string` | Decoded URL path (without leading slash) |
|
|
79
|
-
|
|
80
|
-
Security:
|
|
81
|
-
- Path traversal attack prevention (rejects paths outside `{rootPath}/www/`)
|
|
82
|
-
- Hidden file access denied (files starting with `.` return 403)
|
|
83
|
-
- Directory requests redirect to add trailing slash, then serve `index.html`
|
package/docs/legacy-v1.md
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
# Legacy V1
|
|
2
|
-
|
|
3
|
-
## `handleV1Connection`
|
|
4
|
-
|
|
5
|
-
Handles V1 legacy WebSocket connections. Only supports the `SdAutoUpdateService.getLastVersion` command. All other requests return an upgrade-required error.
|
|
6
|
-
|
|
7
|
-
```typescript
|
|
8
|
-
export function handleV1Connection(
|
|
9
|
-
socket: WebSocket,
|
|
10
|
-
autoUpdateMethods: { getLastVersion: (platform: string) => Promise<any> },
|
|
11
|
-
clientNameSetter?: (clientName: string | undefined) => void,
|
|
12
|
-
): void;
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
| Parameter | Type | Description |
|
|
16
|
-
|-----------|------|-------------|
|
|
17
|
-
| `socket` | `WebSocket` (from `ws`) | Raw WebSocket connection |
|
|
18
|
-
| `autoUpdateMethods` | `{ getLastVersion: (platform: string) => Promise<any> }` | Auto-update method implementations |
|
|
19
|
-
| `clientNameSetter` | `((clientName: string \| undefined) => void)?` | Callback to set the legacy client name on the context |
|
|
20
|
-
|
|
21
|
-
V1 protocol:
|
|
22
|
-
- Sends `{ name: "connected" }` on connection
|
|
23
|
-
- Expects JSON messages with `{ uuid, command, params, clientName? }` format
|
|
24
|
-
- Responds with `{ name: "response", reqUuid, state: "success"|"error", body }` format
|
|
25
|
-
- Only `SdAutoUpdateService.getLastVersion` is supported; all other commands return `UPGRADE_REQUIRED` error
|
package/docs/protocol-wrapper.md
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
# Protocol Wrapper
|
|
2
|
-
|
|
3
|
-
## `ServerProtocolWrapper`
|
|
4
|
-
|
|
5
|
-
Server-side protocol wrapper that automatically offloads heavy message encoding/decoding to a worker thread. Light operations are processed on the main thread.
|
|
6
|
-
|
|
7
|
-
```typescript
|
|
8
|
-
export interface ServerProtocolWrapper {
|
|
9
|
-
encode(uuid: string, message: ServiceMessage): Promise<{ chunks: Bytes[]; totalSize: number }>;
|
|
10
|
-
decode(bytes: Bytes): Promise<ServiceMessageDecodeResult<ServiceMessage>>;
|
|
11
|
-
dispose(): void;
|
|
12
|
-
}
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
| Method | Parameters | Return | Description |
|
|
16
|
-
|--------|-----------|--------|-------------|
|
|
17
|
-
| `encode` | `uuid: string, message: ServiceMessage` | `Promise<{ chunks: Bytes[]; totalSize: number }>` | Encodes a message. Offloads to worker for messages with `Uint8Array` bodies |
|
|
18
|
-
| `decode` | `bytes: Bytes` | `Promise<ServiceMessageDecodeResult<ServiceMessage>>` | Decodes binary data. Offloads to worker for payloads > 30KB |
|
|
19
|
-
| `dispose` | none | `void` | Disposes the underlying protocol's GC timer |
|
|
20
|
-
|
|
21
|
-
## `createServerProtocolWrapper`
|
|
22
|
-
|
|
23
|
-
Creates a `ServerProtocolWrapper` instance.
|
|
24
|
-
|
|
25
|
-
```typescript
|
|
26
|
-
export function createServerProtocolWrapper(): ServerProtocolWrapper;
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
**Returns:** `ServerProtocolWrapper`
|
|
30
|
-
|
|
31
|
-
Worker thread details:
|
|
32
|
-
- Uses `@simplysm/core-node` `Worker` (Node.js `worker_threads`)
|
|
33
|
-
- Shared singleton worker instance across all protocol wrappers
|
|
34
|
-
- Worker memory limit: 4096 MB (old generation)
|
|
35
|
-
- Size threshold for worker offloading: 30KB
|
|
36
|
-
- Encode uses worker when body contains `Uint8Array` elements
|
|
37
|
-
- Decode uses worker when total bytes exceed 30KB
|
package/docs/server-options.md
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
# Server Options
|
|
2
|
-
|
|
3
|
-
## `ServiceServerOptions`
|
|
4
|
-
|
|
5
|
-
Server configuration options.
|
|
6
|
-
|
|
7
|
-
```typescript
|
|
8
|
-
export interface ServiceServerOptions {
|
|
9
|
-
rootPath: string;
|
|
10
|
-
port: number;
|
|
11
|
-
ssl?: {
|
|
12
|
-
pfxBytes: Uint8Array;
|
|
13
|
-
passphrase: string;
|
|
14
|
-
};
|
|
15
|
-
auth?: {
|
|
16
|
-
jwtSecret: string;
|
|
17
|
-
} | false;
|
|
18
|
-
services: ServiceDefinition[];
|
|
19
|
-
}
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
| Field | Type | Description |
|
|
23
|
-
|-------|------|-------------|
|
|
24
|
-
| `rootPath` | `string` | Root directory path. Static files are served from `{rootPath}/www/`, config loaded from `{rootPath}/.config.json` |
|
|
25
|
-
| `port` | `number` | Server listen port |
|
|
26
|
-
| `ssl` | `{ pfxBytes: Uint8Array; passphrase: string }?` | SSL/TLS configuration using PFX certificate |
|
|
27
|
-
| `ssl.pfxBytes` | `Uint8Array` | PFX certificate file contents |
|
|
28
|
-
| `ssl.passphrase` | `string` | PFX certificate passphrase |
|
|
29
|
-
| `auth` | `{ jwtSecret: string } \| false` | Authentication configuration. `undefined` = auto-detect (error if auth-wrapped services exist). `false` = explicitly disable auth checks. `{ jwtSecret }` = enable JWT auth |
|
|
30
|
-
| `auth.jwtSecret` | `string` | JWT signing/verification secret (HS256) |
|
|
31
|
-
| `services` | `ServiceDefinition[]` | Array of service definitions to register |
|
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
# Service Definition/Context
|
|
2
|
-
|
|
3
|
-
## `ServiceContext`
|
|
4
|
-
|
|
5
|
-
Service execution context providing access to the server, socket, authentication info, and configuration.
|
|
6
|
-
|
|
7
|
-
```typescript
|
|
8
|
-
export interface ServiceContext<TAuthInfo = unknown> {
|
|
9
|
-
server: ServiceServer<TAuthInfo>;
|
|
10
|
-
socket?: ServiceSocket;
|
|
11
|
-
http?: {
|
|
12
|
-
clientName: string;
|
|
13
|
-
authTokenPayload?: AuthTokenPayload<TAuthInfo>;
|
|
14
|
-
};
|
|
15
|
-
legacy?: {
|
|
16
|
-
clientName?: string;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
get authInfo(): TAuthInfo | undefined;
|
|
20
|
-
get clientName(): string | undefined;
|
|
21
|
-
get clientPath(): string | undefined;
|
|
22
|
-
getConfig<T>(section: string): Promise<T>;
|
|
23
|
-
}
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
| Member | Type | Description |
|
|
27
|
-
|--------|------|-------------|
|
|
28
|
-
| `server` | `ServiceServer<TAuthInfo>` | The server instance |
|
|
29
|
-
| `socket` | `ServiceSocket?` | WebSocket connection (undefined for HTTP requests) |
|
|
30
|
-
| `http` | `{ clientName: string; authTokenPayload?: AuthTokenPayload<TAuthInfo> }?` | HTTP request context (undefined for WebSocket requests) |
|
|
31
|
-
| `legacy` | `{ clientName?: string }?` | V1 legacy context (auto-update only) |
|
|
32
|
-
| `authInfo` | `TAuthInfo \| undefined` (getter) | Authenticated user data from socket or HTTP auth token |
|
|
33
|
-
| `clientName` | `string \| undefined` (getter) | Client name from socket, HTTP, or legacy context. Validates against path traversal |
|
|
34
|
-
| `clientPath` | `string \| undefined` (getter) | Resolved client path: `{rootPath}/www/{clientName}` |
|
|
35
|
-
| `getConfig<T>(section)` | `(section: string) => Promise<T>` | Loads config section from root and client `.config.json` files (merged) |
|
|
36
|
-
|
|
37
|
-
## `createServiceContext`
|
|
38
|
-
|
|
39
|
-
Creates a `ServiceContext` instance.
|
|
40
|
-
|
|
41
|
-
```typescript
|
|
42
|
-
export function createServiceContext<TAuthInfo = unknown>(
|
|
43
|
-
server: ServiceServer<TAuthInfo>,
|
|
44
|
-
socket?: ServiceSocket,
|
|
45
|
-
http?: { clientName: string; authTokenPayload?: AuthTokenPayload<TAuthInfo> },
|
|
46
|
-
legacy?: { clientName?: string },
|
|
47
|
-
): ServiceContext<TAuthInfo>;
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
| Parameter | Type | Description |
|
|
51
|
-
|-----------|------|-------------|
|
|
52
|
-
| `server` | `ServiceServer<TAuthInfo>` | The server instance |
|
|
53
|
-
| `socket` | `ServiceSocket?` | WebSocket connection |
|
|
54
|
-
| `http` | `{ clientName: string; authTokenPayload?: AuthTokenPayload<TAuthInfo> }?` | HTTP request context |
|
|
55
|
-
| `legacy` | `{ clientName?: string }?` | V1 legacy context |
|
|
56
|
-
|
|
57
|
-
## `getServiceAuthPermissions`
|
|
58
|
-
|
|
59
|
-
Reads auth permissions from a function wrapped by `auth()`. Returns `undefined` for unwrapped functions.
|
|
60
|
-
|
|
61
|
-
```typescript
|
|
62
|
-
export function getServiceAuthPermissions(fn: Function): string[] | undefined;
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
| Parameter | Type | Description |
|
|
66
|
-
|-----------|------|-------------|
|
|
67
|
-
| `fn` | `Function` | The function to check for auth permissions |
|
|
68
|
-
|
|
69
|
-
**Returns:** `string[] | undefined` -- Permission array if auth-wrapped, `undefined` otherwise.
|
|
70
|
-
|
|
71
|
-
## `auth`
|
|
72
|
-
|
|
73
|
-
Authentication wrapper for service factories and methods. Marks functions as requiring authentication, optionally with specific role permissions.
|
|
74
|
-
|
|
75
|
-
```typescript
|
|
76
|
-
// No role restriction (login required)
|
|
77
|
-
export function auth<TFunction extends (...args: any[]) => any>(fn: TFunction): TFunction;
|
|
78
|
-
|
|
79
|
-
// Role restriction (specific roles required)
|
|
80
|
-
export function auth<TFunction extends (...args: any[]) => any>(
|
|
81
|
-
permissions: string[],
|
|
82
|
-
fn: TFunction,
|
|
83
|
-
): TFunction;
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
Usage levels:
|
|
87
|
-
- **Service level:** `auth((ctx) => ({ ... }))` -- All methods require login
|
|
88
|
-
- **Service level with roles:** `auth(["admin"], (ctx) => ({ ... }))` -- All methods require specific roles
|
|
89
|
-
- **Method level:** `auth(() => result)` -- Specific method requires login
|
|
90
|
-
- **Method level with roles:** `auth(["admin"], () => result)` -- Specific method requires specific roles
|
|
91
|
-
|
|
92
|
-
## `ServiceDefinition`
|
|
93
|
-
|
|
94
|
-
Service definition with a name and factory function.
|
|
95
|
-
|
|
96
|
-
```typescript
|
|
97
|
-
export interface ServiceDefinition<TMethods = Record<string, (...args: any[]) => any>> {
|
|
98
|
-
name: string;
|
|
99
|
-
factory: (ctx: ServiceContext) => TMethods;
|
|
100
|
-
authPermissions?: string[];
|
|
101
|
-
}
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
| Field | Type | Description |
|
|
105
|
-
|-------|------|-------------|
|
|
106
|
-
| `name` | `string` | Service name (used in RPC routing) |
|
|
107
|
-
| `factory` | `(ctx: ServiceContext) => TMethods` | Factory function that creates service methods from a context |
|
|
108
|
-
| `authPermissions` | `string[]?` | Service-level auth permissions (extracted from `auth()` wrapper) |
|
|
109
|
-
|
|
110
|
-
## `defineService`
|
|
111
|
-
|
|
112
|
-
Defines a named service with a factory function.
|
|
113
|
-
|
|
114
|
-
```typescript
|
|
115
|
-
export function defineService<TMethods extends Record<string, (...args: any[]) => any>>(
|
|
116
|
-
name: string,
|
|
117
|
-
factory: (ctx: ServiceContext) => TMethods,
|
|
118
|
-
): ServiceDefinition<TMethods>;
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
| Parameter | Type | Description |
|
|
122
|
-
|-----------|------|-------------|
|
|
123
|
-
| `name` | `string` | Service name |
|
|
124
|
-
| `factory` | `(ctx: ServiceContext) => TMethods` | Factory function creating service methods |
|
|
125
|
-
|
|
126
|
-
**Returns:** `ServiceDefinition<TMethods>`
|
|
127
|
-
|
|
128
|
-
**Example:**
|
|
129
|
-
|
|
130
|
-
```typescript
|
|
131
|
-
const UserService = defineService("User", auth((ctx) => ({
|
|
132
|
-
getProfile: () => ctx.authInfo,
|
|
133
|
-
adminOnly: auth(["admin"], () => "admin-data"),
|
|
134
|
-
})));
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
## `ServiceMethods`
|
|
138
|
-
|
|
139
|
-
Type utility that extracts method signatures from a `ServiceDefinition`. Useful for sharing types between server and client.
|
|
140
|
-
|
|
141
|
-
```typescript
|
|
142
|
-
export type ServiceMethods<TDefinition> =
|
|
143
|
-
TDefinition extends ServiceDefinition<infer M> ? M : never;
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
**Example:**
|
|
147
|
-
|
|
148
|
-
```typescript
|
|
149
|
-
export type UserServiceType = ServiceMethods<typeof UserService>;
|
|
150
|
-
// Client: client.getService<UserServiceType>("User");
|
|
151
|
-
```
|
package/docs/service-executor.md
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
# Service Executor
|
|
2
|
-
|
|
3
|
-
## `executeServiceMethod`
|
|
4
|
-
|
|
5
|
-
Executes a service method with full validation and authentication checking.
|
|
6
|
-
|
|
7
|
-
```typescript
|
|
8
|
-
export async function executeServiceMethod(
|
|
9
|
-
server: ServiceServer,
|
|
10
|
-
def: {
|
|
11
|
-
serviceName: string;
|
|
12
|
-
methodName: string;
|
|
13
|
-
params: unknown[];
|
|
14
|
-
socket?: ServiceSocket;
|
|
15
|
-
http?: { clientName: string; authTokenPayload?: AuthTokenPayload };
|
|
16
|
-
},
|
|
17
|
-
): Promise<unknown>;
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
| Parameter | Type | Description |
|
|
21
|
-
|-----------|------|-------------|
|
|
22
|
-
| `server` | `ServiceServer` | The server instance (used to find service definitions and check auth config) |
|
|
23
|
-
| `def.serviceName` | `string` | Service name to look up |
|
|
24
|
-
| `def.methodName` | `string` | Method name to invoke |
|
|
25
|
-
| `def.params` | `unknown[]` | Method parameters |
|
|
26
|
-
| `def.socket` | `ServiceSocket?` | WebSocket connection (for WebSocket requests) |
|
|
27
|
-
| `def.http` | `{ clientName: string; authTokenPayload?: AuthTokenPayload }?` | HTTP context (for HTTP requests) |
|
|
28
|
-
|
|
29
|
-
**Returns:** `Promise<unknown>` -- The method return value.
|
|
30
|
-
|
|
31
|
-
**Execution flow:**
|
|
32
|
-
1. Finds the service definition by name (throws if not found)
|
|
33
|
-
2. Validates client name for path traversal attacks
|
|
34
|
-
3. Creates a `ServiceContext`
|
|
35
|
-
4. Calls the factory to create the method object
|
|
36
|
-
5. Looks up the method by name (throws if not a function)
|
|
37
|
-
6. Checks authentication:
|
|
38
|
-
- Method-level `auth()` permissions take precedence over service-level
|
|
39
|
-
- If `server.options.auth === undefined` and auth is required, throws configuration error
|
|
40
|
-
- If `server.options.auth === false`, skips all auth checks
|
|
41
|
-
- Otherwise, verifies `authTokenPayload` exists and has required roles
|
|
42
|
-
7. Invokes the method with parameters
|
package/docs/service-server.md
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
# Main ServiceServer
|
|
2
|
-
|
|
3
|
-
## `ServiceServer`
|
|
4
|
-
|
|
5
|
-
Main server class built on Fastify with WebSocket support, JWT authentication, and graceful shutdown. Extends `EventEmitter` with `ready` and `close` events.
|
|
6
|
-
|
|
7
|
-
```typescript
|
|
8
|
-
export class ServiceServer<TAuthInfo = unknown> extends EventEmitter<{
|
|
9
|
-
ready: void;
|
|
10
|
-
close: void;
|
|
11
|
-
}> {
|
|
12
|
-
constructor(options: ServiceServerOptions);
|
|
13
|
-
}
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
### Events
|
|
17
|
-
|
|
18
|
-
| Event | Data Type | Description |
|
|
19
|
-
|-------|-----------|-------------|
|
|
20
|
-
| `ready` | `void` | Emitted when the server starts listening |
|
|
21
|
-
| `close` | `void` | Emitted when the server is closed |
|
|
22
|
-
|
|
23
|
-
### Properties
|
|
24
|
-
|
|
25
|
-
| Property | Type | Description |
|
|
26
|
-
|----------|------|-------------|
|
|
27
|
-
| `options` | `ServiceServerOptions` (readonly) | Server configuration options |
|
|
28
|
-
| `fastify` | `FastifyInstance` (readonly) | The underlying Fastify instance for custom route registration |
|
|
29
|
-
| `isOpen` | `boolean` | Whether the server is currently listening |
|
|
30
|
-
|
|
31
|
-
### Methods
|
|
32
|
-
|
|
33
|
-
| Method | Signature | Description |
|
|
34
|
-
|--------|-----------|-------------|
|
|
35
|
-
| `listen` | `listen(): Promise<void>` | Starts the server. Registers all plugins, routes, and WebSocket handlers. Listens on `0.0.0.0:{port}` |
|
|
36
|
-
| `close` | `close(): Promise<void>` | Closes all WebSocket connections and stops the Fastify server |
|
|
37
|
-
| `emitEvent` | `emitEvent<TInfo, TData>(eventDef: ServiceEventDef<TInfo, TData>, infoSelector: (item: TInfo) => boolean, data: TData): Promise<void>` | Broadcasts an event to connected clients matching the info selector |
|
|
38
|
-
| `signAuthToken` | `signAuthToken(payload: AuthTokenPayload<TAuthInfo>): Promise<string>` | Signs a JWT token using the server's secret |
|
|
39
|
-
| `verifyAuthToken` | `verifyAuthToken(token: string): Promise<AuthTokenPayload<TAuthInfo>>` | Verifies a JWT token using the server's secret |
|
|
40
|
-
|
|
41
|
-
### Registered Routes
|
|
42
|
-
|
|
43
|
-
| Route | Method | Description |
|
|
44
|
-
|-------|--------|-------------|
|
|
45
|
-
| `/api/:service/:method` | GET, POST | HTTP RPC endpoint |
|
|
46
|
-
| `/upload` | POST | Multipart file upload endpoint |
|
|
47
|
-
| `/` | WebSocket | WebSocket endpoint (V1 and V2) |
|
|
48
|
-
| `/ws` | WebSocket | WebSocket endpoint (V1 and V2) |
|
|
49
|
-
| `/*` | GET, POST, PUT, DELETE, PATCH, HEAD | Static file handler |
|
|
50
|
-
|
|
51
|
-
### Registered Plugins
|
|
52
|
-
|
|
53
|
-
- `@fastify/websocket` -- WebSocket support
|
|
54
|
-
- `@fastify/helmet` -- Security headers (CSP configured for permissive defaults)
|
|
55
|
-
- `@fastify/multipart` -- File upload support
|
|
56
|
-
- `@fastify/static` -- Static file serving (manual serving via handler)
|
|
57
|
-
- `@fastify/cors` -- Cross-origin support (allows all origins)
|
|
58
|
-
|
|
59
|
-
### Graceful Shutdown
|
|
60
|
-
|
|
61
|
-
Registers `SIGINT` and `SIGTERM` handlers that:
|
|
62
|
-
1. Close all WebSocket connections
|
|
63
|
-
2. Stop the Fastify server
|
|
64
|
-
3. Force exit after 10 seconds if shutdown hangs
|
|
65
|
-
|
|
66
|
-
## `createServiceServer`
|
|
67
|
-
|
|
68
|
-
Factory function to create a `ServiceServer` instance.
|
|
69
|
-
|
|
70
|
-
```typescript
|
|
71
|
-
export function createServiceServer<TAuthInfo = unknown>(
|
|
72
|
-
options: ServiceServerOptions,
|
|
73
|
-
): ServiceServer<TAuthInfo>;
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
| Parameter | Type | Description |
|
|
77
|
-
|-----------|------|-------------|
|
|
78
|
-
| `options` | `ServiceServerOptions` | Server configuration options |
|
|
79
|
-
|
|
80
|
-
**Returns:** `ServiceServer<TAuthInfo>`
|
package/docs/service-socket.md
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
# Service Socket
|
|
2
|
-
|
|
3
|
-
## `ServiceSocket`
|
|
4
|
-
|
|
5
|
-
Manages a single WebSocket connection with protocol encoding/decoding, ping/pong keepalive, and event listener tracking.
|
|
6
|
-
|
|
7
|
-
```typescript
|
|
8
|
-
export interface ServiceSocket {
|
|
9
|
-
readonly connectedAtDateTime: DateTime;
|
|
10
|
-
readonly clientName: string;
|
|
11
|
-
readonly connReq: FastifyRequest;
|
|
12
|
-
authTokenPayload?: AuthTokenPayload;
|
|
13
|
-
|
|
14
|
-
close(): void;
|
|
15
|
-
send(uuid: string, msg: ServiceServerMessage): Promise<number>;
|
|
16
|
-
addListener(key: string, eventName: string, info: unknown): void;
|
|
17
|
-
removeListener(key: string): void;
|
|
18
|
-
getEventListeners(eventName: string): Array<{ key: string; info: unknown }>;
|
|
19
|
-
filterEventTargetKeys(targetKeys: string[]): string[];
|
|
20
|
-
on(event: "error", handler: (err: Error) => void): void;
|
|
21
|
-
on(event: "close", handler: (code: number) => void): void;
|
|
22
|
-
on(event: "message", handler: (data: { uuid: string; msg: ServiceClientMessage }) => void): void;
|
|
23
|
-
}
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
### Properties
|
|
27
|
-
|
|
28
|
-
| Property | Type | Description |
|
|
29
|
-
|----------|------|-------------|
|
|
30
|
-
| `connectedAtDateTime` | `DateTime` (readonly) | Timestamp when the connection was established |
|
|
31
|
-
| `clientName` | `string` (readonly) | Client identifier name |
|
|
32
|
-
| `connReq` | `FastifyRequest` (readonly) | Original Fastify request object |
|
|
33
|
-
| `authTokenPayload` | `AuthTokenPayload?` | Authenticated token payload (set via auth message) |
|
|
34
|
-
|
|
35
|
-
### Methods
|
|
36
|
-
|
|
37
|
-
| Method | Parameters | Return | Description |
|
|
38
|
-
|--------|-----------|--------|-------------|
|
|
39
|
-
| `close` | none | `void` | Terminates the WebSocket connection |
|
|
40
|
-
| `send` | `uuid: string, msg: ServiceServerMessage` | `Promise<number>` | Sends a message to the client. Returns total bytes sent |
|
|
41
|
-
| `addListener` | `key: string, eventName: string, info: unknown` | `void` | Registers an event listener |
|
|
42
|
-
| `removeListener` | `key: string` | `void` | Removes an event listener by key |
|
|
43
|
-
| `getEventListeners` | `eventName: string` | `Array<{ key: string; info: unknown }>` | Gets all listeners for an event name |
|
|
44
|
-
| `filterEventTargetKeys` | `targetKeys: string[]` | `string[]` | Filters target keys that exist in this socket's listeners |
|
|
45
|
-
| `on("error")` | `handler: (err: Error) => void` | `void` | Registers error event handler |
|
|
46
|
-
| `on("close")` | `handler: (code: number) => void` | `void` | Registers close event handler |
|
|
47
|
-
| `on("message")` | `handler: (data: { uuid: string; msg: ServiceClientMessage }) => void` | `void` | Registers message event handler |
|
|
48
|
-
|
|
49
|
-
## `createServiceSocket`
|
|
50
|
-
|
|
51
|
-
Creates a `ServiceSocket` instance wrapping a raw WebSocket.
|
|
52
|
-
|
|
53
|
-
```typescript
|
|
54
|
-
export function createServiceSocket(
|
|
55
|
-
socket: WebSocket,
|
|
56
|
-
clientId: string,
|
|
57
|
-
clientName: string,
|
|
58
|
-
connReq: FastifyRequest,
|
|
59
|
-
): ServiceSocket;
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
| Parameter | Type | Description |
|
|
63
|
-
|-----------|------|-------------|
|
|
64
|
-
| `socket` | `WebSocket` (from `ws`) | Raw WebSocket connection |
|
|
65
|
-
| `clientId` | `string` | Client unique identifier |
|
|
66
|
-
| `clientName` | `string` | Client name |
|
|
67
|
-
| `connReq` | `FastifyRequest` | Original request object |
|
|
68
|
-
|
|
69
|
-
Internal behavior:
|
|
70
|
-
- Ping interval: 5 seconds (terminates connection if no pong response)
|
|
71
|
-
- Responds to client ping (`0x01`) with pong (`0x02`)
|
|
72
|
-
- Uses `ServerProtocolWrapper` for encode/decode
|
|
73
|
-
- Reports chunk progress back to client during message reassembly
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
# WebSocket Handler
|
|
2
|
-
|
|
3
|
-
## `WebSocketHandler`
|
|
4
|
-
|
|
5
|
-
Manages multiple WebSocket connections, routes messages to services, and handles event broadcasting.
|
|
6
|
-
|
|
7
|
-
```typescript
|
|
8
|
-
export interface WebSocketHandler {
|
|
9
|
-
addSocket(
|
|
10
|
-
socket: WebSocket,
|
|
11
|
-
clientId: string,
|
|
12
|
-
clientName: string,
|
|
13
|
-
connReq: FastifyRequest,
|
|
14
|
-
): void;
|
|
15
|
-
closeAll(): void;
|
|
16
|
-
emit<TInfo, TData>(
|
|
17
|
-
eventDef: ServiceEventDef<TInfo, TData>,
|
|
18
|
-
infoSelector: (item: TInfo) => boolean,
|
|
19
|
-
data: TData,
|
|
20
|
-
): Promise<void>;
|
|
21
|
-
}
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
| Method | Parameters | Return | Description |
|
|
25
|
-
|--------|-----------|--------|-------------|
|
|
26
|
-
| `addSocket` | `socket: WebSocket, clientId: string, clientName: string, connReq: FastifyRequest` | `void` | Registers a new WebSocket connection. Closes any existing connection with the same `clientId` |
|
|
27
|
-
| `closeAll` | none | `void` | Closes all active WebSocket connections |
|
|
28
|
-
| `emit` | `eventDef: ServiceEventDef<TInfo, TData>, infoSelector: (item: TInfo) => boolean, data: TData` | `Promise<void>` | Broadcasts an event to all sockets that have matching event listeners |
|
|
29
|
-
|
|
30
|
-
## `createWebSocketHandler`
|
|
31
|
-
|
|
32
|
-
Creates a `WebSocketHandler` instance.
|
|
33
|
-
|
|
34
|
-
```typescript
|
|
35
|
-
export function createWebSocketHandler(
|
|
36
|
-
runMethod: (def: {
|
|
37
|
-
serviceName: string;
|
|
38
|
-
methodName: string;
|
|
39
|
-
params: unknown[];
|
|
40
|
-
socket?: ServiceSocket;
|
|
41
|
-
}) => Promise<unknown>,
|
|
42
|
-
jwtSecret: string | undefined,
|
|
43
|
-
): WebSocketHandler;
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
| Parameter | Type | Description |
|
|
47
|
-
|-----------|------|-------------|
|
|
48
|
-
| `runMethod` | `(def: { serviceName; methodName; params; socket? }) => Promise<unknown>` | Callback to execute service methods |
|
|
49
|
-
| `jwtSecret` | `string \| undefined` | JWT secret for auth message verification |
|
|
50
|
-
|
|
51
|
-
Message routing:
|
|
52
|
-
- `${service}.${method}` -- Invokes `runMethod` and sends response
|
|
53
|
-
- `evt:add` -- Registers an event listener on the socket
|
|
54
|
-
- `evt:remove` -- Removes an event listener from the socket
|
|
55
|
-
- `evt:gets` -- Returns all listener infos for an event name across all sockets
|
|
56
|
-
- `evt:emit` -- Dispatches an event to target listener keys across all sockets
|
|
57
|
-
- `auth` -- Verifies JWT token and stores payload on the socket
|
|
58
|
-
- Other -- Returns `BAD_MESSAGE` error
|