@opengeni/react 4.0.2 → 5.0.4-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 +42 -0
- package/dist/artifacts.js +24 -285
- package/dist/artifacts.js.map +1 -1
- package/dist/chunk-BRFMGY4L.js +274 -0
- package/dist/chunk-BRFMGY4L.js.map +1 -0
- package/dist/chunk-IWIDV7SB.js +1 -0
- package/dist/chunk-IWIDV7SB.js.map +1 -0
- package/dist/{chunk-CQG7YUJB.js → chunk-SCZ6SUBW.js} +1177 -1021
- package/dist/chunk-SCZ6SUBW.js.map +1 -0
- package/dist/clipboard.js +1 -0
- package/dist/components/markdown-table-layout.d.ts +4 -1
- package/dist/components/message-timeline.d.ts +7 -3
- package/dist/connect-accounts.d.ts +10 -0
- package/dist/connect-chooser.d.ts +11 -0
- package/dist/connect-panel.d.ts +10 -0
- package/dist/connect-setup.d.ts +12 -0
- package/dist/connect.d.ts +30 -0
- package/dist/connect.js +831 -0
- package/dist/connect.js.map +1 -0
- package/dist/device-authorization.d.ts +15 -0
- package/dist/identity-link-accounts.d.ts +11 -0
- package/dist/identity-link-consent.d.ts +18 -0
- package/dist/index.js +523 -663
- package/dist/index.js.map +1 -1
- package/dist/{markdown-table-layout-3Z3AWBY7.js → markdown-table-layout-PFUEZ2U4.js} +7 -4
- package/dist/{markdown-table-layout-3Z3AWBY7.js.map → markdown-table-layout-PFUEZ2U4.js.map} +1 -1
- package/dist/session-ui.d.ts +2 -0
- package/dist/session-ui.js +3 -1
- package/dist/sites-ui.d.ts +33 -0
- package/dist/sites.d.ts +3 -0
- package/dist/sites.js +288 -0
- package/dist/sites.js.map +1 -0
- package/package.json +16 -2
- package/src/components/markdown-table-layout.ts +6 -3
- package/src/components/markdown.tsx +11 -3
- package/src/components/message-timeline.tsx +22 -5
- package/src/components/sandbox-workspace.tsx +9 -2
- package/src/connect-accounts.tsx +171 -0
- package/src/connect-chooser.tsx +144 -0
- package/src/connect-panel.tsx +29 -0
- package/src/connect-setup.tsx +260 -0
- package/src/connect.ts +48 -0
- package/src/device-authorization.tsx +90 -0
- package/src/hooks/use-workspace-capture.ts +3 -2
- package/src/identity-link-accounts.tsx +144 -0
- package/src/identity-link-consent.tsx +192 -0
- package/src/session-ui.ts +2 -0
- package/src/sites-ui.tsx +385 -0
- package/src/sites.ts +3 -0
- package/src/timeline/tool-renderers.tsx +1 -1
- package/styles/connect.css +48 -0
- package/styles/connect.d.ts +1 -0
- package/dist/chunk-CQG7YUJB.js.map +0 -1
package/README.md
CHANGED
|
@@ -24,6 +24,48 @@ ancestor. Components are styled with Tailwind v4 utilities mapped onto the
|
|
|
24
24
|
tokens, Radix primitives for behavior, and Motion for state-communicating
|
|
25
25
|
animation. Override the tokens to rebrand everything.
|
|
26
26
|
|
|
27
|
+
## Embedded connections and Sites
|
|
28
|
+
|
|
29
|
+
Optional `@opengeni/react/connect` exports `useConnect`, `ConnectChooser`,
|
|
30
|
+
`ConnectSetup`, `ConnectAccounts`, and the composed `ConnectPanel`. Inject one
|
|
31
|
+
`@opengeni/connect` controller per authenticated actor/workspace and dispose it
|
|
32
|
+
when that scope changes. The controller uses your authenticated backend proxy;
|
|
33
|
+
never place an organization key in browser props. Import
|
|
34
|
+
`@opengeni/react/connect.css` for opt-in, scoped styles without Tailwind.
|
|
35
|
+
|
|
36
|
+
```tsx
|
|
37
|
+
import { ConnectPanel } from "@opengeni/react/connect";
|
|
38
|
+
import "@opengeni/react/connect.css";
|
|
39
|
+
|
|
40
|
+
<ConnectPanel
|
|
41
|
+
controller={controller}
|
|
42
|
+
returnUrl={hostSelectedReturnUrl}
|
|
43
|
+
onAuthorize={hostAuthorizeFromClick}
|
|
44
|
+
/>;
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
The host owns synchronous popup/full-redirect navigation and pending-attempt
|
|
48
|
+
recovery. Backend state, not a popup message or URL query, proves completion.
|
|
49
|
+
Operation installation uses explicit selection; OAuth success alone is not
|
|
50
|
+
installation. Account disconnect requires an observed version and confirmation,
|
|
51
|
+
revokes local OpenGeni access only, and never silently retries an unknown outcome.
|
|
52
|
+
Provider readiness is deployment-dependent; use the server catalog rather than
|
|
53
|
+
assuming every OAuth application or operator-managed provider is configured.
|
|
54
|
+
|
|
55
|
+
Optional `@opengeni/react/sites` exports `SiteList`, `SiteDetail`, and `SiteClient`.
|
|
56
|
+
Pass the public SDK client through your host proxy. `onOpen` owns list
|
|
57
|
+
navigation. Authoring buttons and prompts belong to the host and use the ordinary
|
|
58
|
+
session SDK; they are not part of the Site component API. `SiteDetail` reuses `PublishedHtmlArtifactFrame`, accepts
|
|
59
|
+
an optional authenticated/filtered tool bridge, and removes the frame after
|
|
60
|
+
read-authority refresh failure. Loaded Sites revalidate every 15 seconds;
|
|
61
|
+
downloaded HTML cannot be recalled and every tool call still needs live authority.
|
|
62
|
+
|
|
63
|
+
`canPublish` is only a presentation hint. Version-checked rollback/archive/restore
|
|
64
|
+
remain subject to backend `artifacts:publish` permission. Sites stay workspace
|
|
65
|
+
shared, even if a source session is private. See
|
|
66
|
+
[`examples/embedded-product`](../../examples/embedded-product/README.md) for the
|
|
67
|
+
runnable loopback host reference. Native route reuse and full visual acceptance
|
|
68
|
+
are not implied by these optional package surfaces.
|
|
27
69
|
## Conversation UI
|
|
28
70
|
|
|
29
71
|
Use `SessionConversation` for an existing session, or compose `MessageTimeline`
|
package/dist/artifacts.js
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
import {
|
|
2
|
+
EditablePresentationArtifactSurface,
|
|
3
|
+
PresentationArtifactSurface,
|
|
4
|
+
PresentationEditor,
|
|
5
|
+
PresentationProjectionArtifactSurface,
|
|
6
|
+
PresentationProjectionEditor
|
|
7
|
+
} from "./chunk-PEI6RANI.js";
|
|
1
8
|
import {
|
|
2
9
|
DocumentArtifactSurface,
|
|
3
10
|
DocumentEditor,
|
|
@@ -5,6 +12,12 @@ import {
|
|
|
5
12
|
DocumentProjectionEditor,
|
|
6
13
|
EditableDocumentArtifactSurface
|
|
7
14
|
} from "./chunk-HUIKIDM5.js";
|
|
15
|
+
import {
|
|
16
|
+
PUBLISHED_HTML_ARTIFACT_IFRAME_SANDBOX,
|
|
17
|
+
PublishedHtmlArtifactFrame,
|
|
18
|
+
openGeniSiteBridgePortFromBootstrap,
|
|
19
|
+
publishedHtmlArtifactDocument
|
|
20
|
+
} from "./chunk-BRFMGY4L.js";
|
|
8
21
|
import {
|
|
9
22
|
EditableSpreadsheetArtifactSurface,
|
|
10
23
|
EditableSpreadsheetGrid,
|
|
@@ -12,292 +25,18 @@ import {
|
|
|
12
25
|
SpreadsheetGrid,
|
|
13
26
|
SpreadsheetProjectionGrid
|
|
14
27
|
} from "./chunk-ICA6R6TW.js";
|
|
15
|
-
import {
|
|
16
|
-
EditablePresentationArtifactSurface,
|
|
17
|
-
PresentationArtifactSurface,
|
|
18
|
-
PresentationEditor,
|
|
19
|
-
PresentationProjectionArtifactSurface,
|
|
20
|
-
PresentationProjectionEditor
|
|
21
|
-
} from "./chunk-PEI6RANI.js";
|
|
22
28
|
import {
|
|
23
29
|
ArtifactSurface,
|
|
24
30
|
EditableArtifactMessage
|
|
25
31
|
} from "./chunk-KCGXPP5V.js";
|
|
26
32
|
import "./chunk-22KP6LR5.js";
|
|
27
33
|
|
|
28
|
-
// src/components/artifacts/published-html-artifact-frame.tsx
|
|
29
|
-
import {
|
|
30
|
-
OPENGENI_SITE_BRIDGE_BOOTSTRAP_GLOBAL,
|
|
31
|
-
OPENGENI_SITE_BRIDGE_READY,
|
|
32
|
-
OPENGENI_SITE_BRIDGE_RESPONSE,
|
|
33
|
-
OPENGENI_SITE_BRIDGE_VERSION,
|
|
34
|
-
isOpenGeniSiteBridgeCancelMessage,
|
|
35
|
-
isOpenGeniSiteBridgeConnectMessage,
|
|
36
|
-
isOpenGeniSiteBridgeRequestMessage,
|
|
37
|
-
sanitizeOpenGeniSiteToolCallRequest,
|
|
38
|
-
isSiteHttpRequest,
|
|
39
|
-
serveSiteHttp
|
|
40
|
-
} from "@opengeni/sdk/site";
|
|
41
|
-
import { useEffect, useRef } from "react";
|
|
42
|
-
import { jsx } from "react/jsx-runtime";
|
|
43
|
-
var PUBLISHED_HTML_ARTIFACT_IFRAME_SANDBOX = [
|
|
44
|
-
"allow-downloads",
|
|
45
|
-
"allow-forms",
|
|
46
|
-
"allow-modals",
|
|
47
|
-
"allow-orientation-lock",
|
|
48
|
-
"allow-pointer-lock",
|
|
49
|
-
"allow-popups",
|
|
50
|
-
"allow-popups-to-escape-sandbox",
|
|
51
|
-
"allow-presentation",
|
|
52
|
-
"allow-scripts"
|
|
53
|
-
].join(" ");
|
|
54
|
-
var SITE_BRIDGE_BOOTSTRAP_SCRIPT = `<script>(()=>{const key=${JSON.stringify(
|
|
55
|
-
OPENGENI_SITE_BRIDGE_BOOTSTRAP_GLOBAL
|
|
56
|
-
)};const parentWindow=window.parent;if(parentWindow===window)return;window.addEventListener("message",event=>{const data=event.data;if(event.source!==parentWindow||!data||data.type!==${JSON.stringify(
|
|
57
|
-
OPENGENI_SITE_BRIDGE_READY
|
|
58
|
-
)}||data.version!==${OPENGENI_SITE_BRIDGE_VERSION}||event.ports.length!==1)return;const port=event.ports[0];const previous=window[key]?.port;if(previous&&previous!==port)previous.close();Object.defineProperty(window,key,{configurable:true,value:{port}});port.start();});})();</script>`;
|
|
59
|
-
function publishedHtmlArtifactDocument(html, toolBridgeEnabled) {
|
|
60
|
-
if (!toolBridgeEnabled) return html;
|
|
61
|
-
const doctypeEnd = leadingDoctypeEnd(html);
|
|
62
|
-
if (doctypeEnd >= 0) {
|
|
63
|
-
return `${html.slice(0, doctypeEnd + 1)}${SITE_BRIDGE_BOOTSTRAP_SCRIPT}${html.slice(doctypeEnd + 1)}`;
|
|
64
|
-
}
|
|
65
|
-
return `${SITE_BRIDGE_BOOTSTRAP_SCRIPT}${html}`;
|
|
66
|
-
}
|
|
67
|
-
function leadingDoctypeEnd(html) {
|
|
68
|
-
const lower = html.toLowerCase();
|
|
69
|
-
let cursor = html.charCodeAt(0) === 65279 ? 1 : 0;
|
|
70
|
-
while (cursor < html.length) {
|
|
71
|
-
while (/\s/.test(html[cursor] ?? "")) cursor += 1;
|
|
72
|
-
if (!html.startsWith("<!--", cursor)) break;
|
|
73
|
-
const commentEnd = html.indexOf("-->", cursor + 4);
|
|
74
|
-
if (commentEnd < 0) return -1;
|
|
75
|
-
cursor = commentEnd + 3;
|
|
76
|
-
}
|
|
77
|
-
if (!lower.startsWith("<!doctype", cursor)) return -1;
|
|
78
|
-
return html.indexOf(">", cursor + 9);
|
|
79
|
-
}
|
|
80
|
-
function PublishedHtmlArtifactFrame(props) {
|
|
81
|
-
const frameRef = useRef(null);
|
|
82
|
-
const bridgeRef = useRef(props.toolBridge);
|
|
83
|
-
const onFrameLoadRef = useRef(() => void 0);
|
|
84
|
-
const frameLoadPendingRef = useRef(false);
|
|
85
|
-
const toolBridgeEnabled = props.toolBridge !== void 0;
|
|
86
|
-
useEffect(() => {
|
|
87
|
-
bridgeRef.current = props.toolBridge;
|
|
88
|
-
}, [props.toolBridge]);
|
|
89
|
-
useEffect(() => {
|
|
90
|
-
if (!toolBridgeEnabled || typeof window === "undefined") return;
|
|
91
|
-
const requests = new SiteBridgeRequestRegistry();
|
|
92
|
-
const attachToolPort = (data, ports) => {
|
|
93
|
-
const port = openGeniSiteBridgePortFromBootstrap(data, ports);
|
|
94
|
-
if (!port) return;
|
|
95
|
-
requests.addPort(port);
|
|
96
|
-
port.addEventListener("message", (portEvent) => {
|
|
97
|
-
const message = portEvent.data;
|
|
98
|
-
if (isOpenGeniSiteBridgeCancelMessage(message)) {
|
|
99
|
-
requests.cancel(port, message.requestId);
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
if (isSiteHttpRequest(message) && portEvent.ports.length === 1) {
|
|
103
|
-
const controller2 = requests.start(port, message.requestId);
|
|
104
|
-
if (!controller2) {
|
|
105
|
-
portEvent.ports[0].close();
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
108
|
-
void serveSiteHttp(
|
|
109
|
-
message,
|
|
110
|
-
portEvent.ports[0],
|
|
111
|
-
async (request, signal) => {
|
|
112
|
-
const fetch = bridgeRef.current?.fetch;
|
|
113
|
-
if (!fetch) throw new Error("This Site host does not support the session SDK");
|
|
114
|
-
return fetch(request, signal);
|
|
115
|
-
},
|
|
116
|
-
controller2.signal
|
|
117
|
-
).finally(() => requests.complete(port, message.requestId, controller2));
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
if (!isOpenGeniSiteBridgeRequestMessage(message)) return;
|
|
121
|
-
const controller = requests.start(port, message.requestId);
|
|
122
|
-
if (!controller) {
|
|
123
|
-
port.postMessage({
|
|
124
|
-
type: OPENGENI_SITE_BRIDGE_RESPONSE,
|
|
125
|
-
version: OPENGENI_SITE_BRIDGE_VERSION,
|
|
126
|
-
requestId: message.requestId,
|
|
127
|
-
ok: false,
|
|
128
|
-
error: {
|
|
129
|
-
code: "duplicate_request_id",
|
|
130
|
-
message: "A Site tool request with this id is already running",
|
|
131
|
-
retryable: false
|
|
132
|
-
}
|
|
133
|
-
});
|
|
134
|
-
return;
|
|
135
|
-
}
|
|
136
|
-
void handleSiteBridgeRequest(bridgeRef.current, message, controller.signal).then((value) => {
|
|
137
|
-
if (!controller.signal.aborted) {
|
|
138
|
-
port.postMessage({
|
|
139
|
-
type: OPENGENI_SITE_BRIDGE_RESPONSE,
|
|
140
|
-
version: OPENGENI_SITE_BRIDGE_VERSION,
|
|
141
|
-
requestId: message.requestId,
|
|
142
|
-
ok: true,
|
|
143
|
-
value
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
|
-
}).catch((error) => {
|
|
147
|
-
if (!controller.signal.aborted) {
|
|
148
|
-
port.postMessage({
|
|
149
|
-
type: OPENGENI_SITE_BRIDGE_RESPONSE,
|
|
150
|
-
version: OPENGENI_SITE_BRIDGE_VERSION,
|
|
151
|
-
requestId: message.requestId,
|
|
152
|
-
ok: false,
|
|
153
|
-
error: siteBridgeError(error)
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
}).finally(() => requests.complete(port, message.requestId, controller));
|
|
157
|
-
});
|
|
158
|
-
port.addEventListener("messageerror", () => requests.closePort(port));
|
|
159
|
-
port.start();
|
|
160
|
-
port.postMessage({
|
|
161
|
-
type: OPENGENI_SITE_BRIDGE_READY,
|
|
162
|
-
version: OPENGENI_SITE_BRIDGE_VERSION
|
|
163
|
-
});
|
|
164
|
-
};
|
|
165
|
-
const documentLease = new SiteBridgeDocumentLease(attachToolPort, () => requests.closeAll());
|
|
166
|
-
const onFrameLoad = () => {
|
|
167
|
-
frameLoadPendingRef.current = false;
|
|
168
|
-
const frameWindow = frameRef.current?.contentWindow ?? null;
|
|
169
|
-
if (!frameWindow) return;
|
|
170
|
-
documentLease.load(frameWindow);
|
|
171
|
-
};
|
|
172
|
-
onFrameLoadRef.current = onFrameLoad;
|
|
173
|
-
if (frameLoadPendingRef.current) {
|
|
174
|
-
frameLoadPendingRef.current = false;
|
|
175
|
-
onFrameLoad();
|
|
176
|
-
}
|
|
177
|
-
return () => {
|
|
178
|
-
onFrameLoadRef.current = () => void 0;
|
|
179
|
-
documentLease.close();
|
|
180
|
-
};
|
|
181
|
-
}, [props.html, toolBridgeEnabled]);
|
|
182
|
-
return /* @__PURE__ */ jsx(
|
|
183
|
-
"iframe",
|
|
184
|
-
{
|
|
185
|
-
ref: frameRef,
|
|
186
|
-
title: props.title,
|
|
187
|
-
sandbox: PUBLISHED_HTML_ARTIFACT_IFRAME_SANDBOX,
|
|
188
|
-
referrerPolicy: "no-referrer",
|
|
189
|
-
srcDoc: publishedHtmlArtifactDocument(props.html, toolBridgeEnabled),
|
|
190
|
-
onLoad: () => {
|
|
191
|
-
frameLoadPendingRef.current = true;
|
|
192
|
-
onFrameLoadRef.current();
|
|
193
|
-
},
|
|
194
|
-
className: props.className,
|
|
195
|
-
style: props.style
|
|
196
|
-
}
|
|
197
|
-
);
|
|
198
|
-
}
|
|
199
|
-
var SiteBridgeRequestRegistry = class {
|
|
200
|
-
controllersByPort = /* @__PURE__ */ new Map();
|
|
201
|
-
addPort(port) {
|
|
202
|
-
if (!this.controllersByPort.has(port)) this.controllersByPort.set(port, /* @__PURE__ */ new Map());
|
|
203
|
-
}
|
|
204
|
-
start(port, requestId) {
|
|
205
|
-
const controllers = this.controllersByPort.get(port);
|
|
206
|
-
if (!controllers || controllers.has(requestId)) return null;
|
|
207
|
-
const controller = new AbortController();
|
|
208
|
-
controllers.set(requestId, controller);
|
|
209
|
-
return controller;
|
|
210
|
-
}
|
|
211
|
-
cancel(port, requestId) {
|
|
212
|
-
const controllers = this.controllersByPort.get(port);
|
|
213
|
-
const controller = controllers?.get(requestId);
|
|
214
|
-
if (!controller) return;
|
|
215
|
-
controller.abort(new Error("Site tool request cancelled"));
|
|
216
|
-
controllers.delete(requestId);
|
|
217
|
-
}
|
|
218
|
-
complete(port, requestId, controller) {
|
|
219
|
-
const controllers = this.controllersByPort.get(port);
|
|
220
|
-
if (controllers?.get(requestId) === controller) controllers.delete(requestId);
|
|
221
|
-
}
|
|
222
|
-
closePort(port) {
|
|
223
|
-
const controllers = this.controllersByPort.get(port);
|
|
224
|
-
if (!controllers) return;
|
|
225
|
-
for (const controller of controllers.values()) {
|
|
226
|
-
controller.abort(new Error("Site tool bridge port closed"));
|
|
227
|
-
}
|
|
228
|
-
controllers.clear();
|
|
229
|
-
this.controllersByPort.delete(port);
|
|
230
|
-
port.close();
|
|
231
|
-
}
|
|
232
|
-
closeAll() {
|
|
233
|
-
for (const port of [...this.controllersByPort.keys()]) this.closePort(port);
|
|
234
|
-
}
|
|
235
|
-
};
|
|
236
|
-
var SiteBridgeDocumentLease = class {
|
|
237
|
-
constructor(attachToolPort, closeActivePorts, createMessageChannel = () => new MessageChannel()) {
|
|
238
|
-
this.attachToolPort = attachToolPort;
|
|
239
|
-
this.closeActivePorts = closeActivePorts;
|
|
240
|
-
this.createMessageChannel = createMessageChannel;
|
|
241
|
-
}
|
|
242
|
-
loaded = false;
|
|
243
|
-
bootstrapPort = null;
|
|
244
|
-
load(frameWindow) {
|
|
245
|
-
if (this.loaded) {
|
|
246
|
-
this.close();
|
|
247
|
-
return false;
|
|
248
|
-
}
|
|
249
|
-
this.loaded = true;
|
|
250
|
-
const channel = this.createMessageChannel();
|
|
251
|
-
this.bootstrapPort = channel.port1;
|
|
252
|
-
channel.port1.addEventListener("message", (event) => {
|
|
253
|
-
this.attachToolPort(event.data, event.ports);
|
|
254
|
-
});
|
|
255
|
-
channel.port1.start();
|
|
256
|
-
frameWindow.postMessage(
|
|
257
|
-
{
|
|
258
|
-
type: OPENGENI_SITE_BRIDGE_READY,
|
|
259
|
-
version: OPENGENI_SITE_BRIDGE_VERSION
|
|
260
|
-
},
|
|
261
|
-
"*",
|
|
262
|
-
[channel.port2]
|
|
263
|
-
);
|
|
264
|
-
return true;
|
|
265
|
-
}
|
|
266
|
-
close() {
|
|
267
|
-
this.bootstrapPort?.close();
|
|
268
|
-
this.bootstrapPort = null;
|
|
269
|
-
this.closeActivePorts();
|
|
270
|
-
}
|
|
271
|
-
};
|
|
272
|
-
function openGeniSiteBridgePortFromBootstrap(data, ports) {
|
|
273
|
-
if (!isOpenGeniSiteBridgeConnectMessage(data)) return null;
|
|
274
|
-
return ports.length === 1 ? ports[0] : null;
|
|
275
|
-
}
|
|
276
|
-
async function handleSiteBridgeRequest(bridge, message, signal) {
|
|
277
|
-
if (!bridge) throw new Error("Site tool bridge is unavailable");
|
|
278
|
-
if (message.method === "catalog") return await bridge.catalog({ signal });
|
|
279
|
-
if (message.method === "declarations") {
|
|
280
|
-
if (!bridge.declarations) throw new Error("Site tool declarations are unavailable");
|
|
281
|
-
return await bridge.declarations({ signal });
|
|
282
|
-
}
|
|
283
|
-
return await bridge.call(sanitizeOpenGeniSiteToolCallRequest(message.payload), { signal });
|
|
284
|
-
}
|
|
285
|
-
function siteBridgeError(error) {
|
|
286
|
-
const candidate = error;
|
|
287
|
-
return {
|
|
288
|
-
code: typeof candidate?.code === "string" ? candidate.code : "site_tool_call_failed",
|
|
289
|
-
message: typeof candidate?.message === "string" ? candidate.message : "Site tool request failed",
|
|
290
|
-
retryable: candidate?.retryable === true,
|
|
291
|
-
outcomeUnknown: candidate?.outcomeUnknown === true
|
|
292
|
-
};
|
|
293
|
-
}
|
|
294
|
-
|
|
295
34
|
// src/components/artifacts/editable-artifact-workbench.tsx
|
|
296
35
|
import {
|
|
297
36
|
createBrowserEditableArtifactSession
|
|
298
37
|
} from "@opengeni/sdk/editable-artifacts";
|
|
299
|
-
import { useCallback, useEffect
|
|
300
|
-
import { jsx
|
|
38
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
39
|
+
import { jsx } from "react/jsx-runtime";
|
|
301
40
|
function EditableArtifactWorkbench({
|
|
302
41
|
session,
|
|
303
42
|
document,
|
|
@@ -306,7 +45,7 @@ function EditableArtifactWorkbench({
|
|
|
306
45
|
}) {
|
|
307
46
|
switch (session.modality) {
|
|
308
47
|
case "document":
|
|
309
|
-
return /* @__PURE__ */
|
|
48
|
+
return /* @__PURE__ */ jsx(
|
|
310
49
|
EditableDocumentArtifactSurface,
|
|
311
50
|
{
|
|
312
51
|
...document,
|
|
@@ -315,9 +54,9 @@ function EditableArtifactWorkbench({
|
|
|
315
54
|
}
|
|
316
55
|
);
|
|
317
56
|
case "spreadsheet":
|
|
318
|
-
return /* @__PURE__ */
|
|
57
|
+
return /* @__PURE__ */ jsx(EditableSpreadsheetArtifactSurface, { ...spreadsheet, session });
|
|
319
58
|
case "presentation":
|
|
320
|
-
return /* @__PURE__ */
|
|
59
|
+
return /* @__PURE__ */ jsx(EditablePresentationArtifactSurface, { ...presentation, session });
|
|
321
60
|
}
|
|
322
61
|
}
|
|
323
62
|
function EditableArtifactWorkbenchHost({
|
|
@@ -327,13 +66,13 @@ function EditableArtifactWorkbenchHost({
|
|
|
327
66
|
spreadsheet,
|
|
328
67
|
presentation
|
|
329
68
|
}) {
|
|
330
|
-
const createSessionRef =
|
|
69
|
+
const createSessionRef = useRef(createSession);
|
|
331
70
|
const [retryEpoch, setRetryEpoch] = useState(0);
|
|
332
71
|
const [state, setState] = useState({ key: null, session: null, error: null });
|
|
333
|
-
|
|
72
|
+
useEffect(() => {
|
|
334
73
|
createSessionRef.current = createSession;
|
|
335
74
|
}, [createSession]);
|
|
336
|
-
|
|
75
|
+
useEffect(() => {
|
|
337
76
|
let owned = null;
|
|
338
77
|
setState({ key: sessionKey, session: null, error: null });
|
|
339
78
|
try {
|
|
@@ -355,7 +94,7 @@ function EditableArtifactWorkbenchHost({
|
|
|
355
94
|
const retry = useCallback(() => setRetryEpoch((value) => value + 1), []);
|
|
356
95
|
const currentError = state.key === sessionKey ? state.error : null;
|
|
357
96
|
if (state.key === sessionKey && state.session) {
|
|
358
|
-
return /* @__PURE__ */
|
|
97
|
+
return /* @__PURE__ */ jsx(
|
|
359
98
|
EditableArtifactWorkbench,
|
|
360
99
|
{
|
|
361
100
|
session: state.session,
|
|
@@ -365,7 +104,7 @@ function EditableArtifactWorkbenchHost({
|
|
|
365
104
|
}
|
|
366
105
|
);
|
|
367
106
|
}
|
|
368
|
-
return /* @__PURE__ */
|
|
107
|
+
return /* @__PURE__ */ jsx(
|
|
369
108
|
EditableArtifactMessage,
|
|
370
109
|
{
|
|
371
110
|
title: currentError ? "Could not open this artifact" : "Opening artifact",
|
|
@@ -382,7 +121,7 @@ function BrowserEditableArtifactWorkbench({
|
|
|
382
121
|
}) {
|
|
383
122
|
const sessionKey = browserSessionKey(options);
|
|
384
123
|
const createSession = useCallback(() => createBrowserEditableArtifactSession(options), [options]);
|
|
385
|
-
return /* @__PURE__ */
|
|
124
|
+
return /* @__PURE__ */ jsx(
|
|
386
125
|
EditableArtifactWorkbenchHost,
|
|
387
126
|
{
|
|
388
127
|
sessionKey,
|
package/dist/artifacts.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/artifacts/published-html-artifact-frame.tsx","../src/components/artifacts/editable-artifact-workbench.tsx"],"sourcesContent":["import {\n OPENGENI_SITE_BRIDGE_BOOTSTRAP_GLOBAL,\n OPENGENI_SITE_BRIDGE_READY,\n OPENGENI_SITE_BRIDGE_RESPONSE,\n OPENGENI_SITE_BRIDGE_VERSION,\n isOpenGeniSiteBridgeCancelMessage,\n isOpenGeniSiteBridgeConnectMessage,\n isOpenGeniSiteBridgeRequestMessage,\n sanitizeOpenGeniSiteToolCallRequest,\n isSiteHttpRequest,\n serveSiteHttp,\n type SiteHttpRequest,\n type OpenGeniSiteBridgeResponseMessage,\n type OpenGeniSiteToolCatalog,\n} from \"@opengeni/sdk/site\";\nimport type {\n ToolGatewayCallRequest,\n ToolGatewayCallResponse,\n ToolGatewayDeclarationsResponse,\n} from \"@opengeni/sdk\";\nimport { useEffect, useRef, type CSSProperties } from \"react\";\n\nexport const PUBLISHED_HTML_ARTIFACT_IFRAME_SANDBOX = [\n \"allow-downloads\",\n \"allow-forms\",\n \"allow-modals\",\n \"allow-orientation-lock\",\n \"allow-pointer-lock\",\n \"allow-popups\",\n \"allow-popups-to-escape-sandbox\",\n \"allow-presentation\",\n \"allow-scripts\",\n].join(\" \");\n\nexport type PublishedHtmlArtifactFrameProps = {\n html: string;\n title: string;\n className?: string;\n style?: CSSProperties;\n toolBridge?: PublishedHtmlArtifactToolBridge;\n};\n\nexport type PublishedHtmlArtifactToolBridge = {\n fetch?: (request: SiteHttpRequest, signal: AbortSignal) => Promise<Response>;\n catalog: (options: { signal: AbortSignal }) => Promise<OpenGeniSiteToolCatalog>;\n call: (\n request: ToolGatewayCallRequest,\n options: { signal: AbortSignal },\n ) => Promise<ToolGatewayCallResponse>;\n declarations?: (options: { signal: AbortSignal }) => Promise<ToolGatewayDeclarationsResponse>;\n};\n\nconst SITE_BRIDGE_BOOTSTRAP_SCRIPT = `<script>(()=>{const key=${JSON.stringify(\n OPENGENI_SITE_BRIDGE_BOOTSTRAP_GLOBAL,\n)};const parentWindow=window.parent;if(parentWindow===window)return;window.addEventListener(\"message\",event=>{const data=event.data;if(event.source!==parentWindow||!data||data.type!==${JSON.stringify(\n OPENGENI_SITE_BRIDGE_READY,\n)}||data.version!==${OPENGENI_SITE_BRIDGE_VERSION}||event.ports.length!==1)return;const port=event.ports[0];const previous=window[key]?.port;if(previous&&previous!==port)previous.close();Object.defineProperty(window,key,{configurable:true,value:{port}});port.start();});})();</script>`;\n\nexport function publishedHtmlArtifactDocument(html: string, toolBridgeEnabled: boolean): string {\n if (!toolBridgeEnabled) return html;\n const doctypeEnd = leadingDoctypeEnd(html);\n if (doctypeEnd >= 0) {\n return `${html.slice(0, doctypeEnd + 1)}${SITE_BRIDGE_BOOTSTRAP_SCRIPT}${html.slice(doctypeEnd + 1)}`;\n }\n return `${SITE_BRIDGE_BOOTSTRAP_SCRIPT}${html}`;\n}\n\nfunction leadingDoctypeEnd(html: string): number {\n const lower = html.toLowerCase();\n let cursor = html.charCodeAt(0) === 0xfeff ? 1 : 0;\n while (cursor < html.length) {\n while (/\\s/.test(html[cursor] ?? \"\")) cursor += 1;\n if (!html.startsWith(\"<!--\", cursor)) break;\n const commentEnd = html.indexOf(\"-->\", cursor + 4);\n if (commentEnd < 0) return -1;\n cursor = commentEnd + 3;\n }\n if (!lower.startsWith(\"<!doctype\", cursor)) return -1;\n return html.indexOf(\">\", cursor + 9);\n}\n\n/**\n * Render exact published HTML in an opaque-origin iframe. Artifact scripts,\n * external resources, forms, popups, downloads, and the host-filtered tool\n * bridge work without granting parent-origin authority, shared cookies/storage,\n * or top-level navigation.\n */\nexport function PublishedHtmlArtifactFrame(props: PublishedHtmlArtifactFrameProps) {\n const frameRef = useRef<HTMLIFrameElement | null>(null);\n const bridgeRef = useRef(props.toolBridge);\n const onFrameLoadRef = useRef<() => void>(() => undefined);\n const frameLoadPendingRef = useRef(false);\n const toolBridgeEnabled = props.toolBridge !== undefined;\n useEffect(() => {\n bridgeRef.current = props.toolBridge;\n }, [props.toolBridge]);\n useEffect(() => {\n if (!toolBridgeEnabled || typeof window === \"undefined\") return;\n const requests = new SiteBridgeRequestRegistry();\n const attachToolPort = (data: unknown, ports: readonly MessagePort[]) => {\n const port = openGeniSiteBridgePortFromBootstrap(data, ports);\n if (!port) return;\n requests.addPort(port);\n port.addEventListener(\"message\", (portEvent: MessageEvent<unknown>) => {\n const message = portEvent.data;\n if (isOpenGeniSiteBridgeCancelMessage(message)) {\n requests.cancel(port, message.requestId);\n return;\n }\n if (isSiteHttpRequest(message) && portEvent.ports.length === 1) {\n const controller = requests.start(port, message.requestId);\n if (!controller) {\n portEvent.ports[0]!.close();\n return;\n }\n void serveSiteHttp(\n message,\n portEvent.ports[0]!,\n async (request, signal) => {\n const fetch = bridgeRef.current?.fetch;\n if (!fetch) throw new Error(\"This Site host does not support the session SDK\");\n return fetch(request, signal);\n },\n controller.signal,\n ).finally(() => requests.complete(port, message.requestId, controller));\n return;\n }\n if (!isOpenGeniSiteBridgeRequestMessage(message)) return;\n const controller = requests.start(port, message.requestId);\n if (!controller) {\n port.postMessage({\n type: OPENGENI_SITE_BRIDGE_RESPONSE,\n version: OPENGENI_SITE_BRIDGE_VERSION,\n requestId: message.requestId,\n ok: false,\n error: {\n code: \"duplicate_request_id\",\n message: \"A Site tool request with this id is already running\",\n retryable: false,\n },\n } satisfies OpenGeniSiteBridgeResponseMessage);\n return;\n }\n void handleSiteBridgeRequest(bridgeRef.current, message, controller.signal)\n .then((value) => {\n if (!controller.signal.aborted) {\n port.postMessage({\n type: OPENGENI_SITE_BRIDGE_RESPONSE,\n version: OPENGENI_SITE_BRIDGE_VERSION,\n requestId: message.requestId,\n ok: true,\n value,\n } satisfies OpenGeniSiteBridgeResponseMessage);\n }\n })\n .catch((error) => {\n if (!controller.signal.aborted) {\n port.postMessage({\n type: OPENGENI_SITE_BRIDGE_RESPONSE,\n version: OPENGENI_SITE_BRIDGE_VERSION,\n requestId: message.requestId,\n ok: false,\n error: siteBridgeError(error),\n } satisfies OpenGeniSiteBridgeResponseMessage);\n }\n })\n .finally(() => requests.complete(port, message.requestId, controller));\n });\n port.addEventListener(\"messageerror\", () => requests.closePort(port));\n port.start();\n port.postMessage({\n type: OPENGENI_SITE_BRIDGE_READY,\n version: OPENGENI_SITE_BRIDGE_VERSION,\n });\n };\n const documentLease = new SiteBridgeDocumentLease(attachToolPort, () => requests.closeAll());\n const onFrameLoad = () => {\n frameLoadPendingRef.current = false;\n const frameWindow = frameRef.current?.contentWindow ?? null;\n if (!frameWindow) return;\n documentLease.load(frameWindow);\n };\n onFrameLoadRef.current = onFrameLoad;\n if (frameLoadPendingRef.current) {\n frameLoadPendingRef.current = false;\n onFrameLoad();\n }\n return () => {\n onFrameLoadRef.current = () => undefined;\n documentLease.close();\n };\n }, [props.html, toolBridgeEnabled]);\n return (\n <iframe\n ref={frameRef}\n title={props.title}\n sandbox={PUBLISHED_HTML_ARTIFACT_IFRAME_SANDBOX}\n referrerPolicy=\"no-referrer\"\n srcDoc={publishedHtmlArtifactDocument(props.html, toolBridgeEnabled)}\n onLoad={() => {\n frameLoadPendingRef.current = true;\n onFrameLoadRef.current();\n }}\n className={props.className}\n style={props.style}\n />\n );\n}\n\nexport class SiteBridgeRequestRegistry {\n private readonly controllersByPort = new Map<MessagePort, Map<string, AbortController>>();\n\n addPort(port: MessagePort): void {\n // Several SDK clients may share one document bootstrap. Document teardown,\n // not another client connecting, revokes all of that document's ports.\n if (!this.controllersByPort.has(port)) this.controllersByPort.set(port, new Map());\n }\n\n start(port: MessagePort, requestId: string): AbortController | null {\n const controllers = this.controllersByPort.get(port);\n if (!controllers || controllers.has(requestId)) return null;\n const controller = new AbortController();\n controllers.set(requestId, controller);\n return controller;\n }\n\n cancel(port: MessagePort, requestId: string): void {\n const controllers = this.controllersByPort.get(port);\n const controller = controllers?.get(requestId);\n if (!controller) return;\n controller.abort(new Error(\"Site tool request cancelled\"));\n controllers!.delete(requestId);\n }\n\n complete(port: MessagePort, requestId: string, controller: AbortController): void {\n const controllers = this.controllersByPort.get(port);\n if (controllers?.get(requestId) === controller) controllers.delete(requestId);\n }\n\n closePort(port: MessagePort): void {\n const controllers = this.controllersByPort.get(port);\n if (!controllers) return;\n for (const controller of controllers.values()) {\n controller.abort(new Error(\"Site tool bridge port closed\"));\n }\n controllers.clear();\n this.controllersByPort.delete(port);\n port.close();\n }\n\n closeAll(): void {\n for (const port of [...this.controllersByPort.keys()]) this.closePort(port);\n }\n}\n\nexport class SiteBridgeDocumentLease {\n private loaded = false;\n private bootstrapPort: MessagePort | null = null;\n\n constructor(\n private readonly attachToolPort: (data: unknown, ports: readonly MessagePort[]) => void,\n private readonly closeActivePorts: () => void,\n private readonly createMessageChannel: () => MessageChannel = () => new MessageChannel(),\n ) {}\n\n load(frameWindow: Pick<Window, \"postMessage\">): boolean {\n if (this.loaded) {\n this.close();\n return false;\n }\n this.loaded = true;\n const channel = this.createMessageChannel();\n this.bootstrapPort = channel.port1;\n channel.port1.addEventListener(\"message\", (event: MessageEvent<unknown>) => {\n this.attachToolPort(event.data, event.ports);\n });\n channel.port1.start();\n frameWindow.postMessage(\n {\n type: OPENGENI_SITE_BRIDGE_READY,\n version: OPENGENI_SITE_BRIDGE_VERSION,\n },\n \"*\",\n [channel.port2],\n );\n return true;\n }\n\n close(): void {\n this.bootstrapPort?.close();\n this.bootstrapPort = null;\n this.closeActivePorts();\n }\n}\n\nexport function openGeniSiteBridgePortFromBootstrap(\n data: unknown,\n ports: readonly MessagePort[],\n): MessagePort | null {\n if (!isOpenGeniSiteBridgeConnectMessage(data)) return null;\n return ports.length === 1 ? ports[0]! : null;\n}\n\nasync function handleSiteBridgeRequest(\n bridge: PublishedHtmlArtifactToolBridge | undefined,\n message: Parameters<typeof isOpenGeniSiteBridgeRequestMessage>[0] & {\n method: \"catalog\" | \"call\" | \"declarations\";\n requestId: string;\n payload?: ToolGatewayCallRequest;\n },\n signal: AbortSignal,\n): Promise<OpenGeniSiteToolCatalog | ToolGatewayCallResponse | ToolGatewayDeclarationsResponse> {\n if (!bridge) throw new Error(\"Site tool bridge is unavailable\");\n if (message.method === \"catalog\") return await bridge.catalog({ signal });\n if (message.method === \"declarations\") {\n if (!bridge.declarations) throw new Error(\"Site tool declarations are unavailable\");\n return await bridge.declarations({ signal });\n }\n return await bridge.call(sanitizeOpenGeniSiteToolCallRequest(message.payload!), { signal });\n}\n\nexport function siteBridgeError(error: unknown): {\n code: string;\n message: string;\n retryable: boolean;\n outcomeUnknown: boolean;\n} {\n const candidate = error as {\n code?: unknown;\n message?: unknown;\n retryable?: unknown;\n outcomeUnknown?: unknown;\n };\n return {\n code: typeof candidate?.code === \"string\" ? candidate.code : \"site_tool_call_failed\",\n message:\n typeof candidate?.message === \"string\" ? candidate.message : \"Site tool request failed\",\n retryable: candidate?.retryable === true,\n outcomeUnknown: candidate?.outcomeUnknown === true,\n };\n}\n","import {\n createBrowserEditableArtifactSession,\n type CreateBrowserEditableArtifactSessionOptions,\n type EditableArtifactBrowserRuntime,\n type EditableArtifactSession,\n} from \"@opengeni/sdk/editable-artifacts\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\n\nimport { EditableArtifactMessage } from \"./editable-artifact-ui\";\nimport {\n EditableDocumentArtifactSurface,\n type EditableDocumentArtifactSurfaceProps,\n} from \"./editable-document\";\nimport {\n EditablePresentationArtifactSurface,\n type EditablePresentationArtifactSurfaceProps,\n} from \"./editable-presentation\";\nimport {\n EditableSpreadsheetArtifactSurface,\n type EditableSpreadsheetArtifactSurfaceProps,\n} from \"./editable-spreadsheet\";\n\nexport type EditableArtifactWorkbenchProps = Readonly<{\n session: EditableArtifactSession;\n document?: Omit<EditableDocumentArtifactSurfaceProps, \"session\">;\n spreadsheet?: Omit<EditableSpreadsheetArtifactSurfaceProps, \"session\">;\n presentation?: Omit<EditablePresentationArtifactSurfaceProps, \"session\">;\n}>;\n\nexport type EditableArtifactWorkbenchHostProps = Omit<EditableArtifactWorkbenchProps, \"session\"> &\n Readonly<{\n /**\n * Complete identity of the browser session authority. Change this when the\n * artifact, deployment, principal, or authorization epoch changes.\n */\n sessionKey: string;\n /** Called for the active keyed lifecycle and again only after replacement or retry. */\n createSession: () => EditableArtifactSession;\n }>;\n\ntype DefaultBrowserArtifactTransport = Omit<\n NonNullable<CreateBrowserEditableArtifactSessionOptions[\"transport\"]>,\n \"apiKey\" | \"fetch\" | \"headers\" | \"webSocketFactory\"\n> &\n Readonly<{\n /** Static deployment auth headers; rotate authorizationEpoch when they change. */\n headers?: Readonly<Record<string, string>>;\n }>;\n\nexport type BrowserEditableArtifactWorkbenchOptions = Omit<\n CreateBrowserEditableArtifactSessionOptions,\n \"runtime\" | \"storage\" | \"transport\"\n> &\n Readonly<{\n /** Default module Worker only; custom Worker hosts use EditableArtifactWorkbenchHost. */\n runtime: Omit<EditableArtifactBrowserRuntime, \"workerFactory\">;\n /** Default fetch/WebSocket only; static deployment auth headers are supported. */\n transport?: DefaultBrowserArtifactTransport;\n }>;\n\nexport type BrowserEditableArtifactWorkbenchProps = Omit<\n EditableArtifactWorkbenchProps,\n \"session\"\n> &\n Readonly<{ options: BrowserEditableArtifactWorkbenchOptions }>;\n\n/**\n * One modality-neutral SDK workbench. Embedding hosts keep one route/component;\n * each artifact still renders through its complete first-party editor surface.\n */\nexport function EditableArtifactWorkbench({\n session,\n document,\n spreadsheet,\n presentation,\n}: EditableArtifactWorkbenchProps) {\n switch (session.modality) {\n case \"document\":\n return (\n <EditableDocumentArtifactSurface\n {...document}\n session={session}\n title={document?.title ?? \"Document\"}\n />\n );\n case \"spreadsheet\":\n return <EditableSpreadsheetArtifactSurface {...spreadsheet} session={session} />;\n case \"presentation\":\n return <EditablePresentationArtifactSurface {...presentation} session={session} />;\n }\n}\n\n/**\n * Route/embed composition that owns exactly one SDK session. The host supplies\n * the authenticated SDK factory; React guarantees replacement and teardown.\n */\nexport function EditableArtifactWorkbenchHost({\n sessionKey,\n createSession,\n document,\n spreadsheet,\n presentation,\n}: EditableArtifactWorkbenchHostProps) {\n const createSessionRef = useRef(createSession);\n const [retryEpoch, setRetryEpoch] = useState(0);\n const [state, setState] = useState<\n | Readonly<{ key: string; session: EditableArtifactSession; error: null }>\n | Readonly<{ key: string | null; session: null; error: Error | null }>\n >({ key: null, session: null, error: null });\n\n useEffect(() => {\n createSessionRef.current = createSession;\n }, [createSession]);\n\n useEffect(() => {\n let owned: EditableArtifactSession | null = null;\n setState({ key: sessionKey, session: null, error: null });\n try {\n owned = createSessionRef.current();\n setState({ key: sessionKey, session: owned, error: null });\n } catch (cause) {\n setState({\n key: sessionKey,\n session: null,\n error: cause instanceof Error ? cause : new Error(\"Could not create artifact session\"),\n });\n }\n return () => {\n const closing = owned;\n owned = null;\n if (closing) void closing.close().catch(() => undefined);\n };\n }, [retryEpoch, sessionKey]);\n\n const retry = useCallback(() => setRetryEpoch((value) => value + 1), []);\n const currentError = state.key === sessionKey ? state.error : null;\n if (state.key === sessionKey && state.session) {\n return (\n <EditableArtifactWorkbench\n session={state.session}\n {...(document ? { document } : {})}\n {...(spreadsheet ? { spreadsheet } : {})}\n {...(presentation ? { presentation } : {})}\n />\n );\n }\n return (\n <EditableArtifactMessage\n title={currentError ? \"Could not open this artifact\" : \"Opening artifact\"}\n detail={currentError?.message ?? \"Starting the secure editing session…\"}\n retry={currentError ? retry : undefined}\n />\n );\n}\n\n/**\n * Complete default-browser composition for embedders: verified WASM Worker,\n * durable IndexedDB state, authenticated live sync, teardown, and the matching\n * first-party editor. Advanced/custom transports compose the lower-level host.\n */\nexport function BrowserEditableArtifactWorkbench({\n options,\n document,\n spreadsheet,\n presentation,\n}: BrowserEditableArtifactWorkbenchProps) {\n const sessionKey = browserSessionKey(options);\n const createSession = useCallback(() => createBrowserEditableArtifactSession(options), [options]);\n return (\n <EditableArtifactWorkbenchHost\n sessionKey={sessionKey}\n createSession={createSession}\n {...(document ? { document } : {})}\n {...(spreadsheet ? { spreadsheet } : {})}\n {...(presentation ? { presentation } : {})}\n />\n );\n}\n\nfunction browserSessionKey(options: BrowserEditableArtifactWorkbenchOptions): string {\n const transport = options.transport\n ? {\n ...options.transport,\n // Credentials must not be copied into React lifecycle keys. The\n // authorization epoch is the explicit credential/grant rotation fence.\n headers: options.transport.headers\n ? Object.keys(options.transport.headers).sort()\n : undefined,\n }\n : null;\n return JSON.stringify(\n {\n baseUrl: options.baseUrl,\n workspaceId: options.workspaceId,\n artifact: { id: options.artifact.id, modality: options.artifact.modality },\n storageAuthority: options.storageAuthority,\n runtime: options.runtime,\n replicaId: options.replicaId ?? null,\n transport,\n },\n (_key, value: unknown) => (value instanceof URL ? value.href : value),\n );\n}\n"],"mappings":"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","names":["controller","useEffect","useRef","jsx","useRef","useEffect"]}
|
|
1
|
+
{"version":3,"sources":["../src/components/artifacts/editable-artifact-workbench.tsx"],"sourcesContent":["import {\n createBrowserEditableArtifactSession,\n type CreateBrowserEditableArtifactSessionOptions,\n type EditableArtifactBrowserRuntime,\n type EditableArtifactSession,\n} from \"@opengeni/sdk/editable-artifacts\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\n\nimport { EditableArtifactMessage } from \"./editable-artifact-ui\";\nimport {\n EditableDocumentArtifactSurface,\n type EditableDocumentArtifactSurfaceProps,\n} from \"./editable-document\";\nimport {\n EditablePresentationArtifactSurface,\n type EditablePresentationArtifactSurfaceProps,\n} from \"./editable-presentation\";\nimport {\n EditableSpreadsheetArtifactSurface,\n type EditableSpreadsheetArtifactSurfaceProps,\n} from \"./editable-spreadsheet\";\n\nexport type EditableArtifactWorkbenchProps = Readonly<{\n session: EditableArtifactSession;\n document?: Omit<EditableDocumentArtifactSurfaceProps, \"session\">;\n spreadsheet?: Omit<EditableSpreadsheetArtifactSurfaceProps, \"session\">;\n presentation?: Omit<EditablePresentationArtifactSurfaceProps, \"session\">;\n}>;\n\nexport type EditableArtifactWorkbenchHostProps = Omit<EditableArtifactWorkbenchProps, \"session\"> &\n Readonly<{\n /**\n * Complete identity of the browser session authority. Change this when the\n * artifact, deployment, principal, or authorization epoch changes.\n */\n sessionKey: string;\n /** Called for the active keyed lifecycle and again only after replacement or retry. */\n createSession: () => EditableArtifactSession;\n }>;\n\ntype DefaultBrowserArtifactTransport = Omit<\n NonNullable<CreateBrowserEditableArtifactSessionOptions[\"transport\"]>,\n \"apiKey\" | \"fetch\" | \"headers\" | \"webSocketFactory\"\n> &\n Readonly<{\n /** Static deployment auth headers; rotate authorizationEpoch when they change. */\n headers?: Readonly<Record<string, string>>;\n }>;\n\nexport type BrowserEditableArtifactWorkbenchOptions = Omit<\n CreateBrowserEditableArtifactSessionOptions,\n \"runtime\" | \"storage\" | \"transport\"\n> &\n Readonly<{\n /** Default module Worker only; custom Worker hosts use EditableArtifactWorkbenchHost. */\n runtime: Omit<EditableArtifactBrowserRuntime, \"workerFactory\">;\n /** Default fetch/WebSocket only; static deployment auth headers are supported. */\n transport?: DefaultBrowserArtifactTransport;\n }>;\n\nexport type BrowserEditableArtifactWorkbenchProps = Omit<\n EditableArtifactWorkbenchProps,\n \"session\"\n> &\n Readonly<{ options: BrowserEditableArtifactWorkbenchOptions }>;\n\n/**\n * One modality-neutral SDK workbench. Embedding hosts keep one route/component;\n * each artifact still renders through its complete first-party editor surface.\n */\nexport function EditableArtifactWorkbench({\n session,\n document,\n spreadsheet,\n presentation,\n}: EditableArtifactWorkbenchProps) {\n switch (session.modality) {\n case \"document\":\n return (\n <EditableDocumentArtifactSurface\n {...document}\n session={session}\n title={document?.title ?? \"Document\"}\n />\n );\n case \"spreadsheet\":\n return <EditableSpreadsheetArtifactSurface {...spreadsheet} session={session} />;\n case \"presentation\":\n return <EditablePresentationArtifactSurface {...presentation} session={session} />;\n }\n}\n\n/**\n * Route/embed composition that owns exactly one SDK session. The host supplies\n * the authenticated SDK factory; React guarantees replacement and teardown.\n */\nexport function EditableArtifactWorkbenchHost({\n sessionKey,\n createSession,\n document,\n spreadsheet,\n presentation,\n}: EditableArtifactWorkbenchHostProps) {\n const createSessionRef = useRef(createSession);\n const [retryEpoch, setRetryEpoch] = useState(0);\n const [state, setState] = useState<\n | Readonly<{ key: string; session: EditableArtifactSession; error: null }>\n | Readonly<{ key: string | null; session: null; error: Error | null }>\n >({ key: null, session: null, error: null });\n\n useEffect(() => {\n createSessionRef.current = createSession;\n }, [createSession]);\n\n useEffect(() => {\n let owned: EditableArtifactSession | null = null;\n setState({ key: sessionKey, session: null, error: null });\n try {\n owned = createSessionRef.current();\n setState({ key: sessionKey, session: owned, error: null });\n } catch (cause) {\n setState({\n key: sessionKey,\n session: null,\n error: cause instanceof Error ? cause : new Error(\"Could not create artifact session\"),\n });\n }\n return () => {\n const closing = owned;\n owned = null;\n if (closing) void closing.close().catch(() => undefined);\n };\n }, [retryEpoch, sessionKey]);\n\n const retry = useCallback(() => setRetryEpoch((value) => value + 1), []);\n const currentError = state.key === sessionKey ? state.error : null;\n if (state.key === sessionKey && state.session) {\n return (\n <EditableArtifactWorkbench\n session={state.session}\n {...(document ? { document } : {})}\n {...(spreadsheet ? { spreadsheet } : {})}\n {...(presentation ? { presentation } : {})}\n />\n );\n }\n return (\n <EditableArtifactMessage\n title={currentError ? \"Could not open this artifact\" : \"Opening artifact\"}\n detail={currentError?.message ?? \"Starting the secure editing session…\"}\n retry={currentError ? retry : undefined}\n />\n );\n}\n\n/**\n * Complete default-browser composition for embedders: verified WASM Worker,\n * durable IndexedDB state, authenticated live sync, teardown, and the matching\n * first-party editor. Advanced/custom transports compose the lower-level host.\n */\nexport function BrowserEditableArtifactWorkbench({\n options,\n document,\n spreadsheet,\n presentation,\n}: BrowserEditableArtifactWorkbenchProps) {\n const sessionKey = browserSessionKey(options);\n const createSession = useCallback(() => createBrowserEditableArtifactSession(options), [options]);\n return (\n <EditableArtifactWorkbenchHost\n sessionKey={sessionKey}\n createSession={createSession}\n {...(document ? { document } : {})}\n {...(spreadsheet ? { spreadsheet } : {})}\n {...(presentation ? { presentation } : {})}\n />\n );\n}\n\nfunction browserSessionKey(options: BrowserEditableArtifactWorkbenchOptions): string {\n const transport = options.transport\n ? {\n ...options.transport,\n // Credentials must not be copied into React lifecycle keys. The\n // authorization epoch is the explicit credential/grant rotation fence.\n headers: options.transport.headers\n ? Object.keys(options.transport.headers).sort()\n : undefined,\n }\n : null;\n return JSON.stringify(\n {\n baseUrl: options.baseUrl,\n workspaceId: options.workspaceId,\n artifact: { id: options.artifact.id, modality: options.artifact.modality },\n storageAuthority: options.storageAuthority,\n runtime: options.runtime,\n replicaId: options.replicaId ?? null,\n transport,\n },\n (_key, value: unknown) => (value instanceof URL ? value.href : value),\n );\n}\n"],"mappings":"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","names":[]}
|