@simplysm/service-client 14.0.4 → 14.0.5
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 +84 -397
- package/docs/browser-compat-types.md +77 -0
- package/docs/client-protocol-wrapper.md +35 -0
- package/docs/connection-options.md +21 -0
- package/docs/features.md +147 -0
- package/docs/progress-types.md +37 -0
- package/docs/service-client.md +89 -0
- package/docs/service-transport.md +60 -0
- package/docs/socket-provider.md +72 -0
- package/package.json +6 -5
package/README.md
CHANGED
|
@@ -1,40 +1,95 @@
|
|
|
1
1
|
# @simplysm/service-client
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
WebSocket-based RPC client SDK with type-safe service proxy, event subscription, file upload/download, and ORM connector. Depends on `@simplysm/service-common` for protocol and shared types.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Installation
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
```bash
|
|
8
|
+
npm install @simplysm/service-client
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## API Overview
|
|
12
|
+
|
|
13
|
+
### Browser Compat Types
|
|
14
|
+
| API | Type | Description |
|
|
15
|
+
|-----|------|-------------|
|
|
16
|
+
| `BlobInput` | `type` | Blob constructor data type (DOM BlobPart replacement) |
|
|
17
|
+
| `FileCollection` | `interface` | File collection interface (DOM FileList replacement) |
|
|
18
|
+
| `WorkerLike` | `interface` | Web Worker interface (DOM Worker replacement) |
|
|
19
|
+
| `isWorkerSupported` | `function` | Checks Web Worker API availability |
|
|
20
|
+
| `createBrowserWorker` | `function` | Creates a Web Worker (returns undefined if unsupported) |
|
|
21
|
+
|
|
22
|
+
-> See [docs/browser-compat-types.md](./docs/browser-compat-types.md) for details.
|
|
23
|
+
|
|
24
|
+
### Connection Options
|
|
25
|
+
| API | Type | Description |
|
|
26
|
+
|-----|------|-------------|
|
|
27
|
+
| `ServiceConnectionOptions` | `interface` | Connection options (host, port, SSL, reconnect) |
|
|
28
|
+
|
|
29
|
+
-> See [docs/connection-options.md](./docs/connection-options.md) for details.
|
|
30
|
+
|
|
31
|
+
### Progress Types
|
|
32
|
+
| API | Type | Description |
|
|
33
|
+
|-----|------|-------------|
|
|
34
|
+
| `ServiceProgress` | `interface` | Progress callback hooks for request/response/server |
|
|
35
|
+
| `ServiceProgressState` | `interface` | Progress state (uuid, totalSize, completedSize) |
|
|
36
|
+
|
|
37
|
+
-> See [docs/progress-types.md](./docs/progress-types.md) for details.
|
|
38
|
+
|
|
39
|
+
### Socket Provider
|
|
40
|
+
| API | Type | Description |
|
|
41
|
+
|-----|------|-------------|
|
|
42
|
+
| `SocketProviderEvents` | `interface` | Socket provider event map |
|
|
43
|
+
| `SocketProvider` | `interface` | Low-level WebSocket abstraction with auto-reconnect |
|
|
44
|
+
| `createSocketProvider` | `function` | Creates a socket provider instance |
|
|
8
45
|
|
|
9
|
-
|
|
10
|
-
|--------|------|----------|-------------|
|
|
11
|
-
| `ServiceConnectionOptions` | interface | Types | Connection options (host, port, SSL, reconnect) |
|
|
12
|
-
| `ServiceProgress` | interface | Types | Progress callback hooks for request/response/server |
|
|
13
|
-
| `ServiceProgressState` | interface | Types | Progress state (uuid, totalSize, completedSize) |
|
|
14
|
-
| `SocketProviderEvents` | interface | Transport | Socket provider event map |
|
|
15
|
-
| `SocketProvider` | interface | Transport | Low-level WebSocket abstraction |
|
|
16
|
-
| `createSocketProvider` | function | Transport | Create a socket provider instance |
|
|
17
|
-
| `ServiceTransportEvents` | interface | Transport | Transport event map |
|
|
18
|
-
| `ServiceTransport` | interface | Transport | Service-level message transport |
|
|
19
|
-
| `createServiceTransport` | function | Transport | Create a service transport instance |
|
|
20
|
-
| `ClientProtocolWrapper` | interface | Protocol | Client-side protocol encoder/decoder wrapper |
|
|
21
|
-
| `createClientProtocolWrapper` | function | Protocol | Create a client protocol wrapper |
|
|
22
|
-
| `EventClient` | interface | Features | Event subscription client |
|
|
23
|
-
| `createEventClient` | function | Features | Create an event client |
|
|
24
|
-
| `FileClient` | interface | Features | File upload/download client |
|
|
25
|
-
| `createFileClient` | function | Features | Create a file client |
|
|
26
|
-
| `OrmConnectOptions` | interface | Features | ORM connection options |
|
|
27
|
-
| `OrmClientConnector` | interface | Features | ORM client connector (with/without transaction) |
|
|
28
|
-
| `createOrmClientConnector` | function | Features | Create an ORM client connector |
|
|
29
|
-
| `OrmClientDbContextExecutor` | class | Features | ORM DbContext executor for client-side use |
|
|
30
|
-
| `ServiceClient` | class | Main | Main service client class |
|
|
31
|
-
| `ServiceProxy` | type | Main | Type-safe service proxy mapping |
|
|
32
|
-
| `createServiceClient` | function | Main | Create a ServiceClient instance |
|
|
46
|
+
-> See [docs/socket-provider.md](./docs/socket-provider.md) for details.
|
|
33
47
|
|
|
34
|
-
|
|
48
|
+
### Service Transport
|
|
49
|
+
| API | Type | Description |
|
|
50
|
+
|-----|------|-------------|
|
|
51
|
+
| `ServiceTransportEvents` | `interface` | Transport event map |
|
|
52
|
+
| `ServiceTransport` | `interface` | Service-level message transport |
|
|
53
|
+
| `createServiceTransport` | `function` | Creates a service transport instance |
|
|
35
54
|
|
|
36
|
-
|
|
55
|
+
-> See [docs/service-transport.md](./docs/service-transport.md) for details.
|
|
56
|
+
|
|
57
|
+
### Client Protocol Wrapper
|
|
58
|
+
| API | Type | Description |
|
|
59
|
+
|-----|------|-------------|
|
|
60
|
+
| `ClientProtocolWrapper` | `interface` | Client-side protocol encoder/decoder with Web Worker offloading |
|
|
61
|
+
| `createClientProtocolWrapper` | `function` | Creates a client protocol wrapper |
|
|
62
|
+
|
|
63
|
+
-> See [docs/client-protocol-wrapper.md](./docs/client-protocol-wrapper.md) for details.
|
|
64
|
+
|
|
65
|
+
### Event/File/ORM Client
|
|
66
|
+
| API | Type | Description |
|
|
67
|
+
|-----|------|-------------|
|
|
68
|
+
| `EventClient` | `interface` | Event subscription client |
|
|
69
|
+
| `createEventClient` | `function` | Creates an event client |
|
|
70
|
+
| `FileClient` | `interface` | File upload/download client |
|
|
71
|
+
| `createFileClient` | `function` | Creates a file client |
|
|
72
|
+
| `OrmConnectOptions` | `interface` | ORM connection options |
|
|
73
|
+
| `OrmClientConnector` | `interface` | ORM client connector (with/without transaction) |
|
|
74
|
+
| `createOrmClientConnector` | `function` | Creates an ORM client connector |
|
|
75
|
+
| `OrmClientDbContextExecutor` | `class` | ORM DbContext executor for client-side use |
|
|
76
|
+
|
|
77
|
+
-> See [docs/features.md](./docs/features.md) for details.
|
|
78
|
+
|
|
79
|
+
### Main ServiceClient
|
|
80
|
+
| API | Type | Description |
|
|
81
|
+
|-----|------|-------------|
|
|
82
|
+
| `ServiceClient` | `class` | Main service client class with events, RPC, auth, file ops |
|
|
83
|
+
| `ServiceProxy` | `type` | Type-safe service proxy mapping |
|
|
84
|
+
| `createServiceClient` | `function` | Factory function to create a ServiceClient |
|
|
85
|
+
|
|
86
|
+
-> See [docs/service-client.md](./docs/service-client.md) for details.
|
|
87
|
+
|
|
88
|
+
## Usage Examples
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
37
91
|
import { createServiceClient } from "@simplysm/service-client";
|
|
92
|
+
import { defineEvent } from "@simplysm/service-common";
|
|
38
93
|
|
|
39
94
|
// Create and connect
|
|
40
95
|
const client = createServiceClient("my-app", {
|
|
@@ -61,9 +116,7 @@ const uploadResults = await client.uploadFile(fileList);
|
|
|
61
116
|
const bytes = await client.downloadFileBuffer("uploads/file.txt");
|
|
62
117
|
|
|
63
118
|
// Event subscription
|
|
64
|
-
import { defineEvent } from "@simplysm/service-common";
|
|
65
119
|
const ChatEvent = defineEvent<{ roomId: number }, { text: string }>("ChatEvent");
|
|
66
|
-
|
|
67
120
|
const listenerKey = await client.addListener(ChatEvent, { roomId: 1 }, async (data) => {
|
|
68
121
|
// handle event
|
|
69
122
|
});
|
|
@@ -72,369 +125,3 @@ await client.removeListener(listenerKey);
|
|
|
72
125
|
// Clean up
|
|
73
126
|
await client.close();
|
|
74
127
|
```
|
|
75
|
-
|
|
76
|
-
## Types
|
|
77
|
-
|
|
78
|
-
### ServiceConnectionOptions
|
|
79
|
-
|
|
80
|
-
```ts
|
|
81
|
-
interface ServiceConnectionOptions {
|
|
82
|
-
port: number;
|
|
83
|
-
host: string;
|
|
84
|
-
ssl?: boolean;
|
|
85
|
-
maxReconnectCount?: number;
|
|
86
|
-
}
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
| Field | Type | Description |
|
|
90
|
-
|-------|------|-------------|
|
|
91
|
-
| `port` | `number` | Server port |
|
|
92
|
-
| `host` | `string` | Server hostname |
|
|
93
|
-
| `ssl` | `boolean?` | Enable SSL/TLS |
|
|
94
|
-
| `maxReconnectCount` | `number?` | Max reconnection attempts. Set to `0` to disable reconnection and disconnect immediately. |
|
|
95
|
-
|
|
96
|
-
### ServiceProgress
|
|
97
|
-
|
|
98
|
-
Callback hooks for monitoring message progress.
|
|
99
|
-
|
|
100
|
-
```ts
|
|
101
|
-
interface ServiceProgress {
|
|
102
|
-
request?: (s: ServiceProgressState) => void;
|
|
103
|
-
response?: (s: ServiceProgressState) => void;
|
|
104
|
-
server?: (s: ServiceProgressState) => void;
|
|
105
|
-
}
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
| Field | Type | Description |
|
|
109
|
-
|-------|------|-------------|
|
|
110
|
-
| `request` | `(s: ServiceProgressState) => void` | Called during request encoding/sending progress |
|
|
111
|
-
| `response` | `(s: ServiceProgressState) => void` | Called during response decoding progress |
|
|
112
|
-
| `server` | `(s: ServiceProgressState) => void` | Called when server reports chunk receive progress |
|
|
113
|
-
|
|
114
|
-
### ServiceProgressState
|
|
115
|
-
|
|
116
|
-
```ts
|
|
117
|
-
interface ServiceProgressState {
|
|
118
|
-
uuid: string;
|
|
119
|
-
totalSize: number;
|
|
120
|
-
completedSize: number;
|
|
121
|
-
}
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
| Field | Type | Description |
|
|
125
|
-
|-------|------|-------------|
|
|
126
|
-
| `uuid` | `string` | Message UUID |
|
|
127
|
-
| `totalSize` | `number` | Total message size in bytes |
|
|
128
|
-
| `completedSize` | `number` | Bytes transferred so far |
|
|
129
|
-
|
|
130
|
-
## Transport
|
|
131
|
-
|
|
132
|
-
### SocketProviderEvents
|
|
133
|
-
|
|
134
|
-
```ts
|
|
135
|
-
interface SocketProviderEvents {
|
|
136
|
-
message: Bytes;
|
|
137
|
-
state: "connected" | "closed" | "reconnecting";
|
|
138
|
-
}
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
| Event | Data Type | Description |
|
|
142
|
-
|-------|-----------|-------------|
|
|
143
|
-
| `message` | `Bytes` | Raw binary message received |
|
|
144
|
-
| `state` | `"connected" \| "closed" \| "reconnecting"` | Connection state change |
|
|
145
|
-
|
|
146
|
-
### SocketProvider
|
|
147
|
-
|
|
148
|
-
Low-level WebSocket abstraction with auto-reconnect.
|
|
149
|
-
|
|
150
|
-
```ts
|
|
151
|
-
interface SocketProvider {
|
|
152
|
-
readonly clientName: string;
|
|
153
|
-
readonly connected: boolean;
|
|
154
|
-
on<K extends keyof SocketProviderEvents & string>(type: K, listener: (data: SocketProviderEvents[K]) => void): void;
|
|
155
|
-
off<K extends keyof SocketProviderEvents & string>(type: K, listener: (data: SocketProviderEvents[K]) => void): void;
|
|
156
|
-
connect(): Promise<void>;
|
|
157
|
-
close(): Promise<void>;
|
|
158
|
-
send(data: Bytes): Promise<void>;
|
|
159
|
-
}
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
| Member | Kind | Description |
|
|
163
|
-
|--------|------|-------------|
|
|
164
|
-
| `clientName` | property | Client identifier name |
|
|
165
|
-
| `connected` | property | Whether currently connected |
|
|
166
|
-
| `on` | method | Subscribe to an event |
|
|
167
|
-
| `off` | method | Unsubscribe from an event |
|
|
168
|
-
| `connect` | method | Open the WebSocket connection |
|
|
169
|
-
| `close` | method | Close the connection |
|
|
170
|
-
| `send` | method | Send binary data |
|
|
171
|
-
|
|
172
|
-
### createSocketProvider
|
|
173
|
-
|
|
174
|
-
```ts
|
|
175
|
-
function createSocketProvider(url: string, clientName: string, maxReconnectCount: number): SocketProvider;
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
| Parameter | Type | Description |
|
|
179
|
-
|-----------|------|-------------|
|
|
180
|
-
| `url` | `string` | WebSocket URL |
|
|
181
|
-
| `clientName` | `string` | Client identifier |
|
|
182
|
-
| `maxReconnectCount` | `number` | Maximum reconnection attempts |
|
|
183
|
-
|
|
184
|
-
### ServiceTransportEvents
|
|
185
|
-
|
|
186
|
-
```ts
|
|
187
|
-
interface ServiceTransportEvents {
|
|
188
|
-
event: { keys: string[]; data: unknown };
|
|
189
|
-
}
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
| Event | Data Type | Description |
|
|
193
|
-
|-------|-----------|-------------|
|
|
194
|
-
| `event` | `{ keys: string[]; data: unknown }` | Server-side event broadcast received |
|
|
195
|
-
|
|
196
|
-
### ServiceTransport
|
|
197
|
-
|
|
198
|
-
Service-level message transport built on top of `SocketProvider`.
|
|
199
|
-
|
|
200
|
-
```ts
|
|
201
|
-
interface ServiceTransport {
|
|
202
|
-
on<K extends keyof ServiceTransportEvents & string>(type: K, listener: (data: ServiceTransportEvents[K]) => void): void;
|
|
203
|
-
off<K extends keyof ServiceTransportEvents & string>(type: K, listener: (data: ServiceTransportEvents[K]) => void): void;
|
|
204
|
-
send(message: ServiceClientMessage, progress?: ServiceProgress): Promise<unknown>;
|
|
205
|
-
}
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
| Method | Parameters | Return | Description |
|
|
209
|
-
|--------|-----------|--------|-------------|
|
|
210
|
-
| `on` | `type`, `listener` | `void` | Subscribe to transport events |
|
|
211
|
-
| `off` | `type`, `listener` | `void` | Unsubscribe from transport events |
|
|
212
|
-
| `send` | `message: ServiceClientMessage`, `progress?: ServiceProgress` | `Promise<unknown>` | Send a service message and await the response |
|
|
213
|
-
|
|
214
|
-
### createServiceTransport
|
|
215
|
-
|
|
216
|
-
```ts
|
|
217
|
-
function createServiceTransport(socket: SocketProvider, protocol: ClientProtocolWrapper): ServiceTransport;
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
## Protocol
|
|
221
|
-
|
|
222
|
-
### ClientProtocolWrapper
|
|
223
|
-
|
|
224
|
-
Client-side protocol encoder/decoder wrapper.
|
|
225
|
-
|
|
226
|
-
```ts
|
|
227
|
-
interface ClientProtocolWrapper {
|
|
228
|
-
encode(uuid: string, message: ServiceMessage): Promise<{ chunks: Bytes[]; totalSize: number }>;
|
|
229
|
-
decode(bytes: Bytes): Promise<ServiceMessageDecodeResult<ServiceMessage>>;
|
|
230
|
-
dispose(): void;
|
|
231
|
-
}
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
| Method | Parameters | Return | Description |
|
|
235
|
-
|--------|-----------|--------|-------------|
|
|
236
|
-
| `encode` | `uuid: string`, `message: ServiceMessage` | `Promise<{ chunks: Bytes[]; totalSize: number }>` | Encode a message into binary chunks |
|
|
237
|
-
| `decode` | `bytes: Bytes` | `Promise<ServiceMessageDecodeResult<ServiceMessage>>` | Decode received binary data |
|
|
238
|
-
| `dispose` | -- | `void` | Clean up resources |
|
|
239
|
-
|
|
240
|
-
### createClientProtocolWrapper
|
|
241
|
-
|
|
242
|
-
```ts
|
|
243
|
-
function createClientProtocolWrapper(protocol: ServiceProtocol): ClientProtocolWrapper;
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
Creates a `ClientProtocolWrapper` from a `ServiceProtocol` instance.
|
|
247
|
-
|
|
248
|
-
## Features
|
|
249
|
-
|
|
250
|
-
### EventClient
|
|
251
|
-
|
|
252
|
-
Event subscription client for the service event system.
|
|
253
|
-
|
|
254
|
-
```ts
|
|
255
|
-
interface EventClient {
|
|
256
|
-
addListener<TInfo, TData>(eventDef: ServiceEventDef<TInfo, TData>, info: TInfo, cb: (data: TData) => PromiseLike<void>): Promise<string>;
|
|
257
|
-
removeListener(key: string): Promise<void>;
|
|
258
|
-
emit<TInfo, TData>(eventDef: ServiceEventDef<TInfo, TData>, infoSelector: (item: TInfo) => boolean, data: TData): Promise<void>;
|
|
259
|
-
resubscribeAll(): Promise<void>;
|
|
260
|
-
}
|
|
261
|
-
```
|
|
262
|
-
|
|
263
|
-
| Method | Parameters | Return | Description |
|
|
264
|
-
|--------|-----------|--------|-------------|
|
|
265
|
-
| `addListener` | `eventDef`, `info: TInfo`, `cb` | `Promise<string>` | Subscribe to an event; returns listener key |
|
|
266
|
-
| `removeListener` | `key: string` | `Promise<void>` | Unsubscribe by listener key |
|
|
267
|
-
| `emit` | `eventDef`, `infoSelector`, `data: TData` | `Promise<void>` | Emit an event to matching listeners |
|
|
268
|
-
| `resubscribeAll` | -- | `Promise<void>` | Resubscribe all listeners (e.g., after reconnect) |
|
|
269
|
-
|
|
270
|
-
### createEventClient
|
|
271
|
-
|
|
272
|
-
```ts
|
|
273
|
-
function createEventClient(transport: ServiceTransport): EventClient;
|
|
274
|
-
```
|
|
275
|
-
|
|
276
|
-
### FileClient
|
|
277
|
-
|
|
278
|
-
File upload and download client.
|
|
279
|
-
|
|
280
|
-
```ts
|
|
281
|
-
interface FileClient {
|
|
282
|
-
download(relPath: string): Promise<Bytes>;
|
|
283
|
-
upload(files: File[] | FileList | { name: string; data: BlobPart }[], authToken: string): Promise<ServiceUploadResult[]>;
|
|
284
|
-
}
|
|
285
|
-
```
|
|
286
|
-
|
|
287
|
-
| Method | Parameters | Return | Description |
|
|
288
|
-
|--------|-----------|--------|-------------|
|
|
289
|
-
| `download` | `relPath: string` | `Promise<Bytes>` | Download a file by relative path |
|
|
290
|
-
| `upload` | `files`, `authToken: string` | `Promise<ServiceUploadResult[]>` | Upload files with authentication |
|
|
291
|
-
|
|
292
|
-
### createFileClient
|
|
293
|
-
|
|
294
|
-
```ts
|
|
295
|
-
function createFileClient(hostUrl: string, clientName: string): FileClient;
|
|
296
|
-
```
|
|
297
|
-
|
|
298
|
-
### OrmConnectOptions\<TDef\>
|
|
299
|
-
|
|
300
|
-
```ts
|
|
301
|
-
interface OrmConnectOptions<TDef extends DbContextDef<any, any, any>> {
|
|
302
|
-
dbContextDef: TDef;
|
|
303
|
-
connOpt: DbConnOptions & { configName: string };
|
|
304
|
-
dbContextOpt?: {
|
|
305
|
-
database: string;
|
|
306
|
-
schema: string;
|
|
307
|
-
};
|
|
308
|
-
}
|
|
309
|
-
```
|
|
310
|
-
|
|
311
|
-
| Field | Type | Description |
|
|
312
|
-
|-------|------|-------------|
|
|
313
|
-
| `dbContextDef` | `TDef` | Database context definition |
|
|
314
|
-
| `connOpt` | `DbConnOptions & { configName: string }` | Connection options with required config name |
|
|
315
|
-
| `dbContextOpt` | `{ database: string; schema: string }?` | Optional database/schema override |
|
|
316
|
-
|
|
317
|
-
### OrmClientConnector
|
|
318
|
-
|
|
319
|
-
ORM client connector that opens a database context over the service RPC layer.
|
|
320
|
-
|
|
321
|
-
```ts
|
|
322
|
-
interface OrmClientConnector {
|
|
323
|
-
connect<TDef extends DbContextDef<any, any, any>, R>(
|
|
324
|
-
config: OrmConnectOptions<TDef>,
|
|
325
|
-
callback: (db: DbContextInstance<TDef>) => Promise<R> | R,
|
|
326
|
-
): Promise<R>;
|
|
327
|
-
connectWithoutTransaction<TDef extends DbContextDef<any, any, any>, R>(
|
|
328
|
-
config: OrmConnectOptions<TDef>,
|
|
329
|
-
callback: (db: DbContextInstance<TDef>) => Promise<R> | R,
|
|
330
|
-
): Promise<R>;
|
|
331
|
-
}
|
|
332
|
-
```
|
|
333
|
-
|
|
334
|
-
| Method | Parameters | Return | Description |
|
|
335
|
-
|--------|-----------|--------|-------------|
|
|
336
|
-
| `connect` | `config`, `callback` | `Promise<R>` | Open a DB context with automatic transaction (begin/commit/rollback) |
|
|
337
|
-
| `connectWithoutTransaction` | `config`, `callback` | `Promise<R>` | Open a DB context without automatic transaction management |
|
|
338
|
-
|
|
339
|
-
### createOrmClientConnector
|
|
340
|
-
|
|
341
|
-
```ts
|
|
342
|
-
function createOrmClientConnector(serviceClient: ServiceClient): OrmClientConnector;
|
|
343
|
-
```
|
|
344
|
-
|
|
345
|
-
### OrmClientDbContextExecutor
|
|
346
|
-
|
|
347
|
-
Implements `DbContextExecutor` for client-side ORM usage over the service RPC layer.
|
|
348
|
-
|
|
349
|
-
```ts
|
|
350
|
-
class OrmClientDbContextExecutor implements DbContextExecutor {
|
|
351
|
-
constructor(client: ServiceClient, opt: DbConnOptions & { configName: string });
|
|
352
|
-
}
|
|
353
|
-
```
|
|
354
|
-
|
|
355
|
-
| Method | Parameters | Return | Description |
|
|
356
|
-
|--------|-----------|--------|-------------|
|
|
357
|
-
| `getInfo` | -- | `Promise<{ dialect; database?; schema? }>` | Get database info |
|
|
358
|
-
| `connect` | -- | `Promise<void>` | Open the connection |
|
|
359
|
-
| `beginTransaction` | `isolationLevel?: IsolationLevel` | `Promise<void>` | Begin a transaction |
|
|
360
|
-
| `commitTransaction` | -- | `Promise<void>` | Commit the transaction |
|
|
361
|
-
| `rollbackTransaction` | -- | `Promise<void>` | Rollback the transaction |
|
|
362
|
-
| `close` | -- | `Promise<void>` | Close the connection |
|
|
363
|
-
| `executeDefs` | `defs: QueryDef[]`, `options?: (ResultMeta \| undefined)[]` | `Promise<T[][]>` | Execute query definitions |
|
|
364
|
-
| `executeParametrized` | `query: string`, `params?: unknown[]` | `Promise<unknown[][]>` | Execute a parameterized query |
|
|
365
|
-
| `bulkInsert` | `tableName: string`, `columnDefs: Record<string, ColumnMeta>`, `records: Record<string, unknown>[]` | `Promise<void>` | Bulk insert records |
|
|
366
|
-
|
|
367
|
-
## Main
|
|
368
|
-
|
|
369
|
-
### ServiceClient
|
|
370
|
-
|
|
371
|
-
Main service client class. Extends `EventEmitter` with progress and state events.
|
|
372
|
-
|
|
373
|
-
```ts
|
|
374
|
-
class ServiceClient extends EventEmitter<{
|
|
375
|
-
"request-progress": ServiceProgressState;
|
|
376
|
-
"response-progress": ServiceProgressState;
|
|
377
|
-
"server-progress": ServiceProgressState;
|
|
378
|
-
"state": "connected" | "closed" | "reconnecting";
|
|
379
|
-
}> {
|
|
380
|
-
constructor(name: string, options: ServiceConnectionOptions);
|
|
381
|
-
}
|
|
382
|
-
```
|
|
383
|
-
|
|
384
|
-
#### Events
|
|
385
|
-
|
|
386
|
-
| Event | Data Type | Description |
|
|
387
|
-
|-------|-----------|-------------|
|
|
388
|
-
| `request-progress` | `ServiceProgressState` | Request sending progress |
|
|
389
|
-
| `response-progress` | `ServiceProgressState` | Response receiving progress |
|
|
390
|
-
| `server-progress` | `ServiceProgressState` | Server-side chunk progress |
|
|
391
|
-
| `state` | `"connected" \| "closed" \| "reconnecting"` | Connection state change |
|
|
392
|
-
|
|
393
|
-
#### Properties
|
|
394
|
-
|
|
395
|
-
| Property | Type | Description |
|
|
396
|
-
|----------|------|-------------|
|
|
397
|
-
| `name` | `string` | Client name |
|
|
398
|
-
| `options` | `ServiceConnectionOptions` | Connection options |
|
|
399
|
-
| `connected` | `boolean` | Whether the client is connected |
|
|
400
|
-
| `hostUrl` | `string` | Full host URL (computed from options) |
|
|
401
|
-
|
|
402
|
-
#### Methods
|
|
403
|
-
|
|
404
|
-
| Method | Parameters | Return | Description |
|
|
405
|
-
|--------|-----------|--------|-------------|
|
|
406
|
-
| `getService<TService>` | `serviceName: string` | `ServiceProxy<TService>` | Get a type-safe service proxy |
|
|
407
|
-
| `connect` | -- | `Promise<void>` | Open the WebSocket connection |
|
|
408
|
-
| `close` | -- | `Promise<void>` | Close the connection |
|
|
409
|
-
| `send` | `serviceName`, `methodName`, `params`, `progress?` | `Promise<unknown>` | Send an RPC call |
|
|
410
|
-
| `auth` | `token: string` | `Promise<void>` | Authenticate with a JWT token |
|
|
411
|
-
| `addListener` | `eventDef`, `info`, `cb` | `Promise<string>` | Subscribe to an event |
|
|
412
|
-
| `removeListener` | `key: string` | `Promise<void>` | Unsubscribe from an event |
|
|
413
|
-
| `emitEvent` | `eventDef`, `infoSelector`, `data` | `Promise<void>` | Emit an event |
|
|
414
|
-
| `uploadFile` | `files` | `Promise<ServiceUploadResult[]>` | Upload files |
|
|
415
|
-
| `downloadFileBuffer` | `relPath: string` | `Promise<Bytes>` | Download a file |
|
|
416
|
-
|
|
417
|
-
### ServiceProxy\<TService\>
|
|
418
|
-
|
|
419
|
-
Maps service method signatures to async versions. Every method returns `Promise<Awaited<R>>`.
|
|
420
|
-
|
|
421
|
-
```ts
|
|
422
|
-
type ServiceProxy<TService> = {
|
|
423
|
-
[K in keyof TService]: TService[K] extends (...args: infer P) => infer R
|
|
424
|
-
? (...args: P) => Promise<Awaited<R>>
|
|
425
|
-
: never;
|
|
426
|
-
};
|
|
427
|
-
```
|
|
428
|
-
|
|
429
|
-
### createServiceClient
|
|
430
|
-
|
|
431
|
-
```ts
|
|
432
|
-
function createServiceClient(name: string, options: ServiceConnectionOptions): ServiceClient;
|
|
433
|
-
```
|
|
434
|
-
|
|
435
|
-
Factory function to create a `ServiceClient` instance.
|
|
436
|
-
|
|
437
|
-
| Parameter | Type | Description |
|
|
438
|
-
|-----------|------|-------------|
|
|
439
|
-
| `name` | `string` | Client identifier name |
|
|
440
|
-
| `options` | `ServiceConnectionOptions` | Connection options |
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Browser Compat Types
|
|
2
|
+
|
|
3
|
+
Cross-environment compatible types that replace DOM-only types (`FileList`, `BlobPart`, `Worker`, `Transferable`) so that typecheck passes in both Node.js and browser environments.
|
|
4
|
+
|
|
5
|
+
## `BlobInput`
|
|
6
|
+
|
|
7
|
+
Blob constructor data type replacing DOM `BlobPart`.
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
export type BlobInput = Blob | Uint8Array<ArrayBuffer> | ArrayBuffer | string;
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## `FileCollection`
|
|
14
|
+
|
|
15
|
+
File collection interface replacing DOM `FileList`. Structurally compatible with browser `FileList`.
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
export interface FileCollection {
|
|
19
|
+
readonly length: number;
|
|
20
|
+
item(index: number): File | null;
|
|
21
|
+
[index: number]: File;
|
|
22
|
+
[Symbol.iterator](): IterableIterator<File>;
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
| Member | Type | Description |
|
|
27
|
+
|--------|------|-------------|
|
|
28
|
+
| `length` | `number` (readonly) | Number of files in the collection |
|
|
29
|
+
| `item(index)` | `(index: number) => File \| null` | Returns the file at the given index |
|
|
30
|
+
| `[index]` | `File` | Index accessor |
|
|
31
|
+
| `[Symbol.iterator]` | `() => IterableIterator<File>` | Iterable protocol support |
|
|
32
|
+
|
|
33
|
+
## `WorkerLike`
|
|
34
|
+
|
|
35
|
+
Web Worker interface replacing DOM `Worker`. Structurally compatible with browser `Worker`.
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
export interface WorkerLike {
|
|
39
|
+
onmessage: ((ev: MessageEvent) => void) | null;
|
|
40
|
+
postMessage(message: unknown, transfer?: unknown[]): void;
|
|
41
|
+
terminate(): void;
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
| Member | Type | Description |
|
|
46
|
+
|--------|------|-------------|
|
|
47
|
+
| `onmessage` | `((ev: MessageEvent) => void) \| null` | Message event handler |
|
|
48
|
+
| `postMessage` | `(message: unknown, transfer?: unknown[]) => void` | Posts a message to the worker |
|
|
49
|
+
| `terminate` | `() => void` | Terminates the worker |
|
|
50
|
+
|
|
51
|
+
## `isWorkerSupported`
|
|
52
|
+
|
|
53
|
+
Checks whether Web Worker API is available in the current environment.
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
export function isWorkerSupported(): boolean;
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**Returns:** `boolean` -- `true` if `Worker` exists in `globalThis`.
|
|
60
|
+
|
|
61
|
+
## `createBrowserWorker`
|
|
62
|
+
|
|
63
|
+
Creates a Web Worker instance. Returns `undefined` if the environment does not support workers.
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
export function createBrowserWorker(
|
|
67
|
+
url: URL,
|
|
68
|
+
options: { type: string },
|
|
69
|
+
): WorkerLike | undefined;
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
| Parameter | Type | Description |
|
|
73
|
+
|-----------|------|-------------|
|
|
74
|
+
| `url` | `URL` | Worker script URL |
|
|
75
|
+
| `options` | `{ type: string }` | Worker options (e.g., `{ type: "module" }`) |
|
|
76
|
+
|
|
77
|
+
**Returns:** `WorkerLike | undefined`
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Client Protocol Wrapper
|
|
2
|
+
|
|
3
|
+
## `ClientProtocolWrapper`
|
|
4
|
+
|
|
5
|
+
Client-side protocol encoder/decoder wrapper. Automatically offloads heavy encode/decode operations to a Web Worker when available, falling back to main-thread processing for small messages or when workers are unsupported.
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
export interface ClientProtocolWrapper {
|
|
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 into binary chunks. Offloads to worker for large messages |
|
|
18
|
+
| `decode` | `bytes: Bytes` | `Promise<ServiceMessageDecodeResult<ServiceMessage>>` | Decodes received binary data. Uses zero-copy transfer for large payloads |
|
|
19
|
+
| `dispose` | none | `void` | Disposes the underlying protocol and worker resolver resources |
|
|
20
|
+
|
|
21
|
+
## `createClientProtocolWrapper`
|
|
22
|
+
|
|
23
|
+
Creates a `ClientProtocolWrapper` from a `ServiceProtocol` instance.
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
export function createClientProtocolWrapper(
|
|
27
|
+
protocol: ServiceProtocol,
|
|
28
|
+
): ClientProtocolWrapper;
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
| Parameter | Type | Description |
|
|
32
|
+
|-----------|------|-------------|
|
|
33
|
+
| `protocol` | `ServiceProtocol` | The base protocol encoder/decoder (from `@simplysm/service-common`) |
|
|
34
|
+
|
|
35
|
+
Worker offloading threshold: 30KB. Messages below this size are processed on the main thread. The worker is a shared singleton across all `ClientProtocolWrapper` instances. Worker operations that exceed 60 seconds are automatically timed out and rejected.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Connection Options
|
|
2
|
+
|
|
3
|
+
## `ServiceConnectionOptions`
|
|
4
|
+
|
|
5
|
+
Connection options for the service client.
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
export interface ServiceConnectionOptions {
|
|
9
|
+
port: number;
|
|
10
|
+
host: string;
|
|
11
|
+
ssl?: boolean;
|
|
12
|
+
maxReconnectCount?: number;
|
|
13
|
+
}
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
| Field | Type | Description |
|
|
17
|
+
|-------|------|-------------|
|
|
18
|
+
| `port` | `number` | Server port |
|
|
19
|
+
| `host` | `string` | Server hostname |
|
|
20
|
+
| `ssl` | `boolean?` | Enable SSL/TLS (uses `wss://` and `https://` when true) |
|
|
21
|
+
| `maxReconnectCount` | `number?` | Maximum reconnection attempts. Set to `0` to disable reconnection and disconnect immediately |
|
package/docs/features.md
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# Event/File/ORM Client
|
|
2
|
+
|
|
3
|
+
## `EventClient`
|
|
4
|
+
|
|
5
|
+
Event subscription client for the service event system.
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
export interface EventClient {
|
|
9
|
+
addListener<TInfo, TData>(
|
|
10
|
+
eventDef: ServiceEventDef<TInfo, TData>,
|
|
11
|
+
info: TInfo,
|
|
12
|
+
cb: (data: TData) => PromiseLike<void>,
|
|
13
|
+
): Promise<string>;
|
|
14
|
+
removeListener(key: string): Promise<void>;
|
|
15
|
+
emit<TInfo, TData>(
|
|
16
|
+
eventDef: ServiceEventDef<TInfo, TData>,
|
|
17
|
+
infoSelector: (item: TInfo) => boolean,
|
|
18
|
+
data: TData,
|
|
19
|
+
): Promise<void>;
|
|
20
|
+
resubscribeAll(): Promise<void>;
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
| Method | Parameters | Return | Description |
|
|
25
|
+
|--------|-----------|--------|-------------|
|
|
26
|
+
| `addListener` | `eventDef: ServiceEventDef<TInfo, TData>, info: TInfo, cb: (data: TData) => PromiseLike<void>` | `Promise<string>` | Subscribes to an event. Returns a listener key (UUID) for later removal |
|
|
27
|
+
| `removeListener` | `key: string` | `Promise<void>` | Unsubscribes by listener key |
|
|
28
|
+
| `emit` | `eventDef: ServiceEventDef<TInfo, TData>, infoSelector: (item: TInfo) => boolean, data: TData` | `Promise<void>` | Queries matching listeners from the server, then emits the event to them |
|
|
29
|
+
| `resubscribeAll` | none | `Promise<void>` | Re-registers all local listeners on the server (used after reconnection) |
|
|
30
|
+
|
|
31
|
+
## `createEventClient`
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
export function createEventClient(transport: ServiceTransport): EventClient;
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
| Parameter | Type | Description |
|
|
38
|
+
|-----------|------|-------------|
|
|
39
|
+
| `transport` | `ServiceTransport` | The service transport for sending event messages |
|
|
40
|
+
|
|
41
|
+
## `FileClient`
|
|
42
|
+
|
|
43
|
+
File upload and download client using HTTP `fetch`.
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
export interface FileClient {
|
|
47
|
+
download(relPath: string): Promise<Bytes>;
|
|
48
|
+
upload(
|
|
49
|
+
files: File[] | FileCollection | { name: string; data: BlobInput }[],
|
|
50
|
+
authToken: string,
|
|
51
|
+
): Promise<ServiceUploadResult[]>;
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
| Method | Parameters | Return | Description |
|
|
56
|
+
|--------|-----------|--------|-------------|
|
|
57
|
+
| `download` | `relPath: string` | `Promise<Bytes>` | Downloads a file by relative path as `Uint8Array` |
|
|
58
|
+
| `upload` | `files: File[] \| FileCollection \| { name: string; data: BlobInput }[], authToken: string` | `Promise<ServiceUploadResult[]>` | Uploads files via multipart form data with Bearer token authentication |
|
|
59
|
+
|
|
60
|
+
## `createFileClient`
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
export function createFileClient(hostUrl: string, clientName: string): FileClient;
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
| Parameter | Type | Description |
|
|
67
|
+
|-----------|------|-------------|
|
|
68
|
+
| `hostUrl` | `string` | Full host URL (e.g., `http://localhost:3000`) |
|
|
69
|
+
| `clientName` | `string` | Client identifier sent in `x-sd-client-name` header |
|
|
70
|
+
|
|
71
|
+
## `OrmConnectOptions`
|
|
72
|
+
|
|
73
|
+
ORM connection options for client-side database context usage.
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
export interface OrmConnectOptions<TDef extends DbContextDef<any, any, any>> {
|
|
77
|
+
dbContextDef: TDef;
|
|
78
|
+
connOpt: DbConnOptions & { configName: string };
|
|
79
|
+
dbContextOpt?: {
|
|
80
|
+
database: string;
|
|
81
|
+
schema: string;
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
| Field | Type | Description |
|
|
87
|
+
|-------|------|-------------|
|
|
88
|
+
| `dbContextDef` | `TDef` | Database context definition |
|
|
89
|
+
| `connOpt` | `DbConnOptions & { configName: string }` | Connection options with required config name |
|
|
90
|
+
| `dbContextOpt` | `{ database: string; schema: string }?` | Optional database/schema override |
|
|
91
|
+
|
|
92
|
+
## `OrmClientConnector`
|
|
93
|
+
|
|
94
|
+
ORM client connector that opens a database context over the service RPC layer.
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
export interface OrmClientConnector {
|
|
98
|
+
connect<TDef extends DbContextDef<any, any, any>, R>(
|
|
99
|
+
config: OrmConnectOptions<TDef>,
|
|
100
|
+
callback: (db: DbContextInstance<TDef>) => Promise<R> | R,
|
|
101
|
+
): Promise<R>;
|
|
102
|
+
connectWithoutTransaction<TDef extends DbContextDef<any, any, any>, R>(
|
|
103
|
+
config: OrmConnectOptions<TDef>,
|
|
104
|
+
callback: (db: DbContextInstance<TDef>) => Promise<R> | R,
|
|
105
|
+
): Promise<R>;
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
| Method | Parameters | Return | Description |
|
|
110
|
+
|--------|-----------|--------|-------------|
|
|
111
|
+
| `connect` | `config: OrmConnectOptions<TDef>, callback: (db: DbContextInstance<TDef>) => Promise<R> \| R` | `Promise<R>` | Opens a DB context with automatic transaction (begin/commit/rollback). Wraps foreign key constraint errors with a user-friendly message |
|
|
112
|
+
| `connectWithoutTransaction` | `config: OrmConnectOptions<TDef>, callback: (db: DbContextInstance<TDef>) => Promise<R> \| R` | `Promise<R>` | Opens a DB context without automatic transaction management |
|
|
113
|
+
|
|
114
|
+
## `createOrmClientConnector`
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
export function createOrmClientConnector(serviceClient: ServiceClient): OrmClientConnector;
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
| Parameter | Type | Description |
|
|
121
|
+
|-----------|------|-------------|
|
|
122
|
+
| `serviceClient` | `ServiceClient` | The service client instance for RPC communication |
|
|
123
|
+
|
|
124
|
+
## `OrmClientDbContextExecutor`
|
|
125
|
+
|
|
126
|
+
Implements `DbContextExecutor` (from `@simplysm/orm-common`) for client-side ORM usage over the service RPC layer. Proxies all database operations through the remote `OrmService`.
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
export class OrmClientDbContextExecutor implements DbContextExecutor {
|
|
130
|
+
constructor(
|
|
131
|
+
client: ServiceClient,
|
|
132
|
+
opt: DbConnOptions & { configName: string },
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
| Method | Parameters | Return | Description |
|
|
138
|
+
|--------|-----------|--------|-------------|
|
|
139
|
+
| `getInfo` | none | `Promise<{ dialect: Dialect; database?: string; schema?: string }>` | Gets database info via remote ORM service |
|
|
140
|
+
| `connect` | none | `Promise<void>` | Opens a remote connection |
|
|
141
|
+
| `beginTransaction` | `isolationLevel?: IsolationLevel` | `Promise<void>` | Begins a remote transaction |
|
|
142
|
+
| `commitTransaction` | none | `Promise<void>` | Commits the remote transaction |
|
|
143
|
+
| `rollbackTransaction` | none | `Promise<void>` | Rolls back the remote transaction |
|
|
144
|
+
| `close` | none | `Promise<void>` | Closes the remote connection |
|
|
145
|
+
| `executeDefs` | `defs: QueryDef[], options?: (ResultMeta \| undefined)[]` | `Promise<T[][]>` | Executes query definitions via remote ORM service |
|
|
146
|
+
| `executeParametrized` | `query: string, params?: unknown[]` | `Promise<unknown[][]>` | Executes a parameterized query via remote ORM service |
|
|
147
|
+
| `bulkInsert` | `tableName: string, columnDefs: Record<string, ColumnMeta>, records: Record<string, unknown>[]` | `Promise<void>` | Performs bulk insert via remote ORM service |
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Progress Types
|
|
2
|
+
|
|
3
|
+
## `ServiceProgress`
|
|
4
|
+
|
|
5
|
+
Callback hooks for monitoring message progress at different stages.
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
export interface ServiceProgress {
|
|
9
|
+
request?: (s: ServiceProgressState) => void;
|
|
10
|
+
response?: (s: ServiceProgressState) => void;
|
|
11
|
+
server?: (s: ServiceProgressState) => void;
|
|
12
|
+
}
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
| Field | Type | Description |
|
|
16
|
+
|-------|------|-------------|
|
|
17
|
+
| `request` | `(s: ServiceProgressState) => void` | Called during request encoding/sending progress |
|
|
18
|
+
| `response` | `(s: ServiceProgressState) => void` | Called during response decoding progress |
|
|
19
|
+
| `server` | `(s: ServiceProgressState) => void` | Called when server reports chunk receive progress |
|
|
20
|
+
|
|
21
|
+
## `ServiceProgressState`
|
|
22
|
+
|
|
23
|
+
Progress state for a single message transfer.
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
export interface ServiceProgressState {
|
|
27
|
+
uuid: string;
|
|
28
|
+
totalSize: number;
|
|
29
|
+
completedSize: number;
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
| Field | Type | Description |
|
|
34
|
+
|-------|------|-------------|
|
|
35
|
+
| `uuid` | `string` | Message UUID |
|
|
36
|
+
| `totalSize` | `number` | Total message size in bytes |
|
|
37
|
+
| `completedSize` | `number` | Bytes transferred so far |
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# Main ServiceClient
|
|
2
|
+
|
|
3
|
+
## `ServiceClient`
|
|
4
|
+
|
|
5
|
+
Main service client class. Extends `EventEmitter` with progress and state events. Composes `SocketProvider`, `ServiceTransport`, `EventClient`, `FileClient`, and `ClientProtocolWrapper` internally.
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
export class ServiceClient extends EventEmitter<{
|
|
9
|
+
"request-progress": ServiceProgressState;
|
|
10
|
+
"response-progress": ServiceProgressState;
|
|
11
|
+
"server-progress": ServiceProgressState;
|
|
12
|
+
"state": "connected" | "closed" | "reconnecting";
|
|
13
|
+
}> {
|
|
14
|
+
constructor(name: string, options: ServiceConnectionOptions);
|
|
15
|
+
}
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### Events
|
|
19
|
+
|
|
20
|
+
| Event | Data Type | Description |
|
|
21
|
+
|-------|-----------|-------------|
|
|
22
|
+
| `request-progress` | `ServiceProgressState` | Request sending progress (chunked messages) |
|
|
23
|
+
| `response-progress` | `ServiceProgressState` | Response receiving progress (chunked messages) |
|
|
24
|
+
| `server-progress` | `ServiceProgressState` | Server-side chunk reception progress |
|
|
25
|
+
| `state` | `"connected" \| "closed" \| "reconnecting"` | Connection state change |
|
|
26
|
+
|
|
27
|
+
### Properties
|
|
28
|
+
|
|
29
|
+
| Property | Type | Description |
|
|
30
|
+
|----------|------|-------------|
|
|
31
|
+
| `name` | `string` (readonly) | Client name |
|
|
32
|
+
| `options` | `ServiceConnectionOptions` (readonly) | Connection options |
|
|
33
|
+
| `connected` | `boolean` (readonly, getter) | Whether the client is currently connected |
|
|
34
|
+
| `hostUrl` | `string` (readonly, getter) | Full host URL computed from options (e.g., `https://host:port`) |
|
|
35
|
+
|
|
36
|
+
### Methods
|
|
37
|
+
|
|
38
|
+
| Method | Signature | Description |
|
|
39
|
+
|--------|-----------|-------------|
|
|
40
|
+
| `getService` | `getService<TService>(serviceName: string): ServiceProxy<TService>` | Returns a type-safe proxy that maps method calls to RPC requests |
|
|
41
|
+
| `connect` | `connect(): Promise<void>` | Opens the WebSocket connection |
|
|
42
|
+
| `close` | `close(): Promise<void>` | Closes the connection and disposes protocol resources |
|
|
43
|
+
| `send` | `send(serviceName: string, methodName: string, params: unknown[], progress?: ServiceProgress): Promise<unknown>` | Sends an RPC call directly |
|
|
44
|
+
| `auth` | `auth(token: string): Promise<void>` | Authenticates with a JWT token. Token is cached for reconnection |
|
|
45
|
+
| `addListener` | `addListener<TInfo, TData>(eventDef: ServiceEventDef<TInfo, TData>, info: TInfo, cb: (data: TData) => PromiseLike<void>): Promise<string>` | Subscribes to an event. Returns listener key. Throws if not connected |
|
|
46
|
+
| `removeListener` | `removeListener(key: string): Promise<void>` | Unsubscribes from an event by key |
|
|
47
|
+
| `emitEvent` | `emitEvent<TInfo, TData>(eventDef: ServiceEventDef<TInfo, TData>, infoSelector: (item: TInfo) => boolean, data: TData): Promise<void>` | Emits an event to matching listeners |
|
|
48
|
+
| `uploadFile` | `uploadFile(files: File[] \| FileCollection \| { name: string; data: BlobInput }[]): Promise<ServiceUploadResult[]>` | Uploads files. Requires prior `auth()` call |
|
|
49
|
+
| `downloadFileBuffer` | `downloadFileBuffer(relPath: string): Promise<Bytes>` | Downloads a file as `Uint8Array` |
|
|
50
|
+
|
|
51
|
+
### Reconnection Behavior
|
|
52
|
+
|
|
53
|
+
On reconnection (`state === "connected"` after a disconnect):
|
|
54
|
+
1. Re-authenticates with the cached token (if `auth()` was previously called)
|
|
55
|
+
2. Re-subscribes all event listeners via `EventClient.resubscribeAll()`
|
|
56
|
+
|
|
57
|
+
## `ServiceProxy`
|
|
58
|
+
|
|
59
|
+
Type utility that wraps all methods of a service interface to return `Promise<Awaited<R>>`.
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
export type ServiceProxy<TService> = {
|
|
63
|
+
[K in keyof TService]: TService[K] extends (...args: infer P) => infer R
|
|
64
|
+
? (...args: P) => Promise<Awaited<R>>
|
|
65
|
+
: never;
|
|
66
|
+
};
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Non-function properties are mapped to `never`.
|
|
70
|
+
|
|
71
|
+
## `createServiceClient`
|
|
72
|
+
|
|
73
|
+
Factory function to create a `ServiceClient` instance.
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
export function createServiceClient(
|
|
77
|
+
name: string,
|
|
78
|
+
options: ServiceConnectionOptions,
|
|
79
|
+
): ServiceClient;
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
| Parameter | Type | Description |
|
|
83
|
+
|-----------|------|-------------|
|
|
84
|
+
| `name` | `string` | Client identifier name |
|
|
85
|
+
| `options` | `ServiceConnectionOptions` | Connection options (host, port, SSL, maxReconnectCount) |
|
|
86
|
+
|
|
87
|
+
**Returns:** `ServiceClient`
|
|
88
|
+
|
|
89
|
+
Default `maxReconnectCount` is `10` if not specified in options.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Service Transport
|
|
2
|
+
|
|
3
|
+
## `ServiceTransportEvents`
|
|
4
|
+
|
|
5
|
+
Event map for the service transport.
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
export interface ServiceTransportEvents {
|
|
9
|
+
event: { keys: string[]; data: unknown };
|
|
10
|
+
}
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
| Event | Data Type | Description |
|
|
14
|
+
|-------|-----------|-------------|
|
|
15
|
+
| `event` | `{ keys: string[]; data: unknown }` | Server-side event broadcast received |
|
|
16
|
+
|
|
17
|
+
## `ServiceTransport`
|
|
18
|
+
|
|
19
|
+
Service-level message transport built on top of `SocketProvider` and `ClientProtocolWrapper`. Manages pending request/response correlation via UUIDs, handles progress notifications, and dispatches events.
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
export interface ServiceTransport {
|
|
23
|
+
on<K extends keyof ServiceTransportEvents & string>(
|
|
24
|
+
type: K,
|
|
25
|
+
listener: (data: ServiceTransportEvents[K]) => void,
|
|
26
|
+
): void;
|
|
27
|
+
off<K extends keyof ServiceTransportEvents & string>(
|
|
28
|
+
type: K,
|
|
29
|
+
listener: (data: ServiceTransportEvents[K]) => void,
|
|
30
|
+
): void;
|
|
31
|
+
send(message: ServiceClientMessage, progress?: ServiceProgress): Promise<unknown>;
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
| Method | Parameters | Return | Description |
|
|
36
|
+
|--------|-----------|--------|-------------|
|
|
37
|
+
| `on` | `type: K, listener` | `void` | Subscribe to transport events |
|
|
38
|
+
| `off` | `type: K, listener` | `void` | Unsubscribe from transport events |
|
|
39
|
+
| `send` | `message: ServiceClientMessage, progress?: ServiceProgress` | `Promise<unknown>` | Sends a service message and awaits the server response. Returns the response body |
|
|
40
|
+
|
|
41
|
+
## `createServiceTransport`
|
|
42
|
+
|
|
43
|
+
Creates a `ServiceTransport` instance.
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
export function createServiceTransport(
|
|
47
|
+
socket: SocketProvider,
|
|
48
|
+
protocol: ClientProtocolWrapper,
|
|
49
|
+
): ServiceTransport;
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
| Parameter | Type | Description |
|
|
53
|
+
|-----------|------|-------------|
|
|
54
|
+
| `socket` | `SocketProvider` | The socket provider for sending/receiving binary data |
|
|
55
|
+
| `protocol` | `ClientProtocolWrapper` | The protocol wrapper for encoding/decoding messages |
|
|
56
|
+
|
|
57
|
+
Behavior:
|
|
58
|
+
- Generates a UUID per `send()` call and registers a pending resolver
|
|
59
|
+
- On socket disconnect (`closed`/`reconnecting`), rejects all pending requests
|
|
60
|
+
- Routes server messages: `response` resolves, `error` rejects, `evt:on` emits event, `progress` invokes progress callbacks
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Socket Provider
|
|
2
|
+
|
|
3
|
+
## `SocketProviderEvents`
|
|
4
|
+
|
|
5
|
+
Event map for the socket provider.
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
export interface SocketProviderEvents {
|
|
9
|
+
message: Bytes;
|
|
10
|
+
state: "connected" | "closed" | "reconnecting";
|
|
11
|
+
}
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
| Event | Data Type | Description |
|
|
15
|
+
|-------|-----------|-------------|
|
|
16
|
+
| `message` | `Bytes` | Raw binary message received from server |
|
|
17
|
+
| `state` | `"connected" \| "closed" \| "reconnecting"` | Connection state change |
|
|
18
|
+
|
|
19
|
+
## `SocketProvider`
|
|
20
|
+
|
|
21
|
+
Low-level WebSocket abstraction with automatic reconnection and heartbeat keepalive. Works in both browser and Node.js environments (uses `ws` package as polyfill in Node.js).
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
export interface SocketProvider {
|
|
25
|
+
readonly clientName: string;
|
|
26
|
+
readonly connected: boolean;
|
|
27
|
+
on<K extends keyof SocketProviderEvents & string>(
|
|
28
|
+
type: K,
|
|
29
|
+
listener: (data: SocketProviderEvents[K]) => void,
|
|
30
|
+
): void;
|
|
31
|
+
off<K extends keyof SocketProviderEvents & string>(
|
|
32
|
+
type: K,
|
|
33
|
+
listener: (data: SocketProviderEvents[K]) => void,
|
|
34
|
+
): void;
|
|
35
|
+
connect(): Promise<void>;
|
|
36
|
+
close(): Promise<void>;
|
|
37
|
+
send(data: Bytes): Promise<void>;
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
| Member | Kind | Description |
|
|
42
|
+
|--------|------|-------------|
|
|
43
|
+
| `clientName` | property (readonly) | Client identifier name |
|
|
44
|
+
| `connected` | property (readonly) | Whether currently connected |
|
|
45
|
+
| `on` | method | Subscribe to an event |
|
|
46
|
+
| `off` | method | Unsubscribe from an event |
|
|
47
|
+
| `connect` | method | Opens the WebSocket connection. Throws on initial connection failure |
|
|
48
|
+
| `close` | method | Closes the connection gracefully |
|
|
49
|
+
| `send` | method | Sends binary data. Waits for connection if not yet open |
|
|
50
|
+
|
|
51
|
+
## `createSocketProvider`
|
|
52
|
+
|
|
53
|
+
Creates a `SocketProvider` instance with auto-reconnect and heartbeat.
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
export function createSocketProvider(
|
|
57
|
+
url: string,
|
|
58
|
+
clientName: string,
|
|
59
|
+
maxReconnectCount: number,
|
|
60
|
+
): SocketProvider;
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
| Parameter | Type | Description |
|
|
64
|
+
|-----------|------|-------------|
|
|
65
|
+
| `url` | `string` | WebSocket URL (e.g., `ws://localhost:3000/ws`) |
|
|
66
|
+
| `clientName` | `string` | Client identifier |
|
|
67
|
+
| `maxReconnectCount` | `number` | Maximum reconnection attempts |
|
|
68
|
+
|
|
69
|
+
Internal constants:
|
|
70
|
+
- Heartbeat timeout: 30 seconds
|
|
71
|
+
- Heartbeat interval: 5 seconds (sends ping `0x01`, expects pong `0x02`)
|
|
72
|
+
- Reconnect delay: 3 seconds between attempts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@simplysm/service-client",
|
|
3
|
-
"version": "14.0.
|
|
3
|
+
"version": "14.0.5",
|
|
4
4
|
"description": "심플리즘 패키지 - 서비스 (client)",
|
|
5
5
|
"author": "심플리즘",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -14,14 +14,15 @@
|
|
|
14
14
|
"types": "./dist/index.d.ts",
|
|
15
15
|
"files": [
|
|
16
16
|
"dist",
|
|
17
|
-
"src"
|
|
17
|
+
"src",
|
|
18
|
+
"docs"
|
|
18
19
|
],
|
|
19
20
|
"sideEffects": false,
|
|
20
21
|
"dependencies": {
|
|
21
22
|
"consola": "^3.4.2",
|
|
22
|
-
"@simplysm/core-common": "14.0.
|
|
23
|
-
"@simplysm/orm-common": "14.0.
|
|
24
|
-
"@simplysm/service-common": "14.0.
|
|
23
|
+
"@simplysm/core-common": "14.0.5",
|
|
24
|
+
"@simplysm/orm-common": "14.0.5",
|
|
25
|
+
"@simplysm/service-common": "14.0.5"
|
|
25
26
|
},
|
|
26
27
|
"devDependencies": {
|
|
27
28
|
"@types/ws": "^8.18.1",
|