@morphllm/morphsdk 0.2.116 → 0.2.117
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-SITZC3U6.js → chunk-5IVVJMMX.js} +2 -2
- package/dist/{chunk-62OVBE6G.js → chunk-C3LJORIT.js} +2 -2
- package/dist/{chunk-QOEZARHG.js → chunk-EAT5W3SH.js} +2 -2
- package/dist/{chunk-25APYVON.js → chunk-PR44LEQQ.js} +2 -2
- package/dist/{chunk-Q6Y4R236.js → chunk-YTYCHRQ2.js} +7 -9
- package/dist/{chunk-Q6Y4R236.js.map → chunk-YTYCHRQ2.js.map} +1 -1
- package/dist/{chunk-4IOC2D5Y.js → chunk-ZYPLV3HP.js} +2 -2
- package/dist/client.cjs +6 -8
- package/dist/client.cjs.map +1 -1
- package/dist/client.js +3 -3
- package/dist/index.cjs +6 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +3 -3
- package/dist/tools/browser/anthropic.js +3 -3
- package/dist/tools/browser/core.cjs +6 -8
- package/dist/tools/browser/core.cjs.map +1 -1
- package/dist/tools/browser/core.js +2 -2
- package/dist/tools/browser/index.cjs +6 -8
- package/dist/tools/browser/index.cjs.map +1 -1
- package/dist/tools/browser/index.js +5 -5
- package/dist/tools/browser/live.cjs +6 -8
- package/dist/tools/browser/live.cjs.map +1 -1
- package/dist/tools/browser/live.js +1 -1
- package/dist/tools/browser/openai.js +3 -3
- package/dist/tools/browser/vercel.js +3 -3
- package/package.json +1 -1
- /package/dist/{chunk-SITZC3U6.js.map → chunk-5IVVJMMX.js.map} +0 -0
- /package/dist/{chunk-62OVBE6G.js.map → chunk-C3LJORIT.js.map} +0 -0
- /package/dist/{chunk-QOEZARHG.js.map → chunk-EAT5W3SH.js.map} +0 -0
- /package/dist/{chunk-25APYVON.js.map → chunk-PR44LEQQ.js.map} +0 -0
- /package/dist/{chunk-4IOC2D5Y.js.map → chunk-ZYPLV3HP.js.map} +0 -0
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
} from "./chunk-2HMEZZKK.js";
|
|
5
5
|
import {
|
|
6
6
|
executeBrowserTask
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-ZYPLV3HP.js";
|
|
8
8
|
import {
|
|
9
9
|
__export
|
|
10
10
|
} from "./chunk-PZ5AY32C.js";
|
|
@@ -93,4 +93,4 @@ export {
|
|
|
93
93
|
createBrowserTool,
|
|
94
94
|
openai_exports
|
|
95
95
|
};
|
|
96
|
-
//# sourceMappingURL=chunk-
|
|
96
|
+
//# sourceMappingURL=chunk-5IVVJMMX.js.map
|
|
@@ -36,7 +36,7 @@ import {
|
|
|
36
36
|
} from "./chunk-M5DR2WOZ.js";
|
|
37
37
|
import {
|
|
38
38
|
BrowserClient
|
|
39
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-ZYPLV3HP.js";
|
|
40
40
|
import {
|
|
41
41
|
MorphGit
|
|
42
42
|
} from "./chunk-LE66XCOI.js";
|
|
@@ -643,4 +643,4 @@ export {
|
|
|
643
643
|
VercelToolFactory,
|
|
644
644
|
MorphClient
|
|
645
645
|
};
|
|
646
|
-
//# sourceMappingURL=chunk-
|
|
646
|
+
//# sourceMappingURL=chunk-C3LJORIT.js.map
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
} from "./chunk-2HMEZZKK.js";
|
|
5
5
|
import {
|
|
6
6
|
executeBrowserTask
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-ZYPLV3HP.js";
|
|
8
8
|
import {
|
|
9
9
|
__export
|
|
10
10
|
} from "./chunk-PZ5AY32C.js";
|
|
@@ -77,4 +77,4 @@ export {
|
|
|
77
77
|
createBrowserTool,
|
|
78
78
|
anthropic_exports
|
|
79
79
|
};
|
|
80
|
-
//# sourceMappingURL=chunk-
|
|
80
|
+
//# sourceMappingURL=chunk-EAT5W3SH.js.map
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
} from "./chunk-2HMEZZKK.js";
|
|
4
4
|
import {
|
|
5
5
|
executeBrowserTask
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-ZYPLV3HP.js";
|
|
7
7
|
import {
|
|
8
8
|
__export
|
|
9
9
|
} from "./chunk-PZ5AY32C.js";
|
|
@@ -54,4 +54,4 @@ export {
|
|
|
54
54
|
browserTool,
|
|
55
55
|
vercel_exports
|
|
56
56
|
};
|
|
57
|
-
//# sourceMappingURL=chunk-
|
|
57
|
+
//# sourceMappingURL=chunk-PR44LEQQ.js.map
|
|
@@ -32,13 +32,14 @@ function buildLiveUrl(debugUrl, options = {}) {
|
|
|
32
32
|
}
|
|
33
33
|
return url.toString();
|
|
34
34
|
}
|
|
35
|
+
function cdpToHttps(wsUrl) {
|
|
36
|
+
return wsUrl.replace(/^wss:\/\//, "https://").replace(/^ws:\/\//, "http://");
|
|
37
|
+
}
|
|
35
38
|
function normalizeLiveUrl(debugUrl) {
|
|
36
39
|
const trimmed = debugUrl.trim();
|
|
37
|
-
if (!trimmed)
|
|
38
|
-
return trimmed;
|
|
39
|
-
}
|
|
40
|
+
if (!trimmed) return trimmed;
|
|
40
41
|
if (trimmed.startsWith("wss://") || trimmed.startsWith("ws://")) {
|
|
41
|
-
return `https://live.browser-use.com?wss=${encodeURIComponent(trimmed)}`;
|
|
42
|
+
return `https://live.browser-use.com?wss=${encodeURIComponent(cdpToHttps(trimmed))}`;
|
|
42
43
|
}
|
|
43
44
|
let url;
|
|
44
45
|
try {
|
|
@@ -46,12 +47,9 @@ function normalizeLiveUrl(debugUrl) {
|
|
|
46
47
|
} catch {
|
|
47
48
|
return trimmed;
|
|
48
49
|
}
|
|
49
|
-
if (url.protocol === "wss:" || url.protocol === "ws:") {
|
|
50
|
-
return `https://live.browser-use.com?wss=${encodeURIComponent(trimmed)}`;
|
|
51
|
-
}
|
|
52
50
|
const wssParam = url.searchParams.get("wss");
|
|
53
51
|
if (wssParam && (wssParam.startsWith("wss://") || wssParam.startsWith("ws://"))) {
|
|
54
|
-
url.searchParams.set("wss", wssParam);
|
|
52
|
+
url.searchParams.set("wss", cdpToHttps(wssParam));
|
|
55
53
|
}
|
|
56
54
|
return url.toString();
|
|
57
55
|
}
|
|
@@ -105,4 +103,4 @@ export {
|
|
|
105
103
|
buildEmbedCode,
|
|
106
104
|
resolvePreset
|
|
107
105
|
};
|
|
108
|
-
//# sourceMappingURL=chunk-
|
|
106
|
+
//# sourceMappingURL=chunk-YTYCHRQ2.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../tools/browser/live.ts"],"sourcesContent":["/**\n * Live session utilities for Morph browser sessions\n * \n * Provides helpers for embedding and sharing live browser sessions with WebRTC streaming.\n */\n\nimport type { LiveSessionOptions, IframeOptions } from './types.js';\n\n/**\n * Preset configurations for common use cases\n */\nexport const LIVE_PRESETS = {\n /** Read-only monitoring (no interaction) */\n readonly: { interactive: false } as LiveSessionOptions,\n /** Interactive control (human-in-the-loop) */\n interactive: { interactive: true } as LiveSessionOptions,\n /** Watch-only without controls */\n monitoring: { interactive: false, showControls: false } as LiveSessionOptions,\n} as const;\n\n/**\n * Build a live session URL with query parameters\n * \n * @param debugUrl - Live session debug URL (e.g., from task.debugUrl)\n * @param options - Live session configuration options\n * @returns URL with query parameters for iframe embedding\n * \n * @example\n * ```typescript\n * const url = buildLiveUrl(task.debugUrl, { interactive: true });\n * // Returns: https://example.com/sessions/abc?interactive=true\n * ```\n */\nexport function buildLiveUrl(\n debugUrl: string,\n options: LiveSessionOptions = {}\n): string {\n if (!debugUrl) {\n throw new Error(\n 'debugUrl is required. Ensure your backend returns debugUrl in the task response. ' +\n 'Contact support@morphllm.com if you need help.'\n );\n }\n\n const normalized = normalizeLiveUrl(debugUrl);\n const url = new URL(normalized);\n \n // Add query parameters for supported options\n if (options.interactive !== undefined) {\n url.searchParams.set('interactive', String(options.interactive));\n }\n \n if (options.theme) {\n url.searchParams.set('theme', options.theme);\n }\n \n if (options.showControls !== undefined) {\n url.searchParams.set('showControls', String(options.showControls));\n }\n \n if (options.pageId) {\n url.searchParams.set('pageId', options.pageId);\n }\n \n if (options.pageIndex) {\n url.searchParams.set('pageIndex', options.pageIndex);\n }\n \n return url.toString();\n}\n\nfunction normalizeLiveUrl(debugUrl: string): string {\n const trimmed = debugUrl.trim();\n if (!trimmed)
|
|
1
|
+
{"version":3,"sources":["../tools/browser/live.ts"],"sourcesContent":["/**\n * Live session utilities for Morph browser sessions\n * \n * Provides helpers for embedding and sharing live browser sessions with WebRTC streaming.\n */\n\nimport type { LiveSessionOptions, IframeOptions } from './types.js';\n\n/**\n * Preset configurations for common use cases\n */\nexport const LIVE_PRESETS = {\n /** Read-only monitoring (no interaction) */\n readonly: { interactive: false } as LiveSessionOptions,\n /** Interactive control (human-in-the-loop) */\n interactive: { interactive: true } as LiveSessionOptions,\n /** Watch-only without controls */\n monitoring: { interactive: false, showControls: false } as LiveSessionOptions,\n} as const;\n\n/**\n * Build a live session URL with query parameters\n * \n * @param debugUrl - Live session debug URL (e.g., from task.debugUrl)\n * @param options - Live session configuration options\n * @returns URL with query parameters for iframe embedding\n * \n * @example\n * ```typescript\n * const url = buildLiveUrl(task.debugUrl, { interactive: true });\n * // Returns: https://example.com/sessions/abc?interactive=true\n * ```\n */\nexport function buildLiveUrl(\n debugUrl: string,\n options: LiveSessionOptions = {}\n): string {\n if (!debugUrl) {\n throw new Error(\n 'debugUrl is required. Ensure your backend returns debugUrl in the task response. ' +\n 'Contact support@morphllm.com if you need help.'\n );\n }\n\n const normalized = normalizeLiveUrl(debugUrl);\n const url = new URL(normalized);\n \n // Add query parameters for supported options\n if (options.interactive !== undefined) {\n url.searchParams.set('interactive', String(options.interactive));\n }\n \n if (options.theme) {\n url.searchParams.set('theme', options.theme);\n }\n \n if (options.showControls !== undefined) {\n url.searchParams.set('showControls', String(options.showControls));\n }\n \n if (options.pageId) {\n url.searchParams.set('pageId', options.pageId);\n }\n \n if (options.pageIndex) {\n url.searchParams.set('pageIndex', options.pageIndex);\n }\n \n return url.toString();\n}\n\n/**\n * Convert a CDP WebSocket scheme to HTTPS.\n *\n * Browser-use's live viewer expects `wss=https://UUID.cdpN.browser-use.com`\n * but CDP URLs use `wss://`. This swaps the scheme.\n */\nfunction cdpToHttps(wsUrl: string): string {\n return wsUrl.replace(/^wss:\\/\\//, 'https://').replace(/^ws:\\/\\//, 'http://');\n}\n\n/**\n * Normalize any debug URL into a valid browser-use live viewer URL.\n *\n * Handles three input formats:\n * 1. Already-correct `https://live.browser-use.com?wss=https://...` — pass through\n * 2. Already-correct but with wrong scheme `...?wss=wss://...` — fix the wss param\n * 3. Raw CDP URL `wss://UUID.cdpN.browser-use.com` — wrap into live viewer URL\n */\nfunction normalizeLiveUrl(debugUrl: string): string {\n const trimmed = debugUrl.trim();\n if (!trimmed) return trimmed;\n\n // Case 3: raw CDP WebSocket URL → wrap into live viewer\n if (trimmed.startsWith('wss://') || trimmed.startsWith('ws://')) {\n return `https://live.browser-use.com?wss=${encodeURIComponent(cdpToHttps(trimmed))}`;\n }\n\n let url: URL;\n try {\n url = new URL(trimmed);\n } catch {\n return trimmed;\n }\n\n // Case 2: live viewer URL with wrong scheme in wss param → fix it\n const wssParam = url.searchParams.get('wss');\n if (wssParam && (wssParam.startsWith('wss://') || wssParam.startsWith('ws://'))) {\n url.searchParams.set('wss', cdpToHttps(wssParam));\n }\n\n return url.toString();\n}\n\n/**\n * Build iframe HTML for embedding a live session\n * \n * @param debugUrl - Live session debug URL\n * @param options - Iframe configuration including dimensions and session options\n * @returns HTML iframe element as string\n * \n * @example\n * ```typescript\n * const iframe = buildLiveIframe(task.debugUrl, {\n * interactive: true,\n * width: '100%',\n * height: '600px'\n * });\n * ```\n */\nexport function buildLiveIframe(\n debugUrl: string,\n options: IframeOptions = {}\n): string {\n const {\n width = '100%',\n height = '600px',\n style = '',\n className = '',\n ...sessionOptions\n } = options;\n\n const src = buildLiveUrl(debugUrl, sessionOptions);\n \n // Convert numeric dimensions to pixels\n const widthStr = typeof width === 'number' ? `${width}px` : width;\n const heightStr = typeof height === 'number' ? `${height}px` : height;\n \n // Build style attribute\n const baseStyle = `width: ${widthStr}; height: ${heightStr}; border: none;`;\n const fullStyle = style ? `${baseStyle} ${style}` : baseStyle;\n \n // Build iframe attributes\n const attributes = [\n `src=\"${src}\"`,\n `style=\"${fullStyle}\"`,\n ];\n \n if (className) {\n attributes.push(`class=\"${className}\"`);\n }\n \n return `<iframe ${attributes.join(' ')}></iframe>`;\n}\n\n/**\n * Build complete embed code with HTML snippet\n * \n * @param debugUrl - Live session debug URL\n * @param options - Iframe configuration\n * @returns Multi-line HTML snippet ready to copy-paste\n * \n * @example\n * ```typescript\n * const code = buildEmbedCode(task.debugUrl, { interactive: false });\n * console.log(code);\n * // <!-- Embed Morph Live Session -->\n * // <iframe src=\"...\" style=\"...\"></iframe>\n * ```\n */\nexport function buildEmbedCode(\n debugUrl: string,\n options: IframeOptions = {}\n): string {\n const iframe = buildLiveIframe(debugUrl, options);\n return `<!-- Embed Morph Live Session -->\\n${iframe}`;\n}\n\n/**\n * Get live session options from preset name or custom config\n * \n * @internal\n */\nexport function resolvePreset(\n optionsOrPreset?: string | IframeOptions\n): IframeOptions {\n if (!optionsOrPreset) {\n return {};\n }\n \n if (typeof optionsOrPreset === 'string') {\n const preset = LIVE_PRESETS[optionsOrPreset as keyof typeof LIVE_PRESETS];\n if (!preset) {\n throw new Error(\n `Unknown preset: ${optionsOrPreset}. Available presets: ${Object.keys(LIVE_PRESETS).join(', ')}`\n );\n }\n return preset;\n }\n \n return optionsOrPreset;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
buildLiveIframe,
|
|
7
7
|
buildLiveUrl,
|
|
8
8
|
resolvePreset
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-YTYCHRQ2.js";
|
|
10
10
|
import {
|
|
11
11
|
fetchWithRetry,
|
|
12
12
|
withTimeout
|
|
@@ -609,4 +609,4 @@ export {
|
|
|
609
609
|
getWebp,
|
|
610
610
|
checkHealth
|
|
611
611
|
};
|
|
612
|
-
//# sourceMappingURL=chunk-
|
|
612
|
+
//# sourceMappingURL=chunk-ZYPLV3HP.js.map
|
package/dist/client.cjs
CHANGED
|
@@ -1005,13 +1005,14 @@ function buildLiveUrl(debugUrl, options = {}) {
|
|
|
1005
1005
|
}
|
|
1006
1006
|
return url.toString();
|
|
1007
1007
|
}
|
|
1008
|
+
function cdpToHttps(wsUrl) {
|
|
1009
|
+
return wsUrl.replace(/^wss:\/\//, "https://").replace(/^ws:\/\//, "http://");
|
|
1010
|
+
}
|
|
1008
1011
|
function normalizeLiveUrl(debugUrl) {
|
|
1009
1012
|
const trimmed = debugUrl.trim();
|
|
1010
|
-
if (!trimmed)
|
|
1011
|
-
return trimmed;
|
|
1012
|
-
}
|
|
1013
|
+
if (!trimmed) return trimmed;
|
|
1013
1014
|
if (trimmed.startsWith("wss://") || trimmed.startsWith("ws://")) {
|
|
1014
|
-
return `https://live.browser-use.com?wss=${encodeURIComponent(trimmed)}`;
|
|
1015
|
+
return `https://live.browser-use.com?wss=${encodeURIComponent(cdpToHttps(trimmed))}`;
|
|
1015
1016
|
}
|
|
1016
1017
|
let url;
|
|
1017
1018
|
try {
|
|
@@ -1019,12 +1020,9 @@ function normalizeLiveUrl(debugUrl) {
|
|
|
1019
1020
|
} catch {
|
|
1020
1021
|
return trimmed;
|
|
1021
1022
|
}
|
|
1022
|
-
if (url.protocol === "wss:" || url.protocol === "ws:") {
|
|
1023
|
-
return `https://live.browser-use.com?wss=${encodeURIComponent(trimmed)}`;
|
|
1024
|
-
}
|
|
1025
1023
|
const wssParam = url.searchParams.get("wss");
|
|
1026
1024
|
if (wssParam && (wssParam.startsWith("wss://") || wssParam.startsWith("ws://"))) {
|
|
1027
|
-
url.searchParams.set("wss", wssParam);
|
|
1025
|
+
url.searchParams.set("wss", cdpToHttps(wssParam));
|
|
1028
1026
|
}
|
|
1029
1027
|
return url.toString();
|
|
1030
1028
|
}
|