@@ -3,6 +3,7 @@ import { createHash } from "node:crypto";
33import { readdirSync , readFileSync , statSync } from "node:fs" ;
44import { basename , extname , join , relative } from "node:path" ;
55import { PDF_RUNTIME_ASSETS } from "@atlcli/pdf/browser" ;
6+ import { PDFIUM_WASM_SHA256 } from "@atlcli/import-pdf/browser-worker" ;
67
78const NODE_SPECIFIER_RE = / [ " ' ` ] (?: n o d e | b u n ) : [ A - Z a - z 0 - 9 _ . / - ] * [ " ' ` ] / g;
89const NODE_RUNTIME_RE = / (?< ! [ \w . ] ) B u f f e r \. [ A - Z a - z _ $ ] | \b p r o c e s s \. (?: e n v | v e r s i o n s ) \b | \b r e q u i r e \s * \( \s * [ " ' ` ] | \b _ _ d i r n a m e \b | \b _ _ f i l e n a m e \b / g;
@@ -34,6 +35,11 @@ const AGGREGATE_SHIKI_RUNTIME_RES = [
3435 / \b l a n g s - b u n d l e - f u l l \b / g,
3536 / [ " ' ` ] s h i k i (?: \/ (?: l a n g s | t h e m e s ) ) ? [ " ' ` ] / g,
3637] ;
38+ const IMPORT_ENGINE_BOUNDARY_RES = [
39+ / p d f j s - d i s t / g,
40+ / D E F A U L T _ P D F I U M _ W A S M _ U R L / g,
41+ / c d n [ . ] j s d e l i v r [ . ] n e t \/ n p m \/ @ e m b e d p d f \/ p d f i u m / gi,
42+ ] ;
3743const DOCX_CODE_FONT_SHA256 =
3844 "a0bf60ef0f83c5ed4d7a75d45838548b1f6873372dfac88f71804491898d138f" ;
3945
@@ -56,21 +62,34 @@ function matches(text: string, expressions: RegExp[]): string[] {
5662 return [ ...findings ] ;
5763}
5864
65+ function withoutReviewedEmscriptenBrowserProbe ( text : string ) : string {
66+ // @embedpdf /pdfium's browser-only Emscripten wrapper retains one discarded
67+ // environment probe even though the Node branch is compiled out. This exact
68+ // expression does not import/call Node and evaluates safely in a Worker.
69+ // Keep every other process.versions use subject to the Node-runtime ban.
70+ return text . replace (
71+ / t y p e o f p r o c e s s \s * = = \s * [ " ' ` ] o b j e c t [ " ' ` ] \s * & & \s * t y p e o f p r o c e s s [ . ] v e r s i o n s \s * = = \s * [ " ' ` ] o b j e c t [ " ' ` ] \s * & & \s * t y p e o f p r o c e s s [ . ] v e r s i o n s [ . ] n o d e \s * = = \s * [ " ' ` ] s t r i n g [ " ' ` ] \s * & & \s * p r o c e s s [ . ] t y p e / gu,
72+ "false" ,
73+ ) ;
74+ }
75+
5976export function scanHarnessText ( text : string ) : string [ ] {
77+ const reviewed = withoutReviewedEmscriptenBrowserProbe ( text ) ;
6078 const findings = [
61- ...matches ( text , [ NODE_SPECIFIER_RE , NODE_RUNTIME_RE ] ) ,
62- ...matches ( text , DYNAMIC_CODE_RES ) ,
63- ...matches ( text , REMOTE_EXECUTABLE_RES ) ,
64- ...matches ( text , [ EXTENSION_RUNTIME_RE ] ) ,
65- ...matches ( text , ROOT_RELATIVE_RES ) ,
66- ...matches ( text , ONIGURUMA_RUNTIME_RES ) ,
67- ...matches ( text , AGGREGATE_SHIKI_RUNTIME_RES ) ,
79+ ...matches ( reviewed , [ NODE_SPECIFIER_RE , NODE_RUNTIME_RE ] ) ,
80+ ...matches ( reviewed , DYNAMIC_CODE_RES ) ,
81+ ...matches ( reviewed , REMOTE_EXECUTABLE_RES ) ,
82+ ...matches ( reviewed , [ EXTENSION_RUNTIME_RE ] ) ,
83+ ...matches ( reviewed , ROOT_RELATIVE_RES ) ,
84+ ...matches ( reviewed , ONIGURUMA_RUNTIME_RES ) ,
85+ ...matches ( reviewed , AGGREGATE_SHIKI_RUNTIME_RES ) ,
86+ ...matches ( reviewed , IMPORT_ENGINE_BOUNDARY_RES ) ,
6887 ] ;
6988 // Shiki grammar chunks are inert JSON payloads. Some grammars list Node
7089 // globals as source-language keywords; those strings are not runtime use.
7190 if (
72- text . includes ( "Object.freeze(JSON.parse(`" ) &&
73- text . includes ( '"scopeName"' )
91+ reviewed . includes ( "Object.freeze(JSON.parse(`" ) &&
92+ reviewed . includes ( '"scopeName"' )
7493 ) {
7594 return findings . filter (
7695 ( finding ) => finding !== "__dirname" && finding !== "__filename" ,
@@ -170,6 +189,12 @@ export function validateHarnessInventory(artifacts: OutputArtifact[]): string[]
170189 "Typst compiler WASM" ,
171190 / (?: ^ | \/ ) a s s e t s \/ t y p s t _ t s _ w e b _ c o m p i l e r _ b g - [ ^ / ] + \. w a s m $ / ,
172191 ) ) ;
192+ issues . push ( ...requireOne (
193+ artifacts ,
194+ "PDFium importer WASM" ,
195+ / (?: ^ | \/ ) a s s e t s \/ p d f i u m - [ ^ / ] + \. w a s m $ / ,
196+ PDFIUM_WASM_SHA256 ,
197+ ) ) ;
173198 issues . push ( ...requireOne (
174199 artifacts ,
175200 "DOCX code font" ,
0 commit comments