@opengeni/sdk 0.52.1 → 1.0.1
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 +67 -7
- package/dist/artifacts.js +5 -5
- package/dist/{chunk-FRJFNDIR.js → chunk-4DV37UUA.js} +6 -2
- package/dist/chunk-4DV37UUA.js.map +1 -0
- package/dist/{chunk-KIHGPM7H.js → chunk-A5DC5WEM.js} +288 -45
- package/dist/chunk-A5DC5WEM.js.map +1 -0
- package/dist/{chunk-V5F253OG.js → chunk-GU6JF75T.js} +6 -3
- package/dist/chunk-GU6JF75T.js.map +1 -0
- package/dist/{chunk-MZWTWOX6.js → chunk-ST5DDKJP.js} +327 -1
- package/dist/chunk-ST5DDKJP.js.map +1 -0
- package/dist/{chunk-FHI4DFIG.js → chunk-TYZ4JL4J.js} +2 -2
- package/dist/{chunk-ILQZR5N6.js → chunk-YGH5P47G.js} +693 -34
- package/dist/chunk-YGH5P47G.js.map +1 -0
- package/dist/{chunk-DXDL7EEW.js → chunk-YKZME56C.js} +197 -113
- package/dist/chunk-YKZME56C.js.map +1 -0
- package/dist/client.d.ts +108 -18
- package/dist/codex-realtime-controller.d.ts +5 -0
- package/dist/codex-realtime-controller.js +2 -2
- package/dist/codex-realtime-v3.d.ts +13 -2
- package/dist/core.js +7 -7
- package/dist/desktop.d.ts +8 -0
- package/dist/editable-artifacts.js +4 -4
- package/dist/gateway-realtime-transport.d.ts +1 -0
- package/dist/gateway-realtime-transport.js +5 -3
- package/dist/index.d.ts +6 -2
- package/dist/index.js +68 -34
- package/dist/index.js.map +1 -1
- package/dist/interaction-revision-stream.d.ts +11 -0
- package/dist/interaction.d.ts +604 -5
- package/dist/interaction.js +27 -1
- package/dist/realtime.d.ts +3 -3
- package/dist/realtime.js +11 -7
- package/dist/realtime.js.map +1 -1
- package/dist/types.d.ts +283 -69
- package/dist/workspace-live-stream.d.ts +14 -0
- package/package.json +2 -2
- package/src/client.ts +863 -62
- package/src/codex-realtime-controller.ts +239 -12
- package/src/codex-realtime-lifecycle.ts +1 -0
- package/src/codex-realtime-v3.ts +162 -31
- package/src/desktop.ts +11 -1
- package/src/errors.ts +16 -2
- package/src/gateway-realtime-transport.ts +252 -109
- package/src/index.ts +42 -13
- package/src/interaction-revision-stream.ts +117 -0
- package/src/interaction.ts +1049 -5
- package/src/realtime.ts +14 -4
- package/src/types.ts +353 -72
- package/src/workspace-live-stream.ts +137 -0
- package/dist/chunk-DXDL7EEW.js.map +0 -1
- package/dist/chunk-FRJFNDIR.js.map +0 -1
- package/dist/chunk-ILQZR5N6.js.map +0 -1
- package/dist/chunk-KIHGPM7H.js.map +0 -1
- package/dist/chunk-MZWTWOX6.js.map +0 -1
- package/dist/chunk-V5F253OG.js.map +0 -1
- /package/dist/{chunk-FHI4DFIG.js.map → chunk-TYZ4JL4J.js.map} +0 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { isAbortError, isRetryableStreamError, OpenGeniStreamError } from "./errors";
|
|
2
|
+
import type { WorkspaceInteractionRevisionEvent } from "./interaction";
|
|
3
|
+
import { parseSseStream } from "./sse";
|
|
4
|
+
import {
|
|
5
|
+
jitteredDelay,
|
|
6
|
+
runBeforeLive,
|
|
7
|
+
type StreamSessionEventsOptions,
|
|
8
|
+
withStreamInactivityTimeout,
|
|
9
|
+
} from "./stream";
|
|
10
|
+
|
|
11
|
+
export type WorkspaceInteractionRevisionStreamTransport = {
|
|
12
|
+
openStream: (
|
|
13
|
+
after: number,
|
|
14
|
+
signal: AbortSignal | undefined,
|
|
15
|
+
) => Promise<ReadableStream<Uint8Array>>;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Reconnecting latest-revision stream. Revisions may skip because intermediate
|
|
20
|
+
* invalidations carry no independent evidence; every delivered value means
|
|
21
|
+
* "refetch any interaction resources older than this cursor".
|
|
22
|
+
*/
|
|
23
|
+
export async function* streamWorkspaceInteractionRevisions(
|
|
24
|
+
transport: WorkspaceInteractionRevisionStreamTransport,
|
|
25
|
+
options: StreamSessionEventsOptions = {},
|
|
26
|
+
): AsyncGenerator<WorkspaceInteractionRevisionEvent, void, void> {
|
|
27
|
+
const signal = options.signal;
|
|
28
|
+
const reconnect = options.reconnect ?? true;
|
|
29
|
+
const baseDelayMs = options.reconnectDelayMs ?? 500;
|
|
30
|
+
const maxDelayMs = options.maxReconnectDelayMs ?? 10_000;
|
|
31
|
+
const jitterRatio = options.reconnectJitterRatio ?? 0.2;
|
|
32
|
+
const beforeLiveTimeoutMs = options.beforeLiveTimeoutMs ?? 15_000;
|
|
33
|
+
const heartbeatTimeoutMs = options.heartbeatTimeoutMs ?? 45_000;
|
|
34
|
+
const maxAttempts = options.maxReconnectAttempts ?? Number.POSITIVE_INFINITY;
|
|
35
|
+
let cursor = options.after ?? 0;
|
|
36
|
+
let failures = 0;
|
|
37
|
+
let delayMs = baseDelayMs;
|
|
38
|
+
let everConnected = false;
|
|
39
|
+
|
|
40
|
+
for (;;) {
|
|
41
|
+
if (signal?.aborted) return;
|
|
42
|
+
options.onStateChange?.(everConnected || failures > 0 ? "reconnecting" : "connecting");
|
|
43
|
+
const cursorAtOpen = cursor;
|
|
44
|
+
try {
|
|
45
|
+
const body = await transport.openStream(cursor, signal);
|
|
46
|
+
everConnected = true;
|
|
47
|
+
failures = 0;
|
|
48
|
+
delayMs = baseDelayMs;
|
|
49
|
+
await runBeforeLive(options.beforeLive, beforeLiveTimeoutMs, signal);
|
|
50
|
+
options.onStateChange?.("live");
|
|
51
|
+
for await (const message of parseSseStream(
|
|
52
|
+
withStreamInactivityTimeout(body, heartbeatTimeoutMs, signal),
|
|
53
|
+
)) {
|
|
54
|
+
if (signal?.aborted) return;
|
|
55
|
+
const event = parseWorkspaceInteractionRevision(message.data);
|
|
56
|
+
if (!event || event.sequence <= cursor) continue;
|
|
57
|
+
cursor = event.sequence;
|
|
58
|
+
yield event;
|
|
59
|
+
}
|
|
60
|
+
if (!reconnect) return;
|
|
61
|
+
if (cursor === cursorAtOpen) await sleep(jitteredDelay(baseDelayMs, jitterRatio), signal);
|
|
62
|
+
continue;
|
|
63
|
+
} catch (error) {
|
|
64
|
+
if (signal?.aborted || isAbortError(error)) return;
|
|
65
|
+
if (!reconnect || !isRetryableStreamError(error)) throw error;
|
|
66
|
+
failures += 1;
|
|
67
|
+
if (failures > maxAttempts) {
|
|
68
|
+
throw new OpenGeniStreamError(
|
|
69
|
+
`workspace interaction stream gave up after ${maxAttempts} reconnect attempts: ${
|
|
70
|
+
error instanceof Error ? error.message : String(error)
|
|
71
|
+
}`,
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
await sleep(jitteredDelay(delayMs, jitterRatio), signal);
|
|
76
|
+
delayMs = Math.min(Math.max(delayMs * 2, baseDelayMs), maxDelayMs);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function parseWorkspaceInteractionRevision(data: string): WorkspaceInteractionRevisionEvent | null {
|
|
81
|
+
let value: unknown;
|
|
82
|
+
try {
|
|
83
|
+
value = JSON.parse(data);
|
|
84
|
+
} catch {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
if (
|
|
88
|
+
!isRecord(value) ||
|
|
89
|
+
value.type !== "workspace.interaction.changed" ||
|
|
90
|
+
typeof value.workspaceId !== "string" ||
|
|
91
|
+
typeof value.sequence !== "number" ||
|
|
92
|
+
!Number.isSafeInteger(value.sequence) ||
|
|
93
|
+
value.sequence < 0 ||
|
|
94
|
+
value.revision !== value.sequence ||
|
|
95
|
+
typeof value.occurredAt !== "string"
|
|
96
|
+
) {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
return value as WorkspaceInteractionRevisionEvent;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
103
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async function sleep(delayMs: number, signal: AbortSignal | undefined): Promise<void> {
|
|
107
|
+
if (signal?.aborted || delayMs <= 0) return;
|
|
108
|
+
await new Promise<void>((resolve) => {
|
|
109
|
+
const timer = setTimeout(done, delayMs);
|
|
110
|
+
function done() {
|
|
111
|
+
clearTimeout(timer);
|
|
112
|
+
signal?.removeEventListener("abort", done);
|
|
113
|
+
resolve();
|
|
114
|
+
}
|
|
115
|
+
signal?.addEventListener("abort", done, { once: true });
|
|
116
|
+
});
|
|
117
|
+
}
|