| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 01b66b1 commit 0bf9775
8 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -221,7 +221,10 @@ executable, users can retrieve the assets using the [`sea.getAsset()`][] and | |||
| 221 | 221 | The single-executable application can access the assets as follows: | |
| 222 | 222 | ||
| 223 | 223 | ```cjs | |
| 224 | - const { getAsset, getAssetAsBlob, getRawAsset } = require('node:sea'); | ||
| 224 | + const { getAsset, getAssetAsBlob, getRawAsset, getAssetKeys } = require('node:sea'); | ||
| 225 | + // Get all asset keys. | ||
| 226 | + const keys = getAssetKeys(); | ||
| 227 | + console.log(keys); // ['a.jpg', 'b.txt'] | ||
| 225 | 228 | // Returns a copy of the data in an ArrayBuffer. | |
| 226 | 229 | const image = getAsset('a.jpg'); | |
| 227 | 230 | // Returns a string decoded from the asset as UTF8. | |
@@ -232,8 +235,8 @@ const blob = getAssetAsBlob('a.jpg'); | |||
| 232 | 235 | const raw = getRawAsset('a.jpg'); | |
| 233 | 236 | ``` | |
| 234 | 237 | ||
| 235 | - See documentation of the [`sea.getAsset()`][], [`sea.getAssetAsBlob()`][] and [`sea.getRawAsset()`][] | ||
| 236 | - APIs for more information. | ||
| 238 | + See documentation of the [`sea.getAsset()`][], [`sea.getAssetAsBlob()`][], | ||
| 239 | + [`sea.getRawAsset()`][] and [`sea.getAssetKeys()`][] APIs for more information. | ||
| 237 | 240 | ||
| 238 | 241 | ### Startup snapshot support | |
| 239 | 242 | ||
@@ -429,6 +432,19 @@ writes to the returned array buffer is likely to result in a crash. | |||
| 429 | 432 | `assets` field in the single-executable application configuration. | |
| 430 | 433 | * Returns: {ArrayBuffer} | |
| 431 | 434 | ||
| 435 | + ### `sea.getAssetKeys()` | ||
| 436 | + | ||
| 437 | + <!-- YAML | ||
| 438 | + added: REPLACEME | ||
| 439 | + --> | ||
| 440 | + | ||
| 441 | + * Returns {string\[]} An array containing all the keys of the assets | ||
| 442 | + embedded in the executable. If no assets are embedded, returns an empty array. | ||
| 443 | + | ||
| 444 | + This method can be used to retrieve an array of all the keys of assets | ||
| 445 | + embedded into the single-executable application. | ||
| 446 | + An error is thrown when not running inside a single-executable application. | ||
| 447 | + | ||
| 432 | 448 | ### `require(id)` in the injected main script is not file based | |
| 433 | 449 | ||
| 434 | 450 | `require()` in the injected main script is not the same as the [`require()`][] | |
@@ -503,6 +519,7 @@ to help us document them. | |||
| 503 | 519 | [`require.main`]: modules.md#accessing-the-main-module | |
| 504 | 520 | [`sea.getAsset()`]: #seagetassetkey-encoding | |
| 505 | 521 | [`sea.getAssetAsBlob()`]: #seagetassetasblobkey-options | |
| 522 | + [`sea.getAssetKeys()`]: #seagetassetkeys | ||
| 506 | 523 | [`sea.getRawAsset()`]: #seagetrawassetkey | |
| 507 | 524 | [`v8.startupSnapshot.setDeserializeMainFunction()`]: v8.md#v8startupsnapshotsetdeserializemainfunctioncallback-data | |
| 508 | 525 | [`v8.startupSnapshot` API]: v8.md#startup-snapshot-api | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -3,7 +3,7 @@ const { | |||
| 3 | 3 | ArrayBufferPrototypeSlice, | |
| 4 | 4 | } = primordials; | |
| 5 | 5 | ||
| 6 | - const { isSea, getAsset: getAssetInternal } = internalBinding('sea'); | ||
| 6 | + const { isSea, getAsset: getAssetInternal, getAssetKeys: getAssetKeysInternal } = internalBinding('sea'); | ||
| 7 | 7 | const { TextDecoder } = require('internal/encoding'); | |
| 8 | 8 | const { validateString } = require('internal/validators'); | |
| 9 | 9 | const { | |
@@ -68,9 +68,23 @@ function getAssetAsBlob(key, options) { | |||
| 68 | 68 | return new Blob([asset], options); | |
| 69 | 69 | } | |
| 70 | 70 | ||
| 71 | + /** | ||
| 72 | + * Returns an array of all the keys of assets embedded into the | ||
| 73 | + * single-executable application. | ||
| 74 | + * @returns {string[]} | ||
| 75 | + */ | ||
| 76 | + function getAssetKeys() { | ||
| 77 | + if (!isSea()) { | ||
| 78 | + throw new ERR_NOT_IN_SINGLE_EXECUTABLE_APPLICATION(); | ||
| 79 | + } | ||
| 80 | + | ||
| 81 | + return getAssetKeysInternal() || []; | ||
| 82 | + } | ||
| 83 | + | ||
| 71 | 84 | module.exports = { | |
| 72 | 85 | isSea, | |
| 73 | 86 | getAsset, | |
| 74 | 87 | getRawAsset, | |
| 75 | 88 | getAssetAsBlob, | |
| 89 | + getAssetKeys, | ||
| 76 | 90 | }; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -29,6 +29,7 @@ | |||
| 29 | 29 | #include <vector> | |
| 30 | 30 | ||
| 31 | 31 | using node::ExitCode; | |
| 32 | + using v8::Array; | ||
| 32 | 33 | using v8::ArrayBuffer; | |
| 33 | 34 | using v8::BackingStore; | |
| 34 | 35 | using v8::Context; | |
@@ -807,6 +808,25 @@ void GetAsset(const FunctionCallbackInfo<Value>& args) { | |||
| 807 | 808 | args.GetReturnValue().Set(ab); | |
| 808 | 809 | } | |
| 809 | 810 | ||
| 811 | + void GetAssetKeys(const FunctionCallbackInfo<Value>& args) { | ||
| 812 | + CHECK_EQ(args.Length(), 0); | ||
| 813 | + Isolate* isolate = args.GetIsolate(); | ||
| 814 | + SeaResource sea_resource = FindSingleExecutableResource(); | ||
| 815 | + | ||
| 816 | + Local<Context> context = isolate->GetCurrentContext(); | ||
| 817 | + LocalVector<Value> keys(isolate); | ||
| 818 | + keys.reserve(sea_resource.assets.size()); | ||
| 819 | + for (const auto& [key, _] : sea_resource.assets) { | ||
| 820 | + Local<Value> key_str; | ||
| 821 | + if (!ToV8Value(context, key).ToLocal(&key_str)) { | ||
| 822 | + return; | ||
| 823 | + } | ||
| 824 | + keys.push_back(key_str); | ||
| 825 | + } | ||
| 826 | + Local<Array> result = Array::New(isolate, keys.data(), keys.size()); | ||
| 827 | + args.GetReturnValue().Set(result); | ||
| 828 | + } | ||
| 829 | + | ||
| 810 | 830 | MaybeLocal<Value> LoadSingleExecutableApplication( | |
| 811 | 831 | const StartExecutionCallbackInfo& info) { | |
| 812 | 832 | // Here we are currently relying on the fact that in NodeMainInstance::Run(), | |
@@ -858,12 +878,14 @@ void Initialize(Local<Object> target, | |||
| 858 | 878 | "isExperimentalSeaWarningNeeded", | |
| 859 | 879 | IsExperimentalSeaWarningNeeded); | |
| 860 | 880 | SetMethod(context, target, "getAsset", GetAsset); | |
| 881 | + SetMethod(context, target, "getAssetKeys", GetAssetKeys); | ||
| 861 | 882 | } | |
| 862 | 883 | ||
| 863 | 884 | void RegisterExternalReferences(ExternalReferenceRegistry* registry) { | |
| 864 | 885 | registry->Register(IsSea); | |
| 865 | 886 | registry->Register(IsExperimentalSeaWarningNeeded); | |
| 866 | 887 | registry->Register(GetAsset); | |
| 888 | + registry->Register(GetAssetKeys); | ||
| 867 | 889 | } | |
| 868 | 890 | ||
| 869 | 891 | } // namespace sea | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,9 @@ | |||
| 1 | + 'use strict'; | ||
| 2 | + | ||
| 3 | + const { isSea, getAssetKeys } = require('node:sea'); | ||
| 4 | + const assert = require('node:assert'); | ||
| 5 | + | ||
| 6 | + assert(isSea()); | ||
| 7 | + | ||
| 8 | + const keys = getAssetKeys(); | ||
| 9 | + console.log('Asset keys:', JSON.stringify(keys.sort())); | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,11 @@ | |||
| 1 | + 'use strict'; | ||
| 2 | + | ||
| 3 | + require('../common'); | ||
| 4 | + | ||
| 5 | + const { getAssetKeys } = require('node:sea'); | ||
| 6 | + const assert = require('node:assert'); | ||
| 7 | + | ||
| 8 | + // Test that getAssetKeys throws when not in SEA | ||
| 9 | + assert.throws(() => getAssetKeys(), { | ||
| 10 | + code: 'ERR_NOT_IN_SINGLE_EXECUTABLE_APPLICATION' | ||
| 11 | + }); | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -57,6 +57,8 @@ test-watch-mode-inspect: SKIP | |||
| 57 | 57 | test-single-executable-application: SKIP | |
| 58 | 58 | test-single-executable-application-assets: SKIP | |
| 59 | 59 | test-single-executable-application-assets-raw: SKIP | |
| 60 | + test-single-executable-application-asset-keys-empty: SKIP | ||
| 61 | + test-single-executable-application-asset-keys: SKIP | ||
| 60 | 62 | test-single-executable-application-disable-experimental-sea-warning: SKIP | |
| 61 | 63 | test-single-executable-application-empty: SKIP | |
| 62 | 64 | test-single-executable-application-exec-argv: SKIP | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,65 @@ | |||
| 1 | + 'use strict'; | ||
| 2 | + | ||
| 3 | + // This test verifies that the `getAssetKeys()` function works correctly | ||
| 4 | + // in a single executable application without any assets. | ||
| 5 | + | ||
| 6 | + require('../common'); | ||
| 7 | + | ||
| 8 | + const { | ||
| 9 | + generateSEA, | ||
| 10 | + skipIfSingleExecutableIsNotSupported, | ||
| 11 | + } = require('../common/sea'); | ||
| 12 | + | ||
| 13 | + skipIfSingleExecutableIsNotSupported(); | ||
| 14 | + | ||
| 15 | + const tmpdir = require('../common/tmpdir'); | ||
| 16 | + | ||
| 17 | + const { copyFileSync, writeFileSync, existsSync } = require('fs'); | ||
| 18 | + const { | ||
| 19 | + spawnSyncAndExitWithoutError, | ||
| 20 | + spawnSyncAndAssert, | ||
| 21 | + } = require('../common/child_process'); | ||
| 22 | + const assert = require('assert'); | ||
| 23 | + const fixtures = require('../common/fixtures'); | ||
| 24 | + | ||
| 25 | + const seaPrepBlob = tmpdir.resolve('sea-prep.blob'); | ||
| 26 | + const outputFile = tmpdir.resolve(process.platform === 'win32' ? 'sea.exe' : 'sea'); | ||
| 27 | + | ||
| 28 | + tmpdir.refresh(); | ||
| 29 | + copyFileSync(fixtures.path('sea', 'get-asset-keys.js'), tmpdir.resolve('sea.js')); | ||
| 30 | + | ||
| 31 | + writeFileSync(tmpdir.resolve('sea-config.json'), ` | ||
| 32 | + { | ||
| 33 | + "main": "sea.js", | ||
| 34 | + "output": "sea-prep.blob" | ||
| 35 | + } | ||
| 36 | + `, 'utf8'); | ||
| 37 | + | ||
| 38 | + spawnSyncAndExitWithoutError( | ||
| 39 | + process.execPath, | ||
| 40 | + ['--experimental-sea-config', 'sea-config.json'], | ||
| 41 | + { | ||
| 42 | + env: { | ||
| 43 | + NODE_DEBUG_NATIVE: 'SEA', | ||
| 44 | + ...process.env, | ||
| 45 | + }, | ||
| 46 | + cwd: tmpdir.path | ||
| 47 | + }, | ||
| 48 | + {}); | ||
| 49 | + | ||
| 50 | + assert(existsSync(seaPrepBlob)); | ||
| 51 | + | ||
| 52 | + generateSEA(outputFile, process.execPath, seaPrepBlob); | ||
| 53 | + | ||
| 54 | + spawnSyncAndAssert( | ||
| 55 | + outputFile, | ||
| 56 | + { | ||
| 57 | + env: { | ||
| 58 | + ...process.env, | ||
| 59 | + NODE_DEBUG_NATIVE: 'SEA', | ||
| 60 | + } | ||
| 61 | + }, | ||
| 62 | + { | ||
| 63 | + stdout: /Asset keys: \[\]/, | ||
| 64 | + } | ||
| 65 | + ); | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,74 @@ | |||
| 1 | + 'use strict'; | ||
| 2 | + | ||
| 3 | + // This test verifies that the `getAssetKeys()` function works correctly | ||
| 4 | + // in a single executable application with assets. | ||
| 5 | + | ||
| 6 | + require('../common'); | ||
| 7 | + | ||
| 8 | + const { | ||
| 9 | + generateSEA, | ||
| 10 | + skipIfSingleExecutableIsNotSupported, | ||
| 11 | + } = require('../common/sea'); | ||
| 12 | + | ||
| 13 | + skipIfSingleExecutableIsNotSupported(); | ||
| 14 | + | ||
| 15 | + const tmpdir = require('../common/tmpdir'); | ||
| 16 | + | ||
| 17 | + const { copyFileSync, writeFileSync, existsSync } = require('fs'); | ||
| 18 | + const { | ||
| 19 | + spawnSyncAndExitWithoutError, | ||
| 20 | + spawnSyncAndAssert, | ||
| 21 | + } = require('../common/child_process'); | ||
| 22 | + const assert = require('assert'); | ||
| 23 | + const fixtures = require('../common/fixtures'); | ||
| 24 | + | ||
| 25 | + const configFile = tmpdir.resolve('sea-config.json'); | ||
| 26 | + const seaPrepBlob = tmpdir.resolve('sea-prep.blob'); | ||
| 27 | + const outputFile = tmpdir.resolve(process.platform === 'win32' ? 'sea.exe' : 'sea'); | ||
| 28 | + | ||
| 29 | + tmpdir.refresh(); | ||
| 30 | + copyFileSync(fixtures.path('sea', 'get-asset-keys.js'), tmpdir.resolve('sea.js')); | ||
| 31 | + writeFileSync(tmpdir.resolve('asset-1.txt'), 'This is asset 1'); | ||
| 32 | + writeFileSync(tmpdir.resolve('asset-2.txt'), 'This is asset 2'); | ||
| 33 | + writeFileSync(tmpdir.resolve('asset-3.txt'), 'This is asset 3'); | ||
| 34 | + | ||
| 35 | + writeFileSync(configFile, ` | ||
| 36 | + { | ||
| 37 | + "main": "sea.js", | ||
| 38 | + "output": "sea-prep.blob", | ||
| 39 | + "assets": { | ||
| 40 | + "asset-1.txt": "asset-1.txt", | ||
| 41 | + "asset-2.txt": "asset-2.txt", | ||
| 42 | + "asset-3.txt": "asset-3.txt" | ||
| 43 | + } | ||
| 44 | + } | ||
| 45 | + `, 'utf8'); | ||
| 46 | + | ||
| 47 | + spawnSyncAndExitWithoutError( | ||
| 48 | + process.execPath, | ||
| 49 | + ['--experimental-sea-config', 'sea-config.json'], | ||
| 50 | + { | ||
| 51 | + env: { | ||
| 52 | + NODE_DEBUG_NATIVE: 'SEA', | ||
| 53 | + ...process.env, | ||
| 54 | + }, | ||
| 55 | + cwd: tmpdir.path | ||
| 56 | + }, | ||
| 57 | + {}); | ||
| 58 | + | ||
| 59 | + assert(existsSync(seaPrepBlob)); | ||
| 60 | + | ||
| 61 | + generateSEA(outputFile, process.execPath, seaPrepBlob); | ||
| 62 | + | ||
| 63 | + spawnSyncAndAssert( | ||
| 64 | + outputFile, | ||
| 65 | + { | ||
| 66 | + env: { | ||
| 67 | + ...process.env, | ||
| 68 | + NODE_DEBUG_NATIVE: 'SEA', | ||
| 69 | + } | ||
| 70 | + }, | ||
| 71 | + { | ||
| 72 | + stdout: /Asset keys: \["asset-1\.txt","asset-2\.txt","asset-3\.txt"\]/, | ||
| 73 | + } | ||
| 74 | + ); | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments