typescript-virtual-container 1.4.9 → 1.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.
Files changed (129) hide show
  1. package/.vscode/settings.json +1 -1
  2. package/README.md +117 -79
  3. package/builds/self-standalone.mjs +1768 -0
  4. package/builds/standalone-wo-sftp.js +735 -267
  5. package/builds/standalone.cjs +735 -267
  6. package/bun.lock +3 -3
  7. package/dist/SSHMimic/exec.js +2 -2
  8. package/dist/SSHMimic/exec.js.map +1 -1
  9. package/dist/SSHMimic/index.d.ts.map +1 -1
  10. package/dist/SSHMimic/index.js +2 -1
  11. package/dist/SSHMimic/index.js.map +1 -1
  12. package/dist/SSHMimic/sftp.d.ts.map +1 -1
  13. package/dist/SSHMimic/sftp.js +4 -3
  14. package/dist/SSHMimic/sftp.js.map +1 -1
  15. package/dist/VirtualFileSystem/index.d.ts +14 -0
  16. package/dist/VirtualFileSystem/index.d.ts.map +1 -1
  17. package/dist/VirtualFileSystem/index.js +51 -3
  18. package/dist/VirtualFileSystem/index.js.map +1 -1
  19. package/dist/VirtualFileSystem/journal.d.ts.map +1 -1
  20. package/dist/VirtualFileSystem/journal.js +11 -5
  21. package/dist/VirtualFileSystem/journal.js.map +1 -1
  22. package/dist/VirtualShell/shell.js +12 -12
  23. package/dist/VirtualShell/shell.js.map +1 -1
  24. package/dist/VirtualUserManager/index.js +8 -11
  25. package/dist/VirtualUserManager/index.js.map +1 -1
  26. package/dist/commands/apt.js +3 -3
  27. package/dist/commands/apt.js.map +1 -1
  28. package/dist/commands/cd.d.ts.map +1 -1
  29. package/dist/commands/cd.js +2 -1
  30. package/dist/commands/cd.js.map +1 -1
  31. package/dist/commands/helpers.d.ts +1 -1
  32. package/dist/commands/helpers.d.ts.map +1 -1
  33. package/dist/commands/helpers.js +3 -2
  34. package/dist/commands/helpers.js.map +1 -1
  35. package/dist/commands/index.d.ts +1 -1
  36. package/dist/commands/index.d.ts.map +1 -1
  37. package/dist/commands/index.js +1 -1
  38. package/dist/commands/index.js.map +1 -1
  39. package/dist/commands/lsb-release.js +1 -1
  40. package/dist/commands/lsb-release.js.map +1 -1
  41. package/dist/commands/runtime.d.ts +2 -0
  42. package/dist/commands/runtime.d.ts.map +1 -1
  43. package/dist/commands/runtime.js +5 -1
  44. package/dist/commands/runtime.js.map +1 -1
  45. package/dist/modules/linuxRootfs.d.ts +9 -5
  46. package/dist/modules/linuxRootfs.d.ts.map +1 -1
  47. package/dist/modules/linuxRootfs.js +1079 -148
  48. package/dist/modules/linuxRootfs.js.map +1 -1
  49. package/dist/self-standalone.js +22 -12
  50. package/dist/self-standalone.js.map +1 -1
  51. package/docs/assets/hierarchy.js +1 -1
  52. package/docs/classes/HoneyPot.html +9 -9
  53. package/docs/classes/IdleManager.html +8 -8
  54. package/docs/classes/SshClient.html +18 -18
  55. package/docs/classes/VirtualFileSystem.html +34 -34
  56. package/docs/classes/VirtualPackageManager.html +13 -13
  57. package/docs/classes/VirtualSftpServer.html +3 -3
  58. package/docs/classes/VirtualShell.html +28 -28
  59. package/docs/classes/VirtualSshServer.html +5 -5
  60. package/docs/classes/VirtualUserManager.html +27 -27
  61. package/docs/functions/assertDiff.html +2 -2
  62. package/docs/functions/diffSnapshots.html +2 -2
  63. package/docs/functions/formatDiff.html +2 -2
  64. package/docs/functions/getArg.html +2 -2
  65. package/docs/functions/getFlag.html +2 -2
  66. package/docs/functions/ifFlag.html +2 -2
  67. package/docs/hierarchy.html +1 -1
  68. package/docs/index.html +10 -8
  69. package/docs/interfaces/AuditLogEntry.html +3 -3
  70. package/docs/interfaces/CommandContext.html +12 -12
  71. package/docs/interfaces/CommandResult.html +13 -13
  72. package/docs/interfaces/ExecStream.html +6 -6
  73. package/docs/interfaces/HoneyPotStats.html +3 -3
  74. package/docs/interfaces/IdleManagerOptions.html +3 -3
  75. package/docs/interfaces/InstalledPackage.html +11 -11
  76. package/docs/interfaces/NanoEditorSession.html +5 -5
  77. package/docs/interfaces/PackageDefinition.html +14 -14
  78. package/docs/interfaces/PackageFile.html +5 -5
  79. package/docs/interfaces/PasswordChallenge.html +9 -9
  80. package/docs/interfaces/RemoveOptions.html +3 -3
  81. package/docs/interfaces/ShellEnv.html +4 -4
  82. package/docs/interfaces/ShellModule.html +8 -8
  83. package/docs/interfaces/ShellProperties.html +5 -5
  84. package/docs/interfaces/ShellStream.html +7 -7
  85. package/docs/interfaces/SudoChallenge.html +9 -9
  86. package/docs/interfaces/VfsBaseNode.html +7 -7
  87. package/docs/interfaces/VfsDiff.html +6 -6
  88. package/docs/interfaces/VfsDiffEntry.html +4 -4
  89. package/docs/interfaces/VfsDiffModified.html +6 -6
  90. package/docs/interfaces/VfsDirectoryNode.html +8 -8
  91. package/docs/interfaces/VfsFileNode.html +9 -9
  92. package/docs/interfaces/VfsOptions.html +6 -6
  93. package/docs/interfaces/VfsSnapshot.html +3 -3
  94. package/docs/interfaces/VfsSnapshotBaseNode.html +4 -4
  95. package/docs/interfaces/VfsSnapshotDirectoryNode.html +5 -5
  96. package/docs/interfaces/VfsSnapshotFileNode.html +6 -6
  97. package/docs/interfaces/VirtualActiveSession.html +7 -7
  98. package/docs/interfaces/VirtualSftpServerOptions.html +3 -3
  99. package/docs/interfaces/VirtualShellVfsLike.html +3 -3
  100. package/docs/interfaces/VirtualShellVfsOptions.html +3 -3
  101. package/docs/interfaces/WriteFileOptions.html +4 -4
  102. package/docs/modules.html +1 -1
  103. package/docs/types/ArgParseOptions.html +3 -3
  104. package/docs/types/CommandMode.html +2 -2
  105. package/docs/types/CommandOutcome.html +2 -2
  106. package/docs/types/IdleState.html +1 -1
  107. package/docs/types/VfsNodeStats.html +2 -2
  108. package/docs/types/VfsNodeType.html +2 -2
  109. package/docs/types/VfsPersistenceMode.html +2 -2
  110. package/docs/types/VfsSnapshotNode.html +2 -2
  111. package/package.json +3 -3
  112. package/src/SSHMimic/exec.ts +2 -2
  113. package/src/SSHMimic/index.ts +2 -1
  114. package/src/SSHMimic/sftp.ts +4 -3
  115. package/src/VirtualFileSystem/index.ts +46 -3
  116. package/src/VirtualFileSystem/journal.ts +10 -5
  117. package/src/VirtualShell/shell.ts +12 -12
  118. package/src/VirtualUserManager/index.ts +11 -11
  119. package/src/commands/apt.ts +3 -3
  120. package/src/commands/cd.ts +2 -1
  121. package/src/commands/helpers.ts +3 -2
  122. package/src/commands/index.ts +1 -1
  123. package/src/commands/lsb-release.ts +1 -1
  124. package/src/commands/runtime.ts +6 -1
  125. package/src/modules/linuxRootfs.ts +1293 -207
  126. package/src/self-standalone.ts +26 -12
  127. package/tests/new-features.test.ts +2 -2
  128. package/tests/sftp.test.ts +13 -13
  129. package/builds/self-standalone.js +0 -1299
@@ -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.4.9</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.4.9</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/0d803b637251950a3a6075168d6d3d1127271694/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.4.9</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
+ <!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.0</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.0</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/52880451442508494c6f496513aae8ae8d1600b8/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.0</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.4.9</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.4.9</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">&quot;file&quot;</span> <span class="tsd-signature-symbol">|</span> <span class="tsd-signature-type">&quot;directory&quot;</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/0d803b637251950a3a6075168d6d3d1127271694/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.4.9</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
+ <!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.0</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.0</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">&quot;file&quot;</span> <span class="tsd-signature-symbol">|</span> <span class="tsd-signature-type">&quot;directory&quot;</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/52880451442508494c6f496513aae8ae8d1600b8/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.0</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.4.9</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.4.9</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">&quot;memory&quot;</span> <span class="tsd-signature-symbol">|</span> <span class="tsd-signature-type">&quot;fs&quot;</span></div><div class="tsd-comment tsd-typography"><p>&quot;memory&quot; — pure in-memory, no disk I/O (default).</p>
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.0</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.0</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">&quot;memory&quot;</span> <span class="tsd-signature-symbol">|</span> <span class="tsd-signature-type">&quot;fs&quot;</span></div><div class="tsd-comment tsd-typography"><p>&quot;memory&quot; — pure in-memory, no disk I/O (default).</p>
2
2
  <p>&quot;fs&quot; — 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/0d803b637251950a3a6075168d6d3d1127271694/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.4.9</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>
5
+ </div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/itsrealfortune/typescript-virtual-container/blob/52880451442508494c6f496513aae8ae8d1600b8/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.0</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.4.9</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.4.9</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/0d803b637251950a3a6075168d6d3d1127271694/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.4.9</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
+ <!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.0</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.0</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/52880451442508494c6f496513aae8ae8d1600b8/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.0</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.4.9",
7
+ "version": "1.5.0",
8
8
  "license": "MIT",
9
9
  "repository": {
10
10
  "type": "git",
@@ -37,7 +37,7 @@
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": "bunx esbuild src/self-standalone.ts --bundle --platform=node --format=esm --target=node18 --outfile=builds/self-standalone.js --tree-shaking=true --minify --banner:js='#!/usr/bin/env node'",
40
+ "self-standalone-build": "bunx esbuild src/self-standalone.ts --bundle --platform=node --format=esm --target=node18 --outfile=builds/self-standalone.mjs --tree-shaking=true --minify --banner:js='#!/usr/bin/env node'",
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
42
  "build-all": "bun run generate-manuals && bun run self-standalone-build && bun run standalone-build && bun run standalone-build:wo-sftp && bun run web-build && bun run web-full-build && bun run example-build",
43
43
  "publish-doc": "bunx typedoc && bunx gh-pages -d docs",
@@ -45,7 +45,7 @@
45
45
  },
46
46
  "devDependencies": {
47
47
  "@biomejs/biome": "^2.4.15",
48
- "@types/bun": "^1.3.13",
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",
@@ -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
- `/home/${authUser}`,
25
+ userHome(authUser),
26
26
  shell,
27
27
  undefined,
28
28
  makeDefaultEnv(authUser, hostname),
@@ -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 = `/home/${authUser}`;
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(
@@ -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 = `/home/${authUser}`;
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 = `/home/${authUser}`;
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 = `/home/${authUser}`;
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 ?? 30_000;
137
+ const intervalMs = options.flushIntervalMs ?? 1_000;
138
138
  if (intervalMs > 0) {
139
139
  this._flushTimer = setInterval(() => {
140
- if (this._dirty) void this._autoFlush();
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 binary = encodeVfs(this.root);
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,16 @@ 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
- const fd = fsSync.openSync(journalPath, fsSync.constants.O_WRONLY | fsSync.constants.O_CREAT | fsSync.constants.O_APPEND);
146
- try {
147
- fsSync.writeSync(fd, buf);
148
- } finally {
149
- fsSync.closeSync(fd);
145
+ console.log(`[Journal] Appending entry: op=${entry.op} path=${entry.path} ${entry.content ? `content_len=${entry.content.length}` : ""}${entry.mode ? ` mode=${entry.mode.toString(8)}` : ""}${entry.dest ? ` dest=${entry.dest}` : ""}`);
146
+ if (fsSync.existsSync(journalPath)) {
147
+ const fd = fsSync.openSync(journalPath, fsSync.constants.O_WRONLY | fsSync.constants.O_CREAT | fsSync.constants.O_APPEND);
148
+ try {
149
+ fsSync.writeSync(fd, buf);
150
+ } finally {
151
+ fsSync.closeSync(fd);
152
+ }
153
+ } else {
154
+ fsSync.writeFileSync(journalPath, buf);
150
155
  }
151
156
  }
152
157
 
@@ -2,7 +2,7 @@ import type { ChildProcessWithoutNullStreams } from "node:child_process";
2
2
  import { readFile, unlink, writeFile } from "node:fs/promises";
3
3
  import * as path from "node:path";
4
4
  import type { ShellProperties, VirtualShell } from ".";
5
- import { getCommandNames, makeDefaultEnv, runCommand } from "../commands";
5
+ import { getCommandNames, makeDefaultEnv, runCommand, userHome } from "../commands";
6
6
  import {
7
7
  spawnHtopProcess,
8
8
  spawnNanoEditorProcess,
@@ -55,12 +55,12 @@ export function startShell(
55
55
  let history = loadHistory(shell.vfs, authUser);
56
56
  let historyIndex: number | null = null;
57
57
  let historyDraft = "";
58
- let cwd = `/home/${authUser}`;
58
+ let cwd = userHome(authUser);
59
59
  const shellEnv: ShellEnv = makeDefaultEnv(authUser, hostname);
60
60
  let nanoSession: NanoSession | null = null;
61
61
  let pendingSudo: PendingSudo | null = null;
62
62
  const buildCurrentPrompt = (): string => {
63
- const homePath = `/home/${authUser}`;
63
+ const homePath = userHome(authUser);
64
64
  const cwdLabel = cwd === homePath ? "~" : path.posix.basename(cwd) || "/";
65
65
  return buildPrompt(authUser, hostname, cwdLabel);
66
66
  };
@@ -71,7 +71,7 @@ export function startShell(
71
71
 
72
72
  // Load .bashrc if it exists
73
73
  void (async () => {
74
- const bashrcPath = `/home/${authUser}/.bashrc`;
74
+ const bashrcPath = `${userHome(authUser)}/.bashrc`;
75
75
  if (shell.vfs.exists(bashrcPath)) {
76
76
  try {
77
77
  const bashrc = shell.vfs.readFile(bashrcPath);
@@ -146,7 +146,7 @@ export function startShell(
146
146
  if (!challenge.commandLine) {
147
147
  authUser = challenge.targetUser;
148
148
  if (challenge.loginShell) {
149
- cwd = `/home/${authUser}`;
149
+ cwd = userHome(authUser);
150
150
  }
151
151
  shell.users.updateSession(sessionId, authUser, remoteAddress);
152
152
  stream.write("\r\n");
@@ -154,7 +154,7 @@ export function startShell(
154
154
  return;
155
155
  }
156
156
 
157
- const runCwd = challenge.loginShell ? `/home/${challenge.targetUser}` : cwd;
157
+ const runCwd = challenge.loginShell ? userHome(challenge.targetUser) : cwd;
158
158
  const result = await Promise.resolve(
159
159
  runCommand(
160
160
  challenge.commandLine,
@@ -196,7 +196,7 @@ export function startShell(
196
196
 
197
197
  if (result.switchUser) {
198
198
  authUser = result.switchUser;
199
- cwd = result.nextCwd ?? `/home/${authUser}`;
199
+ cwd = result.nextCwd ?? userHome(authUser);
200
200
  shell.users.updateSession(sessionId, authUser, remoteAddress);
201
201
  } else if (result.nextCwd) {
202
202
  cwd = result.nextCwd;
@@ -388,11 +388,11 @@ export function startShell(
388
388
  }
389
389
 
390
390
  const data = history.length > 0 ? `${history.join("\n")}\n` : "";
391
- shell.vfs.writeFile(`/home/${authUser}/.bash_history`, data);
391
+ shell.vfs.writeFile(`${userHome(authUser)}/.bash_history`, data);
392
392
  }
393
393
 
394
394
  function readLastLogin(): { at: string; from: string } | null {
395
- const lastlogPath = `/home/${authUser}/.lastlog.json`;
395
+ const lastlogPath = `${userHome(authUser)}/.lastlog.json`;
396
396
  if (!shell.vfs.exists(lastlogPath)) {
397
397
  return null;
398
398
  }
@@ -408,7 +408,7 @@ export function startShell(
408
408
  }
409
409
 
410
410
  function writeLastLogin(nowIso: string): void {
411
- const lastlogPath = `/home/${authUser}/.lastlog`;
411
+ const lastlogPath = `${userHome(authUser)}/.lastlog`;
412
412
  shell.vfs.writeFile(
413
413
  lastlogPath,
414
414
  JSON.stringify({ at: nowIso, from: remoteAddress }),
@@ -651,7 +651,7 @@ export function startShell(
651
651
 
652
652
  if (result.switchUser) {
653
653
  authUser = result.switchUser;
654
- cwd = result.nextCwd ?? `/home/${authUser}`;
654
+ cwd = result.nextCwd ?? userHome(authUser);
655
655
  shell.users.updateSession(sessionId, authUser, remoteAddress);
656
656
  lineBuffer = "";
657
657
  cursorPos = 0;
@@ -686,7 +686,7 @@ export function startShell(
686
686
  }
687
687
 
688
688
  function loadHistory(vfs: VirtualFileSystem, authUser: string): string[] {
689
- const historyPath = `/home/${authUser}/.bash_history`;
689
+ const historyPath = `${userHome(authUser)}/.bash_history`;
690
690
  if (!vfs.exists(historyPath)) {
691
691
  vfs.writeFile(historyPath, "");
692
692
  return [];
@@ -103,14 +103,14 @@ export class VirtualUserManager extends EventEmitter {
103
103
  // changed = true;
104
104
  // }
105
105
 
106
- // const homePath = `/home/root`;
107
- // if (!this.vfs.exists(homePath)) {
108
- // this.vfs.mkdir(homePath, 0o755);
109
- // this.vfs.writeFile(
110
- // `${homePath}/README.txt`,
111
- // `Welcome to the virtual environment, root`,
112
- // );
113
- // }
106
+ const homePath = "/root";
107
+ if (!this.vfs.exists(homePath)) {
108
+ this.vfs.mkdir(homePath, 0o755);
109
+ this.vfs.writeFile(
110
+ `${homePath}/README.txt`,
111
+ `Welcome to the virtual environment, root`,
112
+ );
113
+ }
114
114
 
115
115
  if (changed) {
116
116
  await this.persist();
@@ -173,7 +173,7 @@ export class VirtualUserManager extends EventEmitter {
173
173
  */
174
174
  public getUsageBytes(username: string): number {
175
175
  perf.mark("getUsageBytes");
176
- const homePath = `/home/${username}`;
176
+ const homePath = username === "root" ? "/root" : `/home/${username}`;
177
177
  if (!this.vfs.exists(homePath)) {
178
178
  return 0;
179
179
  }
@@ -202,7 +202,7 @@ export class VirtualUserManager extends EventEmitter {
202
202
  }
203
203
 
204
204
  const normalizedPath = normalizeVfsPath(targetPath);
205
- const homePath = normalizeVfsPath(`/home/${username}`);
205
+ const homePath = normalizeVfsPath(username === "root" ? "/root" : `/home/${username}`);
206
206
  const inUserHome =
207
207
  normalizedPath === homePath || normalizedPath.startsWith(`${homePath}/`);
208
208
  if (!inUserHome) {
@@ -279,7 +279,7 @@ export class VirtualUserManager extends EventEmitter {
279
279
  if (this.autoSudoForNewUsers) {
280
280
  this.sudoers.add(username);
281
281
  }
282
- const homePath = `/home/${username}`;
282
+ const homePath = username === "root" ? "/root" : `/home/${username}`;
283
283
  if (!this.vfs.exists(homePath)) {
284
284
  this.vfs.mkdir(homePath, 0o755);
285
285
  this.vfs.writeFile(
@@ -57,8 +57,8 @@ export const aptCommand: ShellModule = {
57
57
  case "update": {
58
58
  return {
59
59
  stdout: [
60
- "Hit:1 fortune://packages.fortune.local aurora InRelease",
61
- "Hit:2 fortune://security.fortune.local aurora-security InRelease",
60
+ "Hit:1 fortune://packages.fortune.local nyx InRelease",
61
+ "Hit:2 fortune://security.fortune.local nyx-security InRelease",
62
62
  "Reading package lists... Done",
63
63
  "Building dependency tree... Done",
64
64
  "Reading state information... Done",
@@ -218,7 +218,7 @@ export const aptCacheCommand: ShellModule = {
218
218
  ` Candidate: ${def.version}`,
219
219
  ` Version table:`,
220
220
  ` ${def.version} 500`,
221
- ` 500 fortune://packages.fortune.local aurora/main amd64 Packages`,
221
+ ` 500 fortune://packages.fortune.local nyx/main amd64 Packages`,
222
222
  ].join("\n"),
223
223
  exitCode: 0,
224
224
  };
@@ -1,5 +1,6 @@
1
1
  import type { ShellModule } from "../types/commands";
2
2
  import { assertPathAccess, resolvePath } from "./helpers";
3
+ import { userHome } from "./runtime";
3
4
 
4
5
  /**
5
6
  * Change current working directory.
@@ -12,7 +13,7 @@ export const cdCommand: ShellModule = {
12
13
  category: "navigation",
13
14
  params: ["[path]"],
14
15
  run: ({ authUser, shell, cwd, args }) => {
15
- const target = resolvePath(cwd, args[0] ?? `~`);
16
+ const target = resolvePath(cwd, args[0] ?? "~", userHome(authUser));
16
17
  assertPathAccess(authUser, target, "cd");
17
18
  const stats = shell.vfs.stat(target);
18
19
  if (stats.type !== "directory") {
@@ -28,12 +28,13 @@ export function normalizeTerminalOutput(text: string): string {
28
28
  .trimEnd();
29
29
  }
30
30
 
31
- export function resolvePath(cwd: string, inputPath: string): string {
31
+ export function resolvePath(cwd: string, inputPath: string, homeDir?: string): string {
32
32
  if (!inputPath || inputPath.trim() === "") {
33
33
  return cwd;
34
34
  }
35
35
  if (inputPath.startsWith("~")) {
36
- return path.posix.normalize(`/home/${inputPath.slice(1)}`);
36
+ const home = homeDir ?? "/root";
37
+ return path.posix.normalize(`${home}${inputPath.slice(1)}`);
37
38
  }
38
39
  return inputPath.startsWith("/")
39
40
  ? path.posix.normalize(inputPath)
@@ -6,4 +6,4 @@ export {
6
6
  resolveModule
7
7
  } from "./registry";
8
8
 
9
- export { makeDefaultEnv, runCommand, runCommandDirect } from "./runtime";
9
+ export { makeDefaultEnv, runCommand, runCommandDirect, userHome } from "./runtime";
@@ -13,7 +13,7 @@ export const lsbReleaseCommand: ShellModule = {
13
13
  params: ["[-a] [-i] [-d] [-r] [-c]"],
14
14
  run: ({ args, shell }) => {
15
15
  let osName = shell.properties?.os ?? "Fortune GNU/Linux x64";
16
- let codename = "aurora";
16
+ let codename = "nyx";
17
17
  let version = "1.0";
18
18
 
19
19
  try {
@@ -11,11 +11,16 @@ import { expandAsync, expandBraces } from "../utils/expand";
11
11
  import { tokenizeCommand } from "../utils/tokenize";
12
12
  import { resolveModule } from "./registry";
13
13
 
14
+ /** Returns the home directory path for a given user. Root lives at /root. */
15
+ export function userHome(authUser: string): string {
16
+ return authUser === "root" ? "/root" : `/home/${authUser}`;
17
+ }
18
+
14
19
  export function makeDefaultEnv(authUser: string, hostname: string): ShellEnv {
15
20
  return {
16
21
  vars: {
17
22
  PATH: "/usr/local/bin:/usr/bin:/bin",
18
- HOME: `/home/${authUser}`,
23
+ HOME: userHome(authUser),
19
24
  USER: authUser,
20
25
  LOGNAME: authUser,
21
26
  SHELL: "/bin/sh",