sunpeak 0.9.2 → 0.9.6
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 +2 -2
- package/dist/chatgpt/conversation.d.ts +5 -2
- package/dist/chatgpt/iframe-resource.d.ts +69 -0
- package/dist/chatgpt/index.cjs +2 -1
- package/dist/chatgpt/index.cjs.map +1 -1
- package/dist/chatgpt/index.d.ts +1 -0
- package/dist/chatgpt/index.js +2 -1
- package/dist/discovery-a4WId9PC.cjs +125 -0
- package/dist/discovery-a4WId9PC.cjs.map +1 -0
- package/dist/discovery-ft3cd2dW.js +126 -0
- package/dist/discovery-ft3cd2dW.js.map +1 -0
- package/dist/index.cjs +13 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +30 -18
- package/dist/index.js.map +1 -1
- package/dist/lib/discovery.d.ts +110 -0
- package/dist/lib/index.d.ts +1 -0
- package/dist/mcp/entry.cjs +2 -10
- package/dist/mcp/entry.cjs.map +1 -1
- package/dist/mcp/entry.js +1 -9
- package/dist/mcp/entry.js.map +1 -1
- package/dist/{simulator-url-CexnaL-e.js → simulator-url-BOSS60NS.js} +592 -4
- package/dist/simulator-url-BOSS60NS.js.map +1 -0
- package/dist/{simulator-url-CG8lAAC3.cjs → simulator-url-BStCoFTv.cjs} +593 -5
- package/dist/simulator-url-BStCoFTv.cjs.map +1 -0
- package/dist/types/simulation.d.ts +4 -1
- package/package.json +1 -1
- package/template/.sunpeak/dev.tsx +6 -91
- package/template/README.md +2 -2
- package/template/dist/albums.json +1 -1
- package/template/dist/carousel.json +1 -1
- package/template/dist/map.json +1 -1
- package/template/dist/review.json +1 -1
- package/template/node_modules/.vite/deps/@openai_apps-sdk-ui_components_SegmentedControl.js +4 -4
- package/template/node_modules/.vite/deps/@openai_apps-sdk-ui_components_Select.js +6 -6
- package/template/node_modules/.vite/deps/_metadata.json +25 -25
- package/template/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
- package/template/src/resources/index.ts +3 -25
- package/template/src/simulations/index.ts +3 -10
- package/dist/simulator-url-CG8lAAC3.cjs.map +0 -1
- package/dist/simulator-url-CexnaL-e.js.map +0 -1
|
@@ -5625,7 +5625,7 @@ const useEscCloseStack = (listening, cb) => {
|
|
|
5625
5625
|
}, [id, listening, latestCallback]);
|
|
5626
5626
|
};
|
|
5627
5627
|
const __vite_import_meta_env__ = { "DEV": false, "MODE": "production" };
|
|
5628
|
-
const META_ENV = typeof { url: typeof document === "undefined" ? require("url").pathToFileURL(__filename).href : _documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === "SCRIPT" && _documentCurrentScript.src || new URL("simulator-url-
|
|
5628
|
+
const META_ENV = typeof { url: typeof document === "undefined" ? require("url").pathToFileURL(__filename).href : _documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === "SCRIPT" && _documentCurrentScript.src || new URL("simulator-url-BStCoFTv.cjs", document.baseURI).href } !== "undefined" ? __vite_import_meta_env__ : void 0;
|
|
5629
5629
|
const NODE_ENV = typeof process !== "undefined" && ((_a = process.env) == null ? void 0 : _a.NODE_ENV) ? (_b = process.env) == null ? void 0 : _b.NODE_ENV : "production";
|
|
5630
5630
|
const isDev = NODE_ENV === "development" || !!(META_ENV == null ? void 0 : META_ENV.DEV);
|
|
5631
5631
|
const isJSDomLike = typeof navigator !== "undefined" && /(jsdom|happy-dom)/i.test(navigator.userAgent) || typeof globalThis.happyDOM === "object";
|
|
@@ -7560,8 +7560,591 @@ const SCREEN_WIDTHS = {
|
|
|
7560
7560
|
tablet: 768,
|
|
7561
7561
|
full: 1024
|
|
7562
7562
|
};
|
|
7563
|
+
const ALLOWED_SCRIPT_ORIGINS = [
|
|
7564
|
+
"https://sandbox.sunpeakai.com",
|
|
7565
|
+
"http://localhost",
|
|
7566
|
+
"https://localhost",
|
|
7567
|
+
"http://127.0.0.1",
|
|
7568
|
+
"https://127.0.0.1"
|
|
7569
|
+
];
|
|
7570
|
+
const ALLOWED_PARENT_ORIGINS = [
|
|
7571
|
+
"https://app.sunpeak.ai",
|
|
7572
|
+
"http://localhost",
|
|
7573
|
+
"https://localhost",
|
|
7574
|
+
"http://127.0.0.1",
|
|
7575
|
+
"https://127.0.0.1"
|
|
7576
|
+
];
|
|
7577
|
+
function escapeHtml(str) {
|
|
7578
|
+
return str.replace(/[&<>"']/g, (c) => {
|
|
7579
|
+
const entities = {
|
|
7580
|
+
"&": "&",
|
|
7581
|
+
"<": "<",
|
|
7582
|
+
">": ">",
|
|
7583
|
+
'"': """,
|
|
7584
|
+
"'": "'"
|
|
7585
|
+
};
|
|
7586
|
+
return entities[c] ?? c;
|
|
7587
|
+
});
|
|
7588
|
+
}
|
|
7589
|
+
function isAllowedScriptSrc(src) {
|
|
7590
|
+
if (!src) {
|
|
7591
|
+
return false;
|
|
7592
|
+
}
|
|
7593
|
+
if (src.startsWith("/") && !src.startsWith("//")) {
|
|
7594
|
+
return true;
|
|
7595
|
+
}
|
|
7596
|
+
if (!src.includes("://")) {
|
|
7597
|
+
return false;
|
|
7598
|
+
}
|
|
7599
|
+
try {
|
|
7600
|
+
const url = new URL(src);
|
|
7601
|
+
if (url.origin === window.location.origin) {
|
|
7602
|
+
return true;
|
|
7603
|
+
}
|
|
7604
|
+
if (url.hostname === "localhost" || url.hostname === "127.0.0.1") {
|
|
7605
|
+
return true;
|
|
7606
|
+
}
|
|
7607
|
+
return ALLOWED_SCRIPT_ORIGINS.some((allowed) => {
|
|
7608
|
+
try {
|
|
7609
|
+
const allowedUrl = new URL(allowed);
|
|
7610
|
+
return url.origin === allowedUrl.origin;
|
|
7611
|
+
} catch {
|
|
7612
|
+
return false;
|
|
7613
|
+
}
|
|
7614
|
+
});
|
|
7615
|
+
} catch {
|
|
7616
|
+
return false;
|
|
7617
|
+
}
|
|
7618
|
+
}
|
|
7619
|
+
function generateCSP(csp, scriptSrc) {
|
|
7620
|
+
let scriptOrigin = "";
|
|
7621
|
+
try {
|
|
7622
|
+
const scriptUrl = new URL(scriptSrc, window.location.origin);
|
|
7623
|
+
scriptOrigin = scriptUrl.origin;
|
|
7624
|
+
} catch {
|
|
7625
|
+
}
|
|
7626
|
+
const directives = [
|
|
7627
|
+
"default-src 'self'",
|
|
7628
|
+
// Allow inline scripts for the bridge, blob: for dynamic content, and the script origin
|
|
7629
|
+
`script-src 'self' 'unsafe-inline' blob: ${scriptOrigin}`.trim(),
|
|
7630
|
+
// Allow inline styles and data: URIs for images embedded in CSS
|
|
7631
|
+
`style-src 'self' 'unsafe-inline' ${scriptOrigin}`.trim(),
|
|
7632
|
+
// Disallow iframes within the iframe (no nesting)
|
|
7633
|
+
"frame-src 'none'",
|
|
7634
|
+
// Disallow form submissions
|
|
7635
|
+
"form-action 'none'",
|
|
7636
|
+
// Disallow changing the base URL
|
|
7637
|
+
"base-uri 'self'"
|
|
7638
|
+
];
|
|
7639
|
+
const connectSources = /* @__PURE__ */ new Set(["'self'"]);
|
|
7640
|
+
if (scriptOrigin) {
|
|
7641
|
+
connectSources.add(scriptOrigin);
|
|
7642
|
+
}
|
|
7643
|
+
if (csp == null ? void 0 : csp.connect_domains) {
|
|
7644
|
+
for (const domain of csp.connect_domains) {
|
|
7645
|
+
connectSources.add(domain);
|
|
7646
|
+
}
|
|
7647
|
+
}
|
|
7648
|
+
directives.push(`connect-src ${Array.from(connectSources).join(" ")}`);
|
|
7649
|
+
const resourceSources = /* @__PURE__ */ new Set(["'self'", "data:", "blob:"]);
|
|
7650
|
+
if (scriptOrigin) {
|
|
7651
|
+
resourceSources.add(scriptOrigin);
|
|
7652
|
+
}
|
|
7653
|
+
if (csp == null ? void 0 : csp.resource_domains) {
|
|
7654
|
+
for (const domain of csp.resource_domains) {
|
|
7655
|
+
resourceSources.add(domain);
|
|
7656
|
+
}
|
|
7657
|
+
}
|
|
7658
|
+
const resourceList = Array.from(resourceSources).join(" ");
|
|
7659
|
+
directives.push(`img-src ${resourceList}`);
|
|
7660
|
+
directives.push(`font-src ${resourceList}`);
|
|
7661
|
+
directives.push(`media-src ${resourceList}`);
|
|
7662
|
+
return directives.join("; ");
|
|
7663
|
+
}
|
|
7664
|
+
function generateBridgeScript(allowedParentOrigins) {
|
|
7665
|
+
const originsJson = JSON.stringify(allowedParentOrigins);
|
|
7666
|
+
return `
|
|
7667
|
+
<script>
|
|
7668
|
+
(function() {
|
|
7669
|
+
// Allowed origins that can send messages to this iframe
|
|
7670
|
+
var allowedOrigins = ${originsJson};
|
|
7671
|
+
|
|
7672
|
+
// MessagePort for secure communication with parent (set during handshake)
|
|
7673
|
+
var messagePort = null;
|
|
7674
|
+
|
|
7675
|
+
// Queue messages until port is ready
|
|
7676
|
+
var messageQueue = [];
|
|
7677
|
+
|
|
7678
|
+
// Check if an origin is allowed (handles localhost with any port)
|
|
7679
|
+
function isAllowedOrigin(origin) {
|
|
7680
|
+
// Note: We no longer accept 'null' origin - MessageChannel provides security
|
|
7681
|
+
for (var i = 0; i < allowedOrigins.length; i++) {
|
|
7682
|
+
if (origin === allowedOrigins[i]) return true;
|
|
7683
|
+
// Handle localhost/127.0.0.1 with any port
|
|
7684
|
+
if (allowedOrigins[i].indexOf('localhost') !== -1 || allowedOrigins[i].indexOf('127.0.0.1') !== -1) {
|
|
7685
|
+
try {
|
|
7686
|
+
var allowed = new URL(allowedOrigins[i]);
|
|
7687
|
+
var test = new URL(origin);
|
|
7688
|
+
if (test.hostname === allowed.hostname && test.protocol === allowed.protocol) return true;
|
|
7689
|
+
} catch (e) {}
|
|
7690
|
+
}
|
|
7691
|
+
}
|
|
7692
|
+
return false;
|
|
7693
|
+
}
|
|
7694
|
+
|
|
7695
|
+
// Send message via MessagePort (queues if port not ready)
|
|
7696
|
+
function sendToParent(message) {
|
|
7697
|
+
if (messagePort) {
|
|
7698
|
+
messagePort.postMessage(message);
|
|
7699
|
+
} else {
|
|
7700
|
+
messageQueue.push(message);
|
|
7701
|
+
}
|
|
7702
|
+
}
|
|
7703
|
+
|
|
7704
|
+
// Flush queued messages once port is ready
|
|
7705
|
+
function flushMessageQueue() {
|
|
7706
|
+
while (messageQueue.length > 0) {
|
|
7707
|
+
var msg = messageQueue.shift();
|
|
7708
|
+
messagePort.postMessage(msg);
|
|
7709
|
+
}
|
|
7710
|
+
}
|
|
7711
|
+
|
|
7712
|
+
// Set up window.openai with placeholder values (updated via MessageChannel)
|
|
7713
|
+
window.openai = {
|
|
7714
|
+
theme: 'dark',
|
|
7715
|
+
locale: 'en-US',
|
|
7716
|
+
displayMode: 'inline',
|
|
7717
|
+
maxHeight: undefined,
|
|
7718
|
+
userAgent: { device: { type: 'desktop' }, capabilities: { hover: true, touch: false } },
|
|
7719
|
+
safeArea: { insets: { top: 0, bottom: 0, left: 0, right: 0 } },
|
|
7720
|
+
view: null,
|
|
7721
|
+
toolInput: {},
|
|
7722
|
+
toolOutput: null,
|
|
7723
|
+
toolResponseMetadata: null,
|
|
7724
|
+
widgetState: null,
|
|
7725
|
+
|
|
7726
|
+
// API methods that send messages to parent via MessagePort
|
|
7727
|
+
callTool: function(name, args) {
|
|
7728
|
+
sendToParent({ type: 'openai:callTool', payload: { name, args } });
|
|
7729
|
+
},
|
|
7730
|
+
sendFollowUpMessage: function(params) {
|
|
7731
|
+
sendToParent({ type: 'openai:sendFollowUpMessage', payload: params });
|
|
7732
|
+
},
|
|
7733
|
+
openExternal: function(params) {
|
|
7734
|
+
sendToParent({ type: 'openai:openExternal', payload: params });
|
|
7735
|
+
},
|
|
7736
|
+
requestDisplayMode: function(params) {
|
|
7737
|
+
sendToParent({ type: 'openai:requestDisplayMode', payload: params });
|
|
7738
|
+
},
|
|
7739
|
+
requestModal: function(params) {
|
|
7740
|
+
sendToParent({ type: 'openai:requestModal', payload: params });
|
|
7741
|
+
},
|
|
7742
|
+
notifyIntrinsicHeight: function(height) {
|
|
7743
|
+
// Height updates use postMessage directly to avoid delays during handshake.
|
|
7744
|
+
// This is safe because height values are validated on the parent side.
|
|
7745
|
+
window.parent.postMessage({ type: 'openai:notifyIntrinsicHeight', payload: { height } }, '*');
|
|
7746
|
+
},
|
|
7747
|
+
setWidgetState: function(state) {
|
|
7748
|
+
sendToParent({ type: 'openai:setWidgetState', payload: state });
|
|
7749
|
+
},
|
|
7750
|
+
};
|
|
7751
|
+
|
|
7752
|
+
// Handle incoming messages on the MessagePort
|
|
7753
|
+
function handlePortMessage(event) {
|
|
7754
|
+
var data = event.data;
|
|
7755
|
+
if (!data || typeof data !== 'object') return;
|
|
7756
|
+
|
|
7757
|
+
if (data.type === 'openai:init' || data.type === 'openai:update') {
|
|
7758
|
+
var payload = data.payload || {};
|
|
7759
|
+
|
|
7760
|
+
// Update window.openai with new values
|
|
7761
|
+
if (payload.theme !== undefined) {
|
|
7762
|
+
window.openai.theme = payload.theme;
|
|
7763
|
+
// Also set data-theme attribute for CSS theming
|
|
7764
|
+
document.documentElement.dataset.theme = payload.theme;
|
|
7765
|
+
}
|
|
7766
|
+
if (payload.displayMode !== undefined) window.openai.displayMode = payload.displayMode;
|
|
7767
|
+
if (payload.locale !== undefined) window.openai.locale = payload.locale;
|
|
7768
|
+
if (payload.maxHeight !== undefined) window.openai.maxHeight = payload.maxHeight;
|
|
7769
|
+
if (payload.userAgent !== undefined) window.openai.userAgent = payload.userAgent;
|
|
7770
|
+
if (payload.safeArea !== undefined) window.openai.safeArea = payload.safeArea;
|
|
7771
|
+
if (payload.view !== undefined) window.openai.view = payload.view;
|
|
7772
|
+
if (payload.toolInput !== undefined) window.openai.toolInput = payload.toolInput;
|
|
7773
|
+
if (payload.toolOutput !== undefined) window.openai.toolOutput = payload.toolOutput;
|
|
7774
|
+
if (payload.toolResponseMetadata !== undefined) window.openai.toolResponseMetadata = payload.toolResponseMetadata;
|
|
7775
|
+
if (payload.widgetState !== undefined) window.openai.widgetState = payload.widgetState;
|
|
7776
|
+
|
|
7777
|
+
// Dispatch custom event so widgets can react to changes
|
|
7778
|
+
// Must match SET_GLOBALS_EVENT_TYPE ('openai:set_globals') in providers/openai/types.ts
|
|
7779
|
+
window.dispatchEvent(new CustomEvent('openai:set_globals', { detail: { globals: payload } }));
|
|
7780
|
+
}
|
|
7781
|
+
}
|
|
7782
|
+
|
|
7783
|
+
// Listen for handshake message from parent (transfers MessagePort)
|
|
7784
|
+
window.addEventListener('message', function(event) {
|
|
7785
|
+
// Strict source validation: only accept messages from parent window
|
|
7786
|
+
if (event.source !== window.parent) {
|
|
7787
|
+
console.warn('[IframeBridge] Rejected message from non-parent source');
|
|
7788
|
+
return;
|
|
7789
|
+
}
|
|
7790
|
+
|
|
7791
|
+
// Validate message origin (allows localhost with any port)
|
|
7792
|
+
if (!isAllowedOrigin(event.origin)) {
|
|
7793
|
+
console.warn('[IframeBridge] Rejected message from untrusted origin:', event.origin);
|
|
7794
|
+
return;
|
|
7795
|
+
}
|
|
7796
|
+
|
|
7797
|
+
// Handle handshake with MessagePort transfer
|
|
7798
|
+
if (event.data && event.data.type === 'openai:handshake' && event.ports && event.ports.length > 0) {
|
|
7799
|
+
messagePort = event.ports[0];
|
|
7800
|
+
messagePort.onmessage = handlePortMessage;
|
|
7801
|
+
messagePort.start();
|
|
7802
|
+
|
|
7803
|
+
// Flush any queued messages
|
|
7804
|
+
flushMessageQueue();
|
|
7805
|
+
|
|
7806
|
+
// Confirm handshake complete
|
|
7807
|
+
sendToParent({ type: 'openai:handshake_complete' });
|
|
7808
|
+
}
|
|
7809
|
+
});
|
|
7810
|
+
|
|
7811
|
+
// Signal to parent that we're ready for handshake
|
|
7812
|
+
window.parent.postMessage({ type: 'openai:ready' }, '*');
|
|
7813
|
+
|
|
7814
|
+
// Auto-measure and report content height immediately
|
|
7815
|
+
var lastHeight = 0;
|
|
7816
|
+
var pendingFrame = null;
|
|
7817
|
+
function reportHeight() {
|
|
7818
|
+
var height = document.documentElement.scrollHeight || document.body.scrollHeight;
|
|
7819
|
+
if (height > 0 && height !== lastHeight) {
|
|
7820
|
+
lastHeight = height;
|
|
7821
|
+
window.openai.notifyIntrinsicHeight(height);
|
|
7822
|
+
}
|
|
7823
|
+
}
|
|
7824
|
+
|
|
7825
|
+
// Schedule height report on next animation frame (batches rapid changes)
|
|
7826
|
+
function scheduleHeightReport() {
|
|
7827
|
+
if (pendingFrame) return;
|
|
7828
|
+
pendingFrame = requestAnimationFrame(function() {
|
|
7829
|
+
pendingFrame = null;
|
|
7830
|
+
reportHeight();
|
|
7831
|
+
});
|
|
7832
|
+
}
|
|
7833
|
+
|
|
7834
|
+
// Report height immediately when ready
|
|
7835
|
+
if (document.readyState === 'complete') {
|
|
7836
|
+
reportHeight();
|
|
7837
|
+
} else {
|
|
7838
|
+
window.addEventListener('load', reportHeight);
|
|
7839
|
+
}
|
|
7840
|
+
|
|
7841
|
+
// Use ResizeObserver to track size changes
|
|
7842
|
+
if (typeof ResizeObserver !== 'undefined') {
|
|
7843
|
+
var resizeObserver = new ResizeObserver(function() {
|
|
7844
|
+
scheduleHeightReport();
|
|
7845
|
+
});
|
|
7846
|
+
function observeElements() {
|
|
7847
|
+
if (document.body) resizeObserver.observe(document.body);
|
|
7848
|
+
if (document.documentElement) resizeObserver.observe(document.documentElement);
|
|
7849
|
+
// Also observe the root element if it exists
|
|
7850
|
+
var root = document.getElementById('root');
|
|
7851
|
+
if (root) resizeObserver.observe(root);
|
|
7852
|
+
}
|
|
7853
|
+
if (document.body) {
|
|
7854
|
+
observeElements();
|
|
7855
|
+
} else {
|
|
7856
|
+
document.addEventListener('DOMContentLoaded', observeElements);
|
|
7857
|
+
}
|
|
7858
|
+
}
|
|
7859
|
+
|
|
7860
|
+
// Use MutationObserver to detect DOM changes that may affect height
|
|
7861
|
+
if (typeof MutationObserver !== 'undefined') {
|
|
7862
|
+
var mutationObserver = new MutationObserver(function() {
|
|
7863
|
+
scheduleHeightReport();
|
|
7864
|
+
});
|
|
7865
|
+
function observeMutations() {
|
|
7866
|
+
mutationObserver.observe(document.body, {
|
|
7867
|
+
childList: true,
|
|
7868
|
+
subtree: true,
|
|
7869
|
+
attributes: true,
|
|
7870
|
+
characterData: true
|
|
7871
|
+
});
|
|
7872
|
+
}
|
|
7873
|
+
if (document.body) {
|
|
7874
|
+
observeMutations();
|
|
7875
|
+
} else {
|
|
7876
|
+
document.addEventListener('DOMContentLoaded', observeMutations);
|
|
7877
|
+
}
|
|
7878
|
+
}
|
|
7879
|
+
})();
|
|
7880
|
+
<\/script>
|
|
7881
|
+
`;
|
|
7882
|
+
}
|
|
7883
|
+
function generateScriptHtml(scriptSrc, theme, cspPolicy) {
|
|
7884
|
+
const safeScriptSrc = escapeHtml(scriptSrc);
|
|
7885
|
+
const safeCsp = escapeHtml(cspPolicy);
|
|
7886
|
+
return `<!DOCTYPE html>
|
|
7887
|
+
<html lang="en" data-theme="${theme}">
|
|
7888
|
+
<head>
|
|
7889
|
+
<meta charset="UTF-8" />
|
|
7890
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7891
|
+
<meta http-equiv="Content-Security-Policy" content="${safeCsp}" />
|
|
7892
|
+
<title>Resource</title>
|
|
7893
|
+
<style>
|
|
7894
|
+
html, body, #root {
|
|
7895
|
+
margin: 0;
|
|
7896
|
+
padding: 0;
|
|
7897
|
+
height: 100%;
|
|
7898
|
+
width: 100%;
|
|
7899
|
+
}
|
|
7900
|
+
body {
|
|
7901
|
+
background: transparent;
|
|
7902
|
+
}
|
|
7903
|
+
</style>
|
|
7904
|
+
</head>
|
|
7905
|
+
<body>
|
|
7906
|
+
<div id="root"></div>
|
|
7907
|
+
<script src="${safeScriptSrc}"><\/script>
|
|
7908
|
+
</body>
|
|
7909
|
+
</html>`;
|
|
7910
|
+
}
|
|
7911
|
+
function injectBridgeScript(htmlContent, bridgeScript) {
|
|
7912
|
+
const headMatch = htmlContent.match(/<head[^>]*>/i);
|
|
7913
|
+
if (headMatch) {
|
|
7914
|
+
const insertPos = headMatch.index + headMatch[0].length;
|
|
7915
|
+
return htmlContent.slice(0, insertPos) + bridgeScript + htmlContent.slice(insertPos);
|
|
7916
|
+
}
|
|
7917
|
+
const doctypeMatch = htmlContent.match(/<!DOCTYPE[^>]*>/i);
|
|
7918
|
+
if (doctypeMatch) {
|
|
7919
|
+
const insertPos = doctypeMatch.index + doctypeMatch[0].length;
|
|
7920
|
+
return htmlContent.slice(0, insertPos) + bridgeScript + htmlContent.slice(insertPos);
|
|
7921
|
+
}
|
|
7922
|
+
return bridgeScript + htmlContent;
|
|
7923
|
+
}
|
|
7924
|
+
function IframeResource({ scriptSrc, className, style, csp }) {
|
|
7925
|
+
const iframeRef = React.useRef(null);
|
|
7926
|
+
const messageChannelRef = React.useRef(null);
|
|
7927
|
+
const messagePortRef = React.useRef(null);
|
|
7928
|
+
const [isHeightReady, setIsHeightReady] = React__namespace.useState(false);
|
|
7929
|
+
React__namespace.useEffect(() => {
|
|
7930
|
+
setIsHeightReady(false);
|
|
7931
|
+
const timeout = setTimeout(() => {
|
|
7932
|
+
setIsHeightReady(true);
|
|
7933
|
+
}, 500);
|
|
7934
|
+
return () => clearTimeout(timeout);
|
|
7935
|
+
}, [scriptSrc]);
|
|
7936
|
+
const theme = useTheme();
|
|
7937
|
+
const displayMode = useDisplayMode();
|
|
7938
|
+
const locale = useLocale();
|
|
7939
|
+
const maxHeight = useMaxHeight();
|
|
7940
|
+
const userAgent = useUserAgent();
|
|
7941
|
+
const safeArea = useSafeArea();
|
|
7942
|
+
const view = useView();
|
|
7943
|
+
const toolInput = useToolInput();
|
|
7944
|
+
const toolOutput = useWidgetProps();
|
|
7945
|
+
const toolResponseMetadata = useToolResponseMetadata();
|
|
7946
|
+
const [widgetState] = useWidgetState();
|
|
7947
|
+
const currentState = React__namespace.useMemo(
|
|
7948
|
+
() => ({
|
|
7949
|
+
theme,
|
|
7950
|
+
displayMode,
|
|
7951
|
+
locale,
|
|
7952
|
+
maxHeight,
|
|
7953
|
+
userAgent,
|
|
7954
|
+
safeArea,
|
|
7955
|
+
view,
|
|
7956
|
+
toolInput,
|
|
7957
|
+
toolOutput,
|
|
7958
|
+
toolResponseMetadata,
|
|
7959
|
+
widgetState
|
|
7960
|
+
}),
|
|
7961
|
+
[
|
|
7962
|
+
theme,
|
|
7963
|
+
displayMode,
|
|
7964
|
+
locale,
|
|
7965
|
+
maxHeight,
|
|
7966
|
+
userAgent,
|
|
7967
|
+
safeArea,
|
|
7968
|
+
view,
|
|
7969
|
+
toolInput,
|
|
7970
|
+
toolOutput,
|
|
7971
|
+
toolResponseMetadata,
|
|
7972
|
+
widgetState
|
|
7973
|
+
]
|
|
7974
|
+
);
|
|
7975
|
+
const sendUpdate = React.useCallback(
|
|
7976
|
+
(type) => {
|
|
7977
|
+
const port = messagePortRef.current;
|
|
7978
|
+
if (port) {
|
|
7979
|
+
const message = {
|
|
7980
|
+
type,
|
|
7981
|
+
payload: currentState
|
|
7982
|
+
};
|
|
7983
|
+
port.postMessage(message);
|
|
7984
|
+
}
|
|
7985
|
+
},
|
|
7986
|
+
[currentState]
|
|
7987
|
+
);
|
|
7988
|
+
const sendUpdateRef = React.useRef(sendUpdate);
|
|
7989
|
+
React.useEffect(() => {
|
|
7990
|
+
sendUpdateRef.current = sendUpdate;
|
|
7991
|
+
}, [sendUpdate]);
|
|
7992
|
+
const handlePortMessage = React.useCallback(
|
|
7993
|
+
(event) => {
|
|
7994
|
+
var _a2, _b2;
|
|
7995
|
+
if (!event.data || typeof event.data !== "object" || typeof event.data.type !== "string") {
|
|
7996
|
+
return;
|
|
7997
|
+
}
|
|
7998
|
+
const { type } = event.data;
|
|
7999
|
+
switch (type) {
|
|
8000
|
+
case "openai:handshake_complete":
|
|
8001
|
+
sendUpdateRef.current("openai:init");
|
|
8002
|
+
break;
|
|
8003
|
+
case "openai:requestDisplayMode": {
|
|
8004
|
+
const payload = event.data.payload;
|
|
8005
|
+
if (!payload || typeof payload !== "object" || !("mode" in payload) || typeof payload.mode !== "string") {
|
|
8006
|
+
console.warn("[IframeResource] Invalid requestDisplayMode payload");
|
|
8007
|
+
return;
|
|
8008
|
+
}
|
|
8009
|
+
const validModes = ["inline", "pip", "fullscreen"];
|
|
8010
|
+
const mode = payload.mode;
|
|
8011
|
+
if (!validModes.includes(mode)) {
|
|
8012
|
+
console.warn("[IframeResource] Invalid display mode:", mode);
|
|
8013
|
+
return;
|
|
8014
|
+
}
|
|
8015
|
+
if (typeof window !== "undefined" && ((_a2 = window.openai) == null ? void 0 : _a2.requestDisplayMode)) {
|
|
8016
|
+
window.openai.requestDisplayMode({ mode });
|
|
8017
|
+
}
|
|
8018
|
+
break;
|
|
8019
|
+
}
|
|
8020
|
+
case "openai:setWidgetState": {
|
|
8021
|
+
const payload = event.data.payload;
|
|
8022
|
+
if (payload !== null && (typeof payload !== "object" || Array.isArray(payload))) {
|
|
8023
|
+
console.warn("[IframeResource] Invalid widgetState payload");
|
|
8024
|
+
return;
|
|
8025
|
+
}
|
|
8026
|
+
if (typeof window !== "undefined" && ((_b2 = window.openai) == null ? void 0 : _b2.setWidgetState)) {
|
|
8027
|
+
window.openai.setWidgetState(payload);
|
|
8028
|
+
}
|
|
8029
|
+
break;
|
|
8030
|
+
}
|
|
8031
|
+
case "openai:notifyIntrinsicHeight": {
|
|
8032
|
+
const payload = event.data.payload;
|
|
8033
|
+
if (!payload || typeof payload !== "object" || !("height" in payload) || typeof payload.height !== "number") {
|
|
8034
|
+
console.warn("[IframeResource] Invalid notifyIntrinsicHeight payload");
|
|
8035
|
+
return;
|
|
8036
|
+
}
|
|
8037
|
+
const height = payload.height;
|
|
8038
|
+
if (height <= 0 || height > 1e5) {
|
|
8039
|
+
console.warn("[IframeResource] Height out of range:", height);
|
|
8040
|
+
return;
|
|
8041
|
+
}
|
|
8042
|
+
if (iframeRef.current) {
|
|
8043
|
+
iframeRef.current.style.height = `${height}px`;
|
|
8044
|
+
}
|
|
8045
|
+
break;
|
|
8046
|
+
}
|
|
8047
|
+
case "openai:callTool":
|
|
8048
|
+
case "openai:sendFollowUpMessage":
|
|
8049
|
+
case "openai:openExternal":
|
|
8050
|
+
case "openai:requestModal":
|
|
8051
|
+
console.log(`[IframeResource] Received ${type}:`, event.data.payload);
|
|
8052
|
+
break;
|
|
8053
|
+
}
|
|
8054
|
+
},
|
|
8055
|
+
[]
|
|
8056
|
+
// No dependencies - uses refs for changing values
|
|
8057
|
+
);
|
|
8058
|
+
React.useEffect(() => {
|
|
8059
|
+
const handleMessage = (event) => {
|
|
8060
|
+
if (iframeRef.current && event.source !== iframeRef.current.contentWindow) {
|
|
8061
|
+
return;
|
|
8062
|
+
}
|
|
8063
|
+
if (!event.data || typeof event.data !== "object" || typeof event.data.type !== "string") {
|
|
8064
|
+
return;
|
|
8065
|
+
}
|
|
8066
|
+
if (event.data.type === "openai:ready") {
|
|
8067
|
+
const channel = new MessageChannel();
|
|
8068
|
+
messageChannelRef.current = channel;
|
|
8069
|
+
messagePortRef.current = channel.port1;
|
|
8070
|
+
channel.port1.onmessage = handlePortMessage;
|
|
8071
|
+
channel.port1.start();
|
|
8072
|
+
const iframe = iframeRef.current;
|
|
8073
|
+
if (iframe == null ? void 0 : iframe.contentWindow) {
|
|
8074
|
+
iframe.contentWindow.postMessage({ type: "openai:handshake" }, "*", [channel.port2]);
|
|
8075
|
+
}
|
|
8076
|
+
}
|
|
8077
|
+
if (event.data.type === "openai:notifyIntrinsicHeight") {
|
|
8078
|
+
const payload = event.data.payload;
|
|
8079
|
+
if (!payload || typeof payload !== "object" || !("height" in payload) || typeof payload.height !== "number") {
|
|
8080
|
+
return;
|
|
8081
|
+
}
|
|
8082
|
+
const height = payload.height;
|
|
8083
|
+
if (height <= 0 || height > 1e5) {
|
|
8084
|
+
return;
|
|
8085
|
+
}
|
|
8086
|
+
if (iframeRef.current) {
|
|
8087
|
+
iframeRef.current.style.height = `${height}px`;
|
|
8088
|
+
setIsHeightReady(true);
|
|
8089
|
+
}
|
|
8090
|
+
}
|
|
8091
|
+
};
|
|
8092
|
+
window.addEventListener("message", handleMessage);
|
|
8093
|
+
return () => {
|
|
8094
|
+
window.removeEventListener("message", handleMessage);
|
|
8095
|
+
if (messagePortRef.current) {
|
|
8096
|
+
messagePortRef.current.close();
|
|
8097
|
+
}
|
|
8098
|
+
};
|
|
8099
|
+
}, [handlePortMessage]);
|
|
8100
|
+
React.useEffect(() => {
|
|
8101
|
+
sendUpdate("openai:update");
|
|
8102
|
+
}, [sendUpdate]);
|
|
8103
|
+
const isValidScriptSrc = React.useMemo(() => isAllowedScriptSrc(scriptSrc), [scriptSrc]);
|
|
8104
|
+
const blobUrl = React.useMemo(() => {
|
|
8105
|
+
if (!isValidScriptSrc) {
|
|
8106
|
+
console.error("[IframeResource] Script source not allowed:", scriptSrc);
|
|
8107
|
+
const errorHtml = `<!DOCTYPE html><html><body><h1>Error</h1><p>Script source not allowed.</p></body></html>`;
|
|
8108
|
+
const blob2 = new Blob([errorHtml], { type: "text/html" });
|
|
8109
|
+
return URL.createObjectURL(blob2);
|
|
8110
|
+
}
|
|
8111
|
+
const absoluteScriptSrc = scriptSrc.startsWith("/") ? `${window.location.origin}${scriptSrc}` : scriptSrc;
|
|
8112
|
+
const cspPolicy = generateCSP(csp, absoluteScriptSrc);
|
|
8113
|
+
const bridgeScript = generateBridgeScript(ALLOWED_PARENT_ORIGINS);
|
|
8114
|
+
const html = injectBridgeScript(
|
|
8115
|
+
generateScriptHtml(absoluteScriptSrc, theme ?? "dark", cspPolicy),
|
|
8116
|
+
bridgeScript
|
|
8117
|
+
);
|
|
8118
|
+
const blob = new Blob([html], { type: "text/html" });
|
|
8119
|
+
return URL.createObjectURL(blob);
|
|
8120
|
+
}, [scriptSrc, theme, isValidScriptSrc, csp]);
|
|
8121
|
+
React.useEffect(() => {
|
|
8122
|
+
return () => URL.revokeObjectURL(blobUrl);
|
|
8123
|
+
}, [blobUrl]);
|
|
8124
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
8125
|
+
"iframe",
|
|
8126
|
+
{
|
|
8127
|
+
ref: iframeRef,
|
|
8128
|
+
src: blobUrl,
|
|
8129
|
+
className,
|
|
8130
|
+
style: {
|
|
8131
|
+
border: "none",
|
|
8132
|
+
width: "100%",
|
|
8133
|
+
height: "100%",
|
|
8134
|
+
// Hide until first height update to prevent flash of incorrect size
|
|
8135
|
+
opacity: isHeightReady ? 1 : 0,
|
|
8136
|
+
transition: "opacity 0.1s ease-in",
|
|
8137
|
+
...style
|
|
8138
|
+
},
|
|
8139
|
+
title: "Resource Preview",
|
|
8140
|
+
sandbox: "allow-scripts",
|
|
8141
|
+
allow: "accelerometer 'none'; autoplay 'none'; camera 'none'; display-capture 'none'; geolocation 'none'; gyroscope 'none'; magnetometer 'none'; microphone 'none'; midi 'none'; payment 'none'; publickey-credentials-get 'none'; usb 'none'; xr-spatial-tracking 'none'"
|
|
8142
|
+
}
|
|
8143
|
+
);
|
|
8144
|
+
}
|
|
7563
8145
|
function Conversation({
|
|
7564
8146
|
children,
|
|
8147
|
+
iframeScriptSrc,
|
|
7565
8148
|
screenWidth,
|
|
7566
8149
|
appName = "Sunpeak",
|
|
7567
8150
|
appIcon,
|
|
@@ -7573,6 +8156,8 @@ function Conversation({
|
|
|
7573
8156
|
const userAgent = useUserAgent();
|
|
7574
8157
|
const isDesktop = (userAgent == null ? void 0 : userAgent.device.type) === "desktop";
|
|
7575
8158
|
const containerWidth = screenWidth === "full" ? "100%" : `${SCREEN_WIDTHS[screenWidth]}px`;
|
|
8159
|
+
const widgetCSP = resourceMeta == null ? void 0 : resourceMeta["openai/widgetCSP"];
|
|
8160
|
+
const content = iframeScriptSrc ? /* @__PURE__ */ jsxRuntime.jsx(IframeResource, { scriptSrc: iframeScriptSrc, className: "h-full w-full", csp: widgetCSP }) : children;
|
|
7576
8161
|
if (displayMode === "fullscreen") {
|
|
7577
8162
|
const handleClose = () => {
|
|
7578
8163
|
if (api == null ? void 0 : api.requestDisplayMode) {
|
|
@@ -7622,7 +8207,7 @@ function Conversation({
|
|
|
7622
8207
|
}
|
|
7623
8208
|
) })
|
|
7624
8209
|
] }),
|
|
7625
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative overflow-hidden flex-1 min-h-0", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full w-full max-w-full overflow-auto", children }) }),
|
|
8210
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative overflow-hidden flex-1 min-h-0", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full w-full max-w-full overflow-auto", children: content }) }),
|
|
7626
8211
|
/* @__PURE__ */ jsxRuntime.jsx("footer", { className: "bg-surface", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-[48rem] mx-auto px-4 py-4", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
7627
8212
|
"input",
|
|
7628
8213
|
{
|
|
@@ -7712,10 +8297,10 @@ function Conversation({
|
|
|
7712
8297
|
children: /* @__PURE__ */ jsxRuntime.jsx(CloseBold, { className: "h-4 w-4" })
|
|
7713
8298
|
}
|
|
7714
8299
|
),
|
|
7715
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative overflow-hidden h-full rounded-2xl sm:rounded-3xl shadow-[0px_0px_0px_1px_#fff3,0px_6px_20px_rgba(0,0,0,0.1)] md:-mx-4", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full w-full max-w-full overflow-auto bg-white dark:bg-[#212121]", children }) })
|
|
8300
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative overflow-hidden h-full rounded-2xl sm:rounded-3xl shadow-[0px_0px_0px_1px_#fff3,0px_6px_20px_rgba(0,0,0,0.1)] md:-mx-4", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full w-full max-w-full overflow-auto bg-white dark:bg-[#212121]", children: content }) })
|
|
7716
8301
|
]
|
|
7717
8302
|
}
|
|
7718
|
-
) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "no-scrollbar relative mb-2 @w-sm/main:w-full mx-0 max-sm:-mx-[1rem] max-sm:w-[100cqw] max-sm:overflow-hidden overflow-visible", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative overflow-hidden h-full", children }) }) })
|
|
8303
|
+
) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "no-scrollbar relative mb-2 @w-sm/main:w-full mx-0 max-sm:-mx-[1rem] max-sm:w-[100cqw] max-sm:overflow-hidden overflow-visible", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative overflow-hidden h-full", children: content }) }) })
|
|
7719
8304
|
}
|
|
7720
8305
|
)
|
|
7721
8306
|
] }) }) })
|
|
@@ -8131,6 +8716,7 @@ function ChatGPTSimulator({
|
|
|
8131
8716
|
}
|
|
8132
8717
|
};
|
|
8133
8718
|
const SelectedComponent = selectedSim == null ? void 0 : selectedSim.resourceComponent;
|
|
8719
|
+
const iframeScriptSrc = !SelectedComponent ? selectedSim == null ? void 0 : selectedSim.resourceScript : void 0;
|
|
8134
8720
|
const content = SelectedComponent ? /* @__PURE__ */ jsxRuntime.jsx(SelectedComponent, {}) : children;
|
|
8135
8721
|
return /* @__PURE__ */ jsxRuntime.jsx(ThemeProvider, { theme, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
8136
8722
|
SimpleSidebar,
|
|
@@ -8465,6 +9051,7 @@ function ChatGPTSimulator({
|
|
|
8465
9051
|
appIcon,
|
|
8466
9052
|
userMessage,
|
|
8467
9053
|
resourceMeta: selectedSim == null ? void 0 : selectedSim.resource._meta,
|
|
9054
|
+
iframeScriptSrc,
|
|
8468
9055
|
children: content
|
|
8469
9056
|
},
|
|
8470
9057
|
selectedSimulationName
|
|
@@ -8517,6 +9104,7 @@ function createSimulatorUrl(params, basePath = "/") {
|
|
|
8517
9104
|
return queryString ? `${basePath}?${queryString}` : basePath;
|
|
8518
9105
|
}
|
|
8519
9106
|
exports.ChatGPTSimulator = ChatGPTSimulator;
|
|
9107
|
+
exports.IframeResource = IframeResource;
|
|
8520
9108
|
exports.SCREEN_WIDTHS = SCREEN_WIDTHS;
|
|
8521
9109
|
exports.ThemeProvider = ThemeProvider;
|
|
8522
9110
|
exports.clsx = clsx;
|
|
@@ -8542,4 +9130,4 @@ exports.useWidgetAPI = useWidgetAPI;
|
|
|
8542
9130
|
exports.useWidgetGlobal = useWidgetGlobal;
|
|
8543
9131
|
exports.useWidgetProps = useWidgetProps;
|
|
8544
9132
|
exports.useWidgetState = useWidgetState;
|
|
8545
|
-
//# sourceMappingURL=simulator-url-
|
|
9133
|
+
//# sourceMappingURL=simulator-url-BStCoFTv.cjs.map
|