@simplysm/service-client 13.0.97 → 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 ADDED
@@ -0,0 +1,126 @@
1
+ # @simplysm/service-client
2
+
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.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install @simplysm/service-client
11
+ ```
12
+
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
71
+
72
+ ```typescript
73
+ import { createServiceClient } from "@simplysm/service-client";
74
+
75
+ const client = createServiceClient("my-app", {
76
+ host: "localhost",
77
+ port: 3000,
78
+ });
79
+
80
+ await client.connect();
81
+ await client.auth(jwtToken);
82
+
83
+ // Type-safe service proxy
84
+ interface UserService {
85
+ getProfile(): Promise<{ name: string; email: string }>;
86
+ updateName(name: string): Promise<void>;
87
+ }
88
+
89
+ const userService = client.getService<UserService>("User");
90
+ const profile = await userService.getProfile();
91
+ await userService.updateName("New Name");
92
+ ```
93
+
94
+ ### Client-Side ORM
95
+
96
+ ```typescript
97
+ import { createOrmClientConnector } from "@simplysm/service-client";
98
+
99
+ const orm = createOrmClientConnector(client);
100
+
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
+ );
107
+ ```
108
+
109
+ ### Event Subscription
110
+
111
+ ```typescript
112
+ import { defineEvent } from "@simplysm/service-common";
113
+
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
+ ```
@@ -0,0 +1,143 @@
1
+ # Features
2
+
3
+ ## `EventClient`
4
+
5
+ Client-side event management interface. Handles event listener registration, removal, emission, and auto-recovery on reconnect.
6
+
7
+ ```typescript
8
+ 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 | 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.
34
+
35
+ ```typescript
36
+ function createEventClient(transport: ServiceTransport): EventClient;
37
+ ```
38
+
39
+ ## `FileClient`
40
+
41
+ File upload/download client interface.
42
+
43
+ ```typescript
44
+ interface FileClient {
45
+ download(relPath: string): Promise<Bytes>;
46
+ upload(
47
+ files: File[] | FileList | { name: string; data: BlobPart }[],
48
+ authToken: string,
49
+ ): Promise<ServiceUploadResult[]>;
50
+ }
51
+ ```
52
+
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.
61
+
62
+ ```typescript
63
+ function createFileClient(hostUrl: string, clientName: string): FileClient;
64
+ ```
65
+
66
+ | Parameter | Type | Description |
67
+ |-----------|------|-------------|
68
+ | `hostUrl` | `string` | Server base URL (http:// or https://) |
69
+ | `clientName` | `string` | Client name for request headers |
70
+
71
+ ## `OrmConnectOptions`
72
+
73
+ ORM connection options for client-side database access.
74
+
75
+ ```typescript
76
+ 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` | DbContext definition |
89
+ | `connOpt` | `DbConnOptions & { configName: string }` | Connection options with config name |
90
+ | `dbContextOpt` | `{ database: string; schema: string }` | Override database/schema from server config |
91
+
92
+ ## `OrmClientConnector`
93
+
94
+ Client-side ORM connector interface. Creates DbContext instances that execute queries via the service protocol.
95
+
96
+ ```typescript
97
+ 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 | 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.
117
+
118
+ ```typescript
119
+ function createOrmClientConnector(serviceClient: ServiceClient): OrmClientConnector;
120
+ ```
121
+
122
+ ## `OrmClientDbContextExecutor`
123
+
124
+ Client-side DbContext executor. Implements `DbContextExecutor` by delegating to the ORM service over the service protocol.
125
+
126
+ ```typescript
127
+ class OrmClientDbContextExecutor implements DbContextExecutor {
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>;
142
+ }
143
+ ```
@@ -0,0 +1,29 @@
1
+ # Protocol
2
+
3
+ ## `ClientProtocolWrapper`
4
+
5
+ Client-side protocol wrapper interface. Handles message encoding/decoding with optional Web Worker offloading for large payloads (>30KB).
6
+
7
+ ```typescript
8
+ interface ClientProtocolWrapper {
9
+ encode(uuid: string, message: ServiceMessage): Promise<{ chunks: Bytes[]; totalSize: number }>;
10
+ decode(bytes: Bytes): Promise<ServiceMessageDecodeResult<ServiceMessage>>;
11
+ }
12
+ ```
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
+
19
+ ## `createClientProtocolWrapper`
20
+
21
+ Create a client protocol wrapper instance. Automatically offloads heavy encoding/decoding to a Web Worker when available and payload exceeds 30KB.
22
+
23
+ ```typescript
24
+ function createClientProtocolWrapper(protocol: ServiceProtocol): ClientProtocolWrapper;
25
+ ```
26
+
27
+ | Parameter | Type | Description |
28
+ |-----------|------|-------------|
29
+ | `protocol` | `ServiceProtocol` | Base protocol instance from `createServiceProtocol()` |
@@ -0,0 +1,93 @@
1
+ # ServiceClient
2
+
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
+ }
35
+ ```
36
+
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 |
43
+
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 |
56
+
57
+ ## `ServiceClientEvents`
58
+
59
+ Events emitted by `ServiceClient`.
60
+
61
+ ```typescript
62
+ interface ServiceClientEvents {
63
+ "request-progress": ServiceProgressState;
64
+ "response-progress": ServiceProgressState;
65
+ "state": "connected" | "closed" | "reconnecting";
66
+ "reload": Set<string>;
67
+ }
68
+ ```
69
+
70
+ ## `ServiceProxy`
71
+
72
+ Type transformer that wraps all method return types of a service with `Promise`.
73
+
74
+ ```typescript
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
+ };
80
+ ```
81
+
82
+ ## `createServiceClient`
83
+
84
+ Factory function to create a `ServiceClient` instance.
85
+
86
+ ```typescript
87
+ function createServiceClient(name: string, options: ServiceConnectionOptions): ServiceClient;
88
+ ```
89
+
90
+ | Parameter | Type | Description |
91
+ |-----------|------|-------------|
92
+ | `name` | `string` | Client name identifier |
93
+ | `options` | `ServiceConnectionOptions` | Connection options |
@@ -0,0 +1,96 @@
1
+ # Transport
2
+
3
+ ## `SocketProvider`
4
+
5
+ WebSocket connection provider interface. Manages connection lifecycle, heartbeat, and auto-reconnect.
6
+
7
+ ```typescript
8
+ interface SocketProvider {
9
+ readonly clientName: string;
10
+ readonly connected: boolean;
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;
13
+ connect(): Promise<void>;
14
+ close(): Promise<void>;
15
+ send(data: Bytes): Promise<void>;
16
+ }
17
+ ```
18
+
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`
30
+
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.
43
+
44
+ ```typescript
45
+ function createSocketProvider(
46
+ url: string,
47
+ clientName: string,
48
+ maxReconnectCount: number,
49
+ ): SocketProvider;
50
+ ```
51
+
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
+
58
+ ## `ServiceTransport`
59
+
60
+ Service transport interface. Handles message routing and request/response correlation.
61
+
62
+ ```typescript
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>;
67
+ }
68
+ ```
69
+
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`.
79
+
80
+ ```typescript
81
+ interface ServiceTransportEvents {
82
+ reload: Set<string>;
83
+ event: { keys: string[]; data: unknown };
84
+ }
85
+ ```
86
+
87
+ ## `createServiceTransport`
88
+
89
+ Create a service transport instance.
90
+
91
+ ```typescript
92
+ function createServiceTransport(
93
+ socket: SocketProvider,
94
+ protocol: ClientProtocolWrapper,
95
+ ): ServiceTransport;
96
+ ```
package/docs/types.md ADDED
@@ -0,0 +1,55 @@
1
+ # Types
2
+
3
+ ## `ServiceConnectionOptions`
4
+
5
+ Connection options for `ServiceClient`.
6
+
7
+ ```typescript
8
+ 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` | Use SSL/TLS (wss:// and https://) |
21
+ | `maxReconnectCount` | `number` | Max reconnect attempts (0 to disable, default: 10) |
22
+
23
+ ## `ServiceProgress`
24
+
25
+ Progress callback configuration for service requests.
26
+
27
+ ```typescript
28
+ interface ServiceProgress {
29
+ request?: (s: ServiceProgressState) => void;
30
+ response?: (s: ServiceProgressState) => void;
31
+ }
32
+ ```
33
+
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`
40
+
41
+ Progress state for chunked message transfers.
42
+
43
+ ```typescript
44
+ interface ServiceProgressState {
45
+ uuid: string;
46
+ totalSize: number;
47
+ completedSize: number;
48
+ }
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.97",
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.97",
24
- "@simplysm/orm-common": "13.0.97",
25
- "@simplysm/service-common": "13.0.97"
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",