@abloatai/transaction 0.59.1 → 0.60.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.
- package/dist/auth/apiKey.d.ts +10 -11
- package/dist/auth/apiKey.d.ts.map +1 -1
- package/dist/auth/apiKey.js +15 -29
- package/dist/auth/apiKey.js.map +1 -1
- package/dist/auth/browserCredentialSafety.js +1 -1
- package/dist/auth/browserCredentialSafety.js.map +1 -1
- package/dist/auth/capabilityLifecycle.d.ts +1 -1
- package/dist/auth/capabilityLifecycle.d.ts.map +1 -1
- package/dist/auth/capabilityLifecycle.js +2 -1
- package/dist/auth/capabilityLifecycle.js.map +1 -1
- package/dist/auth/credentialEndpoint.js +1 -1
- package/dist/auth/credentialEndpoint.js.map +1 -1
- package/dist/auth/credentialResult.d.ts +2 -1
- package/dist/auth/credentialResult.d.ts.map +1 -1
- package/dist/auth/credentialResult.js.map +1 -1
- package/dist/claims/events.d.ts +1 -1
- package/dist/claims/events.d.ts.map +1 -1
- package/dist/client/ablo.d.ts +15 -11
- package/dist/client/ablo.d.ts.map +1 -1
- package/dist/client/ablo.js +5 -14
- package/dist/client/ablo.js.map +1 -1
- package/dist/client/resources/httpResources.d.ts +1 -169
- package/dist/client/resources/httpResources.d.ts.map +1 -1
- package/dist/client/resources/httpResources.js +1 -1
- package/dist/client/resources/httpResources.js.map +1 -1
- package/dist/client/resources/modelOperations.d.ts +0 -9
- package/dist/client/resources/modelOperations.d.ts.map +1 -1
- package/dist/client/surface.d.ts +2 -2
- package/dist/client/surface.d.ts.map +1 -1
- package/dist/client/surface.js +8 -3
- package/dist/client/surface.js.map +1 -1
- package/dist/commit/contract.d.ts +10 -10
- package/dist/commit/recordRuntime.d.ts +3 -2
- package/dist/commit/recordRuntime.d.ts.map +1 -1
- package/dist/commit/recordRuntime.js +1 -0
- package/dist/commit/recordRuntime.js.map +1 -1
- package/dist/coordination/index.d.ts +2 -2
- package/dist/coordination/index.d.ts.map +1 -1
- package/dist/coordination/index.js +3 -4
- package/dist/coordination/index.js.map +1 -1
- package/dist/coordination/schema.d.ts +3 -47
- package/dist/coordination/schema.d.ts.map +1 -1
- package/dist/coordination/schema.js +7 -69
- package/dist/coordination/schema.js.map +1 -1
- package/dist/errorCodes.d.ts +2 -2
- package/dist/errorCodes.d.ts.map +1 -1
- package/dist/errorCodes.js +5 -9
- package/dist/errorCodes.js.map +1 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +16 -1
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/sessions/client.d.ts +29 -0
- package/dist/sessions/client.d.ts.map +1 -0
- package/dist/sessions/client.js +69 -0
- package/dist/sessions/client.js.map +1 -0
- package/dist/sessions/contract.d.ts +97 -0
- package/dist/sessions/contract.d.ts.map +1 -0
- package/dist/sessions/contract.js +5 -0
- package/dist/sessions/contract.js.map +1 -0
- package/dist/{auth/sessionMint.d.ts → sessions/create.d.ts} +4 -4
- package/dist/sessions/create.d.ts.map +1 -0
- package/dist/{auth/sessionMint.js → sessions/create.js} +11 -10
- package/dist/sessions/create.js.map +1 -0
- package/dist/sessions/handler.d.ts +23 -0
- package/dist/sessions/handler.d.ts.map +1 -0
- package/dist/sessions/handler.js +55 -0
- package/dist/sessions/handler.js.map +1 -0
- package/dist/sessions/index.d.ts +14 -0
- package/dist/sessions/index.d.ts.map +1 -0
- package/dist/sessions/index.js +14 -0
- package/dist/sessions/index.js.map +1 -0
- package/dist/{transport/connection/credentialLifecycle.d.ts → sessions/lifecycle.d.ts} +6 -6
- package/dist/sessions/lifecycle.d.ts.map +1 -0
- package/dist/{transport/connection/credentialLifecycle.js → sessions/lifecycle.js} +5 -5
- package/dist/sessions/lifecycle.js.map +1 -0
- package/dist/sessions/source.d.ts +24 -0
- package/dist/sessions/source.d.ts.map +1 -0
- package/dist/sessions/source.js +56 -0
- package/dist/sessions/source.js.map +1 -0
- package/dist/transport/connection/index.d.ts +0 -1
- package/dist/transport/connection/index.d.ts.map +1 -1
- package/dist/transport/connection/index.js +0 -1
- package/dist/transport/connection/index.js.map +1 -1
- package/dist/transport/connection/manager.d.ts +1 -1
- package/dist/transport/connection/manager.d.ts.map +1 -1
- package/dist/transport/http/client.d.ts +44 -16
- package/dist/transport/http/client.d.ts.map +1 -1
- package/dist/transport/http/client.js +125 -12
- package/dist/transport/http/client.js.map +1 -1
- package/dist/transport/http/options.d.ts +4 -1
- package/dist/transport/http/options.d.ts.map +1 -1
- package/dist/transport/http/transport.d.ts +25 -10
- package/dist/transport/http/transport.d.ts.map +1 -1
- package/dist/transport/http/transport.js +102 -56
- package/dist/transport/http/transport.js.map +1 -1
- package/dist/transport/websocket/commitFrames.d.ts +5 -5
- package/dist/transport/websocket/commitFrames.d.ts.map +1 -1
- package/dist/transport/websocket/commitFrames.js +1 -0
- package/dist/transport/websocket/commitFrames.js.map +1 -1
- package/dist/transport/websocket/contextSubscription.d.ts +6 -0
- package/dist/transport/websocket/contextSubscription.d.ts.map +1 -0
- package/dist/transport/websocket/contextSubscription.js +45 -0
- package/dist/transport/websocket/contextSubscription.js.map +1 -0
- package/dist/transport/websocket/frameHandlers.d.ts +0 -14
- package/dist/transport/websocket/frameHandlers.d.ts.map +1 -1
- package/dist/transport/websocket/frameHandlers.js +1 -71
- package/dist/transport/websocket/frameHandlers.js.map +1 -1
- package/dist/transport/websocket/session.d.ts +4 -0
- package/dist/transport/websocket/session.d.ts.map +1 -0
- package/dist/transport/websocket/session.js +425 -0
- package/dist/transport/websocket/session.js.map +1 -0
- package/dist/transport/websocket/sessionContract.d.ts +78 -0
- package/dist/transport/websocket/sessionContract.d.ts.map +1 -0
- package/dist/transport/websocket/sessionContract.js +2 -0
- package/dist/transport/websocket/sessionContract.js.map +1 -0
- package/dist/transport/websocket/transport.d.ts +27 -42
- package/dist/transport/websocket/transport.d.ts.map +1 -1
- package/dist/transport/websocket/transport.js +77 -102
- package/dist/transport/websocket/transport.js.map +1 -1
- package/dist/wire/inboundFrames.d.ts +0 -10
- package/dist/wire/inboundFrames.d.ts.map +1 -1
- package/dist/wire/inboundFrames.js +1 -6
- package/dist/wire/inboundFrames.js.map +1 -1
- package/package.json +7 -1
- package/src/auth/apiKey.ts +25 -44
- package/src/auth/browserCredentialSafety.ts +1 -1
- package/src/auth/capabilityLifecycle.ts +3 -2
- package/src/auth/credentialEndpoint.ts +1 -1
- package/src/auth/credentialResult.ts +2 -0
- package/src/claims/events.ts +1 -2
- package/src/client/ablo.ts +23 -13
- package/src/client/resources/httpResources.ts +2 -174
- package/src/client/resources/modelOperations.ts +0 -10
- package/src/client/surface.ts +9 -4
- package/src/commit/recordRuntime.ts +4 -2
- package/src/coordination/index.ts +2 -9
- package/src/coordination/schema.ts +7 -81
- package/src/errorCodes.ts +8 -13
- package/src/errors.ts +18 -1
- package/src/index.ts +1 -0
- package/src/sessions/client.ts +121 -0
- package/src/sessions/contract.ts +116 -0
- package/src/{auth/sessionMint.ts → sessions/create.ts} +13 -12
- package/src/sessions/handler.ts +96 -0
- package/src/sessions/index.ts +13 -0
- package/src/{transport/connection/credentialLifecycle.ts → sessions/lifecycle.ts} +5 -5
- package/src/sessions/source.ts +94 -0
- package/src/transport/connection/index.ts +0 -1
- package/src/transport/connection/manager.ts +1 -1
- package/src/transport/http/client.ts +183 -26
- package/src/transport/http/options.ts +4 -1
- package/src/transport/http/transport.ts +140 -78
- package/src/transport/websocket/commitFrames.ts +5 -5
- package/src/transport/websocket/contextSubscription.ts +55 -0
- package/src/transport/websocket/frameHandlers.ts +0 -102
- package/src/transport/websocket/session.ts +522 -0
- package/src/transport/websocket/sessionContract.ts +106 -0
- package/src/transport/websocket/transport.ts +85 -137
- package/src/wire/inboundFrames.ts +0 -6
- package/dist/auth/sessionMint.d.ts.map +0 -1
- package/dist/auth/sessionMint.js.map +0 -1
- package/dist/transport/connection/credentialLifecycle.d.ts.map +0 -1
- package/dist/transport/connection/credentialLifecycle.js.map +0 -1
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
import { AbloClaimedError, AbloConnectionError, AbloSessionError, errorFromWire, isAccessCredentialExpiryCloseReason, } from '../../errors.js';
|
|
2
|
+
import { classifyCredentialKind } from '../../auth/credentialKind.js';
|
|
3
|
+
import { credentialToken, } from '../../auth/credentialResult.js';
|
|
4
|
+
import { CredentialLifecycle } from '../../sessions/lifecycle.js';
|
|
5
|
+
import { clientSyncDeltaSchema, } from '../../observation/contract.js';
|
|
6
|
+
import { WsTransport, } from './transport.js';
|
|
7
|
+
const MAX_BUFFERED_OBSERVATION_DELTAS = 1_024;
|
|
8
|
+
function parsePosition(value) {
|
|
9
|
+
if (!value)
|
|
10
|
+
return { lastSyncId: 0, cursor: null };
|
|
11
|
+
try {
|
|
12
|
+
const parsed = JSON.parse(value);
|
|
13
|
+
if (Number.isSafeInteger(parsed.lastSyncId)
|
|
14
|
+
&& parsed.lastSyncId >= 0
|
|
15
|
+
&& (parsed.cursor === null || typeof parsed.cursor === 'string')) {
|
|
16
|
+
return {
|
|
17
|
+
lastSyncId: parsed.lastSyncId,
|
|
18
|
+
cursor: parsed.cursor,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
// Pre-live stores may contain the HTTP feed cursor. It is a different
|
|
24
|
+
// protocol position, so failing closed at zero is safer than skipping.
|
|
25
|
+
}
|
|
26
|
+
return { lastSyncId: 0, cursor: null };
|
|
27
|
+
}
|
|
28
|
+
class AgentWebSocket extends WsTransport {
|
|
29
|
+
position;
|
|
30
|
+
constructor(options, position) {
|
|
31
|
+
super(options);
|
|
32
|
+
this.position = position;
|
|
33
|
+
}
|
|
34
|
+
resumeCursor() {
|
|
35
|
+
return this.position.cursor ?? '';
|
|
36
|
+
}
|
|
37
|
+
onOpened() {
|
|
38
|
+
this.updatePresence();
|
|
39
|
+
this.requestSync(this.position);
|
|
40
|
+
}
|
|
41
|
+
handleDelta(raw) {
|
|
42
|
+
const parsed = clientSyncDeltaSchema.safeParse(raw);
|
|
43
|
+
if (parsed.success)
|
|
44
|
+
this.emit('delta', parsed.data);
|
|
45
|
+
}
|
|
46
|
+
handleSyncResponse(raw) {
|
|
47
|
+
if (typeof raw !== 'object' || raw === null)
|
|
48
|
+
return;
|
|
49
|
+
const response = raw;
|
|
50
|
+
if (Array.isArray(response.deltas)) {
|
|
51
|
+
for (const delta of response.deltas)
|
|
52
|
+
this.handleDelta(delta);
|
|
53
|
+
}
|
|
54
|
+
this.emit('sync_response', response);
|
|
55
|
+
}
|
|
56
|
+
positionAfter(lastSyncId) {
|
|
57
|
+
return {
|
|
58
|
+
lastSyncId: Math.max(this.position.lastSyncId, lastSyncId),
|
|
59
|
+
cursor: this.position.cursor,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
markDurable(position) {
|
|
63
|
+
this.position = position;
|
|
64
|
+
}
|
|
65
|
+
durablePosition() {
|
|
66
|
+
return this.position;
|
|
67
|
+
}
|
|
68
|
+
requestFromDurablePosition() {
|
|
69
|
+
this.requestSync(this.position);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
class WebSocketSession {
|
|
73
|
+
socket;
|
|
74
|
+
options;
|
|
75
|
+
cursorKey;
|
|
76
|
+
readyPromise = null;
|
|
77
|
+
rejectReady = null;
|
|
78
|
+
closed = false;
|
|
79
|
+
currentToken;
|
|
80
|
+
acknowledgeLane = Promise.resolve();
|
|
81
|
+
terminalError = null;
|
|
82
|
+
terminalListeners = new Set();
|
|
83
|
+
credentialLifecycle;
|
|
84
|
+
pendingSessionError = null;
|
|
85
|
+
presence;
|
|
86
|
+
collaboration;
|
|
87
|
+
constructor(options, position, credential) {
|
|
88
|
+
this.options = options;
|
|
89
|
+
const token = credentialToken(credential);
|
|
90
|
+
if (!token) {
|
|
91
|
+
throw new AbloSessionError('The WebSocket transport requires an authenticated credential.');
|
|
92
|
+
}
|
|
93
|
+
this.currentToken = token;
|
|
94
|
+
this.cursorKey = options.cursorKey ?? 'websocket';
|
|
95
|
+
this.socket = new AgentWebSocket({
|
|
96
|
+
baseUrl: options.baseUrl,
|
|
97
|
+
kind: classifyCredentialKind(token) === 'ephemeral' ? 'user' : 'agent',
|
|
98
|
+
getAuthToken: () => this.currentToken,
|
|
99
|
+
syncGroups: [...(options.syncGroups ?? [])],
|
|
100
|
+
collaborationEvents: [...(options.collaborationEvents ?? [])],
|
|
101
|
+
reconnectDelay: options.reconnectDelay,
|
|
102
|
+
maxReconnectDelay: options.maxReconnectDelay,
|
|
103
|
+
}, position);
|
|
104
|
+
this.presence = {
|
|
105
|
+
update: (input = {}) => this.socket.updatePresence(input),
|
|
106
|
+
};
|
|
107
|
+
this.collaboration = {
|
|
108
|
+
send: (event, payload) => this.socket.sendCollaborationEvent(event, payload),
|
|
109
|
+
};
|
|
110
|
+
this.socket.subscribe('session_error', (error) => {
|
|
111
|
+
this.handleSessionError(error);
|
|
112
|
+
});
|
|
113
|
+
this.credentialLifecycle = options.access.renewable
|
|
114
|
+
? new CredentialLifecycle({
|
|
115
|
+
setAuthToken: (freshToken) => {
|
|
116
|
+
this.currentToken = freshToken;
|
|
117
|
+
},
|
|
118
|
+
nudgeReconnect: () => {
|
|
119
|
+
if (this.closed || this.terminalError)
|
|
120
|
+
return;
|
|
121
|
+
this.socket.clearSessionError();
|
|
122
|
+
this.socket.resetReconnectAttempts();
|
|
123
|
+
this.socket.connect();
|
|
124
|
+
},
|
|
125
|
+
reportSessionExpired: () => {
|
|
126
|
+
this.failTerminal(this.pendingSessionError ?? new AbloSessionError('The application session ended while renewing its Ablo session.'));
|
|
127
|
+
},
|
|
128
|
+
})
|
|
129
|
+
: null;
|
|
130
|
+
if (this.credentialLifecycle) {
|
|
131
|
+
this.credentialLifecycle.start(() => this.loadCredential(), { proactiveInNode: true });
|
|
132
|
+
this.credentialLifecycle.accept(credential);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
async loadCredential() {
|
|
136
|
+
return this.options.access.credential();
|
|
137
|
+
}
|
|
138
|
+
handleSessionError(error) {
|
|
139
|
+
if (!this.credentialLifecycle
|
|
140
|
+
|| !isAccessCredentialExpiryCloseReason(error.message)) {
|
|
141
|
+
this.failTerminal(error);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
this.pendingSessionError = error;
|
|
145
|
+
void this.credentialLifecycle.recoverFromAuthRejection('access_credential_expiry');
|
|
146
|
+
}
|
|
147
|
+
failTerminal(error) {
|
|
148
|
+
if (this.terminalError || this.closed)
|
|
149
|
+
return;
|
|
150
|
+
this.terminalError = error;
|
|
151
|
+
this.socket.setSessionErrorDetected();
|
|
152
|
+
this.socket.disconnect();
|
|
153
|
+
for (const listener of this.terminalListeners)
|
|
154
|
+
listener(error);
|
|
155
|
+
}
|
|
156
|
+
onTerminal(listener) {
|
|
157
|
+
if (this.terminalError) {
|
|
158
|
+
const error = this.terminalError;
|
|
159
|
+
queueMicrotask(() => listener(error));
|
|
160
|
+
return () => undefined;
|
|
161
|
+
}
|
|
162
|
+
this.terminalListeners.add(listener);
|
|
163
|
+
return () => this.terminalListeners.delete(listener);
|
|
164
|
+
}
|
|
165
|
+
get connected() {
|
|
166
|
+
return this.socket.isConnected();
|
|
167
|
+
}
|
|
168
|
+
ready() {
|
|
169
|
+
if (this.closed) {
|
|
170
|
+
return Promise.reject(new AbloConnectionError('The WebSocket session is closed.'));
|
|
171
|
+
}
|
|
172
|
+
if (this.terminalError)
|
|
173
|
+
return Promise.reject(this.terminalError);
|
|
174
|
+
if (this.socket.isConnected())
|
|
175
|
+
return Promise.resolve();
|
|
176
|
+
if (this.readyPromise)
|
|
177
|
+
return this.readyPromise;
|
|
178
|
+
this.readyPromise = new Promise((resolve, reject) => {
|
|
179
|
+
const rejectConnection = (error) => {
|
|
180
|
+
cleanup();
|
|
181
|
+
reject(error);
|
|
182
|
+
};
|
|
183
|
+
this.rejectReady = rejectConnection;
|
|
184
|
+
const timeout = setTimeout(() => {
|
|
185
|
+
rejectConnection(new AbloConnectionError('The WebSocket connection timed out.'));
|
|
186
|
+
}, this.options.connectTimeoutMs ?? 15_000);
|
|
187
|
+
const connected = this.socket.subscribe('connected', () => {
|
|
188
|
+
cleanup();
|
|
189
|
+
resolve();
|
|
190
|
+
});
|
|
191
|
+
const failed = this.onTerminal((error) => {
|
|
192
|
+
rejectConnection(error);
|
|
193
|
+
});
|
|
194
|
+
const mismatch = this.socket.subscribe('protocol_mismatch', () => {
|
|
195
|
+
rejectConnection(new AbloConnectionError('The server rejected this live protocol version.', {
|
|
196
|
+
code: 'protocol_version_unsupported',
|
|
197
|
+
}));
|
|
198
|
+
});
|
|
199
|
+
const cleanup = () => {
|
|
200
|
+
clearTimeout(timeout);
|
|
201
|
+
connected();
|
|
202
|
+
failed();
|
|
203
|
+
mismatch();
|
|
204
|
+
this.readyPromise = null;
|
|
205
|
+
this.rejectReady = null;
|
|
206
|
+
};
|
|
207
|
+
this.socket.connect();
|
|
208
|
+
});
|
|
209
|
+
return this.readyPromise;
|
|
210
|
+
}
|
|
211
|
+
async commit(input) {
|
|
212
|
+
await this.ready();
|
|
213
|
+
return this.socket.sendCommitReceipt(input.operations, input.clientTxId, input.timeoutMs, input.reads);
|
|
214
|
+
}
|
|
215
|
+
async claim(input) {
|
|
216
|
+
await this.ready();
|
|
217
|
+
const timeoutMs = input.timeoutMs ?? 15_000;
|
|
218
|
+
return new Promise((resolve, reject) => {
|
|
219
|
+
const cleanups = [];
|
|
220
|
+
const finish = (outcome) => {
|
|
221
|
+
clearTimeout(timeout);
|
|
222
|
+
for (const cleanup of cleanups)
|
|
223
|
+
cleanup();
|
|
224
|
+
outcome();
|
|
225
|
+
};
|
|
226
|
+
const matches = (event) => event.claimId === input.claimId;
|
|
227
|
+
cleanups.push(this.socket.subscribe('claim_acquired', (event) => {
|
|
228
|
+
if (matches(event))
|
|
229
|
+
finish(() => resolve(event));
|
|
230
|
+
}));
|
|
231
|
+
cleanups.push(this.socket.subscribe('claim_granted', (event) => {
|
|
232
|
+
if (matches(event))
|
|
233
|
+
finish(() => resolve(event));
|
|
234
|
+
}));
|
|
235
|
+
cleanups.push(this.socket.subscribe('claim_queued', (event) => {
|
|
236
|
+
if (!matches(event))
|
|
237
|
+
return;
|
|
238
|
+
const refusal = input.onQueued?.(event);
|
|
239
|
+
if (refusal) {
|
|
240
|
+
this.release({
|
|
241
|
+
claimId: input.claimId,
|
|
242
|
+
entityType: input.entityType,
|
|
243
|
+
entityId: input.entityId,
|
|
244
|
+
});
|
|
245
|
+
finish(() => reject(refusal));
|
|
246
|
+
}
|
|
247
|
+
}));
|
|
248
|
+
cleanups.push(this.socket.subscribe('claim_rejected', (event) => {
|
|
249
|
+
if (!matches(event))
|
|
250
|
+
return;
|
|
251
|
+
finish(() => reject(errorFromWire(event.message ?? `Claim ${event.claimId} was rejected.`, {
|
|
252
|
+
code: event.reason === 'conflict' ? 'claim_conflict' : 'claim_rejected',
|
|
253
|
+
details: {
|
|
254
|
+
...(event.target ? { target: event.target } : {}),
|
|
255
|
+
...(event.heldBy ? { heldBy: event.heldBy } : {}),
|
|
256
|
+
...(event.heldByClaimId ? { heldByClaimId: event.heldByClaimId } : {}),
|
|
257
|
+
},
|
|
258
|
+
})));
|
|
259
|
+
}));
|
|
260
|
+
cleanups.push(this.socket.subscribe('disconnected', () => {
|
|
261
|
+
finish(() => reject(new AbloConnectionError(`WebSocket closed while claim ${input.claimId} was pending.`)));
|
|
262
|
+
}));
|
|
263
|
+
const abort = () => {
|
|
264
|
+
this.release({
|
|
265
|
+
claimId: input.claimId,
|
|
266
|
+
entityType: input.entityType,
|
|
267
|
+
entityId: input.entityId,
|
|
268
|
+
});
|
|
269
|
+
finish(() => reject(new AbloClaimedError(`The wait for claim ${input.claimId} was aborted.`, { code: 'claim_wait_aborted' })));
|
|
270
|
+
};
|
|
271
|
+
input.signal?.addEventListener('abort', abort, { once: true });
|
|
272
|
+
cleanups.push(() => input.signal?.removeEventListener('abort', abort));
|
|
273
|
+
const timeout = setTimeout(() => {
|
|
274
|
+
this.release({
|
|
275
|
+
claimId: input.claimId,
|
|
276
|
+
entityType: input.entityType,
|
|
277
|
+
entityId: input.entityId,
|
|
278
|
+
});
|
|
279
|
+
finish(() => reject(new AbloClaimedError(`claim timed out after ${timeoutMs}ms (claimId=${input.claimId})`, { code: 'grant_timeout' })));
|
|
280
|
+
}, timeoutMs);
|
|
281
|
+
if (input.signal?.aborted) {
|
|
282
|
+
abort();
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
const { timeoutMs: _timeoutMs, signal: _signal, onQueued: _onQueued, ...payload } = input;
|
|
286
|
+
this.socket.send({ type: 'claim_begin', payload });
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
release(input) {
|
|
290
|
+
this.socket.send({ type: 'claim_abandon', payload: input });
|
|
291
|
+
}
|
|
292
|
+
subscribe(event, listener) {
|
|
293
|
+
return this.socket.subscribe(event, listener);
|
|
294
|
+
}
|
|
295
|
+
async *observe(options = {}) {
|
|
296
|
+
await this.ready();
|
|
297
|
+
const queued = [];
|
|
298
|
+
const queuedIds = new Set();
|
|
299
|
+
let wake;
|
|
300
|
+
let failure;
|
|
301
|
+
const offDelta = this.socket.subscribe('delta', (delta) => {
|
|
302
|
+
if (failure
|
|
303
|
+
|| delta.id <= this.socket.durablePosition().lastSyncId
|
|
304
|
+
|| queuedIds.has(delta.id))
|
|
305
|
+
return;
|
|
306
|
+
if (queued.length >= MAX_BUFFERED_OBSERVATION_DELTAS) {
|
|
307
|
+
failure = new AbloConnectionError(`WebSocket observation exceeded ${MAX_BUFFERED_OBSERVATION_DELTAS} uncheckpointed deltas; restart observation to resume from the durable cursor.`, { code: 'observation_buffer_overflow' });
|
|
308
|
+
wake?.();
|
|
309
|
+
wake = undefined;
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
queued.push(delta);
|
|
313
|
+
queuedIds.add(delta.id);
|
|
314
|
+
wake?.();
|
|
315
|
+
wake = undefined;
|
|
316
|
+
});
|
|
317
|
+
const offError = this.onTerminal((error) => {
|
|
318
|
+
failure = error;
|
|
319
|
+
wake?.();
|
|
320
|
+
wake = undefined;
|
|
321
|
+
});
|
|
322
|
+
const abort = () => {
|
|
323
|
+
wake?.();
|
|
324
|
+
wake = undefined;
|
|
325
|
+
};
|
|
326
|
+
options.signal?.addEventListener('abort', abort, { once: true });
|
|
327
|
+
// Retain nothing while idle. Register first, then replay from the durable
|
|
328
|
+
// position so starting observation cannot miss a delta from the gap.
|
|
329
|
+
this.socket.requestFromDurablePosition();
|
|
330
|
+
try {
|
|
331
|
+
while (!this.closed && !options.signal?.aborted) {
|
|
332
|
+
if (failure)
|
|
333
|
+
throw failure;
|
|
334
|
+
const delta = queued.shift();
|
|
335
|
+
if (!delta) {
|
|
336
|
+
await new Promise((resolve) => { wake = resolve; });
|
|
337
|
+
continue;
|
|
338
|
+
}
|
|
339
|
+
queuedIds.delete(delta.id);
|
|
340
|
+
if (delta.id <= this.socket.durablePosition().lastSyncId)
|
|
341
|
+
continue;
|
|
342
|
+
let checkpointed = false;
|
|
343
|
+
let checkpointing;
|
|
344
|
+
yield {
|
|
345
|
+
...delta,
|
|
346
|
+
checkpoint: async () => {
|
|
347
|
+
if (checkpointed)
|
|
348
|
+
return;
|
|
349
|
+
checkpointing ??= this.acknowledge(delta.id).then(() => {
|
|
350
|
+
checkpointed = true;
|
|
351
|
+
}).finally(() => {
|
|
352
|
+
checkpointing = undefined;
|
|
353
|
+
});
|
|
354
|
+
await checkpointing;
|
|
355
|
+
},
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
finally {
|
|
360
|
+
offDelta();
|
|
361
|
+
offError();
|
|
362
|
+
options.signal?.removeEventListener('abort', abort);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
async updateSubscription(syncGroups, options) {
|
|
366
|
+
await this.ready();
|
|
367
|
+
return this.socket.updateSubscription(syncGroups, options);
|
|
368
|
+
}
|
|
369
|
+
async acknowledge(lastSyncId) {
|
|
370
|
+
const attempt = this.acknowledgeLane.catch(() => undefined).then(async () => {
|
|
371
|
+
const position = this.socket.positionAfter(lastSyncId);
|
|
372
|
+
await this.options.cursorStore?.save(this.cursorKey, JSON.stringify(position));
|
|
373
|
+
this.socket.markDurable(position);
|
|
374
|
+
this.socket.acknowledge(position.lastSyncId);
|
|
375
|
+
});
|
|
376
|
+
this.acknowledgeLane = attempt.catch(() => undefined);
|
|
377
|
+
await attempt;
|
|
378
|
+
}
|
|
379
|
+
async close() {
|
|
380
|
+
if (this.closed)
|
|
381
|
+
return;
|
|
382
|
+
this.closed = true;
|
|
383
|
+
this.credentialLifecycle?.stop();
|
|
384
|
+
this.terminalListeners.clear();
|
|
385
|
+
this.rejectReady?.(new AbloConnectionError('The WebSocket session was disposed.'));
|
|
386
|
+
await this.acknowledgeLane;
|
|
387
|
+
this.socket.disconnect();
|
|
388
|
+
}
|
|
389
|
+
[Symbol.asyncDispose]() {
|
|
390
|
+
return this.close();
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
export async function createWebSocketSession(options, signal) {
|
|
394
|
+
const cursorKey = options.cursorKey ?? 'websocket';
|
|
395
|
+
const stored = await options.cursorStore?.load(cursorKey) ?? null;
|
|
396
|
+
const credential = await options.access.credential();
|
|
397
|
+
const token = credentialToken(credential);
|
|
398
|
+
if (!token) {
|
|
399
|
+
throw new AbloSessionError('The WebSocket transport requires an authenticated credential.');
|
|
400
|
+
}
|
|
401
|
+
const session = new WebSocketSession(options, parsePosition(stored), credential);
|
|
402
|
+
let rejectOpening;
|
|
403
|
+
const aborted = new Promise((_resolve, reject) => {
|
|
404
|
+
rejectOpening = reject;
|
|
405
|
+
if (signal?.aborted) {
|
|
406
|
+
reject(new AbloConnectionError('WebSocket opening was disposed.'));
|
|
407
|
+
}
|
|
408
|
+
});
|
|
409
|
+
const abort = () => {
|
|
410
|
+
rejectOpening?.(new AbloConnectionError('WebSocket opening was disposed.'));
|
|
411
|
+
};
|
|
412
|
+
signal?.addEventListener('abort', abort, { once: true });
|
|
413
|
+
try {
|
|
414
|
+
await (signal ? Promise.race([session.ready(), aborted]) : session.ready());
|
|
415
|
+
return session;
|
|
416
|
+
}
|
|
417
|
+
catch (error) {
|
|
418
|
+
await session.close();
|
|
419
|
+
throw error;
|
|
420
|
+
}
|
|
421
|
+
finally {
|
|
422
|
+
signal?.removeEventListener('abort', abort);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../../src/transport/websocket/session.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { CommitReceiptWire } from '../../commit/contract.js';
|
|
2
|
+
import type { ReadDependency } from '../../coordination/schema.js';
|
|
3
|
+
import type { ClaimAcquired, ClaimBeginPayload, ClaimGranted, ClaimQueued } from '../../coordination/schema.js';
|
|
4
|
+
import type { ClientSyncDelta } from '../../observation/contract.js';
|
|
5
|
+
import type { ObserveCursorStore } from '../../client/contract.js';
|
|
6
|
+
import type { SessionAccess } from '../../sessions/source.js';
|
|
7
|
+
import type { CommitFrameOperation } from '../websocket/commitFrames.js';
|
|
8
|
+
import type { CoreSyncEventMap, EventMap, PresenceUpdate, SyncWebSocketEventMap } from '../websocket/transport.js';
|
|
9
|
+
export interface WebSocketSessionOptions {
|
|
10
|
+
readonly baseUrl?: string;
|
|
11
|
+
/** Normalized once at the client boundary; transports do not infer policy. */
|
|
12
|
+
readonly access: SessionAccess;
|
|
13
|
+
readonly syncGroups?: readonly string[];
|
|
14
|
+
readonly collaborationEvents?: readonly string[];
|
|
15
|
+
readonly cursorKey?: string;
|
|
16
|
+
readonly cursorStore?: ObserveCursorStore;
|
|
17
|
+
readonly reconnectDelay?: number;
|
|
18
|
+
readonly maxReconnectDelay?: number;
|
|
19
|
+
readonly connectTimeoutMs?: number;
|
|
20
|
+
}
|
|
21
|
+
export interface WebSocketCommitInput {
|
|
22
|
+
readonly operations: readonly CommitFrameOperation[];
|
|
23
|
+
readonly clientTxId: string;
|
|
24
|
+
readonly reads?: readonly ReadDependency[] | null;
|
|
25
|
+
readonly timeoutMs?: number;
|
|
26
|
+
}
|
|
27
|
+
export interface WebSocketObservedDelta extends ClientSyncDelta {
|
|
28
|
+
/** Persist and acknowledge this delta as durably applied. */
|
|
29
|
+
checkpoint(): Promise<void>;
|
|
30
|
+
}
|
|
31
|
+
export interface WebSocketObserveOptions {
|
|
32
|
+
readonly signal?: AbortSignal;
|
|
33
|
+
}
|
|
34
|
+
/** A durable row/field claim carried over the same live protocol. */
|
|
35
|
+
export type WebSocketClaimInput = ClaimBeginPayload & {
|
|
36
|
+
readonly timeoutMs?: number;
|
|
37
|
+
readonly signal?: AbortSignal;
|
|
38
|
+
readonly onQueued?: (event: ClaimQueued) => Error | undefined;
|
|
39
|
+
};
|
|
40
|
+
export type WebSocketClaimGrant = ClaimAcquired | ClaimGranted;
|
|
41
|
+
export interface WebSocketPresence {
|
|
42
|
+
update(input?: {
|
|
43
|
+
readonly status?: 'online' | 'away' | 'offline';
|
|
44
|
+
readonly customStatus?: string;
|
|
45
|
+
readonly timezone?: string;
|
|
46
|
+
readonly activity?: Record<string, unknown>;
|
|
47
|
+
}): void;
|
|
48
|
+
}
|
|
49
|
+
export interface WebSocketCollaboration<TEvents extends EventMap<TEvents>> {
|
|
50
|
+
send<K extends string & keyof TEvents>(event: K, payload: TEvents[K] extends [infer P] ? Omit<P & Record<string, unknown>, 'timestamp'> : never): void;
|
|
51
|
+
}
|
|
52
|
+
export type OpenCollaborationEvents = Record<string, [Record<string, unknown>]>;
|
|
53
|
+
export interface AbloWebSocketSession<TEvents extends EventMap<TEvents> = OpenCollaborationEvents> extends AsyncDisposable {
|
|
54
|
+
readonly presence: WebSocketPresence;
|
|
55
|
+
readonly collaboration: WebSocketCollaboration<TEvents>;
|
|
56
|
+
readonly connected: boolean;
|
|
57
|
+
ready(): Promise<void>;
|
|
58
|
+
commit(input: WebSocketCommitInput): Promise<CommitReceiptWire>;
|
|
59
|
+
claim(input: WebSocketClaimInput): Promise<WebSocketClaimGrant>;
|
|
60
|
+
release(input: {
|
|
61
|
+
readonly claimId: string;
|
|
62
|
+
readonly entityType?: string;
|
|
63
|
+
readonly entityId?: string;
|
|
64
|
+
}): void;
|
|
65
|
+
subscribe<K extends keyof SyncWebSocketEventMap<TEvents>>(event: K, listener: (...args: SyncWebSocketEventMap<TEvents>[K]) => void): () => void;
|
|
66
|
+
observe(options?: WebSocketObserveOptions): AsyncIterable<WebSocketObservedDelta>;
|
|
67
|
+
updateSubscription(syncGroups: readonly string[], options?: {
|
|
68
|
+
timeoutMs?: number;
|
|
69
|
+
}): Promise<{
|
|
70
|
+
syncGroups: string[];
|
|
71
|
+
}>;
|
|
72
|
+
acknowledge(lastSyncId: number): Promise<void>;
|
|
73
|
+
close(): Promise<void>;
|
|
74
|
+
[Symbol.asyncDispose](): Promise<void>;
|
|
75
|
+
}
|
|
76
|
+
export type WebSocketCoreEvent = keyof CoreSyncEventMap;
|
|
77
|
+
export type WebSocketPresenceUpdate = PresenceUpdate;
|
|
78
|
+
//# sourceMappingURL=sessionContract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessionContract.d.ts","sourceRoot":"","sources":["../../../src/transport/websocket/sessionContract.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessionContract.js","sourceRoot":"","sources":["../../../src/transport/websocket/sessionContract.ts"],"names":[],"mappings":""}
|
|
@@ -21,7 +21,7 @@ import { EventEmitter } from 'events';
|
|
|
21
21
|
import type { ParticipantKind } from '../../types/participant.js';
|
|
22
22
|
import type { BootstrapReason } from '../../wire/bootstrapReason.js';
|
|
23
23
|
import type { ClientSyncDelta } from '../../observation/contract.js';
|
|
24
|
-
import type { ClaimAcquired, PresenceUpdate,
|
|
24
|
+
import type { ClaimAcquired, PresenceUpdate, ClaimGranted, ClaimHeartbeatAckPayload, ClaimLost, ClaimQueue, ClaimQueued, ClaimRejection, ReadDependency } from '../../coordination/schema.js';
|
|
25
25
|
import { type AuthTokenGetter } from '../../auth/credentialSource.js';
|
|
26
26
|
import { type CommitAck, type CommitFrameOperation } from './commitFrames.js';
|
|
27
27
|
import type { CommitReceiptWire } from '../../commit/contract.js';
|
|
@@ -154,6 +154,7 @@ export interface CoreSyncEventMap {
|
|
|
154
154
|
presence_update: [PresenceUpdate];
|
|
155
155
|
error: [Error];
|
|
156
156
|
session_error: [Error];
|
|
157
|
+
protocol_mismatch: [CloseEvent];
|
|
157
158
|
/**
|
|
158
159
|
* The WebSocket `onclose` fired before `onopen` — the handshake itself
|
|
159
160
|
* failed. The browser cannot expose the HTTP status (it shows as code
|
|
@@ -165,14 +166,6 @@ export interface CoreSyncEventMap {
|
|
|
165
166
|
reconnect_failed: [{
|
|
166
167
|
attempts: number;
|
|
167
168
|
}];
|
|
168
|
-
/**
|
|
169
|
-
* Server-initiated notification that a previously-active claim's
|
|
170
|
-
* TTL has expired. Consumers (e.g., the participant SDK) re-mint
|
|
171
|
-
* a fresh capability and re-claim, OR accept the drop. The claim
|
|
172
|
-
* is already inactive on the server side by the time this fires —
|
|
173
|
-
* no client-side action needed unless re-claiming.
|
|
174
|
-
*/
|
|
175
|
-
claim_expired: [ClaimExpired];
|
|
176
169
|
/**
|
|
177
170
|
* Server rejected an `claim_begin` because another participant
|
|
178
171
|
* already holds an open claim on the same target (cooperative
|
|
@@ -281,6 +274,10 @@ export declare class WsTransport<TCollaboration extends EventMap<TCollaboration>
|
|
|
281
274
|
* server rejected the upgrade" since browsers hide the HTTP status (e.g.
|
|
282
275
|
* 401) behind the opaque 1006 close code. */
|
|
283
276
|
private _everOpened;
|
|
277
|
+
/** True after any socket in this logical transport has opened. Unlike
|
|
278
|
+
* `_everOpened`, this survives socket replacement so a failed reconnect
|
|
279
|
+
* handshake is retried instead of being mistaken for a failed first login. */
|
|
280
|
+
private _hasConnected;
|
|
284
281
|
/**
|
|
285
282
|
* Diagnostic snapshot of the last connection lifecycle. Persisted across
|
|
286
283
|
* the lifetime of the transport so that any subsequent "not connected"
|
|
@@ -314,13 +311,6 @@ export declare class WsTransport<TCollaboration extends EventMap<TCollaboration>
|
|
|
314
311
|
* sent over the same socket that streams deltas.
|
|
315
312
|
*/
|
|
316
313
|
private pendingMutations;
|
|
317
|
-
/**
|
|
318
|
-
* In-flight `claim` requests keyed by claimId. Resolved when the matching
|
|
319
|
-
* `claim_ack` arrives, or rejected on timeout or disconnect — the same
|
|
320
|
-
* request/response pattern as `pendingMutations`, multiplexed over the one
|
|
321
|
-
* connection.
|
|
322
|
-
*/
|
|
323
|
-
private pendingClaims;
|
|
324
314
|
/**
|
|
325
315
|
* In-flight `update_subscription` frames awaiting `subscription_ack`.
|
|
326
316
|
* A FIFO queue rather than a keyed Map because the wire ack carries no
|
|
@@ -408,6 +398,27 @@ export declare class WsTransport<TCollaboration extends EventMap<TCollaboration>
|
|
|
408
398
|
* Send message to server
|
|
409
399
|
*/
|
|
410
400
|
send(message: any): void;
|
|
401
|
+
/**
|
|
402
|
+
* Ask the server for every durable delta after the supplied position.
|
|
403
|
+
*
|
|
404
|
+
* This is deliberately part of the carrier rather than the reactive
|
|
405
|
+
* materialiser: browser stores and headless WebSocket clients resume the same
|
|
406
|
+
* ordered protocol. The owner decides when a received position is durable
|
|
407
|
+
* enough to acknowledge.
|
|
408
|
+
*/
|
|
409
|
+
requestSync(position: {
|
|
410
|
+
readonly cursor?: string | null;
|
|
411
|
+
readonly lastSyncId: number;
|
|
412
|
+
}): void;
|
|
413
|
+
/** Persist the server-side resume position after the caller durably applied it. */
|
|
414
|
+
acknowledge(lastSyncId: number): void;
|
|
415
|
+
/** Announce this participant's current presence on the shared connection. */
|
|
416
|
+
updatePresence(input?: {
|
|
417
|
+
readonly status?: 'online' | 'away' | 'offline';
|
|
418
|
+
readonly customStatus?: string;
|
|
419
|
+
readonly timezone?: string;
|
|
420
|
+
readonly activity?: Record<string, unknown>;
|
|
421
|
+
}): void;
|
|
411
422
|
/**
|
|
412
423
|
* Sends a `commit` mutation request over the existing WebSocket and resolves
|
|
413
424
|
* when the server's `mutation_result` frame comes back with the same
|
|
@@ -431,32 +442,6 @@ export declare class WsTransport<TCollaboration extends EventMap<TCollaboration>
|
|
|
431
442
|
* instance because no pending resolver is registered.
|
|
432
443
|
*/
|
|
433
444
|
sendCommitQueued(operations: readonly CommitFrameOperation[], clientTxId: string, reads?: readonly ReadDependency[] | null): void;
|
|
434
|
-
/**
|
|
435
|
-
* Activates a participant claim on this connection. One connection can hold
|
|
436
|
-
* several concurrent claims at once, each scoped to a different set of sync
|
|
437
|
-
* groups, so the SDK reuses the existing connection instead of opening a
|
|
438
|
-
* separate socket per scope.
|
|
439
|
-
*
|
|
440
|
-
* Returns a promise that resolves with the server-canonicalized `syncGroups`
|
|
441
|
-
* and effective `ttlSeconds` once `claim_ack` arrives, or rejects with a typed
|
|
442
|
-
* error on a failed ack, a timeout, or a disconnect.
|
|
443
|
-
*/
|
|
444
|
-
sendClaim(claimId: string, syncGroups: readonly string[], options?: Pick<ParticipantClaimPayload, 'capabilityToken' | 'ttlSeconds'> & {
|
|
445
|
-
timeoutMs?: number;
|
|
446
|
-
}): Promise<{
|
|
447
|
-
syncGroups: string[];
|
|
448
|
-
ttlSeconds?: number;
|
|
449
|
-
}>;
|
|
450
|
-
/**
|
|
451
|
-
* Drop a previously-active claim. Idempotent — `release` is
|
|
452
|
-
* fire-and-forget per the wire contract; the server accepts
|
|
453
|
-
* unknown claimIds silently so disconnect-time release storms
|
|
454
|
-
* never error. No ack is expected.
|
|
455
|
-
*
|
|
456
|
-
* If a claim's send promise is still pending (no claim_ack yet),
|
|
457
|
-
* we reject it locally — the user explicitly chose to release.
|
|
458
|
-
*/
|
|
459
|
-
sendRelease(claimId: string): void;
|
|
460
445
|
/**
|
|
461
446
|
* Moves this connection's read interest — replaces the connection-level sync
|
|
462
447
|
* groups mid-session as the user opens and closes entities. This is the
|