14 Commits

Author SHA1 Message Date
Mike Maietta
2b67c905a6 fix: Allow EnableEmbeddedAsarIntegrityValidation when multiple asars are present in app (#124)
- When an application uses multiple asars (`webapp.asar`, `anything.asar`, etc.), `EnableEmbeddedAsarIntegrityValidation` fuse breaks the application due to not all asars having integrity generated for them. Fixes: #116
- **Also fixes bug** to correctly test `makeUniversalApp no asar mode should shim two different app folders`, (it was not having an asar integrity generated for the shimmed asar)

Functionality added:
- Moves all asar integrity generation to **after** all app assets have been merged/shimmed/copied. This allows other asars that were provided to also be scanned and have asar integrity generated for them.
- Extracted common Integrity logic to a single file `integrity.ts`
- Adds unit test for multi-asar apps
2025-02-28 10:03:35 +08:00
Erik Moura
740dd4aab3 chore(deps): bump @electron/asar to 3.3.1 (#127)
* chore(deps): bump `@electron/asar` to `3.3.1`

* update snapshots
2025-02-22 18:35:55 -08:00
Mike Maietta
d90d573ccf test: add test should shim asars with different unpacked dirs (#125) 2025-02-21 16:21:20 -08:00
Mike Maietta
7c0ad6caa5 test: giving steroids to the test suite 💪 (#122)
* purely test suite on steroids

* verify stuff

* more fun verifies

* ok ok ok I'm done

* extend timeout and consolidate to constant for easier usage across tests

* PR feedback :)
Remove warnings by adding transform regex to `ts-jest` and `testMatch`.

* cleanup

* cleanup

* PR feedback & converting `export function` to `export const` in `util.ts`
2025-02-19 15:58:52 +08:00
dependabot[bot]
d76ca76072 build(deps): bump actions/setup-node from 4.1.0 to 4.2.0 (#118) 2025-02-01 16:16:44 +00:00
dependabot[bot]
4bf33415ec build(deps): bump dsanders11/project-actions from 1.4.0 to 1.5.1 (#119)
Bumps [dsanders11/project-actions](https://github.com/dsanders11/project-actions) from 1.4.0 to 1.5.1.
- [Release notes](https://github.com/dsanders11/project-actions/releases)
- [Changelog](https://github.com/dsanders11/project-actions/blob/main/.releaserc.json)
- [Commits](438b25e007...9c80cd31f5)

---
updated-dependencies:
- dependency-name: dsanders11/project-actions
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-01 11:11:32 -05:00
David Sanders
caa0567b76 ci: switch to GHA (#115) 2024-12-03 14:06:00 -08:00
dependabot[bot]
7f59407631 build(deps): bump cross-spawn from 7.0.3 to 7.0.6 (#114)
Bumps [cross-spawn](https://github.com/moxystudio/node-cross-spawn) from 7.0.3 to 7.0.6.
- [Changelog](https://github.com/moxystudio/node-cross-spawn/blob/master/CHANGELOG.md)
- [Commits](https://github.com/moxystudio/node-cross-spawn/compare/v7.0.3...v7.0.6)

---
updated-dependencies:
- dependency-name: cross-spawn
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-18 18:31:12 -05:00
dependabot[bot]
915c061908 build(deps): bump dsanders11/project-actions from 1.3.0 to 1.4.0 (#112)
Bumps [dsanders11/project-actions](https://github.com/dsanders11/project-actions) from 1.3.0 to 1.4.0.
- [Release notes](https://github.com/dsanders11/project-actions/releases)
- [Changelog](https://github.com/dsanders11/project-actions/blob/main/.releaserc.json)
- [Commits](eb760c4889...438b25e007)

---
updated-dependencies:
- dependency-name: dsanders11/project-actions
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-08 21:22:48 -08:00
electron-roller[bot]
ef4ce1f9ac chore: bump electronjs/node in .circleci/config.yml to 2.3.1 (#111)
Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
2024-10-26 10:08:58 -04:00
electron-roller[bot]
bf62ed4113 chore: bump continuousauth/npm in .circleci/config.yml to 2.1.1 (#110)
Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
2024-10-03 09:25:37 -05:00
David Sanders
dd52b47795 build: bump lint-staged to clear audit (#109) 2024-10-02 10:29:07 -07:00
David Sanders
9495fc3840 build: fix repository.url in package.json (#108) 2024-09-07 12:55:50 -07:00
dependabot[bot]
03b841956e build(deps): bump amannn/action-semantic-pull-request (#105)
Bumps [amannn/action-semantic-pull-request](https://github.com/amannn/action-semantic-pull-request) from 5.5.2 to 5.5.3.
- [Release notes](https://github.com/amannn/action-semantic-pull-request/releases)
- [Changelog](https://github.com/amannn/action-semantic-pull-request/blob/main/CHANGELOG.md)
- [Commits](cfb60706e1...0723387faa)

---
updated-dependencies:
- dependency-name: amannn/action-semantic-pull-request
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-01 13:58:02 -07:00
17 changed files with 1458 additions and 324 deletions

View File

@@ -1,35 +0,0 @@
version: 2.1
orbs:
cfa: continuousauth/npm@2.1.0
node: electronjs/node@2.3.0
workflows:
test_and_release:
# Run the test jobs first, then the release only when all the test jobs are successful
jobs:
- node/test:
executor: node/macos
name: test-mac-<< matrix.node-version >>
override-ci-command: yarn install --frozen-lockfile --ignore-engines
test-steps:
- node/install-rosetta
- run: yarn build
- run: yarn lint
- run: yarn test
use-test-steps: true
matrix:
alias: test
parameters:
node-version:
- 20.5.0
- 18.17.0
- 16.20.1
- cfa/release:
requires:
- test
filters:
branches:
only:
- main
context: cfa-release

View File

@@ -21,7 +21,7 @@ jobs:
creds: ${{ secrets.ECOSYSTEM_ISSUE_TRIAGE_GH_APP_CREDS }} creds: ${{ secrets.ECOSYSTEM_ISSUE_TRIAGE_GH_APP_CREDS }}
org: electron org: electron
- name: Add to Project - name: Add to Project
uses: dsanders11/project-actions/add-item@eb760c48894b5702398529cbb8f6e98378e315d0 # v1.3.0 uses: dsanders11/project-actions/add-item@9c80cd31f58599941c64f74636bea95ba5d46090 # v1.5.1
with: with:
field: Opened field: Opened
field-value: ${{ github.event.pull_request.created_at || github.event.issue.created_at }} field-value: ${{ github.event.pull_request.created_at || github.event.issue.created_at }}

35
.github/workflows/release.yml vendored Normal file
View File

@@ -0,0 +1,35 @@
name: Release
on:
push:
branches:
- main
jobs:
test:
uses: ./.github/workflows/test.yml
release:
name: Release
runs-on: ubuntu-latest
needs: test
environment: npm
permissions:
id-token: write # for CFA and npm provenance
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
- name: Setup Node.js
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
with:
node-version: 20.x
cache: 'yarn'
- name: Install
run: yarn install --frozen-lockfile
- uses: continuousauth/action@4e8a2573eeb706f6d7300d6a9f3ca6322740b72d # v1.0.5
with:
project-id: ${{ secrets.CFA_PROJECT_ID }}
secret: ${{ secrets.CFA_SECRET }}
npm-token: ${{ secrets.NPM_TOKEN }}

View File

@@ -19,7 +19,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: semantic-pull-request - name: semantic-pull-request
uses: amannn/action-semantic-pull-request@cfb60706e18bc85e8aec535e3c577abe8f70378e # v5.5.2 uses: amannn/action-semantic-pull-request@0723387faaf9b38adef4775cd42cfd5155ed6017 # v5.5.3
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with: with:

44
.github/workflows/test.yml vendored Normal file
View File

@@ -0,0 +1,44 @@
name: Test
on:
pull_request:
branches:
- main
schedule:
- cron: '0 22 * * 3'
workflow_call:
permissions:
contents: read
jobs:
test:
name: Test
strategy:
fail-fast: false
matrix:
node-version:
- '20.5'
- '18.17'
- '16.20'
runs-on: macos-latest
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Setup Node.js
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
with:
node-version: "${{ matrix.node-version }}"
cache: 'yarn'
- name: Install (Node.js v18+)
if : ${{ matrix.node-version != '16.20' }}
run: yarn install --frozen-lockfile
- name: Install (Node.js < v18)
if : ${{ matrix.node-version == '16.20' }}
run: yarn install --frozen-lockfile --ignore-engines
- name: Build
run: yarn build
- name: Lint
run: yarn lint
- name: Test
run: yarn test

View File

@@ -2,7 +2,7 @@
> Create universal macOS Electron applications > Create universal macOS Electron applications
[![CircleCI](https://circleci.com/gh/electron/universal/tree/main.svg?style=shield)](https://circleci.com/gh/electron/universal) [![Test](https://github.com/electron/universal/actions/workflows/test.yml/badge.svg)](https://github.com/electron/universal/actions/workflows/test.yml)
[![NPM package](https://img.shields.io/npm/v/@electron/universal)](https://npm.im/@electron/universal) [![NPM package](https://img.shields.io/npm/v/@electron/universal)](https://npm.im/@electron/universal)
## Usage ## Usage

View File

@@ -3,12 +3,14 @@ module.exports = {
preset: 'ts-jest', preset: 'ts-jest',
testEnvironment: 'node', testEnvironment: 'node',
transform: { transform: {
'.': [ '^.+\\.ts?$': [
'ts-jest', 'ts-jest',
{ {
tsconfig: 'tsconfig.jest.json' tsconfig: 'tsconfig.jest.json',
} },
] ],
}, },
globalSetup: './jest.setup.ts' testMatch: ['<rootDir>/test/**/*.spec.ts'],
}; globalSetup: './jest.setup.ts',
testTimeout: 10000,
};

View File

@@ -1,28 +1,6 @@
import { downloadArtifact } from '@electron/get';
import * as zip from 'cross-zip';
import * as fs from 'fs-extra'; import * as fs from 'fs-extra';
import * as path from 'path'; import * as path from 'path';
import { appsDir, asarsDir, templateApp } from './test/util';
const asarsDir = path.resolve(__dirname, 'test', 'fixtures', 'asars');
const appsDir = path.resolve(__dirname, 'test', 'fixtures', 'apps');
const templateApp = async (
name: string,
arch: string,
modify: (appPath: string) => Promise<void>,
) => {
const electronZip = await downloadArtifact({
artifactName: 'electron',
version: '27.0.0',
platform: 'darwin',
arch,
});
const appPath = path.resolve(appsDir, name);
zip.unzipSync(electronZip, appsDir);
await fs.rename(path.resolve(appsDir, 'Electron.app'), appPath);
await fs.remove(path.resolve(appPath, 'Contents', 'Resources', 'default_app.asar'));
await modify(appPath);
};
export default async () => { export default async () => {
await fs.remove(appsDir); await fs.remove(appsDir);

View File

@@ -12,7 +12,7 @@
], ],
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/electron/universal.git" "url": "git+https://github.com/electron/universal.git"
}, },
"engines": { "engines": {
"node": ">=16.4" "node": ">=16.4"
@@ -24,6 +24,9 @@
"README.md" "README.md"
], ],
"author": "Samuel Attard", "author": "Samuel Attard",
"publishConfig": {
"provenance": true
},
"scripts": { "scripts": {
"build": "tsc -p tsconfig.cjs.json && tsc -p tsconfig.esm.json && tsc -p tsconfig.entry-asar.json", "build": "tsc -p tsconfig.cjs.json && tsc -p tsconfig.esm.json && tsc -p tsconfig.entry-asar.json",
"build:docs": "npx typedoc", "build:docs": "npx typedoc",
@@ -45,14 +48,14 @@
"cross-zip": "^4.0.0", "cross-zip": "^4.0.0",
"husky": "^8.0.3", "husky": "^8.0.3",
"jest": "^29.7.0", "jest": "^29.7.0",
"lint-staged": "^15.0.2", "lint-staged": "^15.2.10",
"prettier": "^3.0.3", "prettier": "^3.0.3",
"ts-jest": "^29.1.1", "ts-jest": "^29.1.1",
"typedoc": "~0.25.13", "typedoc": "~0.25.13",
"typescript": "^5.2.2" "typescript": "^5.2.2"
}, },
"dependencies": { "dependencies": {
"@electron/asar": "^3.2.7", "@electron/asar": "^3.3.1",
"@malept/cross-spawn-promise": "^2.0.0", "@malept/cross-spawn-promise": "^2.0.0",
"debug": "^4.3.1", "debug": "^4.3.1",
"dir-compare": "^4.2.0", "dir-compare": "^4.2.0",

View File

@@ -84,8 +84,10 @@ export const mergeASARs = async ({
}: MergeASARsOptions): Promise<void> => { }: MergeASARsOptions): Promise<void> => {
d(`merging ${x64AsarPath} and ${arm64AsarPath}`); d(`merging ${x64AsarPath} and ${arm64AsarPath}`);
const x64Files = new Set(asar.listPackage(x64AsarPath).map(toRelativePath)); const x64Files = new Set(asar.listPackage(x64AsarPath, { isPack: false }).map(toRelativePath));
const arm64Files = new Set(asar.listPackage(arm64AsarPath).map(toRelativePath)); const arm64Files = new Set(
asar.listPackage(arm64AsarPath, { isPack: false }).map(toRelativePath),
);
// //
// Build set of unpacked directories and files // Build set of unpacked directories and files

View File

@@ -45,7 +45,7 @@ export const getAllAppFiles = async (appPath: string): Promise<AppFile[]> => {
throw e; throw e;
} }
} }
if (p.includes('app.asar')) { if (p.endsWith('.asar')) {
fileType = AppFileType.APP_CODE; fileType = AppFileType.APP_CODE;
} else if (fileOutput.startsWith(MACHO_PREFIX)) { } else if (fileOutput.startsWith(MACHO_PREFIX)) {
fileType = AppFileType.MACHO; fileType = AppFileType.MACHO;

View File

@@ -8,9 +8,10 @@ import * as plist from 'plist';
import * as dircompare from 'dir-compare'; import * as dircompare from 'dir-compare';
import { AppFile, AppFileType, getAllAppFiles } from './file-utils'; import { AppFile, AppFileType, getAllAppFiles } from './file-utils';
import { AsarMode, detectAsarMode, generateAsarIntegrity, mergeASARs } from './asar-utils'; import { AsarMode, detectAsarMode, mergeASARs } from './asar-utils';
import { sha } from './sha'; import { sha } from './sha';
import { d } from './debug'; import { d } from './debug';
import { computeIntegrityData } from './integrity';
/** /**
* Options to pass into the {@link makeUniversalApp} function. * Options to pass into the {@link makeUniversalApp} function.
@@ -251,9 +252,6 @@ export const makeUniversalApp = async (opts: MakeUniversalOpts): Promise<void> =
} }
} }
const generatedIntegrity: Record<string, { algorithm: 'SHA256'; hash: string }> = {};
let didSplitAsar = false;
/** /**
* If we have an ASAR we just need to check if the two "app.asar" files have the same hash, * If we have an ASAR we just need to check if the two "app.asar" files have the same hash,
* if they are, same as above, we can leave one there and call it a day. If they're different * if they are, same as above, we can leave one there and call it a day. If they're different
@@ -271,8 +269,6 @@ export const makeUniversalApp = async (opts: MakeUniversalOpts): Promise<void> =
outputAsarPath: output, outputAsarPath: output,
singleArchFiles: opts.singleArchFiles, singleArchFiles: opts.singleArchFiles,
}); });
generatedIntegrity['Resources/app.asar'] = generateAsarIntegrity(output);
} else if (x64AsarMode === AsarMode.HAS_ASAR) { } else if (x64AsarMode === AsarMode.HAS_ASAR) {
d('checking if the x64 and arm64 asars are identical'); d('checking if the x64 and arm64 asars are identical');
const x64AsarSha = await sha(path.resolve(tmpApp, 'Contents', 'Resources', 'app.asar')); const x64AsarSha = await sha(path.resolve(tmpApp, 'Contents', 'Resources', 'app.asar'));
@@ -281,7 +277,6 @@ export const makeUniversalApp = async (opts: MakeUniversalOpts): Promise<void> =
); );
if (x64AsarSha !== arm64AsarSha) { if (x64AsarSha !== arm64AsarSha) {
didSplitAsar = true;
d('x64 and arm64 asars are different'); d('x64 and arm64 asars are different');
const x64AsarPath = path.resolve(tmpApp, 'Contents', 'Resources', 'app-x64.asar'); const x64AsarPath = path.resolve(tmpApp, 'Contents', 'Resources', 'app-x64.asar');
await fs.move(path.resolve(tmpApp, 'Contents', 'Resources', 'app.asar'), x64AsarPath); await fs.move(path.resolve(tmpApp, 'Contents', 'Resources', 'app.asar'), x64AsarPath);
@@ -329,18 +324,13 @@ export const makeUniversalApp = async (opts: MakeUniversalOpts): Promise<void> =
await fs.writeJson(path.resolve(entryAsar, 'package.json'), pj); await fs.writeJson(path.resolve(entryAsar, 'package.json'), pj);
const asarPath = path.resolve(tmpApp, 'Contents', 'Resources', 'app.asar'); const asarPath = path.resolve(tmpApp, 'Contents', 'Resources', 'app.asar');
await asar.createPackage(entryAsar, asarPath); await asar.createPackage(entryAsar, asarPath);
generatedIntegrity['Resources/app.asar'] = generateAsarIntegrity(asarPath);
generatedIntegrity['Resources/app-x64.asar'] = generateAsarIntegrity(x64AsarPath);
generatedIntegrity['Resources/app-arm64.asar'] = generateAsarIntegrity(arm64AsarPath);
} else { } else {
d('x64 and arm64 asars are the same'); d('x64 and arm64 asars are the same');
generatedIntegrity['Resources/app.asar'] = generateAsarIntegrity(
path.resolve(tmpApp, 'Contents', 'Resources', 'app.asar'),
);
} }
} }
const generatedIntegrity = await computeIntegrityData(path.join(tmpApp, 'Contents'));
const plistFiles = x64Files.filter((f) => f.type === AppFileType.INFO_PLIST); const plistFiles = x64Files.filter((f) => f.type === AppFileType.INFO_PLIST);
for (const plistFile of plistFiles) { for (const plistFile of plistFiles) {
const x64PlistPath = path.resolve(opts.x64AppPath, plistFile.relativePath); const x64PlistPath = path.resolve(opts.x64AppPath, plistFile.relativePath);

51
src/integrity.ts Normal file
View File

@@ -0,0 +1,51 @@
import * as fs from 'fs-extra';
import path from 'path';
import { AppFileType, getAllAppFiles } from './file-utils';
import { sha } from './sha';
import { generateAsarIntegrity } from './asar-utils';
type IntegrityMap = {
[filepath: string]: string;
};
export interface HeaderHash {
algorithm: 'SHA256';
hash: string;
}
export interface AsarIntegrity {
[key: string]: HeaderHash;
}
export async function computeIntegrityData(contentsPath: string): Promise<AsarIntegrity> {
const root = await fs.realpath(contentsPath);
const resourcesRelativePath = 'Resources';
const resourcesPath = path.resolve(root, resourcesRelativePath);
const resources = await getAllAppFiles(resourcesPath);
const resourceAsars = resources
.filter((file) => file.type === AppFileType.APP_CODE)
.reduce<IntegrityMap>(
(prev, file) => ({
...prev,
[path.join(resourcesRelativePath, file.relativePath)]: path.join(
resourcesPath,
file.relativePath,
),
}),
{},
);
// sort to produce constant result
const allAsars = Object.entries(resourceAsars).sort(([name1], [name2]) =>
name1.localeCompare(name2),
);
const hashes = await Promise.all(allAsars.map(async ([, from]) => generateAsarIntegrity(from)));
const asarIntegrity: AsarIntegrity = {};
for (let i = 0; i < allAsars.length; i++) {
const [asar] = allAsars[i];
asarIntegrity[asar] = hashes[i];
}
return asarIntegrity;
}

View File

@@ -0,0 +1,722 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`makeUniversalApp asar mode should correctly merge two identical asars 1`] = `
{
"files": {
"index.js": {
"integrity": {
"algorithm": "SHA256",
"blockSize": 4194304,
"blocks": [
"8c8cefe616b330a70980c457e479360417a320f53f484d34df65227ce3add026",
],
"hash": "8c8cefe616b330a70980c457e479360417a320f53f484d34df65227ce3add026",
},
"size": 64,
},
"package.json": {
"integrity": {
"algorithm": "SHA256",
"blockSize": 4194304,
"blocks": [
"d6226276d47adc7aa20e6c46e842e258f5157313074a035051a89612acdd6be3",
],
"hash": "d6226276d47adc7aa20e6c46e842e258f5157313074a035051a89612acdd6be3",
},
"size": 41,
},
},
}
`;
exports[`makeUniversalApp asar mode should correctly merge two identical asars 2`] = `
{
"Contents/Info.plist": {
"Resources/app.asar": {
"algorithm": "SHA256",
"hash": "85fff474383bd8df11cd9c5784e8fcd1525af71ff140a8a882e1dc9d5b39fcbf",
},
},
}
`;
exports[`makeUniversalApp asar mode should create a shim if asars are different between architectures 1`] = `
{
"files": {
"extra-file.txt": {
"integrity": {
"algorithm": "SHA256",
"blockSize": 4194304,
"blocks": [
"b8f261b95f81761658c8875b33a68001d8750fd898f447373bf6347e779bc3de",
],
"hash": "b8f261b95f81761658c8875b33a68001d8750fd898f447373bf6347e779bc3de",
},
"size": 15,
},
"index.js": {
"integrity": {
"algorithm": "SHA256",
"blockSize": 4194304,
"blocks": [
"8c8cefe616b330a70980c457e479360417a320f53f484d34df65227ce3add026",
],
"hash": "8c8cefe616b330a70980c457e479360417a320f53f484d34df65227ce3add026",
},
"size": 64,
},
"package.json": {
"integrity": {
"algorithm": "SHA256",
"blockSize": 4194304,
"blocks": [
"d6226276d47adc7aa20e6c46e842e258f5157313074a035051a89612acdd6be3",
],
"hash": "d6226276d47adc7aa20e6c46e842e258f5157313074a035051a89612acdd6be3",
},
"size": 41,
},
},
}
`;
exports[`makeUniversalApp asar mode should create a shim if asars are different between architectures 2`] = `
{
"files": {
"index.js": {
"integrity": {
"algorithm": "SHA256",
"blockSize": 4194304,
"blocks": [
"8c8cefe616b330a70980c457e479360417a320f53f484d34df65227ce3add026",
],
"hash": "8c8cefe616b330a70980c457e479360417a320f53f484d34df65227ce3add026",
},
"size": 64,
},
"package.json": {
"integrity": {
"algorithm": "SHA256",
"blockSize": 4194304,
"blocks": [
"d6226276d47adc7aa20e6c46e842e258f5157313074a035051a89612acdd6be3",
],
"hash": "d6226276d47adc7aa20e6c46e842e258f5157313074a035051a89612acdd6be3",
},
"size": 41,
},
},
}
`;
exports[`makeUniversalApp asar mode should create a shim if asars are different between architectures 3`] = `
{
"files": {
"index.js": {
"integrity": {
"algorithm": "SHA256",
"blockSize": 4194304,
"blocks": [
"b7e5f58d3c0fddc1a57d1279a7f19a34a01784f4036920d4b60a1e33f6d1635b",
],
"hash": "b7e5f58d3c0fddc1a57d1279a7f19a34a01784f4036920d4b60a1e33f6d1635b",
},
"size": 1068,
},
"package.json": {
"integrity": {
"algorithm": "SHA256",
"blockSize": 4194304,
"blocks": [
"2873266521e41d58d02e7acfbbbdb046edfa04b6ce262b8987de8e8548671fc7",
],
"hash": "2873266521e41d58d02e7acfbbbdb046edfa04b6ce262b8987de8e8548671fc7",
},
"size": 33,
},
},
}
`;
exports[`makeUniversalApp asar mode should create a shim if asars are different between architectures 4`] = `
{
"Contents/Info.plist": {
"Resources/app-arm64.asar": {
"algorithm": "SHA256",
"hash": "71db54541357128943df64d54480a22d0cdf4c283f2044f48101fb1fc6e6fb2d",
},
"Resources/app-x64.asar": {
"algorithm": "SHA256",
"hash": "85fff474383bd8df11cd9c5784e8fcd1525af71ff140a8a882e1dc9d5b39fcbf",
},
"Resources/app.asar": {
"algorithm": "SHA256",
"hash": "b62aaaed07ff72dc33da1720d900e0443c060285ef374ce1bdaef1d4f28b5fe4",
},
},
}
`;
exports[`makeUniversalApp asar mode should generate AsarIntegrity for all asars in the application 1`] = `
{
"files": {
"index.js": {
"integrity": {
"algorithm": "SHA256",
"blockSize": 4194304,
"blocks": [
"0f6311dac07f0876c436ce2be042eb88c96e17eaf140b39627cf720dd87ad5b8",
],
"hash": "0f6311dac07f0876c436ce2be042eb88c96e17eaf140b39627cf720dd87ad5b8",
},
"size": 66,
},
"package.json": {
"integrity": {
"algorithm": "SHA256",
"blockSize": 4194304,
"blocks": [
"d6226276d47adc7aa20e6c46e842e258f5157313074a035051a89612acdd6be3",
],
"hash": "d6226276d47adc7aa20e6c46e842e258f5157313074a035051a89612acdd6be3",
},
"size": 41,
},
"private": {
"files": {
"var": {
"files": {
"app": {
"files": {
"file.txt": {
"link": "private/var/file.txt",
},
},
},
"file.txt": {
"integrity": {
"algorithm": "SHA256",
"blockSize": 4194304,
"blocks": [
"b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9",
],
"hash": "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9",
},
"size": 11,
},
},
},
},
},
"var": {
"link": "private/var",
},
},
}
`;
exports[`makeUniversalApp asar mode should generate AsarIntegrity for all asars in the application 2`] = `
{
"files": {
"index.js": {
"integrity": {
"algorithm": "SHA256",
"blockSize": 4194304,
"blocks": [
"0f6311dac07f0876c436ce2be042eb88c96e17eaf140b39627cf720dd87ad5b8",
],
"hash": "0f6311dac07f0876c436ce2be042eb88c96e17eaf140b39627cf720dd87ad5b8",
},
"size": 66,
},
"package.json": {
"integrity": {
"algorithm": "SHA256",
"blockSize": 4194304,
"blocks": [
"d6226276d47adc7aa20e6c46e842e258f5157313074a035051a89612acdd6be3",
],
"hash": "d6226276d47adc7aa20e6c46e842e258f5157313074a035051a89612acdd6be3",
},
"size": 41,
},
"private": {
"files": {
"var": {
"files": {
"app": {
"files": {
"file.txt": {
"link": "private/var/file.txt",
},
},
},
"file.txt": {
"integrity": {
"algorithm": "SHA256",
"blockSize": 4194304,
"blocks": [
"b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9",
],
"hash": "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9",
},
"size": 11,
},
},
},
},
},
"var": {
"link": "private/var",
},
},
}
`;
exports[`makeUniversalApp asar mode should generate AsarIntegrity for all asars in the application 3`] = `
{
"Contents/Info.plist": {
"Resources/app.asar": {
"algorithm": "SHA256",
"hash": "7e6af4d00f4cc737eff922e2b386128a269f80887b79a011022f1276bdbe7832",
},
"Resources/webbapp.asar": {
"algorithm": "SHA256",
"hash": "7e6af4d00f4cc737eff922e2b386128a269f80887b79a011022f1276bdbe7832",
},
},
}
`;
exports[`makeUniversalApp asar mode should merge two different asars when \`mergeASARs\` is enabled 1`] = `
{
"files": {
"extra-file.txt": {
"integrity": {
"algorithm": "SHA256",
"blockSize": 4194304,
"blocks": [
"b8f261b95f81761658c8875b33a68001d8750fd898f447373bf6347e779bc3de",
],
"hash": "b8f261b95f81761658c8875b33a68001d8750fd898f447373bf6347e779bc3de",
},
"size": 15,
},
"index.js": {
"integrity": {
"algorithm": "SHA256",
"blockSize": 4194304,
"blocks": [
"8c8cefe616b330a70980c457e479360417a320f53f484d34df65227ce3add026",
],
"hash": "8c8cefe616b330a70980c457e479360417a320f53f484d34df65227ce3add026",
},
"size": 64,
},
"package.json": {
"integrity": {
"algorithm": "SHA256",
"blockSize": 4194304,
"blocks": [
"d6226276d47adc7aa20e6c46e842e258f5157313074a035051a89612acdd6be3",
],
"hash": "d6226276d47adc7aa20e6c46e842e258f5157313074a035051a89612acdd6be3",
},
"size": 41,
},
},
}
`;
exports[`makeUniversalApp asar mode should merge two different asars when \`mergeASARs\` is enabled 2`] = `
{
"Contents/Info.plist": {
"Resources/app.asar": {
"algorithm": "SHA256",
"hash": "71db54541357128943df64d54480a22d0cdf4c283f2044f48101fb1fc6e6fb2d",
},
},
}
`;
exports[`makeUniversalApp asar mode should not inject ElectronAsarIntegrity into \`infoPlistsToIgnore\` 1`] = `
{
"files": {
"index.js": {
"integrity": {
"algorithm": "SHA256",
"blockSize": 4194304,
"blocks": [
"0f6311dac07f0876c436ce2be042eb88c96e17eaf140b39627cf720dd87ad5b8",
],
"hash": "0f6311dac07f0876c436ce2be042eb88c96e17eaf140b39627cf720dd87ad5b8",
},
"size": 66,
},
"package.json": {
"integrity": {
"algorithm": "SHA256",
"blockSize": 4194304,
"blocks": [
"d6226276d47adc7aa20e6c46e842e258f5157313074a035051a89612acdd6be3",
],
"hash": "d6226276d47adc7aa20e6c46e842e258f5157313074a035051a89612acdd6be3",
},
"size": 41,
},
"private": {
"files": {
"var": {
"files": {
"app": {
"files": {
"file.txt": {
"link": "private/var/file.txt",
},
},
},
"file.txt": {
"integrity": {
"algorithm": "SHA256",
"blockSize": 4194304,
"blocks": [
"b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9",
],
"hash": "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9",
},
"size": 11,
},
},
},
},
},
"var": {
"link": "private/var",
},
},
}
`;
exports[`makeUniversalApp asar mode should not inject ElectronAsarIntegrity into \`infoPlistsToIgnore\` 2`] = `
{
"Contents/Info.plist": undefined,
"Contents/Resources/SubApp-1.app/Contents/Info.plist": undefined,
}
`;
exports[`makeUniversalApp asar mode should shim asars with different unpacked dirs 1`] = `
{
"files": {
"index.js": {
"integrity": {
"algorithm": "SHA256",
"blockSize": 4194304,
"blocks": [
"0f6311dac07f0876c436ce2be042eb88c96e17eaf140b39627cf720dd87ad5b8",
],
"hash": "0f6311dac07f0876c436ce2be042eb88c96e17eaf140b39627cf720dd87ad5b8",
},
"size": 66,
},
"package.json": {
"integrity": {
"algorithm": "SHA256",
"blockSize": 4194304,
"blocks": [
"d6226276d47adc7aa20e6c46e842e258f5157313074a035051a89612acdd6be3",
],
"hash": "d6226276d47adc7aa20e6c46e842e258f5157313074a035051a89612acdd6be3",
},
"size": 41,
},
"private": {
"files": {
"var": {
"files": {
"app": {
"files": {
"file.txt": {
"link": "private/var/file.txt",
"unpacked": true,
},
},
},
"file.txt": {
"integrity": {
"algorithm": "SHA256",
"blockSize": 4194304,
"blocks": [
"b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9",
],
"hash": "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9",
},
"size": 11,
"unpacked": true,
},
},
},
},
},
"var": {
"link": "private/var",
"unpacked": true,
},
},
}
`;
exports[`makeUniversalApp asar mode should shim asars with different unpacked dirs 2`] = `
{
"files": {
"index.js": {
"integrity": {
"algorithm": "SHA256",
"blockSize": 4194304,
"blocks": [
"0f6311dac07f0876c436ce2be042eb88c96e17eaf140b39627cf720dd87ad5b8",
],
"hash": "0f6311dac07f0876c436ce2be042eb88c96e17eaf140b39627cf720dd87ad5b8",
},
"size": 66,
},
"package.json": {
"integrity": {
"algorithm": "SHA256",
"blockSize": 4194304,
"blocks": [
"d6226276d47adc7aa20e6c46e842e258f5157313074a035051a89612acdd6be3",
],
"hash": "d6226276d47adc7aa20e6c46e842e258f5157313074a035051a89612acdd6be3",
},
"size": 41,
},
"private": {
"files": {
"var": {
"files": {
"app": {
"files": {
"file.txt": {
"link": "private/var/file.txt",
},
},
},
"file.txt": {
"integrity": {
"algorithm": "SHA256",
"blockSize": 4194304,
"blocks": [
"b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9",
],
"hash": "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9",
},
"size": 11,
},
},
},
},
},
"var": {
"link": "private/var",
},
},
}
`;
exports[`makeUniversalApp asar mode should shim asars with different unpacked dirs 3`] = `
{
"files": {
"index.js": {
"integrity": {
"algorithm": "SHA256",
"blockSize": 4194304,
"blocks": [
"b7e5f58d3c0fddc1a57d1279a7f19a34a01784f4036920d4b60a1e33f6d1635b",
],
"hash": "b7e5f58d3c0fddc1a57d1279a7f19a34a01784f4036920d4b60a1e33f6d1635b",
},
"size": 1068,
},
"package.json": {
"integrity": {
"algorithm": "SHA256",
"blockSize": 4194304,
"blocks": [
"2873266521e41d58d02e7acfbbbdb046edfa04b6ce262b8987de8e8548671fc7",
],
"hash": "2873266521e41d58d02e7acfbbbdb046edfa04b6ce262b8987de8e8548671fc7",
},
"size": 33,
},
},
}
`;
exports[`makeUniversalApp asar mode should shim asars with different unpacked dirs 4`] = `
[
{
"content": "hello world",
"name": "private/var/file.txt",
},
]
`;
exports[`makeUniversalApp asar mode should shim asars with different unpacked dirs 5`] = `
{
"Contents/Info.plist": {
"Resources/app-arm64.asar": {
"algorithm": "SHA256",
"hash": "d06a628e759f54def7ff8785a077b3a3d756882cb84ee99e9725966226e1f195",
},
"Resources/app-x64.asar": {
"algorithm": "SHA256",
"hash": "7e6af4d00f4cc737eff922e2b386128a269f80887b79a011022f1276bdbe7832",
},
"Resources/app.asar": {
"algorithm": "SHA256",
"hash": "b62aaaed07ff72dc33da1720d900e0443c060285ef374ce1bdaef1d4f28b5fe4",
},
},
}
`;
exports[`makeUniversalApp force packages successfully if \`out\` bundle already exists and \`force\` is \`true\` 1`] = `
{
"files": {
"index.js": {
"integrity": {
"algorithm": "SHA256",
"blockSize": 4194304,
"blocks": [
"8c8cefe616b330a70980c457e479360417a320f53f484d34df65227ce3add026",
],
"hash": "8c8cefe616b330a70980c457e479360417a320f53f484d34df65227ce3add026",
},
"size": 64,
},
"package.json": {
"integrity": {
"algorithm": "SHA256",
"blockSize": 4194304,
"blocks": [
"d6226276d47adc7aa20e6c46e842e258f5157313074a035051a89612acdd6be3",
],
"hash": "d6226276d47adc7aa20e6c46e842e258f5157313074a035051a89612acdd6be3",
},
"size": 41,
},
},
}
`;
exports[`makeUniversalApp force packages successfully if \`out\` bundle already exists and \`force\` is \`true\` 2`] = `
{
"Contents/Info.plist": {
"Resources/app.asar": {
"algorithm": "SHA256",
"hash": "85fff474383bd8df11cd9c5784e8fcd1525af71ff140a8a882e1dc9d5b39fcbf",
},
},
}
`;
exports[`makeUniversalApp no asar mode should correctly merge two identical app folders 1`] = `
[
"index.js",
{
"content": "{
"name": "app",
"main": "index.js"
}",
"name": "package.json",
},
]
`;
exports[`makeUniversalApp no asar mode should correctly merge two identical app folders 2`] = `
{
"Contents/Info.plist": {},
}
`;
exports[`makeUniversalApp no asar mode should shim two different app folders 1`] = `
{
"files": {
"index.js": {
"integrity": {
"algorithm": "SHA256",
"blockSize": 4194304,
"blocks": [
"f1e14240f7c833900fca84fabc2f0ff27084efdf1c5b228b015515de3f8fa28e",
],
"hash": "f1e14240f7c833900fca84fabc2f0ff27084efdf1c5b228b015515de3f8fa28e",
},
"size": 1063,
},
"package.json": {
"integrity": {
"algorithm": "SHA256",
"blockSize": 4194304,
"blocks": [
"2873266521e41d58d02e7acfbbbdb046edfa04b6ce262b8987de8e8548671fc7",
],
"hash": "2873266521e41d58d02e7acfbbbdb046edfa04b6ce262b8987de8e8548671fc7",
},
"size": 33,
},
},
}
`;
exports[`makeUniversalApp no asar mode should shim two different app folders 2`] = `
[
"private/var/i-aint-got-no-rhythm.bin",
]
`;
exports[`makeUniversalApp no asar mode should shim two different app folders 3`] = `
[
"index.js",
{
"content": "{
"name": "app",
"main": "index.js"
}",
"name": "package.json",
},
{
"content": "hello world",
"name": "private/var/file.txt",
},
"private/var/i-aint-got-no-rhythm.bin",
]
`;
exports[`makeUniversalApp no asar mode should shim two different app folders 4`] = `
[
"index.js",
{
"content": "{
"name": "app",
"main": "index.js"
}",
"name": "package.json",
},
{
"content": "hello world",
"name": "private/var/file.txt",
},
"private/var/hello-world.bin",
]
`;
exports[`makeUniversalApp no asar mode should shim two different app folders 5`] = `
{
"Contents/Info.plist": {
"Resources/app.asar": {
"algorithm": "SHA256",
"hash": "27433ee3e34b3b0dabb29d18d40646126e80c56dbce8c4bb2adef7278b5a46c0",
},
},
}
`;

View File

@@ -1,20 +1,13 @@
import { spawn } from '@malept/cross-spawn-promise';
import * as fs from 'fs-extra'; import * as fs from 'fs-extra';
import * as path from 'path'; import * as path from 'path';
import { makeUniversalApp } from '../dist/cjs/index'; import { makeUniversalApp } from '../dist/cjs/index';
import { createTestApp, templateApp, VERIFY_APP_TIMEOUT, verifyApp } from './util';
import { createPackage, createPackageWithOptions } from '@electron/asar';
const appsPath = path.resolve(__dirname, 'fixtures', 'apps'); const appsPath = path.resolve(__dirname, 'fixtures', 'apps');
const appsOutPath = path.resolve(__dirname, 'fixtures', 'apps', 'out'); const appsOutPath = path.resolve(__dirname, 'fixtures', 'apps', 'out');
async function ensureUniversal(app: string) {
const exe = path.resolve(app, 'Contents', 'MacOS', 'Electron');
const result = await spawn(exe);
expect(result).toContain('arm64');
const result2 = await spawn('arch', ['-x86_64', exe]);
expect(result2).toContain('x64');
}
// See `jest.setup.ts` for app fixture setup process // See `jest.setup.ts` for app fixture setup process
describe('makeUniversalApp', () => { describe('makeUniversalApp', () => {
afterEach(async () => { afterEach(async () => {
@@ -49,110 +42,239 @@ describe('makeUniversalApp', () => {
).rejects.toThrow(/The out path ".*" already exists and force is not set to true/); ).rejects.toThrow(/The out path ".*" already exists and force is not set to true/);
}); });
it('packages successfully if `out` bundle already exists and `force` is `true`', async () => { it(
const out = path.resolve(appsOutPath, 'Error.app'); 'packages successfully if `out` bundle already exists and `force` is `true`',
await fs.mkdirp(out); async () => {
await makeUniversalApp({ const out = path.resolve(appsOutPath, 'Error.app');
x64AppPath: path.resolve(appsPath, 'X64Asar.app'), await fs.mkdirp(out);
arm64AppPath: path.resolve(appsPath, 'Arm64Asar.app'), await makeUniversalApp({
outAppPath: out, x64AppPath: path.resolve(appsPath, 'X64Asar.app'),
force: true, arm64AppPath: path.resolve(appsPath, 'Arm64Asar.app'),
}); outAppPath: out,
await ensureUniversal(out); force: true,
// Only a single asar as they were identical });
expect( await verifyApp(out);
(await fs.readdir(path.resolve(out, 'Contents', 'Resources'))).filter((p) => },
p.endsWith('asar'), VERIFY_APP_TIMEOUT,
), );
).toEqual(['app.asar']);
}, 60000);
}); });
describe('asar mode', () => { describe('asar mode', () => {
it('should correctly merge two identical asars', async () => { it(
const out = path.resolve(appsOutPath, 'MergedAsar.app'); 'should correctly merge two identical asars',
await makeUniversalApp({ async () => {
x64AppPath: path.resolve(appsPath, 'X64Asar.app'), const out = path.resolve(appsOutPath, 'MergedAsar.app');
arm64AppPath: path.resolve(appsPath, 'Arm64Asar.app'), await makeUniversalApp({
outAppPath: out, x64AppPath: path.resolve(appsPath, 'X64Asar.app'),
}); arm64AppPath: path.resolve(appsPath, 'Arm64Asar.app'),
await ensureUniversal(out); outAppPath: out,
// Only a single asar as they were identical });
expect( await verifyApp(out);
(await fs.readdir(path.resolve(out, 'Contents', 'Resources'))).filter((p) => },
p.endsWith('asar'), VERIFY_APP_TIMEOUT,
), );
).toEqual(['app.asar']);
}, 60000);
it('should create a shim if asars are different between architectures', async () => { it(
const out = path.resolve(appsOutPath, 'ShimmedAsar.app'); 'should create a shim if asars are different between architectures',
await makeUniversalApp({ async () => {
x64AppPath: path.resolve(appsPath, 'X64Asar.app'), const out = path.resolve(appsOutPath, 'ShimmedAsar.app');
arm64AppPath: path.resolve(appsPath, 'Arm64AsarExtraFile.app'), await makeUniversalApp({
outAppPath: out, x64AppPath: path.resolve(appsPath, 'X64Asar.app'),
}); arm64AppPath: path.resolve(appsPath, 'Arm64AsarExtraFile.app'),
await ensureUniversal(out); outAppPath: out,
// We have three asars including the arch-agnostic shim });
expect( await verifyApp(out);
(await fs.readdir(path.resolve(out, 'Contents', 'Resources'))) },
.filter((p) => p.endsWith('asar')) VERIFY_APP_TIMEOUT,
.sort(), );
).toEqual(['app.asar', 'app-x64.asar', 'app-arm64.asar'].sort());
}, 60000);
it('should merge two different asars when `mergeASARs` is enabled', async () => { it(
const out = path.resolve(appsOutPath, 'MergedAsar.app'); 'should merge two different asars when `mergeASARs` is enabled',
await makeUniversalApp({ async () => {
x64AppPath: path.resolve(appsPath, 'X64Asar.app'), const out = path.resolve(appsOutPath, 'MergedAsar.app');
arm64AppPath: path.resolve(appsPath, 'Arm64AsarExtraFile.app'), await makeUniversalApp({
outAppPath: out,
mergeASARs: true,
singleArchFiles: 'extra-file.txt',
});
await ensureUniversal(out);
// Only a single merged asar
expect(
(await fs.readdir(path.resolve(out, 'Contents', 'Resources'))).filter((p) =>
p.endsWith('asar'),
),
).toEqual(['app.asar']);
}, 60000);
it('throws an error if `mergeASARs` is enabled and `singleArchFiles` is missing a unique file', async () => {
const out = path.resolve(appsOutPath, 'Error.app');
await expect(
makeUniversalApp({
x64AppPath: path.resolve(appsPath, 'X64Asar.app'), x64AppPath: path.resolve(appsPath, 'X64Asar.app'),
arm64AppPath: path.resolve(appsPath, 'Arm64AsarExtraFile.app'), arm64AppPath: path.resolve(appsPath, 'Arm64AsarExtraFile.app'),
outAppPath: out, outAppPath: out,
mergeASARs: true, mergeASARs: true,
singleArchFiles: 'bad-rule', singleArchFiles: 'extra-file.txt',
}), });
).rejects.toThrow(/Detected unique file "extra-file\.txt"/); await verifyApp(out);
}, 60000); },
VERIFY_APP_TIMEOUT,
);
it.todo('should not inject ElectronAsarIntegrity into `infoPlistsToIgnore`'); it(
'throws an error if `mergeASARs` is enabled and `singleArchFiles` is missing a unique file',
async () => {
const out = path.resolve(appsOutPath, 'Error.app');
await expect(
makeUniversalApp({
x64AppPath: path.resolve(appsPath, 'X64Asar.app'),
arm64AppPath: path.resolve(appsPath, 'Arm64AsarExtraFile.app'),
outAppPath: out,
mergeASARs: true,
singleArchFiles: 'bad-rule',
}),
).rejects.toThrow(/Detected unique file "extra-file\.txt"/);
},
VERIFY_APP_TIMEOUT,
);
it(
'should not inject ElectronAsarIntegrity into `infoPlistsToIgnore`',
async () => {
const arm64AppPath = await templateApp('Arm64-1.app', 'arm64', async (appPath) => {
const { testPath } = await createTestApp('Arm64-1');
await createPackage(testPath, path.resolve(appPath, 'Contents', 'Resources', 'app.asar'));
await templateApp('SubApp-1.app', 'arm64', async (subArm64AppPath) => {
await fs.move(
subArm64AppPath,
path.resolve(appPath, 'Contents', 'Resources', path.basename(subArm64AppPath)),
);
});
});
const x64AppPath = await templateApp('X64-1.app', 'x64', async (appPath) => {
const { testPath } = await createTestApp('X64-1');
await createPackage(testPath, path.resolve(appPath, 'Contents', 'Resources', 'app.asar'));
await templateApp('SubApp-1.app', 'x64', async (subArm64AppPath) => {
await fs.move(
subArm64AppPath,
path.resolve(appPath, 'Contents', 'Resources', path.basename(subArm64AppPath)),
);
});
});
const outAppPath = path.resolve(appsOutPath, 'UnmodifiedPlist.app');
await makeUniversalApp({
x64AppPath,
arm64AppPath,
outAppPath,
mergeASARs: true,
infoPlistsToIgnore: 'SubApp-1.app/Contents/Info.plist',
});
await verifyApp(outAppPath);
},
VERIFY_APP_TIMEOUT,
);
// TODO: Investigate if this should even be allowed.
// Current logic detects all unpacked files as APP_CODE, which doesn't seem correct since it could also be a macho file requiring lipo
// https://github.com/electron/universal/blob/d90d573ccf69a5b14b91aa818c8b97e0e6840399/src/file-utils.ts#L48-L49
it.skip(
'should shim asars with different unpacked dirs',
async () => {
const arm64AppPath = await templateApp('UnpackedArm64.app', 'arm64', async (appPath) => {
const { testPath } = await createTestApp('UnpackedAppArm64');
await createPackageWithOptions(
testPath,
path.resolve(appPath, 'Contents', 'Resources', 'app.asar'),
{
unpackDir: 'var',
unpack: '*.txt',
},
);
});
const x64AppPath = await templateApp('UnpackedX64.app', 'x64', async (appPath) => {
const { testPath } = await createTestApp('UnpackedAppX64');
await createPackageWithOptions(
testPath,
path.resolve(appPath, 'Contents', 'Resources', 'app.asar'),
{},
);
});
const outAppPath = path.resolve(appsOutPath, 'UnpackedDir.app');
await makeUniversalApp({
x64AppPath,
arm64AppPath,
outAppPath,
});
await verifyApp(outAppPath);
},
VERIFY_APP_TIMEOUT,
);
it(
'should generate AsarIntegrity for all asars in the application',
async () => {
const { testPath } = await createTestApp('app-2');
const testAsarPath = path.resolve(appsOutPath, 'app-2.asar');
await createPackage(testPath, testAsarPath);
const arm64AppPath = await templateApp('Arm64-2.app', 'arm64', async (appPath) => {
await fs.copyFile(
testAsarPath,
path.resolve(appPath, 'Contents', 'Resources', 'app.asar'),
);
await fs.copyFile(
testAsarPath,
path.resolve(appPath, 'Contents', 'Resources', 'webapp.asar'),
);
});
const x64AppPath = await templateApp('X64-2.app', 'x64', async (appPath) => {
await fs.copyFile(
testAsarPath,
path.resolve(appPath, 'Contents', 'Resources', 'app.asar'),
);
await fs.copyFile(
testAsarPath,
path.resolve(appPath, 'Contents', 'Resources', 'webbapp.asar'),
);
});
const outAppPath = path.resolve(appsOutPath, 'MultipleAsars.app');
await makeUniversalApp({
x64AppPath,
arm64AppPath,
outAppPath,
mergeASARs: true,
});
await verifyApp(outAppPath);
},
VERIFY_APP_TIMEOUT,
);
}); });
describe('no asar mode', () => { describe('no asar mode', () => {
it('should correctly merge two identical app folders', async () => { it(
const out = path.resolve(appsOutPath, 'MergedNoAsar.app'); 'should correctly merge two identical app folders',
await makeUniversalApp({ async () => {
x64AppPath: path.resolve(appsPath, 'X64NoAsar.app'), const out = path.resolve(appsOutPath, 'MergedNoAsar.app');
arm64AppPath: path.resolve(appsPath, 'Arm64NoAsar.app'), await makeUniversalApp({
outAppPath: out, x64AppPath: path.resolve(appsPath, 'X64NoAsar.app'),
}); arm64AppPath: path.resolve(appsPath, 'Arm64NoAsar.app'),
await ensureUniversal(out); outAppPath: out,
// Only a single app folder as they were identical });
expect( await verifyApp(out);
(await fs.readdir(path.resolve(out, 'Contents', 'Resources'))).filter((p) => },
p.startsWith('app'), VERIFY_APP_TIMEOUT,
), );
).toEqual(['app']);
}, 60000);
it.todo('should shim two different app folders'); it(
'should shim two different app folders',
async () => {
const arm64AppPath = await templateApp('ShimArm64.app', 'arm64', async (appPath) => {
const { testPath } = await createTestApp('shimArm64', {
'i-aint-got-no-rhythm.bin': 'boomshakalaka',
});
await fs.copy(testPath, path.resolve(appPath, 'Contents', 'Resources', 'app'));
});
const x64AppPath = await templateApp('ShimX64.app', 'x64', async (appPath) => {
const { testPath } = await createTestApp('shimX64', { 'hello-world.bin': 'Hello World' });
await fs.copy(testPath, path.resolve(appPath, 'Contents', 'Resources', 'app'));
});
const outAppPath = path.resolve(appsOutPath, 'ShimNoAsar.app');
await makeUniversalApp({
x64AppPath,
arm64AppPath,
outAppPath,
});
await verifyApp(outAppPath);
},
VERIFY_APP_TIMEOUT,
);
}); });
// TODO: Add tests for // TODO: Add tests for

181
test/util.ts Normal file
View File

@@ -0,0 +1,181 @@
import { downloadArtifact } from '@electron/get';
import { spawn } from '@malept/cross-spawn-promise';
import * as zip from 'cross-zip';
import * as fs from 'fs-extra';
import * as path from 'path';
import plist from 'plist';
import * as fileUtils from '../dist/cjs/file-utils';
import { getRawHeader } from '@electron/asar';
// We do a LOT of verifications in `verifyApp` 😅
// exec universal binary -> verify ALL asars -> verify ALL app dirs -> verify ALL asar integrity entries
// plus some tests create fixtures at runtime
export const VERIFY_APP_TIMEOUT = 80 * 1000;
export const asarsDir = path.resolve(__dirname, 'fixtures', 'asars');
export const appsDir = path.resolve(__dirname, 'fixtures', 'apps');
export const appsOutPath = path.resolve(appsDir, 'out');
export const verifyApp = async (appPath: string) => {
await ensureUniversal(appPath);
const resourcesDir = path.resolve(appPath, 'Contents', 'Resources');
const resourcesDirContents = await fs.readdir(resourcesDir);
// sort for consistent result
const asars = resourcesDirContents.filter((p) => p.endsWith('.asar')).sort();
for await (const asar of asars) {
// verify header
const asarFs = getRawHeader(path.resolve(resourcesDir, asar));
expect(removeUnstableProperties(asarFs.header)).toMatchSnapshot();
}
// check all app and unpacked dirs (incl. shimmed)
const dirsToSnapshot = [
'app',
'app.asar.unpacked',
'app-x64',
'app-x64.asar.unpacked',
'app-arm64',
'app-arm64.asar.unpacked',
];
const appDirs = resourcesDirContents
.filter((p) => dirsToSnapshot.includes(path.basename(p)))
.sort();
for await (const dir of appDirs) {
await verifyFileTree(path.resolve(resourcesDir, dir));
}
const allFiles = await fileUtils.getAllAppFiles(appPath);
const infoPlists = allFiles
.filter(
(appFile) =>
appFile.type === fileUtils.AppFileType.INFO_PLIST &&
// These are test app fixtures, no need to snapshot within `TestApp.app/Contents/Frameworks`
!appFile.relativePath.includes(path.join('Contents', 'Frameworks')),
)
.map((af) => af.relativePath)
.sort();
const integrityMap: Record<string, string> = {};
const integrity = await Promise.all(
infoPlists.map((ip) => extractAsarIntegrity(path.resolve(appPath, ip))),
);
for (let i = 0; i < integrity.length; i++) {
const relativePath = infoPlists[i];
const asarIntegrity = integrity[i];
integrityMap[relativePath] = asarIntegrity;
}
expect(integrityMap).toMatchSnapshot();
};
// note: `infoPlistsToIgnore` will not have integrity in sub-app plists
const extractAsarIntegrity = async (infoPlist: string) => {
const { ElectronAsarIntegrity: integrity, ...otherData } = plist.parse(
await fs.readFile(infoPlist, 'utf-8'),
) as any;
return integrity;
};
export const verifyFileTree = async (dirPath: string) => {
const dirFiles = await fileUtils.getAllAppFiles(dirPath);
const files = dirFiles.map((file) => {
const it = path.join(dirPath, file.relativePath);
const name = toSystemIndependentPath(file.relativePath);
if (it.endsWith('.txt') || it.endsWith('.json')) {
return { name, content: fs.readFileSync(it, 'utf-8') };
}
return name;
});
expect(files).toMatchSnapshot();
};
export const ensureUniversal = async (app: string) => {
const exe = path.resolve(app, 'Contents', 'MacOS', 'Electron');
const result = await spawn(exe);
expect(result).toContain('arm64');
const result2 = await spawn('arch', ['-x86_64', exe]);
expect(result2).toContain('x64');
};
export const toSystemIndependentPath = (s: string): string => {
return path.sep === '/' ? s : s.replace(/\\/g, '/');
};
export const removeUnstableProperties = (data: any) => {
return JSON.parse(
JSON.stringify(data, (name, value) => {
if (name === 'offset') {
return undefined;
}
return value;
}),
);
};
/**
* Directory structure:
* testName
* ├── private
* │ └── var
* │ ├── app
* │ │ └── file.txt -> ../file.txt
* │ └── file.txt
* └── var -> private/var
* ├── index.js
* ├── package.json
*/
export const createTestApp = async (
testName: string | undefined,
additionalFiles: Record<string, string> = {},
) => {
const outDir = (testName || 'app') + Math.floor(Math.random() * 100); // tests run in parallel, randomize dir suffix to prevent naming collisions
const testPath = path.join(appsDir, outDir);
await fs.remove(testPath);
await fs.copy(path.join(asarsDir, 'app'), testPath);
const privateVarPath = path.join(testPath, 'private', 'var');
const varPath = path.join(testPath, 'var');
await fs.mkdir(privateVarPath, { recursive: true });
await fs.symlink(path.relative(testPath, privateVarPath), varPath);
const files = {
'file.txt': 'hello world',
...additionalFiles,
};
for await (const [filename, fileData] of Object.entries(files)) {
const originFilePath = path.join(varPath, filename);
await fs.writeFile(originFilePath, fileData);
}
const appPath = path.join(varPath, 'app');
await fs.mkdirp(appPath);
await fs.symlink('../file.txt', path.join(appPath, 'file.txt'));
return {
testPath,
varPath,
appPath,
};
};
export const templateApp = async (
name: string,
arch: string,
modify: (appPath: string) => Promise<void>,
) => {
const electronZip = await downloadArtifact({
artifactName: 'electron',
version: '27.0.0',
platform: 'darwin',
arch,
});
const appPath = path.resolve(appsDir, name);
zip.unzipSync(electronZip, appsDir);
await fs.rename(path.resolve(appsDir, 'Electron.app'), appPath);
await fs.remove(path.resolve(appPath, 'Contents', 'Resources', 'default_app.asar'));
await modify(appPath);
return appPath;
};

315
yarn.lock
View File

@@ -297,10 +297,10 @@
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
"@electron/asar@^3.2.7": "@electron/asar@^3.3.1":
version "3.2.7" version "3.3.1"
resolved "https://registry.yarnpkg.com/@electron/asar/-/asar-3.2.7.tgz#bb8117dc6fd0c06a922ae7fb1c0e2d433e35a6e5" resolved "https://registry.yarnpkg.com/@electron/asar/-/asar-3.3.1.tgz#cd14e897770d9844673dd7c1dc8944e086e1e0ea"
integrity sha512-8FaSCAIiZGYFWyjeevPQt+0e9xCK9YmJ2Rjg5SXgdsXon6cRnU0Yxnbe6CvJbQn26baifur2Y2G5EBayRIsjyg== integrity sha512-WtpC/+34p0skWZiarRjLAyqaAX78DofhDxnREy/V5XHfu1XEXbFCSSMcDQ6hNCPJFaPy8/NnUgYuf9uiCkvKPg==
dependencies: dependencies:
commander "^5.0.0" commander "^5.0.0"
glob "^7.1.6" glob "^7.1.6"
@@ -781,12 +781,12 @@ ansi-escapes@^4.2.1:
dependencies: dependencies:
type-fest "^0.21.3" type-fest "^0.21.3"
ansi-escapes@^5.0.0: ansi-escapes@^7.0.0:
version "5.0.0" version "7.0.0"
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-5.0.0.tgz#b6a0caf0eef0c41af190e9a749e0c00ec04bb2a6" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-7.0.0.tgz#00fc19f491bbb18e1d481b97868204f92109bfe7"
integrity sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA== integrity sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==
dependencies: dependencies:
type-fest "^1.0.2" environment "^1.0.0"
ansi-regex@^5.0.1: ansi-regex@^5.0.1:
version "5.0.1" version "5.0.1"
@@ -822,7 +822,7 @@ ansi-styles@^5.0.0:
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b"
integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==
ansi-styles@^6.0.0, ansi-styles@^6.1.0: ansi-styles@^6.0.0, ansi-styles@^6.2.1:
version "6.2.1" version "6.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5"
integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==
@@ -932,7 +932,7 @@ brace-expansion@^2.0.1:
dependencies: dependencies:
balanced-match "^1.0.0" balanced-match "^1.0.0"
braces@^3.0.2: braces@^3.0.3:
version "3.0.3" version "3.0.3"
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789"
integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==
@@ -1006,11 +1006,6 @@ caniuse-lite@^1.0.30001541:
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001561.tgz#752f21f56f96f1b1a52e97aae98c57c562d5d9da" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001561.tgz#752f21f56f96f1b1a52e97aae98c57c562d5d9da"
integrity sha512-NTt0DNoKe958Q0BE0j0c1V9jbUzhBxHIEJy7asmGrpE0yG63KTV7PLHPnK2E1O9RsQrQ081I3NLuXGS6zht3cw== integrity sha512-NTt0DNoKe958Q0BE0j0c1V9jbUzhBxHIEJy7asmGrpE0yG63KTV7PLHPnK2E1O9RsQrQ081I3NLuXGS6zht3cw==
chalk@5.3.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385"
integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==
chalk@^2.4.2: chalk@^2.4.2:
version "2.4.2" version "2.4.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
@@ -1028,6 +1023,11 @@ chalk@^4.0.0:
ansi-styles "^4.1.0" ansi-styles "^4.1.0"
supports-color "^7.1.0" supports-color "^7.1.0"
chalk@~5.3.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385"
integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==
char-regex@^1.0.2: char-regex@^1.0.2:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf"
@@ -1043,20 +1043,20 @@ cjs-module-lexer@^1.0.0:
resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz#6c370ab19f8a3394e318fe682686ec0ac684d107" resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz#6c370ab19f8a3394e318fe682686ec0ac684d107"
integrity sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ== integrity sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==
cli-cursor@^4.0.0: cli-cursor@^5.0.0:
version "4.0.0" version "5.0.0"
resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-4.0.0.tgz#3cecfe3734bf4fe02a8361cbdc0f6fe28c6a57ea" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-5.0.0.tgz#24a4831ecf5a6b01ddeb32fb71a4b2088b0dce38"
integrity sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg== integrity sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==
dependencies: dependencies:
restore-cursor "^4.0.0" restore-cursor "^5.0.0"
cli-truncate@^3.1.0: cli-truncate@^4.0.0:
version "3.1.0" version "4.0.0"
resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-3.1.0.tgz#3f23ab12535e3d73e839bb43e73c9de487db1389" resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-4.0.0.tgz#6cc28a2924fee9e25ce91e973db56c7066e6172a"
integrity sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA== integrity sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==
dependencies: dependencies:
slice-ansi "^5.0.0" slice-ansi "^5.0.0"
string-width "^5.0.0" string-width "^7.0.0"
cliui@^8.0.1: cliui@^8.0.1:
version "8.0.1" version "8.0.1"
@@ -1113,16 +1113,16 @@ colorette@^2.0.20:
resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a"
integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==
commander@11.1.0:
version "11.1.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-11.1.0.tgz#62fdce76006a68e5c1ab3314dc92e800eb83d906"
integrity sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==
commander@^5.0.0: commander@^5.0.0:
version "5.1.0" version "5.1.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae" resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae"
integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg== integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==
commander@~12.1.0:
version "12.1.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-12.1.0.tgz#01423b36f501259fdaac4d0e4d60c96c991585d3"
integrity sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==
concat-map@0.0.1: concat-map@0.0.1:
version "0.0.1" version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
@@ -1147,9 +1147,9 @@ create-jest@^29.7.0:
prompts "^2.0.1" prompts "^2.0.1"
cross-spawn@^7.0.1, cross-spawn@^7.0.3: cross-spawn@^7.0.1, cross-spawn@^7.0.3:
version "7.0.3" version "7.0.6"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f"
integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==
dependencies: dependencies:
path-key "^3.1.0" path-key "^3.1.0"
shebang-command "^2.0.0" shebang-command "^2.0.0"
@@ -1160,13 +1160,20 @@ cross-zip@^4.0.0:
resolved "https://registry.yarnpkg.com/cross-zip/-/cross-zip-4.0.0.tgz#c29bfb2c001659a6d480ae9596f3bee83b48a230" resolved "https://registry.yarnpkg.com/cross-zip/-/cross-zip-4.0.0.tgz#c29bfb2c001659a6d480ae9596f3bee83b48a230"
integrity sha512-MEzGfZo0rqE10O/B+AEcCSJLZsrWuRUvmqJTqHNqBtALhaJc3E3ixLGLJNTRzEA2K34wbmOHC4fwYs9sVsdcCA== integrity sha512-MEzGfZo0rqE10O/B+AEcCSJLZsrWuRUvmqJTqHNqBtALhaJc3E3ixLGLJNTRzEA2K34wbmOHC4fwYs9sVsdcCA==
debug@4.3.4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: debug@^4.1.0, debug@^4.1.1, debug@^4.3.1:
version "4.3.4" version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
dependencies: dependencies:
ms "2.1.2" ms "2.1.2"
debug@~4.3.6:
version "4.3.7"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52"
integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==
dependencies:
ms "^2.1.3"
decompress-response@^6.0.0: decompress-response@^6.0.0:
version "6.0.0" version "6.0.0"
resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc" resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc"
@@ -1230,11 +1237,6 @@ dir-compare@^4.2.0:
minimatch "^3.0.5" minimatch "^3.0.5"
p-limit "^3.1.0 " p-limit "^3.1.0 "
eastasianwidth@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb"
integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==
electron-to-chromium@^1.4.535: electron-to-chromium@^1.4.535:
version "1.4.576" version "1.4.576"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.576.tgz#0c6940fdc0d60f7e34bd742b29d8fa847c9294d1" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.576.tgz#0c6940fdc0d60f7e34bd742b29d8fa847c9294d1"
@@ -1245,16 +1247,16 @@ emittery@^0.13.1:
resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad" resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad"
integrity sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ== integrity sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==
emoji-regex@^10.3.0:
version "10.4.0"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-10.4.0.tgz#03553afea80b3975749cfcb36f776ca268e413d4"
integrity sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==
emoji-regex@^8.0.0: emoji-regex@^8.0.0:
version "8.0.0" version "8.0.0"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
emoji-regex@^9.2.2:
version "9.2.2"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72"
integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==
end-of-stream@^1.1.0: end-of-stream@^1.1.0:
version "1.4.4" version "1.4.4"
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
@@ -1267,6 +1269,11 @@ env-paths@^2.2.0:
resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2"
integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==
environment@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/environment/-/environment-1.1.0.tgz#8e86c66b180f363c7ab311787e0259665f45a9f1"
integrity sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==
error-ex@^1.3.1: error-ex@^1.3.1:
version "1.3.2" version "1.3.2"
resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
@@ -1309,21 +1316,6 @@ eventemitter3@^5.0.1:
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4"
integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA== integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==
execa@8.0.1:
version "8.0.1"
resolved "https://registry.yarnpkg.com/execa/-/execa-8.0.1.tgz#51f6a5943b580f963c3ca9c6321796db8cc39b8c"
integrity sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==
dependencies:
cross-spawn "^7.0.3"
get-stream "^8.0.1"
human-signals "^5.0.0"
is-stream "^3.0.0"
merge-stream "^2.0.0"
npm-run-path "^5.1.0"
onetime "^6.0.0"
signal-exit "^4.1.0"
strip-final-newline "^3.0.0"
execa@^5.0.0: execa@^5.0.0:
version "5.1.1" version "5.1.1"
resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd"
@@ -1339,6 +1331,21 @@ execa@^5.0.0:
signal-exit "^3.0.3" signal-exit "^3.0.3"
strip-final-newline "^2.0.0" strip-final-newline "^2.0.0"
execa@~8.0.1:
version "8.0.1"
resolved "https://registry.yarnpkg.com/execa/-/execa-8.0.1.tgz#51f6a5943b580f963c3ca9c6321796db8cc39b8c"
integrity sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==
dependencies:
cross-spawn "^7.0.3"
get-stream "^8.0.1"
human-signals "^5.0.0"
is-stream "^3.0.0"
merge-stream "^2.0.0"
npm-run-path "^5.1.0"
onetime "^6.0.0"
signal-exit "^4.1.0"
strip-final-newline "^3.0.0"
exit@^0.1.2: exit@^0.1.2:
version "0.1.2" version "0.1.2"
resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c"
@@ -1425,6 +1432,11 @@ get-caller-file@^2.0.5:
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
get-east-asian-width@^1.0.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/get-east-asian-width/-/get-east-asian-width-1.2.0.tgz#5e6ebd9baee6fb8b7b6bd505221065f0cd91f64e"
integrity sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==
get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2: get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2:
version "1.2.2" version "1.2.2"
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.2.tgz#281b7622971123e1ef4b3c90fd7539306da93f3b" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.2.tgz#281b7622971123e1ef4b3c90fd7539306da93f3b"
@@ -1637,6 +1649,13 @@ is-fullwidth-code-point@^4.0.0:
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz#fae3167c729e7463f8461ce512b080a49268aa88" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz#fae3167c729e7463f8461ce512b080a49268aa88"
integrity sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ== integrity sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==
is-fullwidth-code-point@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz#9609efced7c2f97da7b60145ef481c787c7ba704"
integrity sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==
dependencies:
get-east-asian-width "^1.0.0"
is-generator-fn@^2.0.0: is-generator-fn@^2.0.0:
version "2.1.0" version "2.1.0"
resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118"
@@ -2158,43 +2177,43 @@ leven@^3.1.0:
resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2"
integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==
lilconfig@2.1.0: lilconfig@~3.1.2:
version "2.1.0" version "3.1.2"
resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52" resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-3.1.2.tgz#e4a7c3cb549e3a606c8dcc32e5ae1005e62c05cb"
integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ== integrity sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==
lines-and-columns@^1.1.6: lines-and-columns@^1.1.6:
version "1.2.4" version "1.2.4"
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
lint-staged@^15.0.2: lint-staged@^15.2.10:
version "15.0.2" version "15.2.10"
resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-15.0.2.tgz#abef713182ec2770143e40a5d6d0130fe61ed442" resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-15.2.10.tgz#92ac222f802ba911897dcf23671da5bb80643cd2"
integrity sha512-vnEy7pFTHyVuDmCAIFKR5QDO8XLVlPFQQyujQ/STOxe40ICWqJ6knS2wSJ/ffX/Lw0rz83luRDh+ET7toN+rOw== integrity sha512-5dY5t743e1byO19P9I4b3x8HJwalIznL5E1FWYnU6OWw33KxNBSLAc6Cy7F2PsFEO8FKnLwjwm5hx7aMF0jzZg==
dependencies: dependencies:
chalk "5.3.0" chalk "~5.3.0"
commander "11.1.0" commander "~12.1.0"
debug "4.3.4" debug "~4.3.6"
execa "8.0.1" execa "~8.0.1"
lilconfig "2.1.0" lilconfig "~3.1.2"
listr2 "7.0.2" listr2 "~8.2.4"
micromatch "4.0.5" micromatch "~4.0.8"
pidtree "0.6.0" pidtree "~0.6.0"
string-argv "0.3.2" string-argv "~0.3.2"
yaml "2.3.3" yaml "~2.5.0"
listr2@7.0.2: listr2@~8.2.4:
version "7.0.2" version "8.2.4"
resolved "https://registry.yarnpkg.com/listr2/-/listr2-7.0.2.tgz#3aa3e1549dfaf3c57ab5eeaba754da3b87f33063" resolved "https://registry.yarnpkg.com/listr2/-/listr2-8.2.4.tgz#486b51cbdb41889108cb7e2c90eeb44519f5a77f"
integrity sha512-rJysbR9GKIalhTbVL2tYbF2hVyDnrf7pFUZBwjPaMIdadYHmeT+EVi/Bu3qd7ETQPahTotg2WRCatXwRBW554g== integrity sha512-opevsywziHd3zHCVQGAj8zu+Z3yHNkkoYhWIGnq54RrCVwLz0MozotJEDnKsIBLvkfLGN6BLOyAeRrYI0pKA4g==
dependencies: dependencies:
cli-truncate "^3.1.0" cli-truncate "^4.0.0"
colorette "^2.0.20" colorette "^2.0.20"
eventemitter3 "^5.0.1" eventemitter3 "^5.0.1"
log-update "^5.0.1" log-update "^6.1.0"
rfdc "^1.3.0" rfdc "^1.4.1"
wrap-ansi "^8.1.0" wrap-ansi "^9.0.0"
locate-path@^5.0.0: locate-path@^5.0.0:
version "5.0.0" version "5.0.0"
@@ -2208,16 +2227,16 @@ lodash.memoize@4.x:
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==
log-update@^5.0.1: log-update@^6.1.0:
version "5.0.1" version "6.1.0"
resolved "https://registry.yarnpkg.com/log-update/-/log-update-5.0.1.tgz#9e928bf70cb183c1f0c9e91d9e6b7115d597ce09" resolved "https://registry.yarnpkg.com/log-update/-/log-update-6.1.0.tgz#1a04ff38166f94647ae1af562f4bd6a15b1b7cd4"
integrity sha512-5UtUDQ/6edw4ofyljDNcOVJQ4c7OjDro4h3y8e1GQL5iYElYclVHJ3zeWchylvMaKnDbDilC8irOVyexnA/Slw== integrity sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==
dependencies: dependencies:
ansi-escapes "^5.0.0" ansi-escapes "^7.0.0"
cli-cursor "^4.0.0" cli-cursor "^5.0.0"
slice-ansi "^5.0.0" slice-ansi "^7.1.0"
strip-ansi "^7.0.1" strip-ansi "^7.1.0"
wrap-ansi "^8.0.1" wrap-ansi "^9.0.0"
lowercase-keys@^2.0.0: lowercase-keys@^2.0.0:
version "2.0.0" version "2.0.0"
@@ -2279,12 +2298,12 @@ merge-stream@^2.0.0:
resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==
micromatch@4.0.5, micromatch@^4.0.4: micromatch@^4.0.4, micromatch@~4.0.8:
version "4.0.5" version "4.0.8"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202"
integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==
dependencies: dependencies:
braces "^3.0.2" braces "^3.0.3"
picomatch "^2.3.1" picomatch "^2.3.1"
mimic-fn@^2.1.0: mimic-fn@^2.1.0:
@@ -2297,6 +2316,11 @@ mimic-fn@^4.0.0:
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-4.0.0.tgz#60a90550d5cb0b239cca65d893b1a53b29871ecc" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-4.0.0.tgz#60a90550d5cb0b239cca65d893b1a53b29871ecc"
integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw== integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==
mimic-function@^5.0.0:
version "5.0.1"
resolved "https://registry.yarnpkg.com/mimic-function/-/mimic-function-5.0.1.tgz#acbe2b3349f99b9deaca7fb70e48b83e94e67076"
integrity sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==
mimic-response@^1.0.0: mimic-response@^1.0.0:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b"
@@ -2326,6 +2350,11 @@ ms@2.1.2:
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
ms@^2.1.3:
version "2.1.3"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
natural-compare@^1.4.0: natural-compare@^1.4.0:
version "1.4.0" version "1.4.0"
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
@@ -2377,7 +2406,7 @@ once@^1.3.0, once@^1.3.1, once@^1.4.0:
dependencies: dependencies:
wrappy "1" wrappy "1"
onetime@^5.1.0, onetime@^5.1.2: onetime@^5.1.2:
version "5.1.2" version "5.1.2"
resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e"
integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==
@@ -2391,6 +2420,13 @@ onetime@^6.0.0:
dependencies: dependencies:
mimic-fn "^4.0.0" mimic-fn "^4.0.0"
onetime@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/onetime/-/onetime-7.0.0.tgz#9f16c92d8c9ef5120e3acd9dd9957cceecc1ab60"
integrity sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==
dependencies:
mimic-function "^5.0.0"
p-cancelable@^2.0.0: p-cancelable@^2.0.0:
version "2.1.1" version "2.1.1"
resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.1.1.tgz#aab7fbd416582fa32a3db49859c122487c5ed2cf" resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.1.1.tgz#aab7fbd416582fa32a3db49859c122487c5ed2cf"
@@ -2467,7 +2503,7 @@ picomatch@^2.0.4, picomatch@^2.2.3, picomatch@^2.3.1:
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
pidtree@0.6.0: pidtree@~0.6.0:
version "0.6.0" version "0.6.0"
resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.6.0.tgz#90ad7b6d42d5841e69e0a2419ef38f8883aa057c" resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.6.0.tgz#90ad7b6d42d5841e69e0a2419ef38f8883aa057c"
integrity sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g== integrity sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==
@@ -2586,18 +2622,18 @@ responselike@^2.0.0:
dependencies: dependencies:
lowercase-keys "^2.0.0" lowercase-keys "^2.0.0"
restore-cursor@^4.0.0: restore-cursor@^5.0.0:
version "4.0.0" version "5.1.0"
resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-4.0.0.tgz#519560a4318975096def6e609d44100edaa4ccb9" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-5.1.0.tgz#0766d95699efacb14150993f55baf0953ea1ebe7"
integrity sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg== integrity sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==
dependencies: dependencies:
onetime "^5.1.0" onetime "^7.0.0"
signal-exit "^3.0.2" signal-exit "^4.1.0"
rfdc@^1.3.0: rfdc@^1.4.1:
version "1.3.0" version "1.4.1"
resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.4.1.tgz#778f76c4fb731d93414e8f925fbecf64cce7f6ca"
integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== integrity sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==
roarr@^2.15.3: roarr@^2.15.3:
version "2.15.4" version "2.15.4"
@@ -2657,7 +2693,7 @@ shiki@^0.14.7:
vscode-oniguruma "^1.7.0" vscode-oniguruma "^1.7.0"
vscode-textmate "^8.0.0" vscode-textmate "^8.0.0"
signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: signal-exit@^3.0.3, signal-exit@^3.0.7:
version "3.0.7" version "3.0.7"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
@@ -2685,6 +2721,14 @@ slice-ansi@^5.0.0:
ansi-styles "^6.0.0" ansi-styles "^6.0.0"
is-fullwidth-code-point "^4.0.0" is-fullwidth-code-point "^4.0.0"
slice-ansi@^7.1.0:
version "7.1.0"
resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-7.1.0.tgz#cd6b4655e298a8d1bdeb04250a433094b347b9a9"
integrity sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==
dependencies:
ansi-styles "^6.2.1"
is-fullwidth-code-point "^5.0.0"
source-map-support@0.5.13: source-map-support@0.5.13:
version "0.5.13" version "0.5.13"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932"
@@ -2715,7 +2759,7 @@ stack-utils@^2.0.3:
dependencies: dependencies:
escape-string-regexp "^2.0.0" escape-string-regexp "^2.0.0"
string-argv@0.3.2: string-argv@~0.3.2:
version "0.3.2" version "0.3.2"
resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6" resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6"
integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q== integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==
@@ -2737,14 +2781,14 @@ string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
is-fullwidth-code-point "^3.0.0" is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.1" strip-ansi "^6.0.1"
string-width@^5.0.0, string-width@^5.0.1: string-width@^7.0.0:
version "5.1.2" version "7.2.0"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" resolved "https://registry.yarnpkg.com/string-width/-/string-width-7.2.0.tgz#b5bb8e2165ce275d4d43476dd2700ad9091db6dc"
integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== integrity sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==
dependencies: dependencies:
eastasianwidth "^0.2.0" emoji-regex "^10.3.0"
emoji-regex "^9.2.2" get-east-asian-width "^1.0.0"
strip-ansi "^7.0.1" strip-ansi "^7.1.0"
strip-ansi@^6.0.0, strip-ansi@^6.0.1: strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1" version "6.0.1"
@@ -2753,7 +2797,7 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1:
dependencies: dependencies:
ansi-regex "^5.0.1" ansi-regex "^5.0.1"
strip-ansi@^7.0.1: strip-ansi@^7.1.0:
version "7.1.0" version "7.1.0"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45"
integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==
@@ -2868,11 +2912,6 @@ type-fest@^0.21.3:
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37"
integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==
type-fest@^1.0.2:
version "1.4.0"
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-1.4.0.tgz#e9fb813fe3bf1744ec359d55d1affefa76f14be1"
integrity sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==
typedoc@~0.25.13: typedoc@~0.25.13:
version "0.25.13" version "0.25.13"
resolved "https://registry.yarnpkg.com/typedoc/-/typedoc-0.25.13.tgz#9a98819e3b2d155a6d78589b46fa4c03768f0922" resolved "https://registry.yarnpkg.com/typedoc/-/typedoc-0.25.13.tgz#9a98819e3b2d155a6d78589b46fa4c03768f0922"
@@ -2953,14 +2992,14 @@ wrap-ansi@^7.0.0:
string-width "^4.1.0" string-width "^4.1.0"
strip-ansi "^6.0.0" strip-ansi "^6.0.0"
wrap-ansi@^8.0.1, wrap-ansi@^8.1.0: wrap-ansi@^9.0.0:
version "8.1.0" version "9.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-9.0.0.tgz#1a3dc8b70d85eeb8398ddfb1e4a02cd186e58b3e"
integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== integrity sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==
dependencies: dependencies:
ansi-styles "^6.1.0" ansi-styles "^6.2.1"
string-width "^5.0.1" string-width "^7.0.0"
strip-ansi "^7.0.1" strip-ansi "^7.1.0"
wrappy@1: wrappy@1:
version "1.0.2" version "1.0.2"
@@ -2995,10 +3034,10 @@ yallist@^4.0.0:
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
yaml@2.3.3: yaml@~2.5.0:
version "2.3.3" version "2.5.1"
resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.3.tgz#01f6d18ef036446340007db8e016810e5d64aad9" resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.5.1.tgz#c9772aacf62cb7494a95b0c4f1fb065b563db130"
integrity sha512-zw0VAJxgeZ6+++/su5AFoqBbZbrEakwu+X0M5HmcwUiBL7AzcuPKjj5we4xfQLp78LkEMpD0cOnUhmgOVy3KdQ== integrity sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q==
yargs-parser@^21.0.1, yargs-parser@^21.1.1: yargs-parser@^21.0.1, yargs-parser@^21.1.1:
version "21.1.1" version "21.1.1"