@pancake-apps/web 0.0.0-snapshot-20260125200133
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 +333 -0
- package/dist/adaptor-interface-BYbH9PpT.d.ts +370 -0
- package/dist/apps-sdk/index.d.ts +1 -0
- package/dist/apps-sdk/index.js +4 -0
- package/dist/apps-sdk/index.js.map +1 -0
- package/dist/chunk-5NYJ2IVD.js +406 -0
- package/dist/chunk-5NYJ2IVD.js.map +1 -0
- package/dist/chunk-7HJ5PKKT.js +146 -0
- package/dist/chunk-7HJ5PKKT.js.map +1 -0
- package/dist/chunk-PZ5AY32C.js +9 -0
- package/dist/chunk-PZ5AY32C.js.map +1 -0
- package/dist/chunk-TLBYYZHP.js +715 -0
- package/dist/chunk-TLBYYZHP.js.map +1 -0
- package/dist/chunk-YGGRUIUG.js +977 -0
- package/dist/chunk-YGGRUIUG.js.map +1 -0
- package/dist/chunk-ZYBPDIEG.js +674 -0
- package/dist/chunk-ZYBPDIEG.js.map +1 -0
- package/dist/core/index.d.ts +169 -0
- package/dist/core/index.js +195 -0
- package/dist/core/index.js.map +1 -0
- package/dist/index-BBfZZJWn.d.ts +671 -0
- package/dist/index-CpXDfXKD.d.ts +395 -0
- package/dist/index-DtukOUjY.d.ts +738 -0
- package/dist/index.d.ts +741 -0
- package/dist/index.js +685 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-apps/index.d.ts +2 -0
- package/dist/mcp-apps/index.js +4 -0
- package/dist/mcp-apps/index.js.map +1 -0
- package/dist/notify-size-changed-Ck2BGfUk.d.ts +270 -0
- package/dist/react/index.d.ts +3 -0
- package/dist/react/index.js +7 -0
- package/dist/react/index.js.map +1 -0
- package/dist/types-B_O3kZYh.d.ts +253 -0
- package/package.json +90 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
|
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
import { __export } from './chunk-PZ5AY32C.js';
|
|
2
|
+
import { useSyncExternalStore, useCallback } from 'react';
|
|
3
|
+
|
|
4
|
+
// src/apps-sdk/index.ts
|
|
5
|
+
var apps_sdk_exports = {};
|
|
6
|
+
__export(apps_sdk_exports, {
|
|
7
|
+
AppsSdkBridge: () => AppsSdkBridge,
|
|
8
|
+
AppsSdkStore: () => AppsSdkStore,
|
|
9
|
+
SET_GLOBALS_EVENT_TYPE: () => SET_GLOBALS_EVENT_TYPE,
|
|
10
|
+
callTool: () => callTool,
|
|
11
|
+
createOpenAiGlobalHook: () => createOpenAiGlobalHook,
|
|
12
|
+
getBridge: () => getBridge,
|
|
13
|
+
getFileDownloadUrl: () => getFileDownloadUrl,
|
|
14
|
+
getStore: () => getStore,
|
|
15
|
+
isAppsSdkAvailable: () => isAppsSdkAvailable,
|
|
16
|
+
notifyIntrinsicHeight: () => notifyIntrinsicHeight,
|
|
17
|
+
openExternal: () => openExternal,
|
|
18
|
+
requestClose: () => requestClose,
|
|
19
|
+
requestDisplayMode: () => requestDisplayMode,
|
|
20
|
+
requestModal: () => requestModal,
|
|
21
|
+
sendFollowUpMessage: () => sendFollowUpMessage,
|
|
22
|
+
setOpenInAppUrl: () => setOpenInAppUrl,
|
|
23
|
+
uploadFile: () => uploadFile,
|
|
24
|
+
useDisplayMode: () => useDisplayMode,
|
|
25
|
+
useLocale: () => useLocale,
|
|
26
|
+
useMaxHeight: () => useMaxHeight,
|
|
27
|
+
useOpenAiGlobal: () => useOpenAiGlobal,
|
|
28
|
+
useSafeArea: () => useSafeArea,
|
|
29
|
+
useTheme: () => useTheme,
|
|
30
|
+
useToolInput: () => useToolInput,
|
|
31
|
+
useToolOutput: () => useToolOutput,
|
|
32
|
+
useToolResponseMetadata: () => useToolResponseMetadata,
|
|
33
|
+
useUserAgent: () => useUserAgent,
|
|
34
|
+
useView: () => useView,
|
|
35
|
+
useWidgetState: () => useWidgetState
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// src/apps-sdk/types.ts
|
|
39
|
+
var SET_GLOBALS_EVENT_TYPE = "openai:set_globals";
|
|
40
|
+
|
|
41
|
+
// src/apps-sdk/bridge.ts
|
|
42
|
+
var AppsSdkBridge = class _AppsSdkBridge {
|
|
43
|
+
static instance = null;
|
|
44
|
+
/**
|
|
45
|
+
* Get the singleton bridge instance
|
|
46
|
+
* @throws Error if window.openai is not available
|
|
47
|
+
*/
|
|
48
|
+
static getInstance() {
|
|
49
|
+
if (!_AppsSdkBridge.instance) {
|
|
50
|
+
_AppsSdkBridge.instance = new _AppsSdkBridge();
|
|
51
|
+
}
|
|
52
|
+
return _AppsSdkBridge.instance;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Check if the Apps SDK runtime is available
|
|
56
|
+
*/
|
|
57
|
+
static isAvailable() {
|
|
58
|
+
return typeof window !== "undefined" && window.openai != null;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Reset the singleton (for testing)
|
|
62
|
+
*/
|
|
63
|
+
static reset() {
|
|
64
|
+
_AppsSdkBridge.instance = null;
|
|
65
|
+
}
|
|
66
|
+
constructor() {
|
|
67
|
+
if (!_AppsSdkBridge.isAvailable()) {
|
|
68
|
+
throw new Error(
|
|
69
|
+
"window.openai is not available. Make sure your widget is running inside the ChatGPT Apps environment."
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Get the raw window.openai runtime
|
|
75
|
+
*/
|
|
76
|
+
get runtime() {
|
|
77
|
+
if (!window.openai) {
|
|
78
|
+
throw new Error("window.openai became unavailable");
|
|
79
|
+
}
|
|
80
|
+
return window.openai;
|
|
81
|
+
}
|
|
82
|
+
// ============================================
|
|
83
|
+
// Tool Operations
|
|
84
|
+
// ============================================
|
|
85
|
+
/**
|
|
86
|
+
* Call an MCP tool
|
|
87
|
+
*/
|
|
88
|
+
async callTool(name, args) {
|
|
89
|
+
return this.runtime.callTool(name, args);
|
|
90
|
+
}
|
|
91
|
+
// ============================================
|
|
92
|
+
// Conversation Operations
|
|
93
|
+
// ============================================
|
|
94
|
+
/**
|
|
95
|
+
* Send a follow-up message to the conversation
|
|
96
|
+
*/
|
|
97
|
+
sendFollowUpMessage(prompt) {
|
|
98
|
+
this.runtime.sendFollowUpMessage({ prompt });
|
|
99
|
+
}
|
|
100
|
+
// ============================================
|
|
101
|
+
// File Operations
|
|
102
|
+
// ============================================
|
|
103
|
+
/**
|
|
104
|
+
* Upload a file and get its ID
|
|
105
|
+
*/
|
|
106
|
+
async uploadFile(file) {
|
|
107
|
+
return this.runtime.uploadFile(file);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Get a temporary download URL for a file
|
|
111
|
+
*/
|
|
112
|
+
async getFileDownloadUrl(fileId) {
|
|
113
|
+
return this.runtime.getFileDownloadUrl({ fileId });
|
|
114
|
+
}
|
|
115
|
+
// ============================================
|
|
116
|
+
// Display Operations
|
|
117
|
+
// ============================================
|
|
118
|
+
/**
|
|
119
|
+
* Request a change in display mode
|
|
120
|
+
*/
|
|
121
|
+
requestDisplayMode(mode) {
|
|
122
|
+
this.runtime.requestDisplayMode(mode);
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Request to show a modal dialog
|
|
126
|
+
*/
|
|
127
|
+
async requestModal(options) {
|
|
128
|
+
return this.runtime.requestModal(options);
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Notify the host of the widget's intrinsic height
|
|
132
|
+
*/
|
|
133
|
+
notifyIntrinsicHeight(height) {
|
|
134
|
+
this.runtime.notifyIntrinsicHeight({ height });
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Request to close/hide the widget
|
|
138
|
+
*/
|
|
139
|
+
requestClose() {
|
|
140
|
+
this.runtime.requestClose();
|
|
141
|
+
}
|
|
142
|
+
// ============================================
|
|
143
|
+
// Navigation Operations
|
|
144
|
+
// ============================================
|
|
145
|
+
/**
|
|
146
|
+
* Open an external URL in the user's browser
|
|
147
|
+
*/
|
|
148
|
+
openExternal(href) {
|
|
149
|
+
this.runtime.openExternal({ href });
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Set the "Open in App" URL for fullscreen mode
|
|
153
|
+
*/
|
|
154
|
+
setOpenInAppUrl(href) {
|
|
155
|
+
this.runtime.setOpenInAppUrl({ href });
|
|
156
|
+
}
|
|
157
|
+
// ============================================
|
|
158
|
+
// State Operations
|
|
159
|
+
// ============================================
|
|
160
|
+
/**
|
|
161
|
+
* Set the widget state (persisted by host)
|
|
162
|
+
*/
|
|
163
|
+
setWidgetState(state) {
|
|
164
|
+
this.runtime.setWidgetState(state);
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
function getBridge() {
|
|
168
|
+
return AppsSdkBridge.getInstance();
|
|
169
|
+
}
|
|
170
|
+
function isAppsSdkAvailable() {
|
|
171
|
+
return AppsSdkBridge.isAvailable();
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// src/apps-sdk/store.ts
|
|
175
|
+
var AppsSdkStore = class _AppsSdkStore {
|
|
176
|
+
static instance = null;
|
|
177
|
+
subscribers = /* @__PURE__ */ new Map();
|
|
178
|
+
globalSubscribers = /* @__PURE__ */ new Set();
|
|
179
|
+
static getInstance() {
|
|
180
|
+
if (!_AppsSdkStore.instance) {
|
|
181
|
+
_AppsSdkStore.instance = new _AppsSdkStore();
|
|
182
|
+
}
|
|
183
|
+
return _AppsSdkStore.instance;
|
|
184
|
+
}
|
|
185
|
+
static reset() {
|
|
186
|
+
if (_AppsSdkStore.instance) {
|
|
187
|
+
_AppsSdkStore.instance.cleanup();
|
|
188
|
+
}
|
|
189
|
+
_AppsSdkStore.instance = null;
|
|
190
|
+
}
|
|
191
|
+
constructor() {
|
|
192
|
+
this.setupEventListener();
|
|
193
|
+
}
|
|
194
|
+
setupEventListener() {
|
|
195
|
+
if (typeof window !== "undefined") {
|
|
196
|
+
window.addEventListener(SET_GLOBALS_EVENT_TYPE, this.handleSetGlobals);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
cleanup() {
|
|
200
|
+
if (typeof window !== "undefined") {
|
|
201
|
+
window.removeEventListener(SET_GLOBALS_EVENT_TYPE, this.handleSetGlobals);
|
|
202
|
+
}
|
|
203
|
+
this.subscribers.clear();
|
|
204
|
+
this.globalSubscribers.clear();
|
|
205
|
+
}
|
|
206
|
+
handleSetGlobals = (event) => {
|
|
207
|
+
const changedKeys = Object.keys(event.detail.changes);
|
|
208
|
+
for (const key of changedKeys) {
|
|
209
|
+
const keySubscribers = this.subscribers.get(key);
|
|
210
|
+
if (keySubscribers) {
|
|
211
|
+
keySubscribers.forEach((cb) => cb());
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
if (changedKeys.length > 0) {
|
|
215
|
+
this.globalSubscribers.forEach((cb) => cb());
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
/**
|
|
219
|
+
* Subscribe to changes for specific keys
|
|
220
|
+
*/
|
|
221
|
+
subscribe(keys, callback) {
|
|
222
|
+
const keyArray = Array.isArray(keys) ? keys : [keys];
|
|
223
|
+
for (const key of keyArray) {
|
|
224
|
+
if (!this.subscribers.has(key)) {
|
|
225
|
+
this.subscribers.set(key, /* @__PURE__ */ new Set());
|
|
226
|
+
}
|
|
227
|
+
this.subscribers.get(key).add(callback);
|
|
228
|
+
}
|
|
229
|
+
return () => {
|
|
230
|
+
for (const key of keyArray) {
|
|
231
|
+
this.subscribers.get(key)?.delete(callback);
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Subscribe to any change
|
|
237
|
+
*/
|
|
238
|
+
subscribeAll(callback) {
|
|
239
|
+
this.globalSubscribers.add(callback);
|
|
240
|
+
return () => {
|
|
241
|
+
this.globalSubscribers.delete(callback);
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Get current value of a global property
|
|
246
|
+
*/
|
|
247
|
+
getSnapshot(key) {
|
|
248
|
+
return window.openai?.[key];
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Get server snapshot (for SSR, returns undefined)
|
|
252
|
+
*/
|
|
253
|
+
getServerSnapshot(_key) {
|
|
254
|
+
return void 0;
|
|
255
|
+
}
|
|
256
|
+
};
|
|
257
|
+
function getStore() {
|
|
258
|
+
return AppsSdkStore.getInstance();
|
|
259
|
+
}
|
|
260
|
+
function createOpenAiGlobalHook(key) {
|
|
261
|
+
return function useOpenAiGlobal2() {
|
|
262
|
+
const store = getStore();
|
|
263
|
+
return useSyncExternalStore(
|
|
264
|
+
(callback) => store.subscribe(key, callback),
|
|
265
|
+
() => store.getSnapshot(key),
|
|
266
|
+
() => store.getServerSnapshot(key)
|
|
267
|
+
);
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
function useOpenAiGlobal(key) {
|
|
271
|
+
const store = getStore();
|
|
272
|
+
return useSyncExternalStore(
|
|
273
|
+
(callback) => store.subscribe(key, callback),
|
|
274
|
+
() => store.getSnapshot(key),
|
|
275
|
+
() => store.getServerSnapshot(key)
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// src/apps-sdk/hooks/use-theme.ts
|
|
280
|
+
function useTheme() {
|
|
281
|
+
return useOpenAiGlobal("theme") ?? "light";
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// src/apps-sdk/hooks/use-locale.ts
|
|
285
|
+
function useLocale() {
|
|
286
|
+
return useOpenAiGlobal("locale") ?? "en-US";
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// src/apps-sdk/hooks/use-display-mode.ts
|
|
290
|
+
function useDisplayMode() {
|
|
291
|
+
return useOpenAiGlobal("displayMode") ?? "inline";
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// src/apps-sdk/hooks/use-max-height.ts
|
|
295
|
+
function useMaxHeight() {
|
|
296
|
+
return useOpenAiGlobal("maxHeight") ?? 400;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// src/apps-sdk/hooks/use-safe-area.ts
|
|
300
|
+
var DEFAULT_SAFE_AREA = {
|
|
301
|
+
top: 0,
|
|
302
|
+
right: 0,
|
|
303
|
+
bottom: 0,
|
|
304
|
+
left: 0
|
|
305
|
+
};
|
|
306
|
+
function useSafeArea() {
|
|
307
|
+
return useOpenAiGlobal("safeArea") ?? DEFAULT_SAFE_AREA;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// src/apps-sdk/hooks/use-view.ts
|
|
311
|
+
function useView() {
|
|
312
|
+
return useOpenAiGlobal("view");
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// src/apps-sdk/hooks/use-user-agent.ts
|
|
316
|
+
function useUserAgent() {
|
|
317
|
+
return useOpenAiGlobal("userAgent");
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// src/apps-sdk/hooks/use-tool-input.ts
|
|
321
|
+
function useToolInput() {
|
|
322
|
+
return useOpenAiGlobal("toolInput");
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// src/apps-sdk/hooks/use-tool-output.ts
|
|
326
|
+
function useToolOutput() {
|
|
327
|
+
return useOpenAiGlobal("toolOutput");
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// src/apps-sdk/hooks/use-tool-response-metadata.ts
|
|
331
|
+
function useToolResponseMetadata() {
|
|
332
|
+
return useOpenAiGlobal("toolResponseMetadata");
|
|
333
|
+
}
|
|
334
|
+
function useWidgetState(defaultState) {
|
|
335
|
+
const persistedState = useOpenAiGlobal("widgetState");
|
|
336
|
+
const setState = useCallback((newState) => {
|
|
337
|
+
const bridge = getBridge();
|
|
338
|
+
bridge.setWidgetState(newState);
|
|
339
|
+
}, []);
|
|
340
|
+
const resolvedState = persistedState ?? defaultState;
|
|
341
|
+
return [resolvedState, setState];
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// src/apps-sdk/actions/call-tool.ts
|
|
345
|
+
async function callTool(name, args) {
|
|
346
|
+
const bridge = getBridge();
|
|
347
|
+
return bridge.callTool(name, args);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// src/apps-sdk/actions/send-follow-up-message.ts
|
|
351
|
+
function sendFollowUpMessage(prompt) {
|
|
352
|
+
const bridge = getBridge();
|
|
353
|
+
bridge.sendFollowUpMessage(prompt);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// src/apps-sdk/actions/upload-file.ts
|
|
357
|
+
async function uploadFile(file) {
|
|
358
|
+
const bridge = getBridge();
|
|
359
|
+
return bridge.uploadFile(file);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// src/apps-sdk/actions/get-file-download-url.ts
|
|
363
|
+
async function getFileDownloadUrl(fileId) {
|
|
364
|
+
const bridge = getBridge();
|
|
365
|
+
return bridge.getFileDownloadUrl(fileId);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// src/apps-sdk/actions/request-display-mode.ts
|
|
369
|
+
function requestDisplayMode(mode) {
|
|
370
|
+
const bridge = getBridge();
|
|
371
|
+
bridge.requestDisplayMode(mode);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// src/apps-sdk/actions/request-modal.ts
|
|
375
|
+
async function requestModal(options) {
|
|
376
|
+
const bridge = getBridge();
|
|
377
|
+
return bridge.requestModal(options);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// src/apps-sdk/actions/notify-intrinsic-height.ts
|
|
381
|
+
function notifyIntrinsicHeight(height) {
|
|
382
|
+
const bridge = getBridge();
|
|
383
|
+
bridge.notifyIntrinsicHeight(height);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// src/apps-sdk/actions/request-close.ts
|
|
387
|
+
function requestClose() {
|
|
388
|
+
const bridge = getBridge();
|
|
389
|
+
bridge.requestClose();
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// src/apps-sdk/actions/open-external.ts
|
|
393
|
+
function openExternal(href) {
|
|
394
|
+
const bridge = getBridge();
|
|
395
|
+
bridge.openExternal(href);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// src/apps-sdk/actions/set-open-in-app-url.ts
|
|
399
|
+
function setOpenInAppUrl(href) {
|
|
400
|
+
const bridge = getBridge();
|
|
401
|
+
bridge.setOpenInAppUrl(href);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
export { AppsSdkBridge, AppsSdkStore, SET_GLOBALS_EVENT_TYPE, apps_sdk_exports, callTool, createOpenAiGlobalHook, getBridge, getFileDownloadUrl, getStore, isAppsSdkAvailable, notifyIntrinsicHeight, openExternal, requestClose, requestDisplayMode, requestModal, sendFollowUpMessage, setOpenInAppUrl, uploadFile, useDisplayMode, useLocale, useMaxHeight, useOpenAiGlobal, useSafeArea, useTheme, useToolInput, useToolOutput, useToolResponseMetadata, useUserAgent, useView, useWidgetState };
|
|
405
|
+
//# sourceMappingURL=chunk-5NYJ2IVD.js.map
|
|
406
|
+
//# sourceMappingURL=chunk-5NYJ2IVD.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/apps-sdk/index.ts","../src/apps-sdk/types.ts","../src/apps-sdk/bridge.ts","../src/apps-sdk/store.ts","../src/apps-sdk/hooks/use-openai-global.ts","../src/apps-sdk/hooks/use-theme.ts","../src/apps-sdk/hooks/use-locale.ts","../src/apps-sdk/hooks/use-display-mode.ts","../src/apps-sdk/hooks/use-max-height.ts","../src/apps-sdk/hooks/use-safe-area.ts","../src/apps-sdk/hooks/use-view.ts","../src/apps-sdk/hooks/use-user-agent.ts","../src/apps-sdk/hooks/use-tool-input.ts","../src/apps-sdk/hooks/use-tool-output.ts","../src/apps-sdk/hooks/use-tool-response-metadata.ts","../src/apps-sdk/hooks/use-widget-state.ts","../src/apps-sdk/actions/call-tool.ts","../src/apps-sdk/actions/send-follow-up-message.ts","../src/apps-sdk/actions/upload-file.ts","../src/apps-sdk/actions/get-file-download-url.ts","../src/apps-sdk/actions/request-display-mode.ts","../src/apps-sdk/actions/request-modal.ts","../src/apps-sdk/actions/notify-intrinsic-height.ts","../src/apps-sdk/actions/request-close.ts","../src/apps-sdk/actions/open-external.ts","../src/apps-sdk/actions/set-open-in-app-url.ts"],"names":["useOpenAiGlobal"],"mappings":"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","file":"chunk-5NYJ2IVD.js","sourcesContent":["/**\n * @pancake-apps/web/apps-sdk\n *\n * Complete SDK for building widgets that run inside ChatGPT.\n * Wraps the window.openai runtime with React hooks and typed actions.\n */\n\n// Types\nexport type {\n Theme,\n DisplayMode,\n SafeAreaInsets,\n ContentBlock,\n CallToolResult,\n OpenAiGlobals,\n OpenAiMethods,\n OpenAiRuntime,\n SetGlobalsEventDetail,\n SetGlobalsEvent,\n ModalOptions,\n} from './types';\n\nexport { SET_GLOBALS_EVENT_TYPE } from './types';\n\n// Bridge\nexport { AppsSdkBridge, getBridge, isAppsSdkAvailable } from './bridge';\n\n// Store\nexport { AppsSdkStore, getStore } from './store';\n\n// Hooks\nexport {\n useOpenAiGlobal,\n createOpenAiGlobalHook,\n useTheme,\n useLocale,\n useDisplayMode,\n useMaxHeight,\n useSafeArea,\n useView,\n useUserAgent,\n useToolInput,\n useToolOutput,\n useToolResponseMetadata,\n useWidgetState,\n} from './hooks';\n\n// Actions\nexport {\n callTool,\n sendFollowUpMessage,\n uploadFile,\n getFileDownloadUrl,\n requestDisplayMode,\n requestModal,\n notifyIntrinsicHeight,\n requestClose,\n openExternal,\n setOpenInAppUrl,\n} from './actions';\n","/**\n * ChatGPT Apps SDK Type Definitions\n *\n * These types match the window.openai runtime interface as specified\n * in the ChatGPT Apps SDK documentation.\n */\n\n// ============================================\n// Core Types\n// ============================================\n\nexport type Theme = 'light' | 'dark';\n\nexport type DisplayMode = 'inline' | 'pip' | 'fullscreen';\n\nexport interface SafeAreaInsets {\n top: number;\n right: number;\n bottom: number;\n left: number;\n}\n\n// ============================================\n// Tool Types\n// ============================================\n\nexport interface ContentBlock {\n type: string;\n text?: string;\n [key: string]: unknown;\n}\n\nexport interface CallToolResult<TOutput = unknown> {\n content: ContentBlock[];\n structuredContent?: TOutput;\n isError?: boolean;\n _meta?: Record<string, unknown>;\n}\n\n// ============================================\n// window.openai Globals\n// ============================================\n\n/**\n * Read-only properties available on window.openai\n */\nexport interface OpenAiGlobals {\n // Context properties\n theme: Theme;\n locale: string;\n displayMode: DisplayMode;\n maxHeight: number;\n safeArea: SafeAreaInsets;\n view: string;\n userAgent: string;\n\n // Data properties\n toolInput: Record<string, unknown> | undefined;\n toolOutput: unknown | undefined;\n toolResponseMetadata: Record<string, unknown> | undefined;\n\n // State\n widgetState: unknown | undefined;\n}\n\n/**\n * Methods available on window.openai\n */\nexport interface OpenAiMethods {\n callTool(name: string, args?: Record<string, unknown>): Promise<CallToolResult>;\n\n sendFollowUpMessage(options: { prompt: string }): void;\n\n uploadFile(file: File): Promise<{ fileId: string }>;\n\n getFileDownloadUrl(options: { fileId: string }): Promise<{ url: string }>;\n\n requestDisplayMode(mode: DisplayMode): void;\n\n requestModal(options: ModalOptions): Promise<void>;\n\n notifyIntrinsicHeight(options: { height: number }): void;\n\n requestClose(): void;\n\n openExternal(options: { href: string }): void;\n\n setOpenInAppUrl(options: { href: string }): void;\n\n setWidgetState(state: unknown): void;\n}\n\n/**\n * Complete window.openai interface\n */\nexport interface OpenAiRuntime extends OpenAiGlobals, OpenAiMethods {}\n\n// ============================================\n// Event Types\n// ============================================\n\nexport const SET_GLOBALS_EVENT_TYPE = 'openai:set_globals' as const;\n\nexport interface SetGlobalsEventDetail {\n globals: OpenAiGlobals;\n changes: Partial<OpenAiGlobals>;\n}\n\nexport interface SetGlobalsEvent extends CustomEvent<SetGlobalsEventDetail> {\n type: typeof SET_GLOBALS_EVENT_TYPE;\n}\n\n// ============================================\n// Modal Types\n// ============================================\n\nexport interface ModalOptions {\n // Modal configuration - extend as needed based on spec\n [key: string]: unknown;\n}\n\n// ============================================\n// Global Declaration\n// ============================================\n\ndeclare global {\n interface Window {\n openai?: OpenAiRuntime;\n }\n\n interface WindowEventMap {\n [SET_GLOBALS_EVENT_TYPE]: SetGlobalsEvent;\n }\n}\n","/**\n * AppsSdkBridge\n *\n * Singleton bridge that wraps window.openai, providing:\n * - Runtime availability checking\n * - Method wrappers with proper typing\n * - Error handling for missing runtime\n */\n\nimport type { OpenAiRuntime, CallToolResult, DisplayMode, ModalOptions } from './types';\n\nexport class AppsSdkBridge {\n private static instance: AppsSdkBridge | null = null;\n\n /**\n * Get the singleton bridge instance\n * @throws Error if window.openai is not available\n */\n static getInstance(): AppsSdkBridge {\n if (!AppsSdkBridge.instance) {\n AppsSdkBridge.instance = new AppsSdkBridge();\n }\n return AppsSdkBridge.instance;\n }\n\n /**\n * Check if the Apps SDK runtime is available\n */\n static isAvailable(): boolean {\n return typeof window !== 'undefined' && window.openai != null;\n }\n\n /**\n * Reset the singleton (for testing)\n */\n static reset(): void {\n AppsSdkBridge.instance = null;\n }\n\n private constructor() {\n if (!AppsSdkBridge.isAvailable()) {\n throw new Error(\n 'window.openai is not available. ' +\n 'Make sure your widget is running inside the ChatGPT Apps environment.'\n );\n }\n }\n\n /**\n * Get the raw window.openai runtime\n */\n private get runtime(): OpenAiRuntime {\n if (!window.openai) {\n throw new Error('window.openai became unavailable');\n }\n return window.openai;\n }\n\n // ============================================\n // Tool Operations\n // ============================================\n\n /**\n * Call an MCP tool\n */\n async callTool<TInput = Record<string, unknown>, TOutput = unknown>(\n name: string,\n args?: TInput\n ): Promise<CallToolResult<TOutput>> {\n return this.runtime.callTool(name, args as Record<string, unknown>) as Promise<\n CallToolResult<TOutput>\n >;\n }\n\n // ============================================\n // Conversation Operations\n // ============================================\n\n /**\n * Send a follow-up message to the conversation\n */\n sendFollowUpMessage(prompt: string): void {\n this.runtime.sendFollowUpMessage({ prompt });\n }\n\n // ============================================\n // File Operations\n // ============================================\n\n /**\n * Upload a file and get its ID\n */\n async uploadFile(file: File): Promise<{ fileId: string }> {\n return this.runtime.uploadFile(file);\n }\n\n /**\n * Get a temporary download URL for a file\n */\n async getFileDownloadUrl(fileId: string): Promise<{ url: string }> {\n return this.runtime.getFileDownloadUrl({ fileId });\n }\n\n // ============================================\n // Display Operations\n // ============================================\n\n /**\n * Request a change in display mode\n */\n requestDisplayMode(mode: DisplayMode): void {\n this.runtime.requestDisplayMode(mode);\n }\n\n /**\n * Request to show a modal dialog\n */\n async requestModal(options: ModalOptions): Promise<void> {\n return this.runtime.requestModal(options);\n }\n\n /**\n * Notify the host of the widget's intrinsic height\n */\n notifyIntrinsicHeight(height: number): void {\n this.runtime.notifyIntrinsicHeight({ height });\n }\n\n /**\n * Request to close/hide the widget\n */\n requestClose(): void {\n this.runtime.requestClose();\n }\n\n // ============================================\n // Navigation Operations\n // ============================================\n\n /**\n * Open an external URL in the user's browser\n */\n openExternal(href: string): void {\n this.runtime.openExternal({ href });\n }\n\n /**\n * Set the \"Open in App\" URL for fullscreen mode\n */\n setOpenInAppUrl(href: string): void {\n this.runtime.setOpenInAppUrl({ href });\n }\n\n // ============================================\n // State Operations\n // ============================================\n\n /**\n * Set the widget state (persisted by host)\n */\n setWidgetState<T>(state: T): void {\n this.runtime.setWidgetState(state);\n }\n}\n\n/**\n * Get the bridge instance (convenience function)\n */\nexport function getBridge(): AppsSdkBridge {\n return AppsSdkBridge.getInstance();\n}\n\n/**\n * Check if Apps SDK is available (convenience function)\n */\nexport function isAppsSdkAvailable(): boolean {\n return AppsSdkBridge.isAvailable();\n}\n","/**\n * AppsSdkStore\n *\n * External store implementation for React 18's useSyncExternalStore.\n * Listens to openai:set_globals events for reactive updates.\n */\n\nimport { SET_GLOBALS_EVENT_TYPE, type OpenAiGlobals, type SetGlobalsEvent } from './types';\n\ntype Subscriber = () => void;\ntype Unsubscribe = () => void;\n\nclass AppsSdkStore {\n private static instance: AppsSdkStore | null = null;\n private subscribers = new Map<keyof OpenAiGlobals, Set<Subscriber>>();\n private globalSubscribers = new Set<Subscriber>();\n\n static getInstance(): AppsSdkStore {\n if (!AppsSdkStore.instance) {\n AppsSdkStore.instance = new AppsSdkStore();\n }\n return AppsSdkStore.instance;\n }\n\n static reset(): void {\n if (AppsSdkStore.instance) {\n AppsSdkStore.instance.cleanup();\n }\n AppsSdkStore.instance = null;\n }\n\n private constructor() {\n this.setupEventListener();\n }\n\n private setupEventListener(): void {\n if (typeof window !== 'undefined') {\n window.addEventListener(SET_GLOBALS_EVENT_TYPE, this.handleSetGlobals as EventListener);\n }\n }\n\n private cleanup(): void {\n if (typeof window !== 'undefined') {\n window.removeEventListener(SET_GLOBALS_EVENT_TYPE, this.handleSetGlobals as EventListener);\n }\n this.subscribers.clear();\n this.globalSubscribers.clear();\n }\n\n private handleSetGlobals = (event: SetGlobalsEvent): void => {\n const changedKeys = Object.keys(event.detail.changes) as (keyof OpenAiGlobals)[];\n\n // Notify subscribers for changed keys\n for (const key of changedKeys) {\n const keySubscribers = this.subscribers.get(key);\n if (keySubscribers) {\n keySubscribers.forEach((cb) => cb());\n }\n }\n\n // Notify global subscribers\n if (changedKeys.length > 0) {\n this.globalSubscribers.forEach((cb) => cb());\n }\n };\n\n /**\n * Subscribe to changes for specific keys\n */\n subscribe(\n keys: keyof OpenAiGlobals | (keyof OpenAiGlobals)[],\n callback: Subscriber\n ): Unsubscribe {\n const keyArray = Array.isArray(keys) ? keys : [keys];\n\n for (const key of keyArray) {\n if (!this.subscribers.has(key)) {\n this.subscribers.set(key, new Set());\n }\n this.subscribers.get(key)!.add(callback);\n }\n\n return () => {\n for (const key of keyArray) {\n this.subscribers.get(key)?.delete(callback);\n }\n };\n }\n\n /**\n * Subscribe to any change\n */\n subscribeAll(callback: Subscriber): Unsubscribe {\n this.globalSubscribers.add(callback);\n return () => {\n this.globalSubscribers.delete(callback);\n };\n }\n\n /**\n * Get current value of a global property\n */\n getSnapshot<K extends keyof OpenAiGlobals>(key: K): OpenAiGlobals[K] | undefined {\n return window.openai?.[key];\n }\n\n /**\n * Get server snapshot (for SSR, returns undefined)\n */\n getServerSnapshot<K extends keyof OpenAiGlobals>(_key: K): undefined {\n return undefined;\n }\n}\n\nexport { AppsSdkStore };\n\n/**\n * Get the store instance (convenience function)\n */\nexport function getStore(): AppsSdkStore {\n return AppsSdkStore.getInstance();\n}\n","/**\n * Base hook factory for creating reactive hooks for window.openai properties\n */\n\nimport { useSyncExternalStore } from 'react';\nimport { getStore } from '../store';\nimport type { OpenAiGlobals } from '../types';\n\n/**\n * Create a hook that subscribes to a specific window.openai property\n */\nexport function createOpenAiGlobalHook<K extends keyof OpenAiGlobals>(\n key: K\n): () => OpenAiGlobals[K] | undefined {\n return function useOpenAiGlobal(): OpenAiGlobals[K] | undefined {\n const store = getStore();\n\n return useSyncExternalStore(\n (callback) => store.subscribe(key, callback),\n () => store.getSnapshot(key),\n () => store.getServerSnapshot(key)\n );\n };\n}\n\n/**\n * Generic hook to access any window.openai property\n */\nexport function useOpenAiGlobal<K extends keyof OpenAiGlobals>(\n key: K\n): OpenAiGlobals[K] | undefined {\n const store = getStore();\n\n return useSyncExternalStore(\n (callback) => store.subscribe(key, callback),\n () => store.getSnapshot(key),\n () => store.getServerSnapshot(key)\n );\n}\n","import { useOpenAiGlobal } from './use-openai-global';\nimport type { Theme } from '../types';\n\n/**\n * Get the current theme (light or dark)\n *\n * @returns Current theme, defaults to 'light' if not available\n *\n * @example\n * ```tsx\n * function MyWidget() {\n * const theme = useTheme();\n * return <div className={theme === 'dark' ? 'dark' : 'light'}>...</div>;\n * }\n * ```\n */\nexport function useTheme(): Theme {\n return useOpenAiGlobal('theme') ?? 'light';\n}\n","import { useOpenAiGlobal } from './use-openai-global';\n\n/**\n * Get the user's locale setting\n *\n * @returns BCP 47 language tag (e.g., 'en-US', 'ja-JP')\n *\n * @example\n * ```tsx\n * function MyWidget() {\n * const locale = useLocale();\n * const formatter = new Intl.DateTimeFormat(locale);\n * return <span>{formatter.format(new Date())}</span>;\n * }\n * ```\n */\nexport function useLocale(): string {\n return useOpenAiGlobal('locale') ?? 'en-US';\n}\n","import { useOpenAiGlobal } from './use-openai-global';\nimport type { DisplayMode } from '../types';\n\n/**\n * Get the current widget display mode\n *\n * @returns Current display mode: 'inline', 'pip', or 'fullscreen'\n *\n * @example\n * ```tsx\n * function MyWidget() {\n * const mode = useDisplayMode();\n * if (mode === 'fullscreen') {\n * return <FullscreenLayout />;\n * }\n * return <CompactLayout />;\n * }\n * ```\n */\nexport function useDisplayMode(): DisplayMode {\n return useOpenAiGlobal('displayMode') ?? 'inline';\n}\n","import { useOpenAiGlobal } from './use-openai-global';\n\n/**\n * Get the maximum allowed height for the widget\n *\n * @returns Maximum height in pixels\n *\n * @example\n * ```tsx\n * function MyWidget() {\n * const maxHeight = useMaxHeight();\n * return <div style={{ maxHeight }}>...</div>;\n * }\n * ```\n */\nexport function useMaxHeight(): number {\n return useOpenAiGlobal('maxHeight') ?? 400;\n}\n","import { useOpenAiGlobal } from './use-openai-global';\nimport type { SafeAreaInsets } from '../types';\n\nconst DEFAULT_SAFE_AREA: SafeAreaInsets = {\n top: 0,\n right: 0,\n bottom: 0,\n left: 0,\n};\n\n/**\n * Get safe area insets for devices with notches/rounded corners\n *\n * @returns Safe area insets object\n *\n * @example\n * ```tsx\n * function MyWidget() {\n * const safeArea = useSafeArea();\n * return (\n * <div style={{ paddingTop: safeArea.top, paddingBottom: safeArea.bottom }}>\n * ...\n * </div>\n * );\n * }\n * ```\n */\nexport function useSafeArea(): SafeAreaInsets {\n return useOpenAiGlobal('safeArea') ?? DEFAULT_SAFE_AREA;\n}\n","import { useOpenAiGlobal } from './use-openai-global';\n\n/**\n * Get the view context identifier\n *\n * @returns View identifier string or undefined\n */\nexport function useView(): string | undefined {\n return useOpenAiGlobal('view');\n}\n","import { useOpenAiGlobal } from './use-openai-global';\n\n/**\n * Get the user agent string\n *\n * Note: Do not rely on this for security decisions.\n *\n * @returns User agent string or undefined\n */\nexport function useUserAgent(): string | undefined {\n return useOpenAiGlobal('userAgent');\n}\n","import { useOpenAiGlobal } from './use-openai-global';\n\n/**\n * Get the tool input arguments\n *\n * @returns Tool input arguments or undefined if not yet available\n *\n * @example\n * ```tsx\n * interface SearchInput {\n * query: string;\n * limit?: number;\n * }\n *\n * function SearchWidget() {\n * const input = useToolInput<SearchInput>();\n *\n * if (!input) {\n * return <Loading />;\n * }\n *\n * return <div>Searching for: {input.query}</div>;\n * }\n * ```\n */\nexport function useToolInput<T = Record<string, unknown>>(): T | undefined {\n return useOpenAiGlobal('toolInput') as T | undefined;\n}\n","import { useOpenAiGlobal } from './use-openai-global';\n\n/**\n * Get the tool output (structuredContent from tool response)\n *\n * This is the concise JSON that both widget and model can access.\n *\n * @returns Tool output or undefined if not yet available\n *\n * @example\n * ```tsx\n * interface SearchOutput {\n * results: Array<{ id: string; title: string }>;\n * total: number;\n * }\n *\n * function SearchWidget() {\n * const output = useToolOutput<SearchOutput>();\n *\n * if (!output) {\n * return <Loading />;\n * }\n *\n * return (\n * <ul>\n * {output.results.map(r => <li key={r.id}>{r.title}</li>)}\n * </ul>\n * );\n * }\n * ```\n */\nexport function useToolOutput<T = unknown>(): T | undefined {\n return useOpenAiGlobal('toolOutput') as T | undefined;\n}\n","import { useOpenAiGlobal } from './use-openai-global';\n\n/**\n * Get the tool response metadata (_meta from tool response)\n *\n * This data is only visible to the widget, never sent to the model.\n * Use for large datasets, sensitive info, or data not needed for model reasoning.\n *\n * @returns Tool response metadata or undefined\n *\n * @example\n * ```tsx\n * interface SearchMetadata {\n * fullResultData: Array<FullResult>;\n * timing: number;\n * }\n *\n * function SearchWidget() {\n * const meta = useToolResponseMetadata<SearchMetadata>();\n * // meta.fullResultData has the complete data\n * // meta.timing shows how long the search took\n * }\n * ```\n */\nexport function useToolResponseMetadata<T = Record<string, unknown>>(): T | undefined {\n return useOpenAiGlobal('toolResponseMetadata') as T | undefined;\n}\n","import { useCallback } from 'react';\nimport { useOpenAiGlobal } from './use-openai-global';\nimport { getBridge } from '../bridge';\n\n/**\n * Bidirectional sync with host-persisted widget state\n *\n * State is scoped to the specific widget instance on a single message.\n * It persists across page refreshes and conversation reopening.\n *\n * @param defaultState - Optional default state if no persisted state exists\n * @returns Tuple of [state, setState]\n *\n * @example\n * ```tsx\n * interface EditorState {\n * activeTab: string;\n * scrollPosition: number;\n * }\n *\n * function Editor() {\n * const [state, setState] = useWidgetState<EditorState>({\n * activeTab: 'general',\n * scrollPosition: 0,\n * });\n *\n * const handleTabChange = (tab: string) => {\n * setState({ ...state!, activeTab: tab });\n * };\n *\n * return <Tabs active={state?.activeTab} onChange={handleTabChange} />;\n * }\n * ```\n */\nexport function useWidgetState<T>(\n defaultState?: T\n): readonly [T | undefined, (newState: T) => void] {\n const persistedState = useOpenAiGlobal('widgetState') as T | undefined;\n\n const setState = useCallback((newState: T) => {\n const bridge = getBridge();\n bridge.setWidgetState(newState);\n }, []);\n\n const resolvedState = persistedState ?? defaultState;\n\n return [resolvedState, setState] as const;\n}\n","import { getBridge } from '../bridge';\nimport type { CallToolResult } from '../types';\n\n/**\n * Call an MCP tool from the widget\n *\n * The target tool must have `_meta[\"openai/widgetAccessible\"]: true` set on the server.\n *\n * @param name - Tool name to call\n * @param args - Optional arguments for the tool\n * @returns Promise resolving to tool result\n *\n * @example\n * ```tsx\n * const result = await callTool('get_product_details', { productId: '123' });\n * if (result.isError) {\n * console.error('Tool failed:', result.content[0]?.text);\n * } else {\n * console.log('Product:', result.structuredContent);\n * }\n * ```\n */\nexport async function callTool<TInput = Record<string, unknown>, TOutput = unknown>(\n name: string,\n args?: TInput\n): Promise<CallToolResult<TOutput>> {\n const bridge = getBridge();\n return bridge.callTool<TInput, TOutput>(name, args);\n}\n","import { getBridge } from '../bridge';\n\n/**\n * Send a follow-up message to the conversation\n *\n * This will post a message authored by the widget into the chat.\n *\n * @param prompt - The message text to send\n *\n * @example\n * ```tsx\n * function ActionButton() {\n * const handleClick = () => {\n * sendFollowUpMessage('Show me more options like this one');\n * };\n * return <button onClick={handleClick}>Show more</button>;\n * }\n * ```\n */\nexport function sendFollowUpMessage(prompt: string): void {\n const bridge = getBridge();\n bridge.sendFollowUpMessage(prompt);\n}\n","import { getBridge } from '../bridge';\n\n/**\n * Upload a file and get its ID\n *\n * Supported formats: PNG, JPEG, WebP\n *\n * @param file - File object to upload\n * @returns Promise resolving to object with fileId\n *\n * @example\n * ```tsx\n * const input = document.querySelector('input[type=\"file\"]');\n * const file = input.files[0];\n * const { fileId } = await uploadFile(file);\n * ```\n */\nexport async function uploadFile(file: File): Promise<{ fileId: string }> {\n const bridge = getBridge();\n return bridge.uploadFile(file);\n}\n","import { getBridge } from '../bridge';\n\n/**\n * Get a temporary download URL for a previously uploaded file\n *\n * The URL is temporary and will expire.\n *\n * @param fileId - ID of the uploaded file\n * @returns Promise resolving to object with temporary URL\n *\n * @example\n * ```tsx\n * const { url } = await getFileDownloadUrl('file-abc123');\n * // Use url before it expires\n * ```\n */\nexport async function getFileDownloadUrl(fileId: string): Promise<{ url: string }> {\n const bridge = getBridge();\n return bridge.getFileDownloadUrl(fileId);\n}\n","import { getBridge } from '../bridge';\nimport type { DisplayMode } from '../types';\n\n/**\n * Request a change in widget display mode\n *\n * Note: The host may deny the request based on user preferences or device constraints.\n *\n * @param mode - Desired display mode: 'inline', 'pip', or 'fullscreen'\n *\n * @example\n * ```tsx\n * function ExpandButton() {\n * return (\n * <button onClick={() => requestDisplayMode('fullscreen')}>\n * Expand\n * </button>\n * );\n * }\n * ```\n */\nexport function requestDisplayMode(mode: DisplayMode): void {\n const bridge = getBridge();\n bridge.requestDisplayMode(mode);\n}\n","import { getBridge } from '../bridge';\nimport type { ModalOptions } from '../types';\n\n/**\n * Spawn a modal dialog owned by ChatGPT\n *\n * @param options - Modal configuration options\n * @returns Promise that resolves when modal is closed\n */\nexport async function requestModal(options: ModalOptions): Promise<void> {\n const bridge = getBridge();\n return bridge.requestModal(options);\n}\n","import { getBridge } from '../bridge';\n\n/**\n * Report the widget's intrinsic content height to the host\n *\n * Use this to avoid scroll clipping when content size changes dynamically.\n *\n * @param height - Content height in pixels\n *\n * @example\n * ```tsx\n * function DynamicContent({ content }) {\n * const ref = useRef<HTMLDivElement>(null);\n *\n * useEffect(() => {\n * if (ref.current) {\n * notifyIntrinsicHeight(ref.current.scrollHeight);\n * }\n * }, [content]);\n *\n * return <div ref={ref}>{content}</div>;\n * }\n * ```\n */\nexport function notifyIntrinsicHeight(height: number): void {\n const bridge = getBridge();\n bridge.notifyIntrinsicHeight(height);\n}\n","import { getBridge } from '../bridge';\n\n/**\n * Programmatically hide/close the widget\n *\n * @example\n * ```tsx\n * function CloseButton() {\n * return <button onClick={requestClose}>Close</button>;\n * }\n * ```\n */\nexport function requestClose(): void {\n const bridge = getBridge();\n bridge.requestClose();\n}\n","import { getBridge } from '../bridge';\n\n/**\n * Open an external URL in the user's browser\n *\n * The URL must be allowed by the widget's CSP `redirect_domains` configuration.\n *\n * @param href - URL to open\n *\n * @example\n * ```tsx\n * function ProductLink({ url, children }) {\n * const handleClick = (e) => {\n * e.preventDefault();\n * openExternal(url);\n * };\n * return <a href={url} onClick={handleClick}>{children}</a>;\n * }\n * ```\n */\nexport function openExternal(href: string): void {\n const bridge = getBridge();\n bridge.openExternal(href);\n}\n","import { getBridge } from '../bridge';\n\n/**\n * Set the destination URL for the fullscreen mode's \"Open in App\" button\n *\n * @param href - URL to set for the \"Open in App\" button\n */\nexport function setOpenInAppUrl(href: string): void {\n const bridge = getBridge();\n bridge.setOpenInAppUrl(href);\n}\n"]}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { getAdaptor, isAppsSdkAvailable, isMcpAppsAvailable } from './chunk-ZYBPDIEG.js';
|
|
2
|
+
|
|
3
|
+
// src/unified/actions/action.ts
|
|
4
|
+
async function action(toolName, input) {
|
|
5
|
+
const adaptor = getAdaptor();
|
|
6
|
+
await adaptor.ensureReady();
|
|
7
|
+
await adaptor.callTool(toolName, input);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// src/unified/actions/data.ts
|
|
11
|
+
function extractOutput(result) {
|
|
12
|
+
if (result.structuredContent !== void 0) {
|
|
13
|
+
return result.structuredContent;
|
|
14
|
+
}
|
|
15
|
+
const textContent = result.content?.find((c) => c.type === "text")?.text;
|
|
16
|
+
if (textContent) {
|
|
17
|
+
try {
|
|
18
|
+
return JSON.parse(textContent);
|
|
19
|
+
} catch {
|
|
20
|
+
return textContent;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return void 0;
|
|
24
|
+
}
|
|
25
|
+
async function data(toolName, input) {
|
|
26
|
+
const adaptor = getAdaptor();
|
|
27
|
+
await adaptor.ensureReady();
|
|
28
|
+
const result = await adaptor.callTool(toolName, input);
|
|
29
|
+
return extractOutput(result);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// src/unified/actions/say.ts
|
|
33
|
+
function isInChatHost() {
|
|
34
|
+
return isAppsSdkAvailable() || isMcpAppsAvailable();
|
|
35
|
+
}
|
|
36
|
+
function say(message) {
|
|
37
|
+
if (!isInChatHost()) {
|
|
38
|
+
console.log(
|
|
39
|
+
"%c[Pancake] say() called (not in chat host):%c\n%s",
|
|
40
|
+
"color: #8b5cf6; font-weight: bold",
|
|
41
|
+
"color: inherit",
|
|
42
|
+
message
|
|
43
|
+
);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const adaptor = getAdaptor();
|
|
47
|
+
adaptor.sendFollowUpMessage(message);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// src/unified/actions/navigate-to-view.ts
|
|
51
|
+
async function navigateToView(viewName, params) {
|
|
52
|
+
const adaptor = getAdaptor();
|
|
53
|
+
await adaptor.ensureReady();
|
|
54
|
+
await adaptor.callTool(viewName, params);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// src/unified/actions/call-tool.ts
|
|
58
|
+
async function callTool(toolName, input) {
|
|
59
|
+
const adaptor = getAdaptor();
|
|
60
|
+
return adaptor.callTool(toolName, input);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// src/unified/actions/send-follow-up-message.ts
|
|
64
|
+
async function sendFollowUpMessage(message) {
|
|
65
|
+
const adaptor = getAdaptor();
|
|
66
|
+
await adaptor.sendFollowUpMessage(message);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// src/unified/actions/open-external.ts
|
|
70
|
+
async function openExternal(url) {
|
|
71
|
+
const adaptor = getAdaptor();
|
|
72
|
+
await adaptor.openExternal(url);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// src/unified/actions/request-display-mode.ts
|
|
76
|
+
async function requestDisplayMode(mode) {
|
|
77
|
+
const adaptor = getAdaptor();
|
|
78
|
+
await adaptor.requestDisplayMode(mode);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// src/unified/actions/is-supported.ts
|
|
82
|
+
function isSupported(feature) {
|
|
83
|
+
const adaptor = getAdaptor();
|
|
84
|
+
return adaptor.isSupported(feature);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// src/unified/actions/read-resource.ts
|
|
88
|
+
async function readResource(uri) {
|
|
89
|
+
const adaptor = getAdaptor();
|
|
90
|
+
if (!adaptor.readResource) {
|
|
91
|
+
throw new Error("readResource is not supported on this platform");
|
|
92
|
+
}
|
|
93
|
+
await adaptor.ensureReady();
|
|
94
|
+
return adaptor.readResource(uri);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// src/unified/actions/update-model-context.ts
|
|
98
|
+
async function updateModelContext(params) {
|
|
99
|
+
const adaptor = getAdaptor();
|
|
100
|
+
if (!adaptor.updateModelContext) {
|
|
101
|
+
throw new Error("updateModelContext is not supported on this platform");
|
|
102
|
+
}
|
|
103
|
+
await adaptor.ensureReady();
|
|
104
|
+
return adaptor.updateModelContext(params);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// src/unified/actions/log.ts
|
|
108
|
+
function log(level, data2, logger) {
|
|
109
|
+
const adaptor = getAdaptor();
|
|
110
|
+
adaptor.log(level, data2, logger);
|
|
111
|
+
}
|
|
112
|
+
var logDebug = (data2, logger) => log("debug", data2, logger);
|
|
113
|
+
var logInfo = (data2, logger) => log("info", data2, logger);
|
|
114
|
+
var logWarning = (data2, logger) => log("warning", data2, logger);
|
|
115
|
+
var logError = (data2, logger) => log("error", data2, logger);
|
|
116
|
+
|
|
117
|
+
// src/unified/actions/ping.ts
|
|
118
|
+
async function ping() {
|
|
119
|
+
const adaptor = getAdaptor();
|
|
120
|
+
if (!adaptor.ping) {
|
|
121
|
+
return Promise.resolve();
|
|
122
|
+
}
|
|
123
|
+
await adaptor.ensureReady();
|
|
124
|
+
return adaptor.ping();
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// src/unified/actions/on-teardown.ts
|
|
128
|
+
function onTeardown(handler) {
|
|
129
|
+
const adaptor = getAdaptor();
|
|
130
|
+
return adaptor.onTeardown?.(handler) ?? (() => {
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// src/unified/actions/notify-size-changed.ts
|
|
135
|
+
function notifySizeChanged(width, height) {
|
|
136
|
+
const adaptor = getAdaptor();
|
|
137
|
+
adaptor.notifySizeChanged?.(width, height);
|
|
138
|
+
}
|
|
139
|
+
function setupAutoSizeReporting(element = document.documentElement) {
|
|
140
|
+
const adaptor = getAdaptor();
|
|
141
|
+
return adaptor.setupAutoSizeReporting(element);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export { action, callTool, data, isSupported, log, logDebug, logError, logInfo, logWarning, navigateToView, notifySizeChanged, onTeardown, openExternal, ping, readResource, requestDisplayMode, say, sendFollowUpMessage, setupAutoSizeReporting, updateModelContext };
|
|
145
|
+
//# sourceMappingURL=chunk-7HJ5PKKT.js.map
|
|
146
|
+
//# sourceMappingURL=chunk-7HJ5PKKT.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/unified/actions/action.ts","../src/unified/actions/data.ts","../src/unified/actions/say.ts","../src/unified/actions/navigate-to-view.ts","../src/unified/actions/call-tool.ts","../src/unified/actions/send-follow-up-message.ts","../src/unified/actions/open-external.ts","../src/unified/actions/request-display-mode.ts","../src/unified/actions/is-supported.ts","../src/unified/actions/read-resource.ts","../src/unified/actions/update-model-context.ts","../src/unified/actions/log.ts","../src/unified/actions/ping.ts","../src/unified/actions/on-teardown.ts","../src/unified/actions/notify-size-changed.ts"],"names":["data"],"mappings":"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","file":"chunk-7HJ5PKKT.js","sourcesContent":["import { getAdaptor } from '../adaptor';\n\n/**\n * Execute an action tool (fire-and-forget) (Tier 0 Semantic API)\n *\n * Actions are side-effect tools that mutate state. The result is discarded\n * since actions are meant for fire-and-forget operations.\n *\n * Use for: save, delete, update, navigate, send, submit\n *\n * @param toolName - Name of the action tool to execute\n * @param input - Optional input parameters for the action\n *\n * @example\n * ```tsx\n * import { action } from '@pancake-apps/web';\n *\n * // Delete an item\n * await action('delete-item', { id: '123' });\n *\n * // Submit a form\n * await action('submit-form', { name: 'John', email: 'john@example.com' });\n *\n * // Navigate (alternative to navigateToView)\n * await action('open-settings');\n * ```\n */\nexport async function action<TInput = void>(\n toolName: string,\n input?: TInput\n): Promise<void> {\n const adaptor = getAdaptor();\n await adaptor.ensureReady();\n await adaptor.callTool(toolName, input);\n // Result is intentionally discarded - actions are fire-and-forget\n}\n","import { getAdaptor } from '../adaptor';\nimport type { CallToolResult } from '../types';\n\n/**\n * Extract the output from a tool result\n * Prefers structuredContent, falls back to parsing text content\n */\nfunction extractOutput<TOutput>(result: CallToolResult<TOutput>): TOutput {\n // If structuredContent is available, use it directly\n if (result.structuredContent !== undefined) {\n return result.structuredContent;\n }\n\n // Try to extract from text content\n const textContent = result.content?.find((c) => c.type === 'text')?.text;\n if (textContent) {\n try {\n return JSON.parse(textContent) as TOutput;\n } catch {\n // If not JSON, return the text as-is (cast to TOutput)\n return textContent as unknown as TOutput;\n }\n }\n\n // No content available\n return undefined as unknown as TOutput;\n}\n\n/**\n * Fetch data from a tool (query) (Tier 0 Semantic API)\n *\n * Data tools are read-only queries that return structured data.\n * The result is extracted from structuredContent or parsed from text content.\n *\n * Use for: search, get, list, fetch\n *\n * @param toolName - Name of the data tool to call\n * @param input - Optional input parameters for the query\n * @returns The extracted data from the tool result\n *\n * @example\n * ```tsx\n * import { data } from '@pancake-apps/web';\n *\n * // Search for items\n * const results = await data<{ q: string }, SearchResult[]>('search', { q: 'pancakes' });\n *\n * // Get a single item\n * const user = await data<{ id: string }, User>('get-user', { id: '123' });\n *\n * // List all items\n * const items = await data<void, Item[]>('list-items');\n * ```\n */\nexport async function data<TInput = void, TOutput = unknown>(\n toolName: string,\n input?: TInput\n): Promise<TOutput> {\n const adaptor = getAdaptor();\n await adaptor.ensureReady();\n const result = await adaptor.callTool<TInput, TOutput>(toolName, input);\n return extractOutput(result);\n}\n","import { getAdaptor } from '../adaptor';\nimport { isAppsSdkAvailable, isMcpAppsAvailable } from '../detection';\n\n/**\n * Check if we're running inside an actual AI chat host\n */\nfunction isInChatHost(): boolean {\n return isAppsSdkAvailable() || isMcpAppsAvailable();\n}\n\n/**\n * Send a follow-up message to the conversation (Tier 0 Semantic API)\n *\n * This is a semantic wrapper around `sendFollowUpMessage` that provides\n * a more intuitive API for common use cases.\n *\n * When running outside a chat host (e.g., standalone browser testing),\n * the message is logged to the console instead.\n *\n * @param message - The message to send to the conversation\n *\n * @example\n * ```tsx\n * import { say } from '@pancake-apps/web';\n *\n * // Send a simple message\n * say('Task completed successfully!');\n *\n * // Send a formatted message\n * say(`Found ${count} results for \"${query}\"`);\n * ```\n */\nexport function say(message: string): void {\n if (!isInChatHost()) {\n console.log(\n '%c[Pancake] say() called (not in chat host):%c\\n%s',\n 'color: #8b5cf6; font-weight: bold',\n 'color: inherit',\n message\n );\n return;\n }\n\n const adaptor = getAdaptor();\n adaptor.sendFollowUpMessage(message);\n}\n","import { getAdaptor } from '../adaptor';\n\n/**\n * Navigate to another view/tool (Tier 0 Semantic API)\n *\n * This is a semantic wrapper around `callTool` that discards the result,\n * intended for navigation scenarios where you just want to switch views.\n *\n * @param viewName - The name of the view/tool to navigate to\n * @param params - Optional parameters to pass to the view\n *\n * @example\n * ```tsx\n * import { navigateToView } from '@pancake-apps/web';\n *\n * // Navigate to a view with no parameters\n * await navigateToView('settings');\n *\n * // Navigate with parameters\n * await navigateToView('user-profile', { userId: '123' });\n * ```\n */\nexport async function navigateToView<TInput = Record<string, unknown>>(\n viewName: string,\n params?: TInput\n): Promise<void> {\n const adaptor = getAdaptor();\n await adaptor.ensureReady();\n await adaptor.callTool(viewName, params);\n}\n","import { getAdaptor } from '../adaptor';\nimport type { CallToolResult } from '../types';\n\n/**\n * Call a tool by name with input parameters\n *\n * @param toolName - Name of the tool to call\n * @param input - Input parameters for the tool\n * @returns Promise resolving to the tool result\n */\nexport async function callTool<TInput = unknown, TOutput = unknown>(\n toolName: string,\n input: TInput\n): Promise<CallToolResult<TOutput>> {\n const adaptor = getAdaptor();\n return adaptor.callTool(toolName, input) as Promise<CallToolResult<TOutput>>;\n}\n","import { getAdaptor } from '../adaptor';\n\n/**\n * Send a follow-up message to the conversation\n *\n * @param message - Message text to send\n */\nexport async function sendFollowUpMessage(message: string): Promise<void> {\n const adaptor = getAdaptor();\n await adaptor.sendFollowUpMessage(message);\n}\n","import { getAdaptor } from '../adaptor';\n\n/**\n * Open an external URL\n *\n * @param url - URL to open\n */\nexport async function openExternal(url: string): Promise<void> {\n const adaptor = getAdaptor();\n await adaptor.openExternal(url);\n}\n","import { getAdaptor } from '../adaptor';\nimport type { DisplayMode } from '../types';\n\n/**\n * Request a specific display mode\n *\n * @param mode - Display mode to request\n */\nexport async function requestDisplayMode(mode: DisplayMode): Promise<void> {\n const adaptor = getAdaptor();\n await adaptor.requestDisplayMode(mode);\n}\n","import { getAdaptor } from '../adaptor';\nimport type { Feature } from '../types';\n\n/**\n * Check if a feature is supported on the current platform\n *\n * @param feature - Feature to check\n * @returns True if the feature is supported\n */\nexport function isSupported(feature: Feature): boolean {\n const adaptor = getAdaptor();\n return adaptor.isSupported(feature);\n}\n","import { getAdaptor } from '../adaptor';\nimport type { ResourceReadResult } from '../types';\n\n/**\n * Read a resource from the MCP server\n *\n * @param uri - Resource URI to read\n * @returns Promise resolving to resource contents\n * @throws Error if not supported on current platform\n *\n * @example\n * ```tsx\n * const result = await readResource('file:///path/to/resource');\n * console.log(result.contents);\n * ```\n */\nexport async function readResource(uri: string): Promise<ResourceReadResult> {\n const adaptor = getAdaptor();\n if (!adaptor.readResource) {\n throw new Error('readResource is not supported on this platform');\n }\n await adaptor.ensureReady();\n return adaptor.readResource(uri);\n}\n","import { getAdaptor } from '../adaptor';\nimport type { UpdateModelContextParams } from '../types';\n\n/**\n * Update the model context with new content\n *\n * @param params - Context update parameters\n * @throws Error if not supported on current platform\n *\n * @example\n * ```tsx\n * await updateModelContext({\n * structuredContent: { selectedItems: [1, 2, 3] }\n * });\n * ```\n */\nexport async function updateModelContext(params: UpdateModelContextParams): Promise<void> {\n const adaptor = getAdaptor();\n if (!adaptor.updateModelContext) {\n throw new Error('updateModelContext is not supported on this platform');\n }\n await adaptor.ensureReady();\n return adaptor.updateModelContext(params);\n}\n","import { getAdaptor } from '../adaptor';\nimport type { LogLevel } from '../types';\n\n/**\n * Log a message to the host environment\n *\n * On MCP Apps: Sends log message to host via JSON-RPC notification\n * On Apps SDK: Falls back to console.log/warn/error/debug\n *\n * @param level - Log level\n * @param data - Data to log\n * @param logger - Optional logger name\n *\n * @example\n * ```tsx\n * log('info', { action: 'button_clicked', buttonId: 'submit' });\n * logError({ code: 'VALIDATION_FAILED', field: 'email' });\n * ```\n */\nexport function log(level: LogLevel, data: unknown, logger?: string): void {\n const adaptor = getAdaptor();\n // Both adaptors now implement log() - MCP sends to host, Apps SDK uses console\n adaptor.log(level, data, logger);\n}\n\nexport const logDebug = (data: unknown, logger?: string) => log('debug', data, logger);\nexport const logInfo = (data: unknown, logger?: string) => log('info', data, logger);\nexport const logWarning = (data: unknown, logger?: string) => log('warning', data, logger);\nexport const logError = (data: unknown, logger?: string) => log('error', data, logger);\n","import { getAdaptor } from '../adaptor';\n\n/**\n * Ping the host to verify connection\n *\n * @returns Promise that resolves when host responds\n *\n * @example\n * ```tsx\n * await ping();\n * console.log('Host is responsive');\n * ```\n */\nexport async function ping(): Promise<void> {\n const adaptor = getAdaptor();\n if (!adaptor.ping) {\n return Promise.resolve();\n }\n await adaptor.ensureReady();\n return adaptor.ping();\n}\n","import { getAdaptor } from '../adaptor';\nimport type { TeardownHandler } from '../types';\n\n/**\n * Register a handler for when the resource is being torn down\n *\n * @param handler - Function to call on teardown\n * @returns Cleanup function to unregister the handler\n *\n * @example\n * ```tsx\n * useEffect(() => {\n * return onTeardown(async ({ reason }) => {\n * await saveState();\n * console.log('Tearing down:', reason);\n * });\n * }, []);\n * ```\n */\nexport function onTeardown(handler: TeardownHandler): () => void {\n const adaptor = getAdaptor();\n return adaptor.onTeardown?.(handler) ?? (() => {});\n}\n","import { getAdaptor } from '../adaptor';\n\n/**\n * Notify the host that the content size has changed\n *\n * @param width - New width in pixels\n * @param height - New height in pixels\n *\n * @example\n * ```tsx\n * notifySizeChanged(400, 300);\n * ```\n */\nexport function notifySizeChanged(width: number, height: number): void {\n const adaptor = getAdaptor();\n adaptor.notifySizeChanged?.(width, height);\n}\n\n/**\n * Set up automatic size reporting using ResizeObserver\n *\n * @param element - Element to observe (defaults to document.documentElement)\n * @returns Cleanup function to stop observing\n *\n * @example\n * ```tsx\n * useEffect(() => {\n * return setupAutoSizeReporting(containerRef.current);\n * }, []);\n * ```\n */\nexport function setupAutoSizeReporting(element: HTMLElement = document.documentElement): () => void {\n const adaptor = getAdaptor();\n return adaptor.setupAutoSizeReporting(element);\n}\n"]}
|