@simplysm/service-client 13.0.98 → 13.0.99
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 +99 -55
- package/docs/features.md +60 -59
- package/docs/protocol.md +11 -21
- package/docs/service-client.md +64 -181
- package/docs/transport.md +52 -58
- package/docs/types.md +24 -7
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# @simplysm/service-client
|
|
2
2
|
|
|
3
|
-
Service module (client)
|
|
3
|
+
Simplysm package - Service module (client)
|
|
4
|
+
|
|
5
|
+
WebSocket-based service client for communicating with `@simplysm/service-server`. Provides type-safe service method calls, event pub/sub, file upload/download, and client-side ORM connectivity.
|
|
4
6
|
|
|
5
7
|
## Installation
|
|
6
8
|
|
|
@@ -8,41 +10,64 @@ Service module (client) -- WebSocket-based service client for communicating with
|
|
|
8
10
|
npm install @simplysm/service-client
|
|
9
11
|
```
|
|
10
12
|
|
|
11
|
-
##
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
13
|
+
## API Overview
|
|
14
|
+
|
|
15
|
+
### Types
|
|
16
|
+
| API | Type | Description |
|
|
17
|
+
|-----|------|-------------|
|
|
18
|
+
| `ServiceConnectionOptions` | interface | Connection options (host, port, ssl, reconnect) |
|
|
19
|
+
| `ServiceProgress` | interface | Progress callback config for requests |
|
|
20
|
+
| `ServiceProgressState` | interface | Progress state (uuid, totalSize, completedSize) |
|
|
21
|
+
|
|
22
|
+
-> See [docs/types.md](./docs/types.md) for details.
|
|
23
|
+
|
|
24
|
+
### Transport
|
|
25
|
+
| API | Type | Description |
|
|
26
|
+
|-----|------|-------------|
|
|
27
|
+
| `SocketProvider` | interface | WebSocket connection provider |
|
|
28
|
+
| `SocketProviderEvents` | interface | Socket events (message, state) |
|
|
29
|
+
| `createSocketProvider` | function | Create socket with heartbeat and auto-reconnect |
|
|
30
|
+
| `ServiceTransport` | interface | Message routing and request/response correlation |
|
|
31
|
+
| `ServiceTransportEvents` | interface | Transport events (reload, event) |
|
|
32
|
+
| `createServiceTransport` | function | Create transport instance |
|
|
33
|
+
|
|
34
|
+
-> See [docs/transport.md](./docs/transport.md) for details.
|
|
35
|
+
|
|
36
|
+
### Protocol
|
|
37
|
+
| API | Type | Description |
|
|
38
|
+
|-----|------|-------------|
|
|
39
|
+
| `ClientProtocolWrapper` | interface | Protocol wrapper with Web Worker offloading |
|
|
40
|
+
| `createClientProtocolWrapper` | function | Create protocol wrapper |
|
|
41
|
+
|
|
42
|
+
-> See [docs/protocol.md](./docs/protocol.md) for details.
|
|
43
|
+
|
|
44
|
+
### Features (Event, File, ORM)
|
|
45
|
+
| API | Type | Description |
|
|
46
|
+
|-----|------|-------------|
|
|
47
|
+
| `EventClient` | interface | Event listener management |
|
|
48
|
+
| `createEventClient` | function | Create event client |
|
|
49
|
+
| `FileClient` | interface | File upload/download |
|
|
50
|
+
| `createFileClient` | function | Create file client |
|
|
51
|
+
| `OrmConnectOptions` | interface | ORM connection options |
|
|
52
|
+
| `OrmClientConnector` | interface | Client-side ORM connector |
|
|
53
|
+
| `createOrmClientConnector` | function | Create ORM connector |
|
|
54
|
+
| `OrmClientDbContextExecutor` | class | DbContext executor via service protocol |
|
|
55
|
+
|
|
56
|
+
-> See [docs/features.md](./docs/features.md) for details.
|
|
57
|
+
|
|
58
|
+
### Main
|
|
59
|
+
| API | Type | Description |
|
|
60
|
+
|-----|------|-------------|
|
|
61
|
+
| `ServiceClient` | class | Main client (connect, auth, service calls, events, files) |
|
|
62
|
+
| `ServiceClientEvents` | interface | Client events (progress, state, reload) |
|
|
63
|
+
| `ServiceProxy` | type | Type wrapper for remote service methods |
|
|
64
|
+
| `createServiceClient` | function | Factory to create ServiceClient |
|
|
65
|
+
|
|
66
|
+
-> See [docs/service-client.md](./docs/service-client.md) for details.
|
|
67
|
+
|
|
68
|
+
## Usage Examples
|
|
69
|
+
|
|
70
|
+
### Connect and Call Service Methods
|
|
46
71
|
|
|
47
72
|
```typescript
|
|
48
73
|
import { createServiceClient } from "@simplysm/service-client";
|
|
@@ -53,30 +78,49 @@ const client = createServiceClient("my-app", {
|
|
|
53
78
|
});
|
|
54
79
|
|
|
55
80
|
await client.connect();
|
|
81
|
+
await client.auth(jwtToken);
|
|
56
82
|
|
|
57
|
-
//
|
|
58
|
-
|
|
83
|
+
// Type-safe service proxy
|
|
84
|
+
interface UserService {
|
|
85
|
+
getProfile(): Promise<{ name: string; email: string }>;
|
|
86
|
+
updateName(name: string): Promise<void>;
|
|
87
|
+
}
|
|
59
88
|
|
|
60
|
-
|
|
61
|
-
const
|
|
62
|
-
|
|
89
|
+
const userService = client.getService<UserService>("User");
|
|
90
|
+
const profile = await userService.getProfile();
|
|
91
|
+
await userService.updateName("New Name");
|
|
92
|
+
```
|
|
63
93
|
|
|
64
|
-
|
|
65
|
-
await client.addListener(SomeEvent, { id: 1 }, async (data) => {
|
|
66
|
-
// handle event
|
|
67
|
-
});
|
|
94
|
+
### Client-Side ORM
|
|
68
95
|
|
|
69
|
-
|
|
70
|
-
|
|
96
|
+
```typescript
|
|
97
|
+
import { createOrmClientConnector } from "@simplysm/service-client";
|
|
98
|
+
|
|
99
|
+
const orm = createOrmClientConnector(client);
|
|
71
100
|
|
|
72
|
-
|
|
73
|
-
|
|
101
|
+
const users = await orm.connect(
|
|
102
|
+
{ dbContextDef: MyDb, connOpt: { configName: "main" } },
|
|
103
|
+
async (db) => {
|
|
104
|
+
return db.user().where((u) => [expr.eq(u.status, "active")]).execute();
|
|
105
|
+
},
|
|
106
|
+
);
|
|
74
107
|
```
|
|
75
108
|
|
|
76
|
-
|
|
109
|
+
### Event Subscription
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
import { defineEvent } from "@simplysm/service-common";
|
|
77
113
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
114
|
+
const OrderUpdated = defineEvent<{ orderId: number }, { status: string }>("OrderUpdated");
|
|
115
|
+
|
|
116
|
+
const key = await client.addListener(
|
|
117
|
+
OrderUpdated,
|
|
118
|
+
{ orderId: 123 },
|
|
119
|
+
async (data) => {
|
|
120
|
+
console.log("Order status:", data.status);
|
|
121
|
+
},
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
// Later: unsubscribe
|
|
125
|
+
await client.removeListener(key);
|
|
126
|
+
```
|
package/docs/features.md
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
# Features
|
|
2
2
|
|
|
3
|
-
## EventClient
|
|
3
|
+
## `EventClient`
|
|
4
4
|
|
|
5
|
-
Client-side event
|
|
6
|
-
|
|
7
|
-
### `EventClient`
|
|
5
|
+
Client-side event management interface. Handles event listener registration, removal, emission, and auto-recovery on reconnect.
|
|
8
6
|
|
|
9
7
|
```typescript
|
|
10
8
|
interface EventClient {
|
|
@@ -13,38 +11,34 @@ interface EventClient {
|
|
|
13
11
|
info: TInfo,
|
|
14
12
|
cb: (data: TData) => PromiseLike<void>,
|
|
15
13
|
): Promise<string>;
|
|
16
|
-
|
|
17
14
|
removeListener(key: string): Promise<void>;
|
|
18
|
-
|
|
19
15
|
emit<TInfo, TData>(
|
|
20
16
|
eventDef: ServiceEventDef<TInfo, TData>,
|
|
21
17
|
infoSelector: (item: TInfo) => boolean,
|
|
22
18
|
data: TData,
|
|
23
19
|
): Promise<void>;
|
|
24
|
-
|
|
25
20
|
resubscribeAll(): Promise<void>;
|
|
26
21
|
}
|
|
27
22
|
```
|
|
28
23
|
|
|
29
|
-
|
|
24
|
+
| Method | Description |
|
|
25
|
+
|--------|-------------|
|
|
26
|
+
| `addListener()` | Register an event listener on the server, returns listener key |
|
|
27
|
+
| `removeListener()` | Remove an event listener by key |
|
|
28
|
+
| `emit()` | Emit an event to matching listeners (server-side filtering) |
|
|
29
|
+
| `resubscribeAll()` | Re-register all listeners on reconnect |
|
|
30
|
+
|
|
31
|
+
## `createEventClient`
|
|
32
|
+
|
|
33
|
+
Create an event client instance.
|
|
30
34
|
|
|
31
35
|
```typescript
|
|
32
36
|
function createEventClient(transport: ServiceTransport): EventClient;
|
|
33
37
|
```
|
|
34
38
|
|
|
35
|
-
|
|
36
|
-
- `addListener` registers on the server and stores locally for reconnect recovery
|
|
37
|
-
- `removeListener` removes from local map and sends removal request to server
|
|
38
|
-
- `emit` queries the server for matching listener infos, then sends event to matching keys
|
|
39
|
-
- `resubscribeAll` re-registers all local listeners on the server (called on reconnect)
|
|
40
|
-
|
|
41
|
-
---
|
|
42
|
-
|
|
43
|
-
## FileClient
|
|
39
|
+
## `FileClient`
|
|
44
40
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
### `FileClient`
|
|
41
|
+
File upload/download client interface.
|
|
48
42
|
|
|
49
43
|
```typescript
|
|
50
44
|
interface FileClient {
|
|
@@ -56,23 +50,27 @@ interface FileClient {
|
|
|
56
50
|
}
|
|
57
51
|
```
|
|
58
52
|
|
|
59
|
-
|
|
53
|
+
| Method | Description |
|
|
54
|
+
|--------|-------------|
|
|
55
|
+
| `download()` | Download a file by relative path, returns binary data |
|
|
56
|
+
| `upload()` | Upload files via multipart form, returns upload results |
|
|
57
|
+
|
|
58
|
+
## `createFileClient`
|
|
59
|
+
|
|
60
|
+
Create a file client instance.
|
|
60
61
|
|
|
61
62
|
```typescript
|
|
62
63
|
function createFileClient(hostUrl: string, clientName: string): FileClient;
|
|
63
64
|
```
|
|
64
65
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
---
|
|
70
|
-
|
|
71
|
-
## ORM Features
|
|
66
|
+
| Parameter | Type | Description |
|
|
67
|
+
|-----------|------|-------------|
|
|
68
|
+
| `hostUrl` | `string` | Server base URL (http:// or https://) |
|
|
69
|
+
| `clientName` | `string` | Client name for request headers |
|
|
72
70
|
|
|
73
|
-
|
|
71
|
+
## `OrmConnectOptions`
|
|
74
72
|
|
|
75
|
-
|
|
73
|
+
ORM connection options for client-side database access.
|
|
76
74
|
|
|
77
75
|
```typescript
|
|
78
76
|
interface OrmConnectOptions<TDef extends DbContextDef<any, any, any>> {
|
|
@@ -85,9 +83,15 @@ interface OrmConnectOptions<TDef extends DbContextDef<any, any, any>> {
|
|
|
85
83
|
}
|
|
86
84
|
```
|
|
87
85
|
|
|
88
|
-
|
|
86
|
+
| Field | Type | Description |
|
|
87
|
+
|-------|------|-------------|
|
|
88
|
+
| `dbContextDef` | `TDef` | DbContext definition |
|
|
89
|
+
| `connOpt` | `DbConnOptions & { configName: string }` | Connection options with config name |
|
|
90
|
+
| `dbContextOpt` | `{ database: string; schema: string }` | Override database/schema from server config |
|
|
89
91
|
|
|
90
|
-
|
|
92
|
+
## `OrmClientConnector`
|
|
93
|
+
|
|
94
|
+
Client-side ORM connector interface. Creates DbContext instances that execute queries via the service protocol.
|
|
91
95
|
|
|
92
96
|
```typescript
|
|
93
97
|
interface OrmClientConnector {
|
|
@@ -95,7 +99,6 @@ interface OrmClientConnector {
|
|
|
95
99
|
config: OrmConnectOptions<TDef>,
|
|
96
100
|
callback: (db: DbContextInstance<TDef>) => Promise<R> | R,
|
|
97
101
|
): Promise<R>;
|
|
98
|
-
|
|
99
102
|
connectWithoutTransaction<TDef extends DbContextDef<any, any, any>, R>(
|
|
100
103
|
config: OrmConnectOptions<TDef>,
|
|
101
104
|
callback: (db: DbContextInstance<TDef>) => Promise<R> | R,
|
|
@@ -103,40 +106,38 @@ interface OrmClientConnector {
|
|
|
103
106
|
}
|
|
104
107
|
```
|
|
105
108
|
|
|
106
|
-
|
|
109
|
+
| Method | Description |
|
|
110
|
+
|--------|-------------|
|
|
111
|
+
| `connect()` | Connect with transaction (auto commit/rollback) |
|
|
112
|
+
| `connectWithoutTransaction()` | Connect without transaction |
|
|
113
|
+
|
|
114
|
+
## `createOrmClientConnector`
|
|
115
|
+
|
|
116
|
+
Create an ORM client connector.
|
|
107
117
|
|
|
108
118
|
```typescript
|
|
109
119
|
function createOrmClientConnector(serviceClient: ServiceClient): OrmClientConnector;
|
|
110
120
|
```
|
|
111
121
|
|
|
112
|
-
|
|
113
|
-
- `connect` creates a database context and executes the callback within a transaction
|
|
114
|
-
- `connectWithoutTransaction` creates a database context without transaction wrapping
|
|
115
|
-
- Foreign key constraint violations are caught and re-thrown with a user-friendly message
|
|
122
|
+
## `OrmClientDbContextExecutor`
|
|
116
123
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
Implements `DbContextExecutor` by delegating all database operations to the remote `OrmService` via WebSocket.
|
|
124
|
+
Client-side DbContext executor. Implements `DbContextExecutor` by delegating to the ORM service over the service protocol.
|
|
120
125
|
|
|
121
126
|
```typescript
|
|
122
127
|
class OrmClientDbContextExecutor implements DbContextExecutor {
|
|
123
|
-
constructor(
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
): Promise<T[][]>;
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
tableName: string,
|
|
138
|
-
columnDefs: Record<string, ColumnMeta>,
|
|
139
|
-
records: Record<string, unknown>[],
|
|
140
|
-
): Promise<void>;
|
|
128
|
+
constructor(
|
|
129
|
+
private readonly _client: ServiceClient,
|
|
130
|
+
private readonly _opt: DbConnOptions & { configName: string },
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
getInfo(): Promise<{ dialect: Dialect; database?: string; schema?: string }>;
|
|
134
|
+
connect(): Promise<void>;
|
|
135
|
+
beginTransaction(isolationLevel?: IsolationLevel): Promise<void>;
|
|
136
|
+
commitTransaction(): Promise<void>;
|
|
137
|
+
rollbackTransaction(): Promise<void>;
|
|
138
|
+
close(): Promise<void>;
|
|
139
|
+
executeDefs<T>(defs: QueryDef[], options?: (ResultMeta | undefined)[]): Promise<T[][]>;
|
|
140
|
+
executeParametrized(query: string, params?: unknown[]): Promise<unknown[][]>;
|
|
141
|
+
bulkInsert(tableName: string, columnDefs: Record<string, ColumnMeta>, records: Record<string, unknown>[]): Promise<void>;
|
|
141
142
|
}
|
|
142
143
|
```
|
package/docs/protocol.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# Protocol
|
|
2
2
|
|
|
3
|
-
Client-side protocol wrapper that handles message encoding/decoding with optional Web Worker offloading for large payloads.
|
|
4
|
-
|
|
5
3
|
## `ClientProtocolWrapper`
|
|
6
4
|
|
|
5
|
+
Client-side protocol wrapper interface. Handles message encoding/decoding with optional Web Worker offloading for large payloads (>30KB).
|
|
6
|
+
|
|
7
7
|
```typescript
|
|
8
8
|
interface ClientProtocolWrapper {
|
|
9
9
|
encode(uuid: string, message: ServiceMessage): Promise<{ chunks: Bytes[]; totalSize: number }>;
|
|
@@ -11,29 +11,19 @@ interface ClientProtocolWrapper {
|
|
|
11
11
|
}
|
|
12
12
|
```
|
|
13
13
|
|
|
14
|
+
| Method | Description |
|
|
15
|
+
|--------|-------------|
|
|
16
|
+
| `encode()` | Encode a message (delegates to Web Worker for large payloads) |
|
|
17
|
+
| `decode()` | Decode a message (delegates to Web Worker for large payloads) |
|
|
18
|
+
|
|
14
19
|
## `createClientProtocolWrapper`
|
|
15
20
|
|
|
16
|
-
Create a client protocol wrapper instance.
|
|
21
|
+
Create a client protocol wrapper instance. Automatically offloads heavy encoding/decoding to a Web Worker when available and payload exceeds 30KB.
|
|
17
22
|
|
|
18
23
|
```typescript
|
|
19
24
|
function createClientProtocolWrapper(protocol: ServiceProtocol): ClientProtocolWrapper;
|
|
20
25
|
```
|
|
21
26
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
**Behavior:**
|
|
26
|
-
- Messages smaller than 30KB are processed on the main thread
|
|
27
|
-
- Larger messages are offloaded to a Web Worker for encoding/decoding
|
|
28
|
-
- Worker is automatically initialized as a lazy singleton
|
|
29
|
-
- Worker tasks that do not complete within 60s are rejected (prevents memory leaks)
|
|
30
|
-
- Falls back to main-thread processing when `Worker` is not available (e.g., SSR)
|
|
31
|
-
|
|
32
|
-
**Worker delegation heuristics for encoding:**
|
|
33
|
-
- `Uint8Array` body: always use worker
|
|
34
|
-
- String body longer than 30KB: use worker
|
|
35
|
-
- Array body with >100 elements or containing `Uint8Array`: use worker
|
|
36
|
-
|
|
37
|
-
**Worker delegation heuristics for decoding:**
|
|
38
|
-
- Byte size > 30KB: use worker
|
|
39
|
-
- After worker decoding, `transfer.decode()` is applied to restore class instances (e.g., `DateTime`)
|
|
27
|
+
| Parameter | Type | Description |
|
|
28
|
+
|-----------|------|-------------|
|
|
29
|
+
| `protocol` | `ServiceProtocol` | Base protocol instance from `createServiceProtocol()` |
|
package/docs/service-client.md
CHANGED
|
@@ -1,28 +1,62 @@
|
|
|
1
1
|
# ServiceClient
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
## `ServiceClient`
|
|
4
|
+
|
|
5
|
+
Main client class that orchestrates all service communication modules. Extends `EventEmitter`.
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
class ServiceClient extends EventEmitter<ServiceClientEvents> {
|
|
9
|
+
readonly name: string;
|
|
10
|
+
readonly options: ServiceConnectionOptions;
|
|
11
|
+
get connected(): boolean;
|
|
12
|
+
get hostUrl(): string;
|
|
13
|
+
|
|
14
|
+
constructor(name: string, options: ServiceConnectionOptions);
|
|
15
|
+
|
|
16
|
+
getService<TService>(serviceName: string): ServiceProxy<TService>;
|
|
17
|
+
connect(): Promise<void>;
|
|
18
|
+
close(): Promise<void>;
|
|
19
|
+
send(serviceName: string, methodName: string, params: unknown[], progress?: ServiceProgress): Promise<unknown>;
|
|
20
|
+
auth(token: string): Promise<void>;
|
|
21
|
+
addListener<TInfo, TData>(
|
|
22
|
+
eventDef: ServiceEventDef<TInfo, TData>,
|
|
23
|
+
info: TInfo,
|
|
24
|
+
cb: (data: TData) => PromiseLike<void>,
|
|
25
|
+
): Promise<string>;
|
|
26
|
+
removeListener(key: string): Promise<void>;
|
|
27
|
+
emitEvent<TInfo, TData>(
|
|
28
|
+
eventDef: ServiceEventDef<TInfo, TData>,
|
|
29
|
+
infoSelector: (item: TInfo) => boolean,
|
|
30
|
+
data: TData,
|
|
31
|
+
): Promise<void>;
|
|
32
|
+
uploadFile(files: File[] | FileList | { name: string; data: BlobPart }[]): Promise<ServiceUploadResult[]>;
|
|
33
|
+
downloadFileBuffer(relPath: string): Promise<Bytes>;
|
|
34
|
+
}
|
|
7
35
|
```
|
|
8
36
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
[K in keyof TService]: TService[K] extends (...args: infer P) => infer R
|
|
16
|
-
? (...args: P) => Promise<Awaited<R>>
|
|
17
|
-
: never;
|
|
18
|
-
};
|
|
19
|
-
```
|
|
37
|
+
| Property | Type | Description |
|
|
38
|
+
|----------|------|-------------|
|
|
39
|
+
| `name` | `string` | Client name |
|
|
40
|
+
| `options` | `ServiceConnectionOptions` | Connection options |
|
|
41
|
+
| `connected` | `boolean` | Whether connected |
|
|
42
|
+
| `hostUrl` | `string` | HTTP(S) base URL |
|
|
20
43
|
|
|
21
|
-
|
|
44
|
+
| Method | Description |
|
|
45
|
+
|--------|-------------|
|
|
46
|
+
| `getService()` | Create a typed service proxy for calling remote methods |
|
|
47
|
+
| `connect()` | Establish WebSocket connection |
|
|
48
|
+
| `close()` | Close connection |
|
|
49
|
+
| `send()` | Send a service method request |
|
|
50
|
+
| `auth()` | Authenticate with JWT token |
|
|
51
|
+
| `addListener()` | Add event listener |
|
|
52
|
+
| `removeListener()` | Remove event listener |
|
|
53
|
+
| `emitEvent()` | Emit event to matching listeners |
|
|
54
|
+
| `uploadFile()` | Upload files (requires prior auth) |
|
|
55
|
+
| `downloadFileBuffer()` | Download file as binary |
|
|
22
56
|
|
|
23
|
-
|
|
57
|
+
## `ServiceClientEvents`
|
|
24
58
|
|
|
25
|
-
|
|
59
|
+
Events emitted by `ServiceClient`.
|
|
26
60
|
|
|
27
61
|
```typescript
|
|
28
62
|
interface ServiceClientEvents {
|
|
@@ -33,178 +67,27 @@ interface ServiceClientEvents {
|
|
|
33
67
|
}
|
|
34
68
|
```
|
|
35
69
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
```typescript
|
|
39
|
-
constructor(name: string, options: ServiceConnectionOptions)
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
- `name` -- Client name (used for identification on the server)
|
|
43
|
-
- `options` -- Connection options
|
|
44
|
-
|
|
45
|
-
### Properties
|
|
46
|
-
|
|
47
|
-
#### `connected`
|
|
48
|
-
|
|
49
|
-
```typescript
|
|
50
|
-
get connected(): boolean;
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
#### `hostUrl`
|
|
54
|
-
|
|
55
|
-
```typescript
|
|
56
|
-
get hostUrl(): string;
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
Returns the HTTP(S) URL of the server (e.g., `"https://localhost:3000"`).
|
|
60
|
-
|
|
61
|
-
### Methods
|
|
62
|
-
|
|
63
|
-
#### `connect`
|
|
64
|
-
|
|
65
|
-
Connect to the server via WebSocket.
|
|
66
|
-
|
|
67
|
-
```typescript
|
|
68
|
-
async connect(): Promise<void>;
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
#### `close`
|
|
72
|
-
|
|
73
|
-
Close the WebSocket connection.
|
|
74
|
-
|
|
75
|
-
```typescript
|
|
76
|
-
async close(): Promise<void>;
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
#### `auth`
|
|
80
|
-
|
|
81
|
-
Authenticate with the server using a JWT token.
|
|
82
|
-
|
|
83
|
-
```typescript
|
|
84
|
-
async auth(token: string): Promise<void>;
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
#### `getService`
|
|
70
|
+
## `ServiceProxy`
|
|
88
71
|
|
|
89
|
-
|
|
72
|
+
Type transformer that wraps all method return types of a service with `Promise`.
|
|
90
73
|
|
|
91
74
|
```typescript
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
const userService = client.getService<UserServiceType>("User");
|
|
98
|
-
const profile = await userService.getProfile();
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
#### `send`
|
|
102
|
-
|
|
103
|
-
Send a raw service method call.
|
|
104
|
-
|
|
105
|
-
```typescript
|
|
106
|
-
async send(
|
|
107
|
-
serviceName: string,
|
|
108
|
-
methodName: string,
|
|
109
|
-
params: unknown[],
|
|
110
|
-
progress?: ServiceProgress,
|
|
111
|
-
): Promise<unknown>;
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
#### `addListener`
|
|
115
|
-
|
|
116
|
-
Add a server-side event listener.
|
|
117
|
-
|
|
118
|
-
```typescript
|
|
119
|
-
async addListener<TInfo, TData>(
|
|
120
|
-
eventDef: ServiceEventDef<TInfo, TData>,
|
|
121
|
-
info: TInfo,
|
|
122
|
-
cb: (data: TData) => PromiseLike<void>,
|
|
123
|
-
): Promise<string>;
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
Returns a listener key (UUID) that can be used with `removeListener`.
|
|
127
|
-
|
|
128
|
-
#### `removeListener`
|
|
129
|
-
|
|
130
|
-
Remove a server-side event listener.
|
|
131
|
-
|
|
132
|
-
```typescript
|
|
133
|
-
async removeListener(key: string): Promise<void>;
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
#### `emitEvent`
|
|
137
|
-
|
|
138
|
-
Emit an event to matching server-side listeners.
|
|
139
|
-
|
|
140
|
-
```typescript
|
|
141
|
-
async emitEvent<TInfo, TData>(
|
|
142
|
-
eventDef: ServiceEventDef<TInfo, TData>,
|
|
143
|
-
infoSelector: (item: TInfo) => boolean,
|
|
144
|
-
data: TData,
|
|
145
|
-
): Promise<void>;
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
#### `uploadFile`
|
|
149
|
-
|
|
150
|
-
Upload files to the server. Requires prior authentication via `auth()`.
|
|
151
|
-
|
|
152
|
-
```typescript
|
|
153
|
-
async uploadFile(
|
|
154
|
-
files: File[] | FileList | { name: string; data: BlobPart }[],
|
|
155
|
-
): Promise<ServiceUploadResult[]>;
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
#### `downloadFileBuffer`
|
|
159
|
-
|
|
160
|
-
Download a file from the server as bytes.
|
|
161
|
-
|
|
162
|
-
```typescript
|
|
163
|
-
async downloadFileBuffer(relPath: string): Promise<Bytes>;
|
|
75
|
+
type ServiceProxy<TService> = {
|
|
76
|
+
[K in keyof TService]: TService[K] extends (...args: infer P) => infer R
|
|
77
|
+
? (...args: P) => Promise<Awaited<R>>
|
|
78
|
+
: never;
|
|
79
|
+
};
|
|
164
80
|
```
|
|
165
81
|
|
|
166
82
|
## `createServiceClient`
|
|
167
83
|
|
|
168
|
-
Factory function.
|
|
84
|
+
Factory function to create a `ServiceClient` instance.
|
|
169
85
|
|
|
170
86
|
```typescript
|
|
171
87
|
function createServiceClient(name: string, options: ServiceConnectionOptions): ServiceClient;
|
|
172
88
|
```
|
|
173
89
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
import { defineEvent } from "@simplysm/service-common";
|
|
179
|
-
|
|
180
|
-
// Define event
|
|
181
|
-
const OrderUpdated = defineEvent<{ orderId: number }, { status: string }>("OrderUpdated");
|
|
182
|
-
|
|
183
|
-
// Create client
|
|
184
|
-
const client = createServiceClient("my-app", {
|
|
185
|
-
host: "localhost",
|
|
186
|
-
port: 3000,
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
// Connect and authenticate
|
|
190
|
-
await client.connect();
|
|
191
|
-
await client.auth(jwtToken);
|
|
192
|
-
|
|
193
|
-
// Call service
|
|
194
|
-
const orderService = client.getService<OrderServiceType>("Order");
|
|
195
|
-
const orders = await orderService.getAll();
|
|
196
|
-
|
|
197
|
-
// Listen for events
|
|
198
|
-
const key = await client.addListener(OrderUpdated, { orderId: 123 }, async (data) => {
|
|
199
|
-
console.log(data.status);
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
// Track progress
|
|
203
|
-
client.on("request-progress", (state) => {
|
|
204
|
-
console.log(`Upload: ${state.completedSize}/${state.totalSize}`);
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
// Cleanup
|
|
208
|
-
await client.removeListener(key);
|
|
209
|
-
await client.close();
|
|
210
|
-
```
|
|
90
|
+
| Parameter | Type | Description |
|
|
91
|
+
|-----------|------|-------------|
|
|
92
|
+
| `name` | `string` | Client name identifier |
|
|
93
|
+
| `options` | `ServiceConnectionOptions` | Connection options |
|
package/docs/transport.md
CHANGED
|
@@ -1,43 +1,45 @@
|
|
|
1
1
|
# Transport
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## `SocketProvider`
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
Low-level WebSocket connection manager with automatic reconnection and heartbeat keep-alive.
|
|
8
|
-
|
|
9
|
-
### `SocketProviderEvents`
|
|
10
|
-
|
|
11
|
-
```typescript
|
|
12
|
-
interface SocketProviderEvents {
|
|
13
|
-
message: Bytes;
|
|
14
|
-
state: "connected" | "closed" | "reconnecting";
|
|
15
|
-
}
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
### `SocketProvider`
|
|
5
|
+
WebSocket connection provider interface. Manages connection lifecycle, heartbeat, and auto-reconnect.
|
|
19
6
|
|
|
20
7
|
```typescript
|
|
21
8
|
interface SocketProvider {
|
|
22
9
|
readonly clientName: string;
|
|
23
10
|
readonly connected: boolean;
|
|
24
|
-
on<K extends keyof SocketProviderEvents & string>(
|
|
25
|
-
|
|
26
|
-
listener: (data: SocketProviderEvents[K]) => void,
|
|
27
|
-
): void;
|
|
28
|
-
off<K extends keyof SocketProviderEvents & string>(
|
|
29
|
-
type: K,
|
|
30
|
-
listener: (data: SocketProviderEvents[K]) => void,
|
|
31
|
-
): void;
|
|
11
|
+
on<K extends keyof SocketProviderEvents & string>(type: K, listener: (data: SocketProviderEvents[K]) => void): void;
|
|
12
|
+
off<K extends keyof SocketProviderEvents & string>(type: K, listener: (data: SocketProviderEvents[K]) => void): void;
|
|
32
13
|
connect(): Promise<void>;
|
|
33
14
|
close(): Promise<void>;
|
|
34
15
|
send(data: Bytes): Promise<void>;
|
|
35
16
|
}
|
|
36
17
|
```
|
|
37
18
|
|
|
38
|
-
|
|
19
|
+
| Property/Method | Description |
|
|
20
|
+
|-----------------|-------------|
|
|
21
|
+
| `clientName` | Client name identifier |
|
|
22
|
+
| `connected` | Whether WebSocket is currently open |
|
|
23
|
+
| `on()` | Register event listener |
|
|
24
|
+
| `off()` | Remove event listener |
|
|
25
|
+
| `connect()` | Establish WebSocket connection |
|
|
26
|
+
| `close()` | Close connection (graceful shutdown) |
|
|
27
|
+
| `send()` | Send binary data |
|
|
28
|
+
|
|
29
|
+
## `SocketProviderEvents`
|
|
39
30
|
|
|
40
|
-
|
|
31
|
+
Events emitted by `SocketProvider`.
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
interface SocketProviderEvents {
|
|
35
|
+
message: Bytes;
|
|
36
|
+
state: "connected" | "closed" | "reconnecting";
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## `createSocketProvider`
|
|
41
|
+
|
|
42
|
+
Create a WebSocket provider with heartbeat and auto-reconnect.
|
|
41
43
|
|
|
42
44
|
```typescript
|
|
43
45
|
function createSocketProvider(
|
|
@@ -47,46 +49,44 @@ function createSocketProvider(
|
|
|
47
49
|
): SocketProvider;
|
|
48
50
|
```
|
|
49
51
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
---
|
|
52
|
+
| Parameter | Type | Description |
|
|
53
|
+
|-----------|------|-------------|
|
|
54
|
+
| `url` | `string` | WebSocket URL (ws:// or wss://) |
|
|
55
|
+
| `clientName` | `string` | Client name identifier |
|
|
56
|
+
| `maxReconnectCount` | `number` | Max reconnect attempts |
|
|
57
57
|
|
|
58
|
-
## ServiceTransport
|
|
58
|
+
## `ServiceTransport`
|
|
59
59
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
### `ServiceTransportEvents`
|
|
60
|
+
Service transport interface. Handles message routing and request/response correlation.
|
|
63
61
|
|
|
64
62
|
```typescript
|
|
65
|
-
interface
|
|
66
|
-
|
|
67
|
-
|
|
63
|
+
interface ServiceTransport {
|
|
64
|
+
on<K extends keyof ServiceTransportEvents & string>(type: K, listener: (data: ServiceTransportEvents[K]) => void): void;
|
|
65
|
+
off<K extends keyof ServiceTransportEvents & string>(type: K, listener: (data: ServiceTransportEvents[K]) => void): void;
|
|
66
|
+
send(message: ServiceClientMessage, progress?: ServiceProgress): Promise<unknown>;
|
|
68
67
|
}
|
|
69
68
|
```
|
|
70
69
|
|
|
71
|
-
|
|
70
|
+
| Method | Description |
|
|
71
|
+
|--------|-------------|
|
|
72
|
+
| `on()` | Register event listener (reload, event) |
|
|
73
|
+
| `off()` | Remove event listener |
|
|
74
|
+
| `send()` | Send a client message and await response |
|
|
75
|
+
|
|
76
|
+
## `ServiceTransportEvents`
|
|
77
|
+
|
|
78
|
+
Events emitted by `ServiceTransport`.
|
|
72
79
|
|
|
73
80
|
```typescript
|
|
74
|
-
interface
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
listener: (data: ServiceTransportEvents[K]) => void,
|
|
78
|
-
): void;
|
|
79
|
-
off<K extends keyof ServiceTransportEvents & string>(
|
|
80
|
-
type: K,
|
|
81
|
-
listener: (data: ServiceTransportEvents[K]) => void,
|
|
82
|
-
): void;
|
|
83
|
-
send(message: ServiceClientMessage, progress?: ServiceProgress): Promise<unknown>;
|
|
81
|
+
interface ServiceTransportEvents {
|
|
82
|
+
reload: Set<string>;
|
|
83
|
+
event: { keys: string[]; data: unknown };
|
|
84
84
|
}
|
|
85
85
|
```
|
|
86
86
|
|
|
87
|
-
|
|
87
|
+
## `createServiceTransport`
|
|
88
88
|
|
|
89
|
-
Create a
|
|
89
|
+
Create a service transport instance.
|
|
90
90
|
|
|
91
91
|
```typescript
|
|
92
92
|
function createServiceTransport(
|
|
@@ -94,9 +94,3 @@ function createServiceTransport(
|
|
|
94
94
|
protocol: ClientProtocolWrapper,
|
|
95
95
|
): ServiceTransport;
|
|
96
96
|
```
|
|
97
|
-
|
|
98
|
-
**Behavior:**
|
|
99
|
-
- Each `send()` call generates a unique UUID and registers a pending request
|
|
100
|
-
- Incoming messages are correlated by UUID and resolved/rejected accordingly
|
|
101
|
-
- Progress callbacks are invoked for chunked message transfers
|
|
102
|
-
- All pending requests are rejected when the socket disconnects
|
package/docs/types.md
CHANGED
|
@@ -1,22 +1,28 @@
|
|
|
1
1
|
# Types
|
|
2
2
|
|
|
3
|
-
## ServiceConnectionOptions
|
|
3
|
+
## `ServiceConnectionOptions`
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Connection options for `ServiceClient`.
|
|
6
6
|
|
|
7
7
|
```typescript
|
|
8
8
|
interface ServiceConnectionOptions {
|
|
9
9
|
port: number;
|
|
10
10
|
host: string;
|
|
11
11
|
ssl?: boolean;
|
|
12
|
-
/** Set to 0 to disable reconnect; disconnects immediately */
|
|
13
12
|
maxReconnectCount?: number;
|
|
14
13
|
}
|
|
15
14
|
```
|
|
16
15
|
|
|
17
|
-
|
|
16
|
+
| Field | Type | Description |
|
|
17
|
+
|-------|------|-------------|
|
|
18
|
+
| `port` | `number` | Server port |
|
|
19
|
+
| `host` | `string` | Server hostname |
|
|
20
|
+
| `ssl` | `boolean` | Use SSL/TLS (wss:// and https://) |
|
|
21
|
+
| `maxReconnectCount` | `number` | Max reconnect attempts (0 to disable, default: 10) |
|
|
18
22
|
|
|
19
|
-
|
|
23
|
+
## `ServiceProgress`
|
|
24
|
+
|
|
25
|
+
Progress callback configuration for service requests.
|
|
20
26
|
|
|
21
27
|
```typescript
|
|
22
28
|
interface ServiceProgress {
|
|
@@ -25,9 +31,14 @@ interface ServiceProgress {
|
|
|
25
31
|
}
|
|
26
32
|
```
|
|
27
33
|
|
|
28
|
-
|
|
34
|
+
| Field | Type | Description |
|
|
35
|
+
|-------|------|-------------|
|
|
36
|
+
| `request` | `(s: ServiceProgressState) => void` | Request upload progress callback |
|
|
37
|
+
| `response` | `(s: ServiceProgressState) => void` | Response download progress callback |
|
|
38
|
+
|
|
39
|
+
## `ServiceProgressState`
|
|
29
40
|
|
|
30
|
-
|
|
41
|
+
Progress state for chunked message transfers.
|
|
31
42
|
|
|
32
43
|
```typescript
|
|
33
44
|
interface ServiceProgressState {
|
|
@@ -36,3 +47,9 @@ interface ServiceProgressState {
|
|
|
36
47
|
completedSize: number;
|
|
37
48
|
}
|
|
38
49
|
```
|
|
50
|
+
|
|
51
|
+
| Field | Type | Description |
|
|
52
|
+
|-------|------|-------------|
|
|
53
|
+
| `uuid` | `string` | Request UUID |
|
|
54
|
+
| `totalSize` | `number` | Total message size in bytes |
|
|
55
|
+
| `completedSize` | `number` | Completed size in bytes |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@simplysm/service-client",
|
|
3
|
-
"version": "13.0.
|
|
3
|
+
"version": "13.0.99",
|
|
4
4
|
"description": "Simplysm package - Service module (client)",
|
|
5
5
|
"author": "simplysm",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -20,9 +20,9 @@
|
|
|
20
20
|
"sideEffects": false,
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"consola": "^3.4.2",
|
|
23
|
-
"@simplysm/core-common": "13.0.
|
|
24
|
-
"@simplysm/
|
|
25
|
-
"@simplysm/
|
|
23
|
+
"@simplysm/core-common": "13.0.99",
|
|
24
|
+
"@simplysm/service-common": "13.0.99",
|
|
25
|
+
"@simplysm/orm-common": "13.0.99"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"@types/ws": "^8.18.1",
|