@ably/ai-transport 0.1.0 → 0.2.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/README.md +91 -100
- package/dist/ably-ai-transport.js +1553 -1238
- package/dist/ably-ai-transport.js.map +1 -1
- package/dist/ably-ai-transport.umd.cjs +1 -1
- package/dist/ably-ai-transport.umd.cjs.map +1 -1
- package/dist/constants.d.ts +116 -42
- package/dist/core/agent.d.ts +29 -0
- package/dist/core/codec/decoder.d.ts +20 -23
- package/dist/core/codec/encoder.d.ts +11 -8
- package/dist/core/codec/index.d.ts +1 -2
- package/dist/core/codec/lifecycle-tracker.d.ts +10 -9
- package/dist/core/codec/types.d.ts +407 -115
- package/dist/core/transport/agent-session.d.ts +10 -0
- package/dist/core/transport/branch-chain.d.ts +43 -0
- package/dist/core/transport/client-session.d.ts +13 -0
- package/dist/core/transport/decode-fold.d.ts +47 -0
- package/dist/core/transport/headers.d.ts +96 -18
- package/dist/core/transport/index.d.ts +5 -6
- package/dist/core/transport/internal/bounded-map.d.ts +20 -0
- package/dist/core/transport/invocation.d.ts +74 -0
- package/dist/core/transport/load-conversation.d.ts +128 -0
- package/dist/core/transport/load-history.d.ts +39 -0
- package/dist/core/transport/pipe-stream.d.ts +9 -9
- package/dist/core/transport/run-manager.d.ts +78 -0
- package/dist/core/transport/tree.d.ts +373 -109
- package/dist/core/transport/types/agent.d.ts +353 -0
- package/dist/core/transport/types/client.d.ts +168 -0
- package/dist/core/transport/types/shared.d.ts +24 -0
- package/dist/core/transport/types/tree.d.ts +315 -0
- package/dist/core/transport/types/view.d.ts +222 -0
- package/dist/core/transport/types.d.ts +13 -553
- package/dist/core/transport/view.d.ts +272 -84
- package/dist/errors.d.ts +21 -10
- package/dist/index.d.ts +6 -8
- package/dist/logger.d.ts +12 -0
- package/dist/react/ably-ai-transport-react.js +976 -990
- package/dist/react/ably-ai-transport-react.js.map +1 -1
- package/dist/react/ably-ai-transport-react.umd.cjs +1 -1
- package/dist/react/ably-ai-transport-react.umd.cjs.map +1 -1
- package/dist/react/contexts/client-session-context.d.ts +36 -0
- package/dist/react/contexts/client-session-provider.d.ts +53 -0
- package/dist/react/create-session-hooks.d.ts +116 -0
- package/dist/react/index.d.ts +12 -12
- package/dist/react/internal/use-resolved-session.d.ts +36 -0
- package/dist/react/use-ably-messages.d.ts +17 -14
- package/dist/react/use-client-session.d.ts +81 -0
- package/dist/react/use-create-view.d.ts +14 -13
- package/dist/react/use-tree.d.ts +30 -15
- package/dist/react/use-view.d.ts +82 -51
- package/dist/utils.d.ts +32 -23
- package/dist/vercel/ably-ai-transport-vercel.js +2573 -2086
- package/dist/vercel/ably-ai-transport-vercel.js.map +1 -1
- package/dist/vercel/ably-ai-transport-vercel.umd.cjs +1 -1
- package/dist/vercel/ably-ai-transport-vercel.umd.cjs.map +1 -1
- package/dist/vercel/codec/decoder.d.ts +5 -18
- package/dist/vercel/codec/encoder.d.ts +6 -36
- package/dist/vercel/codec/events.d.ts +51 -0
- package/dist/vercel/codec/index.d.ts +24 -12
- package/dist/vercel/codec/reducer.d.ts +144 -0
- package/dist/vercel/codec/tool-transitions.d.ts +2 -2
- package/dist/vercel/index.d.ts +4 -5
- package/dist/vercel/react/ably-ai-transport-vercel-react.js +3907 -3266
- package/dist/vercel/react/ably-ai-transport-vercel-react.js.map +1 -1
- package/dist/vercel/react/ably-ai-transport-vercel-react.umd.cjs +33 -8
- package/dist/vercel/react/ably-ai-transport-vercel-react.umd.cjs.map +1 -1
- package/dist/vercel/react/contexts/chat-transport-context.d.ts +7 -6
- package/dist/vercel/react/contexts/chat-transport-provider.d.ts +53 -41
- package/dist/vercel/react/index.d.ts +1 -2
- package/dist/vercel/react/use-chat-transport.d.ts +30 -26
- package/dist/vercel/react/use-message-sync.d.ts +17 -30
- package/dist/vercel/run-end-reason.d.ts +29 -0
- package/dist/vercel/transport/chat-transport.d.ts +43 -24
- package/dist/vercel/transport/index.d.ts +25 -21
- package/dist/vercel/transport/run-output-stream.d.ts +56 -0
- package/dist/version.d.ts +2 -0
- package/package.json +30 -23
- package/src/constants.ts +124 -51
- package/src/core/agent.ts +68 -0
- package/src/core/codec/decoder.ts +71 -98
- package/src/core/codec/encoder.ts +113 -65
- package/src/core/codec/index.ts +13 -6
- package/src/core/codec/lifecycle-tracker.ts +10 -9
- package/src/core/codec/types.ts +436 -120
- package/src/core/transport/agent-session.ts +1344 -0
- package/src/core/transport/branch-chain.ts +58 -0
- package/src/core/transport/client-session.ts +775 -0
- package/src/core/transport/decode-fold.ts +91 -0
- package/src/core/transport/headers.ts +181 -22
- package/src/core/transport/index.ts +25 -26
- package/src/core/transport/internal/bounded-map.ts +27 -0
- package/src/core/transport/invocation.ts +98 -0
- package/src/core/transport/load-conversation.ts +355 -0
- package/src/core/transport/load-history.ts +269 -0
- package/src/core/transport/pipe-stream.ts +54 -39
- package/src/core/transport/run-manager.ts +249 -0
- package/src/core/transport/tree.ts +926 -308
- package/src/core/transport/types/agent.ts +407 -0
- package/src/core/transport/types/client.ts +211 -0
- package/src/core/transport/types/shared.ts +27 -0
- package/src/core/transport/types/tree.ts +344 -0
- package/src/core/transport/types/view.ts +259 -0
- package/src/core/transport/types.ts +13 -706
- package/src/core/transport/view.ts +864 -433
- package/src/errors.ts +22 -9
- package/src/event-emitter.ts +3 -2
- package/src/index.ts +52 -41
- package/src/logger.ts +14 -1
- package/src/react/contexts/client-session-context.ts +41 -0
- package/src/react/contexts/client-session-provider.tsx +186 -0
- package/src/react/create-session-hooks.ts +141 -0
- package/src/react/index.ts +23 -13
- package/src/react/internal/use-resolved-session.ts +63 -0
- package/src/react/use-ably-messages.ts +32 -22
- package/src/react/use-client-session.ts +201 -0
- package/src/react/use-create-view.ts +33 -29
- package/src/react/use-tree.ts +61 -30
- package/src/react/use-view.ts +139 -97
- package/src/utils.ts +63 -45
- package/src/vercel/codec/decoder.ts +336 -258
- package/src/vercel/codec/encoder.ts +343 -205
- package/src/vercel/codec/events.ts +87 -0
- package/src/vercel/codec/index.ts +60 -13
- package/src/vercel/codec/reducer.ts +977 -0
- package/src/vercel/codec/tool-transitions.ts +2 -2
- package/src/vercel/index.ts +6 -19
- package/src/vercel/react/contexts/chat-transport-context.ts +7 -6
- package/src/vercel/react/contexts/chat-transport-provider.tsx +87 -59
- package/src/vercel/react/index.ts +3 -5
- package/src/vercel/react/use-chat-transport.ts +47 -49
- package/src/vercel/react/use-message-sync.ts +80 -39
- package/src/vercel/run-end-reason.ts +78 -0
- package/src/vercel/transport/chat-transport.ts +392 -98
- package/src/vercel/transport/index.ts +39 -38
- package/src/vercel/transport/run-output-stream.ts +170 -0
- package/src/version.ts +2 -0
- package/dist/core/transport/client-transport.d.ts +0 -10
- package/dist/core/transport/decode-history.d.ts +0 -43
- package/dist/core/transport/server-transport.d.ts +0 -7
- package/dist/core/transport/stream-router.d.ts +0 -29
- package/dist/core/transport/turn-manager.d.ts +0 -37
- package/dist/react/contexts/transport-context.d.ts +0 -31
- package/dist/react/contexts/transport-provider.d.ts +0 -49
- package/dist/react/create-transport-hooks.d.ts +0 -124
- package/dist/react/use-active-turns.d.ts +0 -12
- package/dist/react/use-client-transport.d.ts +0 -80
- package/dist/vercel/codec/accumulator.d.ts +0 -21
- package/dist/vercel/react/use-staged-add-tool-approval-response.d.ts +0 -30
- package/dist/vercel/tool-approvals.d.ts +0 -124
- package/dist/vercel/tool-events.d.ts +0 -26
- package/src/core/transport/client-transport.ts +0 -977
- package/src/core/transport/decode-history.ts +0 -485
- package/src/core/transport/server-transport.ts +0 -612
- package/src/core/transport/stream-router.ts +0 -136
- package/src/core/transport/turn-manager.ts +0 -165
- package/src/react/contexts/transport-context.ts +0 -37
- package/src/react/contexts/transport-provider.tsx +0 -164
- package/src/react/create-transport-hooks.ts +0 -144
- package/src/react/use-active-turns.ts +0 -72
- package/src/react/use-client-transport.ts +0 -197
- package/src/vercel/codec/accumulator.ts +0 -588
- package/src/vercel/react/use-staged-add-tool-approval-response.ts +0 -87
- package/src/vercel/tool-approvals.ts +0 -380
- package/src/vercel/tool-events.ts +0 -53
|
@@ -6,24 +6,18 @@
|
|
|
6
6
|
* event decoding.
|
|
7
7
|
*
|
|
8
8
|
* Domain decoders call `createDecoderCore(hooks, options)` and provide hooks
|
|
9
|
-
* for stream classification, event building, and discrete decoding.
|
|
9
|
+
* for stream classification, event building, and discrete decoding. Hooks
|
|
10
|
+
* return a flat `TEvent[]` — no event-vs-message union. Per-message routing
|
|
11
|
+
* concerns (`codec-message-id`) are handled by the SDK via `ReducerMeta`, not
|
|
12
|
+
* here.
|
|
10
13
|
*/
|
|
11
14
|
|
|
12
15
|
import type * as Ably from 'ably';
|
|
13
16
|
|
|
14
|
-
import {
|
|
17
|
+
import { HEADER_STATUS, HEADER_STREAM, HEADER_STREAM_ID } from '../../constants.js';
|
|
15
18
|
import type { Logger } from '../../logger.js';
|
|
16
|
-
import {
|
|
17
|
-
import type {
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Wrap a domain event as a single-element decoder output array.
|
|
21
|
-
* @param event - The domain event to wrap.
|
|
22
|
-
* @returns A single-element array containing the event as a decoder output.
|
|
23
|
-
*/
|
|
24
|
-
export const eventOutput = <TEvent, TMessage>(event: TEvent): DecoderOutput<TEvent, TMessage>[] => [
|
|
25
|
-
{ kind: 'event', event },
|
|
26
|
-
];
|
|
19
|
+
import { getCodecHeaders, getTransportHeaders } from '../../utils.js';
|
|
20
|
+
import type { MessagePayload, StreamTrackerState } from './types.js';
|
|
27
21
|
|
|
28
22
|
// ---------------------------------------------------------------------------
|
|
29
23
|
// Options
|
|
@@ -44,32 +38,29 @@ export interface DecoderCoreOptions {
|
|
|
44
38
|
// ---------------------------------------------------------------------------
|
|
45
39
|
|
|
46
40
|
/** Hooks that a domain codec provides to the decoder core for stream classification and event building. */
|
|
47
|
-
export interface DecoderCoreHooks<TEvent
|
|
41
|
+
export interface DecoderCoreHooks<TEvent> {
|
|
48
42
|
/**
|
|
49
43
|
* Build domain events emitted when a new stream starts. May return multiple
|
|
50
44
|
* events (e.g. a start event and a start-step event).
|
|
51
45
|
*/
|
|
52
|
-
buildStartEvents(tracker: StreamTrackerState):
|
|
46
|
+
buildStartEvents(tracker: StreamTrackerState): TEvent[];
|
|
53
47
|
|
|
54
48
|
/** Build domain events for a text delta received on a stream. */
|
|
55
|
-
buildDeltaEvents(tracker: StreamTrackerState, delta: string):
|
|
49
|
+
buildDeltaEvents(tracker: StreamTrackerState, delta: string): TEvent[];
|
|
56
50
|
|
|
57
51
|
/**
|
|
58
|
-
* Build domain events emitted when a stream
|
|
59
|
-
* Not called for
|
|
60
|
-
* tracker.
|
|
52
|
+
* Build domain events emitted when a stream completes (status:complete).
|
|
53
|
+
* Not called for cancelled streams. The closing codec headers may differ
|
|
54
|
+
* from tracker.codecHeaders if the closing append carried updated headers.
|
|
61
55
|
*/
|
|
62
|
-
buildEndEvents(
|
|
63
|
-
tracker: StreamTrackerState,
|
|
64
|
-
closingHeaders: Record<string, string>,
|
|
65
|
-
): DecoderOutput<TEvent, TMessage>[];
|
|
56
|
+
buildEndEvents(tracker: StreamTrackerState, closingCodecHeaders: Record<string, string>): TEvent[];
|
|
66
57
|
|
|
67
58
|
/**
|
|
68
|
-
* Decode a discrete message (message.create
|
|
69
|
-
* or a non-streamable first-contact update). Handles user messages,
|
|
70
|
-
*
|
|
59
|
+
* Decode a discrete message (a `message.create` whose stream header is not
|
|
60
|
+
* "true", or a non-streamable first-contact update). Handles user messages,
|
|
61
|
+
* tool lifecycle, data-*, etc.
|
|
71
62
|
*/
|
|
72
|
-
decodeDiscrete(input: MessagePayload):
|
|
63
|
+
decodeDiscrete(input: MessagePayload): TEvent[];
|
|
73
64
|
}
|
|
74
65
|
|
|
75
66
|
// ---------------------------------------------------------------------------
|
|
@@ -77,9 +68,9 @@ export interface DecoderCoreHooks<TEvent, TMessage> {
|
|
|
77
68
|
// ---------------------------------------------------------------------------
|
|
78
69
|
|
|
79
70
|
/** The decoder core returned by {@link createDecoderCore}. */
|
|
80
|
-
export interface DecoderCore<TEvent
|
|
81
|
-
/** Decode a single Ably message into zero or more domain
|
|
82
|
-
decode(message: Ably.InboundMessage):
|
|
71
|
+
export interface DecoderCore<TEvent> {
|
|
72
|
+
/** Decode a single Ably message into zero or more domain TEvents. */
|
|
73
|
+
decode(message: Ably.InboundMessage): TEvent[];
|
|
83
74
|
}
|
|
84
75
|
|
|
85
76
|
// ---------------------------------------------------------------------------
|
|
@@ -87,70 +78,50 @@ export interface DecoderCore<TEvent, TMessage> {
|
|
|
87
78
|
// ---------------------------------------------------------------------------
|
|
88
79
|
|
|
89
80
|
// Spec: AIT-CD7
|
|
90
|
-
class DefaultDecoderCore<TEvent
|
|
91
|
-
private readonly _hooks: DecoderCoreHooks<TEvent
|
|
81
|
+
class DefaultDecoderCore<TEvent> implements DecoderCore<TEvent> {
|
|
82
|
+
private readonly _hooks: DecoderCoreHooks<TEvent>;
|
|
92
83
|
private readonly _logger: Logger | undefined;
|
|
93
84
|
private readonly _onStreamUpdate: ((tracker: StreamTrackerState) => void) | undefined;
|
|
94
85
|
private readonly _onStreamDelete: ((serial: string, tracker: StreamTrackerState | undefined) => void) | undefined;
|
|
95
86
|
private readonly _serialState = new Map<string, StreamTrackerState>();
|
|
96
87
|
|
|
97
|
-
constructor(hooks: DecoderCoreHooks<TEvent
|
|
88
|
+
constructor(hooks: DecoderCoreHooks<TEvent>, options: DecoderCoreOptions = {}) {
|
|
98
89
|
this._hooks = hooks;
|
|
99
90
|
this._onStreamUpdate = options.onStreamUpdate;
|
|
100
91
|
this._onStreamDelete = options.onStreamDelete;
|
|
101
92
|
this._logger = options.logger?.withContext({ component: 'DecoderCore' });
|
|
102
93
|
}
|
|
103
94
|
|
|
104
|
-
decode(message: Ably.InboundMessage):
|
|
95
|
+
decode(message: Ably.InboundMessage): TEvent[] {
|
|
105
96
|
const action = message.action;
|
|
106
97
|
|
|
107
98
|
this._logger?.trace('DefaultDecoderCore.decode();', { action, serial: message.serial, name: message.name });
|
|
108
99
|
|
|
109
|
-
let outputs: DecoderOutput<TEvent, TMessage>[];
|
|
110
|
-
|
|
111
100
|
switch (action) {
|
|
112
101
|
// Spec: AIT-CD7a
|
|
113
102
|
case 'message.create': {
|
|
114
103
|
const payload = this._toPayload(message);
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
payload
|
|
118
|
-
? this._decodeStreamedCreate(payload, message.serial)
|
|
119
|
-
: this._hooks.decodeDiscrete(payload);
|
|
120
|
-
break;
|
|
104
|
+
return payload.transportHeaders?.[HEADER_STREAM] === 'true'
|
|
105
|
+
? this._decodeStreamedCreate(payload, message.serial)
|
|
106
|
+
: this._hooks.decodeDiscrete(payload);
|
|
121
107
|
}
|
|
122
108
|
|
|
123
109
|
case 'message.append': {
|
|
124
|
-
|
|
125
|
-
break;
|
|
110
|
+
return this._decodeAppend(message);
|
|
126
111
|
}
|
|
127
112
|
|
|
128
113
|
case 'message.update': {
|
|
129
|
-
|
|
130
|
-
break;
|
|
114
|
+
return this._decodeUpdate(message);
|
|
131
115
|
}
|
|
132
116
|
|
|
133
117
|
case 'message.delete': {
|
|
134
|
-
|
|
135
|
-
break;
|
|
118
|
+
return this._decodeDelete(message);
|
|
136
119
|
}
|
|
137
120
|
|
|
138
121
|
default: {
|
|
139
122
|
return [];
|
|
140
123
|
}
|
|
141
124
|
}
|
|
142
|
-
|
|
143
|
-
// Tag all event outputs with the message ID from x-ably-msg-id for accumulator correlation.
|
|
144
|
-
const messageId = getHeaders(message)[HEADER_MSG_ID];
|
|
145
|
-
if (messageId) {
|
|
146
|
-
for (const output of outputs) {
|
|
147
|
-
if (output.kind === 'event') {
|
|
148
|
-
output.messageId = messageId;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
return outputs;
|
|
154
125
|
}
|
|
155
126
|
|
|
156
127
|
// -------------------------------------------------------------------------
|
|
@@ -162,7 +133,8 @@ class DefaultDecoderCore<TEvent, TMessage> implements DecoderCore<TEvent, TMessa
|
|
|
162
133
|
name: message.name ?? '',
|
|
163
134
|
// CAST: Ably SDK types `data` as `any`; cast to unknown is the safe boundary type.
|
|
164
135
|
data: message.data as unknown,
|
|
165
|
-
|
|
136
|
+
transportHeaders: getTransportHeaders(message),
|
|
137
|
+
codecHeaders: getCodecHeaders(message),
|
|
166
138
|
};
|
|
167
139
|
}
|
|
168
140
|
|
|
@@ -201,20 +173,17 @@ class DefaultDecoderCore<TEvent, TMessage> implements DecoderCore<TEvent, TMessa
|
|
|
201
173
|
// Private: streamed message create
|
|
202
174
|
// -------------------------------------------------------------------------
|
|
203
175
|
|
|
204
|
-
private _decodeStreamedCreate(
|
|
205
|
-
payload: MessagePayload,
|
|
206
|
-
serial: string | undefined,
|
|
207
|
-
): DecoderOutput<TEvent, TMessage>[] {
|
|
176
|
+
private _decodeStreamedCreate(payload: MessagePayload, serial: string | undefined): TEvent[] {
|
|
208
177
|
if (!serial) return [];
|
|
209
178
|
|
|
210
|
-
const streamId = payload.
|
|
211
|
-
const h = payload.headers ?? {};
|
|
179
|
+
const streamId = payload.transportHeaders?.[HEADER_STREAM_ID] ?? '';
|
|
212
180
|
|
|
213
181
|
const tracker: StreamTrackerState = {
|
|
214
182
|
name: payload.name,
|
|
215
183
|
streamId,
|
|
216
184
|
accumulated: '',
|
|
217
|
-
|
|
185
|
+
codecHeaders: { ...payload.codecHeaders },
|
|
186
|
+
transportHeaders: { ...payload.transportHeaders },
|
|
218
187
|
closed: false,
|
|
219
188
|
};
|
|
220
189
|
this._serialState.set(serial, tracker);
|
|
@@ -233,7 +202,7 @@ class DefaultDecoderCore<TEvent, TMessage> implements DecoderCore<TEvent, TMessa
|
|
|
233
202
|
// -------------------------------------------------------------------------
|
|
234
203
|
|
|
235
204
|
// Spec: AIT-CD8
|
|
236
|
-
private _decodeAppend(message: Ably.InboundMessage):
|
|
205
|
+
private _decodeAppend(message: Ably.InboundMessage): TEvent[] {
|
|
237
206
|
const serial = message.serial;
|
|
238
207
|
if (!serial) return [];
|
|
239
208
|
|
|
@@ -243,23 +212,24 @@ class DefaultDecoderCore<TEvent, TMessage> implements DecoderCore<TEvent, TMessa
|
|
|
243
212
|
return this._decodeUpdate(message);
|
|
244
213
|
}
|
|
245
214
|
|
|
246
|
-
const
|
|
215
|
+
const transport = getTransportHeaders(message);
|
|
216
|
+
const closingCodec = getCodecHeaders(message);
|
|
247
217
|
const delta = typeof message.data === 'string' ? message.data : '';
|
|
248
|
-
const status =
|
|
249
|
-
const outputs:
|
|
218
|
+
const status = transport[HEADER_STATUS];
|
|
219
|
+
const outputs: TEvent[] = [];
|
|
250
220
|
|
|
251
221
|
if (delta.length > 0) {
|
|
252
222
|
tracker.accumulated += delta;
|
|
253
223
|
outputs.push(...this._hooks.buildDeltaEvents(tracker, delta));
|
|
254
224
|
}
|
|
255
225
|
|
|
256
|
-
if (status === '
|
|
226
|
+
if (status === 'complete' && !tracker.closed) {
|
|
257
227
|
tracker.closed = true;
|
|
258
|
-
outputs.push(...this._hooks.buildEndEvents(tracker,
|
|
259
|
-
this._logger?.debug('DefaultDecoderCore._decodeAppend(); stream
|
|
260
|
-
} else if (status === '
|
|
228
|
+
outputs.push(...this._hooks.buildEndEvents(tracker, closingCodec));
|
|
229
|
+
this._logger?.debug('DefaultDecoderCore._decodeAppend(); stream complete', { streamId: tracker.streamId });
|
|
230
|
+
} else if (status === 'cancelled' && !tracker.closed) {
|
|
261
231
|
tracker.closed = true;
|
|
262
|
-
this._logger?.debug('DefaultDecoderCore._decodeAppend(); stream
|
|
232
|
+
this._logger?.debug('DefaultDecoderCore._decodeAppend(); stream cancelled', { streamId: tracker.streamId });
|
|
263
233
|
}
|
|
264
234
|
|
|
265
235
|
return outputs;
|
|
@@ -270,14 +240,15 @@ class DefaultDecoderCore<TEvent, TMessage> implements DecoderCore<TEvent, TMessa
|
|
|
270
240
|
// -------------------------------------------------------------------------
|
|
271
241
|
|
|
272
242
|
// Spec: AIT-CD9
|
|
273
|
-
private _decodeUpdate(message: Ably.InboundMessage):
|
|
243
|
+
private _decodeUpdate(message: Ably.InboundMessage): TEvent[] {
|
|
274
244
|
const serial = message.serial;
|
|
275
245
|
if (!serial) return [];
|
|
276
246
|
|
|
277
247
|
const payload = this._toPayload(message);
|
|
278
|
-
const
|
|
279
|
-
const
|
|
280
|
-
const
|
|
248
|
+
const transport = payload.transportHeaders ?? {};
|
|
249
|
+
const codec = payload.codecHeaders ?? {};
|
|
250
|
+
const isStreamed = transport[HEADER_STREAM] === 'true';
|
|
251
|
+
const status = transport[HEADER_STATUS];
|
|
281
252
|
|
|
282
253
|
const tracker = this._serialState.get(serial);
|
|
283
254
|
|
|
@@ -291,17 +262,17 @@ class DefaultDecoderCore<TEvent, TMessage> implements DecoderCore<TEvent, TMessa
|
|
|
291
262
|
// --- Tracker exists: prefix-match or replacement ---
|
|
292
263
|
if (data.startsWith(tracker.accumulated)) {
|
|
293
264
|
const delta = data.slice(tracker.accumulated.length);
|
|
294
|
-
const outputs:
|
|
265
|
+
const outputs: TEvent[] = [];
|
|
295
266
|
|
|
296
267
|
if (delta.length > 0) {
|
|
297
268
|
tracker.accumulated = data;
|
|
298
269
|
outputs.push(...this._hooks.buildDeltaEvents(tracker, delta));
|
|
299
270
|
}
|
|
300
271
|
|
|
301
|
-
if (status === '
|
|
272
|
+
if (status === 'complete' && !tracker.closed) {
|
|
302
273
|
tracker.closed = true;
|
|
303
|
-
outputs.push(...this._hooks.buildEndEvents(tracker,
|
|
304
|
-
} else if (status === '
|
|
274
|
+
outputs.push(...this._hooks.buildEndEvents(tracker, codec));
|
|
275
|
+
} else if (status === 'cancelled' && !tracker.closed) {
|
|
305
276
|
tracker.closed = true;
|
|
306
277
|
}
|
|
307
278
|
|
|
@@ -310,7 +281,8 @@ class DefaultDecoderCore<TEvent, TMessage> implements DecoderCore<TEvent, TMessa
|
|
|
310
281
|
|
|
311
282
|
// --- Replacement (NOT a prefix match) ---
|
|
312
283
|
tracker.accumulated = data;
|
|
313
|
-
tracker.
|
|
284
|
+
tracker.codecHeaders = { ...codec };
|
|
285
|
+
tracker.transportHeaders = { ...transport };
|
|
314
286
|
|
|
315
287
|
this._invokeOnStreamUpdate(tracker);
|
|
316
288
|
|
|
@@ -322,14 +294,14 @@ class DefaultDecoderCore<TEvent, TMessage> implements DecoderCore<TEvent, TMessa
|
|
|
322
294
|
isStreamed: boolean,
|
|
323
295
|
status: string | undefined,
|
|
324
296
|
serial: string,
|
|
325
|
-
):
|
|
297
|
+
): TEvent[] {
|
|
326
298
|
// Non-streamed messages are discrete
|
|
327
299
|
if (!isStreamed) {
|
|
328
300
|
return this._hooks.decodeDiscrete(payload);
|
|
329
301
|
}
|
|
330
302
|
|
|
331
|
-
const streamId = payload.
|
|
332
|
-
const
|
|
303
|
+
const streamId = payload.transportHeaders?.[HEADER_STREAM_ID] ?? '';
|
|
304
|
+
const codec = payload.codecHeaders ?? {};
|
|
333
305
|
const data = typeof payload.data === 'string' ? payload.data : '';
|
|
334
306
|
|
|
335
307
|
this._logger?.debug('DefaultDecoderCore._decodeFirstContact(); first-contact stream', {
|
|
@@ -343,20 +315,21 @@ class DefaultDecoderCore<TEvent, TMessage> implements DecoderCore<TEvent, TMessa
|
|
|
343
315
|
name: payload.name,
|
|
344
316
|
streamId,
|
|
345
317
|
accumulated: data,
|
|
346
|
-
|
|
347
|
-
|
|
318
|
+
codecHeaders: { ...codec },
|
|
319
|
+
transportHeaders: { ...payload.transportHeaders },
|
|
320
|
+
closed: status === 'complete' || status === 'cancelled',
|
|
348
321
|
};
|
|
349
322
|
this._serialState.set(serial, newTracker);
|
|
350
323
|
|
|
351
|
-
// Emit start + delta (if any) + end (if
|
|
324
|
+
// Emit start + delta (if any) + end (if complete)
|
|
352
325
|
const outputs = this._hooks.buildStartEvents(newTracker);
|
|
353
326
|
|
|
354
327
|
if (data.length > 0) {
|
|
355
328
|
outputs.push(...this._hooks.buildDeltaEvents(newTracker, data));
|
|
356
329
|
}
|
|
357
330
|
|
|
358
|
-
if (status === '
|
|
359
|
-
outputs.push(...this._hooks.buildEndEvents(newTracker,
|
|
331
|
+
if (status === 'complete') {
|
|
332
|
+
outputs.push(...this._hooks.buildEndEvents(newTracker, codec));
|
|
360
333
|
}
|
|
361
334
|
|
|
362
335
|
return outputs;
|
|
@@ -367,7 +340,7 @@ class DefaultDecoderCore<TEvent, TMessage> implements DecoderCore<TEvent, TMessa
|
|
|
367
340
|
// -------------------------------------------------------------------------
|
|
368
341
|
|
|
369
342
|
// Spec: AIT-CD10
|
|
370
|
-
private _decodeDelete(message: Ably.InboundMessage):
|
|
343
|
+
private _decodeDelete(message: Ably.InboundMessage): TEvent[] {
|
|
371
344
|
const serial = message.serial;
|
|
372
345
|
if (!serial) return [];
|
|
373
346
|
|
|
@@ -396,7 +369,7 @@ class DefaultDecoderCore<TEvent, TMessage> implements DecoderCore<TEvent, TMessa
|
|
|
396
369
|
* @param options - Decoder configuration (callbacks, logger).
|
|
397
370
|
* @returns A new {@link DecoderCore} instance.
|
|
398
371
|
*/
|
|
399
|
-
export const createDecoderCore = <TEvent
|
|
400
|
-
hooks: DecoderCoreHooks<TEvent
|
|
372
|
+
export const createDecoderCore = <TEvent>(
|
|
373
|
+
hooks: DecoderCoreHooks<TEvent>,
|
|
401
374
|
options: DecoderCoreOptions = {},
|
|
402
|
-
): DecoderCore<TEvent
|
|
375
|
+
): DecoderCore<TEvent> => new DefaultDecoderCore(hooks, options);
|