mirror of
https://github.com/MercuryWorkshop/scramjet.git
synced 2025-05-13 06:20:02 -04:00
feat: add helper functions to natives store + refac
This commit is contained in:
parent
70f0315791
commit
ef8735f95a
6 changed files with 164 additions and 121 deletions
|
@ -18,6 +18,16 @@ import { createWrapFn } from "./shared/wrap";
|
||||||
import { NavigateEvent } from "./events";
|
import { NavigateEvent } from "./events";
|
||||||
import type { URLMeta } from "../shared/rewriters/url";
|
import type { URLMeta } from "../shared/rewriters/url";
|
||||||
|
|
||||||
|
type NativeStore = {
|
||||||
|
store: Record<string, any>;
|
||||||
|
call: (target: string, that: any, ...args) => any;
|
||||||
|
construct: (target: string, ...args) => any;
|
||||||
|
};
|
||||||
|
type DescriptorStore = {
|
||||||
|
store: Record<string, PropertyDescriptor>;
|
||||||
|
get: (target: string, that: any) => any;
|
||||||
|
set: (target: string, that: any, value: any) => void;
|
||||||
|
};
|
||||||
//eslint-disable-next-line
|
//eslint-disable-next-line
|
||||||
export type AnyFunction = Function;
|
export type AnyFunction = Function;
|
||||||
|
|
||||||
|
@ -65,8 +75,8 @@ export class ScramjetClient {
|
||||||
serviceWorker: ServiceWorkerContainer;
|
serviceWorker: ServiceWorkerContainer;
|
||||||
bare: BareClientType;
|
bare: BareClientType;
|
||||||
|
|
||||||
descriptors: Record<string, PropertyDescriptor> = {};
|
natives: NativeStore;
|
||||||
natives: Record<string, any>;
|
descriptors: DescriptorStore;
|
||||||
wrapfn: (i: any, ...args: any) => any;
|
wrapfn: (i: any, ...args: any) => any;
|
||||||
|
|
||||||
cookieStore = new CookieStore();
|
cookieStore = new CookieStore();
|
||||||
|
@ -120,48 +130,79 @@ export class ScramjetClient {
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
this.natives = new Proxy(
|
this.natives = {
|
||||||
{},
|
store: new Proxy(
|
||||||
{
|
{},
|
||||||
get: (target, prop: string) => {
|
{
|
||||||
if (prop in target) {
|
get: (target, prop: string) => {
|
||||||
|
if (prop in target) {
|
||||||
|
return target[prop];
|
||||||
|
}
|
||||||
|
|
||||||
|
const split = prop.split(".");
|
||||||
|
const realProp = split.pop();
|
||||||
|
const realTarget = split.reduce((a, b) => a?.[b], this.global);
|
||||||
|
|
||||||
|
if (!realTarget) return;
|
||||||
|
|
||||||
|
const original = Reflect.get(realTarget, realProp);
|
||||||
|
target[prop] = original;
|
||||||
|
|
||||||
return target[prop];
|
return target[prop];
|
||||||
}
|
},
|
||||||
|
}
|
||||||
|
),
|
||||||
|
construct(target: string, ...args) {
|
||||||
|
const original = this.store[target];
|
||||||
|
if (!original) return;
|
||||||
|
|
||||||
const split = prop.split(".");
|
return new original(...args);
|
||||||
const realProp = split.pop();
|
},
|
||||||
const realTarget = split.reduce((a, b) => a?.[b], this.global);
|
call(target: string, that: any, ...args) {
|
||||||
|
const original = this.store[target];
|
||||||
|
if (!original) return;
|
||||||
|
|
||||||
if (!realTarget) return;
|
return original.call(that, ...args);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
this.descriptors = {
|
||||||
|
store: new Proxy(
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
get: (target, prop: string) => {
|
||||||
|
if (prop in target) {
|
||||||
|
return target[prop];
|
||||||
|
}
|
||||||
|
|
||||||
const original = Reflect.get(realTarget, realProp);
|
const split = prop.split(".");
|
||||||
target[prop] = original;
|
const realProp = split.pop();
|
||||||
|
const realTarget = split.reduce((a, b) => a?.[b], this.global);
|
||||||
|
|
||||||
|
if (!realTarget) return;
|
||||||
|
|
||||||
|
const original = nativeGetOwnPropertyDescriptor(
|
||||||
|
realTarget,
|
||||||
|
realProp
|
||||||
|
);
|
||||||
|
target[prop] = original;
|
||||||
|
|
||||||
return target[prop];
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
this.descriptors = new Proxy(
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
get: (target, prop: string) => {
|
|
||||||
if (prop in target) {
|
|
||||||
return target[prop];
|
return target[prop];
|
||||||
}
|
},
|
||||||
|
}
|
||||||
|
),
|
||||||
|
get(target: string, that: any) {
|
||||||
|
const original = this.store[target];
|
||||||
|
if (!original) return;
|
||||||
|
|
||||||
const split = prop.split(".");
|
return original.get.call(that);
|
||||||
const realProp = split.pop();
|
},
|
||||||
const realTarget = split.reduce((a, b) => a?.[b], this.global);
|
set(target: string, that: any, value: any) {
|
||||||
|
const original = this.store[target];
|
||||||
|
if (!original) return;
|
||||||
|
|
||||||
if (!realTarget) return;
|
original.set.call(that, value);
|
||||||
|
},
|
||||||
const original = nativeGetOwnPropertyDescriptor(realTarget, realProp);
|
};
|
||||||
target[prop] = original;
|
|
||||||
|
|
||||||
return target[prop];
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||||
const client = this;
|
const client = this;
|
||||||
this.meta = {
|
this.meta = {
|
||||||
|
@ -285,7 +326,7 @@ export class ScramjetClient {
|
||||||
if (!target) return;
|
if (!target) return;
|
||||||
|
|
||||||
const original = Reflect.get(target, prop);
|
const original = Reflect.get(target, prop);
|
||||||
this.natives[name] = original;
|
this.natives.store[name] = original;
|
||||||
|
|
||||||
this.RawProxy(target, prop, handler);
|
this.RawProxy(target, prop, handler);
|
||||||
}
|
}
|
||||||
|
@ -412,7 +453,7 @@ export class ScramjetClient {
|
||||||
if (!target) return;
|
if (!target) return;
|
||||||
|
|
||||||
const original = nativeGetOwnPropertyDescriptor(target, prop);
|
const original = nativeGetOwnPropertyDescriptor(target, prop);
|
||||||
this.descriptors[name] = original;
|
this.descriptors.store[name] = original;
|
||||||
|
|
||||||
return this.RawTrap(target, prop, descriptor);
|
return this.RawTrap(target, prop, descriptor);
|
||||||
}
|
}
|
||||||
|
|
|
@ -127,7 +127,8 @@ export default function (client: ScramjetClient, self: typeof window) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
client.natives["Element.prototype.hasAttribute"].call(
|
client.natives.call(
|
||||||
|
"Element.prototype.hasAttribute",
|
||||||
ctx.this,
|
ctx.this,
|
||||||
`scramjet-attr-${name}`
|
`scramjet-attr-${name}`
|
||||||
)
|
)
|
||||||
|
@ -185,7 +186,7 @@ export default function (client: ScramjetClient, self: typeof window) {
|
||||||
|
|
||||||
// i actually need to do something with this
|
// i actually need to do something with this
|
||||||
client.Proxy("Element.prototype.setAttributeNode", {
|
client.Proxy("Element.prototype.setAttributeNode", {
|
||||||
apply(ctx) {},
|
apply(_ctx) {},
|
||||||
});
|
});
|
||||||
|
|
||||||
client.Proxy("Element.prototype.setAttributeNS", {
|
client.Proxy("Element.prototype.setAttributeNS", {
|
||||||
|
@ -203,7 +204,8 @@ export default function (client: ScramjetClient, self: typeof window) {
|
||||||
|
|
||||||
if (ruleList) {
|
if (ruleList) {
|
||||||
ctx.args[2] = ruleList.fn(value, client.meta, client.cookieStore);
|
ctx.args[2] = ruleList.fn(value, client.meta, client.cookieStore);
|
||||||
client.natives["Element.prototype.setAttribute"].call(
|
client.natives.call(
|
||||||
|
"Element.prototype.setAttribute",
|
||||||
ctx.this,
|
ctx.this,
|
||||||
`scramjet-attr-${ctx.args[1]}`,
|
`scramjet-attr-${ctx.args[1]}`,
|
||||||
value
|
value
|
||||||
|
@ -216,7 +218,8 @@ export default function (client: ScramjetClient, self: typeof window) {
|
||||||
apply(ctx) {
|
apply(ctx) {
|
||||||
if (ctx.args[0].startsWith("scramjet-attr")) return ctx.return(undefined);
|
if (ctx.args[0].startsWith("scramjet-attr")) return ctx.return(undefined);
|
||||||
if (
|
if (
|
||||||
client.natives["Element.prototype.hasAttribute"].call(
|
client.natives.call(
|
||||||
|
"Element.prototype.hasAttribute",
|
||||||
ctx.this,
|
ctx.this,
|
||||||
ctx.args[0]
|
ctx.args[0]
|
||||||
)
|
)
|
||||||
|
@ -230,7 +233,8 @@ export default function (client: ScramjetClient, self: typeof window) {
|
||||||
apply(ctx) {
|
apply(ctx) {
|
||||||
if (ctx.args[0].startsWith("scramjet-attr")) return ctx.return(false);
|
if (ctx.args[0].startsWith("scramjet-attr")) return ctx.return(false);
|
||||||
if (
|
if (
|
||||||
client.natives["Element.prototype.hasAttribute"].call(
|
client.natives.call(
|
||||||
|
"Element.prototype.hasAttribute",
|
||||||
ctx.this,
|
ctx.this,
|
||||||
ctx.args[0]
|
ctx.args[0]
|
||||||
)
|
)
|
||||||
|
@ -245,7 +249,8 @@ export default function (client: ScramjetClient, self: typeof window) {
|
||||||
let newval;
|
let newval;
|
||||||
if (ctx.this instanceof self.HTMLScriptElement) {
|
if (ctx.this instanceof self.HTMLScriptElement) {
|
||||||
newval = rewriteJs(value, "(anonymous script element)", client.meta);
|
newval = rewriteJs(value, "(anonymous script element)", client.meta);
|
||||||
client.natives["Element.prototype.setAttribute"].call(
|
client.natives.call(
|
||||||
|
"Element.prototype.setAttribute",
|
||||||
ctx.this,
|
ctx.this,
|
||||||
"scramjet-attr-script-source-src",
|
"scramjet-attr-script-source-src",
|
||||||
bytesToBase64(encoder.encode(newval))
|
bytesToBase64(encoder.encode(newval))
|
||||||
|
@ -264,9 +269,11 @@ export default function (client: ScramjetClient, self: typeof window) {
|
||||||
},
|
},
|
||||||
get(ctx) {
|
get(ctx) {
|
||||||
if (ctx.this instanceof self.HTMLScriptElement) {
|
if (ctx.this instanceof self.HTMLScriptElement) {
|
||||||
const scriptSource = client.natives[
|
const scriptSource = client.natives.call(
|
||||||
"Element.prototype.getAttribute"
|
"Element.prototype.getAttribute",
|
||||||
].call(ctx.this, "scramjet-attr-script-source-src");
|
ctx.this,
|
||||||
|
"scramjet-attr-script-source-src"
|
||||||
|
);
|
||||||
|
|
||||||
if (scriptSource) {
|
if (scriptSource) {
|
||||||
return atob(scriptSource);
|
return atob(scriptSource);
|
||||||
|
@ -358,11 +365,10 @@ export default function (client: ScramjetClient, self: typeof window) {
|
||||||
],
|
],
|
||||||
{
|
{
|
||||||
get(ctx) {
|
get(ctx) {
|
||||||
const contentwindow =
|
const realwin = client.descriptors.get(
|
||||||
client.descriptors[
|
`${ctx.this.constructor.name}.prototype.contentWindow`,
|
||||||
`${ctx.this.constructor.name}.prototype.contentWindow`
|
ctx.this
|
||||||
].get;
|
);
|
||||||
const realwin = contentwindow.apply(ctx.this);
|
|
||||||
if (!realwin) return realwin;
|
if (!realwin) return realwin;
|
||||||
|
|
||||||
if (SCRAMJETCLIENT in realwin) {
|
if (SCRAMJETCLIENT in realwin) {
|
||||||
|
|
|
@ -67,8 +67,7 @@ export default function (client: ScramjetClient, _self: Self) {
|
||||||
url += "&type=module";
|
url += "&type=module";
|
||||||
}
|
}
|
||||||
|
|
||||||
const nativeSharedWorker = client.natives["SharedWorker"];
|
const worker = client.natives.construct("SharedWorker", url);
|
||||||
const worker = new nativeSharedWorker(url);
|
|
||||||
|
|
||||||
const handle = worker.port;
|
const handle = worker.port;
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { config } from "../../shared";
|
||||||
import { rewriteUrl } from "../../shared/rewriters/url";
|
import { rewriteUrl } from "../../shared/rewriters/url";
|
||||||
|
|
||||||
export default function (client: ScramjetClient, self: Self) {
|
export default function (client: ScramjetClient, self: Self) {
|
||||||
const Function = client.natives["Function"];
|
const Function = client.natives.store["Function"];
|
||||||
|
|
||||||
self[config.globals.importfn] = function (base: string) {
|
self[config.globals.importfn] = function (base: string) {
|
||||||
return function (url: string) {
|
return function (url: string) {
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { ScramjetClient } from "../../client";
|
||||||
export default function (client: ScramjetClient, self: Self) {
|
export default function (client: ScramjetClient, self: Self) {
|
||||||
let worker;
|
let worker;
|
||||||
if (self.Worker && flagEnabled("syncxhr", client.url)) {
|
if (self.Worker && flagEnabled("syncxhr", client.url)) {
|
||||||
worker = new client.natives["Worker"](config.files.sync);
|
worker = client.natives.construct("Worker", config.files.sync);
|
||||||
}
|
}
|
||||||
const ARGS = Symbol("xhr original args");
|
const ARGS = Symbol("xhr original args");
|
||||||
const HEADERS = Symbol("xhr headers");
|
const HEADERS = Symbol("xhr headers");
|
||||||
|
@ -44,7 +44,7 @@ export default function (client: ScramjetClient, self: Self) {
|
||||||
const sab = new SharedArrayBuffer(1024, { maxByteLength: 2147483647 });
|
const sab = new SharedArrayBuffer(1024, { maxByteLength: 2147483647 });
|
||||||
const view = new DataView(sab);
|
const view = new DataView(sab);
|
||||||
|
|
||||||
client.natives["Worker.prototype.postMessage"].call(worker, {
|
client.natives.call("Worker.prototype.postMessage", worker, {
|
||||||
sab,
|
sab,
|
||||||
args,
|
args,
|
||||||
headers: ctx.this[HEADERS],
|
headers: ctx.this[HEADERS],
|
||||||
|
|
|
@ -1,76 +1,73 @@
|
||||||
import { iswindow } from "..";
|
|
||||||
import { BareMuxConnection } from "../../shared";
|
import { BareMuxConnection } from "../../shared";
|
||||||
import { rewriteUrl } from "../../shared";
|
import { rewriteUrl } from "../../shared";
|
||||||
import { ScramjetClient } from "../client";
|
import { ScramjetClient } from "../client";
|
||||||
|
|
||||||
export default function (client: ScramjetClient, self: typeof globalThis) {
|
export default function (client: ScramjetClient, _self: typeof globalThis) {
|
||||||
if (self.Worker) {
|
client.Proxy("Worker", {
|
||||||
client.Proxy("Worker", {
|
construct({ args, call }) {
|
||||||
construct({ args, call }) {
|
args[0] = rewriteUrl(args[0], client.meta) + "?dest=worker";
|
||||||
args[0] = rewriteUrl(args[0], client.meta) + "?dest=worker";
|
|
||||||
|
|
||||||
if (args[1] && args[1].type === "module") {
|
if (args[1] && args[1].type === "module") {
|
||||||
|
args[0] += "&type=module";
|
||||||
|
}
|
||||||
|
|
||||||
|
const worker = call();
|
||||||
|
const conn = new BareMuxConnection();
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
const port = await conn.getInnerPort();
|
||||||
|
client.natives.call(
|
||||||
|
"Worker.prototype.postMessage",
|
||||||
|
worker,
|
||||||
|
{
|
||||||
|
$scramjet$type: "baremuxinit",
|
||||||
|
port,
|
||||||
|
},
|
||||||
|
[port]
|
||||||
|
);
|
||||||
|
})();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// sharedworkers can only be constructed from window
|
||||||
|
client.Proxy("SharedWorker", {
|
||||||
|
construct({ args, call }) {
|
||||||
|
args[0] = rewriteUrl(args[0], client.meta) + "?dest=worker";
|
||||||
|
|
||||||
|
if (args[1] && typeof args[1] === "string")
|
||||||
|
args[1] = `${client.url.origin}@${args[1]}`;
|
||||||
|
|
||||||
|
if (args[1] && typeof args[1] === "object") {
|
||||||
|
if (args[1].type === "module") {
|
||||||
args[0] += "&type=module";
|
args[0] += "&type=module";
|
||||||
}
|
}
|
||||||
|
|
||||||
const worker = call();
|
if (args[1].name) {
|
||||||
const conn = new BareMuxConnection();
|
args[1].name = `${client.url.origin}@${args[1].name}`;
|
||||||
|
|
||||||
(async () => {
|
|
||||||
const port = await conn.getInnerPort();
|
|
||||||
client.natives["Worker.prototype.postMessage"].call(
|
|
||||||
worker,
|
|
||||||
{
|
|
||||||
$scramjet$type: "baremuxinit",
|
|
||||||
port,
|
|
||||||
},
|
|
||||||
[port]
|
|
||||||
);
|
|
||||||
})();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (iswindow) {
|
|
||||||
client.Proxy("Worklet.prototype.addModule", {
|
|
||||||
apply(ctx) {
|
|
||||||
if (ctx.args[0]) ctx.args[0] = rewriteUrl(ctx.args[0], client.meta);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// sharedworkers can only be constructed from window
|
|
||||||
client.Proxy("SharedWorker", {
|
|
||||||
construct({ args, call }) {
|
|
||||||
args[0] = rewriteUrl(args[0], client.meta) + "?dest=worker";
|
|
||||||
|
|
||||||
if (args[1] && typeof args[1] === "string")
|
|
||||||
args[1] = `${client.url.origin}@${args[1]}`;
|
|
||||||
|
|
||||||
if (args[1] && typeof args[1] === "object") {
|
|
||||||
if (args[1].type === "module") {
|
|
||||||
args[0] += "&type=module";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (args[1].name) {
|
|
||||||
args[1].name = `${client.url.origin}@${args[1].name}`;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const worker = call();
|
const worker = call();
|
||||||
const conn = new BareMuxConnection();
|
const conn = new BareMuxConnection();
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
const port = await conn.getInnerPort();
|
const port = await conn.getInnerPort();
|
||||||
client.natives["MessagePort.prototype.postMessage"].call(
|
client.natives.call(
|
||||||
worker.port,
|
"MessagePort.prototype.postMessage",
|
||||||
{
|
worker.port,
|
||||||
$scramjet$type: "baremuxinit",
|
{
|
||||||
port,
|
$scramjet$type: "baremuxinit",
|
||||||
},
|
port,
|
||||||
[port]
|
},
|
||||||
);
|
[port]
|
||||||
})();
|
);
|
||||||
},
|
})();
|
||||||
});
|
},
|
||||||
}
|
});
|
||||||
|
|
||||||
|
client.Proxy("Worklet.prototype.addModule", {
|
||||||
|
apply(ctx) {
|
||||||
|
if (ctx.args[0]) ctx.args[0] = rewriteUrl(ctx.args[0], client.meta);
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue