@cmdoss/file-manager 0.2.0 → 0.2.2

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.
@@ -1,14 +1,14 @@
1
1
 
2
- > @cmdoss/file-manager@0.2.0 build /home/runner/work/ts-sdks/ts-sdks/packages/file-manager
2
+ > @cmdoss/file-manager@0.2.2 build /home/runner/work/ts-sdks/ts-sdks/packages/file-manager
3
3
  > tsdown --platform browser --minify
4
4
 
5
5
  ℹ tsdown v0.16.8 powered by rolldown v1.0.0-beta.52
6
6
  ℹ entry: src/index.ts
7
7
  ℹ tsconfig: tsconfig.json
8
8
  ℹ Build start
9
- ℹ dist/index.js 2.95 kB │ gzip: 1.21 kB
10
- ℹ dist/index.js.map 8.31 kB │ gzip: 2.72 kB
9
+ ℹ dist/index.js 3.01 kB │ gzip: 1.24 kB
10
+ ℹ dist/index.js.map 8.42 kB │ gzip: 2.79 kB
11
11
  ℹ dist/index.d.ts.map 0.87 kB │ gzip: 0.37 kB
12
12
  ℹ dist/index.d.ts 1.06 kB │ gzip: 0.50 kB
13
- ℹ 4 files, total: 13.20 kB
14
- ✔ Build complete in 365ms
13
+ ℹ 4 files, total: 13.36 kB
14
+ ✔ Build complete in 268ms
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":["mountDir?: string"],"sources":["../src/file-manager.ts"],"sourcesContent":[],"mappings":";;;cASa,gBAAA,YAA4B;;EAAzC,SAAa,YAAA,EAAA,MAAA;EACoB;EAAJ,SAAA,QAAA,CAAA,EAAA,MAAA,GAAA,SAAA;EAyBP,UAAA,eAAA,EAzBO,GAyBP,CAzBW,mBAyBX,CAAA;EAcW,WAAA,CAAA,YAAA,CAAA,EAAA,MAAA,EAAA,QAAA,CAAA,EAAA,MAAA,GAAA,SAAA;EAAc,UAAA,CAAA,CAAA,EAdzB,OAcyB,CAAA,IAAA,CAAA;EAiBH,eAAA,CAAA,OAAA,EAjBX,WAiBW,CAAA,EAjBG,OAiBH,CAAA,IAAA,CAAA;EAAR,QAAA,CAAA,QAAA,EAAA,MAAA,CAAA,EAAA,OAAA,CAAQ,UAAR,CAAA;EASf,SAAA,CAAA,CAAA,EAAA,OAAA,CAAA,MAAA,EAAA,CAAA;EAcF,OAAA,CAAA,CAAA,EAAA,OAAA,CAAA,MAAA,CAAA;EAwBG,SAAA,CAAA,QAAA,EAAA,MAAA,EAAA,OAAA,EAAA,MAAA,GAAA,UAAA,CAAA,EACjB,OADiB,CAAA,IAAA,CAAA;EACjB,UAAA,CAAA,QAAA,EAAA,MAAA,CAAA,EAaiC,OAbjC,CAAA,IAAA,CAAA;EAaiC,YAAA,CAAA,QAAA,EASb,mBATa,CAAA,EAAA,GAAA,GAAA,IAAA;EASb,QAAA,YAAA;EA/HgB,OAAA,CAAA,CAAA,EAAA,IAAA"}
1
+ {"version":3,"file":"index.d.ts","names":["mountDir?: string"],"sources":["../src/file-manager.ts"],"sourcesContent":[],"mappings":";;;cASa,gBAAA,YAA4B;;EAAzC,SAAa,YAAA,EAAA,MAAA;EACoB;EAAJ,SAAA,QAAA,CAAA,EAAA,MAAA,GAAA,SAAA;EAyBP,UAAA,eAAA,EAzBO,GAyBP,CAzBW,mBAyBX,CAAA;EAcW,WAAA,CAAA,YAAA,CAAA,EAAA,MAAA,EAAA,QAAA,CAAA,EAAA,MAAA,GAAA,SAAA;EAAc,UAAA,CAAA,CAAA,EAdzB,OAcyB,CAAA,IAAA,CAAA;EAmBH,eAAA,CAAA,OAAA,EAnBX,WAmBW,CAAA,EAnBG,OAmBH,CAAA,IAAA,CAAA;EAAR,QAAA,CAAA,QAAA,EAAA,MAAA,CAAA,EAAA,OAAA,CAAQ,UAAR,CAAA;EASf,SAAA,CAAA,CAAA,EAAA,OAAA,CAAA,MAAA,EAAA,CAAA;EAcF,OAAA,CAAA,CAAA,EAAA,OAAA,CAAA,MAAA,CAAA;EAwBG,SAAA,CAAA,QAAA,EAAA,MAAA,EAAA,OAAA,EAAA,MAAA,GAAA,UAAA,CAAA,EACjB,OADiB,CAAA,IAAA,CAAA;EACjB,UAAA,CAAA,QAAA,EAAA,MAAA,CAAA,EAaiC,OAbjC,CAAA,IAAA,CAAA;EAaiC,YAAA,CAAA,QAAA,EASb,mBATa,CAAA,EAAA,GAAA,GAAA,IAAA;EASb,QAAA,YAAA;EAjIgB,OAAA,CAAA,CAAA,EAAA,IAAA"}
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import{Zip as e}from"@zenfs/archives";import{configure as t,fs as n}from"@zenfs/core";import*as r from"@zenfs/core/path";import{IndexedDB as i}from"@zenfs/dom";import a from"debug";const o=a(`file-manager`);var s=class{changeListeners=new Set;constructor(e=`/workspace`,t){if(this.workspaceDir=e,this.mountDir=t,this.mountDir||=this.workspaceDir,this.mountDir!==this.workspaceDir){let e=r.normalize(this.workspaceDir),t=r.normalize(this.mountDir);if(!e.startsWith(t+`/`)&&e!==t)throw Error(`workspaceDir (${this.workspaceDir}) must be a subdirectory of mountDir (${this.mountDir})`)}}async initialize(){o(`🔧 Configuring filesystem...`),o(`📁 Mounting workspace at ${this.mountDir}`),await t({mounts:{[this.mountDir??this.workspaceDir]:{backend:i,storeName:this.mountDir??this.workspaceDir}}}),o(`✅ Filesystem configured`)}async writeZipArchive(r){let i=`/tmp/zip-write-${crypto.randomUUID()}`;o(`📦 Mounting ZIP archive to temporary directory...`),await t({mounts:{[i]:{backend:e,data:r,lazy:!1}}}),o(`📂 Copying files from ZIP archive to workspace...`),await n.promises.cp(i,this.workspaceDir,{recursive:!0}),o(`✅ Files copied to workspace from ZIP archive`)}async readFile(e){o(`📂 Reading file from`,e),e=c(e);let t=r.join(this.workspaceDir,e),i=await n.promises.readFile(t);return o(`✅ File read from`,e,`(`,i.byteLength,`bytes )`),i}async listFiles(){o(`📄 Listing files in workspace`);let e=(await n.promises.readdir(this.workspaceDir,{withFileTypes:!0,recursive:!0})).filter(e=>e.isFile()).map(e=>r.join(e.parentPath,e.name)).map(c);return o(`✅ Files currently in workspace`,e),e}async getSize(){o(`📏 Calculating total size of files in workspace`);let e=0,t=await n.promises.readdir(this.workspaceDir,{withFileTypes:!0,recursive:!0});for(let i of t)if(i.isFile()){let t=r.join(this.workspaceDir,i.parentPath,i.name),a=await n.promises.stat(t);e+=a.size}return o(`✅ Total size of files in workspace:`,e,`bytes`),e}async writeFile(e,t){o(`✍️ Writing file to`,e),e=c(e);let i=r.join(this.workspaceDir,e),a=r.dirname(i);await n.promises.mkdir(a,{recursive:!0});let s=typeof t==`string`?new TextEncoder().encode(t):t;await n.promises.writeFile(i,s),o(`✅ File written to`,e,`(`,s.byteLength,`bytes )`),this.notifyChange({type:`updated`,path:e})}async deleteFile(e){o(`🗑️ Deleting file at`,e),e=c(e);let t=r.join(this.workspaceDir,e);await n.promises.rm(t),o(`✅ File deleted at`,e),this.notifyChange({type:`removed`,path:e})}onFileChange(e){return this.changeListeners.add(e),()=>{this.changeListeners.delete(e)}}notifyChange(e){for(let t of this.changeListeners)t(e)}unmount(){o(`🚪 Unmounting workspace directory (`,this.workspaceDir,`)`),this.changeListeners.clear(),this.mountDir===this.workspaceDir?n.umount(this.mountDir):o(`⚠️ Skipping unmount: mountDir and workspaceDir are different`)}};function c(e){return e.startsWith(`/`)?e:`/${e}`}export{s as ZenFsFileManager};
1
+ import{Zip as e}from"@zenfs/archives";import{configure as t,fs as n}from"@zenfs/core";import*as r from"@zenfs/core/path";import{IndexedDB as i}from"@zenfs/dom";import a from"debug";const o=a(`file-manager`);var s=class{changeListeners=new Set;constructor(e=`/workspace`,t){if(this.workspaceDir=e,this.mountDir=t,this.mountDir||=this.workspaceDir,this.mountDir!==this.workspaceDir){let e=r.normalize(this.workspaceDir),t=r.normalize(this.mountDir);if(!e.startsWith(t+`/`)&&e!==t)throw Error(`workspaceDir (${this.workspaceDir}) must be a subdirectory of mountDir (${this.mountDir})`)}}async initialize(){o(`🔧 Configuring filesystem...`),o(`📁 Mounting workspace at ${this.mountDir}`),await t({mounts:{[this.mountDir??this.workspaceDir]:{backend:i,storeName:this.mountDir??this.workspaceDir}}}),o(`✅ Filesystem configured`)}async writeZipArchive(r){let i=`/tmp/zip-write-${crypto.randomUUID()}`;o(`📦 Mounting ZIP archive to temporary directory...`),await t({mounts:{[i]:{backend:e,data:r,lazy:!1}}}),o(`📂 Copying files from ZIP archive to workspace...`),await n.promises.cp(i,this.workspaceDir,{recursive:!0}),o(`📦 Unmounting temporary ZIP directory...`),n.umount(i),o(`✅ Files copied to workspace from ZIP archive`)}async readFile(e){o(`📂 Reading file ${e}...`),e=c(e);let t=r.join(this.workspaceDir,e),i=await n.promises.readFile(t);return o(`✅ File ${e} read (${i.byteLength} bytes)`),i}async listFiles(){o(`📄 Listing files in workspace`);let e=(await n.promises.readdir(this.workspaceDir,{withFileTypes:!0,recursive:!0})).filter(e=>e.isFile()).map(e=>r.join(e.parentPath,e.name)).map(c);return o(`✅ Files currently in workspace:`,e),e}async getSize(){o(`📏 Calculating total size of files in workspace`);let e=0,t=await n.promises.readdir(this.workspaceDir,{withFileTypes:!0,recursive:!0});for(let i of t)if(i.isFile()){let t=r.join(this.workspaceDir,i.parentPath,i.name),a=await n.promises.stat(t);e+=a.size}return o(`✅ Total size of files in workspace:`,e,`bytes`),e}async writeFile(e,t){o(`✍️ Writing file to`,e),e=c(e);let i=r.join(this.workspaceDir,e),a=r.dirname(i);await n.promises.mkdir(a,{recursive:!0});let s=typeof t==`string`?new TextEncoder().encode(t):t;await n.promises.writeFile(i,s),o(`✅ File written to`,e,`(`,s.byteLength,`bytes )`),this.notifyChange({type:`updated`,path:e})}async deleteFile(e){o(`🗑️ Deleting file at`,e),e=c(e);let t=r.join(this.workspaceDir,e);await n.promises.rm(t),o(`✅ File deleted at`,e),this.notifyChange({type:`removed`,path:e})}onFileChange(e){return this.changeListeners.add(e),()=>{this.changeListeners.delete(e)}}notifyChange(e){for(let t of this.changeListeners)t(e)}unmount(){o(`🚪 Unmounting workspace directory (`,this.workspaceDir,`)`),this.changeListeners.clear(),this.mountDir===this.workspaceDir?n.umount(this.mountDir):o(`⚠️ Skipping unmount: mountDir and workspaceDir are different`)}};function c(e){return e.startsWith(`/`)?e:`/${e}`}export{s as ZenFsFileManager};
2
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["mountDir?: string","path"],"sources":["../src/file-manager.ts"],"sourcesContent":["import type { FileChangedCallback, IFileManager } from '@cmdoss/site-builder'\nimport { Zip } from '@zenfs/archives'\nimport { configure, fs } from '@zenfs/core'\nimport * as path from '@zenfs/core/path'\nimport { IndexedDB } from '@zenfs/dom'\nimport debug from 'debug'\n\nconst log = debug('file-manager')\n\nexport class ZenFsFileManager implements IFileManager {\n protected changeListeners: Set<FileChangedCallback> = new Set()\n constructor(\n /** The directory of the workspace. Any files within this directory are considered part of the workspace. */\n public readonly workspaceDir = '/workspace',\n /** The directory where the workspace is mounted in the virtual filesystem. */\n public readonly mountDir?: string\n ) {\n if (!this.mountDir) {\n this.mountDir = this.workspaceDir\n }\n if (this.mountDir !== this.workspaceDir) {\n // Ensure workspaceDir is a subdirectory of mountDir\n const normalizedWorkspace = path.normalize(this.workspaceDir)\n const normalizedMount = path.normalize(this.mountDir)\n if (\n !normalizedWorkspace.startsWith(normalizedMount + '/') &&\n normalizedWorkspace !== normalizedMount\n ) {\n throw new Error(\n `workspaceDir (${this.workspaceDir}) must be a subdirectory of mountDir (${this.mountDir})`\n )\n }\n }\n }\n\n async initialize(): Promise<void> {\n log('🔧 Configuring filesystem...')\n log(`📁 Mounting workspace at ${this.mountDir}`)\n await configure({\n mounts: {\n [this.mountDir ?? this.workspaceDir]: {\n backend: IndexedDB,\n storeName: this.mountDir ?? this.workspaceDir\n }\n }\n })\n log('✅ Filesystem configured')\n }\n\n async writeZipArchive(zipData: ArrayBuffer): Promise<void> {\n const tmpDir = `/tmp/zip-write-${crypto.randomUUID()}`\n log('📦 Mounting ZIP archive to temporary directory...')\n await configure({\n mounts: {\n [tmpDir]: {\n backend: Zip,\n data: zipData,\n lazy: false // Extract all files immediately\n }\n }\n })\n log('📂 Copying files from ZIP archive to workspace...')\n await fs.promises.cp(tmpDir, this.workspaceDir, { recursive: true })\n log('✅ Files copied to workspace from ZIP archive')\n }\n\n async readFile(filePath: string): Promise<Uint8Array> {\n log('📂 Reading file from', filePath)\n filePath = ensureLeadingSlash(filePath)\n const workspaceFilePath = path.join(this.workspaceDir, filePath)\n const content = await fs.promises.readFile(workspaceFilePath)\n log('✅ File read from', filePath, '(', content.byteLength, 'bytes )')\n return content\n }\n\n async listFiles(): Promise<string[]> {\n log('📄 Listing files in workspace')\n const files = await fs.promises.readdir(this.workspaceDir, {\n withFileTypes: true,\n recursive: true\n })\n const result = files\n .filter(f => f.isFile())\n .map(f => path.join(f.parentPath, f.name))\n .map(ensureLeadingSlash)\n log('✅ Files currently in workspace', result)\n return result\n }\n\n async getSize(): Promise<number> {\n log('📏 Calculating total size of files in workspace')\n let totalSize = 0\n const files = await fs.promises.readdir(this.workspaceDir, {\n withFileTypes: true,\n recursive: true\n })\n for (const file of files) {\n if (file.isFile()) {\n const filePath = path.join(\n this.workspaceDir,\n file.parentPath,\n file.name\n )\n const stats = await fs.promises.stat(filePath)\n totalSize += stats.size\n }\n }\n log('✅ Total size of files in workspace:', totalSize, 'bytes')\n return totalSize\n }\n\n async writeFile(\n filePath: string,\n content: string | Uint8Array\n ): Promise<void> {\n log('✍️ Writing file to', filePath)\n filePath = ensureLeadingSlash(filePath)\n const workspaceFilePath = path.join(this.workspaceDir, filePath)\n const dir = path.dirname(workspaceFilePath)\n await fs.promises.mkdir(dir, { recursive: true })\n const contentBytes =\n typeof content === 'string' ? new TextEncoder().encode(content) : content\n await fs.promises.writeFile(workspaceFilePath, contentBytes)\n log('✅ File written to', filePath, '(', contentBytes.byteLength, 'bytes )')\n this.notifyChange({ type: 'updated', path: filePath })\n }\n\n async deleteFile(filePath: string): Promise<void> {\n log('🗑️ Deleting file at', filePath)\n filePath = ensureLeadingSlash(filePath)\n const workspaceFilePath = path.join(this.workspaceDir, filePath)\n await fs.promises.rm(workspaceFilePath)\n log('✅ File deleted at', filePath)\n this.notifyChange({ type: 'removed', path: filePath })\n }\n\n onFileChange(callback: FileChangedCallback): () => void {\n this.changeListeners.add(callback)\n return () => {\n this.changeListeners.delete(callback)\n }\n }\n\n private notifyChange(arg: Parameters<FileChangedCallback>[0]): void {\n for (const listener of this.changeListeners) {\n listener(arg)\n }\n }\n\n unmount(): void {\n log('🚪 Unmounting workspace directory (', this.workspaceDir, ')')\n this.changeListeners.clear()\n if (this.mountDir === this.workspaceDir) {\n // Unmount only if mountDir and workspaceDir are the same\n fs.umount(this.mountDir)\n } else {\n log('⚠️ Skipping unmount: mountDir and workspaceDir are different')\n }\n }\n}\n\nfunction ensureLeadingSlash(path: string): string {\n return path.startsWith('/') ? path : `/${path}`\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["mountDir?: string","path"],"sources":["../src/file-manager.ts"],"sourcesContent":["import type { FileChangedCallback, IFileManager } from '@cmdoss/site-builder'\nimport { Zip } from '@zenfs/archives'\nimport { configure, fs } from '@zenfs/core'\nimport * as path from '@zenfs/core/path'\nimport { IndexedDB } from '@zenfs/dom'\nimport debug from 'debug'\n\nconst log = debug('file-manager')\n\nexport class ZenFsFileManager implements IFileManager {\n protected changeListeners: Set<FileChangedCallback> = new Set()\n constructor(\n /** The directory of the workspace. Any files within this directory are considered part of the workspace. */\n public readonly workspaceDir = '/workspace',\n /** The directory where the workspace is mounted in the virtual filesystem. */\n public readonly mountDir?: string\n ) {\n if (!this.mountDir) {\n this.mountDir = this.workspaceDir\n }\n if (this.mountDir !== this.workspaceDir) {\n // Ensure workspaceDir is a subdirectory of mountDir\n const normalizedWorkspace = path.normalize(this.workspaceDir)\n const normalizedMount = path.normalize(this.mountDir)\n if (\n !normalizedWorkspace.startsWith(normalizedMount + '/') &&\n normalizedWorkspace !== normalizedMount\n ) {\n throw new Error(\n `workspaceDir (${this.workspaceDir}) must be a subdirectory of mountDir (${this.mountDir})`\n )\n }\n }\n }\n\n async initialize(): Promise<void> {\n log('🔧 Configuring filesystem...')\n log(`📁 Mounting workspace at ${this.mountDir}`)\n await configure({\n mounts: {\n [this.mountDir ?? this.workspaceDir]: {\n backend: IndexedDB,\n storeName: this.mountDir ?? this.workspaceDir\n }\n }\n })\n log('✅ Filesystem configured')\n }\n\n async writeZipArchive(zipData: ArrayBuffer): Promise<void> {\n const tmpDir = `/tmp/zip-write-${crypto.randomUUID()}`\n log('📦 Mounting ZIP archive to temporary directory...')\n await configure({\n mounts: {\n [tmpDir]: {\n backend: Zip,\n data: zipData,\n lazy: false // Extract all files immediately\n }\n }\n })\n log('📂 Copying files from ZIP archive to workspace...')\n await fs.promises.cp(tmpDir, this.workspaceDir, { recursive: true })\n log('📦 Unmounting temporary ZIP directory...')\n fs.umount(tmpDir)\n log('✅ Files copied to workspace from ZIP archive')\n }\n\n async readFile(filePath: string): Promise<Uint8Array> {\n log(`📂 Reading file ${filePath}...`)\n filePath = ensureLeadingSlash(filePath)\n const workspaceFilePath = path.join(this.workspaceDir, filePath)\n const content = await fs.promises.readFile(workspaceFilePath)\n log(`✅ File ${filePath} read (${content.byteLength} bytes)`)\n return content\n }\n\n async listFiles(): Promise<string[]> {\n log('📄 Listing files in workspace')\n const files = await fs.promises.readdir(this.workspaceDir, {\n withFileTypes: true,\n recursive: true\n })\n const result = files\n .filter(f => f.isFile())\n .map(f => path.join(f.parentPath, f.name))\n .map(ensureLeadingSlash)\n log('✅ Files currently in workspace:', result)\n return result\n }\n\n async getSize(): Promise<number> {\n log('📏 Calculating total size of files in workspace')\n let totalSize = 0\n const files = await fs.promises.readdir(this.workspaceDir, {\n withFileTypes: true,\n recursive: true\n })\n for (const file of files) {\n if (file.isFile()) {\n const filePath = path.join(\n this.workspaceDir,\n file.parentPath,\n file.name\n )\n const stats = await fs.promises.stat(filePath)\n totalSize += stats.size\n }\n }\n log('✅ Total size of files in workspace:', totalSize, 'bytes')\n return totalSize\n }\n\n async writeFile(\n filePath: string,\n content: string | Uint8Array\n ): Promise<void> {\n log('✍️ Writing file to', filePath)\n filePath = ensureLeadingSlash(filePath)\n const workspaceFilePath = path.join(this.workspaceDir, filePath)\n const dir = path.dirname(workspaceFilePath)\n await fs.promises.mkdir(dir, { recursive: true })\n const contentBytes =\n typeof content === 'string' ? new TextEncoder().encode(content) : content\n await fs.promises.writeFile(workspaceFilePath, contentBytes)\n log('✅ File written to', filePath, '(', contentBytes.byteLength, 'bytes )')\n this.notifyChange({ type: 'updated', path: filePath })\n }\n\n async deleteFile(filePath: string): Promise<void> {\n log('🗑️ Deleting file at', filePath)\n filePath = ensureLeadingSlash(filePath)\n const workspaceFilePath = path.join(this.workspaceDir, filePath)\n await fs.promises.rm(workspaceFilePath)\n log('✅ File deleted at', filePath)\n this.notifyChange({ type: 'removed', path: filePath })\n }\n\n onFileChange(callback: FileChangedCallback): () => void {\n this.changeListeners.add(callback)\n return () => {\n this.changeListeners.delete(callback)\n }\n }\n\n private notifyChange(arg: Parameters<FileChangedCallback>[0]): void {\n for (const listener of this.changeListeners) {\n listener(arg)\n }\n }\n\n unmount(): void {\n log('🚪 Unmounting workspace directory (', this.workspaceDir, ')')\n this.changeListeners.clear()\n if (this.mountDir === this.workspaceDir) {\n // Unmount only if mountDir and workspaceDir are the same\n fs.umount(this.mountDir)\n } else {\n log('⚠️ Skipping unmount: mountDir and workspaceDir are different')\n }\n }\n}\n\nfunction ensureLeadingSlash(path: string): string {\n return path.startsWith('/') ? path : `/${path}`\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cmdoss/file-manager",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "exports": "./dist/index.js",
@@ -20,7 +20,7 @@
20
20
  "@zenfs/core": "^2.4.4",
21
21
  "@zenfs/dom": "^1.2.5",
22
22
  "debug": "^4.4.3",
23
- "@cmdoss/site-builder": "0.2.0"
23
+ "@cmdoss/site-builder": "0.2.2"
24
24
  },
25
25
  "devDependencies": {
26
26
  "@types/node": "^22.19.1",
@@ -61,15 +61,17 @@ export class ZenFsFileManager implements IFileManager {
61
61
  })
62
62
  log('📂 Copying files from ZIP archive to workspace...')
63
63
  await fs.promises.cp(tmpDir, this.workspaceDir, { recursive: true })
64
+ log('📦 Unmounting temporary ZIP directory...')
65
+ fs.umount(tmpDir)
64
66
  log('✅ Files copied to workspace from ZIP archive')
65
67
  }
66
68
 
67
69
  async readFile(filePath: string): Promise<Uint8Array> {
68
- log('📂 Reading file from', filePath)
70
+ log(`📂 Reading file ${filePath}...`)
69
71
  filePath = ensureLeadingSlash(filePath)
70
72
  const workspaceFilePath = path.join(this.workspaceDir, filePath)
71
73
  const content = await fs.promises.readFile(workspaceFilePath)
72
- log('✅ File read from', filePath, '(', content.byteLength, 'bytes )')
74
+ log(`✅ File ${filePath} read (${content.byteLength} bytes)`)
73
75
  return content
74
76
  }
75
77
 
@@ -83,7 +85,7 @@ export class ZenFsFileManager implements IFileManager {
83
85
  .filter(f => f.isFile())
84
86
  .map(f => path.join(f.parentPath, f.name))
85
87
  .map(ensureLeadingSlash)
86
- log('✅ Files currently in workspace', result)
88
+ log('✅ Files currently in workspace:', result)
87
89
  return result
88
90
  }
89
91