@simplysm/service-server 14.0.4 → 14.0.6

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.
@@ -0,0 +1,151 @@
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
+ ```
@@ -0,0 +1,42 @@
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
@@ -0,0 +1,80 @@
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>`
@@ -0,0 +1,73 @@
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
@@ -0,0 +1,58 @@
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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simplysm/service-server",
3
- "version": "14.0.4",
3
+ "version": "14.0.6",
4
4
  "description": "심플리즘 패키지 - 서비스 (server)",
5
5
  "author": "심플리즘",
6
6
  "license": "Apache-2.0",
@@ -35,11 +35,11 @@
35
35
  "semver": "^7.7.4",
36
36
  "utf-8-validate": "^6.0.6",
37
37
  "ws": "^8.20.0",
38
- "@simplysm/core-common": "14.0.4",
39
- "@simplysm/orm-common": "14.0.4",
40
- "@simplysm/orm-node": "14.0.4",
41
- "@simplysm/service-common": "14.0.4",
42
- "@simplysm/core-node": "14.0.4"
38
+ "@simplysm/core-common": "14.0.6",
39
+ "@simplysm/core-node": "14.0.6",
40
+ "@simplysm/orm-node": "14.0.6",
41
+ "@simplysm/orm-common": "14.0.6",
42
+ "@simplysm/service-common": "14.0.6"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@types/nodemailer": "^7.0.11",
package/docs/core.md DELETED
@@ -1,192 +0,0 @@
1
- # Core
2
-
3
- Service definition, context, authentication wrapper, and method execution.
4
-
5
- ## ServiceContext\<TAuthInfo\>
6
-
7
- Context object passed to service factory functions. Provides access to the server, socket, HTTP info, and authentication state.
8
-
9
- ```ts
10
- interface ServiceContext<TAuthInfo = unknown> {
11
- server: ServiceServer<TAuthInfo>;
12
- socket?: ServiceSocket;
13
- http?: {
14
- clientName: string;
15
- authTokenPayload?: AuthTokenPayload<TAuthInfo>;
16
- };
17
- legacy?: {
18
- clientName?: string;
19
- };
20
- get authInfo(): TAuthInfo | undefined;
21
- get clientName(): string | undefined;
22
- get clientPath(): string | undefined;
23
- getConfig<T>(section: string): Promise<T>;
24
- }
25
- ```
26
-
27
- | Member | Kind | Type | Description |
28
- |--------|------|------|-------------|
29
- | `server` | property | `ServiceServer<TAuthInfo>` | Reference to the server instance |
30
- | `socket` | property | `ServiceSocket?` | WebSocket connection (present for WS calls) |
31
- | `http` | property | `{ clientName; authTokenPayload? }?` | HTTP request info (present for HTTP calls) |
32
- | `http.clientName` | field | `string` | Client identifier from HTTP header |
33
- | `http.authTokenPayload` | field | `AuthTokenPayload<TAuthInfo>?` | Decoded auth token from HTTP request |
34
- | `legacy` | property | `{ clientName? }?` | Legacy V1 connection info |
35
- | `authInfo` | getter | `TAuthInfo \| undefined` | Authenticated user data (from socket or HTTP token) |
36
- | `clientName` | getter | `string \| undefined` | Client name (from socket, HTTP, or legacy) |
37
- | `clientPath` | getter | `string \| undefined` | Client path identifier |
38
- | `getConfig` | method | `<T>(section: string) => Promise<T>` | Read a configuration section |
39
-
40
- ## createServiceContext
41
-
42
- Create a `ServiceContext` instance.
43
-
44
- ```ts
45
- function createServiceContext<TAuthInfo = unknown>(
46
- server: ServiceServer<TAuthInfo>,
47
- socket?: ServiceSocket,
48
- http?: { clientName: string; authTokenPayload?: AuthTokenPayload<TAuthInfo> },
49
- legacy?: { clientName?: string },
50
- ): ServiceContext<TAuthInfo>;
51
- ```
52
-
53
- | Parameter | Type | Description |
54
- |-----------|------|-------------|
55
- | `server` | `ServiceServer<TAuthInfo>` | Server instance |
56
- | `socket` | `ServiceSocket?` | WebSocket connection |
57
- | `http` | `{ clientName; authTokenPayload? }?` | HTTP request context |
58
- | `legacy` | `{ clientName? }?` | Legacy V1 context |
59
-
60
- ## auth
61
-
62
- Authentication wrapper for service factories and methods. Marks a function as requiring authentication. Optionally restricts access to specific roles.
63
-
64
- ```ts
65
- // No role restriction -- just requires authentication
66
- function auth<TFunction extends (...args: any[]) => any>(fn: TFunction): TFunction;
67
-
68
- // With role restriction
69
- function auth<TFunction extends (...args: any[]) => any>(permissions: string[], fn: TFunction): TFunction;
70
- ```
71
-
72
- Can be applied at the service level (wrapping the factory) or at individual method level.
73
-
74
- ```ts
75
- const MyService = defineService("My", (ctx) => ({
76
- // Public method -- no auth required
77
- publicMethod() { return "open"; },
78
-
79
- // Requires authentication (any role)
80
- protectedMethod: auth(() => "protected"),
81
-
82
- // Requires "admin" role
83
- adminMethod: auth(["admin"], () => "admin only"),
84
- }));
85
- ```
86
-
87
- ## getServiceAuthPermissions
88
-
89
- Read the authentication permissions from a function wrapped with `auth()`. Returns `undefined` if the function is not wrapped.
90
-
91
- ```ts
92
- function getServiceAuthPermissions(fn: Function): string[] | undefined;
93
- ```
94
-
95
- | Parameter | Type | Description |
96
- |-----------|------|-------------|
97
- | `fn` | `Function` | A potentially auth-wrapped function |
98
-
99
- Returns `string[]` (role list, possibly empty for auth-only) or `undefined` (not wrapped).
100
-
101
- ## ServiceDefinition\<TMethods\>
102
-
103
- A named service with a factory function and optional auth permissions.
104
-
105
- ```ts
106
- interface ServiceDefinition<TMethods = Record<string, (...args: any[]) => any>> {
107
- name: string;
108
- factory: (ctx: ServiceContext) => TMethods;
109
- authPermissions?: string[];
110
- }
111
- ```
112
-
113
- | Field | Type | Description |
114
- |-------|------|-------------|
115
- | `name` | `string` | Service name used for RPC routing |
116
- | `factory` | `(ctx: ServiceContext) => TMethods` | Factory function that creates service methods |
117
- | `authPermissions` | `string[]?` | Service-level auth permissions (from `auth()` wrapper) |
118
-
119
- ## defineService
120
-
121
- Define a named service from a factory function.
122
-
123
- ```ts
124
- function defineService<TMethods extends Record<string, (...args: any[]) => any>>(
125
- name: string,
126
- factory: (ctx: ServiceContext) => TMethods,
127
- ): ServiceDefinition<TMethods>;
128
- ```
129
-
130
- | Parameter | Type | Description |
131
- |-----------|------|-------------|
132
- | `name` | `string` | Service name |
133
- | `factory` | `(ctx: ServiceContext) => TMethods` | Factory that receives context and returns methods |
134
-
135
- ```ts
136
- const UserService = defineService("User", (ctx) => ({
137
- async getUser(id: number) {
138
- // ctx.authInfo, ctx.server, ctx.getConfig, etc.
139
- return { id, name: "Alice" };
140
- },
141
- }));
142
- ```
143
-
144
- ## ServiceMethods\<TDefinition\>
145
-
146
- Utility type that extracts method signatures from a `ServiceDefinition`. Useful for sharing types with the client.
147
-
148
- ```ts
149
- type ServiceMethods<TDefinition> = TDefinition extends ServiceDefinition<infer M> ? M : never;
150
- ```
151
-
152
- ```ts
153
- // Server
154
- const UserService = defineService("User", (ctx) => ({
155
- getUser(id: number) { return { id, name: "Alice" }; },
156
- }));
157
-
158
- // Shared type for client
159
- type UserServiceType = ServiceMethods<typeof UserService>;
160
-
161
- // Client
162
- const userSvc = client.getService<UserServiceType>("User");
163
- const user = await userSvc.getUser(1); // typed as { id: number; name: string }
164
- ```
165
-
166
- ## executeServiceMethod
167
-
168
- Execute a service method by name. Used internally by the transport layer; can also be called directly for testing or custom routing.
169
-
170
- ```ts
171
- async function executeServiceMethod(
172
- server: ServiceServer,
173
- def: {
174
- serviceName: string;
175
- methodName: string;
176
- params: unknown[];
177
- socket?: ServiceSocket;
178
- http?: { clientName: string; authTokenPayload?: AuthTokenPayload };
179
- },
180
- ): Promise<unknown>;
181
- ```
182
-
183
- | Parameter | Type | Description |
184
- |-----------|------|-------------|
185
- | `server` | `ServiceServer` | Server instance containing registered services |
186
- | `def.serviceName` | `string` | Name of the service to invoke |
187
- | `def.methodName` | `string` | Method name within the service |
188
- | `def.params` | `unknown[]` | Method arguments |
189
- | `def.socket` | `ServiceSocket?` | WebSocket context (for WS calls) |
190
- | `def.http` | `{ clientName; authTokenPayload? }?` | HTTP context (for HTTP calls) |
191
-
192
- Returns the method return value.
package/docs/legacy.md DELETED
@@ -1,21 +0,0 @@
1
- # Legacy
2
-
3
- ## handleV1Connection
4
-
5
- V1 legacy client handler. Only supports auto-update requests; all other requests receive an upgrade-required error.
6
-
7
- ```ts
8
- 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` | Raw WebSocket connection from the V1 client |
18
- | `autoUpdateMethods` | `{ getLastVersion: (platform: string) => Promise<any> }` | Auto-update method implementation |
19
- | `clientNameSetter` | `((clientName: string \| undefined) => void)?` | Optional callback invoked with the client name when connected (or `undefined` on disconnect) |
20
-
21
- This handler is provided for backward compatibility with V1 protocol clients. New clients should use the V2 binary protocol.