@stacksjs/defaults 0.75.310 → 0.75.311
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Shared Chrome executable preparation for the standalone skill and testing package.
|
|
2
|
-
import { existsSync, mkdirSync, mkdtempSync, renameSync, rmSync } from 'node:fs'
|
|
2
|
+
import { existsSync, mkdirSync, mkdtempSync, readdirSync, renameSync, rmSync } from 'node:fs'
|
|
3
3
|
import { tmpdir } from 'node:os'
|
|
4
|
-
import { join } from 'node:path'
|
|
4
|
+
import { basename, join } from 'node:path'
|
|
5
5
|
import process from 'node:process'
|
|
6
6
|
|
|
7
7
|
const MAC_CHROMES = [
|
|
@@ -56,12 +56,33 @@ export interface PreparedChrome {
|
|
|
56
56
|
reused: boolean
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
/** Postorder, without following symlinks: nested frameworks must be sealed before their parents. */
|
|
60
|
+
function frameworkVersions(directory: string): { path: string, identifier: string }[] {
|
|
61
|
+
const result: { path: string, identifier: string }[] = []
|
|
62
|
+
for (const entry of readdirSync(directory, { withFileTypes: true })) {
|
|
63
|
+
if (!entry.isDirectory()) continue
|
|
64
|
+
const child = join(directory, entry.name)
|
|
65
|
+
result.push(...frameworkVersions(child))
|
|
66
|
+
if (!entry.name.endsWith('.framework') || !existsSync(join(child, 'Versions'))) continue
|
|
67
|
+
const identifier = plist(join(child, 'Resources/Info.plist'), 'Print :CFBundleIdentifier')
|
|
68
|
+
if (!identifier.ok || !identifier.out) throw new Error(`Framework has no signing identifier: ${child}`)
|
|
69
|
+
for (const version of readdirSync(join(child, 'Versions'), { withFileTypes: true }).filter(item => item.isDirectory()).sort((a, b) => a.name.localeCompare(b.name)))
|
|
70
|
+
result.push({ path: join(child, 'Versions', version.name), identifier: identifier.out })
|
|
71
|
+
}
|
|
72
|
+
return result
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function validSignature(app: string): boolean {
|
|
76
|
+
return Bun.spawnSync(['codesign', '--verify', '--deep', '--strict', app], { stdout: 'pipe', stderr: 'pipe' }).exitCode === 0
|
|
77
|
+
}
|
|
78
|
+
|
|
59
79
|
/**
|
|
60
80
|
* A private clone of a macOS Chrome that GoogleUpdater leaves alone (see the
|
|
61
81
|
* module docs): `cp -cR`, the `KS*` keys deleted from `Info.plist`, its own
|
|
62
|
-
* `CFBundleIdentifier`,
|
|
63
|
-
*
|
|
64
|
-
*
|
|
82
|
+
* `CFBundleIdentifier`, and a complete ad-hoc signature. Every framework
|
|
83
|
+
* version shares an explicit designated requirement, as required for a
|
|
84
|
+
* multi-version bundle (Apple TN2206). Kept in `directory` (default a
|
|
85
|
+
* per-version temp folder) and reused only after strict signature validation.
|
|
65
86
|
*/
|
|
66
87
|
export function prepareMacChrome(options: { source?: string, directory?: string } = {}): PreparedChrome {
|
|
67
88
|
if (process.platform !== 'darwin') throw new Error('prepareMacChrome is for macOS; elsewhere launch Chrome as installed')
|
|
@@ -73,12 +94,15 @@ export function prepareMacChrome(options: { source?: string, directory?: string
|
|
|
73
94
|
const executableName = plist(sourceInfo, 'Print :CFBundleExecutable').out || 'Google Chrome'
|
|
74
95
|
const directory = options.directory ?? join(tmpdir(), `stacks-chrome-${version.replace(/[^\w.-]/g, '_')}`)
|
|
75
96
|
const app = join(directory, 'Chrome.app')
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
97
|
+
const candidates = existsSync(directory) ? readdirSync(directory, { withFileTypes: true })
|
|
98
|
+
.filter(entry => entry.isDirectory() && (entry.name === 'Chrome.app' || (entry.name.startsWith('Chrome-') && entry.name.endsWith('.app'))))
|
|
99
|
+
.map(entry => join(directory, entry.name)).sort() : []
|
|
100
|
+
for (const candidate of candidates) {
|
|
101
|
+
const executable = join(candidate, 'Contents/MacOS', executableName), info = join(candidate, 'Contents/Info.plist')
|
|
102
|
+
if (existsSync(executable) && plist(info, 'Print :CFBundleIdentifier').out === PRIVATE_BUNDLE_ID
|
|
103
|
+
&& plist(info, 'Print :CFBundleShortVersionString').out === version && validSignature(candidate))
|
|
104
|
+
return { executable, app: candidate, reused: true }
|
|
105
|
+
}
|
|
82
106
|
|
|
83
107
|
// Build beside the final path and move it in, so a run killed half-way
|
|
84
108
|
// never leaves a half-signed app that a later run would reuse.
|
|
@@ -94,13 +118,26 @@ export function prepareMacChrome(options: { source?: string, directory?: string
|
|
|
94
118
|
const stagedInfo = join(staged, 'Contents/Info.plist')
|
|
95
119
|
for (const key of UPDATER_KEYS) plist(stagedInfo, `Delete :${key}`)
|
|
96
120
|
run(['/usr/libexec/PlistBuddy', '-c', `Set :CFBundleIdentifier ${PRIVATE_BUNDLE_ID}`, stagedInfo], 'Renaming the Chrome bundle')
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
121
|
+
const versions = frameworkVersions(staged)
|
|
122
|
+
// --deep only signs the current framework version. Prepare the code in
|
|
123
|
+
// every version first, then seal nested frameworks and their parents.
|
|
124
|
+
for (const item of versions) run(['codesign', '--force', '--deep', '--sign', '-', item.path], 'Re-signing framework code')
|
|
125
|
+
for (const item of versions) run(['codesign', '--force', '--sign', '-', '--requirements', `=designated => identifier ${JSON.stringify(item.identifier)}`, item.path], 'Sealing a framework version')
|
|
126
|
+
run(['codesign', '--force', ...(versions.length ? [] : ['--deep']), '--sign', '-', staged], 'Sealing Chrome')
|
|
127
|
+
run(['codesign', '--verify', '--deep', '--strict', staged], 'Verifying Chrome')
|
|
128
|
+
// Never remove a cached bundle that another browser process may still be
|
|
129
|
+
// using. An invalid cache, or a concurrent preparation, gets a new generation.
|
|
130
|
+
let destination = existsSync(app) ? join(directory, `Chrome-${basename(staging)}.app`) : app
|
|
131
|
+
try { renameSync(staged, destination) }
|
|
132
|
+
catch (error) {
|
|
133
|
+
if (destination !== app || !['EEXIST', 'ENOTEMPTY'].includes((error as NodeJS.ErrnoException).code ?? '')) throw error
|
|
134
|
+
destination = join(directory, `Chrome-${basename(staging)}.app`)
|
|
135
|
+
renameSync(staged, destination)
|
|
136
|
+
}
|
|
137
|
+
return { executable: join(destination, 'Contents/MacOS', executableName), app: destination, reused: false }
|
|
100
138
|
}
|
|
101
139
|
finally {
|
|
102
140
|
rmSync(staging, { recursive: true, force: true })
|
|
103
141
|
}
|
|
104
|
-
return { executable, app, reused: false }
|
|
105
142
|
}
|
|
106
143
|
|
package/ide/vscode/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"publisher": "Stacks",
|
|
3
3
|
"name": "vscode-stacks",
|
|
4
4
|
"displayName": "Stacks",
|
|
5
|
-
"version": "0.75.
|
|
5
|
+
"version": "0.75.311",
|
|
6
6
|
"description": "Stacks, built into VS Code: stx templates, pickier linting and formatting, encrypted env files, the dev server preview and every buddy command. No other extensions required.",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"funding": "https://github.com/sponsors/chrisbbreuer",
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@stacksjs/defaults",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"sideEffects": false,
|
|
5
|
-
"version": "0.75.
|
|
5
|
+
"version": "0.75.311",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
8
|
"url": "git+https://github.com/stacksjs/stacks.git",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"dependencies": {
|
|
46
46
|
"@iconify-json/f7": "^1.2.2",
|
|
47
47
|
"@iconify-json/hugeicons": "^1.2.35",
|
|
48
|
-
"@stacksjs/mobile": "0.75.
|
|
48
|
+
"@stacksjs/mobile": "0.75.311",
|
|
49
49
|
"@stacksjs/sanitizer": "0.2.691",
|
|
50
50
|
"@stacksjs/stx": "0.2.691",
|
|
51
51
|
"@xterm/addon-fit": "^0.11.0",
|