Skip to content

Commit bba934c

Browse files
committed
sea: move VFS functions from fs to sea module
Move getSeaVfs() and hasSeaAssets() from the fs module to the sea module and rename them to getVfs() and hasAssets() since the "Sea" prefix is redundant when already in the sea namespace. Also fix circular dependency in internal/vfs/sea.js by using internalBinding('sea') directly instead of requiring the public sea module.
1 parent 070ee38 commit bba934c

7 files changed

Lines changed: 44 additions & 127 deletions

File tree

doc/api/fs.md

Lines changed: 0 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -8864,92 +8864,12 @@ const { glob } = require('node:fs/promises');
88648864
})();
88658865
```
88668866
8867-
### SEA (Single Executable Application) integration
8868-
8869-
When running as a Single Executable Application, the VFS can automatically
8870-
provide access to embedded assets through standard file system APIs.
8871-
8872-
#### `fs.hasSeaAssets()`
8873-
8874-
<!-- YAML
8875-
added: REPLACEME
8876-
-->
8877-
8878-
* Returns: {boolean}
8879-
8880-
Returns `true` if running as a SEA with embedded assets, `false` otherwise.
8881-
8882-
```cjs
8883-
const fs = require('node:fs');
8884-
8885-
if (fs.hasSeaAssets()) {
8886-
console.log('Running as SEA with assets');
8887-
}
8888-
```
8889-
8890-
#### `fs.getSeaVfs([options])`
8891-
8892-
<!-- YAML
8893-
added: REPLACEME
8894-
-->
8895-
8896-
* `options` {Object}
8897-
* `prefix` {string} Mount point prefix for SEA assets. **Default:** `'/sea'`.
8898-
* `moduleHooks` {boolean} Whether to enable require/import hooks.
8899-
**Default:** `true`.
8900-
* Returns: {VirtualFileSystem|null}
8901-
8902-
Returns a VFS populated with all SEA embedded assets, mounted at the specified
8903-
prefix. Returns `null` if not running as a SEA or if there are no assets.
8904-
8905-
The VFS is a singleton - subsequent calls return the same instance (options
8906-
are only used on the first call).
8907-
8908-
```cjs
8909-
const fs = require('node:fs');
8910-
8911-
// In a SEA with an embedded 'config.json' asset:
8912-
const seaVfs = fs.getSeaVfs();
8913-
if (seaVfs) {
8914-
// Access embedded assets via standard fs APIs
8915-
const config = fs.readFileSync('/sea/config.json', 'utf8');
8916-
console.log(JSON.parse(config));
8917-
8918-
// Or require modules from embedded assets
8919-
const utils = require('/sea/utils.js');
8920-
}
8921-
```
8922-
8923-
To use SEA assets, first configure them in your SEA configuration file:
8924-
8925-
```json
8926-
{
8927-
"main": "app.js",
8928-
"output": "app.blob",
8929-
"assets": {
8930-
"config.json": "path/to/config.json",
8931-
"utils.js": "path/to/utils.js"
8932-
}
8933-
}
8934-
```
8935-
8936-
Then access them via the VFS:
8937-
8938-
```cjs
8939-
const fs = require('node:fs');
8940-
const seaVfs = fs.getSeaVfs();
8941-
8942-
// Assets are accessible at /sea/<asset-key>
8943-
const config = fs.readFileSync('/sea/config.json', 'utf8');
8944-
```
8945-
89468867
### Limitations
89478868
89488869
The current VFS implementation has the following limitations:
89498870
89508871
* **Read-only**: Files can only be set via `addFile()`. Write operations
89518872
(`writeFile`, `appendFile`, etc.) are not supported.
8952-
* **No symbolic links**: Symbolic links are not supported.
89538873
* **No file watching**: `fs.watch()` and `fs.watchFile()` do not work with
89548874
virtual files.
89558875
* **No real file descriptor**: Virtual file descriptors (10000+) are managed

doc/api/single-executable-applications.md

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -251,11 +251,12 @@ To use the VFS with SEA:
251251
252252
```cjs
253253
const fs = require('node:fs');
254+
const sea = require('node:sea');
254255
255256
// Check if SEA assets are available
256-
if (fs.hasSeaAssets()) {
257+
if (sea.hasAssets()) {
257258
// Initialize and mount the SEA VFS
258-
const vfs = fs.getSeaVfs();
259+
const vfs = sea.getVfs();
259260
260261
// Now you can use standard fs APIs to read bundled assets
261262
const config = JSON.parse(fs.readFileSync('/sea/config.json', 'utf8'));
@@ -290,11 +291,11 @@ built-in modules. To load JavaScript modules bundled as assets, you must use
290291
[`module.createRequire()`][]:
291292
292293
```cjs
293-
const fs = require('node:fs');
294294
const { createRequire } = require('node:module');
295+
const sea = require('node:sea');
295296
296297
// Initialize VFS
297-
fs.getSeaVfs();
298+
sea.getVfs();
298299
299300
// Create a require function that works with VFS
300301
const seaRequire = createRequire('/sea/');
@@ -313,13 +314,16 @@ By default, the VFS is mounted at `/sea`. You can specify a custom prefix
313314
when initializing the VFS:
314315

315316
```cjs
316-
const vfs = fs.getSeaVfs({ prefix: '/app' });
317+
const fs = require('node:fs');
318+
const sea = require('node:sea');
319+
320+
const vfs = sea.getSeaVfs({ prefix: '/app' });
317321
318322
// Assets are now accessible under /app
319323
const config = fs.readFileSync('/app/config.json', 'utf8');
320324
```
321325

322-
Note: `fs.getSeaVfs()` returns a singleton. The `prefix` option is only used
326+
Note: `sea.getVfs()` returns a singleton. The `prefix` option is only used
323327
on the first call; subsequent calls return the same cached instance.
324328
325329
### Startup snapshot support

lib/fs.js

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3207,7 +3207,6 @@ function globSync(pattern, options) {
32073207
}
32083208

32093209
const lazyVfs = getLazy(() => require('internal/vfs/virtual_fs').VirtualFileSystem);
3210-
const lazySeaVfs = getLazy(() => require('internal/vfs/sea'));
32113210

32123211
/**
32133212
* Creates a new virtual file system instance.
@@ -3221,28 +3220,6 @@ function createVirtual(options) {
32213220
return new VirtualFileSystem(options);
32223221
}
32233222

3224-
/**
3225-
* Gets the VFS containing SEA (Single Executable Application) assets.
3226-
* Returns null if not running as a SEA or if there are no assets.
3227-
* @param {object} [options] Configuration options
3228-
* @param {string} [options.prefix] Mount point prefix for SEA assets
3229-
* @param {boolean} [options.moduleHooks] Whether to enable require/import hooks
3230-
* @returns {VirtualFileSystem|null}
3231-
*/
3232-
function getSeaVfs(options) {
3233-
const { getSeaVfs: getSeaVfsInternal } = lazySeaVfs();
3234-
return getSeaVfsInternal(options);
3235-
}
3236-
3237-
/**
3238-
* Checks if SEA assets are available.
3239-
* @returns {boolean}
3240-
*/
3241-
function hasSeaAssets() {
3242-
const { hasSeaAssets: hasSeaAssetsInternal } = lazySeaVfs();
3243-
return hasSeaAssetsInternal();
3244-
}
3245-
32463223
module.exports = fs = {
32473224
appendFile,
32483225
appendFileSync,
@@ -3261,8 +3238,6 @@ module.exports = fs = {
32613238
createReadStream,
32623239
createVirtual,
32633240
createWriteStream,
3264-
getSeaVfs,
3265-
hasSeaAssets,
32663241
exists,
32673242
existsSync,
32683243
fchown,

lib/internal/vfs/sea.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,19 @@ const {
55
} = primordials;
66

77
const { Buffer } = require('buffer');
8-
const { isSea, getAsset, getAssetKeys } = require('sea');
8+
const { isSea, getAsset: getAssetInternal, getAssetKeys: getAssetKeysInternal } = internalBinding('sea');
99
const { kEmptyObject } = require('internal/util');
1010

11+
// Wrapper to get asset as ArrayBuffer (same as public sea.getAsset without encoding)
12+
function getAsset(key) {
13+
return getAssetInternal(key);
14+
}
15+
16+
// Wrapper to get asset keys
17+
function getAssetKeys() {
18+
return getAssetKeysInternal() || [];
19+
}
20+
1121
// Lazy-loaded VFS
1222
let cachedSeaVfs = null;
1323

lib/sea.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,17 @@ function getAssetKeys() {
8181
return getAssetKeysInternal() || [];
8282
}
8383

84+
const {
85+
getSeaVfs: getVfs,
86+
hasSeaAssets: hasAssets,
87+
} = require('internal/vfs/sea');
88+
8489
module.exports = {
8590
isSea,
8691
getAsset,
8792
getRawAsset,
8893
getAssetAsBlob,
8994
getAssetKeys,
95+
getVfs,
96+
hasAssets,
9097
};

test/parallel/test-vfs-sea.js

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,44 +5,44 @@
55

66
require('../common');
77
const assert = require('assert');
8-
const fs = require('fs');
8+
const sea = require('node:sea');
99

10-
// Test that SEA functions are exported from fs module
11-
assert.strictEqual(typeof fs.getSeaVfs, 'function');
12-
assert.strictEqual(typeof fs.hasSeaAssets, 'function');
10+
// Test that SEA functions are exported from sea module
11+
assert.strictEqual(typeof sea.getVfs, 'function');
12+
assert.strictEqual(typeof sea.hasAssets, 'function');
1313

1414
// Test hasSeaAssets() returns false when not running as SEA
1515
{
16-
const hasAssets = fs.hasSeaAssets();
16+
const hasAssets = sea.hasAssets();
1717
assert.strictEqual(hasAssets, false);
1818
}
1919

2020
// Test getSeaVfs() returns null when not running as SEA
2121
{
22-
const seaVfs = fs.getSeaVfs();
22+
const seaVfs = sea.getVfs();
2323
assert.strictEqual(seaVfs, null);
2424
}
2525

2626
// Test getSeaVfs() with options still returns null when not in SEA
2727
{
28-
const seaVfs = fs.getSeaVfs({ prefix: '/custom-sea' });
28+
const seaVfs = sea.getVfs({ prefix: '/custom-sea' });
2929
assert.strictEqual(seaVfs, null);
3030
}
3131

3232
{
33-
const seaVfs = fs.getSeaVfs({ moduleHooks: false });
33+
const seaVfs = sea.getVfs({ moduleHooks: false });
3434
assert.strictEqual(seaVfs, null);
3535
}
3636

3737
{
38-
const seaVfs = fs.getSeaVfs({ prefix: '/my-app', moduleHooks: true });
38+
const seaVfs = sea.getVfs({ prefix: '/my-app', moduleHooks: true });
3939
assert.strictEqual(seaVfs, null);
4040
}
4141

4242
// Verify that calling getSeaVfs multiple times is safe (caching behavior)
4343
{
44-
const vfs1 = fs.getSeaVfs();
45-
const vfs2 = fs.getSeaVfs();
44+
const vfs1 = sea.getVfs();
45+
const vfs2 = sea.getVfs();
4646
assert.strictEqual(vfs1, vfs2);
4747
assert.strictEqual(vfs1, null);
4848
}

test/sea/test-single-executable-application-vfs.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const {
99

1010
skipIfSingleExecutableIsNotSupported();
1111

12-
// This tests the SEA VFS integration - fs.getSeaVfs() and fs.hasSeaAssets()
12+
// This tests the SEA VFS integration - sea.getVfs() and sea.hasAssets()
1313

1414
const tmpdir = require('../common/tmpdir');
1515
const { writeFileSync } = require('fs');
@@ -23,15 +23,16 @@ const outputFile = tmpdir.resolve(process.platform === 'win32' ? 'sea.exe' : 'se
2323
const seaMain = `
2424
'use strict';
2525
const fs = require('fs');
26+
const sea = require('node:sea');
2627
const assert = require('assert');
2728
2829
// Test hasSeaAssets() returns true when we have assets
29-
const hasAssets = fs.hasSeaAssets();
30+
const hasAssets = sea.hasAssets();
3031
assert.strictEqual(hasAssets, true, 'hasSeaAssets() should return true');
3132
console.log('hasSeaAssets:', hasAssets);
3233
3334
// Test getSeaVfs() returns a VFS instance
34-
const vfs = fs.getSeaVfs();
35+
const vfs = sea.getVfs();
3536
assert.ok(vfs !== null, 'getSeaVfs() should not return null');
3637
console.log('getSeaVfs returned VFS instance');
3738
@@ -75,7 +76,7 @@ assert.strictEqual(mathModule.multiply(4, 5), 20, 'math.multiply should work');
7576
console.log('require from VFS tests passed');
7677
7778
// Test getSeaVfs with custom prefix
78-
const customVfs = fs.getSeaVfs({ prefix: '/custom' });
79+
const customVfs = sea.getVfs({ prefix: '/custom' });
7980
// Note: getSeaVfs is a singleton, so it returns the same instance
8081
// with the same mount point (/sea) regardless of options passed after first call
8182
assert.strictEqual(customVfs, vfs, 'Should return the same cached instance');

0 commit comments

Comments
 (0)