11#!/usr/bin/env node
22// Build LevelCode in your browser: one static directory, dist-web/, that any static host can serve.
33//
4- // node scripts/build-web.mjs [--vscode vscode] [--out dist-web] [--account https://levelcode.ai]
4+ // node scripts/build-web.mjs [--vscode vscode] [--out dist-web] [--account https://levelcode.ai] [--api-url <origin>]
55// [--webview-origin 'https://{{uuid}}.view.example.com']
66// [--ext-host-origin 'https://{{uuid}}.ext.example.com']
77// [--static <prebuilt vscode-web dir>] [--id <build id>]
@@ -23,6 +23,7 @@ import { fileURLToPath } from 'node:url';
2323import { webConfig , renderIndex } from '../web/lib/config.mjs' ;
2424import { stageDeclarativeExtensions , copyExtension } from '../web/lib/extensions.mjs' ;
2525import { policy , toHeadersFile , toNginx } from '../web/lib/headers.mjs' ;
26+ import { hashTree } from '../web/lib/fingerprint.mjs' ;
2627
2728const REPO = path . resolve ( path . dirname ( fileURLToPath ( import . meta. url ) ) , '..' ) ;
2829const WEB = path . join ( REPO , 'web' ) ;
@@ -34,6 +35,8 @@ const args = Object.fromEntries(process.argv.slice(2).reduce((a, v, i, all) => {
3435const vscodeDir = path . resolve ( REPO , args . vscode || 'vscode' ) ;
3536const outDir = path . resolve ( REPO , args . out || 'dist-web' ) ;
3637const account = String ( args . account || process . env . LEVELCODE_WEB_ACCOUNT || 'https://levelcode.ai' ) . replace ( / \/ + $ / , '' ) ;
38+ // Only for a deployment whose API is not on the account origin (production has one host for both).
39+ const apiUrl = String ( args [ 'api-url' ] || process . env . LEVELCODE_WEB_API_URL || '' ) . replace ( / \/ + $ / , '' ) ;
3740const webviewOrigin = args [ 'webview-origin' ] || process . env . LEVELCODE_WEB_WEBVIEW_ORIGIN || '' ;
3841const extHostOrigin = args [ 'ext-host-origin' ] || process . env . LEVELCODE_WEB_EXTHOST_ORIGIN || '' ;
3942
@@ -65,8 +68,13 @@ for (const must of ['out/vs/workbench/workbench.web.main.internal.js', 'out/vs/w
6568const fingerprint = createHash ( 'sha256' ) ;
6669fingerprint . update ( fs . readFileSync ( path . join ( staticDir , 'out/vs/workbench/workbench.web.main.internal.js' ) ) ) ;
6770for ( const f of [ 'main.js' , 'boot.css' , 'index.html' ] ) { fingerprint . update ( fs . readFileSync ( path . join ( WEB , f ) ) ) ; }
71+ // Everything that goes into /_/<id>/ and is not the web client itself: the extension (its sources, media and skills),
72+ // its browser build, the scratch workspace, and the page's own configuration code.
6873const aiDir = path . join ( REPO , 'extensions' , 'levelcode-ai' ) ;
69- for ( const f of fs . readdirSync ( aiDir ) ) { if ( f . endsWith ( '.js' ) ) { fingerprint . update ( fs . readFileSync ( path . join ( aiDir , f ) ) ) ; } }
74+ hashTree ( fingerprint , aiDir , { skip : [ 'test' , 'node_modules' , 'scripts' , '.DS_Store' ] } ) ;
75+ hashTree ( fingerprint , path . join ( WEB , 'ai-extension' ) , { skip : [ 'assets.generated.js' , 'node_modules' , '.DS_Store' ] } ) ;
76+ hashTree ( fingerprint , path . join ( WEB , 'workspace' ) , { skip : [ 'node_modules' , '.DS_Store' ] } ) ;
77+ hashTree ( fingerprint , path . join ( WEB , 'lib' ) , { skip : [ '.DS_Store' ] } ) ;
7078const id = String ( args . id || fingerprint . digest ( 'hex' ) . slice ( 0 , 12 ) ) ;
7179let gitHead = 'unknown' ;
7280try { gitHead = execFileSync ( 'git' , [ '-C' , REPO , 'rev-parse' , '--short=10' , 'HEAD' ] , { encoding : 'utf8' } ) . trim ( ) ; } catch { /* not a checkout */ }
@@ -124,6 +132,7 @@ if (webviewOrigin) { productConfiguration.webviewContentExternalBaseUrlTemplate
124132if ( extHostOrigin ) { productConfiguration . webEndpointUrlTemplate = `${ extHostOrigin } ${ prefix } /static` ; }
125133const config = webConfig ( {
126134 account,
135+ apiUrl,
127136 extensions,
128137 base : prefix ,
129138 staticBase : `${ prefix } /static` ,
@@ -142,7 +151,7 @@ fs.writeFileSync(path.join(outDir, '_headers'), toHeadersFile(pol));
142151fs . mkdirSync ( path . join ( outDir , 'deploy' ) , { recursive : true } ) ;
143152fs . writeFileSync ( path . join ( outDir , 'deploy' , 'nginx.conf' ) , toNginx ( pol ) ) ;
144153const info = {
145- id, levelcode : gitHead , builtAt : new Date ( ) . toISOString ( ) , account,
154+ id, levelcode : gitHead , builtAt : new Date ( ) . toISOString ( ) , account, apiUrl : apiUrl || '(the account origin)' ,
146155 webviewOrigin : webviewOrigin || '(Code-OSS default: *.vscode-cdn.net)' ,
147156 extHostOrigin : extHostOrigin || '(same origin as the editor)' ,
148157 extensions,
0 commit comments