mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-04-25 08:26:22 +02:00
add codesigning to gh action
This commit is contained in:
parent
7387d3c1c9
commit
fe77a7a419
4 changed files with 159 additions and 96 deletions
42
.github/workflows/electron-build.yml
vendored
42
.github/workflows/electron-build.yml
vendored
|
|
@ -53,11 +53,45 @@ jobs:
|
||||||
console.log('Updated version to:', version);
|
console.log('Updated version to:', version);
|
||||||
"
|
"
|
||||||
|
|
||||||
|
- name: Import Code Signing Certificate
|
||||||
|
env:
|
||||||
|
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
|
||||||
|
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
||||||
|
run: |
|
||||||
|
# Create a temporary keychain
|
||||||
|
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
|
||||||
|
KEYCHAIN_PASSWORD=$(openssl rand -base64 32)
|
||||||
|
|
||||||
|
# Create keychain
|
||||||
|
security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
|
||||||
|
security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH"
|
||||||
|
security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
|
||||||
|
|
||||||
|
# Decode and import certificate
|
||||||
|
echo "$APPLE_CERTIFICATE" | base64 --decode > $RUNNER_TEMP/certificate.p12
|
||||||
|
security import $RUNNER_TEMP/certificate.p12 -P "$APPLE_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k "$KEYCHAIN_PATH"
|
||||||
|
|
||||||
|
# Allow codesign to access the keychain
|
||||||
|
security set-key-partition-list -S apple-tool:,apple: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
|
||||||
|
|
||||||
|
# Add keychain to search list
|
||||||
|
security list-keychain -d user -s "$KEYCHAIN_PATH" login.keychain
|
||||||
|
|
||||||
|
# Verify certificate was imported
|
||||||
|
security find-identity -v "$KEYCHAIN_PATH"
|
||||||
|
|
||||||
|
# Clean up certificate file
|
||||||
|
rm -f $RUNNER_TEMP/certificate.p12
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: pnpm install --frozen-lockfile
|
run: pnpm install --frozen-lockfile
|
||||||
working-directory: apps/x
|
working-directory: apps/x
|
||||||
|
|
||||||
- name: Build distributables
|
- name: Build distributables
|
||||||
|
env:
|
||||||
|
APPLE_ID: ${{ secrets.APPLE_ID }}
|
||||||
|
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
|
||||||
|
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
||||||
run: npm run make
|
run: npm run make
|
||||||
working-directory: apps/x/apps/main
|
working-directory: apps/x/apps/main
|
||||||
|
|
||||||
|
|
@ -109,3 +143,11 @@ jobs:
|
||||||
files: apps/x/apps/main/out/make/*
|
files: apps/x/apps/main/out/make/*
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Cleanup keychain
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
|
||||||
|
if [ -f "$KEYCHAIN_PATH" ]; then
|
||||||
|
security delete-keychain "$KEYCHAIN_PATH" || true
|
||||||
|
fi
|
||||||
|
|
|
||||||
|
|
@ -39,16 +39,20 @@ Prepares all build artifacts in a hidden `.package/` staging directory:
|
||||||
- Copies preload/renderer dist to `.package/`
|
- Copies preload/renderer dist to `.package/`
|
||||||
|
|
||||||
### 2. `packageAfterCopy` Hook (Post-copy)
|
### 2. `packageAfterCopy` Hook (Post-copy)
|
||||||
After Forge copies source to output, this hook fixes it:
|
After Forge copies source to output, this hook replaces source files with bundled/staged files:
|
||||||
- Removes unbundled `dist/` (has unresolvable `@x/core` imports)
|
- **Hook signature**: `async (config, buildPath, electronVersion, platform, arch)`
|
||||||
- Copies bundled `dist-bundle/`, `preload/`, `renderer/` from staging
|
- `buildPath` already points to `Contents/Resources/app` (not the `.app` bundle root)
|
||||||
|
- Removes unbundled `dist/` directory (has unresolvable `@x/core` imports)
|
||||||
|
- Copies bundled `dist-bundle/` from `.package/` staging directory
|
||||||
|
- Copies `preload/` and `renderer/` directories from staging
|
||||||
- Updates `package.json`: sets `main` to `dist-bundle/main.js`, removes
|
- Updates `package.json`: sets `main` to `dist-bundle/main.js`, removes
|
||||||
`"type": "module"` (since we bundle as CJS), removes dependencies
|
`"type": "module"` (since we bundle as CJS), removes all dependencies/devDependencies
|
||||||
- Cleans up source files (tsconfig.json, src/, etc.)
|
- Cleans up source files (src/, tsconfig.json, forge.config.cjs, agents.md, .gitignore, bundle.mjs)
|
||||||
|
|
||||||
**Why this approach?** Electron Forge ignores `packagerConfig.dir` and always
|
**Why this approach?** Electron Forge ignores `packagerConfig.dir` and always
|
||||||
packages from the config file's directory. The `packageAfterCopy` hook is the
|
packages from the config file's directory. The `packageAfterCopy` hook is the
|
||||||
reliable way to customize the packaged output.
|
reliable way to customize the packaged output by modifying files after Forge
|
||||||
|
copies the source directory but before the app bundle is finalized.
|
||||||
|
|
||||||
## Staged Build Directory (`.package/`)
|
## Staged Build Directory (`.package/`)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,15 @@ module.exports = {
|
||||||
icon: './icons/icon', // .icns extension added automatically
|
icon: './icons/icon', // .icns extension added automatically
|
||||||
appBundleId: 'com.rowboat.app',
|
appBundleId: 'com.rowboat.app',
|
||||||
appCategoryType: 'public.app-category.productivity',
|
appCategoryType: 'public.app-category.productivity',
|
||||||
|
osxSign: {},
|
||||||
|
osxNotarize: {
|
||||||
|
appleId: process.env.APPLE_ID,
|
||||||
|
appleIdPassword: process.env.APPLE_PASSWORD,
|
||||||
|
teamId: process.env.APPLE_TEAM_ID
|
||||||
|
},
|
||||||
|
// NOTE: Electron Forge ignores packagerConfig.dir and always packages from the
|
||||||
|
// config file's directory. We use packageAfterCopy hook instead to customize output.
|
||||||
|
// dir: path.join(__dirname, '.package'), // Not supported by Forge
|
||||||
// Since we bundle everything with esbuild, we don't need node_modules at all.
|
// Since we bundle everything with esbuild, we don't need node_modules at all.
|
||||||
// These settings prevent Forge's dependency walker (flora-colossus) from trying
|
// These settings prevent Forge's dependency walker (flora-colossus) from trying
|
||||||
// to analyze/copy node_modules, which fails with pnpm's symlinked workspaces.
|
// to analyze/copy node_modules, which fails with pnpm's symlinked workspaces.
|
||||||
|
|
@ -141,113 +150,82 @@ module.exports = {
|
||||||
|
|
||||||
console.log('✅ All assets staged in .package/');
|
console.log('✅ All assets staged in .package/');
|
||||||
},
|
},
|
||||||
|
// Hook signature: async (config, buildPath, electronVersion, platform, arch)
|
||||||
// Hook runs after Forge copies source to output directory
|
// Called after Forge copies source directory to build output
|
||||||
// We use this to replace the unbundled code with our bundled version
|
// This is where we replace source files with bundled/staged files
|
||||||
// Hook signature: (forgeConfig, buildPath, electronVersion, platform, arch)
|
packageAfterCopy: async (config, buildPath, electronVersion, platform, arch) => {
|
||||||
packageAfterCopy: async (forgeConfig, buildPath, electronVersion, platform, arch) => {
|
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const packageDir = path.join(__dirname, '.package');
|
const packageDir = path.join(__dirname, '.package');
|
||||||
|
// buildPath already points to the app directory (Contents/Resources/app)
|
||||||
|
const appResourcesPath = buildPath;
|
||||||
|
|
||||||
// buildPath is the app directory inside the packaged output
|
console.log('📦 Copying staged files from .package/ to packaged app...');
|
||||||
// e.g., out/Rowboat-darwin-arm64/Rowboat.app/Contents/Resources/app
|
|
||||||
// App bundle root is 3 levels up: buildPath/../../.. = Rowboat.app
|
|
||||||
const appBundleRoot = path.resolve(buildPath, '../../..');
|
|
||||||
console.log('Fixing packaged app at:', buildPath);
|
|
||||||
console.log('App bundle root:', appBundleRoot);
|
|
||||||
|
|
||||||
|
// Remove unbundled dist/ directory (source TypeScript output)
|
||||||
// 1. Remove the unbundled dist/ directory (it has imports to @x/core, @x/shared)
|
const unbundledDist = path.join(appResourcesPath, 'dist');
|
||||||
const distDir = path.join(buildPath, 'dist');
|
if (fs.existsSync(unbundledDist)) {
|
||||||
if (fs.existsSync(distDir)) {
|
|
||||||
console.log('Removing unbundled dist/...');
|
console.log('Removing unbundled dist/...');
|
||||||
fs.rmSync(distDir, { recursive: true });
|
fs.rmSync(unbundledDist, { recursive: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Copy the bundled dist-bundle/ from staging
|
// Copy bundled dist-bundle/ from staging
|
||||||
console.log('Copying bundled dist-bundle/...');
|
const distBundleSrc = path.join(packageDir, 'dist-bundle');
|
||||||
const bundleSrc = path.join(packageDir, 'dist-bundle');
|
const distBundleDest = path.join(appResourcesPath, 'dist-bundle');
|
||||||
const bundleDest = path.join(buildPath, 'dist-bundle');
|
if (fs.existsSync(distBundleSrc)) {
|
||||||
fs.cpSync(bundleSrc, bundleDest, { recursive: true });
|
console.log('Copying dist-bundle/...');
|
||||||
|
fs.mkdirSync(distBundleDest, { recursive: true });
|
||||||
|
fs.cpSync(distBundleSrc, distBundleDest, { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
// 3. Copy preload from staging
|
// Copy preload/ from staging
|
||||||
console.log('Copying preload/...');
|
|
||||||
const preloadSrc = path.join(packageDir, 'preload');
|
const preloadSrc = path.join(packageDir, 'preload');
|
||||||
const preloadDest = path.join(buildPath, 'preload');
|
const preloadDest = path.join(appResourcesPath, 'preload');
|
||||||
|
if (fs.existsSync(preloadSrc)) {
|
||||||
|
console.log('Copying preload/...');
|
||||||
|
// Remove old preload if it exists
|
||||||
|
if (fs.existsSync(preloadDest)) {
|
||||||
|
fs.rmSync(preloadDest, { recursive: true });
|
||||||
|
}
|
||||||
fs.cpSync(preloadSrc, preloadDest, { recursive: true });
|
fs.cpSync(preloadSrc, preloadDest, { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
// 4. Copy renderer from staging
|
// Copy renderer/ from staging
|
||||||
console.log('Copying renderer/...');
|
|
||||||
const rendererSrc = path.join(packageDir, 'renderer');
|
const rendererSrc = path.join(packageDir, 'renderer');
|
||||||
const rendererDest = path.join(buildPath, 'renderer');
|
const rendererDest = path.join(appResourcesPath, 'renderer');
|
||||||
|
if (fs.existsSync(rendererSrc)) {
|
||||||
|
console.log('Copying renderer/...');
|
||||||
|
// Remove old renderer if it exists
|
||||||
|
if (fs.existsSync(rendererDest)) {
|
||||||
|
fs.rmSync(rendererDest, { recursive: true });
|
||||||
|
}
|
||||||
fs.cpSync(rendererSrc, rendererDest, { recursive: true });
|
fs.cpSync(rendererSrc, rendererDest, { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
// 5. Update package.json to point to bundled entry
|
// Update package.json to point to bundled entry point
|
||||||
|
const packageJsonPath = path.join(appResourcesPath, 'package.json');
|
||||||
|
if (fs.existsSync(packageJsonPath)) {
|
||||||
console.log('Updating package.json...');
|
console.log('Updating package.json...');
|
||||||
const packageJsonPath = path.join(buildPath, 'package.json');
|
const packageJson = {
|
||||||
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
name: '@x/main',
|
||||||
packageJson.main = 'dist-bundle/main.js';
|
version: '0.1.0',
|
||||||
// Remove workspace dependencies (they're bundled now)
|
main: 'dist-bundle/main.js',
|
||||||
delete packageJson.dependencies;
|
// Note: No "type": "module" since we bundle as CommonJS
|
||||||
delete packageJson.devDependencies;
|
// No dependencies/devDependencies since everything is bundled
|
||||||
delete packageJson.scripts;
|
};
|
||||||
// Remove "type": "module" - we bundle as CommonJS for compatibility
|
|
||||||
// with dependencies that use dynamic require()
|
|
||||||
delete packageJson.type;
|
|
||||||
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
||||||
|
}
|
||||||
|
|
||||||
// 6. Clean up source files that shouldn't be in production
|
// Clean up source files that shouldn't be in packaged app
|
||||||
const filesToRemove = ['tsconfig.json', 'forge.config.cjs', 'agents.md'];
|
const filesToRemove = ['src', 'tsconfig.json', 'forge.config.cjs', 'agents.md', '.gitignore', 'bundle.mjs'];
|
||||||
for (const file of filesToRemove) {
|
for (const file of filesToRemove) {
|
||||||
const filePath = path.join(buildPath, file);
|
const filePath = path.join(appResourcesPath, file);
|
||||||
if (fs.existsSync(filePath)) {
|
if (fs.existsSync(filePath)) {
|
||||||
fs.rmSync(filePath);
|
console.log(`Removing ${file}...`);
|
||||||
|
fs.rmSync(filePath, { recursive: true, force: true });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const srcDir = path.join(buildPath, 'src');
|
|
||||||
if (fs.existsSync(srcDir)) {
|
|
||||||
fs.rmSync(srcDir, { recursive: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
// 7. Remove any signature metadata AFTER all file modifications
|
console.log('✅ Staged files copied to packaged app');
|
||||||
// This prevents "code has no resources but signature indicates they must be present" error
|
|
||||||
// which occurs when _CodeSignature exists but files it references have been moved/modified
|
|
||||||
const codeSignatureDir = path.join(appBundleRoot, 'Contents', '_CodeSignature');
|
|
||||||
if (fs.existsSync(codeSignatureDir)) {
|
|
||||||
console.log('Removing _CodeSignature directory (files were modified after packaging)...');
|
|
||||||
fs.rmSync(codeSignatureDir, { recursive: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
// 8. Re-sign the app bundle with adhoc signature after file modifications
|
|
||||||
// The original bundle signature references resources that we've moved/modified
|
|
||||||
// Re-signing with adhoc signature creates a new signature that matches the current bundle structure
|
|
||||||
// This prevents "code has no resources but signature indicates they must be present" error
|
|
||||||
try {
|
|
||||||
const { execSync } = require('child_process');
|
|
||||||
|
|
||||||
// Re-sign the entire app bundle with an adhoc signature
|
|
||||||
// This creates a fresh signature that matches the modified bundle structure
|
|
||||||
execSync(`codesign --force --deep --sign - "${appBundleRoot}"`, { stdio: 'ignore' });
|
|
||||||
console.log('Re-signed app bundle with adhoc signature (matches modified structure)');
|
|
||||||
} catch (e) {
|
|
||||||
// Ignore errors - codesign might fail, but app should still work
|
|
||||||
console.log('Warning: Failed to re-sign app bundle:', e.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 9. Clear any signature-related extended attributes
|
|
||||||
// Even without _CodeSignature or embedded signatures, extended attributes can contain invalid signature metadata
|
|
||||||
// This prevents "code has no resources but signature indicates they must be present" error
|
|
||||||
try {
|
|
||||||
const { execSync } = require('child_process');
|
|
||||||
// Clear extended attributes from the entire app bundle
|
|
||||||
// This removes any signature metadata that might be stored in xattrs
|
|
||||||
execSync(`xattr -cr "${appBundleRoot}"`, { stdio: 'ignore' });
|
|
||||||
console.log('Cleared extended attributes from app bundle');
|
|
||||||
} catch (e) {
|
|
||||||
// Ignore errors - xattr might not be available or might fail silently
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('✅ Packaged app fixed with bundled code');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -3,6 +3,7 @@ import path from "node:path";
|
||||||
import { setupIpcHandlers, startRunsWatcher, startWorkspaceWatcher, stopWorkspaceWatcher } from "./ipc.js";
|
import { setupIpcHandlers, startRunsWatcher, startWorkspaceWatcher, stopWorkspaceWatcher } from "./ipc.js";
|
||||||
import { fileURLToPath, pathToFileURL } from "node:url";
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
||||||
import { dirname } from "node:path";
|
import { dirname } from "node:path";
|
||||||
|
import { existsSync } from "node:fs";
|
||||||
import { init as initGmailSync } from "@x/core/dist/knowledge/sync_gmail.js";
|
import { init as initGmailSync } from "@x/core/dist/knowledge/sync_gmail.js";
|
||||||
import { init as initCalendarSync } from "@x/core/dist/knowledge/sync_calendar.js";
|
import { init as initCalendarSync } from "@x/core/dist/knowledge/sync_calendar.js";
|
||||||
import { init as initFirefliesSync } from "@x/core/dist/knowledge/sync_fireflies.js";
|
import { init as initFirefliesSync } from "@x/core/dist/knowledge/sync_fireflies.js";
|
||||||
|
|
@ -13,6 +14,10 @@ import { init as initPreBuiltRunner } from "@x/core/dist/pre_built/runner.js";
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
const __dirname = dirname(__filename);
|
const __dirname = dirname(__filename);
|
||||||
|
|
||||||
|
// #region agent log
|
||||||
|
fetch('http://127.0.0.1:7242/ingest/dd33b297-24f6-4846-82f9-02599308a13a',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'main.ts:14',message:'__dirname resolved',data:{__dirname,__filename,isPackaged:app.isPackaged},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'B'})}).catch(()=>{});
|
||||||
|
// #endregion
|
||||||
|
|
||||||
// Path resolution differs between development and production:
|
// Path resolution differs between development and production:
|
||||||
// - Development: main.js runs from dist/, preload is at ../../preload/dist/ (sibling dir)
|
// - Development: main.js runs from dist/, preload is at ../../preload/dist/ (sibling dir)
|
||||||
// - Production: main.js runs from .package/dist-bundle/, preload is at ../preload/dist/ (copied into .package/)
|
// - Production: main.js runs from .package/dist-bundle/, preload is at ../preload/dist/ (copied into .package/)
|
||||||
|
|
@ -21,9 +26,17 @@ const preloadPath = app.isPackaged
|
||||||
: path.join(__dirname, "../../preload/dist/preload.js"); // Development
|
: path.join(__dirname, "../../preload/dist/preload.js"); // Development
|
||||||
console.log("preloadPath", preloadPath);
|
console.log("preloadPath", preloadPath);
|
||||||
|
|
||||||
|
// #region agent log
|
||||||
|
fetch('http://127.0.0.1:7242/ingest/dd33b297-24f6-4846-82f9-02599308a13a',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'main.ts:22',message:'preloadPath computed',data:{preloadPath,exists:existsSync(preloadPath)},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'B'})}).catch(()=>{});
|
||||||
|
// #endregion
|
||||||
|
|
||||||
// Register custom protocol for serving built renderer files in production
|
// Register custom protocol for serving built renderer files in production
|
||||||
function registerAppProtocol() {
|
function registerAppProtocol() {
|
||||||
protocol.handle('app', (request) => {
|
protocol.handle('app', (request) => {
|
||||||
|
// #region agent log
|
||||||
|
fetch('http://127.0.0.1:7242/ingest/dd33b297-24f6-4846-82f9-02599308a13a',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'main.ts:26',message:'protocol handler called',data:{url:request.url},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'C'})}).catch(()=>{});
|
||||||
|
// #endregion
|
||||||
|
|
||||||
// Remove 'app://' prefix and get the path
|
// Remove 'app://' prefix and get the path
|
||||||
let urlPath = request.url.slice('app://'.length);
|
let urlPath = request.url.slice('app://'.length);
|
||||||
|
|
||||||
|
|
@ -45,6 +58,10 @@ function registerAppProtocol() {
|
||||||
: path.join(__dirname, '../../renderer/dist');
|
: path.join(__dirname, '../../renderer/dist');
|
||||||
const filePath = path.join(rendererDistPath, urlPath);
|
const filePath = path.join(rendererDistPath, urlPath);
|
||||||
|
|
||||||
|
// #region agent log
|
||||||
|
fetch('http://127.0.0.1:7242/ingest/dd33b297-24f6-4846-82f9-02599308a13a',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'main.ts:46',message:'renderer path resolution',data:{rendererDistPath,filePath,urlPath,exists:existsSync(filePath),rendererDistExists:existsSync(rendererDistPath)},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'D'})}).catch(()=>{});
|
||||||
|
// #endregion
|
||||||
|
|
||||||
return net.fetch(pathToFileURL(filePath).toString());
|
return net.fetch(pathToFileURL(filePath).toString());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -62,9 +79,23 @@ function createWindow() {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// #region agent log
|
||||||
|
const loadURL = app.isPackaged ? 'app://./' : 'http://localhost:5173';
|
||||||
|
fetch('http://127.0.0.1:7242/ingest/dd33b297-24f6-4846-82f9-02599308a13a',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'main.ts:65',message:'createWindow called',data:{isPackaged:app.isPackaged,loadURL,preloadPath},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'E'})}).catch(()=>{});
|
||||||
|
// #endregion
|
||||||
|
|
||||||
if (app.isPackaged) {
|
if (app.isPackaged) {
|
||||||
// Production: load from custom protocol (serves built renderer files)
|
// Production: load from custom protocol (serves built renderer files)
|
||||||
win.loadURL('app://./');
|
win.loadURL('app://./');
|
||||||
|
|
||||||
|
// #region agent log
|
||||||
|
win.webContents.on('did-fail-load', (event, errorCode, errorDescription, validatedURL) => {
|
||||||
|
fetch('http://127.0.0.1:7242/ingest/dd33b297-24f6-4846-82f9-02599308a13a',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'main.ts:69',message:'window load failed',data:{errorCode,errorDescription,validatedURL},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'C'})}).catch(()=>{});
|
||||||
|
});
|
||||||
|
win.webContents.on('did-finish-load', () => {
|
||||||
|
fetch('http://127.0.0.1:7242/ingest/dd33b297-24f6-4846-82f9-02599308a13a',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'main.ts:72',message:'window load finished',data:{url:win.webContents.getURL()},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'C'})}).catch(()=>{});
|
||||||
|
});
|
||||||
|
// #endregion
|
||||||
} else {
|
} else {
|
||||||
// Development: load from Vite dev server
|
// Development: load from Vite dev server
|
||||||
win.loadURL('http://localhost:5173');
|
win.loadURL('http://localhost:5173');
|
||||||
|
|
@ -72,9 +103,17 @@ function createWindow() {
|
||||||
}
|
}
|
||||||
|
|
||||||
app.whenReady().then(() => {
|
app.whenReady().then(() => {
|
||||||
|
// #region agent log
|
||||||
|
fetch('http://127.0.0.1:7242/ingest/dd33b297-24f6-4846-82f9-02599308a13a',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'main.ts:74',message:'app.whenReady triggered',data:{isPackaged:app.isPackaged},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'A'})}).catch(()=>{});
|
||||||
|
// #endregion
|
||||||
|
|
||||||
// Register custom protocol before creating window (for production builds)
|
// Register custom protocol before creating window (for production builds)
|
||||||
registerAppProtocol();
|
registerAppProtocol();
|
||||||
|
|
||||||
|
// #region agent log
|
||||||
|
fetch('http://127.0.0.1:7242/ingest/dd33b297-24f6-4846-82f9-02599308a13a',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'main.ts:77',message:'protocol registered',data:{isPackaged:app.isPackaged},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'C'})}).catch(()=>{});
|
||||||
|
// #endregion
|
||||||
|
|
||||||
setupIpcHandlers();
|
setupIpcHandlers();
|
||||||
|
|
||||||
createWindow();
|
createWindow();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue