typescript-virtual-container 1.4.9 → 1.5.1
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/.vscode/settings.json +1 -1
- package/README.md +141 -89
- package/builds/fortune-nyx-v1.5.1-directbash-k6.1.0.mjs +1768 -0
- package/builds/fortune-nyx-v1.5.1-ssh-nosftp.js +1768 -0
- package/builds/fortune-nyx-v1.5.1-ssh.cjs +1769 -0
- package/bun.lock +3 -3
- package/dist/SSHMimic/exec.js +2 -2
- package/dist/SSHMimic/exec.js.map +1 -1
- package/dist/SSHMimic/index.d.ts.map +1 -1
- package/dist/SSHMimic/index.js +2 -1
- package/dist/SSHMimic/index.js.map +1 -1
- package/dist/SSHMimic/sftp.d.ts.map +1 -1
- package/dist/SSHMimic/sftp.js +4 -3
- package/dist/SSHMimic/sftp.js.map +1 -1
- package/dist/VirtualFileSystem/index.d.ts +14 -0
- package/dist/VirtualFileSystem/index.d.ts.map +1 -1
- package/dist/VirtualFileSystem/index.js +51 -3
- package/dist/VirtualFileSystem/index.js.map +1 -1
- package/dist/VirtualFileSystem/journal.d.ts.map +1 -1
- package/dist/VirtualFileSystem/journal.js +13 -5
- package/dist/VirtualFileSystem/journal.js.map +1 -1
- package/dist/VirtualShell/shell.js +12 -12
- package/dist/VirtualShell/shell.js.map +1 -1
- package/dist/VirtualUserManager/index.js +8 -11
- package/dist/VirtualUserManager/index.js.map +1 -1
- package/dist/commands/apt.js +3 -3
- package/dist/commands/apt.js.map +1 -1
- package/dist/commands/cd.d.ts.map +1 -1
- package/dist/commands/cd.js +2 -1
- package/dist/commands/cd.js.map +1 -1
- package/dist/commands/helpers.d.ts +1 -1
- package/dist/commands/helpers.d.ts.map +1 -1
- package/dist/commands/helpers.js +3 -2
- package/dist/commands/helpers.js.map +1 -1
- package/dist/commands/index.d.ts +1 -1
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +1 -1
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/lsb-release.js +1 -1
- package/dist/commands/lsb-release.js.map +1 -1
- package/dist/commands/runtime.d.ts +2 -0
- package/dist/commands/runtime.d.ts.map +1 -1
- package/dist/commands/runtime.js +5 -1
- package/dist/commands/runtime.js.map +1 -1
- package/dist/modules/linuxRootfs.d.ts +9 -5
- package/dist/modules/linuxRootfs.d.ts.map +1 -1
- package/dist/modules/linuxRootfs.js +1079 -148
- package/dist/modules/linuxRootfs.js.map +1 -1
- package/dist/self-standalone.js +22 -12
- package/dist/self-standalone.js.map +1 -1
- package/docs/assets/hierarchy.js +1 -1
- package/docs/classes/HoneyPot.html +9 -9
- package/docs/classes/IdleManager.html +8 -8
- package/docs/classes/SshClient.html +18 -18
- package/docs/classes/VirtualFileSystem.html +34 -34
- package/docs/classes/VirtualPackageManager.html +13 -13
- package/docs/classes/VirtualSftpServer.html +3 -3
- package/docs/classes/VirtualShell.html +28 -28
- package/docs/classes/VirtualSshServer.html +5 -5
- package/docs/classes/VirtualUserManager.html +27 -27
- package/docs/functions/assertDiff.html +2 -2
- package/docs/functions/diffSnapshots.html +2 -2
- package/docs/functions/formatDiff.html +2 -2
- package/docs/functions/getArg.html +2 -2
- package/docs/functions/getFlag.html +2 -2
- package/docs/functions/ifFlag.html +2 -2
- package/docs/hierarchy.html +1 -1
- package/docs/index.html +37 -31
- package/docs/interfaces/AuditLogEntry.html +3 -3
- package/docs/interfaces/CommandContext.html +12 -12
- package/docs/interfaces/CommandResult.html +13 -13
- package/docs/interfaces/ExecStream.html +6 -6
- package/docs/interfaces/HoneyPotStats.html +3 -3
- package/docs/interfaces/IdleManagerOptions.html +3 -3
- package/docs/interfaces/InstalledPackage.html +11 -11
- package/docs/interfaces/NanoEditorSession.html +5 -5
- package/docs/interfaces/PackageDefinition.html +14 -14
- package/docs/interfaces/PackageFile.html +5 -5
- package/docs/interfaces/PasswordChallenge.html +9 -9
- package/docs/interfaces/RemoveOptions.html +3 -3
- package/docs/interfaces/ShellEnv.html +4 -4
- package/docs/interfaces/ShellModule.html +8 -8
- package/docs/interfaces/ShellProperties.html +5 -5
- package/docs/interfaces/ShellStream.html +7 -7
- package/docs/interfaces/SudoChallenge.html +9 -9
- package/docs/interfaces/VfsBaseNode.html +7 -7
- package/docs/interfaces/VfsDiff.html +6 -6
- package/docs/interfaces/VfsDiffEntry.html +4 -4
- package/docs/interfaces/VfsDiffModified.html +6 -6
- package/docs/interfaces/VfsDirectoryNode.html +8 -8
- package/docs/interfaces/VfsFileNode.html +9 -9
- package/docs/interfaces/VfsOptions.html +6 -6
- package/docs/interfaces/VfsSnapshot.html +3 -3
- package/docs/interfaces/VfsSnapshotBaseNode.html +4 -4
- package/docs/interfaces/VfsSnapshotDirectoryNode.html +5 -5
- package/docs/interfaces/VfsSnapshotFileNode.html +6 -6
- package/docs/interfaces/VirtualActiveSession.html +7 -7
- package/docs/interfaces/VirtualSftpServerOptions.html +3 -3
- package/docs/interfaces/VirtualShellVfsLike.html +3 -3
- package/docs/interfaces/VirtualShellVfsOptions.html +3 -3
- package/docs/interfaces/WriteFileOptions.html +4 -4
- package/docs/modules.html +1 -1
- package/docs/types/ArgParseOptions.html +3 -3
- package/docs/types/CommandMode.html +2 -2
- package/docs/types/CommandOutcome.html +2 -2
- package/docs/types/IdleState.html +1 -1
- package/docs/types/VfsNodeStats.html +2 -2
- package/docs/types/VfsNodeType.html +2 -2
- package/docs/types/VfsPersistenceMode.html +2 -2
- package/docs/types/VfsSnapshotNode.html +2 -2
- package/package.json +6 -5
- package/scripts/build-all.mjs +198 -0
- package/scripts/build-names.mjs +44 -0
- package/src/SSHMimic/exec.ts +2 -2
- package/src/SSHMimic/index.ts +2 -1
- package/src/SSHMimic/sftp.ts +4 -3
- package/src/VirtualFileSystem/index.ts +46 -3
- package/src/VirtualFileSystem/journal.ts +12 -5
- package/src/VirtualShell/shell.ts +12 -12
- package/src/VirtualUserManager/index.ts +11 -11
- package/src/commands/apt.ts +3 -3
- package/src/commands/cd.ts +2 -1
- package/src/commands/helpers.ts +3 -2
- package/src/commands/index.ts +1 -1
- package/src/commands/lsb-release.ts +1 -1
- package/src/commands/runtime.ts +6 -1
- package/src/modules/linuxRootfs.ts +1293 -207
- package/src/self-standalone.ts +26 -12
- package/tests/new-features.test.ts +2 -2
- package/tests/sftp.test.ts +13 -13
- package/builds/self-standalone.js +0 -1299
- package/builds/standalone-wo-sftp.js +0 -1300
- package/builds/standalone.cjs +0 -1301
- /package/builds/{web-full-api.min.js → fortune-nyx-v1.5.1-web-full.min.js} +0 -0
- /package/builds/{web.min.js → fortune-nyx-v1.5.1-web.min.js} +0 -0
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
<!DOCTYPE html><html class="default" lang="en" data-base="../"><head><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>VfsNodeStats | typescript-virtual-container - v1.
|
|
2
|
-
</div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/itsrealfortune/typescript-virtual-container/blob/
|
|
1
|
+
<!DOCTYPE html><html class="default" lang="en" data-base="../"><head><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>VfsNodeStats | typescript-virtual-container - v1.5.1</title><meta name="description" content="Documentation for typescript-virtual-container"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="../assets/style.css"/><link rel="stylesheet" href="../assets/highlight.css"/><script defer src="../assets/main.js"></script><script async src="../assets/icons.js" id="tsd-icons-script"></script><script async src="../assets/search.js" id="tsd-search-script"></script><script async src="../assets/navigation.js" id="tsd-nav-script"></script><script async src="../assets/hierarchy.js" id="tsd-hierarchy-script"></script></head><body><script>document.documentElement.dataset.theme = localStorage.getItem("tsd-theme") || "os";document.body.style.display="none";setTimeout(() => window.app?app.showPage():document.body.style.removeProperty("display"),500)</script><header class="tsd-page-toolbar"><div class="tsd-toolbar-contents container"><a href="../index.html" class="title">typescript-virtual-container - v1.5.1</a><div id="tsd-toolbar-links"></div><button id="tsd-search-trigger" class="tsd-widget" aria-label="Search"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-search"></use></svg></button><dialog id="tsd-search" aria-label="Search"><input role="combobox" id="tsd-search-input" aria-controls="tsd-search-results" aria-autocomplete="list" aria-expanded="true" autocapitalize="off" autocomplete="off" placeholder="Search the docs" maxLength="100"/><ul role="listbox" id="tsd-search-results"></ul><div id="tsd-search-status" aria-live="polite" aria-atomic="true"><div>Preparing search index...</div></div></dialog><a href="#" class="tsd-widget menu" id="tsd-toolbar-menu-trigger" data-toggle="menu" aria-label="Menu"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-menu"></use></svg></a></div></header><div class="container container-main"><div class="col-content"><div class="tsd-page-title"><ul class="tsd-breadcrumb" aria-label="Breadcrumb"><li><a href="" aria-current="page">VfsNodeStats</a></li></ul><h1>Type Alias VfsNodeStats</h1></div><div class="tsd-signature"><span class="tsd-kind-type-alias">VfsNodeStats</span><span class="tsd-signature-symbol">:</span> <a href="../interfaces/VfsFileNode.html" class="tsd-signature-type tsd-kind-interface">VfsFileNode</a> <span class="tsd-signature-symbol">|</span> <a href="../interfaces/VfsDirectoryNode.html" class="tsd-signature-type tsd-kind-interface">VfsDirectoryNode</a></div><div class="tsd-comment tsd-typography"><p>Union of file and directory stat responses.</p>
|
|
2
|
+
</div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/itsrealfortune/typescript-virtual-container/blob/6aa10e32d938703c886defa3dee9cdbf31ed343b/src/types/vfs.ts#L35">src/types/vfs.ts:35</a></li></ul></aside></div><div class="col-sidebar"><div class="page-menu"><div class="tsd-navigation settings"><details class="tsd-accordion"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg><h3>Settings</h3></summary><div class="tsd-accordion-details"><div class="tsd-filter-visibility"><span class="settings-label">Member Visibility</span><ul id="tsd-filter-options"><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-protected" name="protected"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Protected</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-inherited" name="inherited" checked/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Inherited</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-external" name="external"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>External</span></label></li></ul></div><div class="tsd-theme-toggle"><label class="settings-label" for="tsd-theme">Theme</label><select id="tsd-theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></div></div></details></div></div><div class="site-menu"><nav class="tsd-navigation"><a href="../modules.html">typescript-virtual-container - v1.5.1</a><ul class="tsd-small-nested-navigation" id="tsd-nav-container"><li>Loading...</li></ul></nav></div></div></div><footer><p class="tsd-generator">Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p></footer><div class="overlay"></div></body></html>
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
<!DOCTYPE html><html class="default" lang="en" data-base="../"><head><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>VfsNodeType | typescript-virtual-container - v1.
|
|
2
|
-
</div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/itsrealfortune/typescript-virtual-container/blob/
|
|
1
|
+
<!DOCTYPE html><html class="default" lang="en" data-base="../"><head><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>VfsNodeType | typescript-virtual-container - v1.5.1</title><meta name="description" content="Documentation for typescript-virtual-container"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="../assets/style.css"/><link rel="stylesheet" href="../assets/highlight.css"/><script defer src="../assets/main.js"></script><script async src="../assets/icons.js" id="tsd-icons-script"></script><script async src="../assets/search.js" id="tsd-search-script"></script><script async src="../assets/navigation.js" id="tsd-nav-script"></script><script async src="../assets/hierarchy.js" id="tsd-hierarchy-script"></script></head><body><script>document.documentElement.dataset.theme = localStorage.getItem("tsd-theme") || "os";document.body.style.display="none";setTimeout(() => window.app?app.showPage():document.body.style.removeProperty("display"),500)</script><header class="tsd-page-toolbar"><div class="tsd-toolbar-contents container"><a href="../index.html" class="title">typescript-virtual-container - v1.5.1</a><div id="tsd-toolbar-links"></div><button id="tsd-search-trigger" class="tsd-widget" aria-label="Search"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-search"></use></svg></button><dialog id="tsd-search" aria-label="Search"><input role="combobox" id="tsd-search-input" aria-controls="tsd-search-results" aria-autocomplete="list" aria-expanded="true" autocapitalize="off" autocomplete="off" placeholder="Search the docs" maxLength="100"/><ul role="listbox" id="tsd-search-results"></ul><div id="tsd-search-status" aria-live="polite" aria-atomic="true"><div>Preparing search index...</div></div></dialog><a href="#" class="tsd-widget menu" id="tsd-toolbar-menu-trigger" data-toggle="menu" aria-label="Menu"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-menu"></use></svg></a></div></header><div class="container container-main"><div class="col-content"><div class="tsd-page-title"><ul class="tsd-breadcrumb" aria-label="Breadcrumb"><li><a href="" aria-current="page">VfsNodeType</a></li></ul><h1>Type Alias VfsNodeType</h1></div><div class="tsd-signature"><span class="tsd-kind-type-alias">VfsNodeType</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">"file"</span> <span class="tsd-signature-symbol">|</span> <span class="tsd-signature-type">"directory"</span></div><div class="tsd-comment tsd-typography"><p>Supported virtual node kinds.</p>
|
|
2
|
+
</div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/itsrealfortune/typescript-virtual-container/blob/6aa10e32d938703c886defa3dee9cdbf31ed343b/src/types/vfs.ts#L2">src/types/vfs.ts:2</a></li></ul></aside></div><div class="col-sidebar"><div class="page-menu"><div class="tsd-navigation settings"><details class="tsd-accordion"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg><h3>Settings</h3></summary><div class="tsd-accordion-details"><div class="tsd-filter-visibility"><span class="settings-label">Member Visibility</span><ul id="tsd-filter-options"><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-protected" name="protected"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Protected</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-inherited" name="inherited" checked/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Inherited</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-external" name="external"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>External</span></label></li></ul></div><div class="tsd-theme-toggle"><label class="settings-label" for="tsd-theme">Theme</label><select id="tsd-theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></div></div></details></div></div><div class="site-menu"><nav class="tsd-navigation"><a href="../modules.html">typescript-virtual-container - v1.5.1</a><ul class="tsd-small-nested-navigation" id="tsd-nav-container"><li>Loading...</li></ul></nav></div></div></div><footer><p class="tsd-generator">Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p></footer><div class="overlay"></div></body></html>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
<!DOCTYPE html><html class="default" lang="en" data-base="../"><head><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>VfsPersistenceMode | typescript-virtual-container - v1.
|
|
1
|
+
<!DOCTYPE html><html class="default" lang="en" data-base="../"><head><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>VfsPersistenceMode | typescript-virtual-container - v1.5.1</title><meta name="description" content="Documentation for typescript-virtual-container"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="../assets/style.css"/><link rel="stylesheet" href="../assets/highlight.css"/><script defer src="../assets/main.js"></script><script async src="../assets/icons.js" id="tsd-icons-script"></script><script async src="../assets/search.js" id="tsd-search-script"></script><script async src="../assets/navigation.js" id="tsd-nav-script"></script><script async src="../assets/hierarchy.js" id="tsd-hierarchy-script"></script></head><body><script>document.documentElement.dataset.theme = localStorage.getItem("tsd-theme") || "os";document.body.style.display="none";setTimeout(() => window.app?app.showPage():document.body.style.removeProperty("display"),500)</script><header class="tsd-page-toolbar"><div class="tsd-toolbar-contents container"><a href="../index.html" class="title">typescript-virtual-container - v1.5.1</a><div id="tsd-toolbar-links"></div><button id="tsd-search-trigger" class="tsd-widget" aria-label="Search"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-search"></use></svg></button><dialog id="tsd-search" aria-label="Search"><input role="combobox" id="tsd-search-input" aria-controls="tsd-search-results" aria-autocomplete="list" aria-expanded="true" autocapitalize="off" autocomplete="off" placeholder="Search the docs" maxLength="100"/><ul role="listbox" id="tsd-search-results"></ul><div id="tsd-search-status" aria-live="polite" aria-atomic="true"><div>Preparing search index...</div></div></dialog><a href="#" class="tsd-widget menu" id="tsd-toolbar-menu-trigger" data-toggle="menu" aria-label="Menu"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-menu"></use></svg></a></div></header><div class="container container-main"><div class="col-content"><div class="tsd-page-title"><ul class="tsd-breadcrumb" aria-label="Breadcrumb"><li><a href="" aria-current="page">VfsPersistenceMode</a></li></ul><h1>Type Alias VfsPersistenceMode</h1></div><div class="tsd-signature"><span class="tsd-kind-type-alias">VfsPersistenceMode</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">"memory"</span> <span class="tsd-signature-symbol">|</span> <span class="tsd-signature-type">"fs"</span></div><div class="tsd-comment tsd-typography"><p>"memory" — pure in-memory, no disk I/O (default).</p>
|
|
2
2
|
<p>"fs" — mirrors the VFS tree to a directory on the host filesystem.
|
|
3
3
|
<code>snapshotPath</code> must be set to the directory where the binary
|
|
4
4
|
snapshot file will be read/written (<code>vfs-snapshot.vfsb</code>).</p>
|
|
5
|
-
</div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/itsrealfortune/typescript-virtual-container/blob/
|
|
5
|
+
</div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/itsrealfortune/typescript-virtual-container/blob/6aa10e32d938703c886defa3dee9cdbf31ed343b/src/VirtualFileSystem/index.ts#L36">src/VirtualFileSystem/index.ts:36</a></li></ul></aside></div><div class="col-sidebar"><div class="page-menu"><div class="tsd-navigation settings"><details class="tsd-accordion"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg><h3>Settings</h3></summary><div class="tsd-accordion-details"><div class="tsd-filter-visibility"><span class="settings-label">Member Visibility</span><ul id="tsd-filter-options"><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-protected" name="protected"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Protected</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-inherited" name="inherited" checked/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Inherited</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-external" name="external"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>External</span></label></li></ul></div><div class="tsd-theme-toggle"><label class="settings-label" for="tsd-theme">Theme</label><select id="tsd-theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></div></div></details></div></div><div class="site-menu"><nav class="tsd-navigation"><a href="../modules.html">typescript-virtual-container - v1.5.1</a><ul class="tsd-small-nested-navigation" id="tsd-nav-container"><li>Loading...</li></ul></nav></div></div></div><footer><p class="tsd-generator">Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p></footer><div class="overlay"></div></body></html>
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
<!DOCTYPE html><html class="default" lang="en" data-base="../"><head><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>VfsSnapshotNode | typescript-virtual-container - v1.
|
|
2
|
-
</div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/itsrealfortune/typescript-virtual-container/blob/
|
|
1
|
+
<!DOCTYPE html><html class="default" lang="en" data-base="../"><head><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>VfsSnapshotNode | typescript-virtual-container - v1.5.1</title><meta name="description" content="Documentation for typescript-virtual-container"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="../assets/style.css"/><link rel="stylesheet" href="../assets/highlight.css"/><script defer src="../assets/main.js"></script><script async src="../assets/icons.js" id="tsd-icons-script"></script><script async src="../assets/search.js" id="tsd-search-script"></script><script async src="../assets/navigation.js" id="tsd-nav-script"></script><script async src="../assets/hierarchy.js" id="tsd-hierarchy-script"></script></head><body><script>document.documentElement.dataset.theme = localStorage.getItem("tsd-theme") || "os";document.body.style.display="none";setTimeout(() => window.app?app.showPage():document.body.style.removeProperty("display"),500)</script><header class="tsd-page-toolbar"><div class="tsd-toolbar-contents container"><a href="../index.html" class="title">typescript-virtual-container - v1.5.1</a><div id="tsd-toolbar-links"></div><button id="tsd-search-trigger" class="tsd-widget" aria-label="Search"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-search"></use></svg></button><dialog id="tsd-search" aria-label="Search"><input role="combobox" id="tsd-search-input" aria-controls="tsd-search-results" aria-autocomplete="list" aria-expanded="true" autocapitalize="off" autocomplete="off" placeholder="Search the docs" maxLength="100"/><ul role="listbox" id="tsd-search-results"></ul><div id="tsd-search-status" aria-live="polite" aria-atomic="true"><div>Preparing search index...</div></div></dialog><a href="#" class="tsd-widget menu" id="tsd-toolbar-menu-trigger" data-toggle="menu" aria-label="Menu"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-menu"></use></svg></a></div></header><div class="container container-main"><div class="col-content"><div class="tsd-page-title"><ul class="tsd-breadcrumb" aria-label="Breadcrumb"><li><a href="" aria-current="page">VfsSnapshotNode</a></li></ul><h1>Type Alias VfsSnapshotNode</h1></div><div class="tsd-signature"><span class="tsd-kind-type-alias">VfsSnapshotNode</span><span class="tsd-signature-symbol">:</span> <a href="../interfaces/VfsSnapshotFileNode.html" class="tsd-signature-type tsd-kind-interface">VfsSnapshotFileNode</a> <span class="tsd-signature-symbol">|</span> <a href="../interfaces/VfsSnapshotDirectoryNode.html" class="tsd-signature-type tsd-kind-interface">VfsSnapshotDirectoryNode</a></div><div class="tsd-comment tsd-typography"><p>Union of serialized snapshot node variants.</p>
|
|
2
|
+
</div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/itsrealfortune/typescript-virtual-container/blob/6aa10e32d938703c886defa3dee9cdbf31ed343b/src/types/vfs.ts#L76">src/types/vfs.ts:76</a></li></ul></aside></div><div class="col-sidebar"><div class="page-menu"><div class="tsd-navigation settings"><details class="tsd-accordion"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg><h3>Settings</h3></summary><div class="tsd-accordion-details"><div class="tsd-filter-visibility"><span class="settings-label">Member Visibility</span><ul id="tsd-filter-options"><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-protected" name="protected"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Protected</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-inherited" name="inherited" checked/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Inherited</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-external" name="external"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>External</span></label></li></ul></div><div class="tsd-theme-toggle"><label class="settings-label" for="tsd-theme">Theme</label><select id="tsd-theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></div></div></details></div></div><div class="site-menu"><nav class="tsd-navigation"><a href="../modules.html">typescript-virtual-container - v1.5.1</a><ul class="tsd-small-nested-navigation" id="tsd-nav-container"><li>Loading...</li></ul></nav></div></div></div><footer><p class="tsd-generator">Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p></footer><div class="overlay"></div></body></html>
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"type": "module",
|
|
7
|
-
"version": "1.
|
|
7
|
+
"version": "1.5.1",
|
|
8
8
|
"license": "MIT",
|
|
9
9
|
"repository": {
|
|
10
10
|
"type": "git",
|
|
@@ -37,18 +37,19 @@
|
|
|
37
37
|
"example-serve": "cd examples && bun server.js",
|
|
38
38
|
"web-full-build": "bunx esbuild src/web-api.ts --bundle --platform=browser --format=esm --target=es2020 --outfile=builds/web-full-api.min.js --tree-shaking=true --minify --alias:node:events=./polyfills/node_events/index.js --alias:node:path=./polyfills/node_path/index.js --alias:node:os=./polyfills/node_os/index.js --alias:node:fs=./polyfills/node_fs/index.js --alias:node:fs/promises=./polyfills/node_fs/promises.js --alias:node:crypto=./polyfills/node_crypto/index.js --alias:node:child_process=./polyfills/node_child_process/index.js --alias:node:zlib=./polyfills/node_zlib/index.js --alias:node:vm=./polyfills/node_vm/index.js",
|
|
39
39
|
"publish-package": "bash ./scripts/publish-package.sh",
|
|
40
|
-
"self-standalone-build": "
|
|
40
|
+
"self-standalone-build": "node scripts/build-all.mjs",
|
|
41
41
|
"standalone-build": "bunx esbuild src/standalone.ts --bundle --platform=node --target=node18 --outfile=builds/standalone.cjs --tree-shaking=true --minify --banner:js='#!/usr/bin/env node'",
|
|
42
|
-
"build-all": "
|
|
42
|
+
"build-all": "node scripts/build-all.mjs",
|
|
43
43
|
"publish-doc": "bunx typedoc && bunx gh-pages -d docs",
|
|
44
|
-
"generate-manuals": "
|
|
44
|
+
"generate-manuals": "node scripts/generate-manuals-bundle.mjs"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"@biomejs/biome": "^2.4.15",
|
|
48
|
-
"@types/bun": "^1.3.
|
|
48
|
+
"@types/bun": "^1.3.14",
|
|
49
49
|
"@types/node": "^25.7.0",
|
|
50
50
|
"@types/ssh2": "^1.15.5",
|
|
51
51
|
"gh-pages": "^6.3.0",
|
|
52
|
+
"rimraf": "^6.1.3",
|
|
52
53
|
"typescript": "^6.0.3"
|
|
53
54
|
},
|
|
54
55
|
"peerDependencies": {
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* scripts/build-all.mjs
|
|
4
|
+
*
|
|
5
|
+
* Orchestrates the full build pipeline:
|
|
6
|
+
* 1. rimraf builds/ — clean previous artifacts
|
|
7
|
+
* 2. generate-manuals-bundle — inline all man pages
|
|
8
|
+
* 3. esbuild all targets — with dynamic output filenames
|
|
9
|
+
* 4. copy web build to examples/
|
|
10
|
+
* 5. update README.md — replace filenames in marked sections
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { execSync } from "node:child_process";
|
|
14
|
+
import { copyFileSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
15
|
+
import { join } from "node:path";
|
|
16
|
+
import { fileURLToPath } from "node:url";
|
|
17
|
+
import { BUILDS_DIR, NAMES } from "./build-names.mjs";
|
|
18
|
+
import { dirname } from "node:path";
|
|
19
|
+
|
|
20
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
21
|
+
const root = join(__dirname, "..");
|
|
22
|
+
const GH_BASE = "https://raw.githubusercontent.com/itsrealfortune/typescript-virtual-container/refs/heads/main/builds";
|
|
23
|
+
|
|
24
|
+
function run(cmd) {
|
|
25
|
+
console.log(`\n$ ${cmd}`);
|
|
26
|
+
execSync(cmd, { stdio: "inherit", cwd: root });
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// ── 1. Clean ──────────────────────────────────────────────────────────────────
|
|
30
|
+
run(`bunx rimraf ${BUILDS_DIR}`);
|
|
31
|
+
mkdirSync(BUILDS_DIR, { recursive: true });
|
|
32
|
+
|
|
33
|
+
// ── 2. Manuals bundle ─────────────────────────────────────────────────────────
|
|
34
|
+
run("node scripts/generate-manuals-bundle.mjs");
|
|
35
|
+
|
|
36
|
+
// ── 3. esbuild targets ───────────────────────────────────────────────────────
|
|
37
|
+
const ESBUILD = "bunx esbuild";
|
|
38
|
+
const BANNER = `--banner:js='#!/usr/bin/env node'`;
|
|
39
|
+
|
|
40
|
+
const targets = [
|
|
41
|
+
// self-standalone (ESM, interactive CLI)
|
|
42
|
+
`${ESBUILD} src/self-standalone.ts --bundle --platform=node --format=esm --target=node18 \
|
|
43
|
+
--outfile=${BUILDS_DIR}/${NAMES.selfStandalone} --tree-shaking=true --minify ${BANNER}`,
|
|
44
|
+
|
|
45
|
+
// standalone SSH+SFTP (CJS)
|
|
46
|
+
`${ESBUILD} src/standalone.ts --bundle --platform=node --target=node18 \
|
|
47
|
+
--outfile=${BUILDS_DIR}/${NAMES.standalone} --tree-shaking=true --minify ${BANNER}`,
|
|
48
|
+
|
|
49
|
+
// standalone SSH only (no SFTP)
|
|
50
|
+
`${ESBUILD} src/standalone-wo-sftp.ts --bundle --platform=node --target=node18 \
|
|
51
|
+
--outfile=${BUILDS_DIR}/${NAMES.standaloneNoSftp} --tree-shaking=true --minify ${BANNER}`,
|
|
52
|
+
|
|
53
|
+
// web shell (browser ESM)
|
|
54
|
+
`${ESBUILD} src/web.ts --bundle --platform=browser --format=esm --target=es2020 \
|
|
55
|
+
--outfile=${BUILDS_DIR}/${NAMES.web} --tree-shaking=true --minify`,
|
|
56
|
+
|
|
57
|
+
// web full API (browser ESM + node polyfills)
|
|
58
|
+
`${ESBUILD} src/web-api.ts --bundle --platform=browser --format=esm --target=es2020 \
|
|
59
|
+
--outfile=${BUILDS_DIR}/${NAMES.webFull} --tree-shaking=true --minify \
|
|
60
|
+
--alias:node:events=./polyfills/node_events/index.js \
|
|
61
|
+
--alias:node:path=./polyfills/node_path/index.js \
|
|
62
|
+
--alias:node:os=./polyfills/node_os/index.js \
|
|
63
|
+
--alias:node:fs=./polyfills/node_fs/index.js \
|
|
64
|
+
--alias:node:fs/promises=./polyfills/node_fs/promises.js \
|
|
65
|
+
--alias:node:crypto=./polyfills/node_crypto/index.js \
|
|
66
|
+
--alias:node:child_process=./polyfills/node_child_process/index.js \
|
|
67
|
+
--alias:node:zlib=./polyfills/node_zlib/index.js \
|
|
68
|
+
--alias:node:vm=./polyfills/node_vm/index.js`,
|
|
69
|
+
];
|
|
70
|
+
|
|
71
|
+
for (const cmd of targets) {
|
|
72
|
+
run(cmd.replace(/\s+/g, " ").trim());
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// ── 4. Copy web to examples/ ─────────────────────────────────────────────────
|
|
76
|
+
const examplesDir = join(root, "examples");
|
|
77
|
+
mkdirSync(examplesDir, { recursive: true });
|
|
78
|
+
copyFileSync(
|
|
79
|
+
join(BUILDS_DIR, NAMES.web),
|
|
80
|
+
join(examplesDir, "web.min.js"),
|
|
81
|
+
);
|
|
82
|
+
console.log(`\n✓ Copied ${NAMES.web} → examples/web.min.js`);
|
|
83
|
+
|
|
84
|
+
// ── 5. Update README.md ───────────────────────────────────────────────────────
|
|
85
|
+
const readmePath = join(root, "README.md");
|
|
86
|
+
let readme = readFileSync(readmePath, "utf8");
|
|
87
|
+
|
|
88
|
+
const { selfStandalone, standalone, standaloneNoSftp, web, webFull } = NAMES;
|
|
89
|
+
const selfBase = selfStandalone.replace(".mjs", ""); // local filename without ext for the rm -f
|
|
90
|
+
|
|
91
|
+
// Helper: replace content between <!-- BUILD:tag --> and <!-- /BUILD:tag -->
|
|
92
|
+
function replaceSection(tag, content) {
|
|
93
|
+
const re = new RegExp(
|
|
94
|
+
`(<!-- BUILD:${tag} -->)[\\s\\S]*?(<!-- \\/BUILD:${tag} -->)`,
|
|
95
|
+
"g",
|
|
96
|
+
);
|
|
97
|
+
readme = readme.replace(re, `$1\n${content}\n$2`);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Overview table — web and selfStandalone filenames
|
|
101
|
+
replaceSection(
|
|
102
|
+
"web",
|
|
103
|
+
`\`builds/${web}\` / \`builds/${webFull}\``,
|
|
104
|
+
);
|
|
105
|
+
replaceSection(
|
|
106
|
+
"selfStandalone",
|
|
107
|
+
`\`builds/${selfStandalone}\``,
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
// curl commands block
|
|
111
|
+
replaceSection(
|
|
112
|
+
"curl-start",
|
|
113
|
+
[
|
|
114
|
+
`# Interactive local shell — persists VFS in .vfs/ in the current directory`,
|
|
115
|
+
`curl -s ${GH_BASE}/${selfStandalone} -o ${selfStandalone} && node ${selfStandalone} && rm -f ${selfStandalone}`,
|
|
116
|
+
``,
|
|
117
|
+
`# SSH server (connect with any SSH client on port 2222)`,
|
|
118
|
+
`curl -s ${GH_BASE}/${standalone} -o ${standalone} && node ${standalone} && rm -f ${standalone}`,
|
|
119
|
+
``,
|
|
120
|
+
`# SSH server without SFTP (lighter build)`,
|
|
121
|
+
`curl -s ${GH_BASE}/${standaloneNoSftp} -o ${standaloneNoSftp} && node ${standaloneNoSftp} && rm -f ${standaloneNoSftp}`,
|
|
122
|
+
].join("\n"),
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
// self-standalone options block
|
|
126
|
+
replaceSection(
|
|
127
|
+
"selfStandalone-options",
|
|
128
|
+
[
|
|
129
|
+
`**\`${selfStandalone}\` options:**`,
|
|
130
|
+
``,
|
|
131
|
+
`\`\`\`bash`,
|
|
132
|
+
`node ${selfStandalone} # boot as root`,
|
|
133
|
+
`node ${selfStandalone} --user alice # boot as alice (prompts for password if set)`,
|
|
134
|
+
`node ${selfStandalone} --user=alice # same, inline form`,
|
|
135
|
+
`SSH_MIMIC_HOSTNAME=my-box node ${selfStandalone} # custom hostname`,
|
|
136
|
+
`\`\`\``,
|
|
137
|
+
].join("\n"),
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
// Web bundles comparison table
|
|
141
|
+
replaceSection(
|
|
142
|
+
"web-table",
|
|
143
|
+
[
|
|
144
|
+
`| \`builds/${web}\` | ESM | \`createWebShell()\` | Embedded terminals, modern bundlers |`,
|
|
145
|
+
`| \`builds/${webFull}\` | ESM | \`createVirtualShellShim()\` | Full \`VirtualShell\`-like API in the browser |`,
|
|
146
|
+
].join("\n"),
|
|
147
|
+
);
|
|
148
|
+
replaceSection(
|
|
149
|
+
"web-options",
|
|
150
|
+
[
|
|
151
|
+
`**\`${web}\`** — lightweight shell with IndexedDB VFS:`,
|
|
152
|
+
``,
|
|
153
|
+
`\`\`\`html`,
|
|
154
|
+
`<script type="module">`,
|
|
155
|
+
` import { createWebShell } from "./builds/${web}";`,
|
|
156
|
+
``,
|
|
157
|
+
` const shell = createWebShell("web-vm", {`,
|
|
158
|
+
` vfs: { databaseName: "virtual-env-js", storeName: "vfs" },`,
|
|
159
|
+
` });`,
|
|
160
|
+
` await shell.ensureInitialized();`,
|
|
161
|
+
``,
|
|
162
|
+
` const out = await shell.executeCommandLine("ls /etc && echo hello");`,
|
|
163
|
+
` console.log(out.stdout);`,
|
|
164
|
+
`</script>`,
|
|
165
|
+
`\`\`\``,
|
|
166
|
+
``,
|
|
167
|
+
`**\`${webFull}\`** — mirrors the \`VirtualShell\` programmatic API:`,
|
|
168
|
+
``,
|
|
169
|
+
`\`\`\`html`,
|
|
170
|
+
`<script type="module">`,
|
|
171
|
+
` import { createVirtualShellShim } from "./builds/${webFull}";`,
|
|
172
|
+
``,
|
|
173
|
+
` const shell = createVirtualShellShim("web-vm");`,
|
|
174
|
+
` await shell.ensureInitialized();`,
|
|
175
|
+
` await shell.executeCommandLine("mkdir -p /app && echo hello > /app/file.txt");`,
|
|
176
|
+
` console.log(shell.getVfs().readFile("/app/file.txt")); // hello`,
|
|
177
|
+
`</script>`,
|
|
178
|
+
`\`\`\``,
|
|
179
|
+
].join("\n"),
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
// Changelog lines
|
|
183
|
+
replaceSection(
|
|
184
|
+
"changelog",
|
|
185
|
+
[
|
|
186
|
+
`- [x] Web shell bundles (\`${web}\`, \`${webFull}\`) — fully browser-native with IndexedDB VFS`,
|
|
187
|
+
`- [x] Self-standalone CLI (\`${selfStandalone}\`) — single-file interactive shell, per-user history, tab completion`,
|
|
188
|
+
].join("\n"),
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
writeFileSync(readmePath, readme, "utf8");
|
|
192
|
+
console.log("✓ README.md updated with current build filenames");
|
|
193
|
+
|
|
194
|
+
// ── Summary ──────────────────────────────────────────────────────────────────
|
|
195
|
+
console.log("\n✅ Build complete:");
|
|
196
|
+
for (const [key, name] of Object.entries(NAMES)) {
|
|
197
|
+
console.log(` ${key.padEnd(16)} → builds/${name}`);
|
|
198
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* scripts/build-names.mjs
|
|
3
|
+
*
|
|
4
|
+
* Computes dynamic output filenames for all build targets from:
|
|
5
|
+
* - package.json → package version (e.g. 1.5.0)
|
|
6
|
+
* - VirtualShell → default kernel version (e.g. 1.0.0+itsrealfortune+1-amd64)
|
|
7
|
+
*
|
|
8
|
+
* Used by build-all.mjs to pass --outfile to esbuild.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { readFileSync } from "node:fs";
|
|
12
|
+
import { fileURLToPath } from "node:url";
|
|
13
|
+
import { join, dirname } from "node:path";
|
|
14
|
+
|
|
15
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
16
|
+
const root = join(__dirname, "..");
|
|
17
|
+
|
|
18
|
+
// Package version
|
|
19
|
+
const pkg = JSON.parse(readFileSync(join(root, "package.json"), "utf8"));
|
|
20
|
+
const pkgVersion = pkg.version; // e.g. "1.5.0"
|
|
21
|
+
|
|
22
|
+
// Kernel version — read from VirtualShell source to stay in sync
|
|
23
|
+
const shellSrc = readFileSync(join(root, "src/VirtualShell/index.ts"), "utf8");
|
|
24
|
+
const kernelMatch = shellSrc.match(/kernel:\s*"([^"]+)"/);
|
|
25
|
+
const kernelRaw = kernelMatch?.[1] ?? "unknown";
|
|
26
|
+
// Shorten: "1.0.0+itsrealfortune+1-amd64" → "k1.0.0"
|
|
27
|
+
const kernelVersion = `k${kernelRaw.split("+")[0]}`;
|
|
28
|
+
|
|
29
|
+
export const BUILDS_DIR = join(root, "builds");
|
|
30
|
+
|
|
31
|
+
export const NAMES = {
|
|
32
|
+
selfStandalone: `fortune-nyx-v${pkgVersion}-directbash-${kernelVersion}.mjs`,
|
|
33
|
+
standalone: `fortune-nyx-v${pkgVersion}-ssh.cjs`,
|
|
34
|
+
standaloneNoSftp:`fortune-nyx-v${pkgVersion}-ssh-nosftp.js`,
|
|
35
|
+
web: `fortune-nyx-v${pkgVersion}-web.min.js`,
|
|
36
|
+
webFull: `fortune-nyx-v${pkgVersion}-web-full.min.js`,
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// Print for shell consumption: NAME=value pairs
|
|
40
|
+
if (process.argv[1] === fileURLToPath(import.meta.url)) {
|
|
41
|
+
for (const [key, value] of Object.entries(NAMES)) {
|
|
42
|
+
console.log(`${key}=${value}`);
|
|
43
|
+
}
|
|
44
|
+
}
|
package/src/SSHMimic/exec.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { makeDefaultEnv, runCommand } from "../commands";
|
|
1
|
+
import { makeDefaultEnv, runCommand, userHome } from "../commands";
|
|
2
2
|
import type { ExecStream } from "../types/streams";
|
|
3
3
|
import type { VirtualShell } from "../VirtualShell";
|
|
4
4
|
|
|
@@ -22,7 +22,7 @@ export function runExec(
|
|
|
22
22
|
authUser,
|
|
23
23
|
hostname,
|
|
24
24
|
"exec",
|
|
25
|
-
|
|
25
|
+
userHome(authUser),
|
|
26
26
|
shell,
|
|
27
27
|
undefined,
|
|
28
28
|
makeDefaultEnv(authUser, hostname),
|
package/src/SSHMimic/index.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { EventEmitter } from "node:events";
|
|
2
2
|
import { Server as SshServer } from "ssh2";
|
|
3
3
|
import { VirtualShell } from "../VirtualShell";
|
|
4
|
+
import { userHome } from "../commands";
|
|
4
5
|
import { createPerfLogger, type PerfLogger } from "../utils/perfLogger";
|
|
5
6
|
import { runExec } from "./exec";
|
|
6
7
|
import { loadOrCreateHostKey } from "./hostKey";
|
|
@@ -104,7 +105,7 @@ class SshMimic extends EventEmitter {
|
|
|
104
105
|
// ── Home directory bootstrap ─────────────────────────────────────────────
|
|
105
106
|
|
|
106
107
|
private ensureHomeDir(authUser: string): void {
|
|
107
|
-
const homePath =
|
|
108
|
+
const homePath = userHome(authUser);
|
|
108
109
|
if (!this.shell.vfs.exists(homePath)) {
|
|
109
110
|
this.shell.vfs.mkdir(homePath, 0o755);
|
|
110
111
|
this.shell.vfs.writeFile(
|
package/src/SSHMimic/sftp.ts
CHANGED
|
@@ -7,6 +7,7 @@ import type { VfsNodeStats } from "../types/vfs";
|
|
|
7
7
|
import type { PerfLogger } from "../utils/perfLogger";
|
|
8
8
|
import { createPerfLogger } from "../utils/perfLogger";
|
|
9
9
|
import type VirtualFileSystem from "../VirtualFileSystem";
|
|
10
|
+
import { userHome } from "../commands";
|
|
10
11
|
import { VirtualShell } from "../VirtualShell";
|
|
11
12
|
import type { VirtualUserManager } from "../VirtualUserManager";
|
|
12
13
|
import { loadOrCreateHostKey } from "./hostKey";
|
|
@@ -246,7 +247,7 @@ export class SftpMimic extends EventEmitter {
|
|
|
246
247
|
this.getVfs().mkdir(homeRoot, 0o755);
|
|
247
248
|
}
|
|
248
249
|
|
|
249
|
-
const homePath =
|
|
250
|
+
const homePath = userHome(authUser);
|
|
250
251
|
if (!this.getVfs().exists(homePath)) {
|
|
251
252
|
this.getVfs().mkdir(homePath, 0o755);
|
|
252
253
|
this.getVfs().writeFile(
|
|
@@ -384,7 +385,7 @@ export class SftpMimic extends EventEmitter {
|
|
|
384
385
|
* This is standard SFTP behavior where the "working directory" is always the home.
|
|
385
386
|
*/
|
|
386
387
|
private resolveRequestPath(requestPath: string, authUser: string): string {
|
|
387
|
-
const homePath =
|
|
388
|
+
const homePath = userHome(authUser);
|
|
388
389
|
|
|
389
390
|
// Empty path or "." → resolve to home directory
|
|
390
391
|
if (!requestPath || requestPath === ".") {
|
|
@@ -408,7 +409,7 @@ export class SftpMimic extends EventEmitter {
|
|
|
408
409
|
* @returns true if path is within home, false if traversal attempt detected
|
|
409
410
|
*/
|
|
410
411
|
private isPathWithinHome(targetPath: string, authUser: string): boolean {
|
|
411
|
-
const homePath =
|
|
412
|
+
const homePath = userHome(authUser);
|
|
412
413
|
const normalized = path.posix.normalize(targetPath);
|
|
413
414
|
|
|
414
415
|
// Allow access to home directory itself
|
|
@@ -134,10 +134,11 @@ class VirtualFileSystem extends EventEmitter {
|
|
|
134
134
|
this.journalFile = path.resolve(options.snapshotPath, "vfs-journal.bin");
|
|
135
135
|
this.evictionThreshold = options.evictionThresholdBytes ?? 64 * 1024; // 64 KB default
|
|
136
136
|
this.flushAfterNWrites = options.flushAfterNWrites ?? 500;
|
|
137
|
-
const intervalMs = options.flushIntervalMs ??
|
|
137
|
+
const intervalMs = options.flushIntervalMs ?? 1_000;
|
|
138
138
|
if (intervalMs > 0) {
|
|
139
139
|
this._flushTimer = setInterval(() => {
|
|
140
|
-
|
|
140
|
+
const dirty = this._dirty;
|
|
141
|
+
if (dirty) void this._autoFlush();
|
|
141
142
|
}, intervalMs);
|
|
142
143
|
// Don't block process exit on this timer
|
|
143
144
|
if (typeof this._flushTimer === "object" && this._flushTimer !== null && "unref" in this._flushTimer) {
|
|
@@ -303,7 +304,8 @@ class VirtualFileSystem extends EventEmitter {
|
|
|
303
304
|
|
|
304
305
|
const dir = path.dirname(this.snapshotFile);
|
|
305
306
|
fsSync.mkdirSync(dir, { recursive: true });
|
|
306
|
-
const
|
|
307
|
+
const root = this.root;
|
|
308
|
+
const binary = encodeVfs(root);
|
|
307
309
|
fsSync.writeFileSync(this.snapshotFile, binary);
|
|
308
310
|
// Checkpoint complete — truncate the journal (entries are now in the snapshot)
|
|
309
311
|
if (this.journalFile) truncateJournal(this.journalFile);
|
|
@@ -382,6 +384,47 @@ class VirtualFileSystem extends EventEmitter {
|
|
|
382
384
|
try { this.root = root; } finally { this._replayMode = prev; }
|
|
383
385
|
}
|
|
384
386
|
|
|
387
|
+
/**
|
|
388
|
+
* Merge a static rootfs tree into the existing live tree.
|
|
389
|
+
* Used by `bootstrapLinuxRootfs` when a persisted snapshot already exists,
|
|
390
|
+
* to layer in missing system files without overwriting user data.
|
|
391
|
+
*
|
|
392
|
+
* Rules:
|
|
393
|
+
* - Directories: recurse — never overwrite a live dir with an empty one.
|
|
394
|
+
* - Files/stubs: only written if the path does NOT yet exist in the live tree.
|
|
395
|
+
* This ensures user-created files always win over static defaults.
|
|
396
|
+
*
|
|
397
|
+
* @internal
|
|
398
|
+
*/
|
|
399
|
+
public mergeRootTree(incoming: InternalDirectoryNode): void {
|
|
400
|
+
const prev = this._replayMode;
|
|
401
|
+
this._replayMode = true;
|
|
402
|
+
try { this._mergeDir(this.root, incoming); } finally { this._replayMode = prev; }
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
private _mergeDir(live: InternalDirectoryNode, incoming: InternalDirectoryNode): void {
|
|
406
|
+
for (const [name, node] of Object.entries(incoming.children)) {
|
|
407
|
+
const existing = live.children[name];
|
|
408
|
+
if (node.type === "directory") {
|
|
409
|
+
if (!existing) {
|
|
410
|
+
// Dir doesn't exist yet — add it
|
|
411
|
+
live.children[name] = node;
|
|
412
|
+
live._childCount++;
|
|
413
|
+
} else if (existing.type === "directory") {
|
|
414
|
+
// Both dirs — recurse
|
|
415
|
+
this._mergeDir(existing, node);
|
|
416
|
+
}
|
|
417
|
+
// existing is a file where dir expected — leave user file alone
|
|
418
|
+
} else {
|
|
419
|
+
// File or stub — only add if not already present
|
|
420
|
+
if (!existing) {
|
|
421
|
+
live.children[name] = node;
|
|
422
|
+
live._childCount++;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
385
428
|
/** Serialise current tree to VFSB binary. Used for the static rootfs cache. */
|
|
386
429
|
public encodeBinary(): Buffer {
|
|
387
430
|
return encodeVfs(this.root);
|
|
@@ -142,11 +142,18 @@ export function decodeJournal(buf: Buffer): JournalEntry[] {
|
|
|
142
142
|
/** Append a single entry to the journal file (O_APPEND, atomic write). */
|
|
143
143
|
export function appendJournalEntry(journalPath: string, entry: JournalEntry): void {
|
|
144
144
|
const buf = encodeEntry(entry);
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
145
|
+
if (fsSync.existsSync(journalPath)) {
|
|
146
|
+
const fd = fsSync.openSync(journalPath, fsSync.constants.O_WRONLY | fsSync.constants.O_CREAT | fsSync.constants.O_APPEND);
|
|
147
|
+
try {
|
|
148
|
+
fsSync.writeSync(fd, buf);
|
|
149
|
+
} finally {
|
|
150
|
+
fsSync.closeSync(fd);
|
|
151
|
+
}
|
|
152
|
+
} else {
|
|
153
|
+
if(!fsSync.existsSync(".vfs")) {
|
|
154
|
+
fsSync.mkdirSync(".vfs");
|
|
155
|
+
}
|
|
156
|
+
fsSync.writeFileSync(journalPath, buf);
|
|
150
157
|
}
|
|
151
158
|
}
|
|
152
159
|
|