@spinajs/http-socket-client 0.0.0-stage → 3.0.0

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.
Files changed (134) hide show
  1. package/README.md +129 -2
  2. package/lib/cjs/browser.d.ts +4 -0
  3. package/lib/cjs/browser.d.ts.map +1 -0
  4. package/lib/cjs/browser.js +21 -0
  5. package/lib/cjs/browser.js.map +1 -0
  6. package/lib/cjs/client.d.ts +94 -0
  7. package/lib/cjs/client.d.ts.map +1 -0
  8. package/lib/cjs/client.js +139 -0
  9. package/lib/cjs/client.js.map +1 -0
  10. package/lib/cjs/commands.d.ts +30 -0
  11. package/lib/cjs/commands.d.ts.map +1 -0
  12. package/lib/cjs/commands.js +132 -0
  13. package/lib/cjs/commands.js.map +1 -0
  14. package/lib/cjs/connection.d.ts +71 -0
  15. package/lib/cjs/connection.d.ts.map +1 -0
  16. package/lib/cjs/connection.js +233 -0
  17. package/lib/cjs/connection.js.map +1 -0
  18. package/lib/cjs/contract.d.ts +27 -0
  19. package/lib/cjs/contract.d.ts.map +1 -0
  20. package/lib/cjs/contract.js +3 -0
  21. package/lib/cjs/contract.js.map +1 -0
  22. package/lib/cjs/durable.d.ts +122 -0
  23. package/lib/cjs/durable.d.ts.map +1 -0
  24. package/lib/cjs/durable.js +396 -0
  25. package/lib/cjs/durable.js.map +1 -0
  26. package/lib/cjs/emitter.d.ts +22 -0
  27. package/lib/cjs/emitter.d.ts.map +1 -0
  28. package/lib/cjs/emitter.js +82 -0
  29. package/lib/cjs/emitter.js.map +1 -0
  30. package/lib/cjs/ids.d.ts +7 -0
  31. package/lib/cjs/ids.d.ts.map +1 -0
  32. package/lib/cjs/ids.js +11 -0
  33. package/lib/cjs/ids.js.map +1 -0
  34. package/lib/cjs/index.d.ts +17 -0
  35. package/lib/cjs/index.d.ts.map +1 -0
  36. package/lib/cjs/index.js +36 -0
  37. package/lib/cjs/index.js.map +1 -0
  38. package/lib/cjs/node/file-outbox.d.ts +40 -0
  39. package/lib/cjs/node/file-outbox.d.ts.map +1 -0
  40. package/lib/cjs/node/file-outbox.js +234 -0
  41. package/lib/cjs/node/file-outbox.js.map +1 -0
  42. package/lib/cjs/node/index.d.ts +4 -0
  43. package/lib/cjs/node/index.d.ts.map +1 -0
  44. package/lib/cjs/node/index.js +21 -0
  45. package/lib/cjs/node/index.js.map +1 -0
  46. package/lib/cjs/outbox-indexeddb.d.ts +38 -0
  47. package/lib/cjs/outbox-indexeddb.d.ts.map +1 -0
  48. package/lib/cjs/outbox-indexeddb.js +212 -0
  49. package/lib/cjs/outbox-indexeddb.js.map +1 -0
  50. package/lib/cjs/outbox.d.ts +53 -0
  51. package/lib/cjs/outbox.d.ts.map +1 -0
  52. package/lib/cjs/outbox.js +41 -0
  53. package/lib/cjs/outbox.js.map +1 -0
  54. package/lib/cjs/package.json +1 -0
  55. package/lib/cjs/reconnect.d.ts +21 -0
  56. package/lib/cjs/reconnect.d.ts.map +1 -0
  57. package/lib/cjs/reconnect.js +37 -0
  58. package/lib/cjs/reconnect.js.map +1 -0
  59. package/lib/cjs/streams.d.ts +91 -0
  60. package/lib/cjs/streams.d.ts.map +1 -0
  61. package/lib/cjs/streams.js +302 -0
  62. package/lib/cjs/streams.js.map +1 -0
  63. package/lib/cjs/timeout.d.ts +4 -0
  64. package/lib/cjs/timeout.d.ts.map +1 -0
  65. package/lib/cjs/timeout.js +13 -0
  66. package/lib/cjs/timeout.js.map +1 -0
  67. package/lib/mjs/browser.d.ts +4 -0
  68. package/lib/mjs/browser.d.ts.map +1 -0
  69. package/lib/mjs/browser.js +3 -0
  70. package/lib/mjs/browser.js.map +1 -0
  71. package/lib/mjs/client.d.ts +94 -0
  72. package/lib/mjs/client.d.ts.map +1 -0
  73. package/lib/mjs/client.js +135 -0
  74. package/lib/mjs/client.js.map +1 -0
  75. package/lib/mjs/commands.d.ts +30 -0
  76. package/lib/mjs/commands.d.ts.map +1 -0
  77. package/lib/mjs/commands.js +128 -0
  78. package/lib/mjs/commands.js.map +1 -0
  79. package/lib/mjs/connection.d.ts +71 -0
  80. package/lib/mjs/connection.d.ts.map +1 -0
  81. package/lib/mjs/connection.js +229 -0
  82. package/lib/mjs/connection.js.map +1 -0
  83. package/lib/mjs/contract.d.ts +27 -0
  84. package/lib/mjs/contract.d.ts.map +1 -0
  85. package/lib/mjs/contract.js +2 -0
  86. package/lib/mjs/contract.js.map +1 -0
  87. package/lib/mjs/durable.d.ts +122 -0
  88. package/lib/mjs/durable.d.ts.map +1 -0
  89. package/lib/mjs/durable.js +392 -0
  90. package/lib/mjs/durable.js.map +1 -0
  91. package/lib/mjs/emitter.d.ts +22 -0
  92. package/lib/mjs/emitter.d.ts.map +1 -0
  93. package/lib/mjs/emitter.js +77 -0
  94. package/lib/mjs/emitter.js.map +1 -0
  95. package/lib/mjs/ids.d.ts +7 -0
  96. package/lib/mjs/ids.d.ts.map +1 -0
  97. package/lib/mjs/ids.js +8 -0
  98. package/lib/mjs/ids.js.map +1 -0
  99. package/lib/mjs/index.d.ts +17 -0
  100. package/lib/mjs/index.d.ts.map +1 -0
  101. package/lib/mjs/index.js +9 -0
  102. package/lib/mjs/index.js.map +1 -0
  103. package/lib/mjs/node/file-outbox.d.ts +40 -0
  104. package/lib/mjs/node/file-outbox.d.ts.map +1 -0
  105. package/lib/mjs/node/file-outbox.js +230 -0
  106. package/lib/mjs/node/file-outbox.js.map +1 -0
  107. package/lib/mjs/node/index.d.ts +4 -0
  108. package/lib/mjs/node/index.d.ts.map +1 -0
  109. package/lib/mjs/node/index.js +3 -0
  110. package/lib/mjs/node/index.js.map +1 -0
  111. package/lib/mjs/outbox-indexeddb.d.ts +38 -0
  112. package/lib/mjs/outbox-indexeddb.d.ts.map +1 -0
  113. package/lib/mjs/outbox-indexeddb.js +208 -0
  114. package/lib/mjs/outbox-indexeddb.js.map +1 -0
  115. package/lib/mjs/outbox.d.ts +53 -0
  116. package/lib/mjs/outbox.d.ts.map +1 -0
  117. package/lib/mjs/outbox.js +37 -0
  118. package/lib/mjs/outbox.js.map +1 -0
  119. package/lib/mjs/package.json +1 -0
  120. package/lib/mjs/reconnect.d.ts +21 -0
  121. package/lib/mjs/reconnect.d.ts.map +1 -0
  122. package/lib/mjs/reconnect.js +33 -0
  123. package/lib/mjs/reconnect.js.map +1 -0
  124. package/lib/mjs/streams.d.ts +91 -0
  125. package/lib/mjs/streams.d.ts.map +1 -0
  126. package/lib/mjs/streams.js +297 -0
  127. package/lib/mjs/streams.js.map +1 -0
  128. package/lib/mjs/timeout.d.ts +4 -0
  129. package/lib/mjs/timeout.d.ts.map +1 -0
  130. package/lib/mjs/timeout.js +9 -0
  131. package/lib/mjs/timeout.js.map +1 -0
  132. package/lib/tsconfig.cjs.tsbuildinfo +1 -0
  133. package/lib/tsconfig.mjs.tsbuildinfo +1 -0
  134. package/package.json +67 -4
@@ -0,0 +1,94 @@
1
+ import { type ContractShape, type SocketContract, type SocketError } from '@spinajs/http-socket-common';
2
+ import { type CommandOptions } from './commands.js';
3
+ import { type AuthProvider, type ConnectionState, type IoOptions } from './connection.js';
4
+ import type { TypedSocketClient } from './contract.js';
5
+ import { type AckedCommand, type DurableCommandOptions, type DurableOptions, type FailedCommand, type HeldCommand } from './durable.js';
6
+ import { type OutboxStore } from './outbox.js';
7
+ import type { ReconnectOptions } from './reconnect.js';
8
+ import { type StreamOptions } from './streams.js';
9
+ export interface SocketClientOptions {
10
+ /** Server origin; a path in it selects a socket.io namespace. */
11
+ url: string;
12
+ /** socket.io endpoint path (socket.io's default: '/socket.io'). */
13
+ path?: string;
14
+ /** Asked on every (re)connect; its fields go into the handshake. */
15
+ auth?: AuthProvider;
16
+ /** Stable per install, persisted by the app; 1 to MAX_ID_LENGTH printable ASCII characters. Generated when omitted. */
17
+ clientId?: string;
18
+ reconnect?: Partial<ReconnectOptions>;
19
+ defaultTimeoutMs?: number;
20
+ connectTimeoutMs?: number;
21
+ autoConnect?: boolean;
22
+ /** Passed to socket.io-client; reconnection, autoConnect, forceNew, retries and auth stay owned by the client. */
23
+ io?: IoOptions;
24
+ /**
25
+ * Where durable commands wait for their reply. The MemoryOutboxStore default does not survive a reload: browsers pass
26
+ * IndexedDbOutboxStore ( `/browser` ), Node passes FileOutboxStore ( `/node` ). Requires an explicit `clientId`.
27
+ */
28
+ outbox?: OutboxStore;
29
+ durable?: DurableOptions;
30
+ onListenerError?: (error: unknown) => void;
31
+ }
32
+ export interface ClientLifecycleEvents {
33
+ state: (state: ConnectionState, previous: ConnectionState) => void;
34
+ auth_required: (error: SocketError) => void;
35
+ incompatible: (error: SocketError) => void;
36
+ /** The server refused the connection for a reason no retry can fix (forbidden, invalid_argument …); connect() tries again. */
37
+ refused: (error: SocketError) => void;
38
+ /** A durable command was acknowledged; also for commands resumed from the outbox after a reload. In send order. */
39
+ acked: (event: AckedCommand) => void;
40
+ /** A durable command the server refused for good; it is in the outbox's failed list. In send order. */
41
+ failed: (event: FailedCommand) => void;
42
+ /** A durable command was refused as unauthenticated and stays queued; the queue sends nothing until the connection comes online again. */
43
+ held: (event: HeldCommand) => void;
44
+ }
45
+ export type LifecycleEventName = keyof ClientLifecycleEvents;
46
+ /** Names `on()` routes to client lifecycle listeners; server events with these names are unreachable. */
47
+ export declare const LIFECYCLE_EVENTS: ReadonlySet<string>;
48
+ export type ServerEventListener<T = unknown> = (payload: T) => void;
49
+ export type Unsubscribe = () => void;
50
+ export declare class SocketClient {
51
+ readonly clientId: string;
52
+ private readonly connection;
53
+ private readonly commands;
54
+ private readonly durableQueue;
55
+ private readonly streams;
56
+ private readonly lifecycle;
57
+ private readonly serverEvents;
58
+ private controlled;
59
+ constructor(options: SocketClientOptions);
60
+ private autoConnect;
61
+ get state(): ConnectionState;
62
+ connect(): void;
63
+ /** Goes offline and stops reconnecting until connect(). */
64
+ disconnect(): void;
65
+ /**
66
+ * Terminal: rejects pending commands and releases the socket. Resolves once the outbox has no write of this
67
+ * client in flight and every answered durable command has been reported: await it before opening the next
68
+ * client or store on the same outbox, and keep the `acked` / `failed` listeners until then.
69
+ * The outbox store is not closed: call `store.close()` yourself to release its lock and connection before reopening the same name.
70
+ */
71
+ close(): Promise<void>;
72
+ /** The same client, typed by a contract shared with the server; no runtime cost. */
73
+ typed<C extends ContractShape>(_contract: SocketContract<C>): TypedSocketClient<C>;
74
+ command<R = unknown>(name: string, payload?: unknown, options?: CommandOptions): Promise<R>;
75
+ /**
76
+ * Persisted, ordered and retried until the server answers ( spec §6 ); the server command must be idempotent; `ordered: 'client'` is optional, the `after` fence alone orders execution.
77
+ * With the default MemoryOutboxStore the queue is lost on reload; pass `outbox` ( IndexedDbOutboxStore in browsers, FileOutboxStore in Node ) to keep it.
78
+ */
79
+ durable<R = unknown>(name: string, payload?: unknown, options?: DurableCommandOptions): Promise<R>;
80
+ /**
81
+ * A stream reply as an async iterator. The request goes out on the first `next()`; at most
82
+ * `credits` chunks are in flight or buffered; `break` cancels it on the server.
83
+ */
84
+ stream<T = unknown>(name: string, payload?: unknown, options?: StreamOptions): AsyncIterableIterator<T>;
85
+ /** Fire-and-forget event to the server; returns false and drops it when not online. */
86
+ emit(name: string, payload?: unknown): boolean;
87
+ on<K extends LifecycleEventName>(event: K, listener: ClientLifecycleEvents[K]): Unsubscribe;
88
+ on<T = unknown>(event: string, listener: ServerEventListener<T>): Unsubscribe;
89
+ once<K extends LifecycleEventName>(event: K, listener: ClientLifecycleEvents[K]): Unsubscribe;
90
+ once<T = unknown>(event: string, listener: ServerEventListener<T>): Unsubscribe;
91
+ off<K extends LifecycleEventName>(event: K, listener: ClientLifecycleEvents[K]): void;
92
+ off<T = unknown>(event: string, listener: ServerEventListener<T>): void;
93
+ }
94
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,135 @@
1
+ import { WIRE_EVENTS } from '@spinajs/http-socket-common';
2
+ import { CommandDispatcher, DEFAULT_TIMEOUT_MS } from './commands.js';
3
+ import { Connection } from './connection.js';
4
+ import { DurableQueue } from './durable.js';
5
+ import { Emitter, rethrowAsync } from './emitter.js';
6
+ import { randomId } from './ids.js';
7
+ import { MemoryOutboxStore } from './outbox.js';
8
+ import { StreamDispatcher } from './streams.js';
9
+ /** Names `on()` routes to client lifecycle listeners; server events with these names are unreachable. */
10
+ export const LIFECYCLE_EVENTS = new Set(['state', 'auth_required', 'incompatible', 'refused', 'acked', 'failed', 'held']);
11
+ function isLifecycleEvent(event) {
12
+ return LIFECYCLE_EVENTS.has(event);
13
+ }
14
+ export class SocketClient {
15
+ constructor(options) {
16
+ // set once the app calls connect(), disconnect() or close(), which then override autoConnect
17
+ this.controlled = false;
18
+ const onListenerError = options.onListenerError ?? rethrowAsync;
19
+ // persisted keys are `${clientId}:…`: a fresh random id after a reload would break exactly-once and ordering
20
+ if (options.outbox !== undefined && options.clientId === undefined) {
21
+ throw new RangeError('an outbox requires a stable clientId, persisted by the app');
22
+ }
23
+ this.clientId = options.clientId ?? randomId();
24
+ this.lifecycle = new Emitter(onListenerError);
25
+ this.serverEvents = new Emitter(onListenerError);
26
+ this.connection = new Connection({
27
+ url: options.url,
28
+ path: options.path,
29
+ clientId: this.clientId,
30
+ auth: options.auth,
31
+ reconnect: options.reconnect,
32
+ connectTimeoutMs: options.connectTimeoutMs,
33
+ io: options.io,
34
+ onListenerError,
35
+ });
36
+ try {
37
+ this.commands = new CommandDispatcher(this.connection, options.defaultTimeoutMs ?? DEFAULT_TIMEOUT_MS);
38
+ this.durableQueue = new DurableQueue({
39
+ connection: this.connection,
40
+ commands: this.commands,
41
+ store: options.outbox ?? new MemoryOutboxStore(),
42
+ clientId: this.clientId,
43
+ reconnect: options.reconnect,
44
+ durable: options.durable,
45
+ onListenerError,
46
+ });
47
+ }
48
+ catch (error) {
49
+ // invalid options must not leave a socket behind
50
+ this.connection.close();
51
+ throw error;
52
+ }
53
+ this.durableQueue.events.on('acked', (event) => this.lifecycle.emit('acked', event));
54
+ this.durableQueue.events.on('failed', (event) => this.lifecycle.emit('failed', event));
55
+ this.durableQueue.events.on('held', (event) => this.lifecycle.emit('held', event));
56
+ this.streams = new StreamDispatcher(this.connection, () => this.commands.nextId(), options.defaultTimeoutMs ?? DEFAULT_TIMEOUT_MS);
57
+ this.connection.events.on('state', (state, previous) => this.lifecycle.emit('state', state, previous));
58
+ this.connection.events.on('auth_required', (error) => this.lifecycle.emit('auth_required', error));
59
+ this.connection.events.on('incompatible', (error) => this.lifecycle.emit('incompatible', error));
60
+ this.connection.events.on('refused', (error) => this.lifecycle.emit('refused', error));
61
+ this.connection.listen(WIRE_EVENTS.event, (frame) => {
62
+ if (typeof frame?.name === 'string')
63
+ this.serverEvents.emit(frame.name, frame.payload);
64
+ });
65
+ // a microtask, so listeners attached right after construction still see 'connecting'
66
+ if (options.autoConnect !== false)
67
+ queueMicrotask(() => this.autoConnect());
68
+ }
69
+ autoConnect() {
70
+ if (!this.controlled)
71
+ this.connection.connect();
72
+ }
73
+ get state() {
74
+ return this.connection.state;
75
+ }
76
+ connect() {
77
+ this.controlled = true;
78
+ this.connection.connect();
79
+ }
80
+ /** Goes offline and stops reconnecting until connect(). */
81
+ disconnect() {
82
+ this.controlled = true;
83
+ this.connection.disconnect();
84
+ }
85
+ /**
86
+ * Terminal: rejects pending commands and releases the socket. Resolves once the outbox has no write of this
87
+ * client in flight and every answered durable command has been reported: await it before opening the next
88
+ * client or store on the same outbox, and keep the `acked` / `failed` listeners until then.
89
+ * The outbox store is not closed: call `store.close()` yourself to release its lock and connection before reopening the same name.
90
+ */
91
+ close() {
92
+ this.controlled = true;
93
+ this.connection.close();
94
+ return this.durableQueue.close();
95
+ }
96
+ /** The same client, typed by a contract shared with the server; no runtime cost. */
97
+ typed(_contract) {
98
+ return this;
99
+ }
100
+ command(name, payload, options) {
101
+ return this.commands.execute(name, payload, options);
102
+ }
103
+ /**
104
+ * Persisted, ordered and retried until the server answers ( spec §6 ); the server command must be idempotent; `ordered: 'client'` is optional, the `after` fence alone orders execution.
105
+ * With the default MemoryOutboxStore the queue is lost on reload; pass `outbox` ( IndexedDbOutboxStore in browsers, FileOutboxStore in Node ) to keep it.
106
+ */
107
+ durable(name, payload, options) {
108
+ return this.durableQueue.submit(name, payload, options);
109
+ }
110
+ /**
111
+ * A stream reply as an async iterator. The request goes out on the first `next()`; at most
112
+ * `credits` chunks are in flight or buffered; `break` cancels it on the server.
113
+ */
114
+ stream(name, payload, options) {
115
+ return this.streams.stream(name, payload, options);
116
+ }
117
+ /** Fire-and-forget event to the server; returns false and drops it when not online. */
118
+ emit(name, payload) {
119
+ const frame = { name, payload };
120
+ return this.connection.send(WIRE_EVENTS.event, frame);
121
+ }
122
+ on(event, listener) {
123
+ return isLifecycleEvent(event) ? this.lifecycle.on(event, listener) : this.serverEvents.on(event, listener);
124
+ }
125
+ once(event, listener) {
126
+ return isLifecycleEvent(event) ? this.lifecycle.once(event, listener) : this.serverEvents.once(event, listener);
127
+ }
128
+ off(event, listener) {
129
+ if (isLifecycleEvent(event))
130
+ this.lifecycle.off(event, listener);
131
+ else
132
+ this.serverEvents.off(event, listener);
133
+ }
134
+ }
135
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import type { Connection } from './connection.js';
2
+ export type WhenOffline = 'fail' | 'wait';
3
+ export interface CommandOptions {
4
+ /** Budget for the whole call: the wait for a connection (whenOffline 'wait') and for the reply. */
5
+ timeoutMs?: number;
6
+ signal?: AbortSignal;
7
+ whenOffline?: WhenOffline;
8
+ /** W3C trace context, carried into the server handler. */
9
+ traceparent?: string;
10
+ }
11
+ export declare const DEFAULT_TIMEOUT_MS = 15000;
12
+ /** Plain (non-durable) commands: one attempt each, never re-sent. */
13
+ export declare class CommandDispatcher {
14
+ private readonly connection;
15
+ private readonly defaultTimeoutMs;
16
+ private seq;
17
+ private readonly waiting;
18
+ private readonly inFlight;
19
+ constructor(connection: Connection, defaultTimeoutMs?: number);
20
+ /** Unique per client instance; durable and stream requests take ids from here too. */
21
+ nextId(): string;
22
+ execute(name: string, payload: unknown, options?: CommandOptions): Promise<unknown>;
23
+ private transmit;
24
+ private onReply;
25
+ private onState;
26
+ private succeed;
27
+ private fail;
28
+ private finish;
29
+ }
30
+ //# sourceMappingURL=commands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/commands.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAmB,MAAM,iBAAiB,CAAC;AAGnE,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,MAAM,CAAC;AAE1C,MAAM,WAAW,cAAc;IAC7B,mGAAmG;IACnG,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,0DAA0D;IAC1D,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,eAAO,MAAM,kBAAkB,QAAS,CAAC;AAuBzC,qEAAqE;AACrE,qBAAa,iBAAiB;IAMhB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAAc,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IALtF,OAAO,CAAC,GAAG,CAAK;IAEhB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA6B;IACrD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA6B;IAEtD,YAA6B,UAAU,EAAE,UAAU,EAAmB,gBAAgB,GAAE,MAA2B,EAGlH;IAED,sFAAsF;IAC/E,MAAM,IAAI,MAAM,CAEtB;IAEM,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,OAAO,CAAC,CAwC7F;IAED,OAAO,CAAC,QAAQ;IAUhB,OAAO,CAAC,OAAO;IAQf,OAAO,CAAC,OAAO;IASf,OAAO,CAAC,OAAO;IAIf,OAAO,CAAC,IAAI;IAIZ,OAAO,CAAC,MAAM;CAQf"}
@@ -0,0 +1,128 @@
1
+ import { SocketException, WIRE_EVENTS, isSocketError } from '@spinajs/http-socket-common';
2
+ import { assertTimeoutMs } from './timeout.js';
3
+ export const DEFAULT_TIMEOUT_MS = 15_000;
4
+ const CLOSED = { code: 'unavailable', message: 'the client is closed', retryable: false };
5
+ const OFFLINE = { code: 'unavailable', message: 'the client is offline', retryable: true };
6
+ const STAYED_OFFLINE = { code: 'unavailable', message: 'the client stayed offline until the timeout', retryable: true };
7
+ const CONNECTION_LOST = { code: 'unavailable', message: 'the connection dropped before the reply', retryable: true };
8
+ const NO_REPLY = { code: 'deadline_exceeded', message: 'no reply before the timeout', retryable: true };
9
+ const CANCELLED = { code: 'cancelled', message: 'the command was cancelled', retryable: false };
10
+ const STREAM_REPLY = { code: 'failed_precondition', message: 'the command replies with a stream; use stream()', retryable: false };
11
+ const MALFORMED_REPLY = { code: 'internal', message: 'malformed reply', retryable: false };
12
+ /** Plain (non-durable) commands: one attempt each, never re-sent. */
13
+ export class CommandDispatcher {
14
+ constructor(connection, defaultTimeoutMs = DEFAULT_TIMEOUT_MS) {
15
+ this.connection = connection;
16
+ this.defaultTimeoutMs = defaultTimeoutMs;
17
+ this.seq = 0;
18
+ // insertion-ordered, so commands held while offline go out in call order
19
+ this.waiting = new Set();
20
+ this.inFlight = new Set();
21
+ assertTimeoutMs('defaultTimeoutMs', defaultTimeoutMs);
22
+ connection.events.on('state', (state, previous) => this.onState(state, previous));
23
+ }
24
+ /** Unique per client instance; durable and stream requests take ids from here too. */
25
+ nextId() {
26
+ return (++this.seq).toString(36);
27
+ }
28
+ execute(name, payload, options = {}) {
29
+ const timeoutMs = options.timeoutMs ?? this.defaultTimeoutMs;
30
+ try {
31
+ assertTimeoutMs('timeoutMs', timeoutMs);
32
+ }
33
+ catch (error) {
34
+ return Promise.reject(error);
35
+ }
36
+ if (this.connection.state === 'closed')
37
+ return rejected(CLOSED);
38
+ if (options.signal?.aborted)
39
+ return rejected(CANCELLED);
40
+ if (!this.connection.connected && (options.whenOffline ?? 'fail') === 'fail')
41
+ return rejected(OFFLINE);
42
+ const request = { id: this.nextId(), name, payload };
43
+ if (options.traceparent !== undefined)
44
+ request.traceparent = options.traceparent;
45
+ const signal = options.signal;
46
+ return new Promise((resolve, reject) => {
47
+ const onAbort = () => {
48
+ if (command.sent) {
49
+ const cancel = { id: request.id };
50
+ this.connection.send(WIRE_EVENTS.cancel, cancel);
51
+ }
52
+ this.fail(command, CANCELLED);
53
+ };
54
+ const timer = setTimeout(() => this.fail(command, command.sent ? NO_REPLY : STAYED_OFFLINE), timeoutMs);
55
+ const command = {
56
+ request,
57
+ deadlineAt: Date.now() + timeoutMs,
58
+ sent: false,
59
+ done: false,
60
+ resolve,
61
+ reject,
62
+ dispose: () => {
63
+ clearTimeout(timer);
64
+ signal?.removeEventListener('abort', onAbort);
65
+ },
66
+ };
67
+ signal?.addEventListener('abort', onAbort, { once: true });
68
+ if (this.connection.connected)
69
+ this.transmit(command);
70
+ else
71
+ this.waiting.add(command);
72
+ });
73
+ }
74
+ transmit(command) {
75
+ this.waiting.delete(command);
76
+ // relative, so client/server clock skew cannot expire it; the server ignores a deadline <= 0
77
+ command.request.deadline = Math.max(1, command.deadlineAt - Date.now());
78
+ command.sent = true;
79
+ this.inFlight.add(command);
80
+ const sent = this.connection.request(WIRE_EVENTS.command, command.request, (reply) => this.onReply(command, reply));
81
+ if (!sent)
82
+ this.fail(command, CONNECTION_LOST);
83
+ }
84
+ onReply(command, reply) {
85
+ if (typeof reply !== 'object' || reply === null || typeof reply.ok !== 'boolean')
86
+ return this.fail(command, MALFORMED_REPLY);
87
+ if (!reply.ok)
88
+ return this.fail(command, isSocketError(reply.error) ? reply.error : MALFORMED_REPLY);
89
+ // a CommandStreamReply: the result follows as stream frames, which only stream() consumes
90
+ if ('stream' in reply)
91
+ return this.fail(command, STREAM_REPLY);
92
+ this.succeed(command, reply.result);
93
+ }
94
+ onState(state, previous) {
95
+ if (state === 'closed') {
96
+ for (const command of [...this.waiting, ...this.inFlight])
97
+ this.fail(command, CLOSED);
98
+ return;
99
+ }
100
+ if (previous === 'online')
101
+ for (const command of [...this.inFlight])
102
+ this.fail(command, CONNECTION_LOST);
103
+ if (state === 'online')
104
+ for (const command of [...this.waiting])
105
+ this.transmit(command);
106
+ }
107
+ succeed(command, value) {
108
+ if (this.finish(command))
109
+ command.resolve(value);
110
+ }
111
+ fail(command, error) {
112
+ if (this.finish(command))
113
+ command.reject(SocketException.fromWire(error));
114
+ }
115
+ finish(command) {
116
+ if (command.done)
117
+ return false;
118
+ command.done = true;
119
+ command.dispose();
120
+ this.waiting.delete(command);
121
+ this.inFlight.delete(command);
122
+ return true;
123
+ }
124
+ }
125
+ function rejected(error) {
126
+ return Promise.reject(SocketException.fromWire(error));
127
+ }
128
+ //# sourceMappingURL=commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.js","sourceRoot":"","sources":["../../src/commands.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,71 @@
1
+ import { type ManagerOptions, type SocketOptions } from 'socket.io-client';
2
+ import { type SocketError } from '@spinajs/http-socket-common';
3
+ import { Emitter } from './emitter.js';
4
+ import { type ReconnectOptions } from './reconnect.js';
5
+ export type ConnectionState = 'connecting' | 'online' | 'offline' | 'closed';
6
+ export interface AuthPayload {
7
+ token?: string;
8
+ [key: string]: unknown;
9
+ }
10
+ export type AuthProvider = () => AuthPayload | Promise<AuthPayload>;
11
+ export type IoOptions = Partial<ManagerOptions & SocketOptions>;
12
+ export interface ConnectionOptions {
13
+ url: string;
14
+ path?: string;
15
+ clientId: string;
16
+ auth?: AuthProvider;
17
+ reconnect?: Partial<ReconnectOptions>;
18
+ connectTimeoutMs?: number;
19
+ io?: IoOptions;
20
+ onListenerError?: (error: unknown) => void;
21
+ }
22
+ export interface ConnectionEvents {
23
+ state: (state: ConnectionState, previous: ConnectionState) => void;
24
+ auth_required: (error: SocketError) => void;
25
+ incompatible: (error: SocketError) => void;
26
+ refused: (error: SocketError) => void;
27
+ }
28
+ export declare const DEFAULT_CONNECT_TIMEOUT_MS = 20000;
29
+ /**
30
+ * Sole owner of the socket.io socket: state machine, handshake, reconnect and stop conditions.
31
+ * Commands, durable commands and streams use it and never touch socket.io directly.
32
+ */
33
+ export declare class Connection {
34
+ private readonly options;
35
+ readonly events: Emitter<ConnectionEvents>;
36
+ private readonly socket;
37
+ private readonly policy;
38
+ private readonly connectTimeoutMs;
39
+ private current;
40
+ private stopped;
41
+ private attempt;
42
+ private attemptId;
43
+ private retryAfterMs;
44
+ private kickCode;
45
+ private retryTimer;
46
+ private connectTimer;
47
+ constructor(options: ConnectionOptions);
48
+ get state(): ConnectionState;
49
+ get connected(): boolean;
50
+ connect(): void;
51
+ disconnect(): void;
52
+ close(): void;
53
+ send(event: string, ...args: unknown[]): boolean;
54
+ request<R>(event: string, data: unknown, onReply: (reply: R) => void): boolean;
55
+ listen(event: string, handler: (...args: any[]) => void): () => void;
56
+ private open;
57
+ private provideAuth;
58
+ private onConnect;
59
+ private onConnectError;
60
+ private onDisconnect;
61
+ private onEventFrame;
62
+ private onConnectTimeout;
63
+ private haltFor;
64
+ private halt;
65
+ private scheduleRetry;
66
+ private abortAttempt;
67
+ private clearTimers;
68
+ private clearConnectTimer;
69
+ private setState;
70
+ }
71
+ //# sourceMappingURL=connection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../../src/connection.ts"],"names":[],"mappings":"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"}