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