mirror of
https://github.com/VibedByKaKi/t3-code-android-nightly.git
synced 2026-10-09 11:51:15 +02:00
151 lines
4.8 KiB
JavaScript
151 lines
4.8 KiB
JavaScript
import * as NodeEvents from "node:events";
|
|
import * as NodeFS from "node:fs";
|
|
import * as NodeFSP from "node:fs/promises";
|
|
import * as NodeTimers from "node:timers";
|
|
import * as NodeURL from "node:url";
|
|
import * as NodeVM from "node:vm";
|
|
import { parse } from "acorn";
|
|
|
|
const expectedDesktopBridgeApis = [
|
|
"getClientPlatform",
|
|
"getLocalEnvironmentBootstraps",
|
|
"getPathForFile",
|
|
"pickFolder",
|
|
];
|
|
const clerkPasskeysGlobal = "__clerk_internal_electron_passkeys";
|
|
const preloadExecutionTimeoutMs = 1_000;
|
|
const desktopPackage = JSON.parse(
|
|
NodeFS.readFileSync(new URL("../package.json", import.meta.url), "utf8"),
|
|
);
|
|
const electronVersion = desktopPackage.dependencies.electron;
|
|
|
|
const isSyntaxNode = (value) =>
|
|
typeof value === "object" && value !== null && "type" in value && typeof value.type === "string";
|
|
|
|
const inspectBundle = (source) => {
|
|
const runtimeImports = [];
|
|
const visit = (node) => {
|
|
if (node.type === "ImportExpression") {
|
|
throw new Error("Desktop preload bundle contains a dynamic import() call");
|
|
}
|
|
|
|
if (node.type === "CallExpression" && node.callee.type === "Identifier") {
|
|
if (node.callee.name === "require") {
|
|
const [argument] = node.arguments;
|
|
if (node.arguments.length !== 1 || argument?.type !== "Literal") {
|
|
throw new Error("Desktop preload bundle contains a dynamic require() call");
|
|
}
|
|
if (typeof argument.value !== "string") {
|
|
throw new Error("Desktop preload bundle contains a dynamic require() call");
|
|
}
|
|
runtimeImports.push(argument.value);
|
|
}
|
|
}
|
|
|
|
for (const child of Object.values(node)) {
|
|
if (Array.isArray(child)) {
|
|
for (const item of child) {
|
|
if (isSyntaxNode(item)) visit(item);
|
|
}
|
|
} else if (isSyntaxNode(child)) {
|
|
visit(child);
|
|
}
|
|
}
|
|
};
|
|
|
|
visit(parse(source, { ecmaVersion: "latest", sourceType: "script" }));
|
|
return runtimeImports;
|
|
};
|
|
|
|
const createSandboxModules = (exposedGlobals) => {
|
|
const ipcRenderer = {
|
|
invoke: () => Promise.resolve(undefined),
|
|
on: () => undefined,
|
|
removeListener: () => undefined,
|
|
sendSync: () => undefined,
|
|
};
|
|
const electron = {
|
|
contextBridge: {
|
|
exposeInMainWorld: (name, api) => exposedGlobals.set(name, api),
|
|
},
|
|
ipcRenderer,
|
|
webUtils: {
|
|
getPathForFile: () => "",
|
|
},
|
|
};
|
|
|
|
return new Map([
|
|
["electron", electron],
|
|
["electron/common", electron],
|
|
["electron/renderer", electron],
|
|
["events", NodeEvents.default],
|
|
["node:events", NodeEvents.default],
|
|
["timers", NodeTimers.default],
|
|
["node:timers", NodeTimers.default],
|
|
["url", NodeURL.default],
|
|
["node:url", NodeURL.default],
|
|
]);
|
|
};
|
|
|
|
const executeBundle = (source, sandboxModules) => {
|
|
const sandboxProcess = {
|
|
contextIsolated: true,
|
|
// oxlint-disable-next-line t3code/no-global-process-runtime -- This standalone CI verifier supplies the preload's host platform without loading Effect.
|
|
platform: process.platform,
|
|
versions: { electron: electronVersion },
|
|
};
|
|
const requireSandboxModule = (moduleName) => {
|
|
if (!sandboxModules.has(moduleName)) {
|
|
throw new Error(
|
|
`Unsupported sandbox module requested during preload execution: ${moduleName}`,
|
|
);
|
|
}
|
|
return sandboxModules.get(moduleName);
|
|
};
|
|
|
|
NodeVM.runInNewContext(
|
|
source,
|
|
{
|
|
process: sandboxProcess,
|
|
require: requireSandboxModule,
|
|
},
|
|
{
|
|
filename: "desktop-preload.cjs",
|
|
timeout: preloadExecutionTimeoutMs,
|
|
},
|
|
);
|
|
};
|
|
|
|
export const verifyPreloadBundle = (source) => {
|
|
const runtimeImports = inspectBundle(source);
|
|
const exposedGlobals = new Map();
|
|
const sandboxModules = createSandboxModules(exposedGlobals);
|
|
const unsupportedImports = [...new Set(runtimeImports)]
|
|
.filter((moduleName) => !sandboxModules.has(moduleName))
|
|
.toSorted();
|
|
|
|
if (unsupportedImports.length > 0) {
|
|
throw new Error(
|
|
`Desktop preload bundle contains unsupported sandbox imports: ${unsupportedImports.join(", ")}`,
|
|
);
|
|
}
|
|
|
|
executeBundle(source, sandboxModules);
|
|
|
|
const desktopBridge = exposedGlobals.get("desktopBridge");
|
|
const missingApis = expectedDesktopBridgeApis.filter(
|
|
(api) => typeof desktopBridge?.[api] !== "function",
|
|
);
|
|
if (!exposedGlobals.has("desktopBridge")) missingApis.unshift("desktopBridge exposure");
|
|
if (!exposedGlobals.has(clerkPasskeysGlobal)) missingApis.push(`${clerkPasskeysGlobal} exposure`);
|
|
|
|
if (missingApis.length > 0) {
|
|
throw new Error(`Desktop preload bundle is missing executable APIs: ${missingApis.join(", ")}`);
|
|
}
|
|
};
|
|
|
|
if (process.argv[1] && NodeURL.pathToFileURL(process.argv[1]).href === import.meta.url) {
|
|
const preloadUrl = new URL("../dist-electron/preload.cjs", import.meta.url);
|
|
const source = await NodeFSP.readFile(preloadUrl, "utf8");
|
|
verifyPreloadBundle(source);
|
|
}
|