├── .github ├── CODEOWNERS └── workflows │ ├── publish-npm.yml │ ├── release.yml │ ├── semantic.yml │ └── test.yml ├── .gitignore ├── LICENSE ├── README.md ├── download-mksnapshot.js ├── mksnapshot.js ├── package-lock.json ├── package.json ├── script ├── publish.js └── update-version.js └── test ├── fixtures ├── invalid.js └── snapshot.js └── mksnapshot-test.js /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @electron/wg-releases 2 | -------------------------------------------------------------------------------- /.github/workflows/publish-npm.yml: -------------------------------------------------------------------------------- 1 | name: Publish npm Release 2 | 3 | on: 4 | push: 5 | tags: 6 | - v[0-9]+.[0-9]+.[0-9]+ 7 | 8 | jobs: 9 | test: 10 | uses: ./.github/workflows/test.yml 11 | with: 12 | electron-version: ${{ github.ref_name }} 13 | release: 14 | runs-on: ubuntu-latest 15 | needs: test 16 | environment: npm 17 | permissions: 18 | contents: write # for creating new release 19 | id-token: write # for CFA 20 | steps: 21 | - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 22 | - name: "Use Node.js ${{ matrix.node-version }}" 23 | uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 24 | with: 25 | node-version: "20.16.0" 26 | - name: Update Version 27 | run: node script/update-version.js ${{ github.ref_name }} 28 | - name: Confirm Version Updated 29 | run: node -e "if (require('./package.json').version === '0.0.0-development') process.exit(1)" 30 | - name: Install Dependencies 31 | run: npm ci 32 | - name: Obtain OIDC token 33 | id: oidc 34 | run: | 35 | token=$(curl --fail -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \ 36 | "$ACTIONS_ID_TOKEN_REQUEST_URL&audience=continuousauth.dev" | jq -r '.value') 37 | echo "::add-mask::${token}" 38 | echo "token=${token}" >> $GITHUB_OUTPUT 39 | - name: Obtain GitHub credentials 40 | id: github_creds 41 | run: | 42 | token=$(curl --fail "https://continuousauth.dev/api/request/${{ secrets.CFA_PROJECT_ID }}/github/credentials" \ 43 | -X POST \ 44 | -H "Content-Type: application/json" \ 45 | -H "Authorization: bearer ${{ secrets.CFA_SECRET }}" \ 46 | --data "{\"token\":\"${{ steps.oidc.outputs.token }}\"}" | jq -r '.GITHUB_TOKEN') 47 | echo "::add-mask::${token}" 48 | echo "token=${token}" >> $GITHUB_OUTPUT 49 | - name: Set NPM Credentials 50 | run: echo //registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }} > ~/.npmrc 51 | - name: Check NPM Credentials 52 | run: npm whoami 53 | - name: CFA Publish 54 | env: 55 | CFA_PROJECT_ID: ${{ secrets.CFA_PROJECT_ID }} 56 | CFA_SECRET: ${{ secrets.CFA_SECRET }} 57 | GITHUB_OIDC_TOKEN: ${{ steps.oidc.outputs.token }} 58 | run: node script/publish.js 59 | - name: Create Release 60 | env: 61 | GITHUB_TOKEN: ${{ steps.github_creds.outputs.token }} 62 | run: gh release create ${{ github.ref_name }} -t ${{ github.ref_name }} 63 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release For New Electron Version 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | version: 7 | description: Electron version to use with "v" prefix (e.g. v30.0.0) 8 | required: true 9 | 10 | jobs: 11 | test: 12 | uses: ./.github/workflows/test.yml 13 | with: 14 | electron-version: ${{ github.event.inputs.version }} 15 | tag_new_version: 16 | runs-on: ubuntu-latest 17 | environment: deps-releaser 18 | needs: test 19 | steps: 20 | - name: Generate GitHub App token 21 | uses: electron/github-app-auth-action@384fd19694fe7b6dcc9a684746c6976ad78228ae # v1.1.1 22 | id: generate-token 23 | with: 24 | creds: ${{ secrets.DEPS_RELEASER_GH_APP_CREDS }} 25 | - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 26 | with: 27 | token: ${{ steps.generate-token.outputs.token }} 28 | # Tag here, the publish-npm.yml workflow will trigger on the new tag and do the CFA publish 29 | - name: Push New Tag 30 | run: | 31 | git tag ${{ github.event.inputs.version }} 32 | git push origin ${{ github.event.inputs.version }} 33 | -------------------------------------------------------------------------------- /.github/workflows/semantic.yml: -------------------------------------------------------------------------------- 1 | name: "Check Semantic Commit" 2 | 3 | on: 4 | pull_request: 5 | types: 6 | - opened 7 | - edited 8 | - synchronize 9 | 10 | permissions: 11 | contents: read 12 | 13 | jobs: 14 | main: 15 | permissions: 16 | pull-requests: read # for amannn/action-semantic-pull-request to analyze PRs 17 | statuses: write # for amannn/action-semantic-pull-request to mark status of analyzed PR 18 | name: Validate PR Title 19 | runs-on: ubuntu-latest 20 | steps: 21 | - name: semantic-pull-request 22 | uses: amannn/action-semantic-pull-request@01d5fd8a8ebb9aafe902c40c53f0f4744f7381eb # tag: v5 23 | env: 24 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 25 | with: 26 | validateSingleCommit: false 27 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | electron-version: 7 | required: true 8 | type: string 9 | workflow_dispatch: 10 | schedule: 11 | - cron: '0 19 * * 1-5' 12 | push: 13 | branches: 14 | - main 15 | pull_request: 16 | branches: 17 | - main 18 | 19 | permissions: 20 | contents: read 21 | 22 | jobs: 23 | test: 24 | defaults: 25 | run: 26 | shell: bash 27 | strategy: 28 | matrix: 29 | node-version: 30 | - '20.16.0' 31 | - '18.20.4' 32 | - '16.20.2' 33 | - '14.21.3' 34 | os: 35 | - macos-latest 36 | - ubuntu-latest 37 | - windows-latest 38 | exclude: 39 | - os: macos-latest 40 | node-version: 14.21.3 41 | runs-on: "${{ matrix.os }}" 42 | steps: 43 | - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 44 | - name: "Use Node.js ${{ matrix.node-version }}" 45 | uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 46 | with: 47 | node-version: "${{ matrix.node-version }}" 48 | - name: Update Version 49 | if: ${{ inputs.electron-version != '' }} 50 | run: node script/update-version.js ${{ inputs.electron-version }} 51 | - name: Use Latest Electron Version 52 | if: ${{ inputs.electron-version == '' }} 53 | run: echo "ELECTRON_MKSNAPSHOT_STABLE_FALLBACK=1" >> $GITHUB_ENV 54 | - name: Install Dependencies 55 | run: npm ci 56 | - name: Run Tests 57 | run: | 58 | node --version 59 | npm --version 60 | npm test 61 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | bin 3 | npm-debug.log 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Contributors to the Electron project 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Electron mksnapshot 2 | 3 | [![Test](https://github.com/electron/mksnapshot/actions/workflows/test.yml/badge.svg)](https://github.com/electron/mksnapshot/actions/workflows/test.yml) 4 | [![npm:](https://img.shields.io/npm/v/electron-mksnapshot.svg)](https://www.npmjs.com/package/electron-mksnapshot) 5 |
6 | [![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat)](http://standardjs.com/) 7 | [![license:mit](https://img.shields.io/badge/license-mit-blue.svg)](https://opensource.org/licenses/MIT) 8 |
9 | [![dependencies:?](https://img.shields.io/npm/dm/electron-mksnapshot.svg)](https://www.npmjs.com/package/electron-mksnapshot) 10 | 11 | Simple node module to download the `mksnapshot` binaries compatible with 12 | Electron for creating v8 snapshots. 13 | 14 | The major version of this library tracks the major version of the Electron 15 | versions released. So if you are using Electron `2.0.x` you would want to use 16 | an `electron-mksnapshot` dependency of `~2.0.0` in your `package.json` file. 17 | 18 | ## Using 19 | 20 | ```sh 21 | npm install --save-dev electron-mksnapshot 22 | mksnapshot.js file.js (--output_dir OUTPUT_DIR). 23 | ``` 24 | Running mksnapshot.js will generate both a snapshot_blob.bin and v8_context_snapshot.bin files which 25 | are needed to use custom snapshots in Electron. 26 | If an output directory isn't specified, the current directory will be used. 27 | (Additional mksnapshot args except for --startup_blob are supported, run mksnapshot --help to see options) 28 | 29 | ## Custom Mirror 30 | 31 | You can set the `ELECTRON_MIRROR` or [`NPM_CONFIG_ELECTRON_MIRROR`](https://docs.npmjs.com/misc/config#environment-variables) 32 | environment variables to use a custom base URL for downloading mksnapshot zips. 33 | 34 | ```sh 35 | # Electron mirror for China 36 | ELECTRON_MIRROR="https://npm.taobao.org/mirrors/electron/" 37 | 38 | # Local mirror 39 | # Example of requested URL: http://localhost:8080/1.2.0/mksnapshot-v1.2.0-darwin-x64.zip 40 | ELECTRON_MIRROR="http://localhost:8080/" 41 | ``` 42 | 43 | ## Overriding the version downloaded 44 | 45 | The version downloaded can be overriden by setting the `ELECTRON_CUSTOM_VERSION` environment variable. 46 | 47 | ```sh 48 | # Install mksnapshot for Electron v8.3.0 49 | ELECTRON_CUSTOM_VERSION=8.3.0 npm install 50 | ``` 51 | 52 | ## Generating snapshots for ARM hardware 53 | 54 | If you need to generate snapshots for Linux on 32 bit ARM, Linux on ARM64, or Windows on ARM64 you will need to install a cross arch mksnapshot on an Intel x64 machine. To do so, set the npm config `arch` to the proper arch and then run `npm install --save-dev electron-mksnapshot`. For example: 55 | 56 | ### Linux on ARM64 57 | From an Intel x64 Linux OS run: 58 | ```sh 59 | npm config set arch arm64 60 | npm install --save-dev electron-mksnapshot 61 | ``` 62 | 63 | ### Linux on 32 bit ARM 64 | From an Intel x64 Linux OS run: 65 | ```sh 66 | npm config set arch armv7l 67 | npm install --save-dev electron-mksnapshot 68 | ``` 69 | 70 | ### Windows on ARM (64-bit) 71 | From an Intel x64 Windows OS run: 72 | ```sh 73 | npm config set arch arm64 74 | npm install --save-dev electron-mksnapshot 75 | ``` 76 | 77 | ### macOS on ARM64 78 | On macOS you can either run the cross arch mksnapshot directly on arm64 hardware or if you wish you can generate the snapshot on an Intel X64 macOS hardware via the following: 79 | ```sh 80 | npm config set arch arm64 81 | npm install --save-dev electron-mksnapshot 82 | npm run mksnapshot ABSOLUTE_PATH_TO_FILE/file.js -- --output_dir ABSOLUTE_PATH_TO_OUTPUT_DIR 83 | ``` 84 | -------------------------------------------------------------------------------- /download-mksnapshot.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | const { downloadArtifact } = require('@electron/get') 4 | const extractZip = require('extract-zip') 5 | const versionToDownload = require('./package').version 6 | let archToDownload = process.env.npm_config_arch 7 | 8 | function download (version) { 9 | return downloadArtifact({ 10 | version: version, 11 | artifactName: 'mksnapshot', 12 | platform: process.env.npm_config_platform, 13 | arch: archToDownload, 14 | rejectUnauthorized: process.env.npm_config_strict_ssl === 'true', 15 | quiet: ['info', 'verbose', 'silly', 'http'].indexOf(process.env.npm_config_loglevel) === -1 16 | }) 17 | } 18 | 19 | async function attemptDownload (version) { 20 | // Fall back to latest stable if there is not a stamped version, for tests 21 | if (version === '0.0.0-development') { 22 | if (!process.env.ELECTRON_MKSNAPSHOT_STABLE_FALLBACK) { 23 | console.log('WARNING: mksnapshot in development needs the environment variable ELECTRON_MKSNAPSHOT_STABLE_FALLBACK set') 24 | process.exit(1) 25 | } 26 | 27 | const { ElectronVersions } = require('@electron/fiddle-core') 28 | const versions = await ElectronVersions.create(undefined, { ignoreCache: true }) 29 | version = versions.latestStable.version 30 | } 31 | 32 | if (process.arch.indexOf('arm') === 0 && process.platform !== 'darwin') { 33 | console.log(`WARNING: mksnapshot does not run on ${process.arch}. Download 34 | https://github.com/electron/electron/releases/download/v${version}/mksnapshot-v${version}-${process.platform}-${process.arch}-x64.zip 35 | on a x64 ${process.platform} OS to generate ${archToDownload} snapshots.`) 36 | process.exit(1) 37 | } 38 | 39 | if (archToDownload && archToDownload.indexOf('arm') === 0 && process.platform !== 'darwin') { 40 | archToDownload += '-x64' 41 | } 42 | 43 | try { 44 | const targetFolder = path.join(__dirname, 'bin') 45 | const zipPath = await download(version) 46 | await extractZip(zipPath, { dir: targetFolder }) 47 | const platform = process.env.npm_config_platform || process.platform 48 | if (platform !== 'win32') { 49 | const mksnapshotPath = path.join(__dirname, 'bin', 'mksnapshot') 50 | if (fs.existsSync(mksnapshotPath)) { 51 | fs.chmod(mksnapshotPath, '755', function (error) { 52 | if (error != null) throw error 53 | }) 54 | } 55 | } 56 | } catch (err) { 57 | // attempt to fall back to semver minor 58 | const parts = version.split('.') 59 | const baseVersion = `${parts[0]}.${parts[1]}.0` 60 | 61 | // don't recurse infinitely 62 | if (baseVersion === version) { 63 | throw err 64 | } else { 65 | await attemptDownload(baseVersion) 66 | } 67 | } 68 | } 69 | 70 | attemptDownload(versionToDownload) 71 | -------------------------------------------------------------------------------- /mksnapshot.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const fs = require('fs-extra') 4 | const { spawnSync } = require('child_process') 5 | const path = require('path') 6 | const temp = require('temp').track() 7 | const workingDir = temp.mkdirSync('mksnapshot-workdir') 8 | const crossArchDirs = [ 9 | 'clang_x86_v8_arm', 10 | 'clang_x64_v8_arm64', 11 | 'win_clang_x64' 12 | ] 13 | 14 | function getBinaryPath (binary, binaryPath) { 15 | if (process.platform === 'win32') { 16 | return path.join(binaryPath, `${binary}.exe`) 17 | } else { 18 | return path.join(binaryPath, binary) 19 | } 20 | } 21 | 22 | const args = process.argv.slice(2) 23 | if (args.length === 0 || args.includes('--help')) { 24 | console.log('Usage: mksnapshot file.js (--output_dir OUTPUT_DIR). ' + 25 | 'Additional mksnapshot args except for --startup_blob are supported:') 26 | args.push('--help') 27 | } 28 | const outDirIdx = args.indexOf('--output_dir') 29 | let outputDir = process.cwd() 30 | let mksnapshotArgs = args 31 | if (outDirIdx > -1) { 32 | mksnapshotArgs = args.slice(0, outDirIdx) 33 | if (args.length >= (outDirIdx + 2)) { 34 | outputDir = args[(outDirIdx + 1)] 35 | if (args.length > (outDirIdx + 2)) { 36 | mksnapshotArgs = mksnapshotArgs.concat(args.slice(outDirIdx + 2)) 37 | } 38 | } else { 39 | console.log('Error! Output directory argument given but directory not specified.') 40 | process.exit(1) 41 | } 42 | } 43 | if (args.includes('--startup_blob')) { 44 | console.log('--startup_blob argument not supported. Use --output_dir to specify where to output snapshot_blob.bin') 45 | process.exit(1) 46 | } 47 | 48 | const mksnapshotDir = path.join(__dirname, 'bin') 49 | 50 | // Copy mksnapshot files to temporary working directory because 51 | // v8_context_snapshot_generator expects to run everything from the same 52 | // directory. 53 | fs.copySync(mksnapshotDir, workingDir) 54 | 55 | const argsFile = path.join(mksnapshotDir, 'mksnapshot_args') 56 | let mksnapshotBinaryDir = workingDir 57 | if (fs.existsSync(argsFile)) { 58 | // Use args from args file if it is provided as these match what is used to generate the original snapshot 59 | const mksnapshotArgsFile = fs.readFileSync(argsFile, 'utf8') 60 | const newlineRegEx = /(\r\n|\r|\n)/g 61 | const turboProfileRegEx = /--turbo-profiling/g 62 | const builtinsRegEx = /.*builtins-pgo.*/g 63 | const mksnapshotArgsFromFile = mksnapshotArgsFile.split(newlineRegEx).filter((arg) => { 64 | return (!arg.match(newlineRegEx) && !arg.match(turboProfileRegEx) && !arg.match(builtinsRegEx) && arg !== '') 65 | }) 66 | const mksnapshotBinaryPath = path.parse(mksnapshotArgsFromFile[0]) 67 | if (mksnapshotBinaryPath.dir) { 68 | mksnapshotBinaryDir = path.join(workingDir, mksnapshotBinaryPath.dir) 69 | } 70 | mksnapshotArgs = mksnapshotArgs.concat(mksnapshotArgsFromFile.slice(1)) 71 | } else { 72 | mksnapshotArgs = mksnapshotArgs.concat(['--startup_blob', 'snapshot_blob.bin']) 73 | if (!mksnapshotArgs.includes('--turbo_instruction_scheduling')) { 74 | mksnapshotArgs.push('--turbo_instruction_scheduling') 75 | } 76 | if (!fs.existsSync(getBinaryPath('mksnapshot', mksnapshotBinaryDir))) { 77 | const matchingDir = crossArchDirs.find((crossArchDir) => { 78 | const candidatePath = path.join(mksnapshotBinaryDir, crossArchDir) 79 | if (fs.existsSync(getBinaryPath('mksnapshot', candidatePath))) { 80 | return true 81 | } 82 | }) 83 | if (matchingDir) { 84 | mksnapshotBinaryDir = path.join(workingDir, matchingDir) 85 | } else { 86 | console.log('ERROR: Could not find mksnapshot') 87 | process.exit(1) 88 | } 89 | } 90 | } 91 | 92 | const options = { 93 | cwd: mksnapshotBinaryDir, 94 | env: process.env, 95 | stdio: 'inherit' 96 | } 97 | 98 | const mksnapshotCommand = getBinaryPath('mksnapshot', mksnapshotBinaryDir) 99 | const mksnapshotProcess = spawnSync(mksnapshotCommand, mksnapshotArgs, options) 100 | if (mksnapshotProcess.status !== 0) { 101 | let code = mksnapshotProcess.status 102 | if (code == null) { 103 | code = 1 104 | } 105 | console.log('Error running mksnapshot.') 106 | process.exit(code) 107 | } 108 | if (args.includes('--help')) { 109 | process.exit(0) 110 | } 111 | 112 | fs.copyFileSync(path.join(mksnapshotBinaryDir, 'snapshot_blob.bin'), 113 | path.join(outputDir, 'snapshot_blob.bin')) 114 | 115 | const v8ContextGenCommand = getBinaryPath('v8_context_snapshot_generator', mksnapshotBinaryDir) 116 | let v8ContextFile = 'v8_context_snapshot.bin' 117 | if (process.platform === 'darwin') { 118 | const targetArch = process.env.npm_config_arch || process.arch 119 | if (targetArch === 'arm64') { 120 | v8ContextFile = 'v8_context_snapshot.arm64.bin' 121 | } else { 122 | v8ContextFile = 'v8_context_snapshot.x86_64.bin' 123 | } 124 | } 125 | const v8ContextGenArgs = [ 126 | `--output_file=${path.join(outputDir, v8ContextFile)}` 127 | ] 128 | 129 | const v8ContextGenOptions = { 130 | cwd: mksnapshotDir, 131 | env: process.env, 132 | stdio: 'inherit' 133 | } 134 | const v8ContextGenProcess = spawnSync(v8ContextGenCommand, v8ContextGenArgs, v8ContextGenOptions) 135 | if (v8ContextGenProcess.status !== 0) { 136 | console.log('Error running the v8 context snapshot generator.', v8ContextGenProcess) 137 | process.exit(v8ContextGenProcess.status) 138 | } 139 | process.exit(0) 140 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "electron-mksnapshot", 3 | "version": "0.0.0-development", 4 | "description": "Electron version of the mksnapshot binary", 5 | "repository": "https://github.com/electron/mksnapshot", 6 | "bin": { 7 | "mksnapshot": "./mksnapshot.js" 8 | }, 9 | "files": [ 10 | "./download-mksnapshot.js", 11 | "./mksnapshot.js" 12 | ], 13 | "scripts": { 14 | "mksnapshot": "node ./mksnapshot.js", 15 | "install": "node ./download-mksnapshot.js", 16 | "test": "mocha && standard" 17 | }, 18 | "license": "MIT", 19 | "dependencies": { 20 | "@electron/get": "^2.0.1", 21 | "extract-zip": "^2.0.0", 22 | "fs-extra": "^7.0.1", 23 | "temp": "^0.8.3" 24 | }, 25 | "devDependencies": { 26 | "@continuous-auth/client": "^2.3.0", 27 | "@electron/fiddle-core": "^1.3.0", 28 | "mocha": "^10.1.0", 29 | "semver": "^7.3.8", 30 | "standard": "^14.3.1" 31 | }, 32 | "standard": { 33 | "ignore": [ 34 | "test/fixtures" 35 | ] 36 | }, 37 | "engines": { 38 | "node": ">=10.5.0" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /script/publish.js: -------------------------------------------------------------------------------- 1 | // Publish the package in the CWD with an OTP code from CFA 2 | const { getOtp } = require('@continuous-auth/client') 3 | const { spawnSync } = require('child_process') 4 | 5 | async function publish () { 6 | const { status } = spawnSync('npm', ['publish', '--provenance', '--otp', await getOtp()]) 7 | process.exit(status) 8 | } 9 | 10 | publish() 11 | -------------------------------------------------------------------------------- /script/update-version.js: -------------------------------------------------------------------------------- 1 | const { promises: fs } = require('fs') 2 | const path = require('path') 3 | 4 | const versionFormat = /^(\d+\.)(\d+\.)(\d+)$/ 5 | 6 | const normalizeVersion = (version = '') => { 7 | return version.startsWith('v') ? version.slice(1) : version 8 | } 9 | 10 | async function updateVersion () { 11 | const version = normalizeVersion(process.argv[2]) 12 | if (!versionFormat.test(version)) { 13 | console.error(`Unsupported version ${version} - only major, minor, and patch releases are currently supported`) 14 | return 15 | } 16 | 17 | const PJ_PATH = path.join(__dirname, '..', 'package.json') 18 | const pj = require(PJ_PATH) 19 | 20 | const PJLOCK_PATH = path.join(__dirname, '..', 'package-lock.json') 21 | const pjLock = require(PJLOCK_PATH) 22 | 23 | try { 24 | pj.version = version 25 | await fs.writeFile(PJ_PATH, JSON.stringify(pj, null, 2)) 26 | console.log(`Updated package.json version to ${version}`) 27 | 28 | pjLock.version = version 29 | await fs.writeFile(PJLOCK_PATH, JSON.stringify(pjLock, null, 2)) 30 | console.log(`Updated package-lock.json version to ${version}`) 31 | } catch (e) { 32 | console.error('Failed to update mksnapshot version: ', e) 33 | process.exit(1) 34 | } 35 | } 36 | 37 | updateVersion() 38 | -------------------------------------------------------------------------------- /test/fixtures/invalid.js: -------------------------------------------------------------------------------- 1 | 1}2{3 2 | -------------------------------------------------------------------------------- /test/fixtures/snapshot.js: -------------------------------------------------------------------------------- 1 | var foo = function () { 2 | return 'bar' 3 | } 4 | -------------------------------------------------------------------------------- /test/mksnapshot-test.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert') 2 | var ChildProcess = require('child_process') 3 | var fs = require('fs') 4 | var path = require('path') 5 | var temp = require('temp').track() 6 | 7 | var describe = global.describe 8 | var it = global.it 9 | 10 | describe('mksnapshot binary', function () { 11 | this.timeout(30000) 12 | 13 | it('creates a snapshot for a valid file', function (done) { 14 | var tempDir = temp.mkdirSync('mksnapshot-') 15 | var outputFile = path.join(tempDir, 'snapshot_blob.bin') 16 | let v8ContextFileName = 'v8_context_snapshot.bin' 17 | if (process.platform === 'darwin') { 18 | const targetArch = process.env.npm_config_arch || process.arch 19 | if (targetArch === 'arm64') { 20 | v8ContextFileName = 'v8_context_snapshot.arm64.bin' 21 | } else { 22 | v8ContextFileName = 'v8_context_snapshot.x86_64.bin' 23 | } 24 | } 25 | var v8ContextFile = path.join(tempDir, v8ContextFileName) 26 | var args = [ 27 | path.join(__dirname, '..', 'mksnapshot.js'), 28 | path.join(__dirname, 'fixtures', 'snapshot.js'), 29 | '--output_dir', 30 | tempDir 31 | ] 32 | var mksnapshot = ChildProcess.spawn(process.execPath, args) 33 | 34 | var output = '' 35 | mksnapshot.stdout.on('data', function (data) { output += data }) 36 | mksnapshot.stderr.on('data', function (data) { output += data }) 37 | 38 | mksnapshot.on('close', function (code) { 39 | if (code !== 0) { 40 | console.log('Error calling mksnapshot', output) 41 | } 42 | assert.strictEqual(typeof code, 'number', 'Exit code is a number') 43 | assert.strictEqual(code, 0, 'Exit code is not zero') 44 | assert.strictEqual(output.indexOf('Loading script for embedding'), 0, output, 'Output is correct') 45 | assert.strictEqual(fs.existsSync(outputFile), true, 'Output file exists.') 46 | assert.strictEqual(fs.existsSync(v8ContextFile), true, 'V8 context file exists.') 47 | done() 48 | }) 49 | 50 | mksnapshot.on('error', function (code) { 51 | console.log('error Output is', output) 52 | done() 53 | }) 54 | }) 55 | 56 | it('fails for invalid JavaScript files', function (done) { 57 | var tempDir = temp.mkdirSync('mksnapshot-') 58 | var outputFile = path.join(tempDir, 'snapshot_blob.bin') 59 | var v8ContextFile = path.join(tempDir, 'v8_context_snapshot.bin') 60 | var args = [ 61 | path.join(__dirname, '..', 'mksnapshot.js'), 62 | path.join(__dirname, 'fixtures', 'invalid.js'), 63 | '--output_dir', 64 | tempDir 65 | ] 66 | var mksnapshot = ChildProcess.spawn(process.execPath, args) 67 | 68 | var output = '' 69 | mksnapshot.stdout.on('data', function (data) { output += data }) 70 | mksnapshot.stderr.on('data', function (data) { output += data }) 71 | 72 | mksnapshot.on('close', function (code) { 73 | assert.strictEqual(typeof code, 'number', 'Exit code is a number') 74 | assert.notStrictEqual(code, 0, 'Exit code is not zero') 75 | assert.notStrictEqual(output.indexOf('Error running mksnapshot.'), -1, 'Output has error message') 76 | assert.strictEqual(fs.existsSync(outputFile), false, 'Output file does not exist.') 77 | assert.strictEqual(fs.existsSync(v8ContextFile), false, 'V8 context file does not exist.') 78 | done() 79 | }) 80 | 81 | mksnapshot.on('error', function (code) { 82 | console.log('error Output is', output) 83 | done() 84 | }) 85 | }) 86 | }) 87 | --------------------------------------------------------------------------------