@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,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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"}
@@ -0,0 +1,233 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Connection = exports.DEFAULT_CONNECT_TIMEOUT_MS = void 0;
4
+ const socket_io_client_1 = require("socket.io-client");
5
+ const http_socket_common_1 = require("@spinajs/http-socket-common");
6
+ const emitter_js_1 = require("./emitter.js");
7
+ const timeout_js_1 = require("./timeout.js");
8
+ const reconnect_js_1 = require("./reconnect.js");
9
+ exports.DEFAULT_CONNECT_TIMEOUT_MS = 20_000;
10
+ /**
11
+ * Sole owner of the socket.io socket: state machine, handshake, reconnect and stop conditions.
12
+ * Commands, durable commands and streams use it and never touch socket.io directly.
13
+ */
14
+ class Connection {
15
+ constructor(options) {
16
+ this.options = options;
17
+ this.current = 'offline';
18
+ // no automatic attempt may start: before connect(), after disconnect()/close(), after a fatal refusal
19
+ this.stopped = true;
20
+ this.attempt = 0;
21
+ // bumped whenever an attempt is abandoned, so a late auth callback cannot revive it
22
+ this.attemptId = 0;
23
+ // the server refuses such a handshake with invalid_argument, which no retry can fix
24
+ if (!(0, http_socket_common_1.isId)(options.clientId)) {
25
+ throw new RangeError(`clientId must be 1-${http_socket_common_1.MAX_ID_LENGTH} printable ASCII characters`);
26
+ }
27
+ this.events = new emitter_js_1.Emitter(options.onListenerError);
28
+ this.policy = new reconnect_js_1.ReconnectPolicy(options.reconnect);
29
+ this.connectTimeoutMs = (0, timeout_js_1.assertTimeoutMs)('connectTimeoutMs', options.connectTimeoutMs ?? exports.DEFAULT_CONNECT_TIMEOUT_MS);
30
+ this.socket = (0, socket_io_client_1.io)(options.url, {
31
+ ...options.io,
32
+ ...(options.path !== undefined ? { path: options.path } : {}),
33
+ autoConnect: false,
34
+ // socket.io's Manager does not retry refused handshakes or server disconnects and cannot
35
+ // honour retryAfterMs; one policy here covers all of them. Reusing this one Socket keeps its
36
+ // pid/offset, which connection state recovery needs.
37
+ reconnection: false,
38
+ // a Manager multiplexed with another client to the same URL would share its failures and closes
39
+ forceNew: true,
40
+ // socket.io's packet retries would re-send commands without idempotency keys
41
+ retries: 0,
42
+ auth: (cb) => this.provideAuth(cb),
43
+ });
44
+ this.socket.on('connect', () => this.onConnect());
45
+ this.socket.on('connect_error', (error) => this.onConnectError(error));
46
+ this.socket.on('disconnect', (reason) => this.onDisconnect(reason));
47
+ this.socket.on(http_socket_common_1.WIRE_EVENTS.event, (frame) => this.onEventFrame(frame));
48
+ }
49
+ get state() {
50
+ return this.current;
51
+ }
52
+ get connected() {
53
+ return this.current === 'online' && this.socket.connected;
54
+ }
55
+ connect() {
56
+ if (this.current === 'closed')
57
+ throw new Error('the client is closed');
58
+ this.stopped = false;
59
+ this.kickCode = undefined;
60
+ if (this.current !== 'offline')
61
+ return;
62
+ this.retryAfterMs = undefined;
63
+ this.attempt = 0;
64
+ this.clearTimers();
65
+ this.open();
66
+ }
67
+ disconnect() {
68
+ if (this.current === 'closed')
69
+ return;
70
+ this.stopped = true;
71
+ this.abortAttempt();
72
+ this.setState('offline');
73
+ }
74
+ close() {
75
+ if (this.current === 'closed')
76
+ return;
77
+ this.stopped = true;
78
+ this.setState('closed');
79
+ this.abortAttempt();
80
+ }
81
+ send(event, ...args) {
82
+ if (!this.connected)
83
+ return false;
84
+ this.socket.emit(event, ...args);
85
+ return true;
86
+ }
87
+ request(event, data, onReply) {
88
+ if (!this.connected)
89
+ return false;
90
+ this.socket.emit(event, data, onReply);
91
+ return true;
92
+ }
93
+ listen(event, handler) {
94
+ this.socket.on(event, handler);
95
+ return () => {
96
+ this.socket.off(event, handler);
97
+ };
98
+ }
99
+ open() {
100
+ this.attemptId++;
101
+ this.setState('connecting');
102
+ // a state listener may have closed or stopped the connection
103
+ if (this.current !== 'connecting' || this.stopped)
104
+ return;
105
+ this.connectTimer = setTimeout(() => this.onConnectTimeout(), this.connectTimeoutMs);
106
+ this.socket.connect();
107
+ }
108
+ provideAuth(cb) {
109
+ const attemptId = this.attemptId;
110
+ Promise.resolve()
111
+ .then(() => this.options.auth?.())
112
+ .then((extra) => {
113
+ if (attemptId !== this.attemptId)
114
+ return;
115
+ const handshake = { ...extra, protocol: http_socket_common_1.PROTOCOL_VERSION, clientId: this.options.clientId };
116
+ cb(handshake);
117
+ }, (error) => {
118
+ if (attemptId !== this.attemptId)
119
+ return;
120
+ const reason = error instanceof Error ? error.message : String(error);
121
+ this.halt('auth_required', { code: 'unauthenticated', message: `auth callback failed: ${reason}`, retryable: false });
122
+ });
123
+ }
124
+ onConnect() {
125
+ if (this.stopped || this.current === 'closed') {
126
+ this.socket.disconnect();
127
+ return;
128
+ }
129
+ this.clearTimers();
130
+ this.attempt = 0;
131
+ this.retryAfterMs = undefined;
132
+ this.kickCode = undefined;
133
+ this.setState('online');
134
+ }
135
+ onConnectError(error) {
136
+ this.clearConnectTimer();
137
+ if (this.stopped)
138
+ return;
139
+ const data = error.data;
140
+ if ((0, http_socket_common_1.isSocketError)(data)) {
141
+ if (data.code === 'unauthenticated' || data.code === 'version_mismatch' || (data.retryable === false && data.code !== 'internal'))
142
+ return this.haltFor(data);
143
+ if (data.retryAfterMs !== undefined)
144
+ this.retryAfterMs = data.retryAfterMs;
145
+ }
146
+ this.scheduleRetry();
147
+ }
148
+ onDisconnect(reason) {
149
+ const kickCode = this.kickCode;
150
+ this.kickCode = undefined;
151
+ // socket.io re-sends what it buffered during a drop once it reconnects; only the durable
152
+ // queue may re-send a command, and only with an idempotency key
153
+ this.socket.sendBuffer = [];
154
+ if (this.current === 'closed')
155
+ return;
156
+ this.setState('offline');
157
+ if (this.stopped)
158
+ return;
159
+ // a sys.disconnect listener that wanted no reconnect has already called disconnect()
160
+ if (kickCode !== undefined && reason === 'io server disconnect') {
161
+ return this.haltFor({ code: kickCode, message: `the server disconnected the client: ${kickCode}`, retryable: false });
162
+ }
163
+ this.scheduleRetry();
164
+ }
165
+ onEventFrame(frame) {
166
+ if (frame?.name === http_socket_common_1.SYSTEM_EVENTS.disconnect) {
167
+ // W1 sends the error code of the kick as the reason
168
+ const reason = frame.payload?.reason;
169
+ this.kickCode = (0, http_socket_common_1.isErrorCode)(reason) && reason !== 'internal' && !http_socket_common_1.DEFAULT_RETRYABLE[reason] ? reason : undefined;
170
+ return;
171
+ }
172
+ if (frame?.name !== http_socket_common_1.SYSTEM_EVENTS.shutdown)
173
+ return;
174
+ const retryAfterMs = frame.payload?.retryAfterMs;
175
+ if (typeof retryAfterMs === 'number')
176
+ this.retryAfterMs = retryAfterMs;
177
+ }
178
+ onConnectTimeout() {
179
+ this.connectTimer = undefined;
180
+ this.abortAttempt();
181
+ this.scheduleRetry();
182
+ }
183
+ haltFor(error) {
184
+ this.halt(error.code === 'unauthenticated' ? 'auth_required' : error.code === 'version_mismatch' ? 'incompatible' : 'refused', error);
185
+ }
186
+ halt(event, error) {
187
+ this.stopped = true;
188
+ this.abortAttempt();
189
+ this.setState('offline');
190
+ this.events.emit(event, error);
191
+ }
192
+ scheduleRetry() {
193
+ this.clearTimers();
194
+ this.setState('offline');
195
+ // a state listener may have closed or stopped the connection
196
+ if (this.current !== 'offline' || this.stopped)
197
+ return;
198
+ const delay = this.policy.delay(this.attempt++, this.retryAfterMs);
199
+ this.retryAfterMs = undefined;
200
+ this.retryTimer = setTimeout(() => {
201
+ this.retryTimer = undefined;
202
+ if (!this.stopped && this.current === 'offline')
203
+ this.open();
204
+ }, delay);
205
+ }
206
+ abortAttempt() {
207
+ this.attemptId++;
208
+ this.clearTimers();
209
+ this.socket.disconnect();
210
+ }
211
+ clearTimers() {
212
+ this.clearConnectTimer();
213
+ if (this.retryTimer !== undefined) {
214
+ clearTimeout(this.retryTimer);
215
+ this.retryTimer = undefined;
216
+ }
217
+ }
218
+ clearConnectTimer() {
219
+ if (this.connectTimer !== undefined) {
220
+ clearTimeout(this.connectTimer);
221
+ this.connectTimer = undefined;
222
+ }
223
+ }
224
+ setState(next) {
225
+ if (this.current === next)
226
+ return;
227
+ const previous = this.current;
228
+ this.current = next;
229
+ this.events.emit('state', next, previous);
230
+ }
231
+ }
232
+ exports.Connection = Connection;
233
+ //# sourceMappingURL=connection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection.js","sourceRoot":"","sources":["../../src/connection.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import type { ClientEventName, ClientEventPayload, CommandName, CommandPayload, CommandResult, ContractShape, EventName, EventPayload } from '@spinajs/http-socket-common';
2
+ import type { ClientLifecycleEvents, LifecycleEventName, Unsubscribe } from './client.js';
3
+ import type { CommandOptions } from './commands.js';
4
+ import type { DurableCommandOptions } from './durable.js';
5
+ import type { ConnectionState } from './connection.js';
6
+ import type { StreamOptions } from './streams.js';
7
+ /** A stream command declares its result as AsyncIterable<Item>; stream() yields the items. */
8
+ export type StreamItem<C extends ContractShape, N extends CommandName<C>> = CommandResult<C, N> extends AsyncIterable<infer T> ? T : CommandResult<C, N>;
9
+ /** A SocketClient seen through a contract: names and payloads are checked at compile time. */
10
+ export interface TypedSocketClient<C extends ContractShape> {
11
+ readonly clientId: string;
12
+ readonly state: ConnectionState;
13
+ connect(): void;
14
+ disconnect(): void;
15
+ close(): Promise<void>;
16
+ command<N extends CommandName<C>>(name: N, payload: CommandPayload<C, N>, options?: CommandOptions): Promise<CommandResult<C, N>>;
17
+ durable<N extends CommandName<C>>(name: N, payload: CommandPayload<C, N>, options?: DurableCommandOptions): Promise<CommandResult<C, N>>;
18
+ stream<N extends CommandName<C>>(name: N, payload: CommandPayload<C, N>, options?: StreamOptions): AsyncIterableIterator<StreamItem<C, N>>;
19
+ emit<N extends ClientEventName<C>>(name: N, payload: ClientEventPayload<C, N>): boolean;
20
+ on<K extends LifecycleEventName>(event: K, listener: ClientLifecycleEvents[K]): Unsubscribe;
21
+ on<N extends EventName<C>>(event: N, listener: (payload: EventPayload<C, N>) => void): Unsubscribe;
22
+ once<K extends LifecycleEventName>(event: K, listener: ClientLifecycleEvents[K]): Unsubscribe;
23
+ once<N extends EventName<C>>(event: N, listener: (payload: EventPayload<C, N>) => void): Unsubscribe;
24
+ off<K extends LifecycleEventName>(event: K, listener: ClientLifecycleEvents[K]): void;
25
+ off<N extends EventName<C>>(event: N, listener: (payload: EventPayload<C, N>) => void): void;
26
+ }
27
+ //# sourceMappingURL=contract.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../src/contract.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=contract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract.js","sourceRoot":"","sources":["../../src/contract.ts"],"names":[],"mappings":""}
@@ -0,0 +1,122 @@
1
+ import { type SocketError } from '@spinajs/http-socket-common';
2
+ import type { CommandDispatcher } from './commands.js';
3
+ import type { Connection } from './connection.js';
4
+ import { Emitter } from './emitter.js';
5
+ import type { FailedOutboxEntry, OutboxEntry, OutboxStore } from './outbox.js';
6
+ import { type ReconnectOptions } from './reconnect.js';
7
+ export interface DurableOptions {
8
+ /** Durable commands sent and not yet answered at once. */
9
+ window?: number;
10
+ /** A command unanswered this long on a live connection is sent again; the server replays or joins it. */
11
+ ackTimeoutMs?: number;
12
+ /**
13
+ * Largest JSON-encoded payload, binary parts counted by length; the server's default limit. Checked
14
+ * before the command is persisted: one the server refuses for size would otherwise sit in the outbox.
15
+ */
16
+ maxPayloadBytes?: number;
17
+ }
18
+ export interface DurableCommandOptions {
19
+ /**
20
+ * Idempotency key, eg. an op id: 1-MAX_KEY_LENGTH printable ASCII characters, not starting with `${clientId}:`.
21
+ * When omitted, `${clientId}:${random nonce}` is generated and persisted with the entry.
22
+ */
23
+ key?: string;
24
+ }
25
+ export declare const DEFAULT_DURABLE: Readonly<Required<DurableOptions>>;
26
+ export interface AckedCommand {
27
+ entry: OutboxEntry;
28
+ result: unknown;
29
+ }
30
+ export interface FailedCommand {
31
+ entry: FailedOutboxEntry;
32
+ error: SocketError;
33
+ }
34
+ export interface HeldCommand {
35
+ entry: OutboxEntry;
36
+ error: SocketError;
37
+ }
38
+ export interface DurableEvents {
39
+ acked: (event: AckedCommand) => void;
40
+ failed: (event: FailedCommand) => void;
41
+ /**
42
+ * The server refused a command as unauthenticated: the queue sends nothing until the connection
43
+ * comes online again. After a re-login the app reconnects ( disconnect() and connect() ) when the
44
+ * server has not closed the connection itself.
45
+ */
46
+ held: (event: HeldCommand) => void;
47
+ }
48
+ export interface DurableQueueOptions {
49
+ connection: Connection;
50
+ commands: CommandDispatcher;
51
+ store: OutboxStore;
52
+ clientId: string;
53
+ reconnect?: Partial<ReconnectOptions>;
54
+ durable?: DurableOptions;
55
+ /** Gets listener errors, and store failures that no submit() call can reject with. */
56
+ onListenerError?: (error: unknown) => void;
57
+ }
58
+ /**
59
+ * Durable commands ( spec §6 ): persisted before they are sent, sent in order up to a window, sent
60
+ * again after any drop, and settled in send order. The server runs each key once and runs a command
61
+ * only after the one named in its `after`, so a resend never runs twice and never overtakes.
62
+ */
63
+ export declare class DurableQueue {
64
+ private readonly options;
65
+ readonly events: Emitter<DurableEvents>;
66
+ private readonly items;
67
+ private readonly policy;
68
+ private readonly window;
69
+ private readonly ackTimeoutMs;
70
+ private readonly maxPayloadBytes;
71
+ private readonly onStoreError;
72
+ private readonly unsubscribe;
73
+ /** generated keys start with it; app keys must not */
74
+ private readonly keyPrefix;
75
+ private loading;
76
+ private adding;
77
+ private attempt;
78
+ private pausedUntil;
79
+ private pauseTimer;
80
+ private probing;
81
+ private heldUntilOnline;
82
+ private closed;
83
+ private closing;
84
+ private onReported;
85
+ constructor(options: DurableQueueOptions);
86
+ /** Commands not yet settled to their callers, resumed ones included. */
87
+ get size(): number;
88
+ /**
89
+ * Persists the command, then sends it in order. Resolves with its result once it and every earlier
90
+ * command have settled. Rejects when the server refuses it for good ( it is then in the store's
91
+ * failed list ) or when the queue closes ( it stays in the outbox ). A caller that does not await
92
+ * it attaches a catch, or follows the `acked` and `failed` events instead.
93
+ */
94
+ submit(name: string, payload: unknown, options?: DurableCommandOptions): Promise<unknown>;
95
+ /**
96
+ * Rejects the callers still waiting for an answer; their entries stay in the store for the next start.
97
+ * Answered commands settle in send order once the store has applied their outcome, also after close.
98
+ * Resolves once the store has no write of this queue in flight and every answered command has been
99
+ * reported: only then may the next queue open the same store, and the listeners be dropped.
100
+ */
101
+ close(): Promise<void>;
102
+ /** Reads the store once; a failed read is tried again by the next submit() or the next time the connection comes online. */
103
+ private load;
104
+ private item;
105
+ private onState;
106
+ private pump;
107
+ private transmit;
108
+ private onReply;
109
+ private onAckTimeout;
110
+ private requeue;
111
+ /** One backoff for the whole queue: its commands are refused for shared reasons ( overload, shutdown ). */
112
+ private retry;
113
+ private succeed;
114
+ private fail;
115
+ private finish;
116
+ /** The caller hears of an outcome only once the store holds it, so a reload cannot undo what it was told. */
117
+ private record;
118
+ /** Callers and listeners hear about commands in send order, whatever order their replies came in. */
119
+ private settle;
120
+ private report;
121
+ }
122
+ //# sourceMappingURL=durable.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"durable.d.ts","sourceRoot":"","sources":["../../src/durable.ts"],"names":[],"mappings":"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"}