@builder.io/partytown
Advanced tools
Comparing version 0.0.11 to 0.0.12
@@ -57,2 +57,6 @@ /** | ||
/** | ||
* Log calls to main access, which also shows how many tasks were sent per message (debug mode required) | ||
*/ | ||
logMainAccess?: boolean; | ||
/** | ||
* Log script executions (debug mode required) | ||
@@ -59,0 +63,0 @@ */ |
@@ -6,4 +6,4 @@ { | ||
"types": "index.d.ts", | ||
"version": "0.0.11", | ||
"version": "0.0.12", | ||
"private": true | ||
} |
@@ -1,2 +0,2 @@ | ||
const noop = () => {}; | ||
const noop = () => !0; | ||
@@ -20,3 +20,3 @@ const logMain = msg => { | ||
const isValidMemberName = memberName => !startsWith(memberName, "webkit") && !startsWith(memberName, "toJSON") && (!startsWith(memberName, "on") || (str => str.toLowerCase())(memberName) !== memberName); | ||
const isValidMemberName = memberName => !(startsWith(memberName, "webkit") || startsWith(memberName, "toJSON") || startsWith(memberName, "constructor") || startsWith(memberName, "toString")); | ||
@@ -65,6 +65,6 @@ const EMPTY_ARRAY = []; | ||
if ("string" === (type = typeof value) || "number" === type || "boolean" === type || null == value) { | ||
return [ 5, value ]; | ||
return [ 9, value ]; | ||
} | ||
if ("function" === type) { | ||
return [ 2 ]; | ||
return [ 5 ]; | ||
} | ||
@@ -80,16 +80,10 @@ added = added || new Set; | ||
if ("object" === type) { | ||
return value.nodeType ? [ 3, { | ||
return "Window" === (cstrName = getConstructorName(value)) ? [ 6, { | ||
$winId$: $winId$, | ||
$interfaceType$: value.nodeType, | ||
$instanceId$: 0 | ||
} ] : "HTMLCollection" === cstrName || "NodeList" === cstrName ? [ 7, Array.from(value).map((v => serializeForWorker($winId$, v, added)[1])) ] : "Event" === cstrName ? [ 4, serializeObjectForWorker($winId$, value, added) ] : "CSSRuleList" === cstrName ? [ 3, Array.from(value).map(serializeCssRuleForWorker) ] : cstrName.startsWith("CSS") && cstrName.endsWith("Rule") ? [ 2, serializeCssRuleForWorker(value) ] : "CSSStyleDeclaration" === cstrName ? [ 8, serializeObjectForWorker($winId$, value, added) ] : "Attr" === cstrName ? [ 1, [ value.name, value.value ] ] : value.nodeType ? [ 6, { | ||
$winId$: $winId$, | ||
$instanceId$: getAndSetInstanceId(value), | ||
$nodeName$: value.nodeName | ||
} ] : "Window" === (cstrName = getConstructorName(value)) ? [ 3, { | ||
$winId$: $winId$, | ||
$interfaceType$: 0, | ||
$instanceId$: 0 | ||
} ] : "HTMLCollection" === cstrName || "NodeList" === cstrName ? [ 3, { | ||
$winId$: $winId$, | ||
$interfaceType$: 21, | ||
$data$: Array.from(value).map((v => serializeForWorker($winId$, v, added)[1])) | ||
} ] : "Event" === cstrName ? [ 1, serializeObjectForWorker($winId$, value, added) ] : "CSSStyleDeclaration" === cstrName ? [ 4, serializeObjectForWorker($winId$, value, added) ] : [ 4, serializeObjectForWorker($winId$, value, added, !0, !0) ]; | ||
} ] : [ 8, serializeObjectForWorker($winId$, value, added, !0, !0) ]; | ||
} | ||
@@ -104,4 +98,6 @@ } | ||
for (propName in obj) { | ||
propValue = obj[propName]; | ||
isValidMemberName(propName) && (includeFunctions || "function" != typeof propValue) && (includeEmptyStrings || "" !== propValue) && (serializedObj[propName] = serializeForWorker(winId, propValue, added)); | ||
if (isValidMemberName(propName)) { | ||
propValue = obj[propName]; | ||
(includeFunctions || "function" != typeof propValue) && (includeEmptyStrings || "" !== propValue) && (serializedObj[propName] = serializeForWorker(winId, propValue, added)); | ||
} | ||
} | ||
@@ -112,2 +108,13 @@ } | ||
const serializeCssRuleForWorker = cssRule => { | ||
let obj = {}; | ||
let key; | ||
for (key in cssRule) { | ||
validCssRuleProps.includes(key) && (obj[key] = cssRule[key]); | ||
} | ||
return obj; | ||
}; | ||
const validCssRuleProps = "cssText,selectorText,href,media,namespaceURI,prefix,name,conditionText".split(","); | ||
const readNextScript = (worker, winCtx) => { | ||
@@ -157,3 +164,89 @@ let $winId$ = winCtx.$winId$; | ||
const registerWindow = (worker, $winId$, $window$, $isTop$) => { | ||
const readMainPlatform = win => { | ||
const doc = win.document; | ||
const $config$ = win.partytown || {}; | ||
const $libPath$ = ($config$.lib || "/~partytown/") + "debug/"; | ||
return { | ||
$config$: $config$, | ||
$libPath$: new URL($libPath$, win.location) + "", | ||
$interfaces$: readMainInterfaces(win, doc) | ||
}; | ||
}; | ||
const readMainInterfaces = (win, doc) => { | ||
const startTime = performance.now(); | ||
const docImpl = doc.implementation.createHTMLDocument(); | ||
const textNode = docImpl.createTextNode(""); | ||
const comment = docImpl.createComment(""); | ||
const frag = docImpl.createDocumentFragment(); | ||
const elm = docImpl.createElement("i"); | ||
const svg = docImpl.createElementNS("http://www.w3.org/2000/svg", "svg"); | ||
const canvasRenderingContext2D = docImpl.createElement("canvas").getContext("2d"); | ||
const mutationObserver = new MutationObserver(noop); | ||
const resizeObserver = new ResizeObserver(noop); | ||
const elms = Object.getOwnPropertyNames(win).filter((c => /^HTML.+Element$/.test(c))).map((htmlCstrName => { | ||
const htmlTagName = getHtmlTagNameFromConstructor(htmlCstrName); | ||
return [ docImpl.createElement(htmlTagName) ]; | ||
})); | ||
const impls = [ [ win.localStorage ], [ win.history ], [ win.screen ], [ win.screen.orientation ], [ mutationObserver, 12 ], [ resizeObserver, 12 ], [ textNode ], [ comment ], [ frag ], [ elm ], [ elm.attributes ], [ elm.classList ], [ elm.dataset ], [ elm.style ], [ svg ], [ docImpl ], [ docImpl.doctype ], [ canvasRenderingContext2D ], ...elms ].filter((implData => implData[0])).map((implData => { | ||
const impl = implData[0]; | ||
const interfaceType = implData[1]; | ||
const cstrName = impl.constructor.name; | ||
return [ cstrName, win[cstrName].prototype, impl, interfaceType ]; | ||
})); | ||
const interfaces = [ readImplentation("Window", win), readImplentation("Node", textNode) ]; | ||
impls.map((([cstrName, CstrPrototype, impl, intefaceType]) => readOwnImplentation(interfaces, cstrName, CstrPrototype, impl, intefaceType))); | ||
logMain(`Read ${interfaces.length} interfaces in ${(performance.now() - startTime).toFixed(1)}ms`); | ||
return interfaces; | ||
}; | ||
const readImplentation = (cstrName, impl) => { | ||
const interfaceMembers = []; | ||
const interfaceInfo = [ cstrName, "Object", interfaceMembers ]; | ||
for (const memberName in impl) { | ||
readImplentationMember(interfaceMembers, impl, memberName); | ||
} | ||
return interfaceInfo; | ||
}; | ||
const readOwnImplentation = (interfaces, cstrName, CstrPrototype, impl, interfaceType) => { | ||
if ("Object" !== cstrName && !interfaces.some((i => i[0] === cstrName))) { | ||
const SuperCstr = Object.getPrototypeOf(CstrPrototype); | ||
const superCstrName = SuperCstr.constructor.name; | ||
const interfaceMembers = []; | ||
readOwnImplentation(interfaces, superCstrName, SuperCstr, impl, interfaceType); | ||
Object.keys(Object.getOwnPropertyDescriptors(CstrPrototype)).map((memberName => readImplentationMember(interfaceMembers, impl, memberName))); | ||
const interfaceInfo = [ cstrName, superCstrName, interfaceMembers, interfaceType, impl.nodeName ]; | ||
interfaces.push(interfaceInfo); | ||
} | ||
}; | ||
const readImplentationMember = (interfaceMembers, implementation, memberName, cstrName) => { | ||
if (isValidMemberName(memberName)) { | ||
const value = implementation[memberName]; | ||
const memberType = typeof value; | ||
"function" === memberType ? interfaceMembers.push([ memberName, 5 ]) : "object" === memberType && null != value && "Object" !== (cstrName = getConstructorName(value)) ? value.nodeType ? interfaceMembers.push([ memberName, value.nodeType ]) : interfaceMembers.push([ memberName, cstrName ]) : "symbol" !== memberType && (memberName.toUpperCase() === memberName ? interfaceMembers.push([ memberName, 6, value ]) : interfaceMembers.push([ memberName, 6 ])); | ||
} | ||
}; | ||
const htmlConstructorToTagMap = { | ||
Anchor: "A", | ||
DList: "DL", | ||
Image: "IMG", | ||
OList: "OL", | ||
Paragraph: "P", | ||
TableCaption: "CAPTION", | ||
TableCell: "TD", | ||
TableCol: "COLGROUP", | ||
TableRow: "TR", | ||
TableSection: "TBODY", | ||
UList: "UL" | ||
}; | ||
const getHtmlTagNameFromConstructor = t => { | ||
t = t.substr(4).replace("Element", ""); | ||
return htmlConstructorToTagMap[t] || t; | ||
}; | ||
const registerWindow = (worker, $winId$, $window$) => { | ||
if (!windowIds.has($window$)) { | ||
@@ -166,3 +259,2 @@ windowIds.set($window$, $winId$); | ||
$parentWinId$: windowIds.get($window$.parent), | ||
$isTop$: $isTop$, | ||
$url$: $url$ | ||
@@ -178,3 +270,3 @@ }; | ||
{ | ||
const winType = envData.$isTop$ ? "top" : "iframe"; | ||
const winType = envData.$winId$ === envData.$parentWinId$ ? "top" : "iframe"; | ||
logMain(`Registered ${winType} window ${normalizedWinId($winId$)} (${$winId$})`); | ||
@@ -189,44 +281,5 @@ } | ||
if (0 === msgType) { | ||
const initWebWorkerData = (win => { | ||
const doc = win.document; | ||
const $config$ = win.partytown || {}; | ||
const $libPath$ = ($config$.lib || "/~partytown/") + "debug/"; | ||
const $url$ = win.location + ""; | ||
const docImpl = doc.implementation.createHTMLDocument(); | ||
const inputElm = docImpl.createElement("input"); | ||
const canvasRenderingContext2D = docImpl.createElement("canvas").getContext("2d"); | ||
const implementations = [ [ 0, win ], [ 15, inputElm.style ], [ 9, docImpl ], [ 11, docImpl.createDocumentFragment() ], [ 16, inputElm.dataset ], [ 17, inputElm.classList ], [ 1, inputElm ], [ 14, canvasRenderingContext2D ], [ 18, win.history ], [ 19, win.location ], [ 20, new MutationObserver(noop) ], [ 22, inputElm.attributes ], [ 21, inputElm.childNodes ], [ 23, new ResizeObserver(noop) ], [ 24, win.screen ], [ 25, win.localStorage ], [ 3, docImpl.createTextNode("") ] ].map((i => [ ...i, getConstructorName(i[1]) ])); | ||
const initWebWorkerData = { | ||
$config$: $config$, | ||
$libPath$: new URL($libPath$, $url$) + "", | ||
$htmlConstructors$: Object.getOwnPropertyNames(win).filter((c => /^H.*t$/i.test(c))), | ||
$interfaces$: implementations.map((([interfaceType, impl, cstrName]) => { | ||
let memberName; | ||
let value; | ||
let type; | ||
let objCstrName; | ||
let objImpl; | ||
let interfaceInfo = [ interfaceType, cstrName, {} ]; | ||
for (memberName in impl) { | ||
if (isValidMemberName(memberName)) { | ||
value = impl[memberName]; | ||
type = typeof value; | ||
if ("function" === type) { | ||
interfaceInfo[2][memberName] = 13; | ||
} else if ("object" === type) { | ||
objCstrName = getConstructorName(value); | ||
objImpl = implementations.find((i => i[2] === objCstrName)); | ||
objImpl && (interfaceInfo[2][memberName] = objImpl[0]); | ||
} | ||
} | ||
} | ||
return interfaceInfo; | ||
})) | ||
}; | ||
logMain(`Read main window, interfaces: ${initWebWorkerData.$interfaces$.length}, HTML Constructors: ${initWebWorkerData.$htmlConstructors$.length}`); | ||
return initWebWorkerData; | ||
})(mainWindow); | ||
worker.postMessage([ 1, initWebWorkerData ]); | ||
worker.postMessage([ 1, readMainPlatform(mainWindow) ]); | ||
} else if (2 === msgType) { | ||
registerWindow(worker, randomId(), mainWindow, 1); | ||
registerWindow(worker, randomId(), mainWindow); | ||
} else { | ||
@@ -244,6 +297,7 @@ const winCtx = winCtxs[msg[1]]; | ||
const mainWindow = sandboxWindow.parent; | ||
if (await (async (sandboxWindow, _receiveMessage) => { | ||
const success = await (async (sandboxWindow, _receiveMessage) => { | ||
console.log("ATOMICS ⚛️", sandboxWindow.location.href); | ||
return !0; | ||
})(sandboxWindow)) { | ||
})(sandboxWindow); | ||
if (success) { | ||
worker = new Worker("./partytown-ww-atomics.js", { | ||
@@ -250,0 +304,0 @@ name: "Partytown 🎉" |
(window => { | ||
const isPromise = v => "object" == typeof v && v && v.then; | ||
const noop = () => {}; | ||
const noop = () => !0; | ||
const logMain = msg => { | ||
@@ -15,3 +15,3 @@ console.debug.apply(console, [ "%cMain 🌎", "background: #717171; color: white; padding: 2px 3px; border-radius: 2px; font-size: 0.8em;", msg ]); | ||
const startsWith = (str, val) => str.startsWith(val); | ||
const isValidMemberName = memberName => !startsWith(memberName, "webkit") && !startsWith(memberName, "toJSON") && (!startsWith(memberName, "on") || (str => str.toLowerCase())(memberName) !== memberName); | ||
const isValidMemberName = memberName => !(startsWith(memberName, "webkit") || startsWith(memberName, "toJSON") || startsWith(memberName, "constructor") || startsWith(memberName, "toString")); | ||
const EMPTY_ARRAY = []; | ||
@@ -61,6 +61,6 @@ Object.freeze(EMPTY_ARRAY); | ||
if ("string" === (type = typeof value) || "number" === type || "boolean" === type || null == value) { | ||
return [ 5, value ]; | ||
return [ 9, value ]; | ||
} | ||
if ("function" === type) { | ||
return [ 2 ]; | ||
return [ 5 ]; | ||
} | ||
@@ -76,16 +76,10 @@ added = added || new Set; | ||
if ("object" === type) { | ||
return value.nodeType ? [ 3, { | ||
return "Window" === (cstrName = getConstructorName(value)) ? [ 6, { | ||
$winId$: $winId$, | ||
$interfaceType$: value.nodeType, | ||
$instanceId$: 0 | ||
} ] : "HTMLCollection" === cstrName || "NodeList" === cstrName ? [ 7, Array.from(value).map((v => serializeForWorker($winId$, v, added)[1])) ] : "Event" === cstrName ? [ 4, serializeObjectForWorker($winId$, value, added) ] : "CSSRuleList" === cstrName ? [ 3, Array.from(value).map(serializeCssRuleForWorker) ] : cstrName.startsWith("CSS") && cstrName.endsWith("Rule") ? [ 2, serializeCssRuleForWorker(value) ] : "CSSStyleDeclaration" === cstrName ? [ 8, serializeObjectForWorker($winId$, value, added) ] : "Attr" === cstrName ? [ 1, [ value.name, value.value ] ] : value.nodeType ? [ 6, { | ||
$winId$: $winId$, | ||
$instanceId$: getAndSetInstanceId(value), | ||
$nodeName$: value.nodeName | ||
} ] : "Window" === (cstrName = getConstructorName(value)) ? [ 3, { | ||
$winId$: $winId$, | ||
$interfaceType$: 0, | ||
$instanceId$: 0 | ||
} ] : "HTMLCollection" === cstrName || "NodeList" === cstrName ? [ 3, { | ||
$winId$: $winId$, | ||
$interfaceType$: 21, | ||
$data$: Array.from(value).map((v => serializeForWorker($winId$, v, added)[1])) | ||
} ] : "Event" === cstrName ? [ 1, serializeObjectForWorker($winId$, value, added) ] : "CSSStyleDeclaration" === cstrName ? [ 4, serializeObjectForWorker($winId$, value, added) ] : [ 4, serializeObjectForWorker($winId$, value, added, !0, !0) ]; | ||
} ] : [ 8, serializeObjectForWorker($winId$, value, added, !0, !0) ]; | ||
} | ||
@@ -99,4 +93,6 @@ } | ||
for (propName in obj) { | ||
propValue = obj[propName]; | ||
isValidMemberName(propName) && (includeFunctions || "function" != typeof propValue) && (includeEmptyStrings || "" !== propValue) && (serializedObj[propName] = serializeForWorker(winId, propValue, added)); | ||
if (isValidMemberName(propName)) { | ||
propValue = obj[propName]; | ||
(includeFunctions || "function" != typeof propValue) && (includeEmptyStrings || "" !== propValue) && (serializedObj[propName] = serializeForWorker(winId, propValue, added)); | ||
} | ||
} | ||
@@ -106,2 +102,10 @@ } | ||
}; | ||
const serializeCssRuleForWorker = cssRule => { | ||
let obj = {}; | ||
let key; | ||
for (key in cssRule) { | ||
validCssRuleProps.includes(key) && (obj[key] = cssRule[key]); | ||
} | ||
return obj; | ||
}; | ||
const deserializeFromWorker = (worker, serializedTransfer, serializedType, serializedValue) => { | ||
@@ -111,6 +115,6 @@ if (serializedTransfer) { | ||
serializedValue = serializedTransfer[1]; | ||
if (5 === serializedType) { | ||
if (9 === serializedType) { | ||
return serializedValue; | ||
} | ||
if (6 === serializedType) { | ||
if (10 === serializedType) { | ||
return deserializeRefFromWorker(worker, serializedValue); | ||
@@ -121,9 +125,9 @@ } | ||
} | ||
if (3 === serializedType) { | ||
if (6 === serializedType) { | ||
return getInstance(serializedValue.$winId$, serializedValue.$instanceId$); | ||
} | ||
if (1 === serializedType) { | ||
if (4 === serializedType) { | ||
return constructEvent(deserializeObjectFromWorker(worker, serializedValue)); | ||
} | ||
if (4 === serializedType) { | ||
if (8 === serializedType) { | ||
return deserializeObjectFromWorker(worker, serializedValue); | ||
@@ -157,3 +161,4 @@ } | ||
}; | ||
const applyToInstance = (worker, instance, applyPath) => { | ||
const validCssRuleProps = "cssText,selectorText,href,media,namespaceURI,prefix,name,conditionText".split(","); | ||
const applyToInstance = (worker, instance, applyPath, groupedGetters) => { | ||
let i = 0; | ||
@@ -164,2 +169,3 @@ let l = len(applyPath); | ||
let previous; | ||
let args; | ||
for (;i < l; i++) { | ||
@@ -169,3 +175,22 @@ current = applyPath[i]; | ||
previous = applyPath[i - 1]; | ||
Array.isArray(next) || ("string" == typeof current ? instance = instance[current] : 0 === next ? instance[previous] = deserializeFromWorker(worker, current) : "function" == typeof instance[previous] && (instance = instance[previous].apply(instance, deserializeFromWorker(worker, current)))); | ||
if (!Array.isArray(next)) { | ||
if ("string" == typeof current || "number" == typeof current) { | ||
if (i + 1 === l && groupedGetters) { | ||
const groupedRtnValues = {}; | ||
groupedGetters.map((propName => groupedRtnValues[propName] = instance[propName])); | ||
return groupedRtnValues; | ||
} | ||
instance = instance[current]; | ||
} else { | ||
if (0 === next) { | ||
instance[previous] = deserializeFromWorker(worker, current); | ||
return; | ||
} | ||
if ("function" == typeof instance[previous]) { | ||
args = deserializeFromWorker(worker, current); | ||
"insertRule" === previous && args[1] > len(instance.cssRules) && (args[1] = len(instance.cssRules)); | ||
instance = instance[previous].apply(instance, args); | ||
} | ||
} | ||
} | ||
} | ||
@@ -217,3 +242,82 @@ return instance; | ||
}; | ||
const registerWindow = (worker, $winId$, $window$, $isTop$) => { | ||
const readMainPlatform = win => { | ||
const doc = win.document; | ||
const $config$ = win.partytown || {}; | ||
const $libPath$ = ($config$.lib || "/~partytown/") + "debug/"; | ||
return { | ||
$config$: $config$, | ||
$libPath$: new URL($libPath$, win.location) + "", | ||
$interfaces$: readMainInterfaces(win, doc) | ||
}; | ||
}; | ||
const readMainInterfaces = (win, doc) => { | ||
const startTime = performance.now(); | ||
const docImpl = doc.implementation.createHTMLDocument(); | ||
const textNode = docImpl.createTextNode(""); | ||
const comment = docImpl.createComment(""); | ||
const frag = docImpl.createDocumentFragment(); | ||
const elm = docImpl.createElement("i"); | ||
const svg = docImpl.createElementNS("http://www.w3.org/2000/svg", "svg"); | ||
const canvasRenderingContext2D = docImpl.createElement("canvas").getContext("2d"); | ||
const mutationObserver = new MutationObserver(noop); | ||
const resizeObserver = new ResizeObserver(noop); | ||
const elms = Object.getOwnPropertyNames(win).filter((c => /^HTML.+Element$/.test(c))).map((htmlCstrName => { | ||
const htmlTagName = getHtmlTagNameFromConstructor(htmlCstrName); | ||
return [ docImpl.createElement(htmlTagName) ]; | ||
})); | ||
const impls = [ [ win.localStorage ], [ win.history ], [ win.screen ], [ win.screen.orientation ], [ mutationObserver, 12 ], [ resizeObserver, 12 ], [ textNode ], [ comment ], [ frag ], [ elm ], [ elm.attributes ], [ elm.classList ], [ elm.dataset ], [ elm.style ], [ svg ], [ docImpl ], [ docImpl.doctype ], [ canvasRenderingContext2D ], ...elms ].filter((implData => implData[0])).map((implData => { | ||
const impl = implData[0]; | ||
const interfaceType = implData[1]; | ||
const cstrName = impl.constructor.name; | ||
return [ cstrName, win[cstrName].prototype, impl, interfaceType ]; | ||
})); | ||
const interfaces = [ readImplentation("Window", win), readImplentation("Node", textNode) ]; | ||
impls.map((([cstrName, CstrPrototype, impl, intefaceType]) => readOwnImplentation(interfaces, cstrName, CstrPrototype, impl, intefaceType))); | ||
logMain(`Read ${interfaces.length} interfaces in ${(performance.now() - startTime).toFixed(1)}ms`); | ||
return interfaces; | ||
}; | ||
const readImplentation = (cstrName, impl) => { | ||
const interfaceMembers = []; | ||
const interfaceInfo = [ cstrName, "Object", interfaceMembers ]; | ||
for (const memberName in impl) { | ||
readImplentationMember(interfaceMembers, impl, memberName); | ||
} | ||
return interfaceInfo; | ||
}; | ||
const readOwnImplentation = (interfaces, cstrName, CstrPrototype, impl, interfaceType) => { | ||
if ("Object" !== cstrName && !interfaces.some((i => i[0] === cstrName))) { | ||
const SuperCstr = Object.getPrototypeOf(CstrPrototype); | ||
const superCstrName = SuperCstr.constructor.name; | ||
const interfaceMembers = []; | ||
readOwnImplentation(interfaces, superCstrName, SuperCstr, impl, interfaceType); | ||
Object.keys(Object.getOwnPropertyDescriptors(CstrPrototype)).map((memberName => readImplentationMember(interfaceMembers, impl, memberName))); | ||
const interfaceInfo = [ cstrName, superCstrName, interfaceMembers, interfaceType, impl.nodeName ]; | ||
interfaces.push(interfaceInfo); | ||
} | ||
}; | ||
const readImplentationMember = (interfaceMembers, implementation, memberName, cstrName) => { | ||
if (isValidMemberName(memberName)) { | ||
const value = implementation[memberName]; | ||
const memberType = typeof value; | ||
"function" === memberType ? interfaceMembers.push([ memberName, 5 ]) : "object" === memberType && null != value && "Object" !== (cstrName = getConstructorName(value)) ? value.nodeType ? interfaceMembers.push([ memberName, value.nodeType ]) : interfaceMembers.push([ memberName, cstrName ]) : "symbol" !== memberType && (memberName.toUpperCase() === memberName ? interfaceMembers.push([ memberName, 6, value ]) : interfaceMembers.push([ memberName, 6 ])); | ||
} | ||
}; | ||
const htmlConstructorToTagMap = { | ||
Anchor: "A", | ||
DList: "DL", | ||
Image: "IMG", | ||
OList: "OL", | ||
Paragraph: "P", | ||
TableCaption: "CAPTION", | ||
TableCell: "TD", | ||
TableCol: "COLGROUP", | ||
TableRow: "TR", | ||
TableSection: "TBODY", | ||
UList: "UL" | ||
}; | ||
const getHtmlTagNameFromConstructor = t => { | ||
t = t.substr(4).replace("Element", ""); | ||
return htmlConstructorToTagMap[t] || t; | ||
}; | ||
const registerWindow = (worker, $winId$, $window$) => { | ||
if (!windowIds.has($window$)) { | ||
@@ -226,3 +330,2 @@ windowIds.set($window$, $winId$); | ||
$parentWinId$: windowIds.get($window$.parent), | ||
$isTop$: $isTop$, | ||
$url$: $url$ | ||
@@ -238,3 +341,3 @@ }; | ||
{ | ||
const winType = envData.$isTop$ ? "top" : "iframe"; | ||
const winType = envData.$winId$ === envData.$parentWinId$ ? "top" : "iframe"; | ||
logMain(`Registered ${winType} window ${normalizedWinId($winId$)} (${$winId$})`); | ||
@@ -248,44 +351,5 @@ } | ||
if (0 === msgType) { | ||
const initWebWorkerData = (win => { | ||
const doc = win.document; | ||
const $config$ = win.partytown || {}; | ||
const $libPath$ = ($config$.lib || "/~partytown/") + "debug/"; | ||
const $url$ = win.location + ""; | ||
const docImpl = doc.implementation.createHTMLDocument(); | ||
const inputElm = docImpl.createElement("input"); | ||
const canvasRenderingContext2D = docImpl.createElement("canvas").getContext("2d"); | ||
const implementations = [ [ 0, win ], [ 15, inputElm.style ], [ 9, docImpl ], [ 11, docImpl.createDocumentFragment() ], [ 16, inputElm.dataset ], [ 17, inputElm.classList ], [ 1, inputElm ], [ 14, canvasRenderingContext2D ], [ 18, win.history ], [ 19, win.location ], [ 20, new MutationObserver(noop) ], [ 22, inputElm.attributes ], [ 21, inputElm.childNodes ], [ 23, new ResizeObserver(noop) ], [ 24, win.screen ], [ 25, win.localStorage ], [ 3, docImpl.createTextNode("") ] ].map((i => [ ...i, getConstructorName(i[1]) ])); | ||
const initWebWorkerData = { | ||
$config$: $config$, | ||
$libPath$: new URL($libPath$, $url$) + "", | ||
$htmlConstructors$: Object.getOwnPropertyNames(win).filter((c => /^H.*t$/i.test(c))), | ||
$interfaces$: implementations.map((([interfaceType, impl, cstrName]) => { | ||
let memberName; | ||
let value; | ||
let type; | ||
let objCstrName; | ||
let objImpl; | ||
let interfaceInfo = [ interfaceType, cstrName, {} ]; | ||
for (memberName in impl) { | ||
if (isValidMemberName(memberName)) { | ||
value = impl[memberName]; | ||
type = typeof value; | ||
if ("function" === type) { | ||
interfaceInfo[2][memberName] = 13; | ||
} else if ("object" === type) { | ||
objCstrName = getConstructorName(value); | ||
objImpl = implementations.find((i => i[2] === objCstrName)); | ||
objImpl && (interfaceInfo[2][memberName] = objImpl[0]); | ||
} | ||
} | ||
} | ||
return interfaceInfo; | ||
})) | ||
}; | ||
logMain(`Read main window, interfaces: ${initWebWorkerData.$interfaces$.length}, HTML Constructors: ${initWebWorkerData.$htmlConstructors$.length}`); | ||
return initWebWorkerData; | ||
})(mainWindow); | ||
worker.postMessage([ 1, initWebWorkerData ]); | ||
worker.postMessage([ 1, readMainPlatform(mainWindow) ]); | ||
} else if (2 === msgType) { | ||
registerWindow(worker, randomId(), mainWindow, 1); | ||
registerWindow(worker, randomId(), mainWindow); | ||
} else { | ||
@@ -302,9 +366,6 @@ const winCtx = winCtxs[msg[1]]; | ||
const mainWindow = sandboxWindow.parent; | ||
if (await (async (sandboxWindow, receiveMessage) => { | ||
const success = await (async (sandboxWindow, receiveMessage) => { | ||
const swContainer = sandboxWindow.navigator.serviceWorker; | ||
const swRegistration = await swContainer.getRegistration(); | ||
const sendMessageToWorker = accessRsp => { | ||
swRegistration && swRegistration.active && swRegistration.active.postMessage(accessRsp); | ||
}; | ||
swContainer.addEventListener("message", (ev => receiveMessage(ev.data, sendMessageToWorker))); | ||
swContainer.addEventListener("message", (ev => receiveMessage(ev.data, (accessRsp => swRegistration.active && swRegistration.active.postMessage(accessRsp))))); | ||
return !!swRegistration; | ||
@@ -315,5 +376,6 @@ })(sandboxWindow, ((accessReq, responseCallback) => (async (worker, accessReq) => { | ||
}; | ||
const errors = []; | ||
for (const task of accessReq.$tasks$) { | ||
const totalTasks = len(accessReq.$tasks$); | ||
for (let i = 0; i < totalTasks; i++) { | ||
try { | ||
let task = accessReq.$tasks$[i]; | ||
let winId = task.$winId$; | ||
@@ -331,3 +393,3 @@ let instanceId = task.$instanceId$; | ||
})); | ||
if (1 === applyPath[0]) { | ||
if (1 === applyPath[0] && applyPath[1] in winCtxs[winId].$window$) { | ||
const constructedInstance = new winCtxs[winId].$window$[applyPath[1]](...deserializeFromWorker(worker, applyPath[2])); | ||
@@ -338,3 +400,3 @@ setInstanceId(constructedInstance, instanceId); | ||
if (instance) { | ||
rtnValue = applyToInstance(worker, instance, applyPath); | ||
rtnValue = applyToInstance(worker, instance, applyPath, task.$groupedGetters$); | ||
task.$assignInstanceId$ && setInstanceId(rtnValue, task.$assignInstanceId$); | ||
@@ -351,8 +413,8 @@ if (isPromise(rtnValue)) { | ||
} catch (e) { | ||
errors.push(String(e.stack || e)); | ||
i === totalTasks - 1 ? accessRsp.$error$ = String(e.stack || e) : console.error(e); | ||
} | ||
} | ||
len(errors) && (accessRsp.$error$ = errors.join("\n")); | ||
return accessRsp; | ||
})(worker, accessReq).then(responseCallback)))) { | ||
})(worker, accessReq).then(responseCallback))); | ||
if (success) { | ||
worker = new Worker("./partytown-ww-sw.js", { | ||
@@ -359,0 +421,0 @@ name: "Partytown 🎉" |
(self => { | ||
const WinIdKey = Symbol(); | ||
const InstanceIdKey = Symbol(); | ||
const InterfaceTypeKey = Symbol(); | ||
const NodeNameKey = Symbol(); | ||
const ApplyPathKey = Symbol(); | ||
const PropInstancesKey = Symbol(); | ||
const webWorkerInstances = new Map; | ||
const webWorkerRefsByRefId = {}; | ||
const webWorkerRefIdsByRef = new WeakMap; | ||
const nodeConstructors = {}; | ||
const envGlobalConstructors = {}; | ||
const webWorkerState = {}; | ||
const webWorkerCtx = {}; | ||
const environments = {}; | ||
const toLower = str => str.toLowerCase(); | ||
const toUpper = str => str.toUpperCase(); | ||
const cachedDimensions = new Map; | ||
const cachedTree = new Map; | ||
const dimensionMethodNames = "getClientRects,getBoundingClientRect".split(","); | ||
const dimensionPropNames = "innerHeight,innerWidth,outerHeight,outerWidth,clientHeight,clientWidth,clientTop,clientLeft,scrollHeight,scrollWidth,scrollTop,scrollLeft,offsetHeight,offsetWidth,offsetTop,offsetLeft".split(","); | ||
const elementTreePropNames = "childElementCount,children,firstElementChild,lastElementChild,nextElementSibling,previousElementSibling"; | ||
const noop = () => !0; | ||
const logWorker = (msg, winId = -1) => { | ||
@@ -44,21 +52,6 @@ try { | ||
}; | ||
const logWorkerGetter = (target, applyPath, rtnValue, restrictedToWorker = !1) => { | ||
if (webWorkerCtx.$config$.logGetters) { | ||
try { | ||
const msg = `Get ${logTargetProp(target, "Get", applyPath)}, returned: ${logValue(applyPath, rtnValue)}${restrictedToWorker ? " (restricted to worker)" : ""}`; | ||
msg.includes("Symbol(") || logWorker(msg, target[WinIdKey]); | ||
} catch (e) {} | ||
} | ||
}; | ||
const logWorkerSetter = (target, applyPath, value, restrictedToWorker = !1) => { | ||
if (webWorkerCtx.$config$.logSetters) { | ||
try { | ||
logWorker(`Set ${logTargetProp(target, "Set", applyPath)}, value: ${logValue(applyPath, value)}${restrictedToWorker ? " (restricted to worker)" : ""}`, target[WinIdKey]); | ||
} catch (e) {} | ||
} | ||
}; | ||
const logWorkerCall = (target, applyPath, args, rtnValue) => { | ||
const logWorkerGlobalConstructor = (winId, cstrName, args) => { | ||
if (webWorkerCtx.$config$.logCalls) { | ||
try { | ||
logWorker(`Call ${logTargetProp(target, "Call", applyPath)}(${args.map((v => logValue(applyPath, v))).join(", ")}), returned: ${logValue(applyPath, rtnValue)}`, target[WinIdKey]); | ||
logWorker(`Construct new ${cstrName}(${args.map((v => logValue([], v))).join(", ")})`, winId); | ||
} catch (e) {} | ||
@@ -71,2 +64,3 @@ } | ||
const instanceId = target[InstanceIdKey]; | ||
const cstrName = getConstructorName(target); | ||
if (0 === instanceId) { | ||
@@ -82,20 +76,17 @@ n = ""; | ||
n = "document.body."; | ||
} else if (1 === target.nodeType) { | ||
n = toLower(target.nodeName) + "."; | ||
} else if (1 === target[InterfaceTypeKey] && target[NodeNameKey]) { | ||
n = `<${toLower(target[NodeNameKey])}>`; | ||
} else if (8 === target[InterfaceTypeKey]) { | ||
n = "comment."; | ||
} else if (2 === target[InterfaceTypeKey]) { | ||
} else if (target[NodeNameKey]) { | ||
let nodeName = target[NodeNameKey]; | ||
n = "#text" === nodeName ? "textNode." : "#comment" === nodeName ? "commentNode." : "#document" === nodeName ? "document." : "html" === nodeName ? "doctype." : target.nodeName.toLowerCase() + "Element."; | ||
} else if (2 === target.nodeType) { | ||
n = "attributes."; | ||
} else if (11 === target[InterfaceTypeKey]) { | ||
n = "fragment."; | ||
} else if (10 === target[InterfaceTypeKey]) { | ||
n = "documentTypeNode."; | ||
} else if (20 === target[InterfaceTypeKey]) { | ||
} else if ("CanvasRenderingContext2D" === cstrName) { | ||
n = "context2D."; | ||
} else if ("CSSStyleDeclaration" === cstrName) { | ||
n = "value."; | ||
} else if ("MutationObserver" === cstrName) { | ||
n = "mutationObserver."; | ||
} else if (23 === target[InterfaceTypeKey]) { | ||
} else if ("NamedNodeMap" === cstrName) { | ||
n = "namedNodeMap."; | ||
} else if ("ResizeObserver" === cstrName) { | ||
n = "resizeObserver."; | ||
} else if (target[InterfaceTypeKey] <= 11) { | ||
n = "node."; | ||
} else { | ||
@@ -105,4 +96,5 @@ n = "¯\\_(ツ)_/¯ TARGET."; | ||
} | ||
target[ApplyPathKey] && target[ApplyPathKey].length && (n += [ ...target[ApplyPathKey] ].join(".") + "."); | ||
} | ||
if ("Get" === accessType && applyPath.length > 1) { | ||
if (applyPath.length > 1) { | ||
const first = applyPath.slice(0, applyPath.length - 1); | ||
@@ -125,3 +117,3 @@ const last = applyPath[applyPath.length - 1]; | ||
if ("string" === type) { | ||
return applyPath.includes("cookie") ? JSON.stringify(v.substr(0, 10) + "...") : JSON.stringify(v); | ||
return applyPath.includes("cookie") ? JSON.stringify(v.substr(0, 10) + "...") : JSON.stringify(v.length > 50 ? v.substr(0, 40) + "..." : v); | ||
} | ||
@@ -133,3 +125,32 @@ if (Array.isArray(v)) { | ||
const instanceId = v[InstanceIdKey]; | ||
return "number" == typeof instanceId ? 4 === instanceId ? "<body>" : 1 === instanceId ? "#document" : 2 === instanceId ? "<html>" : 3 === instanceId ? "<head>" : 0 === instanceId ? "window" : 1 === v[InterfaceTypeKey] && v[NodeNameKey] ? `<${toLower(v[NodeNameKey])}>` : 10 === v[InterfaceTypeKey] ? `<!DOCTYPE ${v[NodeNameKey]}>` : v[InterfaceTypeKey] <= 11 ? v[NodeNameKey] : "¯\\_(ツ)_/¯ instance obj" : v[Symbol.iterator] ? `[${Array.from(v).map((i => logValue(applyPath, i))).join(", ")}]` : objToString("value" in v ? v.value : v); | ||
if ("number" == typeof instanceId) { | ||
if (4 === instanceId) { | ||
return "<body>"; | ||
} | ||
if (1 === instanceId) { | ||
return "#document"; | ||
} | ||
if (2 === instanceId) { | ||
return "<html>"; | ||
} | ||
if (3 === instanceId) { | ||
return "<head>"; | ||
} | ||
if (0 === instanceId) { | ||
return "window"; | ||
} | ||
if (v[NodeNameKey]) { | ||
if (1 === v.nodeType) { | ||
return `<${v[NodeNameKey].toLowerCase()}>`; | ||
} | ||
if (10 === v.nodeType) { | ||
return `<!DOCTYPE ${v[NodeNameKey]}>`; | ||
} | ||
if (v.nodeType <= 11) { | ||
return v[NodeNameKey]; | ||
} | ||
} | ||
return "¯\\_(ツ)_/¯ instance obj"; | ||
} | ||
return v[Symbol.iterator] ? `[${Array.from(v).map((i => logValue(applyPath, i))).join(", ")}]` : "value" in v ? "string" == typeof v.value ? `"${v.value}"` : objToString(v.value) : objToString(v); | ||
} | ||
@@ -150,33 +171,20 @@ return (v => "object" == typeof v && v && v.then)(v) ? "Promise" : "function" === type ? `ƒ() ${v.name || ""}`.trim() : `¯\\_(ツ)_/¯ ${String(v)}`.trim(); | ||
const len = obj => obj.length; | ||
const getConstructorName = obj => obj && obj.constructor && obj.constructor.name || ""; | ||
const defineConstructorName = (Cstr, value) => Object.defineProperty(Cstr, "name", { | ||
value: value | ||
}); | ||
const nextTick = (cb, ms) => setTimeout(cb, ms); | ||
const EMPTY_ARRAY = []; | ||
Object.freeze(EMPTY_ARRAY); | ||
const randomId = () => Math.round(9999999999 * Math.random() + 4); | ||
const getInstanceStateValue = (instance, stateKey) => getStateValue(instance[InstanceIdKey], stateKey); | ||
const getStateValue = (instanceId, stateKey, stateRecord) => (stateRecord = webWorkerState[instanceId]) ? stateRecord[stateKey] : void 0; | ||
const setInstanceStateValue = (instance, stateKey, stateValue) => setStateValue(instance[InstanceIdKey], stateKey, stateValue); | ||
const setStateValue = (instanceId, stateKey, stateValue, stateRecord) => { | ||
(stateRecord = webWorkerState[instanceId] || {})[stateKey] = stateValue; | ||
webWorkerState[instanceId] = stateRecord; | ||
}; | ||
const setWorkerRef = (ref, refId) => { | ||
if (!(refId = webWorkerRefIdsByRef.get(ref))) { | ||
webWorkerRefIdsByRef.set(ref, refId = randomId()); | ||
webWorkerRefsByRefId[refId] = ref; | ||
} | ||
return refId; | ||
}; | ||
class WorkerProxy { | ||
constructor(interfaceType, instanceId, winId, nodeName) { | ||
this[WinIdKey] = winId; | ||
this[InstanceIdKey] = instanceId; | ||
this[NodeNameKey] = nodeName; | ||
return proxy(this[InterfaceTypeKey] = interfaceType, this, []); | ||
} | ||
} | ||
const definePrototypeProperty = (Cstr, memberName, descriptor) => Object.defineProperty(Cstr.prototype, memberName, { | ||
...descriptor, | ||
configurable: !0 | ||
}); | ||
const definePrototypePropertyDescriptor = (Cstr, propertyDescriptorMap) => Object.defineProperties(Cstr.prototype, propertyDescriptorMap); | ||
const definePrototypeValue = (Cstr, memberName, value) => definePrototypeProperty(Cstr, memberName, { | ||
value: value, | ||
writable: !0 | ||
}); | ||
const taskQueue = []; | ||
const queue = (instance, $applyPath$, isSetter, $assignInstanceId$) => { | ||
const queue = (instance, $applyPath$, isSetter, $assignInstanceId$, $groupedGetters$) => { | ||
const $instanceId$ = instance[InstanceIdKey]; | ||
@@ -186,14 +194,15 @@ taskQueue.push({ | ||
$instanceId$: $instanceId$, | ||
$interfaceType$: instance[InterfaceTypeKey], | ||
$nodeName$: instance[NodeNameKey], | ||
$applyPath$: $applyPath$, | ||
$assignInstanceId$: $assignInstanceId$ | ||
$applyPath$: [ ...instance[ApplyPathKey], ...$applyPath$ ], | ||
$assignInstanceId$: $assignInstanceId$, | ||
$groupedGetters$: $groupedGetters$ | ||
}); | ||
if (!isSetter) { | ||
return sync($instanceId$, $applyPath$); | ||
return sync(); | ||
} | ||
setTimeout((() => sync($instanceId$, $applyPath$)), 50); | ||
setTimeout(sync, 40); | ||
}; | ||
const sync = (instanceId, applyPath) => { | ||
const sync = () => { | ||
if (len(taskQueue)) { | ||
webWorkerCtx.$config$.logMainAccess && logWorker(`Main access, tasks sent: ${taskQueue.length}`); | ||
const endTask = taskQueue[len(taskQueue) - 1]; | ||
const accessReq = { | ||
@@ -208,204 +217,61 @@ $msgId$: randomId(), | ||
}))(0, accessReq); | ||
deserializeFromMain(instanceId, applyPath, accessRsp.$rtnValue$); | ||
deserializeFromMain(endTask.$instanceId$, endTask.$applyPath$, accessRsp.$rtnValue$); | ||
throw new Error(accessRsp.$error$); | ||
} | ||
}; | ||
const getter = (instance, applyPath) => { | ||
const rtnValue = queue(instance, applyPath); | ||
logWorkerGetter(instance, applyPath, rtnValue); | ||
const getter = (instance, applyPath, groupedGetters) => { | ||
const rtnValue = queue(instance, applyPath, !1, void 0, groupedGetters); | ||
((target, applyPath, rtnValue, restrictedToWorker = !1, groupedGetters = !1) => { | ||
if (webWorkerCtx.$config$.logGetters) { | ||
try { | ||
const msg = `Get ${logTargetProp(target, "Get", applyPath)}, returned: ${logValue(applyPath, rtnValue)}${restrictedToWorker ? " (restricted to worker)" : ""}${groupedGetters ? " (grouped getter)" : ""}`; | ||
msg.includes("Symbol(") || logWorker(msg, target[WinIdKey]); | ||
} catch (e) {} | ||
} | ||
})(instance, applyPath, rtnValue, !1, !!groupedGetters); | ||
return rtnValue; | ||
}; | ||
const setter = (instance, applyPath, value) => { | ||
const serializedValue = serializeInstanceForMain(instance, value); | ||
logWorkerSetter(instance, applyPath, value); | ||
queue(instance, [ ...applyPath, serializedValue, 0 ], !0); | ||
const setterApplyPath = [ ...applyPath, serializeInstanceForMain(instance, value), 0 ]; | ||
((target, applyPath, value, restrictedToWorker = !1) => { | ||
if (webWorkerCtx.$config$.logSetters) { | ||
try { | ||
applyPath = applyPath.slice(0, applyPath.length - 2); | ||
logWorker(`Set ${logTargetProp(target, "Set", applyPath)}, value: ${logValue(applyPath, value)}${restrictedToWorker ? " (restricted to worker)" : ""}`, target[WinIdKey]); | ||
} catch (e) {} | ||
} | ||
})(instance, setterApplyPath, value); | ||
queue(instance, setterApplyPath, !0); | ||
}; | ||
const callMethod = (instance, applyPath, args, assignInstanceId) => { | ||
const isSetter = setterMethods.some((m => applyPath.includes(m))); | ||
const rtnValue = queue(instance, [ ...applyPath, serializeInstanceForMain(instance, args) ], isSetter, assignInstanceId); | ||
logWorkerCall(instance, applyPath, args, rtnValue); | ||
const methodName = applyPath[len(applyPath) - 1]; | ||
const isSetter = setterMethods.includes(methodName); | ||
const callApplyPath = [ ...applyPath, serializeInstanceForMain(instance, args) ]; | ||
const rtnValue = queue(instance, callApplyPath, isSetter, assignInstanceId); | ||
((target, applyPath, args, rtnValue) => { | ||
if (webWorkerCtx.$config$.logCalls) { | ||
try { | ||
applyPath = applyPath.slice(0, applyPath.length - 1); | ||
logWorker(`Call ${logTargetProp(target, "Call", applyPath)}(${args.map((v => logValue(applyPath, v))).join(", ")}), returned: ${logValue(applyPath, rtnValue)}`, target[WinIdKey]); | ||
} catch (e) {} | ||
} | ||
})(instance, callApplyPath, args, rtnValue); | ||
isSetter || dimensionMethodNames.includes(methodName) || cachedDimensions.clear(); | ||
return rtnValue; | ||
}; | ||
const createGlobalConstructorProxy = (winId, interfaceType, cstrName) => defineConstructorName(class { | ||
constructor(...args) { | ||
const instanceId = randomId(); | ||
const workerProxy = new WorkerProxy(interfaceType, instanceId, winId); | ||
queue(workerProxy, [ 1, cstrName, serializeForMain(winId, instanceId, args) ]); | ||
((winId, cstrName, args) => { | ||
if (webWorkerCtx.$config$.logCalls) { | ||
try { | ||
logWorker(`Construct new ${cstrName}(${args.map((v => logValue([], v))).join(", ")})`, winId); | ||
} catch (e) {} | ||
} | ||
})(winId, cstrName, args); | ||
return workerProxy; | ||
} | ||
}, cstrName); | ||
const proxy = (interfaceType, target, initApplyPath) => !target || "object" != typeof target && "function" != typeof target || String(target).includes("[native") ? target : new Proxy(target, { | ||
get(target, propKey, receiver) { | ||
if ("symbol" == typeof propKey || Reflect.has(target, propKey)) { | ||
return Reflect.get(target, propKey, receiver); | ||
} | ||
if (shouldRestrictToWorker(interfaceType, propKey)) { | ||
if (Reflect.has(self, propKey)) { | ||
return Reflect.get(self, propKey, receiver); | ||
} | ||
const globalRtnValue = target[propKey]; | ||
logWorkerGetter(target, [ propKey ], globalRtnValue, !0); | ||
return globalRtnValue; | ||
} | ||
8 !== interfaceType && 10 !== interfaceType || (interfaceType = 3); | ||
const applyPath = [ ...initApplyPath, String(propKey) ]; | ||
const interfaceInfo = webWorkerCtx.$interfaces$.find((i => i[0] === interfaceType)); | ||
if (interfaceInfo) { | ||
const memberInfo = interfaceInfo[2][((applyPath, i) => { | ||
for (i = len(applyPath) - 1; i >= 0; i--) { | ||
if ("string" == typeof applyPath[i]) { | ||
return applyPath[i]; | ||
} | ||
} | ||
return applyPath[0]; | ||
})(applyPath)]; | ||
if (13 === memberInfo) { | ||
return (...args) => callMethod(target, applyPath, args); | ||
} | ||
if (memberInfo > 0) { | ||
return proxy(memberInfo, target, [ ...applyPath ]); | ||
} | ||
} | ||
const stateValue = getInstanceStateValue(target, applyPath[0]); | ||
return "function" == typeof stateValue ? (...args) => { | ||
const rtnValue = stateValue.apply(target, args); | ||
logWorkerCall(target, applyPath, args, rtnValue); | ||
return rtnValue; | ||
} : getter(target, applyPath); | ||
}, | ||
set(target, propKey, value, receiver) { | ||
if ("symbol" == typeof propKey || Reflect.has(target, propKey)) { | ||
Reflect.set(target, propKey, value, receiver); | ||
} else if (shouldRestrictToWorker(interfaceType, propKey)) { | ||
target[propKey] = value; | ||
logWorkerSetter(target, [ propKey ], value, !0); | ||
} else { | ||
setter(target, [ ...initApplyPath, propKey ], value); | ||
} | ||
return !0; | ||
}, | ||
has: (target, propKey) => 0 === interfaceType || Reflect.has(target, propKey) | ||
}); | ||
const shouldRestrictToWorker = (interfaceType, propKey) => 0 === interfaceType && (!webWorkerCtx.$windowMemberNames$.includes(propKey) || webWorkerCtx.$forwardedTriggers$.includes(propKey)); | ||
const setterMethods = [ "addEventListener", "createElement", "setAttribute", "setItem" ]; | ||
const constructInstance = (interfaceType, instanceId, winId, nodeName) => new (getConstructor(interfaceType, nodeName = 3 === interfaceType ? "#text" : 8 === interfaceType ? "#comment" : 11 === interfaceType ? "#document-fragment" : 10 === interfaceType ? "html" : nodeName))(interfaceType, instanceId, winId, nodeName); | ||
const getConstructor = (interfaceType, nodeName) => 1 === interfaceType ? getElementConstructor(nodeName) : interfaceType <= 11 ? self.Node : WorkerProxy; | ||
const getElementConstructor = nodeName => elementConstructors[nodeName] || elementConstructors.UNKNOWN; | ||
const elementConstructors = {}; | ||
class NodeList { | ||
constructor(nodes) { | ||
(this._ = nodes).map(((node, index) => this[index] = node)); | ||
} | ||
entries() { | ||
return this._.entries(); | ||
} | ||
forEach(cb, thisArg) { | ||
this._.map(cb, thisArg); | ||
} | ||
item(index) { | ||
return this[index]; | ||
} | ||
keys() { | ||
return this._.keys(); | ||
} | ||
get length() { | ||
return len(this._); | ||
} | ||
values() { | ||
return this._.values(); | ||
} | ||
[Symbol.iterator]() { | ||
return this._[Symbol.iterator](); | ||
} | ||
} | ||
const serializeForMain = ($winId$, $instanceId$, value, added) => { | ||
if (void 0 !== value) { | ||
let type = typeof value; | ||
if ("string" === type || "boolean" === type || "number" === type || null == value) { | ||
return [ 5, value ]; | ||
} | ||
if ("function" === type) { | ||
return [ 6, { | ||
$winId$: $winId$, | ||
$instanceId$: $instanceId$, | ||
$refId$: setWorkerRef(value) | ||
} ]; | ||
} | ||
added = added || new Set; | ||
if (Array.isArray(value)) { | ||
return added.has(value) ? [ 0, [] ] : [ 0, value.map((v => serializeForMain($winId$, $instanceId$, v, added))) ]; | ||
} | ||
if ("object" === type) { | ||
return "number" == typeof value[InstanceIdKey] ? [ 3, { | ||
$winId$: value[WinIdKey], | ||
$interfaceType$: value[InterfaceTypeKey], | ||
$instanceId$: value[InstanceIdKey], | ||
$nodeName$: value[NodeNameKey] | ||
} ] : value instanceof Event ? [ 1, serializeObjectForMain($winId$, $instanceId$, value, !1, added) ] : [ 4, serializeObjectForMain($winId$, $instanceId$, value, !0, added) ]; | ||
} | ||
} | ||
const setterMethods = "addEventListener,removeEventListener,createElement,createTextNode,insertBefore,insertRule,deleteRule,setAttribute,setItem,removeItem,classList.add,classList.remove,classList.toggle".split(","); | ||
const getInstanceStateValue = (instance, stateKey) => getStateValue(instance[InstanceIdKey], stateKey); | ||
const getStateValue = (instanceId, stateKey, stateRecord) => (stateRecord = webWorkerState[instanceId]) ? stateRecord[stateKey] : void 0; | ||
const setInstanceStateValue = (instance, stateKey, stateValue) => setStateValue(instance[InstanceIdKey], stateKey, stateValue); | ||
const setStateValue = (instanceId, stateKey, stateValue, stateRecord) => { | ||
(stateRecord = webWorkerState[instanceId] || {})[stateKey] = stateValue; | ||
webWorkerState[instanceId] = stateRecord; | ||
}; | ||
const serializeObjectForMain = (winId, instanceId, obj, includeFunctions, added, serializedObj, propName, propValue) => { | ||
serializedObj = {}; | ||
if (!added.has(obj)) { | ||
added.add(obj); | ||
for (propName in obj) { | ||
propValue = obj[propName]; | ||
(includeFunctions || "function" != typeof propValue) && (serializedObj[propName] = serializeForMain(winId, instanceId, propValue, added)); | ||
} | ||
const setWorkerRef = (ref, refId) => { | ||
if (!(refId = webWorkerRefIdsByRef.get(ref))) { | ||
webWorkerRefIdsByRef.set(ref, refId = randomId()); | ||
webWorkerRefsByRefId[refId] = ref; | ||
} | ||
return serializedObj; | ||
return refId; | ||
}; | ||
const serializeInstanceForMain = (instance, value) => instance ? serializeForMain(instance[WinIdKey], instance[InstanceIdKey], value) : [ 5, value ]; | ||
const deserializeFromMain = (instanceId, applyPath, serializedValueTransfer, serializedType, serializedValue) => { | ||
if (serializedValueTransfer) { | ||
serializedType = serializedValueTransfer[0]; | ||
serializedValue = serializedValueTransfer[1]; | ||
if (5 === serializedType) { | ||
return serializedValue; | ||
} | ||
if (6 === serializedType) { | ||
return deserializeRefFromMain(instanceId, applyPath, serializedValue); | ||
} | ||
if (3 === serializedType) { | ||
return constructSerializedInstance(serializedValue); | ||
} | ||
if (0 === serializedType) { | ||
return serializedValue.map((v => deserializeFromMain(instanceId, applyPath, v))); | ||
} | ||
if (1 === serializedType) { | ||
return (eventProps => new Proxy(new Event(eventProps.type, eventProps), { | ||
get: (target, propName) => propName in eventProps ? eventProps[propName] : target[String(propName)] | ||
}))(deserializeObjectFromMain(instanceId, applyPath, serializedValue)); | ||
} | ||
if (4 === serializedType) { | ||
return deserializeObjectFromMain(instanceId, applyPath, serializedValue); | ||
} | ||
} | ||
}; | ||
const deserializeObjectFromMain = (instanceId, applyPath, serializedValue, obj, key) => { | ||
obj = {}; | ||
for (key in serializedValue) { | ||
obj[key] = deserializeFromMain(instanceId, [ ...applyPath, key ], serializedValue[key]); | ||
} | ||
return obj; | ||
}; | ||
const constructSerializedInstance = ({$interfaceType$: $interfaceType$, $instanceId$: $instanceId$, $winId$: $winId$, $nodeName$: $nodeName$, $data$: $data$}) => { | ||
const env = environments[$winId$]; | ||
return 0 === $instanceId$ ? env.$window$ : 1 === $instanceId$ ? env.$document$ : 2 === $instanceId$ ? env.$documentElement$ : 3 === $instanceId$ ? env.$head$ : 4 === $instanceId$ ? env.$body$ : 21 === $interfaceType$ ? new NodeList($data$.map(constructSerializedInstance)) : constructInstance($interfaceType$, $instanceId$, $winId$, $nodeName$); | ||
}; | ||
const deserializeRefFromMain = (instanceId, applyPath, {$winId$: $winId$, $refId$: $refId$}) => { | ||
webWorkerRefsByRefId[$refId$] || webWorkerRefIdsByRef.set(webWorkerRefsByRefId[$refId$] = function(...args) { | ||
const instance = constructInstance(0, instanceId, $winId$); | ||
return callMethod(instance, applyPath, args); | ||
}, $refId$); | ||
return webWorkerRefsByRefId[$refId$]; | ||
}; | ||
const runScriptContent = (env, instanceId, scriptContent, winId) => { | ||
@@ -417,3 +283,3 @@ let errorMsg = ""; | ||
env.$currentScriptUrl$ = ""; | ||
env.$run$(scriptContent); | ||
run(env, scriptContent); | ||
} catch (contentError) { | ||
@@ -427,4 +293,9 @@ console.error(scriptContent, contentError); | ||
}; | ||
const run = (env, script) => { | ||
new Function(`with(this){${script}}`).apply(env.$window$); | ||
}; | ||
const runStateLoadHandlers = (instanceId, type, handlers) => { | ||
(handlers = getStateValue(instanceId, type)) && nextTick((() => handlers.map((cb => cb({ | ||
(handlers = getStateValue(instanceId, type)) && ((cb, ms) => { | ||
setTimeout(cb, ms); | ||
})((() => handlers.map((cb => cb({ | ||
type: type | ||
@@ -437,3 +308,3 @@ }))))); | ||
baseLocation = (env = environments[env.$parentWinId$]).$location$; | ||
if (env.$isTop$) { | ||
if (env.$winId$ === env.$parentWinId$) { | ||
break; | ||
@@ -445,174 +316,4 @@ } | ||
const resolveUrl = (env, url) => resolveToUrl(env, url) + ""; | ||
const getUrl = elm => resolveToUrl(getEnv(elm), getInstanceStateValue(elm, 3)); | ||
const getUrl = elm => resolveToUrl(getEnv(elm), getInstanceStateValue(elm, 4)); | ||
const getPartytownScript = () => `<script src=${JSON.stringify(webWorkerCtx.$libPath$ + "partytown.js")} async defer><\/script>`; | ||
class Node extends WorkerProxy { | ||
appendChild(node) { | ||
return this.insertBefore(node, null); | ||
} | ||
get ownerDocument() { | ||
return getEnv(this).$document$; | ||
} | ||
get href() {} | ||
set href(_) {} | ||
insertBefore(newNode, referenceNode) { | ||
const winId = newNode[WinIdKey] = this[WinIdKey]; | ||
const instanceId = newNode[InstanceIdKey]; | ||
const nodeName = newNode[NodeNameKey]; | ||
const isScript = "SCRIPT" === nodeName; | ||
const isIFrame = "IFRAME" === nodeName; | ||
if (isScript) { | ||
const scriptContent = getInstanceStateValue(newNode, 2); | ||
if (scriptContent) { | ||
const errorMsg = runScriptContent(getEnv(newNode), instanceId, scriptContent, winId); | ||
const datasetType = errorMsg ? "pterror" : "ptid"; | ||
const datasetValue = errorMsg || instanceId; | ||
setter(newNode, [ "type" ], "text/partytown-x"); | ||
setter(newNode, [ "dataset", datasetType ], datasetValue); | ||
setter(newNode, [ "innerHTML" ], scriptContent); | ||
} | ||
} | ||
newNode = callMethod(this, [ "insertBefore" ], [ newNode, referenceNode ]); | ||
isIFrame && (iframe => { | ||
let i = 0; | ||
const winId = iframe[InstanceIdKey]; | ||
const callback = () => { | ||
if (environments[winId] && environments[winId].$isInitialized$) { | ||
let type = getInstanceStateValue(iframe, 1) ? "error" : "load"; | ||
let handlers = getInstanceStateValue(iframe, type); | ||
handlers && handlers.map((handler => handler({ | ||
type: type | ||
}))); | ||
} else if (i++ > 2e3) { | ||
let errorHandlers = getInstanceStateValue(iframe, "error"); | ||
errorHandlers && errorHandlers.map((handler => handler({ | ||
type: "error" | ||
}))); | ||
console.error("Timeout"); | ||
} else { | ||
setTimeout(callback, 9); | ||
} | ||
}; | ||
callback(); | ||
})(newNode); | ||
isScript && webWorkerCtx.$postMessage$([ 6, winId ]); | ||
return newNode; | ||
} | ||
get nodeName() { | ||
return this[NodeNameKey]; | ||
} | ||
get nodeType() { | ||
return this[InterfaceTypeKey]; | ||
} | ||
} | ||
class HTMLElement extends Node { | ||
get localName() { | ||
return toLower(this.nodeName); | ||
} | ||
get namespaceURI() { | ||
return "http://www.w3.org/1999/xhtml"; | ||
} | ||
get tagName() { | ||
return this.nodeName; | ||
} | ||
} | ||
class HTMLSrcElement extends HTMLElement { | ||
addEventListener(...args) { | ||
let eventName = args[0]; | ||
let callbacks = getInstanceStateValue(this, eventName) || []; | ||
callbacks.push(args[1]); | ||
setInstanceStateValue(this, eventName, callbacks); | ||
} | ||
get async() { | ||
return !0; | ||
} | ||
set async(_) {} | ||
get defer() { | ||
return !0; | ||
} | ||
set defer(_) {} | ||
get onload() { | ||
let callbacks = getInstanceStateValue(this, "load"); | ||
return callbacks && callbacks[0] || null; | ||
} | ||
set onload(cb) { | ||
setInstanceStateValue(this, "load", cb ? [ cb ] : null); | ||
} | ||
get onerror() { | ||
let callbacks = getInstanceStateValue(this, "error"); | ||
return callbacks && callbacks[0] || null; | ||
} | ||
set onerror(cb) { | ||
setInstanceStateValue(this, "error", cb ? [ cb ] : null); | ||
} | ||
} | ||
class HTMLDocument extends HTMLElement { | ||
get body() { | ||
return getEnv(this).$body$; | ||
} | ||
createElement(tagName) { | ||
tagName = toUpper(tagName); | ||
const winId = this[WinIdKey]; | ||
const instanceId = randomId(); | ||
const elm = new (getElementConstructor(tagName))(1, instanceId, winId, tagName); | ||
callMethod(this, [ "createElement" ], [ tagName ], instanceId); | ||
if ("IFRAME" === tagName) { | ||
createEnvironment({ | ||
$winId$: instanceId, | ||
$parentWinId$: winId, | ||
$url$: "about:blank" | ||
}); | ||
setter(elm, [ "srcdoc" ], getPartytownScript()); | ||
} else { | ||
"SCRIPT" === tagName && setter(elm, [ "type" ], "text/partytown"); | ||
} | ||
return elm; | ||
} | ||
createEvent(type) { | ||
return new Event(type); | ||
} | ||
get currentScript() { | ||
const currentScriptId = getEnv(this).$currentScriptId$; | ||
return currentScriptId > 0 ? constructInstance(1, currentScriptId, this[WinIdKey], "SCRIPT") : null; | ||
} | ||
get defaultView() { | ||
return getEnvWindow(this); | ||
} | ||
get documentElement() { | ||
return getEnv(this).$documentElement$; | ||
} | ||
getElementsByTagName(tagName) { | ||
return "BODY" === (tagName = toUpper(tagName)) ? [ this.body ] : "HEAD" === tagName ? [ this.head ] : callMethod(this, [ "getElementsByTagName" ], [ tagName ]); | ||
} | ||
get head() { | ||
return getEnv(this).$head$; | ||
} | ||
get implementation() { | ||
return { | ||
hasFeature: () => !0 | ||
}; | ||
} | ||
get location() { | ||
return getEnv(this).$location$; | ||
} | ||
set location(url) { | ||
getEnv(this).$location$.href = url + ""; | ||
} | ||
get parentNode() { | ||
return null; | ||
} | ||
get parentElement() { | ||
return null; | ||
} | ||
get readyState() { | ||
return "complete"; | ||
} | ||
} | ||
const constructDocumentElementChild = (winId, instanceId, titleCaseNodeName, documentElement) => new (defineConstructorName(class extends HTMLElement { | ||
get parentElement() { | ||
return documentElement; | ||
} | ||
get parentNode() { | ||
return documentElement; | ||
} | ||
}, `HTML${titleCaseNodeName}Element`))(1, instanceId, winId, toUpper(titleCaseNodeName)); | ||
const createImageConstructor = winId => class HTMLImageElement { | ||
@@ -660,2 +361,11 @@ constructor() { | ||
}; | ||
const getOrCreateNodeInstance = (winId, instanceId, nodeName) => { | ||
let instance = webWorkerInstances.get(instanceId); | ||
if (!instance) { | ||
instance = createNodeInstance(winId, instanceId, nodeName); | ||
webWorkerInstances.set(instanceId, instance); | ||
} | ||
return instance; | ||
}; | ||
const createNodeInstance = (winId, instanceId, nodeName) => new (nodeConstructors[nodeName] ? nodeConstructors[nodeName] : nodeName.includes("-") ? nodeConstructors.UNKNOWN : self.HTMLElement)(winId, instanceId, [], nodeName); | ||
class Location extends URL { | ||
@@ -672,281 +382,784 @@ assign() { | ||
} | ||
const createEnvironment = ({$winId$: $winId$, $parentWinId$: $parentWinId$, $isTop$: $isTop$, $url$: $url$}) => { | ||
if (environments[$winId$]) { | ||
environments[$winId$].$location$.href = $url$; | ||
} else { | ||
class Window { | ||
constructor() { | ||
initWindowInstance(this); | ||
return proxy(0, this, []); | ||
class WorkerProxy { | ||
constructor(winId, instanceId, applyPath, nodeName) { | ||
this[WinIdKey] = winId; | ||
this[InstanceIdKey] = instanceId; | ||
this[ApplyPathKey] = applyPath || []; | ||
this[NodeNameKey] = nodeName; | ||
this[PropInstancesKey] = {}; | ||
} | ||
} | ||
class WorkerTrapProxy extends WorkerProxy { | ||
constructor(winId, instanceId, applyPath, nodeName) { | ||
super(winId, instanceId, applyPath, nodeName); | ||
return new Proxy(this, { | ||
get: (instance, propName) => getter(instance, [ propName ]), | ||
set(instance, propName, propValue) { | ||
setter(instance, [ propName ], propValue); | ||
return !0; | ||
} | ||
get document() { | ||
return $document$; | ||
} | ||
get frameElement() { | ||
if ($isTop$) { | ||
return null; | ||
}); | ||
} | ||
} | ||
class Window extends WorkerProxy { | ||
constructor($winId$, $parentWinId$, url) { | ||
super($winId$, 0); | ||
for (const globalName in self) { | ||
if (!(globalName in this) && "onmessage" !== globalName) { | ||
const value = self[globalName]; | ||
if (null != value) { | ||
const isFunction = "function" == typeof value && !value.toString().startsWith("class"); | ||
this[globalName] = isFunction ? value.bind(self) : value; | ||
} | ||
const env = getEnv(this); | ||
const iframeElementInstanceId = this[WinIdKey]; | ||
const iframeElementWinId = env.$parentWinId$; | ||
return constructInstance(1, iframeElementInstanceId, iframeElementWinId, "IFRAME"); | ||
} | ||
get globalThis() { | ||
return getEnvWindow(this); | ||
} | ||
get location() { | ||
return $location$; | ||
} | ||
set location(loc) { | ||
$location$.href = loc + ""; | ||
} | ||
get parent() { | ||
return environments[$parentWinId$].$window$; | ||
} | ||
get self() { | ||
return getEnvWindow(this); | ||
} | ||
get top() { | ||
for (const envWinId in environments) { | ||
if (environments[envWinId].$isTop$) { | ||
return environments[envWinId].$window$; | ||
} | ||
} | ||
Object.getOwnPropertyNames(self).map((globalName => { | ||
globalName in this || (this[globalName] = self[globalName]); | ||
})); | ||
for (const envCstrName in envGlobalConstructors) { | ||
this[envCstrName] = defineConstructorName(class { | ||
constructor(...cstrArgs) { | ||
const instance = new (0, envGlobalConstructors[envCstrName])($winId$, randomId()); | ||
const serializedCstrArgs = serializeInstanceForMain(instance, cstrArgs); | ||
queue(instance, [ 1, envCstrName, serializedCstrArgs ]); | ||
logWorkerGlobalConstructor($winId$, envCstrName, cstrArgs); | ||
return instance; | ||
} | ||
} | ||
get window() { | ||
return getEnvWindow(this); | ||
} | ||
}, envCstrName); | ||
} | ||
const $document$ = new HTMLDocument(9, 1, $winId$, "#document"); | ||
const $documentElement$ = new elementConstructors.HTML(1, 2, $winId$, "HTML"); | ||
const $head$ = constructDocumentElementChild($winId$, 3, "Head", $documentElement$); | ||
const $body$ = constructDocumentElementChild($winId$, 4, "Body", $documentElement$); | ||
const $location$ = new Location($url$); | ||
const windowFunctionWhiteList = "addEventListener,removeEventListener,dispatchEvent,postMessage".split(","); | ||
const windowPropertyWhiteList = "devicePixelRatio,innerHeight,innerWidth,onmessage,onload,onerror".split(","); | ||
const initWindowInstance = win => { | ||
win[WinIdKey] = $winId$; | ||
win[InstanceIdKey] = win[InterfaceTypeKey] = 0; | ||
for (const globalName in self) { | ||
"function" != typeof self[globalName] || globalName in win || (win[globalName] = self[globalName].bind(self)); | ||
} | ||
Object.getOwnPropertyNames(self).map((globalName => { | ||
globalName in win || (win[globalName] = self[globalName]); | ||
})); | ||
Object.keys(elementConstructors).map((tagName => win[elementConstructors[tagName].name] = elementConstructors[tagName])); | ||
webWorkerCtx.$windowMemberNames$.map((memberName => { | ||
const $interfaceType$ = webWorkerCtx.$windowMembers$[memberName]; | ||
const isFunctionInterface = 13 === $interfaceType$; | ||
!(isFunctionInterface || $interfaceType$ > 11) || memberName in win && !windowFunctionWhiteList.includes(memberName) || (win[memberName] = isFunctionInterface ? (...args) => callMethod(win, [ memberName ], args) : proxy($interfaceType$, win, [ "window", memberName ])); | ||
})); | ||
webWorkerCtx.$interfaces$.map((i => { | ||
const interfaceType = i[0]; | ||
const memberName = i[1]; | ||
win[memberName] = createGlobalConstructorProxy($winId$, interfaceType, memberName); | ||
})); | ||
win.Image = createImageConstructor($winId$); | ||
win.Window = Window; | ||
win.performance = self.performance; | ||
win.name = name + `${normalizedWinId($winId$)} (${$winId$})`; | ||
win.navigator = (winId => { | ||
const navigator = self.navigator; | ||
navigator.sendBeacon = (url, body) => { | ||
const env = environments[winId]; | ||
if (webWorkerCtx.$config$.logSendBeaconRequests) { | ||
try { | ||
logWorker(`sendBeacon: ${resolveUrl(env, url)}${body ? ", data: " + JSON.stringify(body) : ""}`); | ||
} catch (e) { | ||
console.error(e); | ||
} | ||
} | ||
const win = new Proxy(this, { | ||
has: () => !0 | ||
}); | ||
environments[$winId$] = { | ||
$winId$: $winId$, | ||
$parentWinId$: $parentWinId$, | ||
$window$: win, | ||
$document$: createNodeInstance($winId$, 1, "#document"), | ||
$documentElement$: createNodeInstance($winId$, 2, "HTML"), | ||
$head$: createNodeInstance($winId$, 3, "HEAD"), | ||
$body$: createNodeInstance($winId$, 4, "BODY"), | ||
$location$: new Location(url) | ||
}; | ||
this.requestAnimationFrame = cb => setTimeout((() => cb(performance.now())), 9); | ||
this.cancelAnimationFrame = id => clearTimeout(id); | ||
return win; | ||
} | ||
get body() { | ||
return getEnv(this).$body$; | ||
} | ||
get document() { | ||
return getEnv(this).$document$; | ||
} | ||
get documentElement() { | ||
return getEnv(this).$documentElement$; | ||
} | ||
get frameElement() { | ||
const env = getEnv(this); | ||
const parentWinId = env.$parentWinId$; | ||
const winId = env.$winId$; | ||
return winId === parentWinId ? null : getOrCreateNodeInstance(parentWinId, winId, "IFRAME"); | ||
} | ||
get globalThis() { | ||
return this; | ||
} | ||
get head() { | ||
return getEnv(this).$head$; | ||
} | ||
get location() { | ||
return getEnv(this).$location$; | ||
} | ||
set location(loc) { | ||
getEnv(this).$location$.href = loc + ""; | ||
} | ||
get Image() { | ||
return createImageConstructor(this[WinIdKey]); | ||
} | ||
get name() { | ||
const winId = this[WinIdKey]; | ||
return name + `${normalizedWinId(winId)} (${winId})`; | ||
} | ||
get navigator() { | ||
return (winId => { | ||
const navigator = self.navigator; | ||
navigator.sendBeacon = (url, body) => { | ||
const env = environments[winId]; | ||
if (webWorkerCtx.$config$.logSendBeaconRequests) { | ||
try { | ||
fetch(resolveUrl(env, url), { | ||
method: "POST", | ||
body: body, | ||
mode: "no-cors", | ||
keepalive: !0 | ||
}); | ||
return !0; | ||
logWorker(`sendBeacon: ${resolveUrl(env, url)}${body ? ", data: " + JSON.stringify(body) : ""}`); | ||
} catch (e) { | ||
console.error(e); | ||
return !1; | ||
} | ||
}; | ||
return navigator; | ||
})($winId$); | ||
windowPropertyWhiteList.map((propName => Object.defineProperty(win, propName, { | ||
get: () => getter($window$, [ propName ]), | ||
set: value => setter($window$, [ propName ], value) | ||
}))); | ||
}; | ||
const $window$ = new Window; | ||
environments[$winId$] = { | ||
$winId$: $winId$, | ||
$parentWinId$: $parentWinId$, | ||
$window$: $window$, | ||
$document$: $document$, | ||
$documentElement$: $documentElement$, | ||
$head$: $head$, | ||
$body$: $body$, | ||
$location$: $location$, | ||
$isTop$: $isTop$, | ||
$run$: script => { | ||
new Function(`with(this){${script}}`).apply($window$); | ||
} | ||
try { | ||
fetch(resolveUrl(env, url), { | ||
method: "POST", | ||
body: body, | ||
mode: "no-cors", | ||
keepalive: !0 | ||
}); | ||
return !0; | ||
} catch (e) { | ||
console.error(e); | ||
return !1; | ||
} | ||
}; | ||
return navigator; | ||
})(this[WinIdKey]); | ||
} | ||
get origin() { | ||
return getEnv(this).$location$.origin; | ||
} | ||
get parent() { | ||
return environments[getEnv(this).$parentWinId$].$window$; | ||
} | ||
get self() { | ||
return this; | ||
} | ||
get top() { | ||
for (const envWinId in environments) { | ||
if (environments[envWinId].$winId$ === environments[envWinId].$parentWinId$) { | ||
return environments[envWinId].$window$; | ||
} | ||
}; | ||
logWorker(`Created ${$isTop$ ? "top" : "iframe"} window ${normalizedWinId($winId$)} environment (${$winId$})`, $winId$); | ||
} | ||
} | ||
get window() { | ||
return this; | ||
} | ||
} | ||
const createEnvironment = ({$winId$: $winId$, $parentWinId$: $parentWinId$, $url$: $url$}) => { | ||
if (environments[$winId$]) { | ||
environments[$winId$].$location$.href = $url$; | ||
} else { | ||
new Window($winId$, $parentWinId$, $url$); | ||
logWorker(`Created ${$winId$ === $parentWinId$ ? "top" : "iframe"} window ${normalizedWinId($winId$)} environment (${$winId$})`, $winId$); | ||
} | ||
webWorkerCtx.$postMessage$([ 6, $winId$ ]); | ||
}; | ||
const getEnv = instance => environments[instance[WinIdKey]]; | ||
const getEnvWindow = instance => getEnv(instance).$window$; | ||
class HTMLAnchorElement extends HTMLElement { | ||
get hash() { | ||
return getUrl(this).hash; | ||
class Node extends WorkerProxy { | ||
appendChild(node) { | ||
return this.insertBefore(node, null); | ||
} | ||
get host() { | ||
return getUrl(this).host; | ||
get href() {} | ||
set href(_) {} | ||
insertBefore(newNode, referenceNode) { | ||
const winId = newNode[WinIdKey] = this[WinIdKey]; | ||
const instanceId = newNode[InstanceIdKey]; | ||
const nodeName = newNode[NodeNameKey]; | ||
const isScript = "SCRIPT" === nodeName; | ||
const isIFrame = "IFRAME" === nodeName; | ||
if (isScript) { | ||
const scriptContent = getInstanceStateValue(newNode, 3); | ||
if (scriptContent) { | ||
const errorMsg = runScriptContent(getEnv(newNode), instanceId, scriptContent, winId); | ||
const datasetType = errorMsg ? "pterror" : "ptid"; | ||
const datasetValue = errorMsg || instanceId; | ||
setter(newNode, [ "type" ], "text/partytown-x"); | ||
setter(newNode, [ "dataset", datasetType ], datasetValue); | ||
setter(newNode, [ "innerHTML" ], scriptContent); | ||
} | ||
} | ||
callMethod(this, [ "insertBefore" ], [ newNode, referenceNode ]); | ||
isIFrame && (iframe => { | ||
let i = 0; | ||
const winId = iframe[InstanceIdKey]; | ||
const callback = () => { | ||
if (environments[winId] && environments[winId].$isInitialized$) { | ||
let type = getInstanceStateValue(iframe, 1) ? "error" : "load"; | ||
let handlers = getInstanceStateValue(iframe, type); | ||
handlers && handlers.map((handler => handler({ | ||
type: type | ||
}))); | ||
} else if (i++ > 2e3) { | ||
let errorHandlers = getInstanceStateValue(iframe, "error"); | ||
errorHandlers && errorHandlers.map((handler => handler({ | ||
type: "error" | ||
}))); | ||
console.error("Timeout"); | ||
} else { | ||
setTimeout(callback, 9); | ||
} | ||
}; | ||
callback(); | ||
})(newNode); | ||
if (isScript) { | ||
sync(); | ||
webWorkerCtx.$postMessage$([ 6, winId ]); | ||
} | ||
return newNode; | ||
} | ||
get hostname() { | ||
return getUrl(this).hostname; | ||
get nodeName() { | ||
return this[NodeNameKey]; | ||
} | ||
get href() { | ||
return getUrl(this) + ""; | ||
get nodeType() { | ||
return 3; | ||
} | ||
set href(href) { | ||
setInstanceStateValue(this, 3, href += ""); | ||
setter(this, [ "href" ], href); | ||
get ownerDocument() { | ||
return getEnv(this).$document$; | ||
} | ||
get origin() { | ||
return getUrl(this).origin; | ||
} | ||
class Attr { | ||
constructor(serializedAttr) { | ||
this.name = serializedAttr[0]; | ||
this.value = serializedAttr[1]; | ||
} | ||
get pathname() { | ||
return getUrl(this).pathname; | ||
get nodeName() { | ||
return this.name; | ||
} | ||
get port() { | ||
return getUrl(this).port; | ||
get nodeType() { | ||
return 2; | ||
} | ||
get protocol() { | ||
return getUrl(this).protocol; | ||
} | ||
class NodeList { | ||
constructor(nodes) { | ||
(this._ = nodes).map(((node, index) => this[index] = node)); | ||
} | ||
get search() { | ||
return getUrl(this).search; | ||
entries() { | ||
return this._.entries(); | ||
} | ||
} | ||
class HTMLCanvasElement extends HTMLElement { | ||
getContext(...args) { | ||
return proxy(14, this, [ "getContext", serializeInstanceForMain(this, args) ]); | ||
forEach(cb, thisArg) { | ||
this._.map(cb, thisArg); | ||
} | ||
} | ||
class HTMLIFrameElement extends HTMLSrcElement { | ||
get contentDocument() { | ||
return this.contentWindow.document; | ||
item(index) { | ||
return this[index]; | ||
} | ||
get contentWindow() { | ||
const iframeContentWinId = this[InstanceIdKey]; | ||
return environments[iframeContentWinId].$window$; | ||
keys() { | ||
return this._.keys(); | ||
} | ||
get src() { | ||
return getInstanceStateValue(this, 3) || ""; | ||
get length() { | ||
return len(this._); | ||
} | ||
set src(url) { | ||
let xhr = new XMLHttpRequest; | ||
let xhrStatus; | ||
url = resolveUrl(getEnv(this), url); | ||
setInstanceStateValue(this, 1, void 0); | ||
setInstanceStateValue(this, 3, url); | ||
xhr.open("GET", url, !1); | ||
xhr.send(); | ||
xhrStatus = xhr.status; | ||
xhrStatus > 199 && xhrStatus < 300 ? setter(this, [ "srcdoc" ], ((url, html) => `<base href="${url}">` + html.replace(/<script>/g, '<script type="text/partytown">').replace(/<script /g, '<script type="text/partytown" ').replace(/text\/javascript/g, "text/partytown") + getPartytownScript())(url, xhr.responseText)) : setInstanceStateValue(this, 1, xhrStatus); | ||
values() { | ||
return this._.values(); | ||
} | ||
[Symbol.iterator]() { | ||
return this._[Symbol.iterator](); | ||
} | ||
} | ||
class HTMLScriptElement extends HTMLSrcElement { | ||
get innerHTML() { | ||
return getInstanceStateValue(this, 2) || ""; | ||
const serializeForMain = ($winId$, $instanceId$, value, added) => { | ||
if (void 0 !== value) { | ||
let type = typeof value; | ||
if ("string" === type || "boolean" === type || "number" === type || null == value) { | ||
return [ 9, value ]; | ||
} | ||
if ("function" === type) { | ||
return [ 10, { | ||
$winId$: $winId$, | ||
$instanceId$: $instanceId$, | ||
$refId$: setWorkerRef(value) | ||
} ]; | ||
} | ||
added = added || new Set; | ||
if (Array.isArray(value)) { | ||
return added.has(value) ? [ 0, [] ] : [ 0, value.map((v => serializeForMain($winId$, $instanceId$, v, added))) ]; | ||
} | ||
if ("object" === type) { | ||
return "number" == typeof value[InstanceIdKey] ? [ 6, { | ||
$winId$: value[WinIdKey], | ||
$instanceId$: value[InstanceIdKey] | ||
} ] : value instanceof Event ? [ 4, serializeObjectForMain($winId$, $instanceId$, value, !1, added) ] : [ 8, serializeObjectForMain($winId$, $instanceId$, value, !0, added) ]; | ||
} | ||
} | ||
set innerHTML(scriptContent) { | ||
setInstanceStateValue(this, 2, scriptContent); | ||
}; | ||
const serializeObjectForMain = (winId, instanceId, obj, includeFunctions, added, serializedObj, propName, propValue) => { | ||
serializedObj = {}; | ||
if (!added.has(obj)) { | ||
added.add(obj); | ||
for (propName in obj) { | ||
propValue = obj[propName]; | ||
(includeFunctions || "function" != typeof propValue) && (serializedObj[propName] = serializeForMain(winId, instanceId, propValue, added)); | ||
} | ||
} | ||
get innerText() { | ||
return this.innerHTML; | ||
return serializedObj; | ||
}; | ||
const serializeInstanceForMain = (instance, value) => instance ? serializeForMain(instance[WinIdKey], instance[InstanceIdKey], value) : [ 9, value ]; | ||
const deserializeFromMain = (instanceId, applyPath, serializedValueTransfer, serializedType, serializedValue) => { | ||
if (serializedValueTransfer) { | ||
serializedType = serializedValueTransfer[0]; | ||
serializedValue = serializedValueTransfer[1]; | ||
if (9 === serializedType || 2 === serializedType || 3 === serializedType) { | ||
return serializedValue; | ||
} | ||
if (10 === serializedType) { | ||
return deserializeRefFromMain(applyPath, serializedValue); | ||
} | ||
if (6 === serializedType) { | ||
return getOrCreateSerializedInstance(serializedValue); | ||
} | ||
if (7 === serializedType) { | ||
return new NodeList(serializedValue.map(getOrCreateSerializedInstance)); | ||
} | ||
if (1 === serializedType) { | ||
return new Attr(serializedValue); | ||
} | ||
if (0 === serializedType) { | ||
return serializedValue.map((v => deserializeFromMain(instanceId, applyPath, v))); | ||
} | ||
if (4 === serializedType) { | ||
return (eventProps => new Proxy(new Event(eventProps.type, eventProps), { | ||
get: (target, propName) => propName in eventProps ? eventProps[propName] : target[String(propName)] | ||
}))(deserializeObjectFromMain(instanceId, applyPath, serializedValue)); | ||
} | ||
if (8 === serializedType) { | ||
return deserializeObjectFromMain(instanceId, applyPath, serializedValue); | ||
} | ||
} | ||
set innerText(content) { | ||
this.innerHTML = content; | ||
}; | ||
const deserializeObjectFromMain = (instanceId, applyPath, serializedValue, obj, key) => { | ||
obj = {}; | ||
for (key in serializedValue) { | ||
obj[key] = deserializeFromMain(instanceId, [ ...applyPath, key ], serializedValue[key]); | ||
} | ||
get src() { | ||
return getInstanceStateValue(this, 3) || ""; | ||
return obj; | ||
}; | ||
const getOrCreateSerializedInstance = ({$winId$: $winId$, $instanceId$: $instanceId$, $nodeName$: $nodeName$}) => getPlatformInstance($winId$, $instanceId$) || getOrCreateNodeInstance($winId$, $instanceId$, $nodeName$); | ||
const getPlatformInstance = (winId, instanceId) => { | ||
const env = environments[winId]; | ||
return 0 === instanceId ? env.$window$ : 1 === instanceId ? env.$document$ : 2 === instanceId ? env.$documentElement$ : 3 === instanceId ? env.$head$ : 4 === instanceId ? env.$body$ : void 0; | ||
}; | ||
const deserializeRefFromMain = (applyPath, {$winId$: $winId$, $instanceId$: $instanceId$, $nodeName$: $nodeName$, $refId$: $refId$}) => { | ||
webWorkerRefsByRefId[$refId$] || webWorkerRefIdsByRef.set(webWorkerRefsByRefId[$refId$] = function(...args) { | ||
const instance = getOrCreateNodeInstance($winId$, $instanceId$, $nodeName$); | ||
return callMethod(instance, applyPath, args); | ||
}, $refId$); | ||
return webWorkerRefsByRefId[$refId$]; | ||
}; | ||
const HTMLStyleDescriptorMap = { | ||
sheet: { | ||
get() { | ||
return new CSSStyleSheet(this); | ||
} | ||
} | ||
set src(url) { | ||
url = resolveUrl(getEnv(this), url); | ||
setInstanceStateValue(this, 3, url); | ||
setter(this, [ "src" ], url); | ||
}; | ||
class CSSStyleSheet { | ||
constructor(ownerNode) { | ||
this.ownerNode = ownerNode; | ||
} | ||
get textContent() { | ||
return this.innerHTML; | ||
get cssRules() { | ||
const ownerNode = this.ownerNode; | ||
return new Proxy({}, { | ||
get(target, propKey) { | ||
const propName = String(propKey); | ||
return "item" === propName ? index => getCssRule(ownerNode, index) : "length" === propName ? getCssRules(ownerNode).length : isNaN(propName) ? target[propKey] : getCssRule(ownerNode, propName); | ||
} | ||
}); | ||
} | ||
set textContent(content) { | ||
this.innerHTML = content; | ||
insertRule(ruleText, index) { | ||
const cssRules = getCssRules(this.ownerNode); | ||
if ((index = void 0 === index ? 0 : index) >= 0 && index <= cssRules.length) { | ||
callMethod(this.ownerNode, [ "sheet", "insertRule" ], [ ruleText, index ]); | ||
cssRules.splice(index, 0, 0); | ||
} | ||
return index; | ||
} | ||
get type() { | ||
return getter(this, [ "type" ]); | ||
deleteRule(index) { | ||
callMethod(this.ownerNode, [ "sheet", "deleteRule" ], [ index ]); | ||
getCssRules(this.ownerNode).splice(index, 1); | ||
} | ||
set type(type) { | ||
"text/javascript" !== type && setter(this, [ "type" ], type); | ||
} | ||
const getCssRules = ownerNode => { | ||
let cssRules = getInstanceStateValue(ownerNode, 2); | ||
if (!cssRules) { | ||
cssRules = getter(ownerNode, [ "sheet", "cssRules" ]); | ||
setInstanceStateValue(ownerNode, 2, cssRules); | ||
} | ||
} | ||
const SheetKey = Symbol(); | ||
class HTMLStyleElement extends HTMLElement { | ||
get sheet() { | ||
const ownerElement = this; | ||
if (void 0 === ownerElement[SheetKey]) { | ||
const sheetInfo = getter(ownerElement, [ "sheet" ]); | ||
if (null === sheetInfo) { | ||
ownerElement[SheetKey] = sheetInfo; | ||
return cssRules; | ||
}; | ||
const getCssRule = (ownerNode, index) => { | ||
let cssRules = getCssRules(ownerNode); | ||
0 === cssRules[index] && (cssRules[index] = getter(ownerNode, [ "sheet", "cssRules", parseInt(index, 10) ])); | ||
return cssRules[index]; | ||
}; | ||
const DocumentDescriptorMap = { | ||
body: { | ||
get() { | ||
return getEnv(this).$body$; | ||
} | ||
}, | ||
createElement: { | ||
value(tagName) { | ||
tagName = tagName.toUpperCase(); | ||
const winId = this[WinIdKey]; | ||
const instanceId = randomId(); | ||
const elm = getOrCreateNodeInstance(winId, instanceId, tagName); | ||
callMethod(this, [ "createElement" ], [ tagName ], instanceId); | ||
if ("IFRAME" === tagName) { | ||
createEnvironment({ | ||
$winId$: instanceId, | ||
$parentWinId$: winId, | ||
$url$: "about:blank" | ||
}); | ||
setter(elm, [ "srcdoc" ], getPartytownScript()); | ||
} else { | ||
class CSSStyleSheet { | ||
get cssRules() { | ||
return sheetInfo.cssRules; | ||
} | ||
deleteRule(index) { | ||
ownerElement[SheetKey] = void 0; | ||
callMethod(ownerElement, [ "sheet", "deleteRule" ], [ index ]); | ||
} | ||
insertRule(rule, index) { | ||
ownerElement[SheetKey] = void 0; | ||
return callMethod(ownerElement, [ "sheet", "insertRule" ], [ rule, index ]); | ||
} | ||
"SCRIPT" === tagName && setter(elm, [ "type" ], "text/partytown"); | ||
} | ||
return elm; | ||
} | ||
}, | ||
createElementNS: { | ||
value(ns, tagName) { | ||
tagName = tagName.toUpperCase(); | ||
const winId = this[WinIdKey]; | ||
const instanceId = randomId(); | ||
const nsElm = getOrCreateNodeInstance(winId, instanceId, tagName); | ||
callMethod(this, [ "createElementNS" ], [ ns, tagName ], instanceId); | ||
return nsElm; | ||
} | ||
}, | ||
createTextNode: { | ||
value(text) { | ||
const winId = this[WinIdKey]; | ||
const instanceId = randomId(); | ||
const textNode = getOrCreateNodeInstance(winId, instanceId, "#text"); | ||
callMethod(this, [ "createTextNode" ], [ text ], instanceId); | ||
return textNode; | ||
} | ||
}, | ||
createEvent: { | ||
value: type => new Event(type) | ||
}, | ||
currentScript: { | ||
get() { | ||
const winId = this[WinIdKey]; | ||
const currentScriptId = getEnv(this).$currentScriptId$; | ||
return currentScriptId > 0 ? getOrCreateNodeInstance(winId, currentScriptId, "SCRIPT") : null; | ||
} | ||
}, | ||
defaultView: { | ||
get() { | ||
return (instance => getEnv(instance).$window$)(this); | ||
} | ||
}, | ||
documentElement: { | ||
get() { | ||
return getEnv(this).$documentElement$; | ||
} | ||
}, | ||
getElementsByTagName: { | ||
value(tagName) { | ||
return "BODY" === (tagName = tagName.toUpperCase()) ? [ getEnv(this).$body$ ] : "HEAD" === tagName ? [ getEnv(this).$head$ ] : callMethod(this, [ "getElementsByTagName" ], [ tagName ]); | ||
} | ||
}, | ||
head: { | ||
get() { | ||
return getEnv(this).$head$; | ||
} | ||
}, | ||
implementation: { | ||
value: { | ||
hasFeature: noop | ||
} | ||
}, | ||
location: { | ||
get() { | ||
return getEnv(this).$location$; | ||
}, | ||
set(url) { | ||
getEnv(this).$location$.href = url + ""; | ||
} | ||
}, | ||
nodeType: { | ||
value: 9 | ||
}, | ||
parentNode: { | ||
value: null | ||
}, | ||
parentElement: { | ||
value: null | ||
}, | ||
readyState: { | ||
value: "complete" | ||
} | ||
}; | ||
const ElementDescriptorMap = { | ||
localName: { | ||
get() { | ||
return this[NodeNameKey].toLowerCase(); | ||
} | ||
}, | ||
namespaceURI: { | ||
get() { | ||
return "http://www.w3.org/" + ("SVG" === this[NodeNameKey] ? "2000/svg" : "1999/xhtml"); | ||
} | ||
}, | ||
nodeType: { | ||
value: 1 | ||
}, | ||
tagName: { | ||
get() { | ||
return this[NodeNameKey]; | ||
} | ||
} | ||
}; | ||
const HTMLAnchorDescriptorMap = { | ||
hash: { | ||
get() { | ||
return getUrl(this).hash; | ||
} | ||
}, | ||
host: { | ||
get() { | ||
return getUrl(this).host; | ||
} | ||
}, | ||
hostname: { | ||
get() { | ||
return getUrl(this).hostname; | ||
} | ||
}, | ||
href: { | ||
get() { | ||
return getUrl(this).href; | ||
}, | ||
set(href) { | ||
setInstanceStateValue(this, 4, href += ""); | ||
setter(this, [ "href" ], href); | ||
} | ||
}, | ||
origin: { | ||
get() { | ||
return getUrl(this).origin; | ||
} | ||
}, | ||
pathname: { | ||
get() { | ||
return getUrl(this).pathname; | ||
} | ||
}, | ||
port: { | ||
get() { | ||
return getUrl(this).port; | ||
} | ||
}, | ||
protocol: { | ||
get() { | ||
return getUrl(this).protocol; | ||
} | ||
}, | ||
search: { | ||
get() { | ||
return getUrl(this).search; | ||
} | ||
} | ||
}; | ||
const HTMLCanvasDescriptorMap = { | ||
getContext: { | ||
value(...args) { | ||
const applyPath = [ "getContext", serializeInstanceForMain(this, args) ]; | ||
return new self.CanvasRenderingContext2D(this[WinIdKey], this[InstanceIdKey], applyPath); | ||
} | ||
} | ||
}; | ||
const HTMLSrcElementDescriptorMap = { | ||
addEventListener: { | ||
value(...args) { | ||
const eventName = args[0]; | ||
const callbacks = getInstanceStateValue(this, eventName) || []; | ||
callbacks.push(args[1]); | ||
setInstanceStateValue(this, eventName, callbacks); | ||
} | ||
}, | ||
async: { | ||
get: noop, | ||
set: noop | ||
}, | ||
defer: { | ||
get: noop, | ||
set: noop | ||
}, | ||
onload: { | ||
get() { | ||
let callbacks = getInstanceStateValue(this, "load"); | ||
return callbacks && callbacks[0] || null; | ||
}, | ||
set(cb) { | ||
setInstanceStateValue(this, "load", cb ? [ cb ] : null); | ||
} | ||
}, | ||
onerror: { | ||
get() { | ||
let callbacks = getInstanceStateValue(this, "error"); | ||
return callbacks && callbacks[0] || null; | ||
}, | ||
set(cb) { | ||
setInstanceStateValue(this, "error", cb ? [ cb ] : null); | ||
} | ||
} | ||
}; | ||
const HTMLIFrameDescriptorMap = { | ||
contentDocument: { | ||
get() { | ||
return this.contentWindow.document; | ||
} | ||
}, | ||
contentWindow: { | ||
get() { | ||
const iframeContentWinId = this[InstanceIdKey]; | ||
return environments[iframeContentWinId].$window$; | ||
} | ||
}, | ||
src: { | ||
get() { | ||
return getInstanceStateValue(this, 4) || ""; | ||
}, | ||
set(url) { | ||
let xhr = new XMLHttpRequest; | ||
let xhrStatus; | ||
url = resolveUrl(getEnv(this), url); | ||
setInstanceStateValue(this, 1, void 0); | ||
setInstanceStateValue(this, 4, url); | ||
xhr.open("GET", url, !1); | ||
xhr.send(); | ||
xhrStatus = xhr.status; | ||
xhrStatus > 199 && xhrStatus < 300 ? setter(this, [ "srcdoc" ], ((url, html) => `<base href="${url}">` + html.replace(/<script>/g, '<script type="text/partytown">').replace(/<script /g, '<script type="text/partytown" ').replace(/text\/javascript/g, "text/partytown") + getPartytownScript())(url, xhr.responseText)) : setInstanceStateValue(this, 1, xhrStatus); | ||
} | ||
}, | ||
...HTMLSrcElementDescriptorMap | ||
}; | ||
const innerHTMLDescriptor = { | ||
get() { | ||
return getInstanceStateValue(this, 3) || ""; | ||
}, | ||
set(scriptContent) { | ||
setInstanceStateValue(this, 3, scriptContent); | ||
} | ||
}; | ||
const HTMLScriptDescriptorMap = { | ||
innerHTML: innerHTMLDescriptor, | ||
innerText: innerHTMLDescriptor, | ||
src: { | ||
get() { | ||
return getInstanceStateValue(this, 4) || ""; | ||
}, | ||
set(url) { | ||
url = resolveUrl(getEnv(this), url); | ||
setInstanceStateValue(this, 4, url); | ||
setter(this, [ "src" ], url); | ||
} | ||
}, | ||
getAttribute: { | ||
value(attrName) { | ||
return "src" === attrName ? this.src : callMethod(this, [ "getAttribute" ], [ attrName ]); | ||
} | ||
}, | ||
setAttribute: { | ||
value(attrName, attrValue) { | ||
"src" === attrName ? this.src = attrValue : callMethod(this, [ "setAttribute" ], [ attrName, attrValue ]); | ||
} | ||
}, | ||
textContent: innerHTMLDescriptor, | ||
type: { | ||
get() { | ||
return getter(this, [ "type" ]); | ||
}, | ||
set(type) { | ||
"text/javascript" !== type && setter(this, [ "type" ], type); | ||
} | ||
}, | ||
...HTMLSrcElementDescriptorMap | ||
}; | ||
const defineWorkerInterface = ([cstrName, superCstrName, members, interfaceType, nodeName]) => { | ||
const SuperCstr = TrapConstructors[cstrName] ? WorkerTrapProxy : "Object" === superCstrName || "EventTarget" === superCstrName ? WorkerProxy : self[superCstrName]; | ||
const Cstr = self[cstrName] = defineConstructorName(self[cstrName] || class extends SuperCstr {}, cstrName); | ||
12 === interfaceType && (envGlobalConstructors[cstrName] = Cstr); | ||
nodeName && (nodeConstructors[nodeName] = Cstr); | ||
members.map((([memberName, memberType, staticValue]) => { | ||
memberName in Cstr.prototype || memberName in SuperCstr.prototype || ("string" == typeof memberType ? definePrototypeProperty(Cstr, memberName, { | ||
get() { | ||
if (!this[PropInstancesKey][memberName]) { | ||
const winId = this[WinIdKey]; | ||
const instanceId = this[InstanceIdKey]; | ||
const applyPath = [ ...this[ApplyPathKey], memberName ]; | ||
const nodeName = this[NodeNameKey]; | ||
const PropCstr = self[memberType]; | ||
this[PropInstancesKey][memberName] = new PropCstr(winId, instanceId, applyPath, nodeName); | ||
} | ||
ownerElement[SheetKey] = new CSSStyleSheet; | ||
return this[PropInstancesKey][memberName]; | ||
}, | ||
set(value) { | ||
this[PropInstancesKey][memberName] = value; | ||
} | ||
}) : 5 === memberType ? definePrototypeValue(Cstr, memberName, (function(...args) { | ||
return callMethod(this, [ memberName ], args); | ||
})) : memberType > 0 && (void 0 !== staticValue ? definePrototypeValue(Cstr, memberName, staticValue) : definePrototypeProperty(Cstr, memberName, { | ||
get() { | ||
return getter(this, [ memberName ]); | ||
}, | ||
set(value) { | ||
return setter(this, [ memberName ], value); | ||
} | ||
}))); | ||
})); | ||
}; | ||
const TrapConstructors = { | ||
CSSStyleDeclaration: 1, | ||
DOMStringMap: 1, | ||
NamedNodeMap: 1 | ||
}; | ||
const patchPrototypes = () => { | ||
const Element = self.Element; | ||
const DocumentFragment = self.DocumentFragment; | ||
(() => { | ||
"atob,btoa,crypto,indexedDB,performance,setTimeout,setInterval,clearTimeout,clearInterval".split(",").map((memberName => delete Window.prototype[memberName])); | ||
})(); | ||
definePrototypePropertyDescriptor(Element, ElementDescriptorMap); | ||
definePrototypePropertyDescriptor(self.Document, DocumentDescriptorMap); | ||
definePrototypePropertyDescriptor(self.HTMLAnchorElement, HTMLAnchorDescriptorMap); | ||
definePrototypePropertyDescriptor(self.HTMLCanvasElement, HTMLCanvasDescriptorMap); | ||
definePrototypePropertyDescriptor(self.HTMLIFrameElement, HTMLIFrameDescriptorMap); | ||
definePrototypePropertyDescriptor(self.HTMLScriptElement, HTMLScriptDescriptorMap); | ||
definePrototypePropertyDescriptor(self.HTMLStyleElement, HTMLStyleDescriptorMap); | ||
constantProps(CSSStyleSheet, { | ||
type: "text/css" | ||
}); | ||
definePrototypeNodeType(self.Comment, 8); | ||
definePrototypeNodeType(self.DocumentType, 10); | ||
definePrototypeNodeType(DocumentFragment, 11); | ||
cachedTreeProps(Node, "childNodes,firstChild,isConnected,lastChild,nextSibling,parentElement,parentNode,previousSibling"); | ||
cachedTreeProps(Element, elementTreePropNames); | ||
cachedTreeProps(DocumentFragment, elementTreePropNames); | ||
cachedDimensionProps(Element); | ||
cachedDimensionProps(Window); | ||
cachedDimensionMethods(Element); | ||
}; | ||
const definePrototypeNodeType = (Cstr, nodeType) => definePrototypeValue(Cstr, "nodeType", nodeType); | ||
const cachedTreeProps = (Cstr, treeProps) => treeProps.split(",").map((propName => definePrototypeProperty(Cstr, propName, { | ||
get() { | ||
let cacheKey = getDimensionCacheKey(this, propName); | ||
let result = cachedTree.get(cacheKey); | ||
if (!result) { | ||
result = getter(this, [ propName ]); | ||
cachedTree.set(cacheKey, result); | ||
} | ||
return ownerElement[SheetKey]; | ||
return result; | ||
} | ||
} | ||
const initWebWorker = initWebWorkerData => { | ||
Object.assign(webWorkerCtx, initWebWorkerData); | ||
webWorkerCtx.$forwardedTriggers$ = (webWorkerCtx.$config$.forward || EMPTY_ARRAY).map((f => f[0])); | ||
webWorkerCtx.$windowMembers$ = webWorkerCtx.$interfaces$[0][2]; | ||
webWorkerCtx.$windowMemberNames$ = Object.keys(webWorkerCtx.$windowMembers$).filter((m => !webWorkerCtx.$forwardedTriggers$.includes(m))); | ||
webWorkerCtx.$postMessage$ = postMessage.bind(self); | ||
self.postMessage = self.importScripts = void 0; | ||
self.Node = Node; | ||
self.Element = self.HTMLElement = HTMLSrcElement; | ||
self.Document = HTMLDocument; | ||
webWorkerCtx.$htmlConstructors$.map((htmlCstrName => elementConstructors[(t => ({ | ||
IMAGE: "IMG", | ||
OLIST: "OL", | ||
PARAGRAPH: "P", | ||
TABLECELL: "TD", | ||
TABLEROW: "TR", | ||
ULIST: "UL" | ||
}[t = toUpper(t.substr(4).replace("Element", ""))] || t))(htmlCstrName)] = defineConstructorName(class extends HTMLElement {}, htmlCstrName))); | ||
elementConstructors.A = HTMLAnchorElement; | ||
elementConstructors.CANVAS = HTMLCanvasElement; | ||
elementConstructors.IFRAME = HTMLIFrameElement; | ||
elementConstructors.SCRIPT = HTMLScriptElement; | ||
elementConstructors.STYLE = HTMLStyleElement; | ||
webWorkerCtx.$isInitialized$ = 1; | ||
logWorker("Initialized web worker"); | ||
}; | ||
}))); | ||
const getDimensionCacheKey = (instance, memberName) => instance[WinIdKey] + "." + instance[InstanceIdKey] + "." + memberName; | ||
const constantProps = (Cstr, props) => Object.keys(props).map((propName => definePrototypeValue(Cstr, propName, props[propName]))); | ||
const cachedDimensionProps = Cstr => dimensionPropNames.map((propName => { | ||
definePrototypeProperty(Cstr, propName, { | ||
get() { | ||
const dimension = cachedDimensions.get(getDimensionCacheKey(this, propName)); | ||
if ("number" == typeof dimension) { | ||
return dimension; | ||
} | ||
const groupedDimensions = getter(this, [ propName ], dimensionPropNames); | ||
Object.entries(groupedDimensions).map((([dimensionPropName, value]) => { | ||
cachedDimensions.set(getDimensionCacheKey(this, dimensionPropName), value); | ||
})); | ||
return groupedDimensions[propName]; | ||
} | ||
}); | ||
})); | ||
const cachedDimensionMethods = Cstr => dimensionMethodNames.map((methodName => { | ||
Cstr.prototype[methodName] = function() { | ||
let cacheKey = getDimensionCacheKey(this, methodName); | ||
let dimensions = cachedDimensions.get(cacheKey); | ||
if (!dimensions) { | ||
dimensions = callMethod(this, [ methodName ], EMPTY_ARRAY); | ||
cachedDimensions.set(cacheKey, dimensions); | ||
} | ||
return dimensions; | ||
}; | ||
})); | ||
const queuedEvents = []; | ||
@@ -971,13 +1184,12 @@ const receiveMessageFromSandboxToWorker = ev => { | ||
scriptSrc = scriptUrl + ""; | ||
setStateValue(instanceId, 3, scriptSrc); | ||
setStateValue(instanceId, 4, scriptSrc); | ||
webWorkerCtx.$config$.logScriptExecution && logWorker(`Execute script (${instanceId}) src: ${scriptSrc}`, winId); | ||
if (scriptUrl.origin !== origin) { | ||
try { | ||
await self.fetch(scriptSrc, { | ||
method: "OPTIONS" | ||
}); | ||
} catch (e) { | ||
scriptSrc = "https://partytown.builder.io/api/proxy?p=" + scriptSrc; | ||
logWorker(`Proxied script (${instanceId}) src: ${scriptSrc}`, winId); | ||
try { | ||
rsp = await self.fetch(scriptSrc); | ||
} catch (e) { | ||
if (scriptUrl.origin === origin) { | ||
throw e; | ||
} | ||
scriptSrc = "https://partytown.builder.io/api/proxy?p=" + scriptSrc; | ||
logWorker(`Proxied script (${instanceId}) src: ${scriptSrc}`, winId); | ||
} | ||
@@ -989,3 +1201,3 @@ rsp = await self.fetch(scriptSrc); | ||
env.$currentScriptUrl$ = scriptSrc; | ||
env.$run$(scriptContent); | ||
run(env, scriptContent); | ||
runStateLoadHandlers(instanceId, "load"); | ||
@@ -1039,3 +1251,4 @@ } else { | ||
const winId = msg[1]; | ||
const winType = environments[winId].$isTop$ ? "top" : "iframe"; | ||
const env = environments[winId]; | ||
const winType = env.$winId$ === env.$parentWinId$ ? "top" : "iframe"; | ||
logWorker(`Initialized ${winType} window ${normalizedWinId(winId)} environment (${winId}) 🎉`, winId); | ||
@@ -1045,9 +1258,19 @@ } | ||
} else if (1 === msgType) { | ||
initWebWorker(msg[1]); | ||
(initWebWorkerData => { | ||
Object.assign(webWorkerCtx, initWebWorkerData); | ||
webWorkerCtx.$forwardedTriggers$ = (webWorkerCtx.$config$.forward || EMPTY_ARRAY).map((f => f[0])); | ||
webWorkerCtx.$postMessage$ = postMessage.bind(self); | ||
self.postMessage = self.importScripts = void 0; | ||
self.Node = Node; | ||
self.Window = Window; | ||
self.CSSStyleSheet = CSSStyleSheet; | ||
webWorkerCtx.$interfaces$.map(defineWorkerInterface); | ||
patchPrototypes(); | ||
webWorkerCtx.$isInitialized$ = 1; | ||
logWorker("Initialized web worker"); | ||
})(msg[1]); | ||
webWorkerCtx.$postMessage$([ 2 ]); | ||
nextTick((() => { | ||
queuedEvents.length && logWorker(`Queued ready messages: ${queuedEvents.length}`); | ||
queuedEvents.slice().forEach(receiveMessageFromSandboxToWorker); | ||
queuedEvents.length = 0; | ||
})); | ||
queuedEvents.length && logWorker(`Queued ready messages: ${queuedEvents.length}`); | ||
queuedEvents.slice().forEach(receiveMessageFromSandboxToWorker); | ||
queuedEvents.length = 0; | ||
} else { | ||
@@ -1054,0 +1277,0 @@ queuedEvents.push(ev); |
(self => { | ||
const WinIdKey = Symbol(); | ||
const InstanceIdKey = Symbol(); | ||
const InterfaceTypeKey = Symbol(); | ||
const NodeNameKey = Symbol(); | ||
const ApplyPathKey = Symbol(); | ||
const PropInstancesKey = Symbol(); | ||
const webWorkerInstances = new Map; | ||
const webWorkerRefsByRefId = {}; | ||
const webWorkerRefIdsByRef = new WeakMap; | ||
const nodeConstructors = {}; | ||
const envGlobalConstructors = {}; | ||
const webWorkerState = {}; | ||
const webWorkerCtx = {}; | ||
const environments = {}; | ||
const toLower = str => str.toLowerCase(); | ||
const toUpper = str => str.toUpperCase(); | ||
const cachedDimensions = new Map; | ||
const cachedTree = new Map; | ||
const dimensionMethodNames = "getClientRects,getBoundingClientRect".split(","); | ||
const dimensionPropNames = "innerHeight,innerWidth,outerHeight,outerWidth,clientHeight,clientWidth,clientTop,clientLeft,scrollHeight,scrollWidth,scrollTop,scrollLeft,offsetHeight,offsetWidth,offsetTop,offsetLeft".split(","); | ||
const elementTreePropNames = "childElementCount,children,firstElementChild,lastElementChild,nextElementSibling,previousElementSibling"; | ||
const noop = () => !0; | ||
const logWorker = (msg, winId = -1) => { | ||
@@ -44,21 +52,6 @@ try { | ||
}; | ||
const logWorkerGetter = (target, applyPath, rtnValue, restrictedToWorker = !1) => { | ||
if (webWorkerCtx.$config$.logGetters) { | ||
try { | ||
const msg = `Get ${logTargetProp(target, "Get", applyPath)}, returned: ${logValue(applyPath, rtnValue)}${restrictedToWorker ? " (restricted to worker)" : ""}`; | ||
msg.includes("Symbol(") || logWorker(msg, target[WinIdKey]); | ||
} catch (e) {} | ||
} | ||
}; | ||
const logWorkerSetter = (target, applyPath, value, restrictedToWorker = !1) => { | ||
if (webWorkerCtx.$config$.logSetters) { | ||
try { | ||
logWorker(`Set ${logTargetProp(target, "Set", applyPath)}, value: ${logValue(applyPath, value)}${restrictedToWorker ? " (restricted to worker)" : ""}`, target[WinIdKey]); | ||
} catch (e) {} | ||
} | ||
}; | ||
const logWorkerCall = (target, applyPath, args, rtnValue) => { | ||
const logWorkerGlobalConstructor = (winId, cstrName, args) => { | ||
if (webWorkerCtx.$config$.logCalls) { | ||
try { | ||
logWorker(`Call ${logTargetProp(target, "Call", applyPath)}(${args.map((v => logValue(applyPath, v))).join(", ")}), returned: ${logValue(applyPath, rtnValue)}`, target[WinIdKey]); | ||
logWorker(`Construct new ${cstrName}(${args.map((v => logValue([], v))).join(", ")})`, winId); | ||
} catch (e) {} | ||
@@ -71,2 +64,3 @@ } | ||
const instanceId = target[InstanceIdKey]; | ||
const cstrName = getConstructorName(target); | ||
if (0 === instanceId) { | ||
@@ -82,20 +76,17 @@ n = ""; | ||
n = "document.body."; | ||
} else if (1 === target.nodeType) { | ||
n = toLower(target.nodeName) + "."; | ||
} else if (1 === target[InterfaceTypeKey] && target[NodeNameKey]) { | ||
n = `<${toLower(target[NodeNameKey])}>`; | ||
} else if (8 === target[InterfaceTypeKey]) { | ||
n = "comment."; | ||
} else if (2 === target[InterfaceTypeKey]) { | ||
} else if (target[NodeNameKey]) { | ||
let nodeName = target[NodeNameKey]; | ||
n = "#text" === nodeName ? "textNode." : "#comment" === nodeName ? "commentNode." : "#document" === nodeName ? "document." : "html" === nodeName ? "doctype." : target.nodeName.toLowerCase() + "Element."; | ||
} else if (2 === target.nodeType) { | ||
n = "attributes."; | ||
} else if (11 === target[InterfaceTypeKey]) { | ||
n = "fragment."; | ||
} else if (10 === target[InterfaceTypeKey]) { | ||
n = "documentTypeNode."; | ||
} else if (20 === target[InterfaceTypeKey]) { | ||
} else if ("CanvasRenderingContext2D" === cstrName) { | ||
n = "context2D."; | ||
} else if ("CSSStyleDeclaration" === cstrName) { | ||
n = "value."; | ||
} else if ("MutationObserver" === cstrName) { | ||
n = "mutationObserver."; | ||
} else if (23 === target[InterfaceTypeKey]) { | ||
} else if ("NamedNodeMap" === cstrName) { | ||
n = "namedNodeMap."; | ||
} else if ("ResizeObserver" === cstrName) { | ||
n = "resizeObserver."; | ||
} else if (target[InterfaceTypeKey] <= 11) { | ||
n = "node."; | ||
} else { | ||
@@ -105,4 +96,5 @@ n = "¯\\_(ツ)_/¯ TARGET."; | ||
} | ||
target[ApplyPathKey] && target[ApplyPathKey].length && (n += [ ...target[ApplyPathKey] ].join(".") + "."); | ||
} | ||
if ("Get" === accessType && applyPath.length > 1) { | ||
if (applyPath.length > 1) { | ||
const first = applyPath.slice(0, applyPath.length - 1); | ||
@@ -125,3 +117,3 @@ const last = applyPath[applyPath.length - 1]; | ||
if ("string" === type) { | ||
return applyPath.includes("cookie") ? JSON.stringify(v.substr(0, 10) + "...") : JSON.stringify(v); | ||
return applyPath.includes("cookie") ? JSON.stringify(v.substr(0, 10) + "...") : JSON.stringify(v.length > 50 ? v.substr(0, 40) + "..." : v); | ||
} | ||
@@ -133,3 +125,32 @@ if (Array.isArray(v)) { | ||
const instanceId = v[InstanceIdKey]; | ||
return "number" == typeof instanceId ? 4 === instanceId ? "<body>" : 1 === instanceId ? "#document" : 2 === instanceId ? "<html>" : 3 === instanceId ? "<head>" : 0 === instanceId ? "window" : 1 === v[InterfaceTypeKey] && v[NodeNameKey] ? `<${toLower(v[NodeNameKey])}>` : 10 === v[InterfaceTypeKey] ? `<!DOCTYPE ${v[NodeNameKey]}>` : v[InterfaceTypeKey] <= 11 ? v[NodeNameKey] : "¯\\_(ツ)_/¯ instance obj" : v[Symbol.iterator] ? `[${Array.from(v).map((i => logValue(applyPath, i))).join(", ")}]` : objToString("value" in v ? v.value : v); | ||
if ("number" == typeof instanceId) { | ||
if (4 === instanceId) { | ||
return "<body>"; | ||
} | ||
if (1 === instanceId) { | ||
return "#document"; | ||
} | ||
if (2 === instanceId) { | ||
return "<html>"; | ||
} | ||
if (3 === instanceId) { | ||
return "<head>"; | ||
} | ||
if (0 === instanceId) { | ||
return "window"; | ||
} | ||
if (v[NodeNameKey]) { | ||
if (1 === v.nodeType) { | ||
return `<${v[NodeNameKey].toLowerCase()}>`; | ||
} | ||
if (10 === v.nodeType) { | ||
return `<!DOCTYPE ${v[NodeNameKey]}>`; | ||
} | ||
if (v.nodeType <= 11) { | ||
return v[NodeNameKey]; | ||
} | ||
} | ||
return "¯\\_(ツ)_/¯ instance obj"; | ||
} | ||
return v[Symbol.iterator] ? `[${Array.from(v).map((i => logValue(applyPath, i))).join(", ")}]` : "value" in v ? "string" == typeof v.value ? `"${v.value}"` : objToString(v.value) : objToString(v); | ||
} | ||
@@ -150,33 +171,20 @@ return (v => "object" == typeof v && v && v.then)(v) ? "Promise" : "function" === type ? `ƒ() ${v.name || ""}`.trim() : `¯\\_(ツ)_/¯ ${String(v)}`.trim(); | ||
const len = obj => obj.length; | ||
const getConstructorName = obj => obj && obj.constructor && obj.constructor.name || ""; | ||
const defineConstructorName = (Cstr, value) => Object.defineProperty(Cstr, "name", { | ||
value: value | ||
}); | ||
const nextTick = (cb, ms) => setTimeout(cb, ms); | ||
const EMPTY_ARRAY = []; | ||
Object.freeze(EMPTY_ARRAY); | ||
const randomId = () => Math.round(9999999999 * Math.random() + 4); | ||
const getInstanceStateValue = (instance, stateKey) => getStateValue(instance[InstanceIdKey], stateKey); | ||
const getStateValue = (instanceId, stateKey, stateRecord) => (stateRecord = webWorkerState[instanceId]) ? stateRecord[stateKey] : void 0; | ||
const setInstanceStateValue = (instance, stateKey, stateValue) => setStateValue(instance[InstanceIdKey], stateKey, stateValue); | ||
const setStateValue = (instanceId, stateKey, stateValue, stateRecord) => { | ||
(stateRecord = webWorkerState[instanceId] || {})[stateKey] = stateValue; | ||
webWorkerState[instanceId] = stateRecord; | ||
}; | ||
const setWorkerRef = (ref, refId) => { | ||
if (!(refId = webWorkerRefIdsByRef.get(ref))) { | ||
webWorkerRefIdsByRef.set(ref, refId = randomId()); | ||
webWorkerRefsByRefId[refId] = ref; | ||
} | ||
return refId; | ||
}; | ||
class WorkerProxy { | ||
constructor(interfaceType, instanceId, winId, nodeName) { | ||
this[WinIdKey] = winId; | ||
this[InstanceIdKey] = instanceId; | ||
this[NodeNameKey] = nodeName; | ||
return proxy(this[InterfaceTypeKey] = interfaceType, this, []); | ||
} | ||
} | ||
const definePrototypeProperty = (Cstr, memberName, descriptor) => Object.defineProperty(Cstr.prototype, memberName, { | ||
...descriptor, | ||
configurable: !0 | ||
}); | ||
const definePrototypePropertyDescriptor = (Cstr, propertyDescriptorMap) => Object.defineProperties(Cstr.prototype, propertyDescriptorMap); | ||
const definePrototypeValue = (Cstr, memberName, value) => definePrototypeProperty(Cstr, memberName, { | ||
value: value, | ||
writable: !0 | ||
}); | ||
const taskQueue = []; | ||
const queue = (instance, $applyPath$, isSetter, $assignInstanceId$) => { | ||
const queue = (instance, $applyPath$, isSetter, $assignInstanceId$, $groupedGetters$) => { | ||
const $instanceId$ = instance[InstanceIdKey]; | ||
@@ -186,14 +194,15 @@ taskQueue.push({ | ||
$instanceId$: $instanceId$, | ||
$interfaceType$: instance[InterfaceTypeKey], | ||
$nodeName$: instance[NodeNameKey], | ||
$applyPath$: $applyPath$, | ||
$assignInstanceId$: $assignInstanceId$ | ||
$applyPath$: [ ...instance[ApplyPathKey], ...$applyPath$ ], | ||
$assignInstanceId$: $assignInstanceId$, | ||
$groupedGetters$: $groupedGetters$ | ||
}); | ||
if (!isSetter) { | ||
return sync($instanceId$, $applyPath$); | ||
return sync(); | ||
} | ||
setTimeout((() => sync($instanceId$, $applyPath$)), 50); | ||
setTimeout(sync, 40); | ||
}; | ||
const sync = (instanceId, applyPath) => { | ||
const sync = () => { | ||
if (len(taskQueue)) { | ||
webWorkerCtx.$config$.logMainAccess && logWorker(`Main access, tasks sent: ${taskQueue.length}`); | ||
const endTask = taskQueue[len(taskQueue) - 1]; | ||
const accessReq = { | ||
@@ -212,3 +221,3 @@ $msgId$: randomId(), | ||
const isPromise = accessRsp.$isPromise$; | ||
const rtnValue = deserializeFromMain(instanceId, applyPath, accessRsp.$rtnValue$); | ||
const rtnValue = deserializeFromMain(endTask.$instanceId$, endTask.$applyPath$, accessRsp.$rtnValue$); | ||
if (accessRsp.$error$) { | ||
@@ -223,200 +232,57 @@ if (isPromise) { | ||
}; | ||
const getter = (instance, applyPath) => { | ||
const rtnValue = queue(instance, applyPath); | ||
logWorkerGetter(instance, applyPath, rtnValue); | ||
const getter = (instance, applyPath, groupedGetters) => { | ||
const rtnValue = queue(instance, applyPath, !1, void 0, groupedGetters); | ||
((target, applyPath, rtnValue, restrictedToWorker = !1, groupedGetters = !1) => { | ||
if (webWorkerCtx.$config$.logGetters) { | ||
try { | ||
const msg = `Get ${logTargetProp(target, "Get", applyPath)}, returned: ${logValue(applyPath, rtnValue)}${restrictedToWorker ? " (restricted to worker)" : ""}${groupedGetters ? " (grouped getter)" : ""}`; | ||
msg.includes("Symbol(") || logWorker(msg, target[WinIdKey]); | ||
} catch (e) {} | ||
} | ||
})(instance, applyPath, rtnValue, !1, !!groupedGetters); | ||
return rtnValue; | ||
}; | ||
const setter = (instance, applyPath, value) => { | ||
const serializedValue = serializeInstanceForMain(instance, value); | ||
logWorkerSetter(instance, applyPath, value); | ||
queue(instance, [ ...applyPath, serializedValue, 0 ], !0); | ||
const setterApplyPath = [ ...applyPath, serializeInstanceForMain(instance, value), 0 ]; | ||
((target, applyPath, value, restrictedToWorker = !1) => { | ||
if (webWorkerCtx.$config$.logSetters) { | ||
try { | ||
applyPath = applyPath.slice(0, applyPath.length - 2); | ||
logWorker(`Set ${logTargetProp(target, "Set", applyPath)}, value: ${logValue(applyPath, value)}${restrictedToWorker ? " (restricted to worker)" : ""}`, target[WinIdKey]); | ||
} catch (e) {} | ||
} | ||
})(instance, setterApplyPath, value); | ||
queue(instance, setterApplyPath, !0); | ||
}; | ||
const callMethod = (instance, applyPath, args, assignInstanceId) => { | ||
const isSetter = setterMethods.some((m => applyPath.includes(m))); | ||
const rtnValue = queue(instance, [ ...applyPath, serializeInstanceForMain(instance, args) ], isSetter, assignInstanceId); | ||
logWorkerCall(instance, applyPath, args, rtnValue); | ||
const methodName = applyPath[len(applyPath) - 1]; | ||
const isSetter = setterMethods.includes(methodName); | ||
const callApplyPath = [ ...applyPath, serializeInstanceForMain(instance, args) ]; | ||
const rtnValue = queue(instance, callApplyPath, isSetter, assignInstanceId); | ||
((target, applyPath, args, rtnValue) => { | ||
if (webWorkerCtx.$config$.logCalls) { | ||
try { | ||
applyPath = applyPath.slice(0, applyPath.length - 1); | ||
logWorker(`Call ${logTargetProp(target, "Call", applyPath)}(${args.map((v => logValue(applyPath, v))).join(", ")}), returned: ${logValue(applyPath, rtnValue)}`, target[WinIdKey]); | ||
} catch (e) {} | ||
} | ||
})(instance, callApplyPath, args, rtnValue); | ||
isSetter || dimensionMethodNames.includes(methodName) || cachedDimensions.clear(); | ||
return rtnValue; | ||
}; | ||
const createGlobalConstructorProxy = (winId, interfaceType, cstrName) => defineConstructorName(class { | ||
constructor(...args) { | ||
const instanceId = randomId(); | ||
const workerProxy = new WorkerProxy(interfaceType, instanceId, winId); | ||
queue(workerProxy, [ 1, cstrName, serializeForMain(winId, instanceId, args) ]); | ||
((winId, cstrName, args) => { | ||
if (webWorkerCtx.$config$.logCalls) { | ||
try { | ||
logWorker(`Construct new ${cstrName}(${args.map((v => logValue([], v))).join(", ")})`, winId); | ||
} catch (e) {} | ||
} | ||
})(winId, cstrName, args); | ||
return workerProxy; | ||
} | ||
}, cstrName); | ||
const proxy = (interfaceType, target, initApplyPath) => !target || "object" != typeof target && "function" != typeof target || String(target).includes("[native") ? target : new Proxy(target, { | ||
get(target, propKey, receiver) { | ||
if ("symbol" == typeof propKey || Reflect.has(target, propKey)) { | ||
return Reflect.get(target, propKey, receiver); | ||
} | ||
if (shouldRestrictToWorker(interfaceType, propKey)) { | ||
if (Reflect.has(self, propKey)) { | ||
return Reflect.get(self, propKey, receiver); | ||
} | ||
const globalRtnValue = target[propKey]; | ||
logWorkerGetter(target, [ propKey ], globalRtnValue, !0); | ||
return globalRtnValue; | ||
} | ||
8 !== interfaceType && 10 !== interfaceType || (interfaceType = 3); | ||
const applyPath = [ ...initApplyPath, String(propKey) ]; | ||
const interfaceInfo = webWorkerCtx.$interfaces$.find((i => i[0] === interfaceType)); | ||
if (interfaceInfo) { | ||
const memberInfo = interfaceInfo[2][((applyPath, i) => { | ||
for (i = len(applyPath) - 1; i >= 0; i--) { | ||
if ("string" == typeof applyPath[i]) { | ||
return applyPath[i]; | ||
} | ||
} | ||
return applyPath[0]; | ||
})(applyPath)]; | ||
if (13 === memberInfo) { | ||
return (...args) => callMethod(target, applyPath, args); | ||
} | ||
if (memberInfo > 0) { | ||
return proxy(memberInfo, target, [ ...applyPath ]); | ||
} | ||
} | ||
const stateValue = getInstanceStateValue(target, applyPath[0]); | ||
return "function" == typeof stateValue ? (...args) => { | ||
const rtnValue = stateValue.apply(target, args); | ||
logWorkerCall(target, applyPath, args, rtnValue); | ||
return rtnValue; | ||
} : getter(target, applyPath); | ||
}, | ||
set(target, propKey, value, receiver) { | ||
if ("symbol" == typeof propKey || Reflect.has(target, propKey)) { | ||
Reflect.set(target, propKey, value, receiver); | ||
} else if (shouldRestrictToWorker(interfaceType, propKey)) { | ||
target[propKey] = value; | ||
logWorkerSetter(target, [ propKey ], value, !0); | ||
} else { | ||
setter(target, [ ...initApplyPath, propKey ], value); | ||
} | ||
return !0; | ||
}, | ||
has: (target, propKey) => 0 === interfaceType || Reflect.has(target, propKey) | ||
}); | ||
const shouldRestrictToWorker = (interfaceType, propKey) => 0 === interfaceType && (!webWorkerCtx.$windowMemberNames$.includes(propKey) || webWorkerCtx.$forwardedTriggers$.includes(propKey)); | ||
const setterMethods = [ "addEventListener", "createElement", "setAttribute", "setItem" ]; | ||
const constructInstance = (interfaceType, instanceId, winId, nodeName) => new (getConstructor(interfaceType, nodeName = 3 === interfaceType ? "#text" : 8 === interfaceType ? "#comment" : 11 === interfaceType ? "#document-fragment" : 10 === interfaceType ? "html" : nodeName))(interfaceType, instanceId, winId, nodeName); | ||
const getConstructor = (interfaceType, nodeName) => 1 === interfaceType ? getElementConstructor(nodeName) : interfaceType <= 11 ? self.Node : WorkerProxy; | ||
const getElementConstructor = nodeName => elementConstructors[nodeName] || elementConstructors.UNKNOWN; | ||
const elementConstructors = {}; | ||
class NodeList { | ||
constructor(nodes) { | ||
(this._ = nodes).map(((node, index) => this[index] = node)); | ||
} | ||
entries() { | ||
return this._.entries(); | ||
} | ||
forEach(cb, thisArg) { | ||
this._.map(cb, thisArg); | ||
} | ||
item(index) { | ||
return this[index]; | ||
} | ||
keys() { | ||
return this._.keys(); | ||
} | ||
get length() { | ||
return len(this._); | ||
} | ||
values() { | ||
return this._.values(); | ||
} | ||
[Symbol.iterator]() { | ||
return this._[Symbol.iterator](); | ||
} | ||
} | ||
const serializeForMain = ($winId$, $instanceId$, value, added) => { | ||
if (void 0 !== value) { | ||
let type = typeof value; | ||
if ("string" === type || "boolean" === type || "number" === type || null == value) { | ||
return [ 5, value ]; | ||
} | ||
if ("function" === type) { | ||
return [ 6, { | ||
$winId$: $winId$, | ||
$instanceId$: $instanceId$, | ||
$refId$: setWorkerRef(value) | ||
} ]; | ||
} | ||
added = added || new Set; | ||
if (Array.isArray(value)) { | ||
return added.has(value) ? [ 0, [] ] : [ 0, value.map((v => serializeForMain($winId$, $instanceId$, v, added))) ]; | ||
} | ||
if ("object" === type) { | ||
return "number" == typeof value[InstanceIdKey] ? [ 3, { | ||
$winId$: value[WinIdKey], | ||
$interfaceType$: value[InterfaceTypeKey], | ||
$instanceId$: value[InstanceIdKey], | ||
$nodeName$: value[NodeNameKey] | ||
} ] : value instanceof Event ? [ 1, serializeObjectForMain($winId$, $instanceId$, value, !1, added) ] : [ 4, serializeObjectForMain($winId$, $instanceId$, value, !0, added) ]; | ||
} | ||
} | ||
const setterMethods = "addEventListener,removeEventListener,createElement,createTextNode,insertBefore,insertRule,deleteRule,setAttribute,setItem,removeItem,classList.add,classList.remove,classList.toggle".split(","); | ||
const getInstanceStateValue = (instance, stateKey) => getStateValue(instance[InstanceIdKey], stateKey); | ||
const getStateValue = (instanceId, stateKey, stateRecord) => (stateRecord = webWorkerState[instanceId]) ? stateRecord[stateKey] : void 0; | ||
const setInstanceStateValue = (instance, stateKey, stateValue) => setStateValue(instance[InstanceIdKey], stateKey, stateValue); | ||
const setStateValue = (instanceId, stateKey, stateValue, stateRecord) => { | ||
(stateRecord = webWorkerState[instanceId] || {})[stateKey] = stateValue; | ||
webWorkerState[instanceId] = stateRecord; | ||
}; | ||
const serializeObjectForMain = (winId, instanceId, obj, includeFunctions, added, serializedObj, propName, propValue) => { | ||
serializedObj = {}; | ||
if (!added.has(obj)) { | ||
added.add(obj); | ||
for (propName in obj) { | ||
propValue = obj[propName]; | ||
(includeFunctions || "function" != typeof propValue) && (serializedObj[propName] = serializeForMain(winId, instanceId, propValue, added)); | ||
} | ||
const setWorkerRef = (ref, refId) => { | ||
if (!(refId = webWorkerRefIdsByRef.get(ref))) { | ||
webWorkerRefIdsByRef.set(ref, refId = randomId()); | ||
webWorkerRefsByRefId[refId] = ref; | ||
} | ||
return serializedObj; | ||
return refId; | ||
}; | ||
const serializeInstanceForMain = (instance, value) => instance ? serializeForMain(instance[WinIdKey], instance[InstanceIdKey], value) : [ 5, value ]; | ||
const deserializeFromMain = (instanceId, applyPath, serializedValueTransfer, serializedType, serializedValue) => { | ||
if (serializedValueTransfer) { | ||
serializedType = serializedValueTransfer[0]; | ||
serializedValue = serializedValueTransfer[1]; | ||
if (5 === serializedType) { | ||
return serializedValue; | ||
} | ||
if (6 === serializedType) { | ||
return deserializeRefFromMain(instanceId, applyPath, serializedValue); | ||
} | ||
if (3 === serializedType) { | ||
return constructSerializedInstance(serializedValue); | ||
} | ||
if (0 === serializedType) { | ||
return serializedValue.map((v => deserializeFromMain(instanceId, applyPath, v))); | ||
} | ||
if (1 === serializedType) { | ||
return (eventProps => new Proxy(new Event(eventProps.type, eventProps), { | ||
get: (target, propName) => propName in eventProps ? eventProps[propName] : target[String(propName)] | ||
}))(deserializeObjectFromMain(instanceId, applyPath, serializedValue)); | ||
} | ||
if (4 === serializedType) { | ||
return deserializeObjectFromMain(instanceId, applyPath, serializedValue); | ||
} | ||
} | ||
}; | ||
const deserializeObjectFromMain = (instanceId, applyPath, serializedValue, obj, key) => { | ||
obj = {}; | ||
for (key in serializedValue) { | ||
obj[key] = deserializeFromMain(instanceId, [ ...applyPath, key ], serializedValue[key]); | ||
} | ||
return obj; | ||
}; | ||
const constructSerializedInstance = ({$interfaceType$: $interfaceType$, $instanceId$: $instanceId$, $winId$: $winId$, $nodeName$: $nodeName$, $data$: $data$}) => { | ||
const env = environments[$winId$]; | ||
return 0 === $instanceId$ ? env.$window$ : 1 === $instanceId$ ? env.$document$ : 2 === $instanceId$ ? env.$documentElement$ : 3 === $instanceId$ ? env.$head$ : 4 === $instanceId$ ? env.$body$ : 21 === $interfaceType$ ? new NodeList($data$.map(constructSerializedInstance)) : constructInstance($interfaceType$, $instanceId$, $winId$, $nodeName$); | ||
}; | ||
const deserializeRefFromMain = (instanceId, applyPath, {$winId$: $winId$, $refId$: $refId$}) => { | ||
webWorkerRefsByRefId[$refId$] || webWorkerRefIdsByRef.set(webWorkerRefsByRefId[$refId$] = function(...args) { | ||
const instance = constructInstance(0, instanceId, $winId$); | ||
return callMethod(instance, applyPath, args); | ||
}, $refId$); | ||
return webWorkerRefsByRefId[$refId$]; | ||
}; | ||
const runScriptContent = (env, instanceId, scriptContent, winId) => { | ||
@@ -428,3 +294,3 @@ let errorMsg = ""; | ||
env.$currentScriptUrl$ = ""; | ||
env.$run$(scriptContent); | ||
run(env, scriptContent); | ||
} catch (contentError) { | ||
@@ -438,4 +304,9 @@ console.error(scriptContent, contentError); | ||
}; | ||
const run = (env, script) => { | ||
new Function(`with(this){${script}}`).apply(env.$window$); | ||
}; | ||
const runStateLoadHandlers = (instanceId, type, handlers) => { | ||
(handlers = getStateValue(instanceId, type)) && nextTick((() => handlers.map((cb => cb({ | ||
(handlers = getStateValue(instanceId, type)) && ((cb, ms) => { | ||
setTimeout(cb, ms); | ||
})((() => handlers.map((cb => cb({ | ||
type: type | ||
@@ -448,3 +319,3 @@ }))))); | ||
baseLocation = (env = environments[env.$parentWinId$]).$location$; | ||
if (env.$isTop$) { | ||
if (env.$winId$ === env.$parentWinId$) { | ||
break; | ||
@@ -456,174 +327,4 @@ } | ||
const resolveUrl = (env, url) => resolveToUrl(env, url) + ""; | ||
const getUrl = elm => resolveToUrl(getEnv(elm), getInstanceStateValue(elm, 3)); | ||
const getUrl = elm => resolveToUrl(getEnv(elm), getInstanceStateValue(elm, 4)); | ||
const getPartytownScript = () => `<script src=${JSON.stringify(webWorkerCtx.$libPath$ + "partytown.js")} async defer><\/script>`; | ||
class Node extends WorkerProxy { | ||
appendChild(node) { | ||
return this.insertBefore(node, null); | ||
} | ||
get ownerDocument() { | ||
return getEnv(this).$document$; | ||
} | ||
get href() {} | ||
set href(_) {} | ||
insertBefore(newNode, referenceNode) { | ||
const winId = newNode[WinIdKey] = this[WinIdKey]; | ||
const instanceId = newNode[InstanceIdKey]; | ||
const nodeName = newNode[NodeNameKey]; | ||
const isScript = "SCRIPT" === nodeName; | ||
const isIFrame = "IFRAME" === nodeName; | ||
if (isScript) { | ||
const scriptContent = getInstanceStateValue(newNode, 2); | ||
if (scriptContent) { | ||
const errorMsg = runScriptContent(getEnv(newNode), instanceId, scriptContent, winId); | ||
const datasetType = errorMsg ? "pterror" : "ptid"; | ||
const datasetValue = errorMsg || instanceId; | ||
setter(newNode, [ "type" ], "text/partytown-x"); | ||
setter(newNode, [ "dataset", datasetType ], datasetValue); | ||
setter(newNode, [ "innerHTML" ], scriptContent); | ||
} | ||
} | ||
newNode = callMethod(this, [ "insertBefore" ], [ newNode, referenceNode ]); | ||
isIFrame && (iframe => { | ||
let i = 0; | ||
const winId = iframe[InstanceIdKey]; | ||
const callback = () => { | ||
if (environments[winId] && environments[winId].$isInitialized$) { | ||
let type = getInstanceStateValue(iframe, 1) ? "error" : "load"; | ||
let handlers = getInstanceStateValue(iframe, type); | ||
handlers && handlers.map((handler => handler({ | ||
type: type | ||
}))); | ||
} else if (i++ > 2e3) { | ||
let errorHandlers = getInstanceStateValue(iframe, "error"); | ||
errorHandlers && errorHandlers.map((handler => handler({ | ||
type: "error" | ||
}))); | ||
console.error("Timeout"); | ||
} else { | ||
setTimeout(callback, 9); | ||
} | ||
}; | ||
callback(); | ||
})(newNode); | ||
isScript && webWorkerCtx.$postMessage$([ 6, winId ]); | ||
return newNode; | ||
} | ||
get nodeName() { | ||
return this[NodeNameKey]; | ||
} | ||
get nodeType() { | ||
return this[InterfaceTypeKey]; | ||
} | ||
} | ||
class HTMLElement extends Node { | ||
get localName() { | ||
return toLower(this.nodeName); | ||
} | ||
get namespaceURI() { | ||
return "http://www.w3.org/1999/xhtml"; | ||
} | ||
get tagName() { | ||
return this.nodeName; | ||
} | ||
} | ||
class HTMLSrcElement extends HTMLElement { | ||
addEventListener(...args) { | ||
let eventName = args[0]; | ||
let callbacks = getInstanceStateValue(this, eventName) || []; | ||
callbacks.push(args[1]); | ||
setInstanceStateValue(this, eventName, callbacks); | ||
} | ||
get async() { | ||
return !0; | ||
} | ||
set async(_) {} | ||
get defer() { | ||
return !0; | ||
} | ||
set defer(_) {} | ||
get onload() { | ||
let callbacks = getInstanceStateValue(this, "load"); | ||
return callbacks && callbacks[0] || null; | ||
} | ||
set onload(cb) { | ||
setInstanceStateValue(this, "load", cb ? [ cb ] : null); | ||
} | ||
get onerror() { | ||
let callbacks = getInstanceStateValue(this, "error"); | ||
return callbacks && callbacks[0] || null; | ||
} | ||
set onerror(cb) { | ||
setInstanceStateValue(this, "error", cb ? [ cb ] : null); | ||
} | ||
} | ||
class HTMLDocument extends HTMLElement { | ||
get body() { | ||
return getEnv(this).$body$; | ||
} | ||
createElement(tagName) { | ||
tagName = toUpper(tagName); | ||
const winId = this[WinIdKey]; | ||
const instanceId = randomId(); | ||
const elm = new (getElementConstructor(tagName))(1, instanceId, winId, tagName); | ||
callMethod(this, [ "createElement" ], [ tagName ], instanceId); | ||
if ("IFRAME" === tagName) { | ||
createEnvironment({ | ||
$winId$: instanceId, | ||
$parentWinId$: winId, | ||
$url$: "about:blank" | ||
}); | ||
setter(elm, [ "srcdoc" ], getPartytownScript()); | ||
} else { | ||
"SCRIPT" === tagName && setter(elm, [ "type" ], "text/partytown"); | ||
} | ||
return elm; | ||
} | ||
createEvent(type) { | ||
return new Event(type); | ||
} | ||
get currentScript() { | ||
const currentScriptId = getEnv(this).$currentScriptId$; | ||
return currentScriptId > 0 ? constructInstance(1, currentScriptId, this[WinIdKey], "SCRIPT") : null; | ||
} | ||
get defaultView() { | ||
return getEnvWindow(this); | ||
} | ||
get documentElement() { | ||
return getEnv(this).$documentElement$; | ||
} | ||
getElementsByTagName(tagName) { | ||
return "BODY" === (tagName = toUpper(tagName)) ? [ this.body ] : "HEAD" === tagName ? [ this.head ] : callMethod(this, [ "getElementsByTagName" ], [ tagName ]); | ||
} | ||
get head() { | ||
return getEnv(this).$head$; | ||
} | ||
get implementation() { | ||
return { | ||
hasFeature: () => !0 | ||
}; | ||
} | ||
get location() { | ||
return getEnv(this).$location$; | ||
} | ||
set location(url) { | ||
getEnv(this).$location$.href = url + ""; | ||
} | ||
get parentNode() { | ||
return null; | ||
} | ||
get parentElement() { | ||
return null; | ||
} | ||
get readyState() { | ||
return "complete"; | ||
} | ||
} | ||
const constructDocumentElementChild = (winId, instanceId, titleCaseNodeName, documentElement) => new (defineConstructorName(class extends HTMLElement { | ||
get parentElement() { | ||
return documentElement; | ||
} | ||
get parentNode() { | ||
return documentElement; | ||
} | ||
}, `HTML${titleCaseNodeName}Element`))(1, instanceId, winId, toUpper(titleCaseNodeName)); | ||
const createImageConstructor = winId => class HTMLImageElement { | ||
@@ -671,2 +372,11 @@ constructor() { | ||
}; | ||
const getOrCreateNodeInstance = (winId, instanceId, nodeName) => { | ||
let instance = webWorkerInstances.get(instanceId); | ||
if (!instance) { | ||
instance = createNodeInstance(winId, instanceId, nodeName); | ||
webWorkerInstances.set(instanceId, instance); | ||
} | ||
return instance; | ||
}; | ||
const createNodeInstance = (winId, instanceId, nodeName) => new (nodeConstructors[nodeName] ? nodeConstructors[nodeName] : nodeName.includes("-") ? nodeConstructors.UNKNOWN : self.HTMLElement)(winId, instanceId, [], nodeName); | ||
class Location extends URL { | ||
@@ -683,281 +393,784 @@ assign() { | ||
} | ||
const createEnvironment = ({$winId$: $winId$, $parentWinId$: $parentWinId$, $isTop$: $isTop$, $url$: $url$}) => { | ||
if (environments[$winId$]) { | ||
environments[$winId$].$location$.href = $url$; | ||
} else { | ||
class Window { | ||
constructor() { | ||
initWindowInstance(this); | ||
return proxy(0, this, []); | ||
class WorkerProxy { | ||
constructor(winId, instanceId, applyPath, nodeName) { | ||
this[WinIdKey] = winId; | ||
this[InstanceIdKey] = instanceId; | ||
this[ApplyPathKey] = applyPath || []; | ||
this[NodeNameKey] = nodeName; | ||
this[PropInstancesKey] = {}; | ||
} | ||
} | ||
class WorkerTrapProxy extends WorkerProxy { | ||
constructor(winId, instanceId, applyPath, nodeName) { | ||
super(winId, instanceId, applyPath, nodeName); | ||
return new Proxy(this, { | ||
get: (instance, propName) => getter(instance, [ propName ]), | ||
set(instance, propName, propValue) { | ||
setter(instance, [ propName ], propValue); | ||
return !0; | ||
} | ||
get document() { | ||
return $document$; | ||
} | ||
get frameElement() { | ||
if ($isTop$) { | ||
return null; | ||
}); | ||
} | ||
} | ||
class Window extends WorkerProxy { | ||
constructor($winId$, $parentWinId$, url) { | ||
super($winId$, 0); | ||
for (const globalName in self) { | ||
if (!(globalName in this) && "onmessage" !== globalName) { | ||
const value = self[globalName]; | ||
if (null != value) { | ||
const isFunction = "function" == typeof value && !value.toString().startsWith("class"); | ||
this[globalName] = isFunction ? value.bind(self) : value; | ||
} | ||
const env = getEnv(this); | ||
const iframeElementInstanceId = this[WinIdKey]; | ||
const iframeElementWinId = env.$parentWinId$; | ||
return constructInstance(1, iframeElementInstanceId, iframeElementWinId, "IFRAME"); | ||
} | ||
get globalThis() { | ||
return getEnvWindow(this); | ||
} | ||
get location() { | ||
return $location$; | ||
} | ||
set location(loc) { | ||
$location$.href = loc + ""; | ||
} | ||
get parent() { | ||
return environments[$parentWinId$].$window$; | ||
} | ||
get self() { | ||
return getEnvWindow(this); | ||
} | ||
get top() { | ||
for (const envWinId in environments) { | ||
if (environments[envWinId].$isTop$) { | ||
return environments[envWinId].$window$; | ||
} | ||
} | ||
Object.getOwnPropertyNames(self).map((globalName => { | ||
globalName in this || (this[globalName] = self[globalName]); | ||
})); | ||
for (const envCstrName in envGlobalConstructors) { | ||
this[envCstrName] = defineConstructorName(class { | ||
constructor(...cstrArgs) { | ||
const instance = new (0, envGlobalConstructors[envCstrName])($winId$, randomId()); | ||
const serializedCstrArgs = serializeInstanceForMain(instance, cstrArgs); | ||
queue(instance, [ 1, envCstrName, serializedCstrArgs ]); | ||
logWorkerGlobalConstructor($winId$, envCstrName, cstrArgs); | ||
return instance; | ||
} | ||
} | ||
get window() { | ||
return getEnvWindow(this); | ||
} | ||
}, envCstrName); | ||
} | ||
const $document$ = new HTMLDocument(9, 1, $winId$, "#document"); | ||
const $documentElement$ = new elementConstructors.HTML(1, 2, $winId$, "HTML"); | ||
const $head$ = constructDocumentElementChild($winId$, 3, "Head", $documentElement$); | ||
const $body$ = constructDocumentElementChild($winId$, 4, "Body", $documentElement$); | ||
const $location$ = new Location($url$); | ||
const windowFunctionWhiteList = "addEventListener,removeEventListener,dispatchEvent,postMessage".split(","); | ||
const windowPropertyWhiteList = "devicePixelRatio,innerHeight,innerWidth,onmessage,onload,onerror".split(","); | ||
const initWindowInstance = win => { | ||
win[WinIdKey] = $winId$; | ||
win[InstanceIdKey] = win[InterfaceTypeKey] = 0; | ||
for (const globalName in self) { | ||
"function" != typeof self[globalName] || globalName in win || (win[globalName] = self[globalName].bind(self)); | ||
} | ||
Object.getOwnPropertyNames(self).map((globalName => { | ||
globalName in win || (win[globalName] = self[globalName]); | ||
})); | ||
Object.keys(elementConstructors).map((tagName => win[elementConstructors[tagName].name] = elementConstructors[tagName])); | ||
webWorkerCtx.$windowMemberNames$.map((memberName => { | ||
const $interfaceType$ = webWorkerCtx.$windowMembers$[memberName]; | ||
const isFunctionInterface = 13 === $interfaceType$; | ||
!(isFunctionInterface || $interfaceType$ > 11) || memberName in win && !windowFunctionWhiteList.includes(memberName) || (win[memberName] = isFunctionInterface ? (...args) => callMethod(win, [ memberName ], args) : proxy($interfaceType$, win, [ "window", memberName ])); | ||
})); | ||
webWorkerCtx.$interfaces$.map((i => { | ||
const interfaceType = i[0]; | ||
const memberName = i[1]; | ||
win[memberName] = createGlobalConstructorProxy($winId$, interfaceType, memberName); | ||
})); | ||
win.Image = createImageConstructor($winId$); | ||
win.Window = Window; | ||
win.performance = self.performance; | ||
win.name = name + `${normalizedWinId($winId$)} (${$winId$})`; | ||
win.navigator = (winId => { | ||
const navigator = self.navigator; | ||
navigator.sendBeacon = (url, body) => { | ||
const env = environments[winId]; | ||
if (webWorkerCtx.$config$.logSendBeaconRequests) { | ||
try { | ||
logWorker(`sendBeacon: ${resolveUrl(env, url)}${body ? ", data: " + JSON.stringify(body) : ""}`); | ||
} catch (e) { | ||
console.error(e); | ||
} | ||
} | ||
const win = new Proxy(this, { | ||
has: () => !0 | ||
}); | ||
environments[$winId$] = { | ||
$winId$: $winId$, | ||
$parentWinId$: $parentWinId$, | ||
$window$: win, | ||
$document$: createNodeInstance($winId$, 1, "#document"), | ||
$documentElement$: createNodeInstance($winId$, 2, "HTML"), | ||
$head$: createNodeInstance($winId$, 3, "HEAD"), | ||
$body$: createNodeInstance($winId$, 4, "BODY"), | ||
$location$: new Location(url) | ||
}; | ||
this.requestAnimationFrame = cb => setTimeout((() => cb(performance.now())), 9); | ||
this.cancelAnimationFrame = id => clearTimeout(id); | ||
return win; | ||
} | ||
get body() { | ||
return getEnv(this).$body$; | ||
} | ||
get document() { | ||
return getEnv(this).$document$; | ||
} | ||
get documentElement() { | ||
return getEnv(this).$documentElement$; | ||
} | ||
get frameElement() { | ||
const env = getEnv(this); | ||
const parentWinId = env.$parentWinId$; | ||
const winId = env.$winId$; | ||
return winId === parentWinId ? null : getOrCreateNodeInstance(parentWinId, winId, "IFRAME"); | ||
} | ||
get globalThis() { | ||
return this; | ||
} | ||
get head() { | ||
return getEnv(this).$head$; | ||
} | ||
get location() { | ||
return getEnv(this).$location$; | ||
} | ||
set location(loc) { | ||
getEnv(this).$location$.href = loc + ""; | ||
} | ||
get Image() { | ||
return createImageConstructor(this[WinIdKey]); | ||
} | ||
get name() { | ||
const winId = this[WinIdKey]; | ||
return name + `${normalizedWinId(winId)} (${winId})`; | ||
} | ||
get navigator() { | ||
return (winId => { | ||
const navigator = self.navigator; | ||
navigator.sendBeacon = (url, body) => { | ||
const env = environments[winId]; | ||
if (webWorkerCtx.$config$.logSendBeaconRequests) { | ||
try { | ||
fetch(resolveUrl(env, url), { | ||
method: "POST", | ||
body: body, | ||
mode: "no-cors", | ||
keepalive: !0 | ||
}); | ||
return !0; | ||
logWorker(`sendBeacon: ${resolveUrl(env, url)}${body ? ", data: " + JSON.stringify(body) : ""}`); | ||
} catch (e) { | ||
console.error(e); | ||
return !1; | ||
} | ||
}; | ||
return navigator; | ||
})($winId$); | ||
windowPropertyWhiteList.map((propName => Object.defineProperty(win, propName, { | ||
get: () => getter($window$, [ propName ]), | ||
set: value => setter($window$, [ propName ], value) | ||
}))); | ||
}; | ||
const $window$ = new Window; | ||
environments[$winId$] = { | ||
$winId$: $winId$, | ||
$parentWinId$: $parentWinId$, | ||
$window$: $window$, | ||
$document$: $document$, | ||
$documentElement$: $documentElement$, | ||
$head$: $head$, | ||
$body$: $body$, | ||
$location$: $location$, | ||
$isTop$: $isTop$, | ||
$run$: script => { | ||
new Function(`with(this){${script}}`).apply($window$); | ||
} | ||
try { | ||
fetch(resolveUrl(env, url), { | ||
method: "POST", | ||
body: body, | ||
mode: "no-cors", | ||
keepalive: !0 | ||
}); | ||
return !0; | ||
} catch (e) { | ||
console.error(e); | ||
return !1; | ||
} | ||
}; | ||
return navigator; | ||
})(this[WinIdKey]); | ||
} | ||
get origin() { | ||
return getEnv(this).$location$.origin; | ||
} | ||
get parent() { | ||
return environments[getEnv(this).$parentWinId$].$window$; | ||
} | ||
get self() { | ||
return this; | ||
} | ||
get top() { | ||
for (const envWinId in environments) { | ||
if (environments[envWinId].$winId$ === environments[envWinId].$parentWinId$) { | ||
return environments[envWinId].$window$; | ||
} | ||
}; | ||
logWorker(`Created ${$isTop$ ? "top" : "iframe"} window ${normalizedWinId($winId$)} environment (${$winId$})`, $winId$); | ||
} | ||
} | ||
get window() { | ||
return this; | ||
} | ||
} | ||
const createEnvironment = ({$winId$: $winId$, $parentWinId$: $parentWinId$, $url$: $url$}) => { | ||
if (environments[$winId$]) { | ||
environments[$winId$].$location$.href = $url$; | ||
} else { | ||
new Window($winId$, $parentWinId$, $url$); | ||
logWorker(`Created ${$winId$ === $parentWinId$ ? "top" : "iframe"} window ${normalizedWinId($winId$)} environment (${$winId$})`, $winId$); | ||
} | ||
webWorkerCtx.$postMessage$([ 6, $winId$ ]); | ||
}; | ||
const getEnv = instance => environments[instance[WinIdKey]]; | ||
const getEnvWindow = instance => getEnv(instance).$window$; | ||
class HTMLAnchorElement extends HTMLElement { | ||
get hash() { | ||
return getUrl(this).hash; | ||
class Node extends WorkerProxy { | ||
appendChild(node) { | ||
return this.insertBefore(node, null); | ||
} | ||
get host() { | ||
return getUrl(this).host; | ||
get href() {} | ||
set href(_) {} | ||
insertBefore(newNode, referenceNode) { | ||
const winId = newNode[WinIdKey] = this[WinIdKey]; | ||
const instanceId = newNode[InstanceIdKey]; | ||
const nodeName = newNode[NodeNameKey]; | ||
const isScript = "SCRIPT" === nodeName; | ||
const isIFrame = "IFRAME" === nodeName; | ||
if (isScript) { | ||
const scriptContent = getInstanceStateValue(newNode, 3); | ||
if (scriptContent) { | ||
const errorMsg = runScriptContent(getEnv(newNode), instanceId, scriptContent, winId); | ||
const datasetType = errorMsg ? "pterror" : "ptid"; | ||
const datasetValue = errorMsg || instanceId; | ||
setter(newNode, [ "type" ], "text/partytown-x"); | ||
setter(newNode, [ "dataset", datasetType ], datasetValue); | ||
setter(newNode, [ "innerHTML" ], scriptContent); | ||
} | ||
} | ||
callMethod(this, [ "insertBefore" ], [ newNode, referenceNode ]); | ||
isIFrame && (iframe => { | ||
let i = 0; | ||
const winId = iframe[InstanceIdKey]; | ||
const callback = () => { | ||
if (environments[winId] && environments[winId].$isInitialized$) { | ||
let type = getInstanceStateValue(iframe, 1) ? "error" : "load"; | ||
let handlers = getInstanceStateValue(iframe, type); | ||
handlers && handlers.map((handler => handler({ | ||
type: type | ||
}))); | ||
} else if (i++ > 2e3) { | ||
let errorHandlers = getInstanceStateValue(iframe, "error"); | ||
errorHandlers && errorHandlers.map((handler => handler({ | ||
type: "error" | ||
}))); | ||
console.error("Timeout"); | ||
} else { | ||
setTimeout(callback, 9); | ||
} | ||
}; | ||
callback(); | ||
})(newNode); | ||
if (isScript) { | ||
sync(); | ||
webWorkerCtx.$postMessage$([ 6, winId ]); | ||
} | ||
return newNode; | ||
} | ||
get hostname() { | ||
return getUrl(this).hostname; | ||
get nodeName() { | ||
return this[NodeNameKey]; | ||
} | ||
get href() { | ||
return getUrl(this) + ""; | ||
get nodeType() { | ||
return 3; | ||
} | ||
set href(href) { | ||
setInstanceStateValue(this, 3, href += ""); | ||
setter(this, [ "href" ], href); | ||
get ownerDocument() { | ||
return getEnv(this).$document$; | ||
} | ||
get origin() { | ||
return getUrl(this).origin; | ||
} | ||
class Attr { | ||
constructor(serializedAttr) { | ||
this.name = serializedAttr[0]; | ||
this.value = serializedAttr[1]; | ||
} | ||
get pathname() { | ||
return getUrl(this).pathname; | ||
get nodeName() { | ||
return this.name; | ||
} | ||
get port() { | ||
return getUrl(this).port; | ||
get nodeType() { | ||
return 2; | ||
} | ||
get protocol() { | ||
return getUrl(this).protocol; | ||
} | ||
class NodeList { | ||
constructor(nodes) { | ||
(this._ = nodes).map(((node, index) => this[index] = node)); | ||
} | ||
get search() { | ||
return getUrl(this).search; | ||
entries() { | ||
return this._.entries(); | ||
} | ||
} | ||
class HTMLCanvasElement extends HTMLElement { | ||
getContext(...args) { | ||
return proxy(14, this, [ "getContext", serializeInstanceForMain(this, args) ]); | ||
forEach(cb, thisArg) { | ||
this._.map(cb, thisArg); | ||
} | ||
} | ||
class HTMLIFrameElement extends HTMLSrcElement { | ||
get contentDocument() { | ||
return this.contentWindow.document; | ||
item(index) { | ||
return this[index]; | ||
} | ||
get contentWindow() { | ||
const iframeContentWinId = this[InstanceIdKey]; | ||
return environments[iframeContentWinId].$window$; | ||
keys() { | ||
return this._.keys(); | ||
} | ||
get src() { | ||
return getInstanceStateValue(this, 3) || ""; | ||
get length() { | ||
return len(this._); | ||
} | ||
set src(url) { | ||
let xhr = new XMLHttpRequest; | ||
let xhrStatus; | ||
url = resolveUrl(getEnv(this), url); | ||
setInstanceStateValue(this, 1, void 0); | ||
setInstanceStateValue(this, 3, url); | ||
xhr.open("GET", url, !1); | ||
xhr.send(); | ||
xhrStatus = xhr.status; | ||
xhrStatus > 199 && xhrStatus < 300 ? setter(this, [ "srcdoc" ], ((url, html) => `<base href="${url}">` + html.replace(/<script>/g, '<script type="text/partytown">').replace(/<script /g, '<script type="text/partytown" ').replace(/text\/javascript/g, "text/partytown") + getPartytownScript())(url, xhr.responseText)) : setInstanceStateValue(this, 1, xhrStatus); | ||
values() { | ||
return this._.values(); | ||
} | ||
[Symbol.iterator]() { | ||
return this._[Symbol.iterator](); | ||
} | ||
} | ||
class HTMLScriptElement extends HTMLSrcElement { | ||
get innerHTML() { | ||
return getInstanceStateValue(this, 2) || ""; | ||
const serializeForMain = ($winId$, $instanceId$, value, added) => { | ||
if (void 0 !== value) { | ||
let type = typeof value; | ||
if ("string" === type || "boolean" === type || "number" === type || null == value) { | ||
return [ 9, value ]; | ||
} | ||
if ("function" === type) { | ||
return [ 10, { | ||
$winId$: $winId$, | ||
$instanceId$: $instanceId$, | ||
$refId$: setWorkerRef(value) | ||
} ]; | ||
} | ||
added = added || new Set; | ||
if (Array.isArray(value)) { | ||
return added.has(value) ? [ 0, [] ] : [ 0, value.map((v => serializeForMain($winId$, $instanceId$, v, added))) ]; | ||
} | ||
if ("object" === type) { | ||
return "number" == typeof value[InstanceIdKey] ? [ 6, { | ||
$winId$: value[WinIdKey], | ||
$instanceId$: value[InstanceIdKey] | ||
} ] : value instanceof Event ? [ 4, serializeObjectForMain($winId$, $instanceId$, value, !1, added) ] : [ 8, serializeObjectForMain($winId$, $instanceId$, value, !0, added) ]; | ||
} | ||
} | ||
set innerHTML(scriptContent) { | ||
setInstanceStateValue(this, 2, scriptContent); | ||
}; | ||
const serializeObjectForMain = (winId, instanceId, obj, includeFunctions, added, serializedObj, propName, propValue) => { | ||
serializedObj = {}; | ||
if (!added.has(obj)) { | ||
added.add(obj); | ||
for (propName in obj) { | ||
propValue = obj[propName]; | ||
(includeFunctions || "function" != typeof propValue) && (serializedObj[propName] = serializeForMain(winId, instanceId, propValue, added)); | ||
} | ||
} | ||
get innerText() { | ||
return this.innerHTML; | ||
return serializedObj; | ||
}; | ||
const serializeInstanceForMain = (instance, value) => instance ? serializeForMain(instance[WinIdKey], instance[InstanceIdKey], value) : [ 9, value ]; | ||
const deserializeFromMain = (instanceId, applyPath, serializedValueTransfer, serializedType, serializedValue) => { | ||
if (serializedValueTransfer) { | ||
serializedType = serializedValueTransfer[0]; | ||
serializedValue = serializedValueTransfer[1]; | ||
if (9 === serializedType || 2 === serializedType || 3 === serializedType) { | ||
return serializedValue; | ||
} | ||
if (10 === serializedType) { | ||
return deserializeRefFromMain(applyPath, serializedValue); | ||
} | ||
if (6 === serializedType) { | ||
return getOrCreateSerializedInstance(serializedValue); | ||
} | ||
if (7 === serializedType) { | ||
return new NodeList(serializedValue.map(getOrCreateSerializedInstance)); | ||
} | ||
if (1 === serializedType) { | ||
return new Attr(serializedValue); | ||
} | ||
if (0 === serializedType) { | ||
return serializedValue.map((v => deserializeFromMain(instanceId, applyPath, v))); | ||
} | ||
if (4 === serializedType) { | ||
return (eventProps => new Proxy(new Event(eventProps.type, eventProps), { | ||
get: (target, propName) => propName in eventProps ? eventProps[propName] : target[String(propName)] | ||
}))(deserializeObjectFromMain(instanceId, applyPath, serializedValue)); | ||
} | ||
if (8 === serializedType) { | ||
return deserializeObjectFromMain(instanceId, applyPath, serializedValue); | ||
} | ||
} | ||
set innerText(content) { | ||
this.innerHTML = content; | ||
}; | ||
const deserializeObjectFromMain = (instanceId, applyPath, serializedValue, obj, key) => { | ||
obj = {}; | ||
for (key in serializedValue) { | ||
obj[key] = deserializeFromMain(instanceId, [ ...applyPath, key ], serializedValue[key]); | ||
} | ||
get src() { | ||
return getInstanceStateValue(this, 3) || ""; | ||
return obj; | ||
}; | ||
const getOrCreateSerializedInstance = ({$winId$: $winId$, $instanceId$: $instanceId$, $nodeName$: $nodeName$}) => getPlatformInstance($winId$, $instanceId$) || getOrCreateNodeInstance($winId$, $instanceId$, $nodeName$); | ||
const getPlatformInstance = (winId, instanceId) => { | ||
const env = environments[winId]; | ||
return 0 === instanceId ? env.$window$ : 1 === instanceId ? env.$document$ : 2 === instanceId ? env.$documentElement$ : 3 === instanceId ? env.$head$ : 4 === instanceId ? env.$body$ : void 0; | ||
}; | ||
const deserializeRefFromMain = (applyPath, {$winId$: $winId$, $instanceId$: $instanceId$, $nodeName$: $nodeName$, $refId$: $refId$}) => { | ||
webWorkerRefsByRefId[$refId$] || webWorkerRefIdsByRef.set(webWorkerRefsByRefId[$refId$] = function(...args) { | ||
const instance = getOrCreateNodeInstance($winId$, $instanceId$, $nodeName$); | ||
return callMethod(instance, applyPath, args); | ||
}, $refId$); | ||
return webWorkerRefsByRefId[$refId$]; | ||
}; | ||
const HTMLStyleDescriptorMap = { | ||
sheet: { | ||
get() { | ||
return new CSSStyleSheet(this); | ||
} | ||
} | ||
set src(url) { | ||
url = resolveUrl(getEnv(this), url); | ||
setInstanceStateValue(this, 3, url); | ||
setter(this, [ "src" ], url); | ||
}; | ||
class CSSStyleSheet { | ||
constructor(ownerNode) { | ||
this.ownerNode = ownerNode; | ||
} | ||
get textContent() { | ||
return this.innerHTML; | ||
get cssRules() { | ||
const ownerNode = this.ownerNode; | ||
return new Proxy({}, { | ||
get(target, propKey) { | ||
const propName = String(propKey); | ||
return "item" === propName ? index => getCssRule(ownerNode, index) : "length" === propName ? getCssRules(ownerNode).length : isNaN(propName) ? target[propKey] : getCssRule(ownerNode, propName); | ||
} | ||
}); | ||
} | ||
set textContent(content) { | ||
this.innerHTML = content; | ||
insertRule(ruleText, index) { | ||
const cssRules = getCssRules(this.ownerNode); | ||
if ((index = void 0 === index ? 0 : index) >= 0 && index <= cssRules.length) { | ||
callMethod(this.ownerNode, [ "sheet", "insertRule" ], [ ruleText, index ]); | ||
cssRules.splice(index, 0, 0); | ||
} | ||
return index; | ||
} | ||
get type() { | ||
return getter(this, [ "type" ]); | ||
deleteRule(index) { | ||
callMethod(this.ownerNode, [ "sheet", "deleteRule" ], [ index ]); | ||
getCssRules(this.ownerNode).splice(index, 1); | ||
} | ||
set type(type) { | ||
"text/javascript" !== type && setter(this, [ "type" ], type); | ||
} | ||
const getCssRules = ownerNode => { | ||
let cssRules = getInstanceStateValue(ownerNode, 2); | ||
if (!cssRules) { | ||
cssRules = getter(ownerNode, [ "sheet", "cssRules" ]); | ||
setInstanceStateValue(ownerNode, 2, cssRules); | ||
} | ||
} | ||
const SheetKey = Symbol(); | ||
class HTMLStyleElement extends HTMLElement { | ||
get sheet() { | ||
const ownerElement = this; | ||
if (void 0 === ownerElement[SheetKey]) { | ||
const sheetInfo = getter(ownerElement, [ "sheet" ]); | ||
if (null === sheetInfo) { | ||
ownerElement[SheetKey] = sheetInfo; | ||
return cssRules; | ||
}; | ||
const getCssRule = (ownerNode, index) => { | ||
let cssRules = getCssRules(ownerNode); | ||
0 === cssRules[index] && (cssRules[index] = getter(ownerNode, [ "sheet", "cssRules", parseInt(index, 10) ])); | ||
return cssRules[index]; | ||
}; | ||
const DocumentDescriptorMap = { | ||
body: { | ||
get() { | ||
return getEnv(this).$body$; | ||
} | ||
}, | ||
createElement: { | ||
value(tagName) { | ||
tagName = tagName.toUpperCase(); | ||
const winId = this[WinIdKey]; | ||
const instanceId = randomId(); | ||
const elm = getOrCreateNodeInstance(winId, instanceId, tagName); | ||
callMethod(this, [ "createElement" ], [ tagName ], instanceId); | ||
if ("IFRAME" === tagName) { | ||
createEnvironment({ | ||
$winId$: instanceId, | ||
$parentWinId$: winId, | ||
$url$: "about:blank" | ||
}); | ||
setter(elm, [ "srcdoc" ], getPartytownScript()); | ||
} else { | ||
class CSSStyleSheet { | ||
get cssRules() { | ||
return sheetInfo.cssRules; | ||
} | ||
deleteRule(index) { | ||
ownerElement[SheetKey] = void 0; | ||
callMethod(ownerElement, [ "sheet", "deleteRule" ], [ index ]); | ||
} | ||
insertRule(rule, index) { | ||
ownerElement[SheetKey] = void 0; | ||
return callMethod(ownerElement, [ "sheet", "insertRule" ], [ rule, index ]); | ||
} | ||
"SCRIPT" === tagName && setter(elm, [ "type" ], "text/partytown"); | ||
} | ||
return elm; | ||
} | ||
}, | ||
createElementNS: { | ||
value(ns, tagName) { | ||
tagName = tagName.toUpperCase(); | ||
const winId = this[WinIdKey]; | ||
const instanceId = randomId(); | ||
const nsElm = getOrCreateNodeInstance(winId, instanceId, tagName); | ||
callMethod(this, [ "createElementNS" ], [ ns, tagName ], instanceId); | ||
return nsElm; | ||
} | ||
}, | ||
createTextNode: { | ||
value(text) { | ||
const winId = this[WinIdKey]; | ||
const instanceId = randomId(); | ||
const textNode = getOrCreateNodeInstance(winId, instanceId, "#text"); | ||
callMethod(this, [ "createTextNode" ], [ text ], instanceId); | ||
return textNode; | ||
} | ||
}, | ||
createEvent: { | ||
value: type => new Event(type) | ||
}, | ||
currentScript: { | ||
get() { | ||
const winId = this[WinIdKey]; | ||
const currentScriptId = getEnv(this).$currentScriptId$; | ||
return currentScriptId > 0 ? getOrCreateNodeInstance(winId, currentScriptId, "SCRIPT") : null; | ||
} | ||
}, | ||
defaultView: { | ||
get() { | ||
return (instance => getEnv(instance).$window$)(this); | ||
} | ||
}, | ||
documentElement: { | ||
get() { | ||
return getEnv(this).$documentElement$; | ||
} | ||
}, | ||
getElementsByTagName: { | ||
value(tagName) { | ||
return "BODY" === (tagName = tagName.toUpperCase()) ? [ getEnv(this).$body$ ] : "HEAD" === tagName ? [ getEnv(this).$head$ ] : callMethod(this, [ "getElementsByTagName" ], [ tagName ]); | ||
} | ||
}, | ||
head: { | ||
get() { | ||
return getEnv(this).$head$; | ||
} | ||
}, | ||
implementation: { | ||
value: { | ||
hasFeature: noop | ||
} | ||
}, | ||
location: { | ||
get() { | ||
return getEnv(this).$location$; | ||
}, | ||
set(url) { | ||
getEnv(this).$location$.href = url + ""; | ||
} | ||
}, | ||
nodeType: { | ||
value: 9 | ||
}, | ||
parentNode: { | ||
value: null | ||
}, | ||
parentElement: { | ||
value: null | ||
}, | ||
readyState: { | ||
value: "complete" | ||
} | ||
}; | ||
const ElementDescriptorMap = { | ||
localName: { | ||
get() { | ||
return this[NodeNameKey].toLowerCase(); | ||
} | ||
}, | ||
namespaceURI: { | ||
get() { | ||
return "http://www.w3.org/" + ("SVG" === this[NodeNameKey] ? "2000/svg" : "1999/xhtml"); | ||
} | ||
}, | ||
nodeType: { | ||
value: 1 | ||
}, | ||
tagName: { | ||
get() { | ||
return this[NodeNameKey]; | ||
} | ||
} | ||
}; | ||
const HTMLAnchorDescriptorMap = { | ||
hash: { | ||
get() { | ||
return getUrl(this).hash; | ||
} | ||
}, | ||
host: { | ||
get() { | ||
return getUrl(this).host; | ||
} | ||
}, | ||
hostname: { | ||
get() { | ||
return getUrl(this).hostname; | ||
} | ||
}, | ||
href: { | ||
get() { | ||
return getUrl(this).href; | ||
}, | ||
set(href) { | ||
setInstanceStateValue(this, 4, href += ""); | ||
setter(this, [ "href" ], href); | ||
} | ||
}, | ||
origin: { | ||
get() { | ||
return getUrl(this).origin; | ||
} | ||
}, | ||
pathname: { | ||
get() { | ||
return getUrl(this).pathname; | ||
} | ||
}, | ||
port: { | ||
get() { | ||
return getUrl(this).port; | ||
} | ||
}, | ||
protocol: { | ||
get() { | ||
return getUrl(this).protocol; | ||
} | ||
}, | ||
search: { | ||
get() { | ||
return getUrl(this).search; | ||
} | ||
} | ||
}; | ||
const HTMLCanvasDescriptorMap = { | ||
getContext: { | ||
value(...args) { | ||
const applyPath = [ "getContext", serializeInstanceForMain(this, args) ]; | ||
return new self.CanvasRenderingContext2D(this[WinIdKey], this[InstanceIdKey], applyPath); | ||
} | ||
} | ||
}; | ||
const HTMLSrcElementDescriptorMap = { | ||
addEventListener: { | ||
value(...args) { | ||
const eventName = args[0]; | ||
const callbacks = getInstanceStateValue(this, eventName) || []; | ||
callbacks.push(args[1]); | ||
setInstanceStateValue(this, eventName, callbacks); | ||
} | ||
}, | ||
async: { | ||
get: noop, | ||
set: noop | ||
}, | ||
defer: { | ||
get: noop, | ||
set: noop | ||
}, | ||
onload: { | ||
get() { | ||
let callbacks = getInstanceStateValue(this, "load"); | ||
return callbacks && callbacks[0] || null; | ||
}, | ||
set(cb) { | ||
setInstanceStateValue(this, "load", cb ? [ cb ] : null); | ||
} | ||
}, | ||
onerror: { | ||
get() { | ||
let callbacks = getInstanceStateValue(this, "error"); | ||
return callbacks && callbacks[0] || null; | ||
}, | ||
set(cb) { | ||
setInstanceStateValue(this, "error", cb ? [ cb ] : null); | ||
} | ||
} | ||
}; | ||
const HTMLIFrameDescriptorMap = { | ||
contentDocument: { | ||
get() { | ||
return this.contentWindow.document; | ||
} | ||
}, | ||
contentWindow: { | ||
get() { | ||
const iframeContentWinId = this[InstanceIdKey]; | ||
return environments[iframeContentWinId].$window$; | ||
} | ||
}, | ||
src: { | ||
get() { | ||
return getInstanceStateValue(this, 4) || ""; | ||
}, | ||
set(url) { | ||
let xhr = new XMLHttpRequest; | ||
let xhrStatus; | ||
url = resolveUrl(getEnv(this), url); | ||
setInstanceStateValue(this, 1, void 0); | ||
setInstanceStateValue(this, 4, url); | ||
xhr.open("GET", url, !1); | ||
xhr.send(); | ||
xhrStatus = xhr.status; | ||
xhrStatus > 199 && xhrStatus < 300 ? setter(this, [ "srcdoc" ], ((url, html) => `<base href="${url}">` + html.replace(/<script>/g, '<script type="text/partytown">').replace(/<script /g, '<script type="text/partytown" ').replace(/text\/javascript/g, "text/partytown") + getPartytownScript())(url, xhr.responseText)) : setInstanceStateValue(this, 1, xhrStatus); | ||
} | ||
}, | ||
...HTMLSrcElementDescriptorMap | ||
}; | ||
const innerHTMLDescriptor = { | ||
get() { | ||
return getInstanceStateValue(this, 3) || ""; | ||
}, | ||
set(scriptContent) { | ||
setInstanceStateValue(this, 3, scriptContent); | ||
} | ||
}; | ||
const HTMLScriptDescriptorMap = { | ||
innerHTML: innerHTMLDescriptor, | ||
innerText: innerHTMLDescriptor, | ||
src: { | ||
get() { | ||
return getInstanceStateValue(this, 4) || ""; | ||
}, | ||
set(url) { | ||
url = resolveUrl(getEnv(this), url); | ||
setInstanceStateValue(this, 4, url); | ||
setter(this, [ "src" ], url); | ||
} | ||
}, | ||
getAttribute: { | ||
value(attrName) { | ||
return "src" === attrName ? this.src : callMethod(this, [ "getAttribute" ], [ attrName ]); | ||
} | ||
}, | ||
setAttribute: { | ||
value(attrName, attrValue) { | ||
"src" === attrName ? this.src = attrValue : callMethod(this, [ "setAttribute" ], [ attrName, attrValue ]); | ||
} | ||
}, | ||
textContent: innerHTMLDescriptor, | ||
type: { | ||
get() { | ||
return getter(this, [ "type" ]); | ||
}, | ||
set(type) { | ||
"text/javascript" !== type && setter(this, [ "type" ], type); | ||
} | ||
}, | ||
...HTMLSrcElementDescriptorMap | ||
}; | ||
const defineWorkerInterface = ([cstrName, superCstrName, members, interfaceType, nodeName]) => { | ||
const SuperCstr = TrapConstructors[cstrName] ? WorkerTrapProxy : "Object" === superCstrName || "EventTarget" === superCstrName ? WorkerProxy : self[superCstrName]; | ||
const Cstr = self[cstrName] = defineConstructorName(self[cstrName] || class extends SuperCstr {}, cstrName); | ||
12 === interfaceType && (envGlobalConstructors[cstrName] = Cstr); | ||
nodeName && (nodeConstructors[nodeName] = Cstr); | ||
members.map((([memberName, memberType, staticValue]) => { | ||
memberName in Cstr.prototype || memberName in SuperCstr.prototype || ("string" == typeof memberType ? definePrototypeProperty(Cstr, memberName, { | ||
get() { | ||
if (!this[PropInstancesKey][memberName]) { | ||
const winId = this[WinIdKey]; | ||
const instanceId = this[InstanceIdKey]; | ||
const applyPath = [ ...this[ApplyPathKey], memberName ]; | ||
const nodeName = this[NodeNameKey]; | ||
const PropCstr = self[memberType]; | ||
this[PropInstancesKey][memberName] = new PropCstr(winId, instanceId, applyPath, nodeName); | ||
} | ||
ownerElement[SheetKey] = new CSSStyleSheet; | ||
return this[PropInstancesKey][memberName]; | ||
}, | ||
set(value) { | ||
this[PropInstancesKey][memberName] = value; | ||
} | ||
}) : 5 === memberType ? definePrototypeValue(Cstr, memberName, (function(...args) { | ||
return callMethod(this, [ memberName ], args); | ||
})) : memberType > 0 && (void 0 !== staticValue ? definePrototypeValue(Cstr, memberName, staticValue) : definePrototypeProperty(Cstr, memberName, { | ||
get() { | ||
return getter(this, [ memberName ]); | ||
}, | ||
set(value) { | ||
return setter(this, [ memberName ], value); | ||
} | ||
}))); | ||
})); | ||
}; | ||
const TrapConstructors = { | ||
CSSStyleDeclaration: 1, | ||
DOMStringMap: 1, | ||
NamedNodeMap: 1 | ||
}; | ||
const patchPrototypes = () => { | ||
const Element = self.Element; | ||
const DocumentFragment = self.DocumentFragment; | ||
(() => { | ||
"atob,btoa,crypto,indexedDB,performance,setTimeout,setInterval,clearTimeout,clearInterval".split(",").map((memberName => delete Window.prototype[memberName])); | ||
})(); | ||
definePrototypePropertyDescriptor(Element, ElementDescriptorMap); | ||
definePrototypePropertyDescriptor(self.Document, DocumentDescriptorMap); | ||
definePrototypePropertyDescriptor(self.HTMLAnchorElement, HTMLAnchorDescriptorMap); | ||
definePrototypePropertyDescriptor(self.HTMLCanvasElement, HTMLCanvasDescriptorMap); | ||
definePrototypePropertyDescriptor(self.HTMLIFrameElement, HTMLIFrameDescriptorMap); | ||
definePrototypePropertyDescriptor(self.HTMLScriptElement, HTMLScriptDescriptorMap); | ||
definePrototypePropertyDescriptor(self.HTMLStyleElement, HTMLStyleDescriptorMap); | ||
constantProps(CSSStyleSheet, { | ||
type: "text/css" | ||
}); | ||
definePrototypeNodeType(self.Comment, 8); | ||
definePrototypeNodeType(self.DocumentType, 10); | ||
definePrototypeNodeType(DocumentFragment, 11); | ||
cachedTreeProps(Node, "childNodes,firstChild,isConnected,lastChild,nextSibling,parentElement,parentNode,previousSibling"); | ||
cachedTreeProps(Element, elementTreePropNames); | ||
cachedTreeProps(DocumentFragment, elementTreePropNames); | ||
cachedDimensionProps(Element); | ||
cachedDimensionProps(Window); | ||
cachedDimensionMethods(Element); | ||
}; | ||
const definePrototypeNodeType = (Cstr, nodeType) => definePrototypeValue(Cstr, "nodeType", nodeType); | ||
const cachedTreeProps = (Cstr, treeProps) => treeProps.split(",").map((propName => definePrototypeProperty(Cstr, propName, { | ||
get() { | ||
let cacheKey = getDimensionCacheKey(this, propName); | ||
let result = cachedTree.get(cacheKey); | ||
if (!result) { | ||
result = getter(this, [ propName ]); | ||
cachedTree.set(cacheKey, result); | ||
} | ||
return ownerElement[SheetKey]; | ||
return result; | ||
} | ||
} | ||
const initWebWorker = initWebWorkerData => { | ||
Object.assign(webWorkerCtx, initWebWorkerData); | ||
webWorkerCtx.$forwardedTriggers$ = (webWorkerCtx.$config$.forward || EMPTY_ARRAY).map((f => f[0])); | ||
webWorkerCtx.$windowMembers$ = webWorkerCtx.$interfaces$[0][2]; | ||
webWorkerCtx.$windowMemberNames$ = Object.keys(webWorkerCtx.$windowMembers$).filter((m => !webWorkerCtx.$forwardedTriggers$.includes(m))); | ||
webWorkerCtx.$postMessage$ = postMessage.bind(self); | ||
self.postMessage = self.importScripts = void 0; | ||
self.Node = Node; | ||
self.Element = self.HTMLElement = HTMLSrcElement; | ||
self.Document = HTMLDocument; | ||
webWorkerCtx.$htmlConstructors$.map((htmlCstrName => elementConstructors[(t => ({ | ||
IMAGE: "IMG", | ||
OLIST: "OL", | ||
PARAGRAPH: "P", | ||
TABLECELL: "TD", | ||
TABLEROW: "TR", | ||
ULIST: "UL" | ||
}[t = toUpper(t.substr(4).replace("Element", ""))] || t))(htmlCstrName)] = defineConstructorName(class extends HTMLElement {}, htmlCstrName))); | ||
elementConstructors.A = HTMLAnchorElement; | ||
elementConstructors.CANVAS = HTMLCanvasElement; | ||
elementConstructors.IFRAME = HTMLIFrameElement; | ||
elementConstructors.SCRIPT = HTMLScriptElement; | ||
elementConstructors.STYLE = HTMLStyleElement; | ||
webWorkerCtx.$isInitialized$ = 1; | ||
logWorker("Initialized web worker"); | ||
}; | ||
}))); | ||
const getDimensionCacheKey = (instance, memberName) => instance[WinIdKey] + "." + instance[InstanceIdKey] + "." + memberName; | ||
const constantProps = (Cstr, props) => Object.keys(props).map((propName => definePrototypeValue(Cstr, propName, props[propName]))); | ||
const cachedDimensionProps = Cstr => dimensionPropNames.map((propName => { | ||
definePrototypeProperty(Cstr, propName, { | ||
get() { | ||
const dimension = cachedDimensions.get(getDimensionCacheKey(this, propName)); | ||
if ("number" == typeof dimension) { | ||
return dimension; | ||
} | ||
const groupedDimensions = getter(this, [ propName ], dimensionPropNames); | ||
Object.entries(groupedDimensions).map((([dimensionPropName, value]) => { | ||
cachedDimensions.set(getDimensionCacheKey(this, dimensionPropName), value); | ||
})); | ||
return groupedDimensions[propName]; | ||
} | ||
}); | ||
})); | ||
const cachedDimensionMethods = Cstr => dimensionMethodNames.map((methodName => { | ||
Cstr.prototype[methodName] = function() { | ||
let cacheKey = getDimensionCacheKey(this, methodName); | ||
let dimensions = cachedDimensions.get(cacheKey); | ||
if (!dimensions) { | ||
dimensions = callMethod(this, [ methodName ], EMPTY_ARRAY); | ||
cachedDimensions.set(cacheKey, dimensions); | ||
} | ||
return dimensions; | ||
}; | ||
})); | ||
const queuedEvents = []; | ||
@@ -982,13 +1195,12 @@ const receiveMessageFromSandboxToWorker = ev => { | ||
scriptSrc = scriptUrl + ""; | ||
setStateValue(instanceId, 3, scriptSrc); | ||
setStateValue(instanceId, 4, scriptSrc); | ||
webWorkerCtx.$config$.logScriptExecution && logWorker(`Execute script (${instanceId}) src: ${scriptSrc}`, winId); | ||
if (scriptUrl.origin !== origin) { | ||
try { | ||
await self.fetch(scriptSrc, { | ||
method: "OPTIONS" | ||
}); | ||
} catch (e) { | ||
scriptSrc = "https://partytown.builder.io/api/proxy?p=" + scriptSrc; | ||
logWorker(`Proxied script (${instanceId}) src: ${scriptSrc}`, winId); | ||
try { | ||
rsp = await self.fetch(scriptSrc); | ||
} catch (e) { | ||
if (scriptUrl.origin === origin) { | ||
throw e; | ||
} | ||
scriptSrc = "https://partytown.builder.io/api/proxy?p=" + scriptSrc; | ||
logWorker(`Proxied script (${instanceId}) src: ${scriptSrc}`, winId); | ||
} | ||
@@ -1000,3 +1212,3 @@ rsp = await self.fetch(scriptSrc); | ||
env.$currentScriptUrl$ = scriptSrc; | ||
env.$run$(scriptContent); | ||
run(env, scriptContent); | ||
runStateLoadHandlers(instanceId, "load"); | ||
@@ -1050,3 +1262,4 @@ } else { | ||
const winId = msg[1]; | ||
const winType = environments[winId].$isTop$ ? "top" : "iframe"; | ||
const env = environments[winId]; | ||
const winType = env.$winId$ === env.$parentWinId$ ? "top" : "iframe"; | ||
logWorker(`Initialized ${winType} window ${normalizedWinId(winId)} environment (${winId}) 🎉`, winId); | ||
@@ -1056,9 +1269,19 @@ } | ||
} else if (1 === msgType) { | ||
initWebWorker(msg[1]); | ||
(initWebWorkerData => { | ||
Object.assign(webWorkerCtx, initWebWorkerData); | ||
webWorkerCtx.$forwardedTriggers$ = (webWorkerCtx.$config$.forward || EMPTY_ARRAY).map((f => f[0])); | ||
webWorkerCtx.$postMessage$ = postMessage.bind(self); | ||
self.postMessage = self.importScripts = void 0; | ||
self.Node = Node; | ||
self.Window = Window; | ||
self.CSSStyleSheet = CSSStyleSheet; | ||
webWorkerCtx.$interfaces$.map(defineWorkerInterface); | ||
patchPrototypes(); | ||
webWorkerCtx.$isInitialized$ = 1; | ||
logWorker("Initialized web worker"); | ||
})(msg[1]); | ||
webWorkerCtx.$postMessage$([ 2 ]); | ||
nextTick((() => { | ||
queuedEvents.length && logWorker(`Queued ready messages: ${queuedEvents.length}`); | ||
queuedEvents.slice().forEach(receiveMessageFromSandboxToWorker); | ||
queuedEvents.length = 0; | ||
})); | ||
queuedEvents.length && logWorker(`Queued ready messages: ${queuedEvents.length}`); | ||
queuedEvents.slice().forEach(receiveMessageFromSandboxToWorker); | ||
queuedEvents.length = 0; | ||
} else { | ||
@@ -1065,0 +1288,0 @@ queuedEvents.push(ev); |
@@ -1,1 +0,1 @@ | ||
const e=new Map,t=(e,t)=>({B:e.B,l:t}),r=(e,t)=>new Response(e,{headers:{"content-type":t||"text/html","Cache-Control":"no-store"}});self.oninstall=()=>self.skipWaiting(),self.onactivate=()=>self.clients.claim(),self.onmessage=t=>{const r=t.data,n=e.get(r.B);n&&(e.delete(r.B),clearTimeout(n[1]),n[0](r))},self.onfetch=n=>{const s=n.request,o=new URL(s.url).pathname;o.endsWith("partytown-sandbox-sw.html")?n.respondWith(r('<!DOCTYPE html><html><head><meta charset="utf-8"><script type="module">(e=>{const t=()=>{},r=e=>e.length,n=e=>e&&e.constructor&&e.constructor.name||"",s=(e,t)=>e.startsWith(t),i=e=>!(s(e,"webkit")||s(e,"toJSON")||s(e,"on")&&e.toLowerCase()===e),o=()=>Math.round(9999999999*Math.random()+4),a=new WeakMap,c=[],u=new Map,l={},d=new WeakMap,h=(e,t,r)=>e?e===e.window?0:"#document"===(r=e.nodeName)?1:"HTML"===r?2:"HEAD"===r?3:"BODY"===r?4:("number"!=typeof(t=a.get(e))&&f(e,t=o()),t):-1,p=(e,t,r)=>{const n=l[e].K,s=n.document;return 0===t?n:1===t?s:2===t?s.documentElement:3===t?s.head:4===t?s.body:(r=c.find((e=>e[0]===t)))?r[1]:void 0},f=(e,t)=>{e&&(c.push([t,e]),a.set(e,t))},m=(e,t,r,s,i)=>{if(void 0!==t){if("string"==(s=typeof t)||"number"===s||"boolean"===s||null==t)return[5,t];if("function"===s)return[2];if(r=r||new Set,Array.isArray(t))return r.has(t)?[0,[]]:(r.add(t),[0,t.map((t=>m(e,t,r)))]);if("object"===s)return t.nodeType?[3,{N:e,t:t.nodeType,s:h(t),C:t.nodeName}]:"Window"===(i=n(t))?[3,{N:e,t:0,s:0}]:"HTMLCollection"===i||"NodeList"===i?[3,{N:e,t:21,i:Array.from(t).map((t=>m(e,t,r)[1]))}]:"Event"===i?[1,$(e,t,r)]:"CSSStyleDeclaration"===i?[4,$(e,t,r)]:[4,$(e,t,r,!0,!0)]}},$=(e,t,r,n,s,o,a,c)=>{if(o={},!r.has(t))for(a in r.add(t),t)c=t[a],i(a)&&(n||"function"!=typeof c)&&(s||""!==c)&&(o[a]=m(e,c,r));return o},g=(e,t,r,n)=>{if(t){if(r=t[0],n=t[1],5===r)return n;if(6===r)return y(e,n);if(0===r)return n.map((t=>g(e,t)));if(3===r)return p(n.N,n.s);if(1===r)return w(T(e,n));if(4===r)return T(e,n)}},y=(e,{N:t,s:r,F:n})=>{let s=u.get(n);return s||(s=function(...s){const i={s:r,F:n,I:m(t,this),b:m(t,s)};e.postMessage([7,i])},u.set(n,s)),s},w=e=>new("detail"in e?CustomEvent:Event)(e.type,e),T=(e,t,r,n)=>{for(n in r={},t)r[n]=g(e,t[n]);return r},E=(e,t,n)=>{let s,i,o,a=0,c=r(n);for(;a<c;a++)i=n[a],s=n[a+1],o=n[a-1],Array.isArray(s)||("string"==typeof i?t=t[i]:0===s?t[o]=g(e,i):"function"==typeof t[o]&&(t=t[o].apply(t,g(e,i))));return t},L=(e,t)=>{let n,s,i=t.N,o=t.K,a=o.document,c=a.querySelector(\'script[type="text/partytown"]:not([data-ptid]):not([data-pterror]):not([async]):not([defer])\');c||(c=a.querySelector(\'script[type="text/partytown"]:not([data-ptid]):not([data-pterror])\')),c?(c.dataset.ptid=n=h(c,i),s={N:i,s:n},c.src?s.J=c.src:s.f=c.innerHTML,e.postMessage([6,s])):t.u||(t.u=1,((e,t,n)=>{let s=n._ptf,i=n._ptf=[],o=0;if(i.push=(r,n)=>e.postMessage([8,{N:t,s:0,m:r,b:m(t,Array.from(n))}]),s)for(;o<r(s);o+=2)i.push(s[o],s[o+1])})(e,i,o),a.dispatchEvent(new CustomEvent("pt0")),e.postMessage([4,i]))},M=(e,t,r,n)=>{if(!d.has(r)){d.set(r,t);const s=r.document,i=s.baseURI,o={N:t,D:d.get(r.parent),w:n,J:i},a=()=>e.postMessage([3,o]);l[t]={N:t,K:r,J:i},"complete"===s.readyState?a():r.addEventListener("load",a)}};(async e=>{let s;const a=e.parent;await(async(e,t)=>{const n=e.navigator.serviceWorker,i=await n.getRegistration(),o=e=>{i&&i.active&&i.active.postMessage(e)};return n.addEventListener("message",(e=>{return t=e.data,n=o,(async(e,t)=>{const n={B:t.B},s=[];for(const r of t.$tasks$)try{let t,s,o=r.N,a=r.s,c=r.a;if(l[o]||await new Promise((e=>{let t=0,r=()=>{l[o]||t++>999?e():setTimeout(r,9)};r()})),1===c[0]){const t=new l[o].K[c[1]](...g(e,c[2]));f(t,a)}else t=p(o,a),t?(s=E(e,t,c),r.c&&f(s,r.c),"object"==typeof(i=s)&&i&&i.then&&(s=await s,n.v=!0),n.G=m(o,s)):n.l=a+" not found"}catch(e){s.push(String(e.stack||e))}var i;return r(s)&&(n.l=s.join("\\n")),n})(s,t).then(n);var t,n})),!!i})(e)&&(s=new Worker(URL.createObjectURL(new Blob([\'(e=>{const t=Symbol(),r=Symbol(),n=Symbol(),s=Symbol(),i={},o=new WeakMap,a={},c={},$={},l=e=>e.toUpperCase(),u=e=>e.length,d=(e,t)=>Object.defineProperty(e,"name",{value:t}),h=(e,t)=>setTimeout(e,t),p=[],m=()=>Math.round(9999999999*Math.random()+4),g="text/partytown",f=(e,t)=>w(e[r],t),w=(e,t,r)=>(r=a[e])?r[t]:void 0,y=(e,t,n)=>T(e[r],t,n),T=(e,t,r,n)=>{(n=a[e]||{})[t]=r,a[e]=n};class E{constructor(e,i,o,a){return this[t]=o,this[r]=i,this[s]=a,v(this[n]=e,this,[])}}const I=[],M=(e,i,o,a)=>{const c=e[r];if(I.push({N:e[t],s:c,t:e[n],C:e[s],a:i,c:a}),!o)return L(c,i);setTimeout((()=>L(c,i)),50)},L=(e,t)=>{if(u(I)){const r={B:m(),$tasks$:I.slice()};I.length=0;const n=((e,t)=>{const r=new XMLHttpRequest,n=e.y+"proxytown";return r.open("POST",n,!1),r.send(JSON.stringify(t)),JSON.parse(r.responseText)})(c,r),s=n.v,i=j(e,t,n.G);if(n.l){if(s)return Promise.reject(n.l);throw new Error(n.l)}return s?Promise.resolve(i):i}},b=(e,t)=>M(e,t),S=(e,t,r)=>{const n=k(e,r);M(e,[...t,n,0],!0)},x=(e,t,r,n)=>{const s=N.some((e=>t.includes(e)));return M(e,[...t,k(e,r)],s,n)},v=(t,r,n)=>!r||"object"!=typeof r&&"function"!=typeof r||String(r).includes("[native")?r:new Proxy(r,{get(r,s,i){if("symbol"==typeof s||Reflect.has(r,s))return Reflect.get(r,s,i);if(H(t,s)){if(Reflect.has(e,s))return Reflect.get(e,s,i);return r[s]}8!==t&&10!==t||(t=3);const o=[...n,String(s)],a=c.r.find((e=>e[0]===t));if(a){const e=a[2][((e,t)=>{for(t=u(e)-1;t>=0;t--)if("string"==typeof e[t])return e[t];return e[0]})(o)];if(13===e)return(...e)=>x(r,o,e);if(e>0)return v(e,r,[...o])}const $=f(r,o[0]);return"function"==typeof $?(...e)=>$.apply(r,e):b(r,o)},set:(e,r,s,i)=>("symbol"==typeof r||Reflect.has(e,r)?Reflect.set(e,r,s,i):H(t,r)?e[r]=s:S(e,[...n,r],s),!0),has:(e,r)=>0===t||Reflect.has(e,r)}),H=(e,t)=>0===e&&(!c.M.includes(t)||c.n.includes(t)),N=["addEventListener","createElement","setAttribute","setItem"],R=(e,t,r,n)=>new(A(e,n=3===e?"#text":8===e?"#comment":11===e?"#document-fragment":10===e?"html":n))(e,t,r,n),A=(t,r)=>1===t?P(r):t<=11?e.Node:E,P=e=>O[e]||O.UNKNOWN,O={};class NodeList{constructor(e){(this._=e).map(((e,t)=>this[t]=e))}entries(){return this._.entries()}forEach(e,t){this._.map(e,t)}item(e){return this[e]}keys(){return this._.keys()}get length(){return u(this._)}values(){return this._.values()}[Symbol.iterator](){return this._[Symbol.iterator]()}}const W=(e,a,c,$)=>{if(void 0!==c){let d=typeof c;if("string"===d||"boolean"===d||"number"===d||null==c)return[5,c];if("function"===d)return[6,{N:e,s:a,F:(l=c,(u=o.get(l))||(o.set(l,u=m()),i[u]=l),u)}];if($=$||new Set,Array.isArray(c))return $.has(c)?[0,[]]:[0,c.map((t=>W(e,a,t,$)))];if("object"===d)return"number"==typeof c[r]?[3,{N:c[t],t:c[n],s:c[r],C:c[s]}]:c instanceof Event?[1,C(e,a,c,!1,$)]:[4,C(e,a,c,!0,$)]}var l,u},C=(e,t,r,n,s,i,o,a)=>{if(i={},!s.has(r))for(o in s.add(r),r)a=r[o],(n||"function"!=typeof a)&&(i[o]=W(e,t,a,s));return i},k=(e,n)=>e?W(e[t],e[r],n):[5,n],j=(e,t,r,n,s)=>{if(r){if(n=r[0],s=r[1],5===n)return s;if(6===n)return D(e,t,s);if(3===n)return B(s);if(0===n)return s.map((r=>j(e,t,r)));if(1===n)return i=U(e,t,s),new Proxy(new Event(i.type,i),{get:(e,t)=>t in i?i[t]:e[String(t)]});if(4===n)return U(e,t,s)}var i},U=(e,t,r,n,s)=>{for(s in n={},r)n[s]=j(e,[...t,s],r[s]);return n},B=({t:e,s:t,N:r,C:n,i:s})=>{const i=$[r];return 0===t?i.K:1===t?i.j:2===t?i.k:3===t?i.o:4===t?i.d:21===e?new NodeList(s.map(B)):R(e,t,r,n)},D=(e,t,{N:r,F:n})=>(i[n]||o.set(i[n]=function(...n){const s=R(0,e,r);return x(s,t,n)},n),i[n]),F=(e,t,r,n)=>{let s="";try{e.g=t,e.h="",e.H(r)}catch(e){console.error(r,e),s=String(e.stack||e)+""}return e.g=-1,e.h="",s},_=(e,t,r)=>{(r=w(e,t))&&h((()=>r.map((e=>e({type:t})))))},z=(e,t,r)=>{for(r=e.z;!r.host&&(r=(e=$[e.D]).z,!e.w););return new URL(t||"",r)},G=(e,t)=>z(e,t)+"",J=e=>z(Z(e),f(e,3)),V=()=>`<script src=${JSON.stringify(c.y+"partytown.js")} async defer><\\\\/script>`;class Node extends E{appendChild(e){return this.insertBefore(e,null)}get ownerDocument(){return Z(this).j}get href(){}set href(e){}insertBefore(e,n){const i=e[t]=this[t],o=e[r],a=e[s],l="SCRIPT"===a,u="IFRAME"===a;if(l){const t=f(e,2);if(t){const r=F(Z(e),o,t),n=r?"pterror":"ptid",s=r||o;S(e,["type"],g+"-x"),S(e,["dataset",n],s),S(e,["innerHTML"],t)}}return e=x(this,["insertBefore"],[e,n]),u&&(e=>{let t=0;const n=e[r],s=()=>{if($[n]&&$[n].u){let t=f(e,1)?"error":"load",r=f(e,t);r&&r.map((e=>e({type:t})))}else if(t++>2e3){let t=f(e,"error");t&&t.map((e=>e({type:"error"}))),console.error("Timeout")}else setTimeout(s,9)};s()})(e),l&&c.E([6,i]),e}get nodeName(){return this[s]}get nodeType(){return this[n]}}class HTMLElement extends Node{get localName(){return this.nodeName.toLowerCase()}get namespaceURI(){return"http://www.w3.org/1999/xhtml"}get tagName(){return this.nodeName}}class q extends HTMLElement{addEventListener(...e){let t=e[0],r=f(this,t)||[];r.push(e[1]),y(this,t,r)}get async(){return!0}set async(e){}get defer(){return!0}set defer(e){}get onload(){let e=f(this,"load");return e&&e[0]||null}set onload(e){y(this,"load",e?[e]:null)}get onerror(){let e=f(this,"error");return e&&e[0]||null}set onerror(e){y(this,"error",e?[e]:null)}}class HTMLDocument extends HTMLElement{get body(){return Z(this).d}createElement(e){e=l(e);const r=this[t],n=m(),s=new(P(e))(1,n,r,e);return x(this,["createElement"],[e],n),"IFRAME"===e?(Q({N:n,D:r,J:"about:blank"}),S(s,["srcdoc"],V())):"SCRIPT"===e&&S(s,["type"],g),s}createEvent(e){return new Event(e)}get currentScript(){const e=Z(this).g;return e>0?R(1,e,this[t],"SCRIPT"):null}get defaultView(){return ee(this)}get documentElement(){return Z(this).k}getElementsByTagName(e){return"BODY"===(e=l(e))?[this.body]:"HEAD"===e?[this.head]:x(this,["getElementsByTagName"],[e])}get head(){return Z(this).o}get implementation(){return{hasFeature:()=>!0}}get location(){return Z(this).z}set location(e){Z(this).z.href=e+""}get parentNode(){return null}get parentElement(){return null}get readyState(){return"complete"}}const X=(e,t,r,n)=>new(d(class extends HTMLElement{get parentElement(){return n}get parentNode(){return n}},`HTML${r}Element`))(1,t,e,l(r)),Y=e=>class{constructor(){this.s="",this.l=[],this.e=[]}get src(){return this.s}set src(t){const r=$[e];fetch(G(r,t),{mode:"no-cors",keepalive:!0}).then((e=>{e.ok?this.l.map((e=>e({type:"load"}))):this.e.map((e=>e({type:"error"})))}),(()=>this.e.forEach((e=>e({type:"error"})))))}addEventListener(e,t){"load"===e&&this.l.push(t),"error"===e&&this.e.push(t)}get onload(){return this.l[0]}set onload(e){this.l=[e]}get onerror(){return this.e[0]}set onerror(e){this.e=[e]}};class K extends URL{assign(){}reload(){}replace(){}}const Q=({N:s,D:i,w:o,J:a})=>{if($[s])$[s].z.href=a;else{class Window{constructor(){return y(this),v(0,this,[])}get document(){return l}get frameElement(){if(o)return null;const e=Z(this),r=this[t],n=e.D;return R(1,r,n,"IFRAME")}get globalThis(){return ee(this)}get location(){return g}set location(e){g.href=e+""}get parent(){return $[i].K}get self(){return ee(this)}get top(){for(const e in $)if($[e].w)return $[e].K}get window(){return ee(this)}}const l=new HTMLDocument(9,1,s,"#document"),u=new O.HTML(1,2,s,"HTML"),h=X(s,3,"Head",u),p=X(s,4,"Body",u),g=new K(a),f="addEventListener,removeEventListener,dispatchEvent,postMessage".split(","),w="devicePixelRatio,innerHeight,innerWidth,onmessage,onload,onerror".split(","),y=i=>{i[t]=s,i[r]=i[n]=0;for(const t in e)"function"!=typeof e[t]||t in i||(i[t]=e[t].bind(e));Object.getOwnPropertyNames(e).map((t=>{t in i||(i[t]=e[t])})),Object.keys(O).map((e=>i[O[e].name]=O[e])),c.M.map((e=>{const t=c.L[e],r=13===t;!(r||t>11)||e in i&&!f.includes(e)||(i[e]=r?(...t)=>x(i,[e],t):v(t,i,["window",e]))})),c.r.map((e=>{const t=e[0],r=e[1];i[r]=((e,t,r)=>d(class{constructor(...n){const s=m(),i=new E(t,s,e);return M(i,[1,r,W(e,s,n)]),i}},r))(s,t,r)})),i.Image=Y(s),i.Window=Window,i.performance=e.performance,i.name=name+s,i.navigator=(t=>{const r=e.navigator;return r.sendBeacon=(e,r)=>{const n=$[t];try{return fetch(G(n,e),{method:"POST",body:r,mode:"no-cors",keepalive:!0}),!0}catch(e){return console.error(e),!1}},r})(s),w.map((e=>Object.defineProperty(i,e,{get:()=>b(T,[e]),set:t=>S(T,[e],t)})))},T=new Window;$[s]={N:s,D:i,K:T,j:l,k:u,o:h,d:p,z:g,w:o,H:e=>{new Function(`with(this){${e}}`).apply(T)}}}c.E([6,s])},Z=e=>$[e[t]],ee=e=>Z(e).K;class HTMLAnchorElement extends HTMLElement{get hash(){return J(this).hash}get host(){return J(this).host}get hostname(){return J(this).hostname}get href(){return J(this)+""}set href(e){y(this,3,e+=""),S(this,["href"],e)}get origin(){return J(this).origin}get pathname(){return J(this).pathname}get port(){return J(this).port}get protocol(){return J(this).protocol}get search(){return J(this).search}}class te extends HTMLElement{getContext(...e){return v(14,this,["getContext",k(this,e)])}}class HTMLIFrameElement extends q{get contentDocument(){return this.contentWindow.document}get contentWindow(){const e=this[r];return $[e].K}get src(){return f(this,3)||""}set src(e){let t,r=new XMLHttpRequest;e=G(Z(this),e),y(this,1,void 0),y(this,3,e),r.open("GET",e,!1),r.send(),t=r.status,t>199&&t<300?S(this,["srcdoc"],((e,t)=>`<base href="${e}">`+t.replace(/<script>/g,\\\'<script type="text/partytown">\\\').replace(/<script /g,\\\'<script type="text/partytown" \\\').replace(/text\\\\/javascript/g,g)+V())(e,r.responseText)):y(this,1,t)}}class HTMLScriptElement extends q{get innerHTML(){return f(this,2)||""}set innerHTML(e){y(this,2,e)}get innerText(){return this.innerHTML}set innerText(e){this.innerHTML=e}get src(){return f(this,3)||""}set src(e){e=G(Z(this),e),y(this,3,e),S(this,["src"],e)}get textContent(){return this.innerHTML}set textContent(e){this.innerHTML=e}get type(){return b(this,["type"])}set type(e){"text/javascript"!==e&&S(this,["type"],e)}}const re=Symbol();class ne extends HTMLElement{get sheet(){const e=this;if(void 0===e[re]){const t=b(e,["sheet"]);if(null===t)e[re]=t;else{class r{get cssRules(){return t.cssRules}deleteRule(t){e[re]=void 0,x(e,["sheet","deleteRule"],[t])}insertRule(t,r){return e[re]=void 0,x(e,["sheet","insertRule"],[t,r])}}e[re]=new r}}return e[re]}}const se=[],ie=t=>{const r=t.data,n=r[0];var s;c.u?6===n?(async t=>{let r,n,s=t.N,i=t.s,o=t.f,a=t.J,l="",u=$[s];if(a)try{if(n=z(u,a),a=n+"",T(i,3,a),n.origin!==origin)try{await e.fetch(a,{method:"OPTIONS"})}catch(e){a="https://partytown.builder.io/api/proxy?p="+a}r=await e.fetch(a),r.ok?(o=await r.text(),u.g=i,u.h=a,u.H(o),_(i,"load")):(console.error(r.status,"url:",a),l=r.statusText,_(i,"error"))}catch(e){console.error("url:",a,e),l=String(e.stack||e)+"",_(i,"error")}else o&&(l=F(u,i,o));u.g=-1,u.h="",c.E([5,s,i,l])})(r[1]):7===n?(({s:e,F:t,I:r,b:n})=>{if(i[t])try{const s=j(e,[],r),o=j(e,[],n);i[t].apply(s,o)}catch(e){console.error(e)}})(r[1]):8===n?(({N:t,s:r,m:n,b:s})=>{try{const i=$[t].K,o=n[0]in i?i:n[0]in e?e:{},a=j(r,[],s),c=o[n[0]];Array.isArray(c)?c.push(...a):"function"==typeof c&&c.apply(o,a)}catch(e){console.error(e)}})(r[1]):3===n?Q(r[1]):4===n&&($[r[1]].u=1):1===n?(s=r[1],Object.assign(c,s),c.n=(c.e.forward||p).map((e=>e[0])),c.L=c.r[0][2],c.M=Object.keys(c.L).filter((e=>!c.n.includes(e))),c.E=postMessage.bind(e),e.postMessage=e.importScripts=void 0,e.Node=Node,e.Element=e.HTMLElement=q,e.Document=HTMLDocument,c.p.map((e=>{return O[(t=e,{IMAGE:"IMG",OLIST:"OL",PARAGRAPH:"P",TABLECELL:"TD",TABLEROW:"TR",ULIST:"UL"}[t=l(t.substr(4).replace("Element",""))]||t)]=d(class extends HTMLElement{},e);var t})),O.A=HTMLAnchorElement,O.CANVAS=te,O.IFRAME=HTMLIFrameElement,O.SCRIPT=HTMLScriptElement,O.STYLE=ne,c.u=1,c.E([2]),h((()=>{se.slice().forEach(ie),se.length=0}))):se.push(t)};e.onmessage=ie,postMessage([0])})(self);\\n\'],{type:"text/javascript"})),{name:"Partytown 🎉"}),s.onmessage=e=>((e,r,s)=>{const a=s[0];if(0===a){const s=(e=>{const r=e.document,s=e.partytown||{},o=(s.lib||"/~partytown/")+"",a=e.location+"",c=r.implementation.createHTMLDocument(),u=c.createElement("input"),l=c.createElement("canvas").getContext("2d"),d=[[0,e],[15,u.style],[9,c],[11,c.createDocumentFragment()],[16,u.dataset],[17,u.classList],[1,u],[14,l],[18,e.history],[19,e.location],[20,new MutationObserver(t)],[22,u.attributes],[21,u.childNodes],[23,new ResizeObserver(t)],[24,e.screen],[25,e.localStorage],[3,c.createTextNode("")]].map((e=>[...e,n(e[1])]));return{e:s,y:new URL(o,a)+"",p:Object.getOwnPropertyNames(e).filter((e=>/^H.*t$/i.test(e))),r:d.map((([e,t,r])=>{let s,o,a,c,u,l=[e,r,{}];for(s in t)i(s)&&(o=t[s],a=typeof o,"function"===a?l[2][s]=13:"object"===a&&(c=n(o),u=d.find((e=>e[2]===c)),u&&(l[2][s]=u[0])));return l}))}})(r);e.postMessage([1,s])}else if(2===a)M(e,o(),r,1);else{const t=l[s[1]];t&&(6===a?L(e,t):5===a&&((e,t,r,n,s)=>{(s=t.K.document.querySelector(`[data-ptid="${r}"]`))&&(n?s.dataset.pterror=n:s.type+="-x"),L(e,t)})(e,t,s[2],s[3]))}})(s,a,e.data),a.addEventListener("pt1",(e=>{const t=e.detail,r=h(t.frameElement);M(s,r,t)})))})(e)})(window);\n<\/script></head></html>')):o.endsWith("proxytown")&&n.respondWith((n=>new Promise((async s=>{const o=await n.clone().json(),i=await(r=>new Promise((async n=>{const s=[...await self.clients.matchAll()].sort(((e,t)=>e.url>t.url?-1:e.url<t.url?1:0))[0];if(s){const o=[n,setTimeout((()=>{e.delete(r.B),n(t(r,"Timeout"))}),1e4)];e.set(r.B,o),s.postMessage(r)}else n(t(r,"No Party"))})))(o);s(r(JSON.stringify(i),"application/json"))})))(s))}; | ||
const t=new Map,e=(t,e)=>({C:t.C,m:e}),r=(t,e)=>new Response(t,{headers:{"content-type":e||"text/html","Cache-Control":"no-store"}});self.oninstall=()=>self.skipWaiting(),self.onactivate=()=>self.clients.claim(),self.onmessage=e=>{const r=e.data,n=t.get(r.C);n&&(t.delete(r.C),clearTimeout(n[1]),n[0](r))},self.onfetch=n=>{const s=n.request,o=new URL(s.url).pathname;o.endsWith("partytown-sandbox-sw.html")?n.respondWith(r('<!DOCTYPE html><html><head><meta charset="utf-8"><script type="module">(t=>{const e=()=>!0,r=t=>t.length,n=t=>t&&t.constructor&&t.constructor.name||"",s=(t,e)=>t.startsWith(e),o=t=>!(s(t,"webkit")||s(t,"toJSON")||s(t,"constructor")||s(t,"toString")),i=()=>Math.round(9999999999*Math.random()+4),a=new WeakMap,c=[],l=new Map,u={},h=new WeakMap,p=(t,e,r)=>t?t===t.window?0:"#document"===(r=t.nodeName)?1:"HTML"===r?2:"HEAD"===r?3:"BODY"===r?4:("number"!=typeof(e=a.get(t))&&m(t,e=i()),e):-1,d=(t,e,r)=>{const n=u[t].L,s=n.document;return 0===e?n:1===e?s:2===e?s.documentElement:3===e?s.head:4===e?s.body:(r=c.find((t=>t[0]===e)))?r[1]:void 0},m=(t,e)=>{t&&(c.push([e,t]),a.set(t,e))},g=(t,e,r,s,o)=>{if(void 0!==e){if("string"==(s=typeof e)||"number"===s||"boolean"===s||null==e)return[9,e];if("function"===s)return[5];if(r=r||new Set,Array.isArray(e))return r.has(e)?[0,[]]:(r.add(e),[0,e.map((e=>g(t,e,r)))]);if("object"===s)return"Window"===(o=n(e))?[6,{O:t,t:0}]:"HTMLCollection"===o||"NodeList"===o?[7,Array.from(e).map((e=>g(t,e,r)[1]))]:"Event"===o?[4,f(t,e,r)]:"CSSRuleList"===o?[3,Array.from(e).map(y)]:o.startsWith("CSS")&&o.endsWith("Rule")?[2,y(e)]:"CSSStyleDeclaration"===o?[8,f(t,e,r)]:"Attr"===o?[1,[e.name,e.value]]:e.nodeType?[6,{O:t,t:p(e),D:e.nodeName}]:[8,f(t,e,r,!0,!0)]}},f=(t,e,r,n,s,i,a,c)=>{if(i={},!r.has(e))for(a in r.add(e),e)o(a)&&(c=e[a],(n||"function"!=typeof c)&&(s||""!==c)&&(i[a]=g(t,c,r)));return i},y=t=>{let e,r={};for(e in t)E.includes(e)&&(r[e]=t[e]);return r},$=(t,e,r,n)=>{if(e){if(r=e[0],n=e[1],9===r)return n;if(10===r)return w(t,n);if(0===r)return n.map((e=>$(t,e)));if(6===r)return d(n.O,n.t);if(4===r)return v(b(t,n));if(8===r)return b(t,n)}},w=(t,{O:e,t:r,G:n})=>{let s=l.get(n);return s||(s=function(...s){const o={t:r,G:n,J:g(e,this),b:g(e,s)};t.postMessage([7,o])},l.set(n,s)),s},v=t=>new("detail"in t?CustomEvent:Event)(t.type,t),b=(t,e,r,n)=>{for(n in r={},e)r[n]=$(t,e[n]);return r},E="cssText,selectorText,href,media,namespaceURI,prefix,name,conditionText".split(","),T=(t,e,n,s)=>{let o,i,a,c,l=0,u=r(n);for(;l<u;l++)if(i=n[l],o=n[l+1],a=n[l-1],!Array.isArray(o))if("string"==typeof i||"number"==typeof i){if(l+1===u&&s){const t={};return s.map((r=>t[r]=e[r])),t}e=e[i]}else{if(0===o)return void(e[a]=$(t,i));"function"==typeof e[a]&&(c=$(t,i),"insertRule"===a&&c[1]>r(e.cssRules)&&(c[1]=r(e.cssRules)),e=e[a].apply(e,c))}return e},S=(t,e)=>{let n,s,o=e.O,i=e.L,a=i.document,c=a.querySelector(\'script[type="text/partytown"]:not([data-ptid]):not([data-pterror]):not([async]):not([defer])\');c||(c=a.querySelector(\'script[type="text/partytown"]:not([data-ptid]):not([data-pterror])\')),c?(c.dataset.ptid=n=p(c,o),s={O:o,t:n},c.src?s.K=c.src:s.f=c.innerHTML,t.postMessage([6,s])):e.v||(e.v=1,((t,e,n)=>{let s=n._ptf,o=n._ptf=[],i=0;if(o.push=(r,n)=>t.postMessage([8,{O:e,t:0,n:r,b:g(e,Array.from(n))}]),s)for(;i<r(s);i+=2)o.push(s[i],s[i+1])})(t,o,i),a.dispatchEvent(new CustomEvent("pt0")),t.postMessage([4,o]))},L=t=>{const e=t.document,r=t.partytown||{},n=(r.lib||"/~partytown/")+"";return{e:r,z:new URL(n,t.location)+"",s:N(t,e)}},N=(t,r)=>{const n=r.implementation.createHTMLDocument(),s=n.createTextNode(""),o=n.createComment(""),i=n.createDocumentFragment(),a=n.createElement("i"),c=n.createElementNS("http://www.w3.org/2000/svg","svg"),l=n.createElement("canvas").getContext("2d"),u=new MutationObserver(e),h=new ResizeObserver(e),p=Object.getOwnPropertyNames(t).filter((t=>/^HTML.+Element$/.test(t))).map((t=>{const e=R(t);return[n.createElement(e)]})),d=[[t.localStorage],[t.history],[t.screen],[t.screen.orientation],[u,12],[h,12],[s],[o],[i],[a],[a.attributes],[a.classList],[a.dataset],[a.style],[c],[n],[n.doctype],[l],...p].filter((t=>t[0])).map((e=>{const r=e[0],n=e[1],s=r.constructor.name;return[s,t[s].prototype,r,n]})),m=[I("Window",t),I("Node",s)];return d.map((([t,e,r,n])=>O(m,t,e,r,n))),m},I=(t,e)=>{const r=[],n=[t,"Object",r];for(const t in e)M(r,e,t);return n},O=(t,e,r,n,s)=>{if("Object"!==e&&!t.some((t=>t[0]===e))){const o=Object.getPrototypeOf(r),i=o.constructor.name,a=[];O(t,i,o,n,s),Object.keys(Object.getOwnPropertyDescriptors(r)).map((t=>M(a,n,t)));const c=[e,i,a,s,n.nodeName];t.push(c)}},M=(t,e,r,s)=>{if(o(r)){const o=e[r],i=typeof o;"function"===i?t.push([r,5]):"object"===i&&null!=o&&"Object"!==(s=n(o))?o.nodeType?t.push([r,o.nodeType]):t.push([r,s]):"symbol"!==i&&(r.toUpperCase()===r?t.push([r,6,o]):t.push([r,6]))}},x={Anchor:"A",DList:"DL",Image:"IMG",OList:"OL",Paragraph:"P",TableCaption:"CAPTION",TableCell:"TD",TableCol:"COLGROUP",TableRow:"TR",TableSection:"TBODY",UList:"UL"},R=t=>(t=t.substr(4).replace("Element",""),x[t]||t),C=(t,e,r)=>{if(!h.has(r)){h.set(r,e);const n=r.document,s=n.baseURI,o={O:e,E:h.get(r.parent),K:s},i=()=>t.postMessage([3,o]);u[e]={O:e,L:r,K:s},"complete"===n.readyState?i():r.addEventListener("load",i)}};(async t=>{let e;const n=t.parent,s=await(async(t,n)=>{const s=t.navigator.serviceWorker,o=await s.getRegistration();return s.addEventListener("message",(t=>{return n=t.data,s=t=>o.active&&o.active.postMessage(t),(async(t,e)=>{const n={C:e.C},s=r(e.$tasks$);for(let r=0;r<s;r++)try{let s,i,a=e.$tasks$[r],c=a.O,l=a.t,h=a.a;if(u[c]||await new Promise((t=>{let e=0,r=()=>{u[c]||e++>999?t():setTimeout(r,9)};r()})),1===h[0]&&h[1]in u[c].L){const e=new u[c].L[h[1]](...$(t,h[2]));m(e,l)}else s=d(c,l),s?(i=T(t,s,h,a.$groupedGetters$),a.c&&m(i,a.c),"object"==typeof(o=i)&&o&&o.then&&(i=await i,n.w=!0),n.H=g(c,i)):n.m=l+" not found"}catch(t){r===s-1?n.m=String(t.stack||t):console.error(t)}var o;return n})(e,n).then(s);var n,s})),!!o})(t);s&&(e=new Worker(URL.createObjectURL(new Blob([\'(t=>{const e=Symbol(),r=Symbol(),n=Symbol(),s=Symbol(),i=Symbol(),o=new Map,a={},c=new WeakMap,l={},h={},u={},$={},d={},p=new Map,g=new Map,m="getClientRects,getBoundingClientRect".split(","),f="innerHeight,innerWidth,outerHeight,outerWidth,clientHeight,clientWidth,clientTop,clientLeft,scrollHeight,scrollWidth,scrollTop,scrollLeft,offsetHeight,offsetWidth,offsetTop,offsetLeft".split(","),w="childElementCount,children,firstElementChild,lastElementChild,nextElementSibling,previousElementSibling",y=()=>!0,I=t=>t.length,v=(t,e)=>Object.defineProperty(t,"name",{value:e}),b=[],S=()=>Math.round(9999999999*Math.random()+4),E="text/partytown",T=(t,e,r)=>Object.defineProperty(t.prototype,e,{...r,configurable:!0}),N=(t,e)=>Object.defineProperties(t.prototype,e),x=(t,e,r)=>T(t,e,{value:r,writable:!0}),M=[],L=(t,n,i,o,a)=>{const c=t[r];if(M.push({O:t[e],t:c,a:[...t[s],...n],c:o,$groupedGetters$:a}),!i)return C();setTimeout(C,40)},C=()=>{if(I(M)){const t=M[I(M)-1],e={C:S(),$tasks$:M.slice()};M.length=0;const r=((t,e)=>{const r=new XMLHttpRequest,n=t.z+"proxytown";return r.open("POST",n,!1),r.send(JSON.stringify(e)),JSON.parse(r.responseText)})($,e),n=r.w,s=st(t.t,t.a,r.H);if(r.m){if(n)return Promise.reject(r.m);throw new Error(r.m)}return n?Promise.resolve(s):s}},W=(t,e,r)=>L(t,e,!1,void 0,r),R=(t,e,r)=>{const n=[...e,nt(t,r),0];L(t,n,!0)},P=(t,e,r,n)=>{const s=e[I(e)-1],i=A.includes(s),o=[...e,nt(t,r)],a=L(t,o,i,n);return i||m.includes(s)||p.clear(),a},A="addEventListener,removeEventListener,createElement,createTextNode,insertBefore,insertRule,deleteRule,setAttribute,setItem,removeItem,classList.add,classList.remove,classList.toggle".split(","),H=(t,e)=>O(t[r],e),O=(t,e,r)=>(r=u[t])?r[e]:void 0,j=(t,e,n)=>D(t[r],e,n),D=(t,e,r,n)=>{(n=u[t]||{})[e]=r,u[t]=n},k=(t,e,r,n)=>{let s="";try{t.g=e,t.h="",B(t,r)}catch(t){console.error(r,t),s=String(t.stack||t)+""}return t.g=-1,t.h="",s},B=(t,e)=>{new Function(`with(this){${e}}`).apply(t.L)},U=(t,e,r)=>{(r=O(t,e))&&setTimeout((()=>r.map((t=>t({type:e})))),undefined)},F=(t,e,r)=>{for(r=t.A;!r.host&&(r=(t=d[t.E]).A,t.O!==t.E););return new URL(e||"",r)},_=(t,e)=>F(t,e)+"",z=t=>F(Z(t),H(t,4)),q=()=>`<script src=${JSON.stringify($.z+"partytown.js")} async defer><\\\\/script>`,G=t=>class{constructor(){this.s="",this.l=[],this.e=[]}get src(){return this.s}set src(e){const r=d[t];fetch(_(r,e),{mode:"no-cors",keepalive:!0}).then((t=>{t.ok?this.l.map((t=>t({type:"load"}))):this.e.map((t=>t({type:"error"})))}),(()=>this.e.forEach((t=>t({type:"error"})))))}addEventListener(t,e){"load"===t&&this.l.push(e),"error"===t&&this.e.push(e)}get onload(){return this.l[0]}set onload(t){this.l=[t]}get onerror(){return this.e[0]}set onerror(t){this.e=[t]}},J=(t,e,r)=>{let n=o.get(e);return n||(n=V(t,e,r),o.set(e,n)),n},V=(e,r,n)=>new(l[n]?l[n]:n.includes("-")?l.UNKNOWN:t.HTMLElement)(e,r,[],n);class X extends URL{assign(){}reload(){}replace(){}}class Y{constructor(t,o,a,c){this[e]=t,this[r]=o,this[s]=a||[],this[n]=c,this[i]={}}}class K extends Y{constructor(t,e,r,n){return super(t,e,r,n),new Proxy(this,{get:(t,e)=>W(t,[e]),set:(t,e,r)=>(R(t,[e],r),!0)})}}class Window extends Y{constructor(e,r,n){super(e,0);for(const e in t)if(!(e in this)&&"onmessage"!==e){const r=t[e];if(null!=r){const n="function"==typeof r&&!r.toString().startsWith("class");this[e]=n?r.bind(t):r}}Object.getOwnPropertyNames(t).map((e=>{e in this||(this[e]=t[e])}));for(const t in h)this[t]=v(class{constructor(...r){const n=new(0,h[t])(e,S()),s=nt(n,r);return L(n,[1,t,s]),n}},t);const s=new Proxy(this,{has:()=>!0});return d[e]={O:e,E:r,L:s,k:V(e,1,"#document"),l:V(e,2,"HTML"),p:V(e,3,"HEAD"),d:V(e,4,"BODY"),A:new X(n)},this.requestAnimationFrame=t=>setTimeout((()=>t(performance.now())),9),this.cancelAnimationFrame=t=>clearTimeout(t),s}get body(){return Z(this).d}get document(){return Z(this).k}get documentElement(){return Z(this).l}get frameElement(){const t=Z(this),e=t.E,r=t.O;return r===e?null:J(e,r,"IFRAME")}get globalThis(){return this}get head(){return Z(this).p}get location(){return Z(this).A}set location(t){Z(this).A.href=t+""}get Image(){return G(this[e])}get name(){const t=this[e];return name+t}get navigator(){return(e=>{const r=t.navigator;return r.sendBeacon=(t,r)=>{const n=d[e];try{return fetch(_(n,t),{method:"POST",body:r,mode:"no-cors",keepalive:!0}),!0}catch(t){return console.error(t),!1}},r})(this[e])}get origin(){return Z(this).A.origin}get parent(){return d[Z(this).E].L}get self(){return this}get top(){for(const t in d)if(d[t].O===d[t].E)return d[t].L}get window(){return this}}const Q=({O:t,E:e,K:r})=>{d[t]?d[t].A.href=r:new Window(t,e,r),$.F([6,t])},Z=t=>d[t[e]];class Node extends Y{appendChild(t){return this.insertBefore(t,null)}get href(){}set href(t){}insertBefore(t,s){const i=t[e]=this[e],o=t[r],a=t[n],c="SCRIPT"===a,l="IFRAME"===a;if(c){const e=H(t,3);if(e){const r=k(Z(t),o,e),n=r?"pterror":"ptid",s=r||o;R(t,["type"],E+"-x"),R(t,["dataset",n],s),R(t,["innerHTML"],e)}}return P(this,["insertBefore"],[t,s]),l&&(t=>{let e=0;const n=t[r],s=()=>{if(d[n]&&d[n].v){let e=H(t,1)?"error":"load",r=H(t,e);r&&r.map((t=>t({type:e})))}else if(e++>2e3){let e=H(t,"error");e&&e.map((t=>t({type:"error"}))),console.error("Timeout")}else setTimeout(s,9)};s()})(t),c&&(C(),$.F([6,i])),t}get nodeName(){return this[n]}get nodeType(){return 3}get ownerDocument(){return Z(this).k}}class tt{constructor(t){this.name=t[0],this.value=t[1]}get nodeName(){return this.name}get nodeType(){return 2}}class NodeList{constructor(t){(this._=t).map(((t,e)=>this[e]=t))}entries(){return this._.entries()}forEach(t,e){this._.map(t,e)}item(t){return this[t]}keys(){return this._.keys()}get length(){return I(this._)}values(){return this._.values()}[Symbol.iterator](){return this._[Symbol.iterator]()}}const et=(t,n,s,i)=>{if(void 0!==s){let h=typeof s;if("string"===h||"boolean"===h||"number"===h||null==s)return[9,s];if("function"===h)return[10,{O:t,t:n,G:(o=s,(l=c.get(o))||(c.set(o,l=S()),a[l]=o),l)}];if(i=i||new Set,Array.isArray(s))return i.has(s)?[0,[]]:[0,s.map((e=>et(t,n,e,i)))];if("object"===h)return"number"==typeof s[r]?[6,{O:s[e],t:s[r]}]:s instanceof Event?[4,rt(t,n,s,!1,i)]:[8,rt(t,n,s,!0,i)]}var o,l},rt=(t,e,r,n,s,i,o,a)=>{if(i={},!s.has(r))for(o in s.add(r),r)a=r[o],(n||"function"!=typeof a)&&(i[o]=et(t,e,a,s));return i},nt=(t,n)=>t?et(t[e],t[r],n):[9,n],st=(t,e,r,n,s)=>{if(r){if(n=r[0],s=r[1],9===n||2===n||3===n)return s;if(10===n)return ct(e,s);if(6===n)return ot(s);if(7===n)return new NodeList(s.map(ot));if(1===n)return new tt(s);if(0===n)return s.map((r=>st(t,e,r)));if(4===n)return i=it(t,e,s),new Proxy(new Event(i.type,i),{get:(t,e)=>e in i?i[e]:t[String(e)]});if(8===n)return it(t,e,s)}var i},it=(t,e,r,n,s)=>{for(s in n={},r)n[s]=st(t,[...e,s],r[s]);return n},ot=({O:t,t:e,D:r})=>at(t,e)||J(t,e,r),at=(t,e)=>{const r=d[t];return 0===e?r.L:1===e?r.k:2===e?r.l:3===e?r.p:4===e?r.d:void 0},ct=(t,{O:e,t:r,D:n,G:s})=>(a[s]||c.set(a[s]=function(...s){const i=J(e,r,n);return P(i,t,s)},s),a[s]),lt={sheet:{get(){return new ht(this)}}};class ht{constructor(t){this.ownerNode=t}get cssRules(){const t=this.ownerNode;return new Proxy({},{get(e,r){const n=String(r);return"item"===n?e=>$t(t,e):"length"===n?ut(t).length:isNaN(n)?e[r]:$t(t,n)}})}insertRule(t,e){const r=ut(this.ownerNode);return(e=void 0===e?0:e)>=0&&e<=r.length&&(P(this.ownerNode,["sheet","insertRule"],[t,e]),r.splice(e,0,0)),e}deleteRule(t){P(this.ownerNode,["sheet","deleteRule"],[t]),ut(this.ownerNode).splice(t,1)}}const ut=t=>{let e=H(t,2);return e||(e=W(t,["sheet","cssRules"]),j(t,2,e)),e},$t=(t,e)=>{let r=ut(t);return 0===r[e]&&(r[e]=W(t,["sheet","cssRules",parseInt(e,10)])),r[e]},dt={body:{get(){return Z(this).d}},createElement:{value(t){t=t.toUpperCase();const r=this[e],n=S(),s=J(r,n,t);return P(this,["createElement"],[t],n),"IFRAME"===t?(Q({O:n,E:r,K:"about:blank"}),R(s,["srcdoc"],q())):"SCRIPT"===t&&R(s,["type"],E),s}},createElementNS:{value(t,r){r=r.toUpperCase();const n=this[e],s=S(),i=J(n,s,r);return P(this,["createElementNS"],[t,r],s),i}},createTextNode:{value(t){const r=this[e],n=S(),s=J(r,n,"#text");return P(this,["createTextNode"],[t],n),s}},createEvent:{value:t=>new Event(t)},currentScript:{get(){const t=this[e],r=Z(this).g;return r>0?J(t,r,"SCRIPT"):null}},defaultView:{get(){return Z(this).L}},documentElement:{get(){return Z(this).l}},getElementsByTagName:{value(t){return"BODY"===(t=t.toUpperCase())?[Z(this).d]:"HEAD"===t?[Z(this).p]:P(this,["getElementsByTagName"],[t])}},head:{get(){return Z(this).p}},implementation:{value:{hasFeature:y}},location:{get(){return Z(this).A},set(t){Z(this).A.href=t+""}},nodeType:{value:9},parentNode:{value:null},parentElement:{value:null},readyState:{value:"complete"}},pt={localName:{get(){return this[n].toLowerCase()}},namespaceURI:{get(){return"http://www.w3.org/"+("SVG"===this[n]?"2000/svg":"1999/xhtml")}},nodeType:{value:1},tagName:{get(){return this[n]}}},gt={hash:{get(){return z(this).hash}},host:{get(){return z(this).host}},hostname:{get(){return z(this).hostname}},href:{get(){return z(this).href},set(t){j(this,4,t+=""),R(this,["href"],t)}},origin:{get(){return z(this).origin}},pathname:{get(){return z(this).pathname}},port:{get(){return z(this).port}},protocol:{get(){return z(this).protocol}},search:{get(){return z(this).search}}},mt={getContext:{value(...n){const s=["getContext",nt(this,n)];return new t.CanvasRenderingContext2D(this[e],this[r],s)}}},ft={addEventListener:{value(...t){const e=t[0],r=H(this,e)||[];r.push(t[1]),j(this,e,r)}},async:{get:y,set:y},defer:{get:y,set:y},onload:{get(){let t=H(this,"load");return t&&t[0]||null},set(t){j(this,"load",t?[t]:null)}},onerror:{get(){let t=H(this,"error");return t&&t[0]||null},set(t){j(this,"error",t?[t]:null)}}},wt={contentDocument:{get(){return this.contentWindow.document}},contentWindow:{get(){const t=this[r];return d[t].L}},src:{get(){return H(this,4)||""},set(t){let e,r=new XMLHttpRequest;t=_(Z(this),t),j(this,1,void 0),j(this,4,t),r.open("GET",t,!1),r.send(),e=r.status,e>199&&e<300?R(this,["srcdoc"],((t,e)=>`<base href="${t}">`+e.replace(/<script>/g,\\\'<script type="text/partytown">\\\').replace(/<script /g,\\\'<script type="text/partytown" \\\').replace(/text\\\\/javascript/g,E)+q())(t,r.responseText)):j(this,1,e)}},...ft},yt={get(){return H(this,3)||""},set(t){j(this,3,t)}},It={innerHTML:yt,innerText:yt,src:{get(){return H(this,4)||""},set(t){t=_(Z(this),t),j(this,4,t),R(this,["src"],t)}},getAttribute:{value(t){return"src"===t?this.src:P(this,["getAttribute"],[t])}},setAttribute:{value(t,e){"src"===t?this.src=e:P(this,["setAttribute"],[t,e])}},textContent:yt,type:{get(){return W(this,["type"])},set(t){"text/javascript"!==t&&R(this,["type"],t)}},...ft},vt=([o,a,c,u,$])=>{const d=bt[o]?K:"Object"===a||"EventTarget"===a?Y:t[a],p=t[o]=v(t[o]||class extends d{},o);12===u&&(h[o]=p),$&&(l[$]=p),c.map((([o,a,c])=>{o in p.prototype||o in d.prototype||("string"==typeof a?T(p,o,{get(){if(!this[i][o]){const c=this[e],l=this[r],h=[...this[s],o],u=this[n],$=t[a];this[i][o]=new $(c,l,h,u)}return this[i][o]},set(t){this[i][o]=t}}):5===a?x(p,o,(function(...t){return P(this,[o],t)})):a>0&&(void 0!==c?x(p,o,c):T(p,o,{get(){return W(this,[o])},set(t){return R(this,[o],t)}})))}))},bt={CSSStyleDeclaration:1,DOMStringMap:1,NamedNodeMap:1},St=(t,e)=>x(t,"nodeType",e),Et=(t,e)=>e.split(",").map((e=>T(t,e,{get(){let t=Tt(this,e),r=g.get(t);return r||(r=W(this,[e]),g.set(t,r)),r}}))),Tt=(t,n)=>t[e]+"."+t[r]+"."+n,Nt=(t,e)=>Object.keys(e).map((r=>x(t,r,e[r]))),xt=t=>f.map((e=>{T(t,e,{get(){const t=p.get(Tt(this,e));if("number"==typeof t)return t;const r=W(this,[e],f);return Object.entries(r).map((([t,e])=>{p.set(Tt(this,t),e)})),r[e]}})})),Mt=t=>m.map((e=>{t.prototype[e]=function(){let t=Tt(this,e),r=p.get(t);return r||(r=P(this,[e],b),p.set(t,r)),r}})),Lt=[],Ct=e=>{const r=e.data,n=r[0];var s;$.v?6===n?(async e=>{let r,n,s=e.O,i=e.t,o=e.f,a=e.K,c="",l=d[s];if(a)try{n=F(l,a),a=n+"",D(i,4,a);try{r=await t.fetch(a)}catch(t){if(n.origin===origin)throw t;a="https://partytown.builder.io/api/proxy?p="+a}r=await t.fetch(a),r.ok?(o=await r.text(),l.g=i,l.h=a,B(l,o),U(i,"load")):(console.error(r.status,"url:",a),c=r.statusText,U(i,"error"))}catch(t){console.error("url:",a,t),c=String(t.stack||t)+"",U(i,"error")}else o&&(c=k(l,i,o));l.g=-1,l.h="",$.F([5,s,i,c])})(r[1]):7===n?(({t:t,G:e,J:r,b:n})=>{if(a[e])try{const s=st(t,[],r),i=st(t,[],n);a[e].apply(s,i)}catch(t){console.error(t)}})(r[1]):8===n?(({O:e,t:r,n:n,b:s})=>{try{const i=d[e].L,o=n[0]in i?i:n[0]in t?t:{},a=st(r,[],s),c=o[n[0]];Array.isArray(c)?c.push(...a):"function"==typeof c&&c.apply(o,a)}catch(t){console.error(t)}})(r[1]):3===n?Q(r[1]):4===n&&(d[r[1]].v=1):1===n?(s=r[1],Object.assign($,s),$.o=($.e.forward||b).map((t=>t[0])),$.F=postMessage.bind(t),t.postMessage=t.importScripts=void 0,t.Node=Node,t.Window=Window,t.CSSStyleSheet=ht,$.s.map(vt),(()=>{const e=t.Element,r=t.DocumentFragment;"atob,btoa,crypto,indexedDB,performance,setTimeout,setInterval,clearTimeout,clearInterval".split(",").map((t=>delete Window.prototype[t])),N(e,pt),N(t.Document,dt),N(t.HTMLAnchorElement,gt),N(t.HTMLCanvasElement,mt),N(t.HTMLIFrameElement,wt),N(t.HTMLScriptElement,It),N(t.HTMLStyleElement,lt),Nt(ht,{type:"text/css"}),St(t.Comment,8),St(t.DocumentType,10),St(r,11),Et(Node,"childNodes,firstChild,isConnected,lastChild,nextSibling,parentElement,parentNode,previousSibling"),Et(e,w),Et(r,w),xt(e),xt(Window),Mt(e)})(),$.v=1,$.F([2]),Lt.slice().forEach(Ct),Lt.length=0):Lt.push(e)};t.onmessage=Ct,postMessage([0])})(self);\\n\'],{type:"text/javascript"})),{name:"Partytown 🎉"}),e.onmessage=t=>((t,e,r)=>{const n=r[0];if(0===n)t.postMessage([1,L(e)]);else if(2===n)C(t,i(),e);else{const e=u[r[1]];e&&(6===n?S(t,e):5===n&&((t,e,r,n,s)=>{(s=e.L.document.querySelector(`[data-ptid="${r}"]`))&&(n?s.dataset.pterror=n:s.type+="-x"),S(t,e)})(t,e,r[2],r[3]))}})(e,n,t.data),n.addEventListener("pt1",(t=>{const r=t.detail,n=p(r.frameElement);C(e,n,r)})))})(t)})(window);\n<\/script></head></html>')):o.endsWith("proxytown")&&n.respondWith((n=>new Promise((async s=>{const o=await n.clone().json(),i=await(r=>new Promise((async n=>{const s=[...await self.clients.matchAll()].sort(((t,e)=>t.url>e.url?-1:t.url<e.url?1:0))[0];if(s){const o=[n,setTimeout((()=>{t.delete(r.C),n(e(r,"Timeout"))}),1e4)];t.set(r.C,o),s.postMessage(r)}else n(e(r,"No Party"))})))(o);s(r(JSON.stringify(i),"application/json"))})))(s))}; |
{ | ||
"name": "@builder.io/partytown", | ||
"version": "0.0.11", | ||
"version": "0.0.12", | ||
"description": "Relocate resource intensive 3rd-party scripts off of the main thread and into a web worker.", | ||
@@ -30,9 +30,7 @@ "license": "MIT", | ||
"dev": "tsc && concurrently \"npm:build.watch\" \"npm:tsc.watch\" -n build,tsc -c magenta,yellow", | ||
"playwright": "playwright test tests --browser=chromium", | ||
"playwright.webkit": "playwright test --browser=webkit", | ||
"release": "npm run build && npm test && np --no-2fa --no-tests", | ||
"release": "npm run build && npm test && np --no-tests", | ||
"serve": "sirv tests --port 4000 --dev", | ||
"serve.test": "sirv tests --port 5000 --dev --quiet", | ||
"test": "start-server-and-test serve.test http://localhost:5000/ playwright", | ||
"test.webkit": "start-server-and-test serve.test http://localhost:5000/ playwright.webkit", | ||
"serve.test": "sirv tests --port 4001 --dev --quiet", | ||
"test": "playwright test tests/platform --browser=chromium", | ||
"test.webkit": "playwright test tests/platform --browser=webkit", | ||
"tsc.watch": "tsc -w", | ||
@@ -42,18 +40,17 @@ "version": "npm run build.prod" | ||
"devDependencies": { | ||
"@microsoft/api-extractor": "^7.18.16", | ||
"@playwright/test": "^1.15.2", | ||
"@microsoft/api-extractor": "^7.18.19", | ||
"@playwright/test": "^1.17.0-rc1", | ||
"@types/fs-extra": "^9.0.13", | ||
"@types/react": "^17.0.30", | ||
"concurrently": "^6.3.0", | ||
"@types/react": "^17.0.35", | ||
"concurrently": "^6.4.0", | ||
"fs-extra": "^10.0.0", | ||
"gzip-size": "^6.0.0", | ||
"node-fetch": "^3.0.0", | ||
"np": "^7.5.0", | ||
"node-fetch": "^3.1.0", | ||
"np": "^7.6.0", | ||
"prettier": "^2.4.1", | ||
"rollup": "^2.58.0", | ||
"rollup": "^2.60.0", | ||
"rollup-plugin-terser": "^7.0.2", | ||
"sirv-cli": "^1.0.14", | ||
"start-server-and-test": "^1.14.0", | ||
"tslib": "^2.3.1", | ||
"typescript": "^4.4.4" | ||
"typescript": "^4.5.2" | ||
}, | ||
@@ -60,0 +57,0 @@ "prettier": { |
@@ -90,2 +90,6 @@ /** | ||
/** | ||
* Log calls to main access, which also shows how many tasks were sent per message (debug mode required) | ||
*/ | ||
logMainAccess?: boolean; | ||
/** | ||
* Log script executions (debug mode required) | ||
@@ -92,0 +96,0 @@ */ |
@@ -6,4 +6,4 @@ { | ||
"types": "index.d.ts", | ||
"version": "0.0.11", | ||
"version": "0.0.12", | ||
"private": true | ||
} |
Sorry, the diff of this file is not supported yet
233315
15
3942