gdx 0.4.5 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gdx",
3
- "version": "0.4.5",
3
+ "version": "0.5.0",
4
4
  "description": "Git, but with better DX. The raw power of Git, aligned with human workflows.",
5
5
  "homepage": "https://github.com/Type-Delta/gdx#readme",
6
6
  "bugs": {
@@ -25,12 +25,13 @@
25
25
  "files": [
26
26
  "dist/*.js",
27
27
  "dist/workers/*.js",
28
+ "dist/diagnostics/*.js",
28
29
  "scripts/postinstall.cjs",
29
30
  "scripts/launcher.cjs",
30
31
  "README.md",
31
32
  "LICENSE"
32
33
  ],
33
- "packageManager": "bun@1.3.10",
34
+ "packageManager": "bun@1.3.14",
34
35
  "scripts": {
35
36
  "prepare-dev": "bun i && bun run transpile-esm",
36
37
  "start": "bun run src/index.ts",
@@ -38,11 +39,17 @@
38
39
  "start:node": "tsx src/index.ts",
39
40
  "transpile-esm": "bunx tsc -p lib/tsconfig.json && bun run scripts/transform-tools.mjs",
40
41
  "check": "bun run ts-check && bun run lint && bun run build",
41
- "lint": "bun run ts-check && eslint src --ext .ts -c eslint.config.ts --fix",
42
- "test": "bun test",
43
- "build": "bun run transpile-esm && bun build ./src/index.ts --outfile=./bin/gdx --compile --bytecode --production --keep-names",
42
+ "lint": "bun run ts-check && eslint src --ext .ts -c eslint.config.ts",
43
+ "lint:fix": "bun run ts-check && eslint src --ext .ts -c eslint.config.ts --fix",
44
+ "test:serial": "bun test",
45
+ "test": "bun test --parallel --timeout 20000",
46
+ "build": "bun run transpile-esm && bun run build:diagnostics:bin && GDX_BUILD=$(git describe --tags --always --dirty) bun build ./src/index.ts --env='GDX_BUILD*' --outfile=./bin/gdx --compile --bytecode --production --keep-names",
47
+ "build:release:win32-x64": "bun run transpile-esm && bun run build:diagnostics:bin && GDX_BUILD=$(git describe --tags --always --dirty) bun build ./src/index.ts --env='GDX_BUILD*' --outfile=./bin/gdx-win32-x64.exe --compile --bytecode --production --keep-names",
48
+ "build:diagnostics:bin": "bun build ./test/postinstall.validator.ts --outfile=./bin/diagnostics/postinstall.validator.js --target=bun --format=esm --production --minify --keep-names",
49
+ "build:diagnostics:node": "bun build ./test/postinstall.validator.ts --outfile=./dist/diagnostics/postinstall.validator.js --target=node --format=esm --production --minify --keep-names",
44
50
  "ts-check": "bunx tsc --noEmit",
45
- "package:node": "bun run transpile-esm && bun build ./src/index.ts --outdir=./dist --target=node --external=keytar --external=cspell-lib --external=@shikijs/cli --external=yaml --external=openai --external=fflate --format=esm --production --keep-names && bun build ./src/workers/generic.worker.ts --outfile=./dist/workers/generic.worker.min.js --target=node --external=@shikijs/cli --format=esm --production --minify --keep-names",
51
+ "package:node": "bun run transpile-esm && GDX_BUILD=$(git describe --tags --always --dirty) bun build ./src/index.ts --env='GDX_BUILD*' --outdir=./dist --target=node --external=keytar --external=cspell-lib --external=@shikijs/cli --external=shiki --external=yaml --external=openai --external=fflate --external=diff --external=@leeoniya/ufuzzy --format=esm --production --keep-names && bun build ./src/workers/generic.worker.ts --outfile=./dist/workers/generic.worker.min.js --target=node --external=@shikijs/cli --format=esm --production --minify --keep-names && bun run build:diagnostics:node",
52
+ "publish:npm": "npm login && npm publish --access public",
46
53
  "prepack": "bun run package:node",
47
54
  "postinstall": "node scripts/postinstall.cjs",
48
55
  "prettier": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\" \"./*.md\"",
@@ -56,13 +63,14 @@
56
63
  "@babel/core": "^7.29.0",
57
64
  "@babel/preset-env": "^7.29.5",
58
65
  "@babel/preset-typescript": "^7.28.5",
59
- "@eslint/js": "^9.39.4",
66
+ "@eslint/js": "^10.0.1",
60
67
  "@sinclair/typebox": "^0.34.49",
61
68
  "@types/chai": "^5.2.3",
62
69
  "@types/ini": "^4.1.1",
70
+ "@types/which": "^3.0.4",
63
71
  "@typescript-eslint/eslint-plugin": "^8.59.4",
64
72
  "@typescript-eslint/parser": "^8.59.4",
65
- "bun-types": "latest",
73
+ "bun-types": "1.3.14",
66
74
  "chai": "^6.2.2",
67
75
  "dedent": "^1.7.2",
68
76
  "eslint": "^10.4.0",
@@ -73,11 +81,14 @@
73
81
  "smol-toml": "^1.6.1",
74
82
  "tinybench": "^6.0.2",
75
83
  "tsx": "^4.22.3",
84
+ "tty-strings": "^1.5.2",
76
85
  "typescript": "^6.0.3",
77
86
  "typescript-eslint": "^8.59.4",
78
- "unicode-animations": "^1.0.3"
87
+ "unicode-animations": "^1.0.3",
88
+ "which": "2.0.2"
79
89
  },
80
90
  "dependencies": {
91
+ "@leeoniya/ufuzzy": "^1.0.19",
81
92
  "@shikijs/cli": "^4.1.0",
82
93
  "cspell-lib": "10.0.0",
83
94
  "diff": "^9.0.0",
@@ -85,5 +96,9 @@
85
96
  "keytar": "^7.9.0",
86
97
  "openai": "^6.38.0",
87
98
  "yaml": "^2.9.0"
99
+ },
100
+ "patchedDependencies": {
101
+ "tty-strings@1.5.2": "patches/tty-strings@1.5.2.patch",
102
+ "execa@9.6.1": "patches/execa@9.6.1.patch"
88
103
  }
89
104
  }
@@ -6,32 +6,55 @@ const fs = require('fs');
6
6
  const path = require('path');
7
7
  const { spawn } = require('child_process');
8
8
 
9
- const DIST_DIR = path.join(__dirname, '../dist');
10
- const NATIVE_DIR = path.join(DIST_DIR, 'native');
11
- const isWin = process.platform === 'win32';
12
- const binaryName = isWin ? 'gdx.exe' : 'gdx';
13
- const binaryPath = path.join(NATIVE_DIR, binaryName);
14
-
15
- // Check if native binary exists
16
- if (fs.existsSync(binaryPath)) {
17
- const child = spawn(binaryPath, process.argv.slice(2), {
18
- stdio: 'inherit'
19
- });
20
-
21
- child.on('close', (code) => {
22
- process.exit(code);
23
- });
24
-
25
- child.on('error', (err) => {
26
- console.error('Failed to start native binary:', err);
27
- process.exit(1);
28
- });
29
- } else {
30
- // Fallback to Node.js runtime (dist/index.js)
31
- // Since dist/index.js is ESM, we use dynamic import
32
- const jsEntry = path.join(DIST_DIR, 'index.js');
33
- import(require('url').pathToFileURL(jsEntry)).catch(err => {
34
- console.error('Failed to load JS fallback:', err);
35
- process.exit(1);
36
- });
37
- }
9
+ const DIST_DIR = path.join(__dirname, '../dist');
10
+ const NATIVE_DIR = path.join(__dirname, '../bin/native');
11
+ const isWin = process.platform === 'win32';
12
+ const binaryName = isWin ? 'gdx.exe' : 'gdx';
13
+
14
+ if (
15
+ (process.env.GDX_RUNTIME_SHIM === '1' || process.env.GDX_NODE_SHIM === '1') &&
16
+ process.argv[2] === '--'
17
+ ) {
18
+ process.argv.splice(2, 1);
19
+ }
20
+
21
+ function getNativeBinaryPath() {
22
+ return path.join(NATIVE_DIR, binaryName);
23
+ }
24
+
25
+ function runLauncher() {
26
+ const binaryPath = getNativeBinaryPath();
27
+
28
+ // Check if native binary exists
29
+ if (fs.existsSync(binaryPath)) {
30
+ const child = spawn(binaryPath, process.argv.slice(2), {
31
+ stdio: 'inherit'
32
+ });
33
+
34
+ child.on('close', (code) => {
35
+ process.exit(code);
36
+ });
37
+
38
+ child.on('error', (err) => {
39
+ console.error('Failed to start native binary:', err);
40
+ process.exit(1);
41
+ });
42
+ } else {
43
+ // Fallback to Node.js runtime (dist/index.js)
44
+ // Since dist/index.js is ESM, we use dynamic import
45
+ const jsEntry = path.join(DIST_DIR, 'index.js');
46
+ import(require('url').pathToFileURL(jsEntry)).catch(err => {
47
+ console.error('Failed to load JS fallback:', err);
48
+ process.exit(1);
49
+ });
50
+ }
51
+ }
52
+
53
+ if (require.main === module) {
54
+ runLauncher();
55
+ }
56
+
57
+ module.exports = {
58
+ getNativeBinaryPath,
59
+ runLauncher,
60
+ };
@@ -2,10 +2,12 @@
2
2
  /* eslint-disable @typescript-eslint/no-require-imports */
3
3
  const fs = require('fs');
4
4
  const path = require('path');
5
+ const crypto = require('crypto');
5
6
  const { spawnSync, execFileSync } = require('child_process');
6
7
 
7
8
  // Configuration
8
9
  const PACKAGE_JSON_PATH = path.join(__dirname, '../package.json');
10
+ const PACKAGE_DIR = path.join(__dirname, '..');
9
11
  const BIN_DIR = path.join(__dirname, '../bin');
10
12
  const NATIVE_DIR = path.join(BIN_DIR, 'native');
11
13
  const PKG_SRC_PATH = path.join(__dirname, '../dist/index.js');
@@ -33,9 +35,39 @@ function error(message) {
33
35
  }
34
36
 
35
37
  function writeInstallInfo(info) {
38
+ ensureBinDir();
36
39
  fs.writeFileSync(INSTALL_INFO_PATH, JSON.stringify(info, null, 2));
37
40
  }
38
41
 
42
+ function getNativeBinaryName(platform = process.platform) {
43
+ return platform === 'win32' ? 'gdx.exe' : 'gdx';
44
+ }
45
+
46
+ function getNativeBuildArgs(finalPath) {
47
+ return [
48
+ 'build',
49
+ PKG_SRC_PATH,
50
+ `--outfile=${finalPath}`,
51
+ '--compile',
52
+ '--bytecode',
53
+ '--production',
54
+ '--keep-names',
55
+ ];
56
+ }
57
+
58
+ function createInstallInfo(mode, finalPath, useNativeShim) {
59
+ return {
60
+ mode,
61
+ platform: process.platform,
62
+ arch: process.arch,
63
+ version: getPackageVersion(),
64
+ userAgent: process.env.npm_config_user_agent || null,
65
+ useNativeShim,
66
+ ts: (new Date).toLocaleString(),
67
+ binaryPath: finalPath
68
+ };
69
+ }
70
+
39
71
  function isTruthy(v) {
40
72
  return v === '1' || v === 'true' || v === 'yes';
41
73
  }
@@ -49,11 +81,10 @@ function getPrefixFromEnvOrNpm() {
49
81
  const npmExecPath = process.env.npm_execpath;
50
82
  if (!npmExecPath) return null;
51
83
 
52
- const prefix = execFileSync(
53
- `"${npmExecPath}"`,
54
- ['config', 'get', 'prefix'],
55
- { encoding: 'utf8', shell: true }
56
- ).trim();
84
+ const prefix = execFileSync(npmExecPath, ['config', 'get', 'prefix'], {
85
+ encoding: 'utf8',
86
+ shell: false,
87
+ }).trim();
57
88
 
58
89
  return prefix || null;
59
90
  }
@@ -64,7 +95,10 @@ async function checkUrlExists(url) {
64
95
  const res = await fetch(url, { method: 'HEAD', redirect: 'follow' });
65
96
  return res.ok;
66
97
  } catch (err) {
67
- throw new Error(`Network error while checking prebuilt availability: ${err.message} (${url})`);
98
+ throw new Error(
99
+ `Network error while checking prebuilt availability: ${err.message} (${url})`,
100
+ { cause: err }
101
+ );
68
102
  }
69
103
  }
70
104
 
@@ -74,13 +108,38 @@ async function downloadFile(url, tmpPath, destPath) {
74
108
  throw new Error(`Failed to download: ${res.statusText} (${url})`);
75
109
  }
76
110
 
77
- const fileStream = fs.createWriteStream(destPath);
111
+ const fileStream = fs.createWriteStream(tmpPath);
78
112
  const stream = require('stream');
79
113
  const { promisify } = require('util');
80
114
  const pipeline = promisify(stream.pipeline);
81
115
 
82
116
  await pipeline(res.body, fileStream);
83
- fs.renameSync(tmpPath, destPath);
117
+ if (tmpPath !== destPath) {
118
+ fs.renameSync(tmpPath, destPath);
119
+ }
120
+ }
121
+
122
+ function readSha256FromText(text, assetName) {
123
+ const trimmed = text.trim();
124
+ const match = trimmed.match(/\b([a-fA-F0-9]{64})\b/);
125
+ if (!match) {
126
+ throw new Error(`Invalid SHA256 checksum for ${assetName}.`);
127
+ }
128
+ return match[1].toLowerCase();
129
+ }
130
+
131
+ function sha256File(filePath) {
132
+ return crypto.createHash('sha256').update(fs.readFileSync(filePath)).digest('hex');
133
+ }
134
+
135
+ function verifySha256(filePath, checksumText, assetName) {
136
+ const expected = readSha256FromText(checksumText, assetName);
137
+ const actual = sha256File(filePath);
138
+ if (actual !== expected) {
139
+ throw new Error(
140
+ `Checksum mismatch for ${assetName}. Expected ${expected}, got ${actual}.`
141
+ );
142
+ }
84
143
  }
85
144
 
86
145
  function setExecutable(filePath) {
@@ -90,10 +149,59 @@ function setExecutable(filePath) {
90
149
  }
91
150
 
92
151
  function writeFileExecutable(filePath, content) {
152
+ // Remove any existing entry first. npm links bin entries as symlinks
153
+ // (e.g. <bindir>/gdx -> ../gdx/scripts/launcher.cjs); writing without
154
+ // unlinking would follow that symlink and overwrite its target
155
+ // (launcher.cjs) with shim content instead of replacing the bin entry.
156
+ // fs.rmSync unlinks the symlink itself; force ignores a missing path.
157
+ fs.rmSync(filePath, { force: true });
93
158
  fs.writeFileSync(filePath, content, { encoding: 'utf8' });
94
159
  setExecutable(filePath);
95
160
  }
96
161
 
162
+ function buildRuntimeShimContents(runtimeAbsPath, launcherAbsPath) {
163
+ return {
164
+ cmd: [
165
+ '@echo off',
166
+ 'set "GDX_RUNTIME_SHIM=1"',
167
+ `"${runtimeAbsPath}" "${launcherAbsPath}" -- %*`,
168
+ 'exit /b %ERRORLEVEL%',
169
+ ''
170
+ ].join('\r\n'),
171
+ ps1: [
172
+ '$env:GDX_RUNTIME_SHIM = "1"',
173
+ `& "${runtimeAbsPath}" "${launcherAbsPath}" -- @args`,
174
+ 'exit $LASTEXITCODE',
175
+ ''
176
+ ].join('\r\n'),
177
+ sh: [
178
+ '#!/usr/bin/env sh',
179
+ 'export GDX_RUNTIME_SHIM=1',
180
+ `exec "${runtimeAbsPath}" "${launcherAbsPath}" -- "$@"`,
181
+ ''
182
+ ].join('\n'),
183
+ };
184
+ }
185
+
186
+ function getLocalNodeModulesBinDir() {
187
+ return path.resolve(PACKAGE_DIR, '..', '.bin');
188
+ }
189
+
190
+ function overwriteRuntimeShim(binDir, launcherAbsPath, runtime) {
191
+ if (!binDir || !fs.existsSync(binDir)) return false;
192
+
193
+ const shims = buildRuntimeShimContents(runtime.executable, launcherAbsPath);
194
+
195
+ if (process.platform === 'win32') {
196
+ writeFileExecutable(path.join(binDir, 'gdx.cmd'), shims.cmd);
197
+ writeFileExecutable(path.join(binDir, 'gdx.ps1'), shims.ps1);
198
+ return true;
199
+ }
200
+
201
+ writeFileExecutable(path.join(binDir, 'gdx'), shims.sh);
202
+ return true;
203
+ }
204
+
97
205
  function getNpmGlobalBinDir() {
98
206
  if (!isTruthy(process.env.npm_config_global)) return null;
99
207
 
@@ -116,7 +224,7 @@ function overwriteGlobalShim(nativeAbsPath) {
116
224
 
117
225
  if (!(process.env.npm_config_user_agent || '').includes('npm/')) {
118
226
  log('Non-npm global install detected; skipping global shim overwrite.');
119
- log('This may result in overhead introduced by the Node.js launch script.');
227
+ log('This may result in overhead introduced by the JavaScript launch script.');
120
228
  return false;
121
229
  }
122
230
 
@@ -156,6 +264,49 @@ function overwriteGlobalShim(nativeAbsPath) {
156
264
  return true;
157
265
  }
158
266
 
267
+ function findRuntimeExecutable(name, platform = process.platform) {
268
+ const locator = platform === 'win32' ? 'where.exe' : 'which';
269
+ const located = spawnSync(locator, [name], {
270
+ encoding: 'utf8',
271
+ windowsHide: true,
272
+ });
273
+ if (located.error || located.status !== 0) return null;
274
+
275
+ for (const executable of String(located.stdout || '').split(/\r?\n/).filter(Boolean)) {
276
+ const needsShell = platform === 'win32' && /\.(?:cmd|bat)$/i.test(executable);
277
+ const probe = spawnSync(
278
+ executable,
279
+ ['-e', "require('path');process.stdout.write('gdx-runtime')"],
280
+ {
281
+ encoding: 'utf8',
282
+ shell: needsShell,
283
+ windowsHide: true,
284
+ }
285
+ );
286
+ if (!probe.error && probe.status === 0 && probe.stdout === 'gdx-runtime') return executable;
287
+ }
288
+ return null;
289
+ }
290
+
291
+ function selectFallbackRuntime(findExecutable = findRuntimeExecutable) {
292
+ for (const name of ['bun']) { // FIXME: waiting to runtimes with latency lower than Bun's
293
+ const executable = findExecutable(name);
294
+ if (executable) return { name, executable };
295
+ }
296
+ return { name: 'node', executable: process.execPath };
297
+ }
298
+
299
+ function installRuntimeFallbackShims(runtime) {
300
+ const launcherAbsPath = path.join(__dirname, 'launcher.cjs');
301
+ const localBin = getLocalNodeModulesBinDir();
302
+ const globalBin = getNpmGlobalBinDir();
303
+
304
+ return {
305
+ local: overwriteRuntimeShim(localBin, launcherAbsPath, runtime),
306
+ global: overwriteRuntimeShim(globalBin, launcherAbsPath, runtime),
307
+ };
308
+ }
309
+
159
310
  async function tryDownloadPrebuilt() {
160
311
  const version = getPackageVersion();
161
312
  const platform = process.platform;
@@ -169,6 +320,7 @@ async function tryDownloadPrebuilt() {
169
320
  const ext = platform === 'win32' ? '.exe' : '';
170
321
  const assetName = `gdx-${platform}-${arch}${ext}`;
171
322
  const url = `${PREBUILT_BASE_URL}/v${version}/${assetName}`;
323
+ const checksumUrl = `${url}.sha256`;
172
324
 
173
325
  log(`Checking availability of prebuilt binary: ${url}`);
174
326
  const exists = await checkUrlExists(url);
@@ -178,11 +330,21 @@ async function tryDownloadPrebuilt() {
178
330
 
179
331
  log(`Downloading prebuilt binary...`);
180
332
  const tmpPath = path.join(NATIVE_DIR, `${assetName}.tmp`);
333
+ const checksumTmpPath = path.join(NATIVE_DIR, `${assetName}.sha256.tmp`);
334
+ const checksumPath = path.join(NATIVE_DIR, `${assetName}.sha256`);
181
335
  const finalPath = path.join(NATIVE_DIR, 'gdx' + ext);
182
336
 
183
337
  ensureBinDir();
184
- await downloadFile(url, tmpPath, finalPath);
185
- setExecutable(finalPath);
338
+ try {
339
+ await downloadFile(url, tmpPath, tmpPath);
340
+ await downloadFile(checksumUrl, checksumTmpPath, checksumPath);
341
+ verifySha256(tmpPath, fs.readFileSync(checksumPath, 'utf8'), assetName);
342
+ fs.renameSync(tmpPath, finalPath);
343
+ setExecutable(finalPath);
344
+ } finally {
345
+ fs.rmSync(tmpPath, { force: true });
346
+ fs.rmSync(checksumTmpPath, { force: true });
347
+ }
186
348
 
187
349
  log(`Prebuilt binary installed to ${finalPath}`);
188
350
 
@@ -208,21 +370,11 @@ function tryBuildNative() {
208
370
  }
209
371
 
210
372
  const platform = process.platform;
211
- const arch = process.arch;
212
- const isWin = platform === 'win32';
213
- const binaryName = isWin ? 'gdx.exe' : 'gdx';
373
+ const binaryName = getNativeBinaryName(platform);
214
374
  const finalPath = path.join(NATIVE_DIR, binaryName);
215
375
 
216
376
  // Build command
217
- const args = [
218
- 'build',
219
- PKG_SRC_PATH,
220
- `--outfile=${finalPath}`,
221
- '--compile',
222
- '--bytecode',
223
- '--production',
224
- '--keep-names',
225
- ];
377
+ const args = getNativeBuildArgs(finalPath);
226
378
 
227
379
  ensureBinDir();
228
380
  log(`Running: bun ${args.join(' ')}`);
@@ -234,16 +386,7 @@ function tryBuildNative() {
234
386
 
235
387
  log(`Native binary built at ${finalPath}`);
236
388
 
237
- writeInstallInfo({
238
- mode: 'built',
239
- platform,
240
- arch,
241
- version: getPackageVersion(),
242
- userAgent: process.env.npm_config_user_agent || null,
243
- useNativeShim: overwriteGlobalShim(finalPath),
244
- ts: (new Date).toLocaleString(),
245
- binaryPath: finalPath
246
- });
389
+ writeInstallInfo(createInstallInfo('built', finalPath, overwriteGlobalShim(finalPath)));
247
390
  }
248
391
 
249
392
  async function main() {
@@ -260,8 +403,22 @@ async function main() {
260
403
  } else if (isTruthy(process.env.GDX_BUILD_NATIVE)) {
261
404
  tryBuildNative();
262
405
  } else {
263
- log('No native install requested (default). Using Node.js fallback.');
264
- // Do nothing
406
+ const runtime = selectFallbackRuntime();
407
+ log(`No native install requested (default). Using ${runtime.name} fallback.`);
408
+ const shimInstall = installRuntimeFallbackShims(runtime);
409
+ writeInstallInfo({
410
+ mode: 'runtime',
411
+ runtime: runtime.name,
412
+ runtimePath: runtime.executable,
413
+ platform: process.platform,
414
+ arch: process.arch,
415
+ version: getPackageVersion(),
416
+ userAgent: process.env.npm_config_user_agent || null,
417
+ useGlobalShim: shimInstall.global,
418
+ useLocalShim: shimInstall.local,
419
+ ts: (new Date).toLocaleString(),
420
+ launcherPath: path.join(__dirname, 'launcher.cjs')
421
+ });
265
422
  }
266
423
  } catch (err) {
267
424
  error(err.message);
@@ -269,4 +426,21 @@ async function main() {
269
426
  }
270
427
  }
271
428
 
272
- main();
429
+ if (require.main === module) {
430
+ main();
431
+ }
432
+
433
+ module.exports = {
434
+ buildRuntimeShimContents,
435
+ createInstallInfo,
436
+ downloadFile,
437
+ getNativeBinaryName,
438
+ getNativeBuildArgs,
439
+ getLocalNodeModulesBinDir,
440
+ findRuntimeExecutable,
441
+ installRuntimeFallbackShims,
442
+ overwriteRuntimeShim,
443
+ readSha256FromText,
444
+ selectFallbackRuntime,
445
+ verifySha256,
446
+ };