mirror of
https://github.com/ThatGuySam/doesitarm.git
synced 2026-05-15 06:35:20 -07:00
Move the worker scanner surface into TypeScript, add a direct worker regression, and make the version=2 app-test path populate the same visible result data and final status as the legacy scanner. This keeps the refactor bounded while making the worker route safe to exercise. Constraint: Must preserve the existing Apple Silicon app-test behavior while changing the worker internals Rejected: Flip production to the worker path immediately | still needs the normal deploy path and broader production soak Confidence: medium Scope-risk: moderate Reversibility: clean Directive: Keep the version=2 adapter using the shared finishFileScan path until the legacy scanner can be removed entirely Tested: pnpm run typecheck; pnpm exec vitest run test/scanner/client.test.ts; pnpm run test:browser (original workspace); netlify build --context deploy-preview (original workspace) Not-tested: Browser suite from the clean clone environment (local Astro dev server startup timed out there)
76 lines
3.2 KiB
TypeScript
76 lines
3.2 KiB
TypeScript
import { mkdtemp, mkdir, readFile, rm, writeFile } from 'node:fs/promises'
|
|
import { tmpdir } from 'node:os'
|
|
import { join } from 'node:path'
|
|
|
|
import { Zip } from 'zip-lib'
|
|
|
|
const machoObjectBase64 =
|
|
'z/rt/gwAAAEAAAAAAQAAAAQAAABoAQAAACAAAAAAAAAZAAAA6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgAAAAAAAAAiAEAAAAAAAA4AAAAAAAAAAcAAAAHAAAAAgAAAAAAAABfX3RleHQAAAAAAAAAAAAAX19URVhUAAAAAAAAAAAAAAAAAAAAAAAAFAAAAAAAAACIAQAAAgAAAAAAAAAAAAAAAAQAgAAAAAAAAAAAAAAAAF9fY29tcGFjdF91bndpbmRfX0xEAAAAAAAAAAAAAAAAGAAAAAAAAAAgAAAAAAAAAKABAAADAAAAwAEAAAEAAAAAAAACAAAAAAAAAAAAAAAAMgAAABgAAAABAAAAAAALAAACGgAAAAAAAgAAABgAAADIAQAAAwAAAPgBAAAYAAAACwAAAFAAAAAAAAAAAgAAAAIAAAABAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/QwDRAACAUv8PALn/QwCRwANf1gAAAAAAAAAAAAAAABQAAAAAEAACAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAGDQAAAA4BAAAAAAAAAAAAAAcAAAAOAgAAGAAAAAAAAAABAAAADwEAAAAAAAAAAAAAAF9tYWluAGx0bXAxAGx0bXAwAAAAAAAA'
|
|
|
|
export interface PlaywrightUploadFile {
|
|
arrayBuffer: ArrayBuffer
|
|
buffer: Buffer
|
|
mimeType: string
|
|
name: string
|
|
type: string
|
|
}
|
|
|
|
function makeInfoPlist ( appName: string ) {
|
|
return [
|
|
'<?xml version="1.0" encoding="UTF-8"?>',
|
|
'<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">',
|
|
'<plist version="1.0">',
|
|
'<dict>',
|
|
' <key>CFBundleDisplayName</key>',
|
|
` <string>${ appName }</string>`,
|
|
' <key>CFBundleExecutable</key>',
|
|
` <string>${ appName }</string>`,
|
|
' <key>CFBundleIdentifier</key>',
|
|
` <string>com.doesitarm.${ appName.toLowerCase().replaceAll( ' ', '-' ) }</string>`,
|
|
' <key>CFBundleName</key>',
|
|
` <string>${ appName }</string>`,
|
|
' <key>CFBundleShortVersionString</key>',
|
|
' <string>1.0.0</string>',
|
|
'</dict>',
|
|
'</plist>',
|
|
''
|
|
].join( '\n' )
|
|
}
|
|
|
|
export async function createNativeAppArchive ( appName = 'Playwright Native App' ): Promise<PlaywrightUploadFile> {
|
|
const tempRoot = await mkdtemp( join( tmpdir(), 'doesitarm-playwright-' ) )
|
|
const appBundlePath = join( tempRoot, `${ appName }.app` )
|
|
const contentsPath = join( appBundlePath, 'Contents' )
|
|
const executablePath = join( contentsPath, 'MacOS', appName )
|
|
const archivePath = join( tempRoot, `${ appName }.app.zip` )
|
|
|
|
try {
|
|
const executableBytes = new Uint8Array( Buffer.from( machoObjectBase64, 'base64' ) )
|
|
|
|
await mkdir( join( contentsPath, 'MacOS' ), { recursive: true } )
|
|
await writeFile( join( contentsPath, 'Info.plist' ), makeInfoPlist( appName ) )
|
|
await writeFile( executablePath, executableBytes, { mode: 0o755 } )
|
|
|
|
const zip = new Zip()
|
|
|
|
zip.addFolder( appBundlePath, `${ appName }.app` )
|
|
await zip.archive( archivePath )
|
|
|
|
const archiveBuffer = await readFile( archivePath )
|
|
|
|
const archiveArrayBuffer = new Uint8Array( archiveBuffer ).slice().buffer
|
|
|
|
return {
|
|
arrayBuffer: archiveArrayBuffer,
|
|
buffer: archiveBuffer,
|
|
mimeType: 'application/zip',
|
|
name: `${ appName }.app.zip`,
|
|
type: 'application/zip'
|
|
}
|
|
} finally {
|
|
await rm( tempRoot, {
|
|
force: true,
|
|
recursive: true
|
|
} )
|
|
}
|
|
}
|