@opengeni/react 1.0.1 → 2.2.0-canary.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 +33 -10
- package/dist/artifacts-spreadsheet.js +1 -1
- package/dist/artifacts.js +1 -1
- package/dist/browser-viewer-GXUICIAG.js +14 -0
- package/dist/{chunk-R3AZOAB5.js → chunk-4MDLEHXL.js} +9 -115
- package/dist/chunk-4MDLEHXL.js.map +1 -0
- package/dist/{chunk-Y7OEDUJ5.js → chunk-5RZN3DD5.js} +1014 -420
- package/dist/chunk-5RZN3DD5.js.map +1 -0
- package/dist/chunk-5YK2ZDIG.js +116 -0
- package/dist/chunk-5YK2ZDIG.js.map +1 -0
- package/dist/chunk-H5YGYNXS.js +329 -0
- package/dist/chunk-H5YGYNXS.js.map +1 -0
- package/dist/{chunk-7WCLAEFV.js → chunk-ICA6R6TW.js} +2 -2
- package/dist/{chunk-7WCLAEFV.js.map → chunk-ICA6R6TW.js.map} +1 -1
- package/dist/{chunk-IGC6A2ZI.js → chunk-JOAVA2TW.js} +589 -217
- package/dist/chunk-JOAVA2TW.js.map +1 -0
- package/dist/{chunk-5UQPNLIO.js → chunk-LTCHJ4MS.js} +9 -9
- package/dist/chunk-LTCHJ4MS.js.map +1 -0
- package/dist/{chunk-C5ZPSSS5.js → chunk-NEXLLTP4.js} +2 -1
- package/dist/{chunk-C5ZPSSS5.js.map → chunk-NEXLLTP4.js.map} +1 -1
- package/dist/chunk-QGBJ6GHG.js +2300 -0
- package/dist/chunk-QGBJ6GHG.js.map +1 -0
- package/dist/{chunk-B6WPZSTT.js → chunk-UOLJWT5Y.js} +78 -16
- package/dist/chunk-UOLJWT5Y.js.map +1 -0
- package/dist/{chunk-MKPIAGVL.js → chunk-W6NFJXSA.js} +8 -19
- package/dist/chunk-W6NFJXSA.js.map +1 -0
- package/dist/{chunk-XBZWOM2K.js → chunk-X4A66EWZ.js} +8 -3
- package/dist/chunk-X4A66EWZ.js.map +1 -0
- package/dist/chunk-X4JAFD5R.js +3907 -0
- package/dist/chunk-X4JAFD5R.js.map +1 -0
- package/dist/{chunk-6KLX2RH5.js → chunk-XSA2QAKP.js} +334 -19
- package/dist/chunk-XSA2QAKP.js.map +1 -0
- package/dist/{chunk-HA46CYQK.js → chunk-XXWH2JLC.js} +792 -206
- package/dist/chunk-XXWH2JLC.js.map +1 -0
- package/dist/client.d.ts +2 -2
- package/dist/components/browser-viewer.d.ts +7 -1
- package/dist/components/computer-viewer.d.ts +4 -1
- package/dist/components/enrollment-consent.d.ts +6 -3
- package/dist/components/file-browser.d.ts +7 -1
- package/dist/components/human-input-form.d.ts +1 -1
- package/dist/components/human-input-surface.d.ts +1 -1
- package/dist/components/machine-card.d.ts +4 -1
- package/dist/components/machines/machine-detail.d.ts +4 -1
- package/dist/components/machines/machine-operation-policy.d.ts +11 -0
- package/dist/components/machines-dashboard.d.ts +3 -1
- package/dist/components/markdown.d.ts +20 -1
- package/dist/components/message-timeline.d.ts +1 -1
- package/dist/components/model-policy-picker.d.ts +2 -0
- package/dist/components/pierre-file.d.ts +1 -1
- package/dist/components/sandbox-files.d.ts +8 -2
- package/dist/components/sandbox-workspace.d.ts +33 -3
- package/dist/components/session-chrome.d.ts +15 -3
- package/dist/components/workspace-dock.d.ts +6 -2
- package/dist/composer.js +5 -5
- package/dist/computer-viewer-ZOP4Q7A7.js +16 -0
- package/dist/computer-viewer-ZOP4Q7A7.js.map +1 -0
- package/dist/hooks/channel-cache.d.ts +23 -0
- package/dist/hooks/shared-machines-list.d.ts +14 -0
- package/dist/hooks/use-attached-browsers.d.ts +2 -1
- package/dist/hooks/use-channels.d.ts +1 -0
- package/dist/hooks/use-composer.d.ts +37 -9
- package/dist/hooks/use-machine-chip.d.ts +3 -3
- package/dist/hooks/use-machines.d.ts +19 -1
- package/dist/hooks/use-sandbox-files.d.ts +1 -0
- package/dist/hooks/use-session-background-commands.d.ts +14 -0
- package/dist/hooks/use-turn-queue.d.ts +12 -0
- package/dist/hooks/use-workspace-sessions.d.ts +1 -0
- package/dist/index.d.ts +7 -5
- package/dist/index.js +1096 -623
- package/dist/index.js.map +1 -1
- package/dist/interaction.js +29 -181
- package/dist/interaction.js.map +1 -1
- package/dist/lib/interaction-errors.d.ts +3 -0
- package/dist/machines.d.ts +4 -2
- package/dist/machines.js +10 -2
- package/dist/model-policy.d.ts +1 -1
- package/dist/model-policy.js +1 -1
- package/dist/platform-activity-row-BJHUHXAT.js +169 -0
- package/dist/platform-activity-row-BJHUHXAT.js.map +1 -0
- package/dist/{queue-surface-implementation-2KVJTYXH.js → queue-surface-implementation-BSKUWHRI.js} +76 -16
- package/dist/queue-surface-implementation-BSKUWHRI.js.map +1 -0
- package/dist/realtime/realtime-control.d.ts +6 -3
- package/dist/realtime.js +36 -14
- package/dist/realtime.js.map +1 -1
- package/dist/session-ui.d.ts +1 -1
- package/dist/session-ui.js +6 -2
- package/dist/session.d.ts +2 -2
- package/dist/session.js +4 -4
- package/dist/timeline/index.d.ts +1 -1
- package/dist/timeline/platform-activity-row.d.ts +15 -0
- package/dist/timeline/screenshot-lightbox.d.ts +1 -1
- package/dist/timeline/shared.d.ts +4 -2
- package/dist/timeline/types.d.ts +48 -5
- package/dist/types/machines.d.ts +2 -2
- package/package.json +3 -3
- package/src/client.ts +12 -1
- package/src/components/artifacts/editable-spreadsheet.tsx +1 -1
- package/src/components/browser-viewer.tsx +361 -58
- package/src/components/chat-composer.tsx +1 -1
- package/src/components/composer.tsx +6 -6
- package/src/components/computer-viewer.tsx +368 -115
- package/src/components/enrollment-consent.tsx +64 -6
- package/src/components/file-browser.tsx +117 -2
- package/src/components/human-input-form.tsx +91 -55
- package/src/components/human-input-surface.tsx +1 -1
- package/src/components/machine-card.tsx +111 -0
- package/src/components/machine-input-display.ts +15 -0
- package/src/components/machines/machine-detail.tsx +47 -0
- package/src/components/machines/machine-operation-policy.tsx +179 -0
- package/src/components/machines-dashboard.tsx +6 -0
- package/src/components/markdown.tsx +174 -20
- package/src/components/message-timeline.tsx +162 -17
- package/src/components/model-policy-picker.tsx +9 -17
- package/src/components/pierre-file.tsx +1 -1
- package/src/components/queue-surface-implementation.tsx +82 -16
- package/src/components/sandbox-files.tsx +135 -19
- package/src/components/sandbox-workspace.tsx +204 -92
- package/src/components/session-chrome.tsx +415 -208
- package/src/components/session-status.tsx +1 -1
- package/src/components/user-message-body.tsx +168 -48
- package/src/components/workspace-dock.tsx +141 -175
- package/src/hooks/channel-cache.ts +104 -0
- package/src/hooks/shared-machines-list.ts +239 -0
- package/src/hooks/use-attached-browsers.ts +5 -1
- package/src/hooks/use-browser-frame-stream.ts +6 -1
- package/src/hooks/use-browser-session.ts +6 -4
- package/src/hooks/use-browser-sessions.ts +7 -1
- package/src/hooks/use-channels.ts +32 -10
- package/src/hooks/use-composer.ts +760 -291
- package/src/hooks/use-computer-frame-stream.ts +14 -9
- package/src/hooks/use-computer-session.ts +16 -14
- package/src/hooks/use-computer-sessions.ts +8 -1
- package/src/hooks/use-last-started-turn-policy.ts +1 -1
- package/src/hooks/use-machine-chip.ts +23 -6
- package/src/hooks/use-machines.ts +104 -6
- package/src/hooks/use-sandbox-files.ts +195 -140
- package/src/hooks/use-sandbox-git.ts +58 -29
- package/src/hooks/use-session-background-commands.ts +56 -0
- package/src/hooks/use-session-capabilities.ts +18 -0
- package/src/hooks/use-turn-queue.ts +111 -12
- package/src/hooks/use-workspace-sessions.ts +5 -1
- package/src/index.ts +26 -4
- package/src/lib/interaction-errors.ts +18 -0
- package/src/machines.ts +9 -1
- package/src/model-policy.ts +10 -2
- package/src/realtime/realtime-control.tsx +53 -17
- package/src/session-context.ts +1 -0
- package/src/session-ui.ts +6 -1
- package/src/session.ts +9 -1
- package/src/timeline/activity-rail.tsx +20 -75
- package/src/timeline/index.ts +4 -0
- package/src/timeline/platform-activity-row.tsx +201 -0
- package/src/timeline/projection.ts +476 -23
- package/src/timeline/screenshot-lightbox.tsx +48 -14
- package/src/timeline/shared.tsx +8 -2
- package/src/timeline/tool-renderers.tsx +104 -6
- package/src/timeline/turn-summary.tsx +6 -1
- package/src/timeline/types.ts +75 -2
- package/src/types/machines.ts +10 -0
- package/styles/compiled.css +115 -104
- package/dist/chunk-5UQPNLIO.js.map +0 -1
- package/dist/chunk-6KLX2RH5.js.map +0 -1
- package/dist/chunk-B6WPZSTT.js.map +0 -1
- package/dist/chunk-HA46CYQK.js.map +0 -1
- package/dist/chunk-IGC6A2ZI.js.map +0 -1
- package/dist/chunk-LLOLUHVG.js +0 -5937
- package/dist/chunk-LLOLUHVG.js.map +0 -1
- package/dist/chunk-MKPIAGVL.js.map +0 -1
- package/dist/chunk-R3AZOAB5.js.map +0 -1
- package/dist/chunk-XBZWOM2K.js.map +0 -1
- package/dist/chunk-Y7OEDUJ5.js.map +0 -1
- package/dist/interactive-workbench-viewers-TOHBXJEE.js +0 -15
- package/dist/queue-surface-implementation-2KVJTYXH.js.map +0 -1
- /package/dist/{interactive-workbench-viewers-TOHBXJEE.js.map → browser-viewer-GXUICIAG.js.map} +0 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
// src/lib/relay-wire.ts
|
|
2
|
+
import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire";
|
|
3
|
+
var STREAM_KIND_DESKTOP = 2;
|
|
4
|
+
var STREAM_KIND_PTY = 1;
|
|
5
|
+
var STREAM_KIND_BROWSER = 3;
|
|
6
|
+
var STREAM_KIND_COMPUTER = 4;
|
|
7
|
+
var STREAM_ROLE_CLIENT = 2;
|
|
8
|
+
var STREAM_CLOSE_REASON_NORMAL = 1;
|
|
9
|
+
function encodeChannel(message, writer) {
|
|
10
|
+
if (message.channelId !== "") writer.uint32(10).string(message.channelId);
|
|
11
|
+
if (message.workspaceId !== "") writer.uint32(18).string(message.workspaceId);
|
|
12
|
+
if (message.agentId !== "") writer.uint32(26).string(message.agentId);
|
|
13
|
+
if (message.kind !== 0) writer.uint32(32).int32(message.kind);
|
|
14
|
+
if (message.port !== 0) writer.uint32(40).uint32(message.port);
|
|
15
|
+
return writer;
|
|
16
|
+
}
|
|
17
|
+
function encodeStreamOpen(message) {
|
|
18
|
+
const writer = new BinaryWriter();
|
|
19
|
+
encodeChannel(message.channel, writer.uint32(10).fork()).join();
|
|
20
|
+
if (message.token !== "") writer.uint32(18).string(message.token);
|
|
21
|
+
if (message.role !== 0) writer.uint32(24).int32(message.role);
|
|
22
|
+
if (message.resumeFromSeq !== "0") writer.uint32(32).uint64(message.resumeFromSeq);
|
|
23
|
+
return writer.finish();
|
|
24
|
+
}
|
|
25
|
+
function encodeStreamClose(message) {
|
|
26
|
+
const writer = new BinaryWriter();
|
|
27
|
+
if (message.channelId !== "") writer.uint32(10).string(message.channelId);
|
|
28
|
+
if (message.reason !== 0) writer.uint32(16).int32(message.reason);
|
|
29
|
+
if (message.message !== "") writer.uint32(26).string(message.message);
|
|
30
|
+
return writer.finish();
|
|
31
|
+
}
|
|
32
|
+
function encodeStreamFrame(message) {
|
|
33
|
+
const writer = new BinaryWriter();
|
|
34
|
+
if (message.channelId !== "") writer.uint32(10).string(message.channelId);
|
|
35
|
+
if (message.seq !== "0") writer.uint32(16).uint64(message.seq);
|
|
36
|
+
if (message.data.length > 0) writer.uint32(26).bytes(message.data);
|
|
37
|
+
if (message.producedAtMs !== "0") writer.uint32(32).uint64(message.producedAtMs);
|
|
38
|
+
return writer.finish();
|
|
39
|
+
}
|
|
40
|
+
function decodeAgentErrorMessage(reader, length) {
|
|
41
|
+
const end = reader.pos + length;
|
|
42
|
+
let message;
|
|
43
|
+
while (reader.pos < end) {
|
|
44
|
+
const tag = reader.uint32();
|
|
45
|
+
if (tag >>> 3 === 2 && tag === 18) {
|
|
46
|
+
message = reader.string();
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
if ((tag & 7) === 4 || tag === 0) break;
|
|
50
|
+
reader.skip(tag & 7);
|
|
51
|
+
}
|
|
52
|
+
return message !== void 0 ? { message } : {};
|
|
53
|
+
}
|
|
54
|
+
function decodeStreamOpenAck(bytes) {
|
|
55
|
+
const reader = new BinaryReader(bytes);
|
|
56
|
+
const end = reader.len;
|
|
57
|
+
let accepted = false;
|
|
58
|
+
let error;
|
|
59
|
+
while (reader.pos < end) {
|
|
60
|
+
const tag = reader.uint32();
|
|
61
|
+
if (tag >>> 3 === 1 && tag === 8) {
|
|
62
|
+
accepted = reader.bool();
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if (tag >>> 3 === 2 && tag === 18) {
|
|
66
|
+
error = decodeAgentErrorMessage(reader, reader.uint32());
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if ((tag & 7) === 4 || tag === 0) break;
|
|
70
|
+
reader.skip(tag & 7);
|
|
71
|
+
}
|
|
72
|
+
return error !== void 0 ? { accepted, error } : { accepted };
|
|
73
|
+
}
|
|
74
|
+
function decodeStreamFrame(bytes) {
|
|
75
|
+
const reader = new BinaryReader(bytes);
|
|
76
|
+
const end = reader.len;
|
|
77
|
+
let seq = "0";
|
|
78
|
+
let data = new Uint8Array(0);
|
|
79
|
+
while (reader.pos < end) {
|
|
80
|
+
const tag = reader.uint32();
|
|
81
|
+
if (tag >>> 3 === 2 && tag === 16) {
|
|
82
|
+
seq = reader.uint64().toString();
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
if (tag >>> 3 === 3 && tag === 26) {
|
|
86
|
+
data = new Uint8Array(reader.bytes());
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
if ((tag & 7) === 4 || tag === 0) break;
|
|
90
|
+
reader.skip(tag & 7);
|
|
91
|
+
}
|
|
92
|
+
return { seq, data };
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// src/lib/host-platform.ts
|
|
96
|
+
function interactionHostPlatform() {
|
|
97
|
+
if (typeof navigator === "undefined") return "other";
|
|
98
|
+
const platform = navigator.platform || navigator.userAgent;
|
|
99
|
+
return /Mac|iPhone|iPad|iPod/u.test(platform) ? "mac" : "other";
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export {
|
|
103
|
+
STREAM_KIND_DESKTOP,
|
|
104
|
+
STREAM_KIND_PTY,
|
|
105
|
+
STREAM_KIND_BROWSER,
|
|
106
|
+
STREAM_KIND_COMPUTER,
|
|
107
|
+
STREAM_ROLE_CLIENT,
|
|
108
|
+
STREAM_CLOSE_REASON_NORMAL,
|
|
109
|
+
encodeStreamOpen,
|
|
110
|
+
encodeStreamClose,
|
|
111
|
+
encodeStreamFrame,
|
|
112
|
+
decodeStreamOpenAck,
|
|
113
|
+
decodeStreamFrame,
|
|
114
|
+
interactionHostPlatform
|
|
115
|
+
};
|
|
116
|
+
//# sourceMappingURL=chunk-5YK2ZDIG.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/relay-wire.ts","../src/lib/host-platform.ts"],"sourcesContent":["// Minimal HAND-MIRROR of the relay stream wire messages the desktop frame client\n// needs (`StreamOpen`/`StreamClose` encode; `StreamOpenAck` + `StreamFrame` decode). It exists\n// because the publish-closure guard (scripts/publish-closure-guard.ts) forbids\n// `@opengeni/react` from depending on `@opengeni/agent-proto` — the published SDK\n// closure may only reach `@opengeni/sdk` among `@opengeni/*` packages. So, exactly\n// as the guard prescribes (\"hand-mirror it\"), we re-encode just these three\n// messages against the third-party `@bufbuild/protobuf/wire` runtime (the same\n// runtime `@opengeni/agent-proto` generates against), byte-compatible with the\n// generated code. Field numbers copied verbatim from\n// `packages/agent-proto/src/gen/opengeni_agent.ts`:\n// StreamChannel: channelId=1, workspaceId=2, agentId=3, kind=4(int32), port=5(uint32)\n// StreamOpen: channel=1(msg), token=2, role=3(int32), resumeFromSeq=4(uint64, omitted when \"0\")\n// StreamOpenAck: accepted=1(bool), error=2(AgentError msg), resumeFromSeq=3\n// AgentError: code=1, message=2, retryable=3, detail=4 (we read only message)\n// StreamFrame: channelId=1, seq=2, data=3(bytes), producedAtMs=4 (we read only data)\n// StreamClose: channelId=1, reason=2(int32), message=3\nimport { BinaryReader, BinaryWriter } from \"@bufbuild/protobuf/wire\";\n\n/** `StreamKind.STREAM_KIND_DESKTOP` (agent-proto enum value). */\nexport const STREAM_KIND_DESKTOP = 2;\n/** `StreamKind.STREAM_KIND_PTY` (agent-proto enum value). */\nexport const STREAM_KIND_PTY = 1;\n/** `StreamKind.STREAM_KIND_BROWSER` (agent-proto enum value). */\nexport const STREAM_KIND_BROWSER = 3;\n/** `StreamKind.STREAM_KIND_COMPUTER` (agent-proto enum value). */\nexport const STREAM_KIND_COMPUTER = 4;\n/** `StreamRole.STREAM_ROLE_CLIENT` (agent-proto enum value). */\nexport const STREAM_ROLE_CLIENT = 2;\n/** `StreamCloseReason.STREAM_CLOSE_REASON_NORMAL`. */\nexport const STREAM_CLOSE_REASON_NORMAL = 1;\n\nexport interface RelayChannel {\n channelId: string;\n workspaceId: string;\n agentId: string;\n kind: number;\n port: number;\n}\n\nexport interface RelayStreamOpen {\n channel: RelayChannel;\n token: string;\n role: number;\n resumeFromSeq: string;\n}\n\nfunction encodeChannel(message: RelayChannel, writer: BinaryWriter): BinaryWriter {\n if (message.channelId !== \"\") writer.uint32(10).string(message.channelId);\n if (message.workspaceId !== \"\") writer.uint32(18).string(message.workspaceId);\n if (message.agentId !== \"\") writer.uint32(26).string(message.agentId);\n if (message.kind !== 0) writer.uint32(32).int32(message.kind);\n if (message.port !== 0) writer.uint32(40).uint32(message.port);\n return writer;\n}\n\n/** Encode a `StreamOpen`, byte-compatible with `StreamOpen.encode(...).finish()`. */\nexport function encodeStreamOpen(message: RelayStreamOpen): Uint8Array {\n const writer = new BinaryWriter();\n encodeChannel(message.channel, writer.uint32(10).fork()).join();\n if (message.token !== \"\") writer.uint32(18).string(message.token);\n if (message.role !== 0) writer.uint32(24).int32(message.role);\n if (message.resumeFromSeq !== \"0\") writer.uint32(32).uint64(message.resumeFromSeq);\n return writer.finish();\n}\n\n/** Encode an intentional viewer detach. Transport loss omits this message so\n * reconnect/resume remains available. */\nexport function encodeStreamClose(message: {\n channelId: string;\n reason: number;\n message: string;\n}): Uint8Array {\n const writer = new BinaryWriter();\n if (message.channelId !== \"\") writer.uint32(10).string(message.channelId);\n if (message.reason !== 0) writer.uint32(16).int32(message.reason);\n if (message.message !== \"\") writer.uint32(26).string(message.message);\n return writer.finish();\n}\n\n/** Encode a viewer→agent PTY input `StreamFrame`. */\nexport function encodeStreamFrame(message: {\n channelId: string;\n seq: string;\n data: Uint8Array;\n producedAtMs: string;\n}): Uint8Array {\n const writer = new BinaryWriter();\n if (message.channelId !== \"\") writer.uint32(10).string(message.channelId);\n if (message.seq !== \"0\") writer.uint32(16).uint64(message.seq);\n if (message.data.length > 0) writer.uint32(26).bytes(message.data);\n if (message.producedAtMs !== \"0\") writer.uint32(32).uint64(message.producedAtMs);\n return writer.finish();\n}\n\n/** The only `AgentError` field we surface from a rejected ack. */\nfunction decodeAgentErrorMessage(reader: BinaryReader, length: number): { message?: string } {\n const end = reader.pos + length;\n let message: string | undefined;\n while (reader.pos < end) {\n const tag = reader.uint32();\n if (tag >>> 3 === 2 && tag === 18) {\n message = reader.string();\n continue;\n }\n if ((tag & 7) === 4 || tag === 0) break;\n reader.skip(tag & 7);\n }\n return message !== undefined ? { message } : {};\n}\n\n/** Decode a `StreamOpenAck` (we need `accepted` + the error message). */\nexport function decodeStreamOpenAck(bytes: Uint8Array): {\n accepted: boolean;\n error?: { message?: string };\n} {\n const reader = new BinaryReader(bytes);\n const end = reader.len;\n let accepted = false;\n let error: { message?: string } | undefined;\n while (reader.pos < end) {\n const tag = reader.uint32();\n if (tag >>> 3 === 1 && tag === 8) {\n accepted = reader.bool();\n continue;\n }\n if (tag >>> 3 === 2 && tag === 18) {\n error = decodeAgentErrorMessage(reader, reader.uint32());\n continue;\n }\n if ((tag & 7) === 4 || tag === 0) break;\n reader.skip(tag & 7);\n }\n return error !== undefined ? { accepted, error } : { accepted };\n}\n\n/** Decode the sequence plus `data` from a `StreamFrame`. */\nexport function decodeStreamFrame(bytes: Uint8Array): { seq: string; data: Uint8Array } {\n const reader = new BinaryReader(bytes);\n const end = reader.len;\n let seq = \"0\";\n let data = new Uint8Array(0);\n while (reader.pos < end) {\n const tag = reader.uint32();\n if (tag >>> 3 === 2 && tag === 16) {\n seq = reader.uint64().toString();\n continue;\n }\n if (tag >>> 3 === 3 && tag === 26) {\n // Copy into a fresh ArrayBuffer-backed view: BinaryReader.bytes() returns\n // `Uint8Array<ArrayBufferLike>` (a view into the message buffer), which both\n // narrows the type to `Uint8Array<ArrayBuffer>` and isolates just this frame.\n data = new Uint8Array(reader.bytes());\n continue;\n }\n if ((tag & 7) === 4 || tag === 0) break;\n reader.skip(tag & 7);\n }\n return { seq, data };\n}\n","export type InteractionHostPlatform = \"mac\" | \"other\";\n\n/** Physical client platform. Remote input adapters use this only to identify\n * the user's primary shortcut modifier; the target platform is resolved\n * separately. */\nexport function interactionHostPlatform(): InteractionHostPlatform {\n if (typeof navigator === \"undefined\") return \"other\";\n const platform = navigator.platform || navigator.userAgent;\n return /Mac|iPhone|iPad|iPod/u.test(platform) ? \"mac\" : \"other\";\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
import {
|
|
2
|
+
usePageLiveActivity
|
|
3
|
+
} from "./chunk-KZ73RL76.js";
|
|
4
|
+
import {
|
|
5
|
+
useEmbeddedInterventions
|
|
6
|
+
} from "./chunk-NEXLLTP4.js";
|
|
7
|
+
import {
|
|
8
|
+
cn
|
|
9
|
+
} from "./chunk-22KP6LR5.js";
|
|
10
|
+
|
|
11
|
+
// src/lib/interaction-errors.ts
|
|
12
|
+
import { OpenGeniApiError } from "@opengeni/sdk";
|
|
13
|
+
function isNonRetryableInteractionError(error) {
|
|
14
|
+
return error instanceof OpenGeniApiError && error.retryable === false;
|
|
15
|
+
}
|
|
16
|
+
function isSourcePlacementChangedError(error, resource) {
|
|
17
|
+
return isNonRetryableInteractionError(error) && error.status === 409 && error.details?.interactionResource === resource && error.details?.interactionFailureCode === "source_placement_changed" && error.details?.interactionLifecycle === "lost";
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// src/hooks/use-interaction-interventions.ts
|
|
21
|
+
import { useCallback, useEffect as useEffect2, useRef as useRef2, useState } from "react";
|
|
22
|
+
|
|
23
|
+
// src/hooks/use-interaction-invalidation.ts
|
|
24
|
+
import { useEffect, useRef } from "react";
|
|
25
|
+
function useInteractionInvalidation(options) {
|
|
26
|
+
const {
|
|
27
|
+
workspaceId,
|
|
28
|
+
key,
|
|
29
|
+
enabled,
|
|
30
|
+
event,
|
|
31
|
+
connectionState,
|
|
32
|
+
knownRevision,
|
|
33
|
+
refresh,
|
|
34
|
+
fallbackPollIntervalMs
|
|
35
|
+
} = options;
|
|
36
|
+
const pageLive = usePageLiveActivity();
|
|
37
|
+
const lastUnversionedEvent = useRef({
|
|
38
|
+
key,
|
|
39
|
+
sequence: 0
|
|
40
|
+
});
|
|
41
|
+
const eventSequence = event?.workspaceId === workspaceId ? event.sequence : 0;
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
if (!enabled || eventSequence <= 0) return;
|
|
44
|
+
if (knownRevision !== void 0) {
|
|
45
|
+
if (eventSequence > knownRevision) void refresh();
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
if (lastUnversionedEvent.current.key !== key) {
|
|
49
|
+
lastUnversionedEvent.current = { key, sequence: 0 };
|
|
50
|
+
}
|
|
51
|
+
if (eventSequence <= lastUnversionedEvent.current.sequence) return;
|
|
52
|
+
lastUnversionedEvent.current = { key, sequence: eventSequence };
|
|
53
|
+
void refresh();
|
|
54
|
+
}, [enabled, eventSequence, key, knownRevision, refresh]);
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
if (!enabled || !pageLive || connectionState === "live") return;
|
|
57
|
+
const interval = boundedPollInterval(fallbackPollIntervalMs ?? 3e3);
|
|
58
|
+
const timer = setInterval(() => void refresh(), interval);
|
|
59
|
+
return () => clearInterval(timer);
|
|
60
|
+
}, [connectionState, enabled, fallbackPollIntervalMs, pageLive, refresh]);
|
|
61
|
+
}
|
|
62
|
+
function boundedPollInterval(value) {
|
|
63
|
+
if (!Number.isFinite(value)) return 3e3;
|
|
64
|
+
return Math.min(6e4, Math.max(1e3, Math.floor(value)));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// src/hooks/use-interaction-interventions.ts
|
|
68
|
+
function useInteractionInterventions(options = {}) {
|
|
69
|
+
const { client, workspaceId, workspaceInteractionEvent, workspaceInteractionConnectionState } = useEmbeddedInterventions(options);
|
|
70
|
+
const enabled = (options.enabled ?? true) && options.resourceId !== null;
|
|
71
|
+
const resourceKind = options.resourceKind;
|
|
72
|
+
const resourceId = options.resourceId ?? void 0;
|
|
73
|
+
const includeSettled = options.includeSettled ?? false;
|
|
74
|
+
const key = `${workspaceId}:${resourceKind ?? "*"}:${resourceId ?? "*"}:${includeSettled}`;
|
|
75
|
+
const [state, setState] = useState(() => emptyState(key, enabled));
|
|
76
|
+
const [mutationCount, setMutationCount] = useState(0);
|
|
77
|
+
const requestRef = useRef2({
|
|
78
|
+
id: 0,
|
|
79
|
+
controller: null
|
|
80
|
+
});
|
|
81
|
+
const mountedRef = useRef2(true);
|
|
82
|
+
const visible = state.key === key ? state : emptyState(key, enabled);
|
|
83
|
+
const cancelLoad = useCallback(() => {
|
|
84
|
+
requestRef.current.controller?.abort();
|
|
85
|
+
requestRef.current = { id: requestRef.current.id + 1, controller: null };
|
|
86
|
+
}, []);
|
|
87
|
+
const load = useCallback(
|
|
88
|
+
async (foreground, replace = true) => {
|
|
89
|
+
if (!enabled) return;
|
|
90
|
+
if (requestRef.current.controller && !replace) return;
|
|
91
|
+
const id = requestRef.current.id + 1;
|
|
92
|
+
requestRef.current.controller?.abort();
|
|
93
|
+
const controller = new AbortController();
|
|
94
|
+
requestRef.current = { id, controller };
|
|
95
|
+
if (foreground || replace) {
|
|
96
|
+
setState((current) => ({
|
|
97
|
+
...current.key === key ? current : emptyState(key, true),
|
|
98
|
+
loading: foreground,
|
|
99
|
+
refreshing: !foreground,
|
|
100
|
+
error: foreground ? null : current.error
|
|
101
|
+
}));
|
|
102
|
+
}
|
|
103
|
+
try {
|
|
104
|
+
const response = await client.listInteractionInterventions(workspaceId, {
|
|
105
|
+
...resourceKind ? { resourceKind } : {},
|
|
106
|
+
...resourceId ? { resourceId } : {},
|
|
107
|
+
includeSettled,
|
|
108
|
+
signal: controller.signal
|
|
109
|
+
});
|
|
110
|
+
if (!mountedRef.current || requestRef.current.id !== id) return;
|
|
111
|
+
setState({
|
|
112
|
+
key,
|
|
113
|
+
interventions: sortInterventions(response.interventions),
|
|
114
|
+
loading: false,
|
|
115
|
+
refreshing: false,
|
|
116
|
+
error: null
|
|
117
|
+
});
|
|
118
|
+
} catch (cause) {
|
|
119
|
+
if (controller.signal.aborted || !mountedRef.current || requestRef.current.id !== id)
|
|
120
|
+
return;
|
|
121
|
+
setState((current) => ({
|
|
122
|
+
...current.key === key ? current : emptyState(key, true),
|
|
123
|
+
loading: false,
|
|
124
|
+
refreshing: false,
|
|
125
|
+
error: asError(cause)
|
|
126
|
+
}));
|
|
127
|
+
} finally {
|
|
128
|
+
if (requestRef.current.id === id) requestRef.current = { id, controller: null };
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
[client, enabled, includeSettled, key, resourceId, resourceKind, workspaceId]
|
|
132
|
+
);
|
|
133
|
+
const refresh = useCallback(async () => await load(false, true), [load]);
|
|
134
|
+
useEffect2(() => {
|
|
135
|
+
mountedRef.current = true;
|
|
136
|
+
if (!enabled) {
|
|
137
|
+
cancelLoad();
|
|
138
|
+
setState(emptyState(key, false));
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
void load(true);
|
|
142
|
+
return () => {
|
|
143
|
+
mountedRef.current = false;
|
|
144
|
+
cancelLoad();
|
|
145
|
+
};
|
|
146
|
+
}, [cancelLoad, enabled, key, load]);
|
|
147
|
+
useInteractionInvalidation({
|
|
148
|
+
workspaceId,
|
|
149
|
+
key,
|
|
150
|
+
enabled,
|
|
151
|
+
event: workspaceInteractionEvent,
|
|
152
|
+
connectionState: workspaceInteractionConnectionState,
|
|
153
|
+
refresh,
|
|
154
|
+
fallbackPollIntervalMs: options.pollIntervalMs ?? 2e3
|
|
155
|
+
});
|
|
156
|
+
const mutate = useCallback(async (operation) => {
|
|
157
|
+
setMutationCount((count) => count + 1);
|
|
158
|
+
try {
|
|
159
|
+
return await operation();
|
|
160
|
+
} finally {
|
|
161
|
+
if (mountedRef.current) setMutationCount((count) => Math.max(0, count - 1));
|
|
162
|
+
}
|
|
163
|
+
}, []);
|
|
164
|
+
const merge = useCallback(
|
|
165
|
+
(intervention) => {
|
|
166
|
+
setState((current) => {
|
|
167
|
+
if (current.key !== key) return current;
|
|
168
|
+
const interventions = current.interventions.filter(
|
|
169
|
+
(candidate) => candidate.id !== intervention.id
|
|
170
|
+
);
|
|
171
|
+
const matches = (!resourceKind || intervention.resourceKind === resourceKind) && (!resourceId || intervention.resourceId === resourceId);
|
|
172
|
+
if (matches && (includeSettled || intervention.status === "open")) {
|
|
173
|
+
interventions.push(intervention);
|
|
174
|
+
}
|
|
175
|
+
return {
|
|
176
|
+
...current,
|
|
177
|
+
interventions: sortInterventions(interventions),
|
|
178
|
+
error: null
|
|
179
|
+
};
|
|
180
|
+
});
|
|
181
|
+
},
|
|
182
|
+
[includeSettled, key, resourceId, resourceKind]
|
|
183
|
+
);
|
|
184
|
+
const create = useCallback(
|
|
185
|
+
async (request) => await mutate(async () => {
|
|
186
|
+
const response = await client.createInteractionIntervention(workspaceId, {
|
|
187
|
+
...request,
|
|
188
|
+
operationId: request.operationId ?? crypto.randomUUID()
|
|
189
|
+
});
|
|
190
|
+
merge(response.intervention);
|
|
191
|
+
return response;
|
|
192
|
+
}),
|
|
193
|
+
[client, merge, mutate, workspaceId]
|
|
194
|
+
);
|
|
195
|
+
const resolve = useCallback(
|
|
196
|
+
async (interventionId, request) => await mutate(async () => {
|
|
197
|
+
const response = await client.resolveInteractionIntervention(workspaceId, interventionId, {
|
|
198
|
+
...request,
|
|
199
|
+
operationId: request.operationId ?? crypto.randomUUID()
|
|
200
|
+
});
|
|
201
|
+
merge(response.intervention);
|
|
202
|
+
return response;
|
|
203
|
+
}),
|
|
204
|
+
[client, merge, mutate, workspaceId]
|
|
205
|
+
);
|
|
206
|
+
return {
|
|
207
|
+
interventions: visible.interventions,
|
|
208
|
+
loading: visible.loading,
|
|
209
|
+
refreshing: visible.refreshing,
|
|
210
|
+
mutating: mutationCount > 0,
|
|
211
|
+
error: visible.error,
|
|
212
|
+
refresh,
|
|
213
|
+
create,
|
|
214
|
+
resolve
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
function emptyState(key, loading) {
|
|
218
|
+
return {
|
|
219
|
+
key,
|
|
220
|
+
interventions: [],
|
|
221
|
+
loading,
|
|
222
|
+
refreshing: false,
|
|
223
|
+
error: null
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
function sortInterventions(interventions) {
|
|
227
|
+
return [...interventions].sort(
|
|
228
|
+
(left, right) => Date.parse(right.updatedAt) - Date.parse(left.updatedAt)
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
function asError(cause) {
|
|
232
|
+
return cause instanceof Error ? cause : new Error(String(cause));
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// src/components/interaction-intervention-banner.tsx
|
|
236
|
+
import { CheckIcon, CircleAlertIcon, LoaderCircleIcon, XIcon } from "lucide-react";
|
|
237
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
238
|
+
function InteractionInterventionBanner({
|
|
239
|
+
interventions,
|
|
240
|
+
activeTargetId,
|
|
241
|
+
mutating = false,
|
|
242
|
+
className,
|
|
243
|
+
onOpen,
|
|
244
|
+
onResolve
|
|
245
|
+
}) {
|
|
246
|
+
const intervention = interventions[0];
|
|
247
|
+
if (!intervention) return null;
|
|
248
|
+
const targetOpen = activeTargetId === void 0 || activeTargetId === intervention.targetId;
|
|
249
|
+
return /* @__PURE__ */ jsxs(
|
|
250
|
+
"div",
|
|
251
|
+
{
|
|
252
|
+
className: cn(
|
|
253
|
+
"flex shrink-0 items-center gap-2 border-b border-og-status-waiting/25 bg-og-status-waiting/[0.07] px-3 py-2",
|
|
254
|
+
className
|
|
255
|
+
),
|
|
256
|
+
role: "status",
|
|
257
|
+
children: [
|
|
258
|
+
/* @__PURE__ */ jsx("span", { className: "grid size-7 shrink-0 place-items-center rounded-og-sm bg-og-status-waiting/10 text-og-status-waiting", children: /* @__PURE__ */ jsx(CircleAlertIcon, { className: "size-3.5" }) }),
|
|
259
|
+
/* @__PURE__ */ jsxs("span", { className: "min-w-0 flex-1", children: [
|
|
260
|
+
/* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1.5 text-og-control font-medium text-og-fg", children: [
|
|
261
|
+
interventionTitle(intervention.kind),
|
|
262
|
+
interventions.length > 1 ? /* @__PURE__ */ jsxs("span", { className: "rounded-full bg-og-surface-2 px-1.5 py-0.5 text-[10px] font-normal text-og-muted", children: [
|
|
263
|
+
"+",
|
|
264
|
+
interventions.length - 1
|
|
265
|
+
] }) : null
|
|
266
|
+
] }),
|
|
267
|
+
/* @__PURE__ */ jsx("span", { className: "block truncate text-og-xs text-og-muted", children: intervention.reason })
|
|
268
|
+
] }),
|
|
269
|
+
!targetOpen && onOpen ? /* @__PURE__ */ jsx(
|
|
270
|
+
"button",
|
|
271
|
+
{
|
|
272
|
+
type: "button",
|
|
273
|
+
onClick: () => onOpen(intervention),
|
|
274
|
+
disabled: mutating,
|
|
275
|
+
className: "h-7 shrink-0 rounded-og-sm border border-og-border bg-og-surface-1 px-2.5 text-og-control font-medium text-og-fg transition hover:bg-og-surface-2 disabled:opacity-50",
|
|
276
|
+
children: "Open"
|
|
277
|
+
}
|
|
278
|
+
) : /* @__PURE__ */ jsxs(
|
|
279
|
+
"button",
|
|
280
|
+
{
|
|
281
|
+
type: "button",
|
|
282
|
+
onClick: () => onResolve(intervention, "completed"),
|
|
283
|
+
disabled: mutating,
|
|
284
|
+
className: "inline-flex h-7 shrink-0 items-center gap-1 rounded-og-sm bg-og-accent px-2.5 text-og-control font-medium text-og-accent-fg transition hover:brightness-105 disabled:opacity-50",
|
|
285
|
+
children: [
|
|
286
|
+
mutating ? /* @__PURE__ */ jsx(LoaderCircleIcon, { className: "size-3 animate-spin" }) : /* @__PURE__ */ jsx(CheckIcon, { className: "size-3" }),
|
|
287
|
+
"Done"
|
|
288
|
+
]
|
|
289
|
+
}
|
|
290
|
+
),
|
|
291
|
+
/* @__PURE__ */ jsx(
|
|
292
|
+
"button",
|
|
293
|
+
{
|
|
294
|
+
type: "button",
|
|
295
|
+
onClick: () => onResolve(intervention, "dismissed"),
|
|
296
|
+
disabled: mutating,
|
|
297
|
+
className: "grid size-7 shrink-0 place-items-center rounded-og-sm text-og-muted transition hover:bg-og-surface-2 hover:text-og-fg disabled:opacity-50",
|
|
298
|
+
"aria-label": "Cancel request",
|
|
299
|
+
title: "Cancel request",
|
|
300
|
+
children: /* @__PURE__ */ jsx(XIcon, { className: "size-3.5" })
|
|
301
|
+
}
|
|
302
|
+
)
|
|
303
|
+
]
|
|
304
|
+
}
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
function interventionTitle(kind) {
|
|
308
|
+
switch (kind) {
|
|
309
|
+
case "manual_login":
|
|
310
|
+
return "Sign in needed";
|
|
311
|
+
case "mfa":
|
|
312
|
+
return "Verification needed";
|
|
313
|
+
case "external_action":
|
|
314
|
+
return "Action needed";
|
|
315
|
+
case "confirmation":
|
|
316
|
+
return "Confirmation needed";
|
|
317
|
+
case "other":
|
|
318
|
+
return "Agent needs your help";
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
export {
|
|
323
|
+
useInteractionInvalidation,
|
|
324
|
+
isNonRetryableInteractionError,
|
|
325
|
+
isSourcePlacementChangedError,
|
|
326
|
+
useInteractionInterventions,
|
|
327
|
+
InteractionInterventionBanner
|
|
328
|
+
};
|
|
329
|
+
//# sourceMappingURL=chunk-H5YGYNXS.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/interaction-errors.ts","../src/hooks/use-interaction-interventions.ts","../src/hooks/use-interaction-invalidation.ts","../src/components/interaction-intervention-banner.tsx"],"sourcesContent":["import { OpenGeniApiError } from \"@opengeni/sdk\";\n\nexport function isNonRetryableInteractionError(error: unknown): error is OpenGeniApiError {\n return error instanceof OpenGeniApiError && error.retryable === false;\n}\n\nexport function isSourcePlacementChangedError(\n error: unknown,\n resource: \"browser_session\" | \"computer_session\",\n): error is OpenGeniApiError {\n return (\n isNonRetryableInteractionError(error) &&\n error.status === 409 &&\n error.details?.interactionResource === resource &&\n error.details?.interactionFailureCode === \"source_placement_changed\" &&\n error.details?.interactionLifecycle === \"lost\"\n );\n}\n","import type {\n CreateInteractionInterventionRequest,\n InteractionIntervention,\n InteractionInterventionMutationResponse,\n ResolveInteractionInterventionRequest,\n} from \"@opengeni/sdk/interaction\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport type { EmbeddedInterventionClientLike } from \"../client\";\nimport {\n type EmbeddedInterventionClientOverride,\n useEmbeddedInterventions,\n} from \"../session-context\";\nimport { useInteractionInvalidation } from \"./use-interaction-invalidation\";\n\nexport type UseInteractionInterventionsOptions = EmbeddedInterventionClientOverride & {\n enabled?: boolean | undefined;\n resourceKind?: \"browser_session\" | \"computer_session\" | undefined;\n resourceId?: string | null | undefined;\n includeSettled?: boolean | undefined;\n pollIntervalMs?: number | undefined;\n};\n\nexport type UseInteractionInterventionsResult = {\n interventions: InteractionIntervention[];\n loading: boolean;\n refreshing: boolean;\n mutating: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n create: (\n request: Omit<CreateInteractionInterventionRequest, \"operationId\"> & {\n operationId?: string;\n },\n ) => Promise<InteractionInterventionMutationResponse>;\n resolve: (\n interventionId: string,\n request: Omit<ResolveInteractionInterventionRequest, \"operationId\"> & {\n operationId?: string;\n },\n ) => Promise<InteractionInterventionMutationResponse>;\n};\n\n/** Human-action bridge shared by Browser and Computer surfaces. */\nexport function useInteractionInterventions(\n options: UseInteractionInterventionsOptions = {},\n): UseInteractionInterventionsResult {\n const { client, workspaceId, workspaceInteractionEvent, workspaceInteractionConnectionState } =\n useEmbeddedInterventions(options);\n const enabled = (options.enabled ?? true) && options.resourceId !== null;\n const resourceKind = options.resourceKind;\n const resourceId = options.resourceId ?? undefined;\n const includeSettled = options.includeSettled ?? false;\n const key = `${workspaceId}:${resourceKind ?? \"*\"}:${resourceId ?? \"*\"}:${includeSettled}`;\n const [state, setState] = useState(() => emptyState(key, enabled));\n const [mutationCount, setMutationCount] = useState(0);\n const requestRef = useRef<{ id: number; controller: AbortController | null }>({\n id: 0,\n controller: null,\n });\n const mountedRef = useRef(true);\n const visible = state.key === key ? state : emptyState(key, enabled);\n\n const cancelLoad = useCallback(() => {\n requestRef.current.controller?.abort();\n requestRef.current = { id: requestRef.current.id + 1, controller: null };\n }, []);\n\n const load = useCallback(\n async (foreground: boolean, replace = true): Promise<void> => {\n if (!enabled) return;\n if (requestRef.current.controller && !replace) return;\n const id = requestRef.current.id + 1;\n requestRef.current.controller?.abort();\n const controller = new AbortController();\n requestRef.current = { id, controller };\n if (foreground || replace) {\n setState((current) => ({\n ...(current.key === key ? current : emptyState(key, true)),\n loading: foreground,\n refreshing: !foreground,\n error: foreground ? null : current.error,\n }));\n }\n try {\n const response = await client.listInteractionInterventions(workspaceId, {\n ...(resourceKind ? { resourceKind } : {}),\n ...(resourceId ? { resourceId } : {}),\n includeSettled,\n signal: controller.signal,\n });\n if (!mountedRef.current || requestRef.current.id !== id) return;\n setState({\n key,\n interventions: sortInterventions(response.interventions),\n loading: false,\n refreshing: false,\n error: null,\n });\n } catch (cause) {\n if (controller.signal.aborted || !mountedRef.current || requestRef.current.id !== id)\n return;\n setState((current) => ({\n ...(current.key === key ? current : emptyState(key, true)),\n loading: false,\n refreshing: false,\n error: asError(cause),\n }));\n } finally {\n if (requestRef.current.id === id) requestRef.current = { id, controller: null };\n }\n },\n [client, enabled, includeSettled, key, resourceId, resourceKind, workspaceId],\n );\n\n const refresh = useCallback(async () => await load(false, true), [load]);\n\n useEffect(() => {\n mountedRef.current = true;\n if (!enabled) {\n cancelLoad();\n setState(emptyState(key, false));\n return;\n }\n void load(true);\n return () => {\n mountedRef.current = false;\n cancelLoad();\n };\n }, [cancelLoad, enabled, key, load]);\n\n useInteractionInvalidation({\n workspaceId,\n key,\n enabled,\n event: workspaceInteractionEvent,\n connectionState: workspaceInteractionConnectionState,\n refresh,\n fallbackPollIntervalMs: options.pollIntervalMs ?? 2_000,\n });\n\n const mutate = useCallback(async <T>(operation: () => Promise<T>): Promise<T> => {\n setMutationCount((count) => count + 1);\n try {\n return await operation();\n } finally {\n if (mountedRef.current) setMutationCount((count) => Math.max(0, count - 1));\n }\n }, []);\n\n const merge = useCallback(\n (intervention: InteractionIntervention) => {\n setState((current) => {\n if (current.key !== key) return current;\n const interventions = current.interventions.filter(\n (candidate) => candidate.id !== intervention.id,\n );\n const matches =\n (!resourceKind || intervention.resourceKind === resourceKind) &&\n (!resourceId || intervention.resourceId === resourceId);\n if (matches && (includeSettled || intervention.status === \"open\")) {\n interventions.push(intervention);\n }\n return {\n ...current,\n interventions: sortInterventions(interventions),\n error: null,\n };\n });\n },\n [includeSettled, key, resourceId, resourceKind],\n );\n\n const create = useCallback(\n async (\n request: Omit<CreateInteractionInterventionRequest, \"operationId\"> & {\n operationId?: string;\n },\n ): Promise<InteractionInterventionMutationResponse> =>\n await mutate(async () => {\n const response = await client.createInteractionIntervention(workspaceId, {\n ...request,\n operationId: request.operationId ?? crypto.randomUUID(),\n });\n merge(response.intervention);\n return response;\n }),\n [client, merge, mutate, workspaceId],\n );\n\n const resolve = useCallback(\n async (\n interventionId: string,\n request: Omit<ResolveInteractionInterventionRequest, \"operationId\"> & {\n operationId?: string;\n },\n ): Promise<InteractionInterventionMutationResponse> =>\n await mutate(async () => {\n const response = await client.resolveInteractionIntervention(workspaceId, interventionId, {\n ...request,\n operationId: request.operationId ?? crypto.randomUUID(),\n });\n merge(response.intervention);\n return response;\n }),\n [client, merge, mutate, workspaceId],\n );\n\n return {\n interventions: visible.interventions,\n loading: visible.loading,\n refreshing: visible.refreshing,\n mutating: mutationCount > 0,\n error: visible.error,\n refresh,\n create,\n resolve,\n };\n}\n\nfunction emptyState(key: string, loading: boolean) {\n return {\n key,\n interventions: [] as InteractionIntervention[],\n loading,\n refreshing: false,\n error: null as Error | null,\n };\n}\n\nfunction sortInterventions(\n interventions: readonly InteractionIntervention[],\n): InteractionIntervention[] {\n return [...interventions].sort(\n (left, right) => Date.parse(right.updatedAt) - Date.parse(left.updatedAt),\n );\n}\n\nfunction asError(cause: unknown): Error {\n return cause instanceof Error ? cause : new Error(String(cause));\n}\n\nexport type InteractionInterventionsClient = EmbeddedInterventionClientLike;\n","import type { StreamConnectionState, WorkspaceInteractionRevisionEvent } from \"@opengeni/sdk\";\nimport { useEffect, useRef } from \"react\";\nimport { usePageLiveActivity } from \"./internal\";\n\nexport type InteractionInvalidationOptions = {\n workspaceId: string;\n /** Distinguishes filtered projections of the same workspace catalog. */\n key: string;\n enabled: boolean;\n event: WorkspaceInteractionRevisionEvent | null;\n connectionState: StreamConnectionState | \"idle\" | \"error\";\n /** Catalog responses carry the workspace revision; live-state lists do not. */\n knownRevision?: number | undefined;\n refresh: () => Promise<void>;\n fallbackPollIntervalMs?: number | undefined;\n};\n\n/**\n * Refetch authoritative lists on the shared latest-revision stream. Poll only\n * while that stream is unavailable, preserving standalone-hook degradation\n * without multiplying healthy-provider traffic.\n */\nexport function useInteractionInvalidation(options: InteractionInvalidationOptions): void {\n const {\n workspaceId,\n key,\n enabled,\n event,\n connectionState,\n knownRevision,\n refresh,\n fallbackPollIntervalMs,\n } = options;\n const pageLive = usePageLiveActivity();\n const lastUnversionedEvent = useRef<{ key: string; sequence: number }>({\n key,\n sequence: 0,\n });\n const eventSequence = event?.workspaceId === workspaceId ? event.sequence : 0;\n\n useEffect(() => {\n if (!enabled || eventSequence <= 0) return;\n if (knownRevision !== undefined) {\n if (eventSequence > knownRevision) void refresh();\n return;\n }\n if (lastUnversionedEvent.current.key !== key) {\n lastUnversionedEvent.current = { key, sequence: 0 };\n }\n if (eventSequence <= lastUnversionedEvent.current.sequence) return;\n lastUnversionedEvent.current = { key, sequence: eventSequence };\n void refresh();\n }, [enabled, eventSequence, key, knownRevision, refresh]);\n\n useEffect(() => {\n if (!enabled || !pageLive || connectionState === \"live\") return;\n const interval = boundedPollInterval(fallbackPollIntervalMs ?? 3_000);\n const timer = setInterval(() => void refresh(), interval);\n return () => clearInterval(timer);\n }, [connectionState, enabled, fallbackPollIntervalMs, pageLive, refresh]);\n}\n\nfunction boundedPollInterval(value: number): number {\n if (!Number.isFinite(value)) return 3_000;\n return Math.min(60_000, Math.max(1_000, Math.floor(value)));\n}\n","import type { InteractionIntervention } from \"@opengeni/sdk/interaction\";\nimport { CheckIcon, CircleAlertIcon, LoaderCircleIcon, XIcon } from \"lucide-react\";\nimport { cn } from \"../lib/cn\";\n\nexport type InteractionInterventionBannerProps = {\n interventions: InteractionIntervention[];\n activeTargetId?: string | null | undefined;\n mutating?: boolean | undefined;\n className?: string | undefined;\n onOpen?: ((intervention: InteractionIntervention) => void) | undefined;\n onResolve: (intervention: InteractionIntervention, outcome: \"completed\" | \"dismissed\") => void;\n};\n\n/** Compact durable human-action prompt shared by Browser and Computer viewers. */\nexport function InteractionInterventionBanner({\n interventions,\n activeTargetId,\n mutating = false,\n className,\n onOpen,\n onResolve,\n}: InteractionInterventionBannerProps) {\n const intervention = interventions[0];\n if (!intervention) return null;\n const targetOpen = activeTargetId === undefined || activeTargetId === intervention.targetId;\n return (\n <div\n className={cn(\n \"flex shrink-0 items-center gap-2 border-b border-og-status-waiting/25 bg-og-status-waiting/[0.07] px-3 py-2\",\n className,\n )}\n role=\"status\"\n >\n <span className=\"grid size-7 shrink-0 place-items-center rounded-og-sm bg-og-status-waiting/10 text-og-status-waiting\">\n <CircleAlertIcon className=\"size-3.5\" />\n </span>\n <span className=\"min-w-0 flex-1\">\n <span className=\"flex items-center gap-1.5 text-og-control font-medium text-og-fg\">\n {interventionTitle(intervention.kind)}\n {interventions.length > 1 ? (\n <span className=\"rounded-full bg-og-surface-2 px-1.5 py-0.5 text-[10px] font-normal text-og-muted\">\n +{interventions.length - 1}\n </span>\n ) : null}\n </span>\n <span className=\"block truncate text-og-xs text-og-muted\">{intervention.reason}</span>\n </span>\n {!targetOpen && onOpen ? (\n <button\n type=\"button\"\n onClick={() => onOpen(intervention)}\n disabled={mutating}\n className=\"h-7 shrink-0 rounded-og-sm border border-og-border bg-og-surface-1 px-2.5 text-og-control font-medium text-og-fg transition hover:bg-og-surface-2 disabled:opacity-50\"\n >\n Open\n </button>\n ) : (\n <button\n type=\"button\"\n onClick={() => onResolve(intervention, \"completed\")}\n disabled={mutating}\n className=\"inline-flex h-7 shrink-0 items-center gap-1 rounded-og-sm bg-og-accent px-2.5 text-og-control font-medium text-og-accent-fg transition hover:brightness-105 disabled:opacity-50\"\n >\n {mutating ? (\n <LoaderCircleIcon className=\"size-3 animate-spin\" />\n ) : (\n <CheckIcon className=\"size-3\" />\n )}\n Done\n </button>\n )}\n <button\n type=\"button\"\n onClick={() => onResolve(intervention, \"dismissed\")}\n disabled={mutating}\n className=\"grid size-7 shrink-0 place-items-center rounded-og-sm text-og-muted transition hover:bg-og-surface-2 hover:text-og-fg disabled:opacity-50\"\n aria-label=\"Cancel request\"\n title=\"Cancel request\"\n >\n <XIcon className=\"size-3.5\" />\n </button>\n </div>\n );\n}\n\nfunction interventionTitle(kind: InteractionIntervention[\"kind\"]): string {\n switch (kind) {\n case \"manual_login\":\n return \"Sign in needed\";\n case \"mfa\":\n return \"Verification needed\";\n case \"external_action\":\n return \"Action needed\";\n case \"confirmation\":\n return \"Confirmation needed\";\n case \"other\":\n return \"Agent needs your help\";\n }\n}\n"],"mappings":"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","names":["useEffect","useRef","useRef","useEffect"]}
|
|
@@ -2756,7 +2756,7 @@ function sheetGeneration(sheet) {
|
|
|
2756
2756
|
};
|
|
2757
2757
|
}
|
|
2758
2758
|
function spreadsheetCellInput(input, kind) {
|
|
2759
|
-
if (kind === "formula") return { formula: input
|
|
2759
|
+
if (kind === "formula") return { formula: input };
|
|
2760
2760
|
if (input === "") return null;
|
|
2761
2761
|
const normalized = input.trim();
|
|
2762
2762
|
if (/^(?:true|false)$/i.test(normalized)) return normalized.toLowerCase() === "true";
|
|
@@ -2825,4 +2825,4 @@ export {
|
|
|
2825
2825
|
EditableSpreadsheetGrid,
|
|
2826
2826
|
EditableSpreadsheetArtifactSurface
|
|
2827
2827
|
};
|
|
2828
|
-
//# sourceMappingURL=chunk-
|
|
2828
|
+
//# sourceMappingURL=chunk-ICA6R6TW.js.map
|