forked from BasedHardware/omi
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathverify-bytecode.mjs
More file actions
97 lines (90 loc) · 4.71 KB
/
Copy pathverify-bytecode.mjs
File metadata and controls
97 lines (90 loc) · 4.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
// Post-build guard for the main+preload V8 bytecode compilation
// (electron.vite.config.ts → build.bytecode). Runs after `electron-vite build`
// in the `build` npm script.
//
// WHY: electron-vite's bytecode plugin is SILENT when it can't run — if the main
// or preload output ever becomes ESM (e.g. someone adds "type":"module" to
// package.json or forces output.format:'es'), the plugin logs a yellow warning
// and emits plain JS with NO error. The perf win would vanish unnoticed and the
// shipped installer would quietly lose it. This check turns that silent no-op
// into a loud build failure. It also guards the OTHER direction: kgWorker (a
// worker-thread entry loaded via new Worker()) must STAY plain JS — if it ever
// gets bytecoded it would fail to load at runtime in the worker thread.
//
// Matches AGENTS.md "back rules with checks — enforced rules don't drift".
import { existsSync, statSync, readFileSync } from 'node:fs'
import { fileURLToPath } from 'node:url'
import path from 'node:path'
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..')
const p = (rel) => path.join(root, rel)
const errors = []
// 1. The bytecoded entries must exist and be non-trivial. Their presence is the
// proof that build.bytecode actually ran (CJS output + production mode).
for (const rel of ['out/main/index.jsc', 'out/preload/index.jsc']) {
const abs = p(rel)
if (!existsSync(abs)) {
errors.push(
`${rel} is MISSING — bytecode did not run. The main/preload output is likely no ` +
`longer CJS (electron-vite bytecode is CJS-only and fails silently on ESM). ` +
`Check package.json "type" and electron.vite.config.ts output.format.`
)
} else if (statSync(abs).size < 1024) {
errors.push(`${rel} exists but is suspiciously small (${statSync(abs).size} bytes).`)
}
}
// 2. The entry .js files must be the tiny bootstrap stub (require loader + .jsc),
// confirming the entry is actually served from bytecode.
for (const rel of ['out/main/index.js', 'out/preload/index.js']) {
const abs = p(rel)
if (existsSync(abs)) {
const code = readFileSync(abs, 'utf8')
if (!code.includes('bytecode-loader.cjs') || !code.includes('.jsc')) {
errors.push(`${rel} is not the bytecode bootstrap stub — bytecode may not be active.`)
}
}
}
// 2b. STRUCTURAL GUARD (the coherent posture for the bytecode-entry export class):
// the MAIN entry stub MUST forward its compiled exports, i.e.
// `module.exports = require("./index.jsc")`. electron-vite's generated stub does
// NOT forward, so `require("../index.js")` from a plain chunk returns {} and any
// `require("../index.js").<name>(...)` throws `index.<name> is not a function` at
// runtime — in packaged builds only. scripts/patch-bytecode-entry-forward.mjs
// adds the forwarding; this asserts it stuck. With forwarding in place, a plain
// chunk reading ANY entry export is legitimately functional, so this single
// structural check (not a per-symbol denylist) covers the whole class — it would
// have gone red on BOTH shipped instances (getBackendSession + the
// mainChatPersonalization reads). The preload entry needs no forwarding (nothing
// requires its namespace; Electron loads it as the preload script).
const mainEntry = p('out/main/index.js')
if (existsSync(mainEntry)) {
const code = readFileSync(mainEntry, 'utf8')
if (!/module\.exports\s*=\s*require\((["'])\.\/index\.jsc\1\)/.test(code)) {
errors.push(
'out/main/index.js does not FORWARD its bytecode exports — expected ' +
'`module.exports = require("./index.jsc")`. Without it, `require("../index.js").<name>` ' +
'from any plain chunk is undefined at runtime (packaged only). Run ' +
'scripts/patch-bytecode-entry-forward.mjs after electron-vite build.'
)
}
}
// 3. kgWorker MUST stay plain JS. It is loaded via new Worker(kgWorker.js) in a
// worker thread that has no bytecode loader registered, so a bytecoded worker
// entry (a stub requiring kgWorker.jsc) would fail to load.
const kg = p('out/main/kgWorker.js')
if (existsSync(kg)) {
const code = readFileSync(kg, 'utf8')
if (code.includes('.jsc') || existsSync(p('out/main/kgWorker.jsc'))) {
errors.push(
'out/main/kgWorker.js appears bytecoded — it MUST stay plain JS (it runs in a ' +
'worker thread with no bytecode loader). Do not add "kgWorker" to bytecode.chunkAlias.'
)
}
} else {
errors.push('out/main/kgWorker.js is missing — expected the KG write-worker entry.')
}
if (errors.length) {
console.error('\n[verify-bytecode] FAILED:')
for (const e of errors) console.error(' - ' + e)
process.exit(1)
}
console.log('[verify-bytecode] OK — main+preload bytecode present, kgWorker plain.')