@simplysm/service-common 13.0.72 → 13.0.75

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 CHANGED
@@ -2,38 +2,496 @@
2
2
 
3
3
  Simplysm package - Service module (common)
4
4
 
5
+ Shared types, protocol definitions, and service interfaces used by both `@simplysm/service-client` and `@simplysm/service-server`.
6
+
5
7
  ## Installation
6
8
 
9
+ ```bash
7
10
  pnpm add @simplysm/service-common
11
+ ```
12
+
13
+ ## Protocol
14
+
15
+ ### `PROTOCOL_CONFIG`
16
+
17
+ Constants that control the binary wire protocol.
18
+
19
+ ```ts
20
+ import { PROTOCOL_CONFIG } from "@simplysm/service-common";
21
+
22
+ console.log(PROTOCOL_CONFIG.MAX_TOTAL_SIZE); // 104857600 (100 MB)
23
+ console.log(PROTOCOL_CONFIG.SPLIT_MESSAGE_SIZE); // 3145728 (3 MB)
24
+ console.log(PROTOCOL_CONFIG.CHUNK_SIZE); // 307200 (300 KB)
25
+ console.log(PROTOCOL_CONFIG.GC_INTERVAL); // 10000 (10 s)
26
+ console.log(PROTOCOL_CONFIG.EXPIRE_TIME); // 60000 (60 s)
27
+ ```
28
+
29
+ | Field | Value | Description |
30
+ |---|---|---|
31
+ | `MAX_TOTAL_SIZE` | 100 MB | Maximum allowed message size |
32
+ | `SPLIT_MESSAGE_SIZE` | 3 MB | Messages larger than this are split into chunks |
33
+ | `CHUNK_SIZE` | 300 KB | Size of each chunk |
34
+ | `GC_INTERVAL` | 10 s | Interval for GC of incomplete messages |
35
+ | `EXPIRE_TIME` | 60 s | Expiry time for incomplete chunked messages |
36
+
37
+ ---
38
+
39
+ ### Message Types
40
+
41
+ Type union aliases for all WebSocket messages exchanged between client and server.
42
+
43
+ ```ts
44
+ import type {
45
+ ServiceMessage,
46
+ ServiceServerMessage,
47
+ ServiceServerRawMessage,
48
+ ServiceClientMessage,
49
+ } from "@simplysm/service-common";
50
+ ```
51
+
52
+ | Type | Direction | Description |
53
+ |---|---|---|
54
+ | `ServiceMessage` | both | Union of all possible messages |
55
+ | `ServiceServerMessage` | server → client | Messages the server sends to the client |
56
+ | `ServiceServerRawMessage` | server → client | `ServiceProgressMessage` plus `ServiceServerMessage` |
57
+ | `ServiceClientMessage` | client → server | Messages the client sends to the server |
58
+
59
+ ---
60
+
61
+ ### Individual Message Interfaces
62
+
63
+ #### `ServiceReloadMessage`
64
+
65
+ Server-sent notification asking the client to reload.
66
+
67
+ ```ts
68
+ import type { ServiceReloadMessage } from "@simplysm/service-common";
69
+
70
+ const msg: ServiceReloadMessage = {
71
+ name: "reload",
72
+ body: {
73
+ clientName: "my-app",
74
+ changedFileSet: new Set(["main.js"]),
75
+ },
76
+ };
77
+ ```
78
+
79
+ #### `ServiceProgressMessage`
80
+
81
+ Server-sent progress notification while a large chunked message is being received.
82
+
83
+ ```ts
84
+ import type { ServiceProgressMessage } from "@simplysm/service-common";
85
+
86
+ const msg: ServiceProgressMessage = {
87
+ name: "progress",
88
+ body: { totalSize: 10_000_000, completedSize: 3_000_000 },
89
+ };
90
+ ```
91
+
92
+ #### `ServiceErrorMessage`
93
+
94
+ Server-sent error notification.
95
+
96
+ ```ts
97
+ import type { ServiceErrorMessage } from "@simplysm/service-common";
98
+
99
+ const msg: ServiceErrorMessage = {
100
+ name: "error",
101
+ body: {
102
+ name: "NotFoundError",
103
+ message: "Record not found",
104
+ code: "NOT_FOUND",
105
+ stack: "...",
106
+ detail: { id: 42 },
107
+ },
108
+ };
109
+ ```
110
+
111
+ #### `ServiceAuthMessage`
112
+
113
+ Client-sent authentication message carrying a token.
114
+
115
+ ```ts
116
+ import type { ServiceAuthMessage } from "@simplysm/service-common";
117
+
118
+ const msg: ServiceAuthMessage = { name: "auth", body: "<jwt-token>" };
119
+ ```
120
+
121
+ #### `ServiceRequestMessage`
122
+
123
+ Client-sent message to invoke a service method.
124
+
125
+ ```ts
126
+ import type { ServiceRequestMessage } from "@simplysm/service-common";
127
+
128
+ const msg: ServiceRequestMessage = {
129
+ name: "UserService.getUser", // "${service}.${method}"
130
+ body: [42], // method arguments
131
+ };
132
+ ```
133
+
134
+ #### `ServiceResponseMessage`
135
+
136
+ Server-sent response to a `ServiceRequestMessage`.
137
+
138
+ ```ts
139
+ import type { ServiceResponseMessage } from "@simplysm/service-common";
140
+
141
+ const msg: ServiceResponseMessage = {
142
+ name: "response",
143
+ body: { id: 42, name: "Alice" },
144
+ };
145
+ ```
146
+
147
+ #### `ServiceAddEventListenerMessage`
148
+
149
+ Client-sent message to subscribe to a named event.
150
+
151
+ ```ts
152
+ import type { ServiceAddEventListenerMessage } from "@simplysm/service-common";
153
+
154
+ const msg: ServiceAddEventListenerMessage = {
155
+ name: "evt:add",
156
+ body: {
157
+ key: "<uuid>", // unique listener key for later removal
158
+ name: "OrderUpdated", // event name
159
+ info: { orderId: 1 }, // filter info passed to the server
160
+ },
161
+ };
162
+ ```
163
+
164
+ #### `ServiceRemoveEventListenerMessage`
165
+
166
+ Client-sent message to unsubscribe from an event.
167
+
168
+ ```ts
169
+ import type { ServiceRemoveEventListenerMessage } from "@simplysm/service-common";
170
+
171
+ const msg: ServiceRemoveEventListenerMessage = {
172
+ name: "evt:remove",
173
+ body: { key: "<uuid>" },
174
+ };
175
+ ```
176
+
177
+ #### `ServiceGetEventListenerInfosMessage`
178
+
179
+ Client-sent message to retrieve listener info objects for a named event.
180
+
181
+ ```ts
182
+ import type { ServiceGetEventListenerInfosMessage } from "@simplysm/service-common";
183
+
184
+ const msg: ServiceGetEventListenerInfosMessage = {
185
+ name: "evt:gets",
186
+ body: { name: "OrderUpdated" },
187
+ };
188
+ ```
189
+
190
+ #### `ServiceEmitEventMessage`
191
+
192
+ Client-sent message to emit an event to specific listeners.
193
+
194
+ ```ts
195
+ import type { ServiceEmitEventMessage } from "@simplysm/service-common";
196
+
197
+ const msg: ServiceEmitEventMessage = {
198
+ name: "evt:emit",
199
+ body: {
200
+ keys: ["<uuid1>", "<uuid2>"],
201
+ data: { status: "shipped" },
202
+ },
203
+ };
204
+ ```
205
+
206
+ #### `ServiceEventMessage`
207
+
208
+ Server-sent event notification delivered to subscribed clients.
209
+
210
+ ```ts
211
+ import type { ServiceEventMessage } from "@simplysm/service-common";
212
+
213
+ const msg: ServiceEventMessage = {
214
+ name: "evt:on",
215
+ body: {
216
+ keys: ["<uuid1>"],
217
+ data: { status: "shipped" },
218
+ },
219
+ };
220
+ ```
221
+
222
+ ---
223
+
224
+ ### `createServiceProtocol`
225
+
226
+ Factory function that creates a `ServiceProtocol` encoder/decoder.
227
+
228
+ Implements Binary Protocol V2:
229
+ - Header: 28 bytes (UUID 16 + TotalSize 8 + Index 4), Big Endian
230
+ - Body: UTF-8 JSON
231
+ - Automatically splits messages larger than 3 MB into 300 KB chunks
232
+ - Automatically reassembles chunked packets on decode
233
+
234
+ ```ts
235
+ import { createServiceProtocol } from "@simplysm/service-common";
236
+
237
+ const protocol = createServiceProtocol();
238
+
239
+ // Encode
240
+ const uuid = crypto.randomUUID();
241
+ const { chunks, totalSize } = protocol.encode(uuid, {
242
+ name: "UserService.getUser",
243
+ body: [42],
244
+ });
245
+ // Send each chunk over a WebSocket
246
+
247
+ // Decode (call for every incoming binary frame)
248
+ const result = protocol.decode(incomingBytes);
249
+ if (result.type === "complete") {
250
+ console.log(result.uuid, result.message);
251
+ } else {
252
+ // result.type === "progress"
253
+ console.log(`${result.completedSize} / ${result.totalSize} bytes received`);
254
+ }
255
+
256
+ // Release internal GC timer when done
257
+ protocol.dispose();
258
+ ```
259
+
260
+ ---
261
+
262
+ ### `ServiceProtocol`
263
+
264
+ Interface returned by `createServiceProtocol`.
265
+
266
+ ```ts
267
+ import type { ServiceProtocol } from "@simplysm/service-common";
268
+
269
+ interface ServiceProtocol {
270
+ encode(uuid: string, message: ServiceMessage): { chunks: Bytes[]; totalSize: number };
271
+ decode<T extends ServiceMessage>(bytes: Bytes): ServiceMessageDecodeResult<T>;
272
+ dispose(): void;
273
+ }
274
+ ```
275
+
276
+ ---
277
+
278
+ ### `ServiceMessageDecodeResult`
279
+
280
+ Union type returned by `ServiceProtocol.decode`.
281
+
282
+ ```ts
283
+ import type { ServiceMessageDecodeResult } from "@simplysm/service-common";
284
+
285
+ type ServiceMessageDecodeResult<TMessage extends ServiceMessage> =
286
+ | { type: "complete"; uuid: string; message: TMessage }
287
+ | { type: "progress"; uuid: string; totalSize: number; completedSize: number };
288
+ ```
289
+
290
+ ## Service Types
291
+
292
+ Pre-defined service interfaces for common backend services. Implement these interfaces on the server side and consume them on the client side.
293
+
294
+ ### `OrmService`
295
+
296
+ Interface for ORM database access over the service layer.
297
+
298
+ ```ts
299
+ import type { OrmService } from "@simplysm/service-common";
300
+ ```
301
+
302
+ | Method | Description |
303
+ |---|---|
304
+ | `getInfo(opt)` | Returns dialect, database, and schema for a connection config |
305
+ | `connect(opt)` | Opens a connection and returns a connection ID |
306
+ | `close(connId)` | Closes the connection |
307
+ | `beginTransaction(connId, isolationLevel?)` | Begins a transaction |
308
+ | `commitTransaction(connId)` | Commits the current transaction |
309
+ | `rollbackTransaction(connId)` | Rolls back the current transaction |
310
+ | `executeParametrized(connId, query, params?)` | Executes a parameterized SQL query |
311
+ | `executeDefs(connId, defs, options?)` | Executes a list of `QueryDef` objects |
312
+ | `bulkInsert(connId, tableName, columnDefs, records)` | Performs a bulk insert |
313
+
314
+ ---
315
+
316
+ ### `DbConnOptions`
317
+
318
+ Options for selecting a database connection configuration.
319
+
320
+ ```ts
321
+ import type { DbConnOptions } from "@simplysm/service-common";
322
+
323
+ type DbConnOptions = {
324
+ configName?: string; // Named config key
325
+ config?: Record<string, unknown>; // Inline config object
326
+ };
327
+ ```
328
+
329
+ ---
330
+
331
+ ### `AutoUpdateService`
332
+
333
+ Interface for retrieving the latest client application version.
334
+
335
+ ```ts
336
+ import type { AutoUpdateService } from "@simplysm/service-common";
337
+
338
+ // Server implementation example
339
+ class MyAutoUpdateService implements AutoUpdateService {
340
+ async getLastVersion(platform: string) {
341
+ if (platform === "win32") {
342
+ return { version: "1.2.3", downloadPath: "/updates/app-1.2.3.exe" };
343
+ }
344
+ return undefined;
345
+ }
346
+ }
347
+ ```
348
+
349
+ | Method | Parameters | Returns | Description |
350
+ |---|---|---|---|
351
+ | `getLastVersion` | `platform: string` | `Promise<{ version: string; downloadPath: string } \| undefined>` | Returns the latest version info for the given platform, or `undefined` if none exists |
352
+
353
+ ---
354
+
355
+ ### `SmtpClientSendAttachment`
356
+
357
+ Attachment descriptor for outgoing emails.
358
+
359
+ ```ts
360
+ import type { SmtpClientSendAttachment } from "@simplysm/service-common";
361
+
362
+ interface SmtpClientSendAttachment {
363
+ filename: string;
364
+ content?: string | Uint8Array; // Inline content
365
+ path?: any; // File path (node)
366
+ contentType?: string;
367
+ }
368
+ ```
369
+
370
+ ---
371
+
372
+ ### `SmtpClientSendByDefaultOption`
373
+
374
+ Email send options when using a pre-configured SMTP default.
375
+
376
+ ```ts
377
+ import type { SmtpClientSendByDefaultOption } from "@simplysm/service-common";
378
+
379
+ interface SmtpClientSendByDefaultOption {
380
+ to: string;
381
+ cc?: string;
382
+ bcc?: string;
383
+ subject: string;
384
+ html: string;
385
+ attachments?: SmtpClientSendAttachment[];
386
+ }
387
+ ```
388
+
389
+ ---
390
+
391
+ ### `SmtpClientSendOption`
392
+
393
+ Full email send options including explicit SMTP connection details.
394
+
395
+ ```ts
396
+ import type { SmtpClientSendOption } from "@simplysm/service-common";
397
+
398
+ interface SmtpClientSendOption {
399
+ host: string;
400
+ port?: number;
401
+ secure?: boolean;
402
+ user?: string;
403
+ pass?: string;
404
+
405
+ from: string;
406
+ to: string;
407
+ cc?: string;
408
+ bcc?: string;
409
+ subject: string;
410
+ html: string;
411
+ attachments?: SmtpClientSendAttachment[];
412
+ }
413
+ ```
414
+
415
+ ---
416
+
417
+ ### `SmtpClientDefaultConfig`
418
+
419
+ Configuration for a default SMTP sender used server-side.
420
+
421
+ ```ts
422
+ import type { SmtpClientDefaultConfig } from "@simplysm/service-common";
423
+
424
+ interface SmtpClientDefaultConfig {
425
+ senderName: string;
426
+ senderEmail?: string;
427
+ user?: string;
428
+ pass?: string;
429
+ host: string;
430
+ port?: number;
431
+ secure?: boolean;
432
+ }
433
+ ```
434
+
435
+ ## Types
436
+
437
+ ### `ServiceUploadResult`
438
+
439
+ Describes a file that has been uploaded to the server.
440
+
441
+ ```ts
442
+ import type { ServiceUploadResult } from "@simplysm/service-common";
443
+
444
+ interface ServiceUploadResult {
445
+ path: string; // Storage path on the server
446
+ filename: string; // Original filename
447
+ size: number; // File size in bytes
448
+ }
449
+ ```
450
+
451
+ ## Define
452
+
453
+ ### `defineEvent`
454
+
455
+ Creates a type-safe event definition object used to subscribe and emit events through the service layer.
8
456
 
9
- ## Source Index
457
+ ```ts
458
+ import { defineEvent } from "@simplysm/service-common";
10
459
 
11
- ### Protocol
460
+ // Define a typed event
461
+ const OrderUpdated = defineEvent<
462
+ { orderId: number }, // TInfo — filter info sent with addEventListener
463
+ { status: string } // TData — data payload delivered to the listener
464
+ >("OrderUpdated");
12
465
 
13
- | Source | Exports | Description | Test |
14
- |--------|---------|-------------|------|
15
- | `src/protocol/protocol.types.ts` | `PROTOCOL_CONFIG`, `ServiceMessage`, `ServiceServerMessage`, `ServiceServerRawMessage`, `ServiceClientMessage`, `ServiceReloadMessage`, `ServiceProgressMessage`, `ServiceErrorMessage`, `ServiceAuthMessage`, `ServiceRequestMessage`, `ServiceResponseMessage`, `ServiceAddEventListenerMessage`, `ServiceRemoveEventListenerMessage`, `ServiceGetEventListenerInfosMessage`, `ServiceEmitEventMessage`, `ServiceEventMessage` | Protocol constants and all WebSocket message type definitions | - |
16
- | `src/protocol/service-protocol.ts` | `ServiceProtocol`, `ServiceMessageDecodeResult`, `createServiceProtocol` | Factory and types for encoding/decoding chunked service messages | `service-protocol.spec.ts` |
466
+ // Server: emit the event
467
+ ctx.socket?.emitEvent(OrderUpdated, { orderId: 123 }, { status: "shipped" });
17
468
 
18
- ### Service Types
469
+ // Client: subscribe to the event
470
+ await client.addEventListener(OrderUpdated, { orderId: 123 }, (data) => {
471
+ console.log(data.status); // typed as string
472
+ });
473
+ ```
19
474
 
20
- | Source | Exports | Description | Test |
21
- |--------|---------|-------------|------|
22
- | `src/service-types/orm-service.types.ts` | `OrmService`, `DbConnOptions` | Service interface for ORM database connection and query execution | - |
23
- | `src/service-types/auto-update-service.types.ts` | `AutoUpdateService` | Service interface for retrieving the latest client application version | - |
475
+ **Signature**
24
476
 
25
- ### Types
477
+ ```ts
478
+ function defineEvent<TInfo = unknown, TData = unknown>(
479
+ eventName: string,
480
+ ): ServiceEventDef<TInfo, TData>
481
+ ```
26
482
 
27
- | Source | Exports | Description | Test |
28
- |--------|---------|-------------|------|
29
- | `src/types.ts` | `ServiceUploadResult` | Result type describing a file uploaded to the server | - |
483
+ ---
30
484
 
31
- ### Define
485
+ ### `ServiceEventDef`
32
486
 
33
- | Source | Exports | Description | Test |
34
- |--------|---------|-------------|------|
35
- | `src/define-event.ts` | `ServiceEventDef`, `defineEvent` | Helper to define typed service events with info and data shapes | `define-event.spec.ts` |
487
+ The object type returned by `defineEvent`. The `$info` and `$data` fields are compile-time type markers only and hold no runtime value.
36
488
 
37
- ## License
489
+ ```ts
490
+ import type { ServiceEventDef } from "@simplysm/service-common";
38
491
 
39
- Apache-2.0
492
+ interface ServiceEventDef<TInfo = unknown, TData = unknown> {
493
+ eventName: string;
494
+ readonly $info: TInfo; // type extraction only
495
+ readonly $data: TData; // type extraction only
496
+ }
497
+ ```
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export * from "./protocol/protocol.types";
2
- export * from "./protocol/service-protocol";
2
+ export * from "./protocol/create-service-protocol";
3
3
  export * from "./service-types/orm-service.types";
4
4
  export * from "./service-types/auto-update-service.types";
5
5
  export * from "./service-types/smtp-client-service.types";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["..\\src\\index.ts"],"names":[],"mappings":"AACA,cAAc,2BAA2B,CAAC;AAC1C,cAAc,6BAA6B,CAAC;AAG5C,cAAc,mCAAmC,CAAC;AAClD,cAAc,2CAA2C,CAAC;AAC1D,cAAc,2CAA2C,CAAC;AAG1D,cAAc,SAAS,CAAC;AAGxB,cAAc,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["..\\src\\index.ts"],"names":[],"mappings":"AACA,cAAc,2BAA2B,CAAC;AAC1C,cAAc,oCAAoC,CAAC;AAGnD,cAAc,mCAAmC,CAAC;AAClD,cAAc,2CAA2C,CAAC;AAC1D,cAAc,2CAA2C,CAAC;AAG1D,cAAc,SAAS,CAAC;AAGxB,cAAc,gBAAgB,CAAC"}
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  export * from "./protocol/protocol.types.js";
2
- export * from "./protocol/service-protocol.js";
2
+ export * from "./protocol/create-service-protocol.js";
3
3
  export * from "./service-types/orm-service.types.js";
4
4
  export * from "./service-types/auto-update-service.types.js";
5
5
  export * from "./service-types/smtp-client-service.types.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simplysm/service-common",
3
- "version": "13.0.72",
3
+ "version": "13.0.75",
4
4
  "description": "Simplysm package - Service module (common)",
5
5
  "author": "simplysm",
6
6
  "license": "Apache-2.0",
@@ -19,7 +19,7 @@
19
19
  ],
20
20
  "sideEffects": false,
21
21
  "dependencies": {
22
- "@simplysm/core-common": "13.0.72",
23
- "@simplysm/orm-common": "13.0.72"
22
+ "@simplysm/core-common": "13.0.75",
23
+ "@simplysm/orm-common": "13.0.75"
24
24
  }
25
25
  }
package/src/index.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  // Protocol
2
2
  export * from "./protocol/protocol.types";
3
- export * from "./protocol/service-protocol";
3
+ export * from "./protocol/create-service-protocol";
4
4
 
5
5
  // Service Types
6
6
  export * from "./service-types/orm-service.types";
@@ -1,5 +1,5 @@
1
1
  import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
- import { createServiceProtocol, type ServiceProtocol } from "../../src/protocol/service-protocol";
2
+ import { createServiceProtocol, type ServiceProtocol } from "../../src/protocol/create-service-protocol";
3
3
  import type { ServiceMessage } from "../../src/protocol/protocol.types";
4
4
  import { Uuid } from "@simplysm/core-common";
5
5
 
@@ -1,3 +0,0 @@
1
- export type { ServiceProtocol, ServiceMessageDecodeResult } from "./create-service-protocol";
2
- export { createServiceProtocol } from "./create-service-protocol";
3
- //# sourceMappingURL=service-protocol.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"service-protocol.d.ts","sourceRoot":"","sources":["..\\..\\src\\protocol\\service-protocol.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,eAAe,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AAC7F,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC"}
@@ -1,5 +0,0 @@
1
- import { createServiceProtocol } from "./create-service-protocol.js";
2
- export {
3
- createServiceProtocol
4
- };
5
- //# sourceMappingURL=service-protocol.js.map
@@ -1,6 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/protocol/service-protocol.ts"],
4
- "mappings": "AACA,SAAS,6BAA6B;",
5
- "names": []
6
- }
@@ -1,2 +0,0 @@
1
- export type { ServiceProtocol, ServiceMessageDecodeResult } from "./create-service-protocol";
2
- export { createServiceProtocol } from "./create-service-protocol";