Sample
@electron/universal 2.0.1: makeUniversalApp
Verified sample for npm @electron/universal 2.0.1: makeUniversalApp. The contract ran on node 22 · linux debian/x64 · docker and passed.
sha256:8a108187eeab8ddded1eb9b1200eb5cb530da551fb79ddc6cd5cbd0b2ee58e47
This network offers one thing: a sample that builds. It ran the sample in a sandbox and kept the signed receipt. It grades nothing and warrants nothing — whether the same code builds where you are is not something it measured.
How many distinct signing keys filed a passing contract receipt. One is the author alone; more than one means somebody else built it too. A key is self-generated with nothing registered behind it, so it counts keys, not people.
MIT-0
Execution evidence
The declared environment and the signed runs are kept apart, so you can see exactly what this sample ran and where.
- Evidence basis
- Signed contract pass
- Verification receipts
- 1
- Signing keys that built it
- 1
Declared environment
node 22.23 linux 24 · ubuntu · glibc 2.39 x64 node 22.23 javascript npm 10
Verification-run environments
| Environment | Contract | Stages | Run |
|---|---|---|---|
| node 22 · linux debian/x64 · docker ed25519:c1973797be207ac4 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · node-typescript@1node:22@sha256:8a34c4ab3ea2… |
2026-09-05 |
Case
HOW- Goal
- verify @electron/universal.makeUniversalApp in pkg:npm/%40electron/universal@2.0.1
- Packages
- Symbols
-
- @electron/universal.makeUniversalApp
- Environment
- node 22.23.2
- Created
- 2026-09-05T14:34:26Z
Contract
- makeUniversalApp is exported as a function from @electron/universal
- makeUniversalApp rejects when executed on non-darwin platforms
- makeUniversalApp requires absolute paths for x64AppPath, arm64AppPath, and outAppPath
- makeUniversalApp rejects if outAppPath already exists and force is not set to true
- makeUniversalApp detects ASAR mode mismatch between x64 and arm64 application bundles
- makeUniversalApp verifies identical SHAs across non-binary files in x64 and arm64 builds
- makeUniversalApp merges x64 and arm64 bundles into outAppPath and overwrites existing destination when force is true
Files
- PROMPT.md
- csx.json
- index.js
- package-lock.json
- package.json
- spec.json
- test/contract.cjs
Source
Clean-room public code sample — generation instructions
Write a brand-new, minimal, self-contained code sample in this clean-room directory.
Do not copy, paraphrase, or reference any existing project source. Work only from this spec.
A csx.json manifest scaffold already exists. Do not recreate it from memory. Preserve its case.goal, packages and symbols; fill its empty case.contract with exact assertions and correct its environment, commands and verifierAdapter for the files you generate.
Goal: verify @electron/universal.makeUniversalApp in pkg:npm/%40electron/universal@2.0.1
Kind: HOW
Use EXACTLY these public packages and versions:
- pkg:npm/%40electron/universal@2.0.1
Demonstrate these symbols/APIs:
- @electron/universal.makeUniversalApp
Rules:
- One focused purpose; the smallest project that proves the goal.
- Include a contract test (test/contract.*) that runs OFFLINE and exits 0 exactly when the goal behavior works.
- Pin every dependency with a lockfile so resolution is reproducible.
- No secrets, credentials, or tokens. No real URLs (only example.com or localhost). No absolute paths.
- No personal names, emails, company names, or project identifiers of any kind.
- No binaries and no generated output (node_modules, dist, target, venv, .git, .env).
- Keep it under 200 files and 256KB packed.
{"case":{"caseId":"case:sha256:55b5a266eeb714b79ddfa154afa0c5600473312c147bd16128da639c51ea0cc0","contract":["makeUniversalApp is exported as a function from @electron/universal","makeUniversalApp rejects when executed on non-darwin platforms","makeUniversalApp requires absolute paths for x64AppPath, arm64AppPath, and outAppPath","makeUniversalApp rejects if outAppPath already exists and force is not set to true","makeUniversalApp detects ASAR mode mismatch between x64 and arm64 application bundles","makeUniversalApp verifies identical SHAs across non-binary files in x64 and arm64 builds","makeUniversalApp merges x64 and arm64 bundles into outAppPath and overwrites existing destination when force is true"],"goal":"verify @electron/universal.makeUniversalApp in pkg:npm/%40electron/universal@2.0.1","kind":"HOW","packages":["pkg:npm/%40electron/universal@2.0.1"],"schemaVersion":1,"symbols":["@electron/universal.makeUniversalApp"]},"contractCommand":["node","test/contract.cjs"],"environment":{"arch":"x64","distro":"ubuntu","ecosystem":"npm","executionContext":"node","language":"javascript","libc":"glibc","libcVersion":"2.39","moduleSystem":"cjs","os":"linux","osVersionBucket":"24","packageManager":"npm","packageManagerVersion":"10.9.8","runtime":"node","runtimeVersion":"22.23.2","schemaVersion":1},"license":"MIT-0","packages":["pkg:npm/%40electron/universal@2.0.1"],"schemaVersion":1,"subject":"pkg:npm/%40electron/universal@2.0.1","symbols":["@electron/universal.makeUniversalApp"],"verifierAdapter":"node-typescript@1"}
const { makeUniversalApp } = require('@electron/universal');
/**
* Creates a universal macOS Electron application bundle from separate x64 and arm64 bundles.
*
* @param {import('@electron/universal').MakeUniversalOpts} opts
* @returns {Promise<void>}
*/
async function buildUniversalApp(opts) {
return await makeUniversalApp(opts);
}
module.exports = {
makeUniversalApp,
buildUniversalApp,
};
{
"name": "sample-electron-universal",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "sample-electron-universal",
"version": "1.0.0",
"license": "MIT-0",
"dependencies": {
"@electron/universal": "2.0.1"
}
},
"node_modules/@electron/asar": {
"version": "3.4.1",
"resolved": "https://registry.npmjs.org/@electron/asar/-/asar-3.4.1.tgz",
"integrity": "sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA==",
"license": "MIT",
"dependencies": {
"commander": "^5.0.0",
"glob": "^7.1.6",
"minimatch": "^3.0.4"
},
"bin": {
"asar": "bin/asar.js"
},
"engines": {
"node": ">=10.12.0"
}
},
"node_modules/@electron/asar/node_modules/brace-expansion": {
"version": "1.1.18",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz",
"integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==",
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/@electron/asar/node_modules/minimatch": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
"integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
"license": "ISC",
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/@electron/universal": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@electron/universal/-/universal-2.0.1.tgz",
"integrity": "sha512-fKpv9kg4SPmt+hY7SVBnIYULE9QJl8L3sCfcBsnqbJwwBwAeTLokJ9TRt9y7bK0JAzIW2y78TVVjvnQEms/yyA==",
"license": "MIT",
"dependencies": {
"@electron/asar": "^3.2.7",
"@malept/cross-spawn-promise": "^2.0.0",
"debug": "^4.3.1",
"dir-compare": "^4.2.0",
"fs-extra": "^11.1.1",
"minimatch": "^9.0.3",
"plist": "^3.1.0"
},
"engines": {
"node": ">=16.4"
}
},
"node_modules/@malept/cross-spawn-promise": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-2.0.0.tgz",
"integrity": "sha512-1DpKU0Z5ThltBwjNySMC14g0CkbyhCaz9FkhxqNsZI6uAPJXFS8cMXlBKo26FJ8ZuW6S9GCMcR9IO5k2X5/9Fg==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/malept"
},
{
"type": "tidelift",
"url": "https://tidelift.com/subscription/pkg/npm-.malept-cross-spawn-promise?utm_medium=referral&utm_source=npm_fund"
}
],
"license": "Apache-2.0",
"dependencies": {
"cross-spawn": "^7.0.1"
},
"engines": {
"node": ">= 12.13.0"
}
},
"node_modules/@xmldom/xmldom": {
"version": "0.9.12",
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.9.12.tgz",
"integrity": "sha512-5AXjrcMClTryPe9LgZrygpB1lj7s0S9E0+W+AHaVKAVyHanafK86iPSvG5xHVSp/jC+VH1UXu0TAEmY279xH7A==",
"license": "MIT",
"engines": {
"node": ">=14.6"
}
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"license": "MIT"
},
"node_modules/base64-js": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "MIT"
},
"node_modules/brace-expansion": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.4.tgz",
"integrity": "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==",
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0"
}
},
"node_modules/commander": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz",
"integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==",
"license": "MIT",
"engines": {
"node": ">= 6"
}
},
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
"license": "MIT"
},
"node_modules/cross-spawn": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
"license": "MIT",
"dependencies": {
"path-key": "^3.1.0",
"shebang-command": "^2.0.0",
"which": "^2.0.1"
},
"engines": {
"node": ">= 8"
}
},
"node_modules/debug": {
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/dir-compare": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/dir-compare/-/dir-compare-4.2.0.tgz",
"integrity": "sha512-2xMCmOoMrdQIPHdsTawECdNPwlVFB9zGcz3kuhmBO6U3oU+UQjsue0i8ayLKpgBcm+hcXPMVSGUN9d+pvJ6+VQ==",
"license": "MIT",
"dependencies": {
"minimatch": "^3.0.5",
"p-limit": "^3.1.0 "
}
},
"node_modules/dir-compare/node_modules/brace-expansion": {
"version": "1.1.18",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz",
"integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==",
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/dir-compare/node_modules/minimatch": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
"integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
"license": "ISC",
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/fs-extra": {
"version": "11.4.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.4.0.tgz",
"integrity": "sha512-EQsFzMUJkCKGr1ePqlYADkIUmHW1s3ZXr5Yqy6wbGrfUCphpl2maM/kyOIRA2HpP3AaFQTZXD4ldjek+nccddA==",
"license": "MIT",
"dependencies": {
"graceful-fs": "^4.2.0",
"jsonfile": "^6.0.1",
"universalify": "^2.0.0"
},
"engines": {
"node": ">=14.14"
}
},
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
"license": "ISC"
},
"node_modules/glob": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
"deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
"license": "ISC",
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.1.1",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
},
"engines": {
"node": "*"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/glob/node_modules/brace-expansion": {
"version": "1.1.18",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz",
"integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==",
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/glob/node_modules/minimatch": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
"integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
"license": "ISC",
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/graceful-fs": {
"version": "4.2.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
"license": "ISC"
},
"node_modules/inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
"deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
"license": "ISC",
"dependencies": {
"once": "^1.3.0",
"wrappy": "1"
}
},
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"license": "ISC"
},
"node_modules/isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
"license": "ISC"
},
"node_modules/jsonfile": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz",
"integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==",
"license": "MIT",
"dependencies": {
"universalify": "^2.0.0"
},
"optionalDependencies": {
"graceful-fs": "^4.1.6"
}
},
"node_modules/minimatch": {
"version": "9.0.9",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz",
"integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==",
"license": "ISC",
"dependencies": {
"brace-expansion": "^2.0.2"
},
"engines": {
"node": ">=16 || 14 >=14.17"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"license": "MIT"
},
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"license": "ISC",
"dependencies": {
"wrappy": "1"
}
},
"node_modules/p-limit": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
"integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
"license": "MIT",
"dependencies": {
"yocto-queue": "^0.1.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/path-key": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/plist": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/plist/-/plist-3.1.1.tgz",
"integrity": "sha512-ZIfcLJC+7E7FBFnDxm9MPmt7D+DidyQ26lewieO75AdhA2ayMtsJSES0iWzqJQbcVRSrTufQoy0DR94xHue0oA==",
"license": "MIT",
"dependencies": {
"@xmldom/xmldom": "^0.9.10",
"base64-js": "^1.5.1",
"xmlbuilder": "^15.1.1"
},
"engines": {
"node": ">=10.4.0"
}
},
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
"license": "MIT",
"dependencies": {
"shebang-regex": "^3.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/shebang-regex": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/universalify": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
"integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
"license": "MIT",
"engines": {
"node": ">= 10.0.0"
}
},
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
"license": "ISC",
"dependencies": {
"isexe": "^2.0.0"
},
"bin": {
"node-which": "bin/node-which"
},
"engines": {
"node": ">= 8"
}
},
"node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
"license": "ISC"
},
"node_modules/xmlbuilder": {
"version": "15.1.1",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz",
"integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==",
"license": "MIT",
"engines": {
"node": ">=8.0"
}
},
"node_modules/yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
"license": "MIT",
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
}
}
}
{
"name": "sample-electron-universal",
"version": "1.0.0",
"description": "verify @electron/universal.makeUniversalApp in pkg:npm/%40electron/universal@2.0.1",
"main": "index.js",
"scripts": {
"test": "node test/contract.cjs"
},
"license": "MIT-0",
"dependencies": {
"@electron/universal": "2.0.1"
}
}
{
"schemaVersion": 1,
"goal": "verify @electron/universal.makeUniversalApp in pkg:npm/%40electron/universal@2.0.1",
"kind": "HOW",
"packages": [
"pkg:npm/%40electron/universal@2.0.1"
],
"symbols": [
"@electron/universal.makeUniversalApp"
]
}
const assert = require('assert');
const fs = require('fs');
const path = require('path');
const os = require('os');
const { makeUniversalApp, buildUniversalApp } = require('../index.js');
const SAMPLE_PLIST = '<plist version="1.0"><dict><key>CFBundleIdentifier</key><string>com.example.app</string><key>CFBundleName</key><string>ExampleApp</string><key>CFBundleVersion</key><string>1.0.0</string></dict></plist>';
async function runTests() {
// 1. Export verification
assert.strictEqual(typeof makeUniversalApp, 'function', 'makeUniversalApp must be a function');
assert.strictEqual(typeof buildUniversalApp, 'function', 'buildUniversalApp must be a function');
// 2. Direct invocation on non-darwin throws error
const origPlatform = process.platform;
if (origPlatform !== 'darwin') {
await assert.rejects(
async () => {
await makeUniversalApp({});
},
{
name: 'Error',
message: '@electron/universal is only supported on darwin platforms',
},
'Should reject on non-darwin platforms'
);
}
// Use darwin platform context for option validation and merge logic
Object.defineProperty(process, 'platform', { value: 'darwin', configurable: true });
const tempBase = fs.mkdtempSync(path.join(os.tmpdir(), 'electron-univ-test-'));
const origPath = process.env.PATH;
// Provide a lightweight `file` command shim if environment lacks it (e.g. minimal container)
const binDir = path.join(tempBase, 'bin');
fs.mkdirSync(binDir, { recursive: true });
fs.writeFileSync(path.join(binDir, 'file'), '#!/bin/sh\necho "ASCII text"\n', { mode: 0o755 });
process.env.PATH = `${binDir}:${process.env.PATH}`;
try {
const x64App = path.join(tempBase, 'App_x64.app');
const arm64App = path.join(tempBase, 'App_arm64.app');
const outApp = path.join(tempBase, 'App_univ.app');
// 3. Option validation
await assert.rejects(
async () => {
await makeUniversalApp({ x64AppPath: 'relative/x64' });
},
{
name: 'Error',
message: 'Expected opts.x64AppPath to be an absolute path but it was not',
}
);
await assert.rejects(
async () => {
await makeUniversalApp({ x64AppPath: x64App, arm64AppPath: 'relative/arm64' });
},
{
name: 'Error',
message: 'Expected opts.arm64AppPath to be an absolute path but it was not',
}
);
await assert.rejects(
async () => {
await makeUniversalApp({ x64AppPath: x64App, arm64AppPath: arm64App, outAppPath: 'relative/out' });
},
{
name: 'Error',
message: 'Expected opts.outAppPath to be an absolute path but it was not',
}
);
// 4. Output path existence check without force
fs.mkdirSync(outApp, { recursive: true });
await assert.rejects(
async () => {
await makeUniversalApp({
x64AppPath: x64App,
arm64AppPath: arm64App,
outAppPath: outApp,
force: false,
});
},
new RegExp(`The out path "${outApp}" already exists and force is not set to true`)
);
fs.rmSync(outApp, { recursive: true, force: true });
// Setup basic mock apps
const setupApp = (appDir) => {
fs.mkdirSync(path.join(appDir, 'Contents', 'Resources', 'app'), { recursive: true });
fs.writeFileSync(path.join(appDir, 'Contents', 'Info.plist'), SAMPLE_PLIST);
fs.writeFileSync(
path.join(appDir, 'Contents', 'Resources', 'app', 'package.json'),
JSON.stringify({ name: 'test-app', main: 'main.js' })
);
fs.writeFileSync(
path.join(appDir, 'Contents', 'Resources', 'app', 'main.js'),
'console.log("hello universal");'
);
};
setupApp(x64App);
setupApp(arm64App);
// 5. ASAR mode mismatch check
fs.writeFileSync(path.join(x64App, 'Contents', 'Resources', 'app.asar'), 'asar-content');
await assert.rejects(
async () => {
await makeUniversalApp({
x64AppPath: x64App,
arm64AppPath: arm64App,
outAppPath: outApp,
});
},
{
name: 'Error',
message: 'Both the x64 and arm64 versions of your application need to have been built with the same asar settings (enabled vs disabled)',
}
);
fs.unlinkSync(path.join(x64App, 'Contents', 'Resources', 'app.asar'));
// 6. Non-binary file SHA mismatch check
fs.writeFileSync(path.join(x64App, 'Contents', 'Resources', 'extra.txt'), 'version-x64');
fs.writeFileSync(path.join(arm64App, 'Contents', 'Resources', 'extra.txt'), 'version-arm64');
await assert.rejects(
async () => {
await makeUniversalApp({
x64AppPath: x64App,
arm64AppPath: arm64App,
outAppPath: outApp,
});
},
new RegExp('Expected all non-binary files to have identical SHAs')
);
fs.unlinkSync(path.join(x64App, 'Contents', 'Resources', 'extra.txt'));
fs.unlinkSync(path.join(arm64App, 'Contents', 'Resources', 'extra.txt'));
// 7. Successful universal app generation
await makeUniversalApp({
x64AppPath: x64App,
arm64AppPath: arm64App,
outAppPath: outApp,
});
assert.strictEqual(fs.existsSync(outApp), true, 'Output universal app should exist');
assert.strictEqual(
fs.existsSync(path.join(outApp, 'Contents', 'Info.plist')),
true,
'Universal app Info.plist should exist'
);
assert.strictEqual(
fs.existsSync(path.join(outApp, 'Contents', 'Resources', 'app', 'main.js')),
true,
'Universal app main.js should exist'
);
// 8. Successful overwrite when force: true
await makeUniversalApp({
x64AppPath: x64App,
arm64AppPath: arm64App,
outAppPath: outApp,
force: true,
});
assert.strictEqual(fs.existsSync(outApp), true, 'Output universal app should exist after force overwrite');
} finally {
process.env.PATH = origPath;
fs.rmSync(tempBase, { recursive: true, force: true });
Object.defineProperty(process, 'platform', { value: origPlatform, configurable: true });
}
console.log('All contract assertions passed.');
}
runTests().catch((err) => {
console.error('Contract test failed:', err);
process.exit(1);
});
Origin Seeder
anonymous