Skip to content

Commit afd7341

Browse files
committed
[chrome] migrate to bundled scramjet
1 parent 4ba3e81 commit afd7341

File tree

12 files changed

+317
-271
lines changed

12 files changed

+317
-271
lines changed

packages/chrome/index.html

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
77
<title>Vite + TS</title>
88

9-
<script src="/scram/scramjet.all.js"></script>
109
<script src="https://js.puter.com/v2/"></script>
1110
</head>
1211

packages/chrome/src/IsolatedFrame.tsx

Lines changed: 32 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {
1414
} from "@mercuryworkshop/scramjet/bundled";
1515

1616
import scramjetWASM from "../../scramjet/dist/scramjet.wasm.wasm?url";
17-
import scramjetAll from "../../scramjet/dist/scramjet.all.js?url";
17+
import scramjetAll from "../../scramjet/dist/scramjet.js?url";
1818
import injectScript from "../../inject/dist/inject.js?url";
1919
import { BareClient } from "@mercuryworkshop/bare-mux-custom";
2020
import { ElementType, type Handler, Parser } from "htmlparser2";
@@ -34,7 +34,11 @@ import {
3434
iconSearch,
3535
} from "./icons";
3636

37-
import type { Chromebound, Framebound } from "../../inject/src/types";
37+
import type {
38+
Chromebound,
39+
Framebound,
40+
FrameSequence,
41+
} from "../../inject/src/types";
3842
import type { Tab } from "./Tab";
3943
import { browser } from "./Browser";
4044
import { createMenu } from "./components/Menu";
@@ -60,11 +64,6 @@ const cfg = {
6064
templocid: "$scramjet$temploc",
6165
tempunusedid: "$scramjet$tempunused",
6266
},
63-
files: {
64-
wasm: "/scram/scramjet.wasm.wasm",
65-
all: "/scram/scramjet.all.js",
66-
sync: "/scram/scramjet.sync.js",
67-
},
6867
flags: {
6968
syncxhr: false,
7069
strictRewrites: true,
@@ -92,13 +91,13 @@ const cfg = {
9291
return decodeURIComponent(url);
9392
}`,
9493
},
94+
maskedfiles: ["inject.js", "scramjet.wasm.js"],
9595
};
9696

9797
setConfig(cfg);
9898

9999
// you can get to any frame by window.frames[index][index]...
100100
// so we can encode a certain frame as a sequence of indices to reach it, and then it will be available from any other frame, even cross-origin
101-
type FrameSequence = number[];
102101

103102
function findSelfSequence(
104103
target: Window,
@@ -161,6 +160,9 @@ addEventListener("message", async (e) => {
161160
}
162161
});
163162

163+
const virtualWasmPath = "/scramjet.wasm.js";
164+
const virtualInjectPath = "/inject.js";
165+
164166
const getInjectScripts: ScramjetInterface["getInjectScripts"] = (
165167
meta,
166168
handler,
@@ -169,72 +171,13 @@ const getInjectScripts: ScramjetInterface["getInjectScripts"] = (
169171
script
170172
) => {
171173
const injected = `
172-
{
173-
const top = self.top;
174-
const sequence = ${JSON.stringify(findSelfSequence(self)!)};
175-
const target = sequence.reduce((win, idx) => win.frames[idx], top);
176-
let counter = 0;
177-
178-
let syncPool = new Map();
179-
let listeners = new Map();
180-
181-
addEventListener("message", async (e) => {
182-
if (!e.data || !("$scramjetipc$type" in e.data)) return;
183-
const type = e.data.$scramjetipc$type;
184-
if (type === "response") {
185-
const token = e.data.$scramjetipc$token;
186-
const message = e.data.$scramjetipc$message;
187-
188-
const cb = syncPool.get(token);
189-
if (cb) {
190-
cb(message);
191-
syncPool.delete(token);
192-
}
193-
} else if (type === "request") {
194-
const method = e.data.$scramjetipc$method;
195-
const message = e.data.$scramjetipc$message;
196-
const token = e.data.$scramjetipc$token;
197-
198-
const fn = listeners.get(method);
199-
if (fn) {
200-
const response = await fn(message);
201-
e.source.postMessage({
202-
$scramjetipc$type: "response",
203-
$scramjetipc$token: token,
204-
$scramjetipc$message: response,
205-
});
206-
} else {
207-
console.error("Unknown scramjet ipc clientbound method", method);
208-
}
209-
}
210-
});
211-
212-
const client = $scramjetLoadClient().loadAndHook({
213-
interface: {
214-
getInjectScripts: ${getInjectScripts.toString()},
215-
onClientbound: function(type, callback) {
216-
listeners.set(type, callback);
217-
},
218-
sendServerbound: async function(type, msg) {
219-
const token = counter++;
220-
target.postMessage({
221-
$scramjetipc$type: "request",
222-
$scramjetipc$method: type,
223-
$scramjetipc$token: token,
224-
$scramjetipc$message: msg,
225-
}, "*");
226-
227-
return new Promise((res) => {
228-
syncPool.set(token, res);
229-
});
230-
}
231-
},
232-
config: ${JSON.stringify(config)},
233-
cookies: ${JSON.stringify(cookieJar.dump())},
234-
transport: null,
235-
});
236-
document.currentScript.remove();
237-
}
174+
$injectLoad({
175+
sequence: ${JSON.stringify(findSelfSequence(self)!)},
176+
config: ${JSON.stringify(config)},
177+
cookies: ${JSON.stringify(cookieJar.dump())},
178+
wisp: ${JSON.stringify(cfg.wisp)},
179+
});
180+
document.currentScript.remove();
238181
`;
239182

240183
// for compatibility purpose
@@ -248,10 +191,9 @@ const getInjectScripts: ScramjetInterface["getInjectScripts"] = (
248191
);
249192

250193
return [
251-
script(config.files.wasm),
252-
script(config.files.all),
194+
script(virtualWasmPath),
195+
script(virtualInjectPath),
253196
script("data:application/javascript;base64," + base64Injected),
254-
script(virtualInjectUrl),
255197
];
256198
};
257199
setInterface({
@@ -287,20 +229,21 @@ setInterface({
287229
getWorkerInjectScripts: (meta, js, config, type) => {
288230
const module = type === "module";
289231
let str = "";
290-
const script = (script: keyof typeof config.files) => {
232+
const script = (script: string) => {
291233
if (module) {
292-
str += `import "${config.files[script]}"\n`;
234+
str += `import "${script}"\n`;
293235
} else {
294-
str += `importScripts("${config.files[script]}");\n`;
236+
str += `importScripts("${script}");\n`;
295237
}
296238
};
297-
script("wasm");
298-
script("all");
299-
str += `$scramjetLoadClient().loadAndHook({
300-
config: ${JSON.stringify(config)},
301-
interface: {},
302-
transport: null,
303-
});`;
239+
script(virtualWasmPath);
240+
// TODO
241+
// script();
242+
// str += `$scramjetLoadClient().loadAndHook({
243+
// config: ${JSON.stringify(config)},
244+
// interface: {},
245+
// transport: null,
246+
// });`;
304247

305248
return str;
306249
},
@@ -341,8 +284,6 @@ function getRootDomain(url: URL): string {
341284
return tldts.getDomain(url.href) || url.hostname;
342285
}
343286

344-
const virtualInjectUrl = "/inject.js";
345-
346287
function makeController(url: URL): Controller {
347288
let originurl = new URL(ISOLATION_ORIGIN);
348289
let baseurl = new URL(
@@ -427,11 +368,9 @@ const methods = {
427368
data.initialHeaders = headers;
428369

429370
// handle scramjet.all.js and scramjet.wasm.js requests
430-
if (data.rawUrl.pathname === cfg.files.wasm) {
371+
if (data.rawUrl.pathname === virtualWasmPath) {
431372
return [await makeWasmResponse(), undefined];
432-
} else if (data.rawUrl.pathname === cfg.files.all) {
433-
return [await makeAllResponse(), undefined];
434-
} else if (data.rawUrl.pathname === virtualInjectUrl) {
373+
} else if (data.rawUrl.pathname === virtualInjectPath) {
435374
return [
436375
await fetch(injectScript).then(async (x) => {
437376
const text = await x.text();
@@ -537,7 +476,6 @@ window.addEventListener("message", async (event) => {
537476
});
538477

539478
let wasmPayload: string | null = null;
540-
let allPayload: string | null = null;
541479

542480
async function makeWasmResponse() {
543481
if (!wasmPayload) {
@@ -567,20 +505,6 @@ async function makeWasmResponse() {
567505
};
568506
}
569507

570-
async function makeAllResponse(): Promise<ScramjetFetchResponse> {
571-
if (!allPayload) {
572-
const resp = await fetch(scramjetAll);
573-
allPayload = await resp.text();
574-
}
575-
576-
return {
577-
body: allPayload,
578-
headers: { "Content-Type": "application/javascript" },
579-
status: 200,
580-
statusText: "OK",
581-
};
582-
}
583-
584508
let synctoken = 0;
585509
let syncPool: { [token: number]: (val: any) => void } = {};
586510
export function sendFrame<T extends keyof Framebound>(

packages/chrome/src/Tab.tsx

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,6 @@ import { HistoryPage } from "./pages/HistoryPage";
99
import { SettingsPage } from "./pages/SettingsPage";
1010
import { serviceWorkerReady } from "./main";
1111
import { DownloadsPage } from "./pages/DownloadsPage";
12-
import {
13-
ScramjetClient,
14-
ScramjetFrame,
15-
} from "@mercuryworkshop/scramjet/bundled";
1612
import { IsolatedFrame } from "./IsolatedFrame";
1713
import { defaultFaviconUrl } from "./assets/favicon";
1814

@@ -29,7 +25,7 @@ export class Tab extends StatefulClass {
2925
id: number;
3026
title: string | null;
3127
frame: IsolatedFrame;
32-
devtoolsFrame: ScramjetFrame;
28+
devtoolsFrame: any;
3329
screenshot: string | null = null;
3430

3531
icon: string | null;

packages/inject/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"packageManager": "[email protected]",
1414
"dependencies": {
1515
"@mercuryworkshop/scramjet": "workspace:*",
16+
"@mercuryworkshop/libcurl-transport": "workspace:*",
1617
"chobitsu": "workspace:*",
1718
"html-to-image": "^1.11.13"
1819
}

packages/inject/src/contextmenu.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { sendChrome } from "./ipc";
2+
import { Chromebound } from "./types";
3+
4+
export function setupContextMenu() {
5+
// TODO: this needs to always be last
6+
document.addEventListener("contextmenu", (e) => {
7+
e.preventDefault();
8+
const target = e.target;
9+
const selection = getSelection()?.toString();
10+
11+
const resp: Chromebound["contextmenu"][0] = {
12+
x: e.clientX,
13+
y: e.clientY,
14+
selection,
15+
};
16+
17+
if (target instanceof HTMLImageElement) {
18+
resp.image = {
19+
src: target.src,
20+
width: target.naturalWidth,
21+
height: target.naturalHeight,
22+
};
23+
} else if (target instanceof HTMLAnchorElement) {
24+
resp.anchor = {
25+
href: target.href,
26+
};
27+
} else if (target instanceof HTMLVideoElement) {
28+
resp.video = {
29+
src: target.currentSrc,
30+
width: target.videoWidth,
31+
height: target.videoHeight,
32+
};
33+
}
34+
35+
sendChrome("contextmenu", resp);
36+
});
37+
}

packages/inject/src/history.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { sendChrome } from "./ipc";
2+
import { client } from "./scramjet";
3+
4+
export function setupHistoryEmulation() {
5+
client.Proxy("History.prototype.pushState", {
6+
apply(ctx) {
7+
sendChrome("history_pushState", {
8+
state: ctx.args[0],
9+
title: ctx.args[1],
10+
url: new URL(ctx.args[2], client.url).href,
11+
});
12+
13+
ctx.return(undefined);
14+
},
15+
});
16+
17+
client.Proxy("History.prototype.replaceState", {
18+
apply(ctx) {
19+
sendChrome("history_replaceState", {
20+
state: ctx.args[0],
21+
title: ctx.args[1],
22+
url: new URL(ctx.args[2], client.url).href,
23+
});
24+
25+
ctx.return(undefined);
26+
},
27+
});
28+
client.Proxy("History.prototype.back", {
29+
apply(ctx) {
30+
sendChrome("history_go", { delta: -1 });
31+
32+
ctx.return(undefined);
33+
},
34+
});
35+
client.Proxy("History.prototype.forward", {
36+
apply(ctx) {
37+
sendChrome("history_go", { delta: 1 });
38+
39+
ctx.return(undefined);
40+
},
41+
});
42+
client.Proxy("History.prototype.go", {
43+
apply(ctx) {
44+
sendChrome("history_go", { delta: ctx.args[0] });
45+
46+
ctx.return(undefined);
47+
},
48+
});
49+
}

0 commit comments

Comments
 (0)