@pancake-apps/web 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +929 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +479 -0
- package/dist/index.d.ts +479 -0
- package/dist/index.js +919 -0
- package/dist/index.js.map +1 -0
- package/dist/react/index.cjs +1067 -0
- package/dist/react/index.cjs.map +1 -0
- package/dist/react/index.d.cts +536 -0
- package/dist/react/index.d.ts +536 -0
- package/dist/react/index.js +1053 -0
- package/dist/react/index.js.map +1 -0
- package/package.json +83 -0
|
@@ -0,0 +1,1053 @@
|
|
|
1
|
+
import { createContext, useContext, useState, useEffect, useCallback } from 'react';
|
|
2
|
+
import { jsx, Fragment } from 'react/jsx-runtime';
|
|
3
|
+
|
|
4
|
+
// src/react/provider.tsx
|
|
5
|
+
|
|
6
|
+
// src/types.ts
|
|
7
|
+
var DEFAULT_HOST_CONTEXT = {
|
|
8
|
+
theme: "light",
|
|
9
|
+
displayMode: "inline",
|
|
10
|
+
availableDisplayModes: ["inline"],
|
|
11
|
+
viewport: { width: 0, height: 0 },
|
|
12
|
+
locale: "en-US",
|
|
13
|
+
timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
14
|
+
platform: "web"
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
// src/adapters/mcp.ts
|
|
18
|
+
var McpAdapter = class {
|
|
19
|
+
constructor(options) {
|
|
20
|
+
this.options = options;
|
|
21
|
+
}
|
|
22
|
+
protocol = "mcp";
|
|
23
|
+
app = null;
|
|
24
|
+
connected = false;
|
|
25
|
+
context = { ...DEFAULT_HOST_CONTEXT };
|
|
26
|
+
currentToolInput;
|
|
27
|
+
currentToolOutput;
|
|
28
|
+
state = null;
|
|
29
|
+
hostContextHandlers = /* @__PURE__ */ new Set();
|
|
30
|
+
toolInputHandlers = /* @__PURE__ */ new Set();
|
|
31
|
+
toolOutputHandlers = /* @__PURE__ */ new Set();
|
|
32
|
+
toolCancelledHandlers = /* @__PURE__ */ new Set();
|
|
33
|
+
teardownHandlers = /* @__PURE__ */ new Set();
|
|
34
|
+
isConnected() {
|
|
35
|
+
return this.connected;
|
|
36
|
+
}
|
|
37
|
+
async connect() {
|
|
38
|
+
if (this.connected) return;
|
|
39
|
+
if (typeof window === "undefined") {
|
|
40
|
+
this.connected = true;
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
const { App } = await import('@modelcontextprotocol/ext-apps');
|
|
45
|
+
this.app = new App(
|
|
46
|
+
{ name: "pancake-client", version: "0.1.0" },
|
|
47
|
+
{ tools: {} },
|
|
48
|
+
{ autoResize: this.options?.autoResize ?? true }
|
|
49
|
+
);
|
|
50
|
+
const app = this.app;
|
|
51
|
+
app.onerror = (err) => this.log("error", err);
|
|
52
|
+
app.onhostcontextchanged = (params) => {
|
|
53
|
+
const hostContext = params?.hostContext ?? params;
|
|
54
|
+
this.context = this.mapHostContext(hostContext);
|
|
55
|
+
for (const handler of this.hostContextHandlers) {
|
|
56
|
+
handler(this.context);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
app.ontoolinput = (params) => {
|
|
60
|
+
const args = params?.arguments;
|
|
61
|
+
if (args) {
|
|
62
|
+
this.currentToolInput = args;
|
|
63
|
+
for (const handler of this.toolInputHandlers) {
|
|
64
|
+
handler(args);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
app.ontoolresult = (result) => {
|
|
69
|
+
const output = result?.structuredContent ?? {};
|
|
70
|
+
this.currentToolOutput = output;
|
|
71
|
+
for (const handler of this.toolOutputHandlers) {
|
|
72
|
+
handler(output);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
app.ontoolcancelled = (params) => {
|
|
76
|
+
const reason = params?.reason;
|
|
77
|
+
for (const handler of this.toolCancelledHandlers) {
|
|
78
|
+
handler(reason);
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
app.onteardown = async (params) => {
|
|
82
|
+
const reason = params?.reason;
|
|
83
|
+
for (const handler of this.teardownHandlers) {
|
|
84
|
+
handler(reason);
|
|
85
|
+
}
|
|
86
|
+
return {};
|
|
87
|
+
};
|
|
88
|
+
await app.connect();
|
|
89
|
+
const initialContext = app.getHostContext();
|
|
90
|
+
if (initialContext) {
|
|
91
|
+
this.context = this.mapHostContext(initialContext);
|
|
92
|
+
}
|
|
93
|
+
this.connected = true;
|
|
94
|
+
} catch (error) {
|
|
95
|
+
console.warn("[Pancake] Failed to connect MCP adapter:", error);
|
|
96
|
+
this.connected = true;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
async disconnect() {
|
|
100
|
+
this.connected = false;
|
|
101
|
+
this.app = null;
|
|
102
|
+
}
|
|
103
|
+
mapHostContext(raw) {
|
|
104
|
+
const ctx = raw;
|
|
105
|
+
const result = {
|
|
106
|
+
theme: ctx["theme"] ?? "light",
|
|
107
|
+
displayMode: ctx["displayMode"] ?? "inline",
|
|
108
|
+
availableDisplayModes: ctx["availableDisplayModes"] ?? ["inline"],
|
|
109
|
+
viewport: ctx["viewport"] ?? { width: 0, height: 0 },
|
|
110
|
+
locale: ctx["locale"] ?? "en-US",
|
|
111
|
+
timeZone: ctx["timeZone"] ?? Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
112
|
+
platform: ctx["platform"] ?? "web"
|
|
113
|
+
};
|
|
114
|
+
if (ctx["view"] !== void 0) {
|
|
115
|
+
result.view = ctx["view"];
|
|
116
|
+
}
|
|
117
|
+
if (ctx["safeAreaInsets"] !== void 0) {
|
|
118
|
+
result.safeAreaInsets = ctx["safeAreaInsets"];
|
|
119
|
+
}
|
|
120
|
+
return result;
|
|
121
|
+
}
|
|
122
|
+
getHostContext() {
|
|
123
|
+
return this.context;
|
|
124
|
+
}
|
|
125
|
+
onHostContextChange(handler) {
|
|
126
|
+
this.hostContextHandlers.add(handler);
|
|
127
|
+
return () => this.hostContextHandlers.delete(handler);
|
|
128
|
+
}
|
|
129
|
+
getViewParams() {
|
|
130
|
+
return {
|
|
131
|
+
inputs: this.currentToolInput ?? {},
|
|
132
|
+
data: this.currentToolOutput ?? {}
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
getToolInput() {
|
|
136
|
+
return this.currentToolInput;
|
|
137
|
+
}
|
|
138
|
+
getToolOutput() {
|
|
139
|
+
return this.currentToolOutput;
|
|
140
|
+
}
|
|
141
|
+
onToolInput(handler) {
|
|
142
|
+
this.toolInputHandlers.add(handler);
|
|
143
|
+
return () => this.toolInputHandlers.delete(handler);
|
|
144
|
+
}
|
|
145
|
+
onToolOutput(handler) {
|
|
146
|
+
this.toolOutputHandlers.add(handler);
|
|
147
|
+
return () => this.toolOutputHandlers.delete(handler);
|
|
148
|
+
}
|
|
149
|
+
async callTool(name, args) {
|
|
150
|
+
if (!this.app) {
|
|
151
|
+
throw new Error("Not connected");
|
|
152
|
+
}
|
|
153
|
+
const app = this.app;
|
|
154
|
+
const result = await app.callServerTool({ name, arguments: args });
|
|
155
|
+
return result.structuredContent ?? {};
|
|
156
|
+
}
|
|
157
|
+
async sendMessage(content) {
|
|
158
|
+
if (!this.app) return;
|
|
159
|
+
const app = this.app;
|
|
160
|
+
await app.sendMessage({
|
|
161
|
+
role: "user",
|
|
162
|
+
content: [{ type: "text", text: content.text }]
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
async openLink(url) {
|
|
166
|
+
if (!this.app) {
|
|
167
|
+
window.open(url, "_blank");
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
const app = this.app;
|
|
171
|
+
await app.openLink({ url });
|
|
172
|
+
}
|
|
173
|
+
async requestDisplayMode(mode) {
|
|
174
|
+
if (!this.app) {
|
|
175
|
+
return { mode };
|
|
176
|
+
}
|
|
177
|
+
const app = this.app;
|
|
178
|
+
return app.requestDisplayMode({ mode });
|
|
179
|
+
}
|
|
180
|
+
requestClose() {
|
|
181
|
+
}
|
|
182
|
+
// State is not supported in MCP
|
|
183
|
+
getState() {
|
|
184
|
+
return this.state;
|
|
185
|
+
}
|
|
186
|
+
setState(state) {
|
|
187
|
+
this.state = state;
|
|
188
|
+
}
|
|
189
|
+
onToolCancelled(handler) {
|
|
190
|
+
this.toolCancelledHandlers.add(handler);
|
|
191
|
+
return () => this.toolCancelledHandlers.delete(handler);
|
|
192
|
+
}
|
|
193
|
+
onTeardown(handler) {
|
|
194
|
+
this.teardownHandlers.add(handler);
|
|
195
|
+
return () => this.teardownHandlers.delete(handler);
|
|
196
|
+
}
|
|
197
|
+
log(level, data) {
|
|
198
|
+
if (this.app) {
|
|
199
|
+
const app = this.app;
|
|
200
|
+
try {
|
|
201
|
+
app.sendLog({ level, data, logger: "pancake" });
|
|
202
|
+
return;
|
|
203
|
+
} catch {
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
console[level === "debug" ? "log" : level]("[Pancake]", data);
|
|
207
|
+
}
|
|
208
|
+
async sendSizeChanged(params) {
|
|
209
|
+
if (!this.app) return;
|
|
210
|
+
const app = this.app;
|
|
211
|
+
await app.sendSizeChanged(params);
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
// src/adapters/openai.ts
|
|
216
|
+
var OpenAIAdapter = class {
|
|
217
|
+
protocol = "openai";
|
|
218
|
+
connected = false;
|
|
219
|
+
context = { ...DEFAULT_HOST_CONTEXT };
|
|
220
|
+
currentToolInput;
|
|
221
|
+
currentToolOutput;
|
|
222
|
+
state = null;
|
|
223
|
+
hostContextHandlers = /* @__PURE__ */ new Set();
|
|
224
|
+
toolInputHandlers = /* @__PURE__ */ new Set();
|
|
225
|
+
toolOutputHandlers = /* @__PURE__ */ new Set();
|
|
226
|
+
toolCancelledHandlers = /* @__PURE__ */ new Set();
|
|
227
|
+
teardownHandlers = /* @__PURE__ */ new Set();
|
|
228
|
+
globalsHandler = null;
|
|
229
|
+
setGlobalsHandler = null;
|
|
230
|
+
isConnected() {
|
|
231
|
+
return this.connected;
|
|
232
|
+
}
|
|
233
|
+
getOpenAI() {
|
|
234
|
+
if (typeof window !== "undefined" && "openai" in window) {
|
|
235
|
+
return window.openai;
|
|
236
|
+
}
|
|
237
|
+
return null;
|
|
238
|
+
}
|
|
239
|
+
async connect() {
|
|
240
|
+
if (this.connected) return;
|
|
241
|
+
await this.waitForOpenAI();
|
|
242
|
+
const openai = this.getOpenAI();
|
|
243
|
+
if (openai) {
|
|
244
|
+
this.readContextFromSDK();
|
|
245
|
+
this.readToolDataFromSDK();
|
|
246
|
+
if (typeof openai["init"] === "function") {
|
|
247
|
+
await openai["init"]();
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
this.setupGlobalsListener();
|
|
251
|
+
this.connected = true;
|
|
252
|
+
}
|
|
253
|
+
async disconnect() {
|
|
254
|
+
if (this.globalsHandler) {
|
|
255
|
+
window.removeEventListener("message", this.globalsHandler);
|
|
256
|
+
}
|
|
257
|
+
if (this.setGlobalsHandler) {
|
|
258
|
+
window.removeEventListener("openai:set_globals", this.setGlobalsHandler);
|
|
259
|
+
}
|
|
260
|
+
this.connected = false;
|
|
261
|
+
}
|
|
262
|
+
async waitForOpenAI(timeout = 5e3) {
|
|
263
|
+
if (this.getOpenAI()) return;
|
|
264
|
+
return new Promise((resolve) => {
|
|
265
|
+
const startTime = Date.now();
|
|
266
|
+
const check = () => {
|
|
267
|
+
if (this.getOpenAI()) {
|
|
268
|
+
resolve();
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
if (Date.now() - startTime > timeout) {
|
|
272
|
+
resolve();
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
setTimeout(check, 50);
|
|
276
|
+
};
|
|
277
|
+
const messageHandler = (event) => {
|
|
278
|
+
if (this.isSetGlobalsMessage(event.data)) {
|
|
279
|
+
setTimeout(() => {
|
|
280
|
+
if (this.getOpenAI()) {
|
|
281
|
+
window.removeEventListener("message", messageHandler);
|
|
282
|
+
resolve();
|
|
283
|
+
}
|
|
284
|
+
}, 50);
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
window.addEventListener("message", messageHandler);
|
|
288
|
+
check();
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
isSetGlobalsMessage(data) {
|
|
292
|
+
return data === "openai:set_globals" || typeof data === "object" && data !== null && "type" in data && data.type === "openai:set_globals" || typeof data === "object" && data !== null && "message" in data && data.message === "openai:set_globals";
|
|
293
|
+
}
|
|
294
|
+
setupGlobalsListener() {
|
|
295
|
+
this.setGlobalsHandler = (event) => {
|
|
296
|
+
const detail = event.detail;
|
|
297
|
+
const globals = detail?.globals ?? detail;
|
|
298
|
+
this.updateContextFromGlobals(globals);
|
|
299
|
+
};
|
|
300
|
+
window.addEventListener("openai:set_globals", this.setGlobalsHandler);
|
|
301
|
+
this.globalsHandler = (event) => {
|
|
302
|
+
if (this.isSetGlobalsMessage(event.data)) {
|
|
303
|
+
setTimeout(() => this.readContextFromSDK(), 50);
|
|
304
|
+
}
|
|
305
|
+
};
|
|
306
|
+
window.addEventListener("message", this.globalsHandler);
|
|
307
|
+
}
|
|
308
|
+
updateContextFromGlobals(globals) {
|
|
309
|
+
if (globals?.["theme"]) this.context.theme = globals["theme"];
|
|
310
|
+
if (globals?.["locale"]) this.context.locale = globals["locale"];
|
|
311
|
+
if (globals?.["displayMode"]) this.context.displayMode = globals["displayMode"];
|
|
312
|
+
for (const handler of this.hostContextHandlers) {
|
|
313
|
+
handler({ ...this.context });
|
|
314
|
+
}
|
|
315
|
+
if (globals?.["toolOutput"]) {
|
|
316
|
+
this.currentToolOutput = globals["toolOutput"];
|
|
317
|
+
for (const handler of this.toolOutputHandlers) {
|
|
318
|
+
handler(this.currentToolOutput);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
readContextFromSDK() {
|
|
323
|
+
const openai = this.getOpenAI();
|
|
324
|
+
if (!openai) return;
|
|
325
|
+
if (typeof openai["theme"] === "string") {
|
|
326
|
+
this.context.theme = openai["theme"];
|
|
327
|
+
}
|
|
328
|
+
if (typeof openai["displayMode"] === "string") {
|
|
329
|
+
this.context.displayMode = openai["displayMode"];
|
|
330
|
+
}
|
|
331
|
+
if (typeof openai["locale"] === "string") {
|
|
332
|
+
this.context.locale = openai["locale"];
|
|
333
|
+
}
|
|
334
|
+
if (openai["safeArea"] && typeof openai["safeArea"] === "object") {
|
|
335
|
+
this.context.safeAreaInsets = openai["safeArea"];
|
|
336
|
+
}
|
|
337
|
+
if (typeof openai["maxHeight"] === "number") {
|
|
338
|
+
this.context.viewport = {
|
|
339
|
+
width: window.innerWidth,
|
|
340
|
+
height: openai["maxHeight"]
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
readToolDataFromSDK() {
|
|
345
|
+
const openai = this.getOpenAI();
|
|
346
|
+
if (!openai) return;
|
|
347
|
+
if (typeof openai["getToolInput"] === "function") {
|
|
348
|
+
this.currentToolInput = openai["getToolInput"]();
|
|
349
|
+
} else if (openai["toolInput"]) {
|
|
350
|
+
this.currentToolInput = openai["toolInput"];
|
|
351
|
+
} else if (openai["input"]) {
|
|
352
|
+
this.currentToolInput = openai["input"];
|
|
353
|
+
}
|
|
354
|
+
if (typeof openai["getToolOutput"] === "function") {
|
|
355
|
+
this.currentToolOutput = openai["getToolOutput"]();
|
|
356
|
+
} else if (openai["toolOutput"]) {
|
|
357
|
+
this.currentToolOutput = openai["toolOutput"];
|
|
358
|
+
} else if (openai["result"]) {
|
|
359
|
+
this.currentToolOutput = openai["result"];
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
getHostContext() {
|
|
363
|
+
return this.context;
|
|
364
|
+
}
|
|
365
|
+
onHostContextChange(handler) {
|
|
366
|
+
this.hostContextHandlers.add(handler);
|
|
367
|
+
return () => this.hostContextHandlers.delete(handler);
|
|
368
|
+
}
|
|
369
|
+
getViewParams() {
|
|
370
|
+
return {
|
|
371
|
+
inputs: this.currentToolInput ?? {},
|
|
372
|
+
data: this.currentToolOutput ?? {}
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
getToolInput() {
|
|
376
|
+
return this.currentToolInput;
|
|
377
|
+
}
|
|
378
|
+
getToolOutput() {
|
|
379
|
+
return this.currentToolOutput;
|
|
380
|
+
}
|
|
381
|
+
onToolInput(handler) {
|
|
382
|
+
this.toolInputHandlers.add(handler);
|
|
383
|
+
return () => this.toolInputHandlers.delete(handler);
|
|
384
|
+
}
|
|
385
|
+
onToolOutput(handler) {
|
|
386
|
+
this.toolOutputHandlers.add(handler);
|
|
387
|
+
return () => this.toolOutputHandlers.delete(handler);
|
|
388
|
+
}
|
|
389
|
+
async callTool(name, args) {
|
|
390
|
+
const openai = this.getOpenAI();
|
|
391
|
+
if (openai && typeof openai["callTool"] === "function") {
|
|
392
|
+
return openai["callTool"](name, args);
|
|
393
|
+
}
|
|
394
|
+
throw new Error("OpenAI SDK not available");
|
|
395
|
+
}
|
|
396
|
+
async sendMessage(content) {
|
|
397
|
+
const openai = this.getOpenAI();
|
|
398
|
+
if (openai && typeof openai["sendFollowUpMessage"] === "function") {
|
|
399
|
+
await openai["sendFollowUpMessage"]({ prompt: content.text });
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
async openLink(url) {
|
|
403
|
+
const openai = this.getOpenAI();
|
|
404
|
+
if (openai && typeof openai["openExternal"] === "function") {
|
|
405
|
+
await openai["openExternal"]({ href: url });
|
|
406
|
+
} else {
|
|
407
|
+
window.open(url, "_blank");
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
async requestDisplayMode(mode) {
|
|
411
|
+
const openai = this.getOpenAI();
|
|
412
|
+
if (openai && typeof openai["requestDisplayMode"] === "function") {
|
|
413
|
+
return openai["requestDisplayMode"]({ mode });
|
|
414
|
+
}
|
|
415
|
+
return { mode };
|
|
416
|
+
}
|
|
417
|
+
requestClose() {
|
|
418
|
+
const openai = this.getOpenAI();
|
|
419
|
+
if (openai && typeof openai["close"] === "function") {
|
|
420
|
+
openai["close"]();
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
// State IS supported in ChatGPT
|
|
424
|
+
getState() {
|
|
425
|
+
const openai = this.getOpenAI();
|
|
426
|
+
if (openai && typeof openai["getWidgetState"] === "function") {
|
|
427
|
+
return openai["getWidgetState"]();
|
|
428
|
+
}
|
|
429
|
+
return this.state;
|
|
430
|
+
}
|
|
431
|
+
setState(state) {
|
|
432
|
+
this.state = state;
|
|
433
|
+
const openai = this.getOpenAI();
|
|
434
|
+
if (openai && typeof openai["setWidgetState"] === "function") {
|
|
435
|
+
openai["setWidgetState"](state);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
onToolCancelled(handler) {
|
|
439
|
+
this.toolCancelledHandlers.add(handler);
|
|
440
|
+
return () => this.toolCancelledHandlers.delete(handler);
|
|
441
|
+
}
|
|
442
|
+
onTeardown(handler) {
|
|
443
|
+
this.teardownHandlers.add(handler);
|
|
444
|
+
return () => this.teardownHandlers.delete(handler);
|
|
445
|
+
}
|
|
446
|
+
log(level, data) {
|
|
447
|
+
console[level === "debug" ? "log" : level]("[Pancake]", data);
|
|
448
|
+
}
|
|
449
|
+
async sendSizeChanged(params) {
|
|
450
|
+
const openai = this.getOpenAI();
|
|
451
|
+
if (openai && typeof openai["notifyIntrinsicHeight"] === "function") {
|
|
452
|
+
openai["notifyIntrinsicHeight"](params.height);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
};
|
|
456
|
+
|
|
457
|
+
// src/adapters/mock.ts
|
|
458
|
+
var MockAdapter = class {
|
|
459
|
+
protocol = "mock";
|
|
460
|
+
connected = false;
|
|
461
|
+
context;
|
|
462
|
+
toolInput;
|
|
463
|
+
toolOutput;
|
|
464
|
+
state = null;
|
|
465
|
+
hostContextHandlers = /* @__PURE__ */ new Set();
|
|
466
|
+
toolInputHandlers = /* @__PURE__ */ new Set();
|
|
467
|
+
toolOutputHandlers = /* @__PURE__ */ new Set();
|
|
468
|
+
toolCancelledHandlers = /* @__PURE__ */ new Set();
|
|
469
|
+
teardownHandlers = /* @__PURE__ */ new Set();
|
|
470
|
+
toolHandlers = /* @__PURE__ */ new Map();
|
|
471
|
+
constructor(options) {
|
|
472
|
+
this.context = { ...DEFAULT_HOST_CONTEXT, ...options?.hostContext };
|
|
473
|
+
this.toolInput = options?.toolInput;
|
|
474
|
+
this.toolOutput = options?.toolOutput;
|
|
475
|
+
}
|
|
476
|
+
isConnected() {
|
|
477
|
+
return this.connected;
|
|
478
|
+
}
|
|
479
|
+
async connect() {
|
|
480
|
+
this.connected = true;
|
|
481
|
+
}
|
|
482
|
+
async disconnect() {
|
|
483
|
+
this.connected = false;
|
|
484
|
+
}
|
|
485
|
+
// ─────────────────────────────────────────────────────────────
|
|
486
|
+
// Mock-specific methods for testing
|
|
487
|
+
// ─────────────────────────────────────────────────────────────
|
|
488
|
+
/**
|
|
489
|
+
* Set the host context (for testing)
|
|
490
|
+
*/
|
|
491
|
+
setHostContext(ctx) {
|
|
492
|
+
this.context = { ...this.context, ...ctx };
|
|
493
|
+
for (const handler of this.hostContextHandlers) {
|
|
494
|
+
handler(this.context);
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
/**
|
|
498
|
+
* Set the tool input (for testing)
|
|
499
|
+
*/
|
|
500
|
+
setToolInput(input) {
|
|
501
|
+
this.toolInput = input;
|
|
502
|
+
for (const handler of this.toolInputHandlers) {
|
|
503
|
+
handler(input);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* Set the tool output (for testing)
|
|
508
|
+
*/
|
|
509
|
+
setToolOutput(output) {
|
|
510
|
+
this.toolOutput = output;
|
|
511
|
+
for (const handler of this.toolOutputHandlers) {
|
|
512
|
+
handler(output);
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
/**
|
|
516
|
+
* Register a tool handler (for testing)
|
|
517
|
+
*/
|
|
518
|
+
registerToolHandler(name, handler) {
|
|
519
|
+
this.toolHandlers.set(name, handler);
|
|
520
|
+
}
|
|
521
|
+
/**
|
|
522
|
+
* Trigger tool cancellation (for testing)
|
|
523
|
+
*/
|
|
524
|
+
triggerToolCancelled(reason) {
|
|
525
|
+
for (const handler of this.toolCancelledHandlers) {
|
|
526
|
+
handler(reason);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
/**
|
|
530
|
+
* Trigger teardown (for testing)
|
|
531
|
+
*/
|
|
532
|
+
triggerTeardown(reason) {
|
|
533
|
+
for (const handler of this.teardownHandlers) {
|
|
534
|
+
handler(reason);
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
// ─────────────────────────────────────────────────────────────
|
|
538
|
+
// ProtocolAdapter implementation
|
|
539
|
+
// ─────────────────────────────────────────────────────────────
|
|
540
|
+
getHostContext() {
|
|
541
|
+
return this.context;
|
|
542
|
+
}
|
|
543
|
+
onHostContextChange(handler) {
|
|
544
|
+
this.hostContextHandlers.add(handler);
|
|
545
|
+
return () => this.hostContextHandlers.delete(handler);
|
|
546
|
+
}
|
|
547
|
+
getViewParams() {
|
|
548
|
+
return {
|
|
549
|
+
inputs: this.toolInput ?? {},
|
|
550
|
+
data: this.toolOutput ?? {}
|
|
551
|
+
};
|
|
552
|
+
}
|
|
553
|
+
getToolInput() {
|
|
554
|
+
return this.toolInput;
|
|
555
|
+
}
|
|
556
|
+
getToolOutput() {
|
|
557
|
+
return this.toolOutput;
|
|
558
|
+
}
|
|
559
|
+
onToolInput(handler) {
|
|
560
|
+
this.toolInputHandlers.add(handler);
|
|
561
|
+
return () => this.toolInputHandlers.delete(handler);
|
|
562
|
+
}
|
|
563
|
+
onToolOutput(handler) {
|
|
564
|
+
this.toolOutputHandlers.add(handler);
|
|
565
|
+
return () => this.toolOutputHandlers.delete(handler);
|
|
566
|
+
}
|
|
567
|
+
async callTool(name, args) {
|
|
568
|
+
const handler = this.toolHandlers.get(name);
|
|
569
|
+
if (handler) {
|
|
570
|
+
return handler(args);
|
|
571
|
+
}
|
|
572
|
+
console.log(`[MockAdapter] callTool: ${name}`, args);
|
|
573
|
+
return {};
|
|
574
|
+
}
|
|
575
|
+
async sendMessage(content) {
|
|
576
|
+
console.log(`[MockAdapter] sendMessage:`, content);
|
|
577
|
+
}
|
|
578
|
+
async openLink(url) {
|
|
579
|
+
console.log(`[MockAdapter] openLink: ${url}`);
|
|
580
|
+
if (typeof window !== "undefined") {
|
|
581
|
+
window.open(url, "_blank");
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
async requestDisplayMode(mode) {
|
|
585
|
+
console.log(`[MockAdapter] requestDisplayMode: ${mode}`);
|
|
586
|
+
this.context.displayMode = mode;
|
|
587
|
+
return { mode };
|
|
588
|
+
}
|
|
589
|
+
requestClose() {
|
|
590
|
+
console.log(`[MockAdapter] requestClose`);
|
|
591
|
+
}
|
|
592
|
+
getState() {
|
|
593
|
+
return this.state;
|
|
594
|
+
}
|
|
595
|
+
setState(state) {
|
|
596
|
+
this.state = state;
|
|
597
|
+
}
|
|
598
|
+
onToolCancelled(handler) {
|
|
599
|
+
this.toolCancelledHandlers.add(handler);
|
|
600
|
+
return () => this.toolCancelledHandlers.delete(handler);
|
|
601
|
+
}
|
|
602
|
+
onTeardown(handler) {
|
|
603
|
+
this.teardownHandlers.add(handler);
|
|
604
|
+
return () => this.teardownHandlers.delete(handler);
|
|
605
|
+
}
|
|
606
|
+
log(level, data) {
|
|
607
|
+
console[level === "debug" ? "log" : level]("[MockAdapter]", data);
|
|
608
|
+
}
|
|
609
|
+
async sendSizeChanged(params) {
|
|
610
|
+
console.log(`[MockAdapter] sendSizeChanged:`, params);
|
|
611
|
+
}
|
|
612
|
+
};
|
|
613
|
+
|
|
614
|
+
// src/detection.ts
|
|
615
|
+
function detectProtocol() {
|
|
616
|
+
if (typeof window === "undefined") {
|
|
617
|
+
return "mock";
|
|
618
|
+
}
|
|
619
|
+
if ("openai" in window) {
|
|
620
|
+
return "openai";
|
|
621
|
+
}
|
|
622
|
+
const url = window.location.href;
|
|
623
|
+
const referrer = document.referrer;
|
|
624
|
+
const isChatGPTSandbox = url.includes("chatgpt") || url.includes("sandbox-proxy") || url.includes("widget-content") || referrer.includes("chatgpt") || referrer.includes("openai.com");
|
|
625
|
+
if (isChatGPTSandbox) {
|
|
626
|
+
return "openai";
|
|
627
|
+
}
|
|
628
|
+
if (window.parent !== window) {
|
|
629
|
+
return "mcp";
|
|
630
|
+
}
|
|
631
|
+
return "mock";
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
// src/client.ts
|
|
635
|
+
var PancakeClient = class _PancakeClient {
|
|
636
|
+
adapter;
|
|
637
|
+
constructor(adapter) {
|
|
638
|
+
this.adapter = adapter;
|
|
639
|
+
}
|
|
640
|
+
/**
|
|
641
|
+
* Create and connect a Pancake client.
|
|
642
|
+
*/
|
|
643
|
+
static async create(options) {
|
|
644
|
+
const protocol = options?.forceAdapter ?? detectProtocol();
|
|
645
|
+
let adapter;
|
|
646
|
+
switch (protocol) {
|
|
647
|
+
case "mcp":
|
|
648
|
+
adapter = new McpAdapter({ autoResize: options?.autoResize ?? true });
|
|
649
|
+
break;
|
|
650
|
+
case "openai":
|
|
651
|
+
adapter = new OpenAIAdapter();
|
|
652
|
+
break;
|
|
653
|
+
case "mock":
|
|
654
|
+
default: {
|
|
655
|
+
const mockOptions = {};
|
|
656
|
+
if (options?.toolInput !== void 0) mockOptions.toolInput = options.toolInput;
|
|
657
|
+
if (options?.toolOutput !== void 0) mockOptions.toolOutput = options.toolOutput;
|
|
658
|
+
if (options?.hostContext !== void 0) mockOptions.hostContext = options.hostContext;
|
|
659
|
+
adapter = new MockAdapter(mockOptions);
|
|
660
|
+
break;
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
await adapter.connect();
|
|
664
|
+
return new _PancakeClient(adapter);
|
|
665
|
+
}
|
|
666
|
+
/**
|
|
667
|
+
* Create a Pancake client with a pre-configured adapter.
|
|
668
|
+
*/
|
|
669
|
+
static fromAdapter(adapter) {
|
|
670
|
+
return new _PancakeClient(adapter);
|
|
671
|
+
}
|
|
672
|
+
/**
|
|
673
|
+
* Get the underlying protocol adapter.
|
|
674
|
+
*/
|
|
675
|
+
getAdapter() {
|
|
676
|
+
return this.adapter;
|
|
677
|
+
}
|
|
678
|
+
/**
|
|
679
|
+
* Get the current protocol.
|
|
680
|
+
*/
|
|
681
|
+
get protocol() {
|
|
682
|
+
return this.adapter.protocol;
|
|
683
|
+
}
|
|
684
|
+
/**
|
|
685
|
+
* Check if the client is connected.
|
|
686
|
+
*/
|
|
687
|
+
isConnected() {
|
|
688
|
+
return this.adapter.isConnected();
|
|
689
|
+
}
|
|
690
|
+
// ─────────────────────────────────────────────────────────────
|
|
691
|
+
// Host Context
|
|
692
|
+
// ─────────────────────────────────────────────────────────────
|
|
693
|
+
/**
|
|
694
|
+
* Get the current host context.
|
|
695
|
+
*/
|
|
696
|
+
getHostContext() {
|
|
697
|
+
return this.adapter.getHostContext();
|
|
698
|
+
}
|
|
699
|
+
/**
|
|
700
|
+
* Subscribe to host context changes.
|
|
701
|
+
*/
|
|
702
|
+
onHostContextChange(handler) {
|
|
703
|
+
return this.adapter.onHostContextChange(handler);
|
|
704
|
+
}
|
|
705
|
+
// ─────────────────────────────────────────────────────────────
|
|
706
|
+
// View Parameters
|
|
707
|
+
// ─────────────────────────────────────────────────────────────
|
|
708
|
+
/**
|
|
709
|
+
* Get the current view parameters.
|
|
710
|
+
*/
|
|
711
|
+
getViewParams() {
|
|
712
|
+
return this.adapter.getViewParams();
|
|
713
|
+
}
|
|
714
|
+
/**
|
|
715
|
+
* Get the current tool input.
|
|
716
|
+
*/
|
|
717
|
+
getToolInput() {
|
|
718
|
+
return this.adapter.getToolInput();
|
|
719
|
+
}
|
|
720
|
+
/**
|
|
721
|
+
* Get the current tool output.
|
|
722
|
+
*/
|
|
723
|
+
getToolOutput() {
|
|
724
|
+
return this.adapter.getToolOutput();
|
|
725
|
+
}
|
|
726
|
+
/**
|
|
727
|
+
* Subscribe to tool input changes.
|
|
728
|
+
*/
|
|
729
|
+
onToolInput(handler) {
|
|
730
|
+
return this.adapter.onToolInput(handler);
|
|
731
|
+
}
|
|
732
|
+
/**
|
|
733
|
+
* Subscribe to tool output changes.
|
|
734
|
+
*/
|
|
735
|
+
onToolOutput(handler) {
|
|
736
|
+
return this.adapter.onToolOutput(handler);
|
|
737
|
+
}
|
|
738
|
+
// ─────────────────────────────────────────────────────────────
|
|
739
|
+
// Tool Calls
|
|
740
|
+
// ─────────────────────────────────────────────────────────────
|
|
741
|
+
/**
|
|
742
|
+
* Call a tool on the server.
|
|
743
|
+
*/
|
|
744
|
+
async callTool(name, args = {}) {
|
|
745
|
+
return this.adapter.callTool(name, args);
|
|
746
|
+
}
|
|
747
|
+
/**
|
|
748
|
+
* Navigate to a view (calls view:name tool).
|
|
749
|
+
*/
|
|
750
|
+
async navigateToView(viewName, params = {}) {
|
|
751
|
+
await this.adapter.callTool(`view:${viewName}`, params);
|
|
752
|
+
}
|
|
753
|
+
/**
|
|
754
|
+
* Dispatch an action (calls action:name tool).
|
|
755
|
+
*/
|
|
756
|
+
async dispatch(actionName, params = {}) {
|
|
757
|
+
return this.adapter.callTool(`action:${actionName}`, params);
|
|
758
|
+
}
|
|
759
|
+
/**
|
|
760
|
+
* Get data from a data fetcher (calls data:name tool).
|
|
761
|
+
*/
|
|
762
|
+
async getData(dataName, params = {}) {
|
|
763
|
+
return this.adapter.callTool(`data:${dataName}`, params);
|
|
764
|
+
}
|
|
765
|
+
// ─────────────────────────────────────────────────────────────
|
|
766
|
+
// Communication
|
|
767
|
+
// ─────────────────────────────────────────────────────────────
|
|
768
|
+
/**
|
|
769
|
+
* Send a message to the model.
|
|
770
|
+
*/
|
|
771
|
+
async say(message) {
|
|
772
|
+
await this.adapter.sendMessage({ type: "text", text: message });
|
|
773
|
+
}
|
|
774
|
+
/**
|
|
775
|
+
* Open a link in the host.
|
|
776
|
+
*/
|
|
777
|
+
async openLink(url) {
|
|
778
|
+
await this.adapter.openLink(url);
|
|
779
|
+
}
|
|
780
|
+
/**
|
|
781
|
+
* Request a display mode change.
|
|
782
|
+
*/
|
|
783
|
+
async requestDisplayMode(mode) {
|
|
784
|
+
return this.adapter.requestDisplayMode(mode);
|
|
785
|
+
}
|
|
786
|
+
/**
|
|
787
|
+
* Request to close the UI.
|
|
788
|
+
*/
|
|
789
|
+
requestClose() {
|
|
790
|
+
this.adapter.requestClose();
|
|
791
|
+
}
|
|
792
|
+
// ─────────────────────────────────────────────────────────────
|
|
793
|
+
// State
|
|
794
|
+
// ─────────────────────────────────────────────────────────────
|
|
795
|
+
/**
|
|
796
|
+
* Get the current view state.
|
|
797
|
+
*/
|
|
798
|
+
getState() {
|
|
799
|
+
return this.adapter.getState();
|
|
800
|
+
}
|
|
801
|
+
/**
|
|
802
|
+
* Set the view state.
|
|
803
|
+
*/
|
|
804
|
+
setState(state) {
|
|
805
|
+
this.adapter.setState(state);
|
|
806
|
+
}
|
|
807
|
+
// ─────────────────────────────────────────────────────────────
|
|
808
|
+
// Events
|
|
809
|
+
// ─────────────────────────────────────────────────────────────
|
|
810
|
+
/**
|
|
811
|
+
* Subscribe to tool cancellation.
|
|
812
|
+
*/
|
|
813
|
+
onToolCancelled(handler) {
|
|
814
|
+
return this.adapter.onToolCancelled(handler);
|
|
815
|
+
}
|
|
816
|
+
/**
|
|
817
|
+
* Subscribe to teardown.
|
|
818
|
+
*/
|
|
819
|
+
onTeardown(handler) {
|
|
820
|
+
return this.adapter.onTeardown(handler);
|
|
821
|
+
}
|
|
822
|
+
// ─────────────────────────────────────────────────────────────
|
|
823
|
+
// Logging
|
|
824
|
+
// ─────────────────────────────────────────────────────────────
|
|
825
|
+
/**
|
|
826
|
+
* Log a message.
|
|
827
|
+
*/
|
|
828
|
+
log(level, data) {
|
|
829
|
+
this.adapter.log(level, data);
|
|
830
|
+
}
|
|
831
|
+
// ─────────────────────────────────────────────────────────────
|
|
832
|
+
// Size Notifications
|
|
833
|
+
// ─────────────────────────────────────────────────────────────
|
|
834
|
+
/**
|
|
835
|
+
* Notify the host of a size change.
|
|
836
|
+
*/
|
|
837
|
+
async sendSizeChanged(params) {
|
|
838
|
+
await this.adapter.sendSizeChanged(params);
|
|
839
|
+
}
|
|
840
|
+
};
|
|
841
|
+
var PancakeContext = createContext(null);
|
|
842
|
+
function usePancakeContext() {
|
|
843
|
+
const ctx = useContext(PancakeContext);
|
|
844
|
+
if (!ctx) {
|
|
845
|
+
throw new Error("usePancakeContext must be used within a PancakeProvider");
|
|
846
|
+
}
|
|
847
|
+
return ctx;
|
|
848
|
+
}
|
|
849
|
+
function usePancakeClient() {
|
|
850
|
+
const { client, isConnecting, error } = usePancakeContext();
|
|
851
|
+
if (error) {
|
|
852
|
+
throw error;
|
|
853
|
+
}
|
|
854
|
+
if (isConnecting || !client) {
|
|
855
|
+
throw new Error("Pancake client not ready. Make sure PancakeProvider has finished connecting.");
|
|
856
|
+
}
|
|
857
|
+
return client;
|
|
858
|
+
}
|
|
859
|
+
function PancakeProvider({
|
|
860
|
+
children,
|
|
861
|
+
client: providedClient,
|
|
862
|
+
forceAdapter,
|
|
863
|
+
autoResize = true,
|
|
864
|
+
hostContext,
|
|
865
|
+
fallback,
|
|
866
|
+
errorFallback: ErrorFallback
|
|
867
|
+
}) {
|
|
868
|
+
const [client, setClient] = useState(providedClient ?? null);
|
|
869
|
+
const [isConnecting, setIsConnecting] = useState(!providedClient);
|
|
870
|
+
const [error, setError] = useState(null);
|
|
871
|
+
useEffect(() => {
|
|
872
|
+
if (providedClient) {
|
|
873
|
+
setClient(providedClient);
|
|
874
|
+
setIsConnecting(false);
|
|
875
|
+
return;
|
|
876
|
+
}
|
|
877
|
+
setIsConnecting(true);
|
|
878
|
+
setError(null);
|
|
879
|
+
const options = { autoResize };
|
|
880
|
+
if (forceAdapter !== void 0) options.forceAdapter = forceAdapter;
|
|
881
|
+
if (hostContext !== void 0) options.hostContext = hostContext;
|
|
882
|
+
PancakeClient.create(options).then((newClient) => {
|
|
883
|
+
setClient(newClient);
|
|
884
|
+
setIsConnecting(false);
|
|
885
|
+
}).catch((err) => {
|
|
886
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
887
|
+
setIsConnecting(false);
|
|
888
|
+
});
|
|
889
|
+
}, [providedClient, forceAdapter, autoResize]);
|
|
890
|
+
if (error) {
|
|
891
|
+
if (ErrorFallback) {
|
|
892
|
+
return /* @__PURE__ */ jsx(ErrorFallback, { error, reset: () => setError(null) });
|
|
893
|
+
}
|
|
894
|
+
throw error;
|
|
895
|
+
}
|
|
896
|
+
if (isConnecting || !client) {
|
|
897
|
+
if (fallback) {
|
|
898
|
+
return /* @__PURE__ */ jsx(Fragment, { children: fallback });
|
|
899
|
+
}
|
|
900
|
+
return /* @__PURE__ */ jsx(Fragment, {});
|
|
901
|
+
}
|
|
902
|
+
const value = {
|
|
903
|
+
client,
|
|
904
|
+
isConnecting,
|
|
905
|
+
error
|
|
906
|
+
};
|
|
907
|
+
return /* @__PURE__ */ jsx(PancakeContext.Provider, { value, children });
|
|
908
|
+
}
|
|
909
|
+
function useViewState(defaultValue) {
|
|
910
|
+
const client = usePancakeClient();
|
|
911
|
+
const [state, setStateInternal] = useState(() => {
|
|
912
|
+
const stored = client.getState();
|
|
913
|
+
return stored ?? defaultValue;
|
|
914
|
+
});
|
|
915
|
+
const setState = useCallback(
|
|
916
|
+
(newState) => {
|
|
917
|
+
setStateInternal((prev) => {
|
|
918
|
+
const next = typeof newState === "function" ? newState(prev) : newState;
|
|
919
|
+
client.setState(next);
|
|
920
|
+
return next;
|
|
921
|
+
});
|
|
922
|
+
},
|
|
923
|
+
[client]
|
|
924
|
+
);
|
|
925
|
+
return [state, setState];
|
|
926
|
+
}
|
|
927
|
+
function useHost() {
|
|
928
|
+
const { client } = usePancakeContext();
|
|
929
|
+
const [context, setContext] = useState(
|
|
930
|
+
() => client?.getHostContext() ?? DEFAULT_HOST_CONTEXT
|
|
931
|
+
);
|
|
932
|
+
useEffect(() => {
|
|
933
|
+
if (!client) return;
|
|
934
|
+
setContext(client.getHostContext());
|
|
935
|
+
return client.onHostContextChange(setContext);
|
|
936
|
+
}, [client]);
|
|
937
|
+
return context;
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
// src/react/hooks/useTheme.ts
|
|
941
|
+
function useTheme() {
|
|
942
|
+
const host = useHost();
|
|
943
|
+
return host.theme;
|
|
944
|
+
}
|
|
945
|
+
function useDisplayMode() {
|
|
946
|
+
const client = usePancakeClient();
|
|
947
|
+
const host = useHost();
|
|
948
|
+
const requestMode = useCallback(
|
|
949
|
+
async (mode) => {
|
|
950
|
+
await client.requestDisplayMode(mode);
|
|
951
|
+
},
|
|
952
|
+
[client]
|
|
953
|
+
);
|
|
954
|
+
return {
|
|
955
|
+
mode: host.displayMode,
|
|
956
|
+
availableModes: host.availableDisplayModes,
|
|
957
|
+
requestMode
|
|
958
|
+
};
|
|
959
|
+
}
|
|
960
|
+
function useNavigation() {
|
|
961
|
+
const client = usePancakeClient();
|
|
962
|
+
const navigate = useCallback(
|
|
963
|
+
async (viewName, params) => {
|
|
964
|
+
await client.navigateToView(viewName, params ?? {});
|
|
965
|
+
},
|
|
966
|
+
[client]
|
|
967
|
+
);
|
|
968
|
+
const say = useCallback(
|
|
969
|
+
async (message) => {
|
|
970
|
+
await client.say(message);
|
|
971
|
+
},
|
|
972
|
+
[client]
|
|
973
|
+
);
|
|
974
|
+
return { navigate, say };
|
|
975
|
+
}
|
|
976
|
+
function useActionInput() {
|
|
977
|
+
const { client } = usePancakeContext();
|
|
978
|
+
const [input, setInput] = useState(() => {
|
|
979
|
+
return client?.getToolInput();
|
|
980
|
+
});
|
|
981
|
+
useEffect(() => {
|
|
982
|
+
if (!client) return;
|
|
983
|
+
setInput(client.getToolInput());
|
|
984
|
+
return client.onToolInput((newInput) => {
|
|
985
|
+
setInput(newInput);
|
|
986
|
+
});
|
|
987
|
+
}, [client]);
|
|
988
|
+
return input;
|
|
989
|
+
}
|
|
990
|
+
function useViewParams() {
|
|
991
|
+
const { client } = usePancakeContext();
|
|
992
|
+
const [params, setParams] = useState(() => {
|
|
993
|
+
if (!client) {
|
|
994
|
+
return { inputs: {}, data: {} };
|
|
995
|
+
}
|
|
996
|
+
const viewParams = client.getViewParams();
|
|
997
|
+
return {
|
|
998
|
+
inputs: viewParams.inputs,
|
|
999
|
+
data: viewParams.data
|
|
1000
|
+
};
|
|
1001
|
+
});
|
|
1002
|
+
useEffect(() => {
|
|
1003
|
+
if (!client) return;
|
|
1004
|
+
const viewParams = client.getViewParams();
|
|
1005
|
+
setParams({
|
|
1006
|
+
inputs: viewParams.inputs,
|
|
1007
|
+
data: viewParams.data
|
|
1008
|
+
});
|
|
1009
|
+
const unsubInput = client.onToolInput(() => {
|
|
1010
|
+
const updated = client.getViewParams();
|
|
1011
|
+
setParams({
|
|
1012
|
+
inputs: updated.inputs,
|
|
1013
|
+
data: updated.data
|
|
1014
|
+
});
|
|
1015
|
+
});
|
|
1016
|
+
const unsubOutput = client.onToolOutput(() => {
|
|
1017
|
+
const updated = client.getViewParams();
|
|
1018
|
+
setParams({
|
|
1019
|
+
inputs: updated.inputs,
|
|
1020
|
+
data: updated.data
|
|
1021
|
+
});
|
|
1022
|
+
});
|
|
1023
|
+
return () => {
|
|
1024
|
+
unsubInput();
|
|
1025
|
+
unsubOutput();
|
|
1026
|
+
};
|
|
1027
|
+
}, [client]);
|
|
1028
|
+
return params;
|
|
1029
|
+
}
|
|
1030
|
+
function useAction() {
|
|
1031
|
+
const client = usePancakeClient();
|
|
1032
|
+
const dispatch = useCallback(
|
|
1033
|
+
async (actionName, params) => {
|
|
1034
|
+
return client.dispatch(actionName, params ?? {});
|
|
1035
|
+
},
|
|
1036
|
+
[client]
|
|
1037
|
+
);
|
|
1038
|
+
return { dispatch };
|
|
1039
|
+
}
|
|
1040
|
+
function useData() {
|
|
1041
|
+
const client = usePancakeClient();
|
|
1042
|
+
const getData = useCallback(
|
|
1043
|
+
async (dataName, params) => {
|
|
1044
|
+
return client.getData(dataName, params ?? {});
|
|
1045
|
+
},
|
|
1046
|
+
[client]
|
|
1047
|
+
);
|
|
1048
|
+
return { getData };
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
export { PancakeContext, PancakeProvider, useAction, useActionInput, useData, useDisplayMode, useHost, useNavigation, usePancakeClient, usePancakeContext, useTheme, useViewParams, useViewState };
|
|
1052
|
+
//# sourceMappingURL=index.js.map
|
|
1053
|
+
//# sourceMappingURL=index.js.map
|