From 3a6f50f0a46f20aa7100bd481d69cd7bde2107b8 Mon Sep 17 00:00:00 2001 From: hmmhmmhm Date: Mon, 20 Oct 2025 00:10:40 +0900 Subject: [PATCH] refactor: convert build scripts from JavaScript to TypeScript --- apps/browser/.gitignore | 3 + apps/browser/package.json | 5 +- .../before-sign.ts} | 44 +++++++++---- .../download-widevine.ts} | 29 ++++++--- .../evs-sign.js => scripts-src/evs-sign.ts} | 63 ++++++++++++------- apps/browser/tsconfig.scripts.json | 17 +++++ 6 files changed, 116 insertions(+), 45 deletions(-) rename apps/browser/{scripts/before-sign.js => scripts-src/before-sign.ts} (67%) mode change 100755 => 100644 rename apps/browser/{scripts/download-widevine.js => scripts-src/download-widevine.ts} (73%) rename apps/browser/{scripts/evs-sign.js => scripts-src/evs-sign.ts} (84%) create mode 100644 apps/browser/tsconfig.scripts.json diff --git a/apps/browser/.gitignore b/apps/browser/.gitignore index 634af8e..e7325e8 100644 --- a/apps/browser/.gitignore +++ b/apps/browser/.gitignore @@ -4,3 +4,6 @@ dist-renderer release *.log .DS_Store + +# Compiled scripts (TypeScript sources in scripts-src/) +scripts/*.js diff --git a/apps/browser/package.json b/apps/browser/package.json index c101902..669415f 100644 --- a/apps/browser/package.json +++ b/apps/browser/package.json @@ -4,9 +4,10 @@ "description": "A lightweight, elegant web browser for developers featuring an iPhone frame interface", "main": "dist/main/index.js", "scripts": { - "dev": "npm run copy:assets && concurrently \"npm run build:main:watch\" \"npm run build:webview:watch\" \"npm run dev:renderer\" \"npm run start\"", + "dev": "npm run copy:assets && npm run build:scripts && concurrently \"npm run build:main:watch\" \"npm run build:webview:watch\" \"npm run dev:renderer\" \"npm run start\"", "dev:renderer": "vite", - "build": "npm run copy:assets && npm run build:main && npm run build:webview && npm run build:renderer", + "build": "npm run copy:assets && npm run build:scripts && npm run build:main && npm run build:webview && npm run build:renderer", + "build:scripts": "tsc --project tsconfig.scripts.json", "build:main": "tsc", "build:webview": "tsc --project tsconfig.webview.json", "build:webview:watch": "tsc --project tsconfig.webview.json --watch", diff --git a/apps/browser/scripts/before-sign.js b/apps/browser/scripts-src/before-sign.ts old mode 100755 new mode 100644 similarity index 67% rename from apps/browser/scripts/before-sign.js rename to apps/browser/scripts-src/before-sign.ts index fd52eb2..72fb9d5 --- a/apps/browser/scripts/before-sign.js +++ b/apps/browser/scripts-src/before-sign.ts @@ -5,15 +5,30 @@ * This runs BEFORE electron-builder's codesign */ -const { execSync } = require('child_process'); -const path = require('path'); -const os = require('os'); -const fs = require('fs'); +import { execSync } from 'child_process'; +import * as path from 'path'; +import * as os from 'os'; +import * as fs from 'fs'; + +interface EVSConfig { + account_name?: string; + Auth?: { + AccountName?: string; + }; + Account?: { + AccountName?: string; + }; +} + +interface BuildContext { + electronPlatformName: string; + appOutDir: string; +} /** * Verify EVS environment */ -function verifyEnvironment() { +function verifyEnvironment(): boolean { const configPath = path.join(os.homedir(), '.config', 'evs', 'config.json'); if (!fs.existsSync(configPath)) { @@ -22,14 +37,16 @@ function verifyEnvironment() { } try { - const config = JSON.parse(fs.readFileSync(configPath, 'utf8')); - const accountName = config.account_name || (config.Auth && config.Auth.AccountName) || (config.Account && config.Account.AccountName); + const configContent = fs.readFileSync(configPath, 'utf8'); + const config: EVSConfig = JSON.parse(configContent); + const accountName = config.account_name || config.Auth?.AccountName || config.Account?.AccountName; if (accountName) { console.log('[EVS] ✓ EVS account configured:', accountName); return true; } } catch (error) { - console.error('[EVS] ✗ Failed to read EVS config:', error.message); + const errorMessage = error instanceof Error ? error.message : String(error); + console.error('[EVS] ✗ Failed to read EVS config:', errorMessage); return false; } @@ -39,7 +56,7 @@ function verifyEnvironment() { /** * Sign with EVS VMP */ -function signWithEVS(appPath) { +function signWithEVS(appPath: string): boolean { console.log('[EVS] Signing with VMP before Apple codesign...'); console.log('[EVS] App path:', appPath); @@ -54,7 +71,8 @@ function signWithEVS(appPath) { console.log('[EVS] ✓ VMP signing completed successfully\n'); return true; } catch (error) { - console.error('[EVS] ✗ VMP signing failed:', error.message); + const errorMessage = error instanceof Error ? error.message : String(error); + console.error('[EVS] ✗ VMP signing failed:', errorMessage); return false; } } @@ -62,7 +80,7 @@ function signWithEVS(appPath) { /** * beforeSign hook for electron-builder */ -exports.default = async function(context) { +export default async function(context: BuildContext): Promise { const { electronPlatformName, appOutDir } = context; console.log('\n[EVS] beforeSign hook triggered'); @@ -82,7 +100,7 @@ exports.default = async function(context) { } // Determine app path - let appPath; + let appPath: string; if (electronPlatformName === 'darwin') { // Find .app bundle const files = fs.readdirSync(appOutDir); @@ -102,4 +120,4 @@ exports.default = async function(context) { if (!success) { console.warn('[EVS] ⚠ VMP signing failed, but continuing with Apple codesign...'); } -}; +} diff --git a/apps/browser/scripts/download-widevine.js b/apps/browser/scripts-src/download-widevine.ts similarity index 73% rename from apps/browser/scripts/download-widevine.js rename to apps/browser/scripts-src/download-widevine.ts index 378a6c9..0c37e5c 100644 --- a/apps/browser/scripts/download-widevine.js +++ b/apps/browser/scripts-src/download-widevine.ts @@ -7,29 +7,42 @@ * This script manually downloads the Widevine CDM component. */ -const { execSync } = require('child_process'); -const fs = require('fs'); -const path = require('path'); -const https = require('https'); +import * as path from 'path'; + +interface PackageJson { + devDependencies: { + electron: string; + [key: string]: string; + }; +} console.log('[Widevine] Starting Widevine CDM download...\n'); // Get Electron version -const packageJson = require('../package.json'); -const electronVersion = packageJson.devDependencies.electron.match(/v?(\d+\.\d+\.\d+)/)[1]; +const packageJsonPath = path.join(__dirname, '..', 'package.json'); +const packageJson: PackageJson = require(packageJsonPath); +const electronVersionMatch = packageJson.devDependencies.electron.match(/v?(\d+\.\d+\.\d+)/); + +if (!electronVersionMatch) { + console.error('[Widevine] ✗ Could not parse Electron version'); + process.exit(1); +} + +const electronVersion = electronVersionMatch[1]; console.log(`[Widevine] Electron version: ${electronVersion}`); console.log(`[Widevine] Platform: ${process.platform}`); console.log(`[Widevine] Arch: ${process.arch}\n`); // Widevine CDM download URLs (from Chrome) -const WIDEVINE_VERSIONS = { +const WIDEVINE_VERSIONS: Record = { '38.0.0': '4.10.2710.0', '37.0.0': '4.10.2710.0', '36.0.0': '4.10.2710.0' }; -const widevineVersion = WIDEVINE_VERSIONS[electronVersion.split('.').slice(0, 2).join('.')] || '4.10.2710.0'; +const majorMinorVersion = electronVersion.split('.').slice(0, 2).join('.'); +const widevineVersion = WIDEVINE_VERSIONS[majorMinorVersion] || '4.10.2710.0'; console.log(`[Widevine] Widevine CDM version: ${widevineVersion}\n`); diff --git a/apps/browser/scripts/evs-sign.js b/apps/browser/scripts-src/evs-sign.ts similarity index 84% rename from apps/browser/scripts/evs-sign.js rename to apps/browser/scripts-src/evs-sign.ts index a59d05d..b0cf755 100644 --- a/apps/browser/scripts/evs-sign.js +++ b/apps/browser/scripts-src/evs-sign.ts @@ -7,17 +7,32 @@ * 2. Signs the application with Widevine VMP signature after packaging */ -const { execSync, spawnSync } = require('child_process'); -const fs = require('fs'); -const path = require('path'); -const os = require('os'); +import { execSync, spawnSync, SpawnSyncReturns } from 'child_process'; +import * as fs from 'fs'; +import * as path from 'path'; +import * as os from 'os'; + +interface EVSConfig { + account_name?: string; + Auth?: { + AccountName?: string; + }; + Account?: { + AccountName?: string; + }; +} + +interface BuildContext { + electronPlatformName: string; + appOutDir: string; +} /** * Check if Python 3 is available */ -function checkPython() { +function checkPython(): boolean { try { - const result = spawnSync('python3', ['--version'], { encoding: 'utf8' }); + const result: SpawnSyncReturns = spawnSync('python3', ['--version'], { encoding: 'utf8' }); if (result.status === 0) { console.log('[EVS] Python 3 found:', result.stdout.trim()); return true; @@ -32,9 +47,9 @@ function checkPython() { /** * Check if castlabs-evs is installed */ -function checkEvsInstalled() { +function checkEvsInstalled(): boolean { try { - const result = spawnSync('python3', ['-m', 'pip', 'show', 'castlabs-evs'], { encoding: 'utf8' }); + const result: SpawnSyncReturns = spawnSync('python3', ['-m', 'pip', 'show', 'castlabs-evs'], { encoding: 'utf8' }); if (result.status === 0 && result.stdout.includes('Name: castlabs-evs')) { const versionMatch = result.stdout.match(/Version: ([\d.]+)/); const version = versionMatch ? versionMatch[1] : 'unknown'; @@ -51,7 +66,7 @@ function checkEvsInstalled() { /** * Check if EVS account is configured */ -function checkEvsAccount() { +function checkEvsAccount(): boolean { const configPath = path.join(os.homedir(), '.config', 'evs', 'config.json'); if (!fs.existsSync(configPath)) { @@ -60,15 +75,17 @@ function checkEvsAccount() { } try { - const config = JSON.parse(fs.readFileSync(configPath, 'utf8')); + const configContent = fs.readFileSync(configPath, 'utf8'); + const config: EVSConfig = JSON.parse(configContent); // Check for both formats: account_name (old) and Auth.AccountName (new) - const accountName = config.account_name || (config.Auth && config.Auth.AccountName) || (config.Account && config.Account.AccountName); + const accountName = config.account_name || config.Auth?.AccountName || config.Account?.AccountName; if (accountName) { console.log('[EVS] ✓ EVS account configured:', accountName); return true; } } catch (error) { - console.error('[EVS] ✗ Failed to read EVS config:', error.message); + const errorMessage = error instanceof Error ? error.message : String(error); + console.error('[EVS] ✗ Failed to read EVS config:', errorMessage); return false; } @@ -79,7 +96,7 @@ function checkEvsAccount() { /** * Print setup instructions */ -function printSetupInstructions() { +function printSetupInstructions(): void { console.error('\n[EVS] Setup Instructions:'); console.error('[EVS] =========================================='); console.error('[EVS] '); @@ -101,7 +118,7 @@ function printSetupInstructions() { /** * Verify EVS environment setup */ -function verifyEnvironment() { +function verifyEnvironment(): boolean { console.log('\n[EVS] Verifying EVS environment...'); console.log('[EVS] =========================================='); @@ -124,12 +141,12 @@ function verifyEnvironment() { /** * Copy Widevine CDM to app bundle */ -function copyWidevineCdm(appOutDir, electronPlatformName) { +function copyWidevineCdm(appOutDir: string, electronPlatformName: string): boolean { console.log('[Widevine] Copying Widevine CDM to app bundle...'); // Determine source path based on platform - let widevineSrcPath; - let widevineDestPath; + let widevineSrcPath: string | undefined; + let widevineDestPath: string; if (electronPlatformName === 'darwin') { // macOS: Check multiple possible locations @@ -211,7 +228,8 @@ function copyWidevineCdm(appOutDir, electronPlatformName) { return false; } } catch (error) { - console.error('[Widevine] ✗ Failed to copy Widevine CDM:', error.message); + const errorMessage = error instanceof Error ? error.message : String(error); + console.error('[Widevine] ✗ Failed to copy Widevine CDM:', errorMessage); return false; } } else if (electronPlatformName === 'win32') { @@ -226,7 +244,7 @@ function copyWidevineCdm(appOutDir, electronPlatformName) { /** * Sign the application package */ -function signPackage(appOutDir, persistent = false) { +function signPackage(appOutDir: string, persistent: boolean = false): boolean { const persistentFlag = persistent ? '--persistent' : ''; const command = `python3 -m castlabs_evs.vmp sign-pkg ${persistentFlag} "${appOutDir}"`; @@ -241,7 +259,8 @@ function signPackage(appOutDir, persistent = false) { console.log('[EVS] VMP signing completed successfully\n'); return true; } catch (error) { - console.error('[EVS] VMP signing failed:', error.message); + const errorMessage = error instanceof Error ? error.message : String(error); + console.error('[EVS] VMP signing failed:', errorMessage); return false; } } @@ -249,7 +268,7 @@ function signPackage(appOutDir, persistent = false) { /** * Main electron-builder hook */ -exports.default = async function(context) { +export default async function(context: BuildContext): Promise { const { electronPlatformName, appOutDir } = context; console.log('\n[EVS] Starting post-pack process...'); @@ -280,7 +299,7 @@ exports.default = async function(context) { // castlabs v16+ uses Component Updater to automatically download and install CDM // Manual bundling is not recommended and has legal implications console.log('\n[EVS] Widevine CDM will be downloaded automatically by Component Updater on first run'); -}; +} // Allow running this script directly for verification if (require.main === module) { diff --git a/apps/browser/tsconfig.scripts.json b/apps/browser/tsconfig.scripts.json new file mode 100644 index 0000000..ea6618c --- /dev/null +++ b/apps/browser/tsconfig.scripts.json @@ -0,0 +1,17 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "module": "CommonJS", + "target": "ES2020", + "moduleResolution": "node", + "outDir": "./scripts", + "rootDir": "./scripts-src", + "esModuleInterop": true, + "skipLibCheck": true, + "strict": true, + "resolveJsonModule": true, + "types": ["node"] + }, + "include": ["scripts-src/**/*"], + "exclude": ["node_modules", "dist", "dist-renderer", "release"] +}