@cmdoss/file-manager 0.1.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.
@@ -0,0 +1,14 @@
1
+
2
+ > @cmdoss/file-manager@0.1.0 build /home/runner/work/ts-sdks/ts-sdks/packages/file-manager
3
+ > tsdown --platform browser --minify
4
+
5
+ ℹ tsdown v0.15.4 powered by rolldown v1.0.0-beta.43
6
+ ℹ entry: src/index.ts
7
+ ℹ tsconfig: tsconfig.json
8
+ ℹ Build start
9
+ ℹ dist/index.js 1.87 kB │ gzip: 0.82 kB
10
+ ℹ dist/index.js.map 5.55 kB │ gzip: 1.92 kB
11
+ ℹ dist/index.d.ts.map 0.73 kB │ gzip: 0.35 kB
12
+ ℹ dist/index.d.ts 0.79 kB │ gzip: 0.41 kB
13
+ ℹ 4 files, total: 8.94 kB
14
+ ✔ Build complete in 236ms
@@ -0,0 +1,14 @@
1
+
2
+ > @cmdoss/file-manager@0.1.0 test /home/runner/work/ts-sdks/ts-sdks/packages/file-manager
3
+ > node --test
4
+
5
+ TAP version 13
6
+ 1..0
7
+ # tests 0
8
+ # suites 0
9
+ # pass 0
10
+ # fail 0
11
+ # cancelled 0
12
+ # skipped 0
13
+ # todo 0
14
+ # duration_ms 56.835878
@@ -0,0 +1,21 @@
1
+ import { FileChangedCallback, IFileManager } from "@cmdoss/site-builder";
2
+
3
+ //#region src/file-manager.d.ts
4
+ declare class ZenFsFileManager implements IFileManager {
5
+ private workspaceDir;
6
+ private backend;
7
+ private changeListeners;
8
+ constructor(workspaceDir?: string, backend?: "indexeddb" | "zip" | "iso");
9
+ mount(data?: ArrayBuffer, force?: boolean): Promise<void>;
10
+ writeFile(filePath: string, content: string | Uint8Array): Promise<void>;
11
+ removeFile(filePath: string): Promise<void>;
12
+ readFile(filePath: string): Promise<Uint8Array>;
13
+ listFiles(): Promise<string[]>;
14
+ onFileChange(callback: FileChangedCallback): () => void;
15
+ private notifyChange;
16
+ clear(): Promise<void>;
17
+ unmount(): void;
18
+ }
19
+ //#endregion
20
+ export { ZenFsFileManager };
21
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":["backend: 'indexeddb' | 'zip' | 'iso'"],"sources":["../src/file-manager.ts"],"sourcesContent":[],"mappings":";;;cAMa,gBAAA,YAA4B;;EAAzC,QAAa,OAAA;EAAA,QAAA,eAAA;aAQQ,CAAA,YAAA,CAAA,EAAA,MAAA,EAAA,OAAA,CAAA,EAAA,WAAA,GAAA,KAAA,GAAA,KAAA;QAA6B,IAAA,CAAA,EAA7B,WAA6B,EAAA,KAAA,CAAA,EAAA,OAAA,CAAA,EAAA,OAAA,CAAA,IAAA,CAAA;WAuB5B,CAAA,QAAA,EAAA,MAAA,EAAA,OAAA,EAAA,MAAA,GAAA,UAAA,CAAA,EACjB,OADiB,CAAA,IAAA,CAAA;YACjB,CAAA,QAAA,EAAA,MAAA,CAAA,EAciC,OAdjC,CAAA,IAAA,CAAA;UAciC,CAAA,QAAA,EAAA,MAAA,CAAA,EAOF,OAPE,CAOM,UAPN,CAAA;WAOM,CAAA,CAAA,EAOvB,OAPuB,CAAA,MAAA,EAAA,CAAA;cAAR,CAAA,QAAA,EAmBX,mBAnBW,CAAA,EAAA,GAAA,GAAA,IAAA;UAOf,YAAA;SAYI,EAaR,OAbQ,CAAA,IAAA,CAAA;SAaR,CAAA,CAAA,EAAA,IAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ import{Iso as e,Zip as t}from"@zenfs/archives";import{configure as n,fs as r}from"@zenfs/core";import*as i from"@zenfs/core/path";import{IndexedDB as a}from"@zenfs/dom";var o=class{changeListeners=new Set;constructor(e=`/workspace`,t=`indexeddb`){this.workspaceDir=e,this.backend=t}async mount(i,o=!1){let s=this.backend===`indexeddb`?a:this.backend===`zip`?t:this.backend===`iso`?e:null;if(!s)throw Error(`Invalid backend specified`);if(await r.promises.access(this.workspaceDir).then(()=>!0).catch(()=>!1)){if(!o)throw Error(`Workspace directory is already mounted`);this.unmount()}await n({mounts:{[this.workspaceDir]:{backend:s,data:i}}})}async writeFile(e,t){e=s(e);let n=i.join(this.workspaceDir,e),a=i.dirname(n);await r.promises.mkdir(a,{recursive:!0});let o=typeof t==`string`?new TextEncoder().encode(t):t;await r.promises.writeFile(n,o),this.notifyChange({type:`updated`,path:e})}async removeFile(e){e=s(e);let t=i.join(this.workspaceDir,e);await r.promises.rm(t),this.notifyChange({type:`removed`,path:e})}async readFile(e){e=s(e);let t=i.join(this.workspaceDir,e);return console.log(`Reading file from path:`,t),await r.promises.readFile(t)}async listFiles(){let e=await r.promises.readdir(this.workspaceDir,{withFileTypes:!0,recursive:!0});return console.log(`Files in workspace:`,e),e.filter(e=>e.isFile()).map(e=>i.resolve(e.parentPath,e.name)).map(s)}onFileChange(e){return this.changeListeners.add(e),()=>{this.changeListeners.delete(e)}}notifyChange(e){for(let t of this.changeListeners)t(e)}async clear(){let e=await r.promises.readdir(this.workspaceDir,{withFileTypes:!0});for(let t of e){let e=i.join(t.parentPath,t.name);await r.promises.rm(e,{recursive:!0,force:!0})}}unmount(){this.changeListeners.clear(),r.umount(this.workspaceDir)}};function s(e){return e.startsWith(`/`)?e:`/${e}`}export{o as ZenFsFileManager};
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["backend: 'indexeddb' | 'zip' | 'iso'","path"],"sources":["../src/file-manager.ts"],"sourcesContent":["import type { FileChangedCallback, IFileManager } from '@cmdoss/site-builder'\nimport { Iso, Zip } from '@zenfs/archives'\nimport { configure, fs } from '@zenfs/core'\nimport * as path from '@zenfs/core/path'\nimport { IndexedDB } from '@zenfs/dom'\n\nexport class ZenFsFileManager implements IFileManager {\n private changeListeners = new Set<FileChangedCallback>()\n\n constructor(\n private workspaceDir = '/workspace',\n private backend: 'indexeddb' | 'zip' | 'iso' = 'indexeddb'\n ) {}\n\n async mount(data?: ArrayBuffer, force = false): Promise<void> {\n const backend =\n this.backend === 'indexeddb'\n ? IndexedDB\n : this.backend === 'zip'\n ? Zip\n : this.backend === 'iso'\n ? Iso\n : null\n if (!backend) throw new Error('Invalid backend specified')\n const isAccessible = await fs.promises\n .access(this.workspaceDir)\n .then(() => true)\n .catch(() => false)\n if (isAccessible) {\n if (!force) throw new Error('Workspace directory is already mounted')\n this.unmount() // Unmount existing instance\n }\n await configure({ mounts: { [this.workspaceDir]: { backend, data } } })\n }\n\n async writeFile(\n filePath: string,\n content: string | Uint8Array\n ): Promise<void> {\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 this.notifyChange({\n type: 'updated',\n path: filePath\n })\n }\n\n async removeFile(filePath: string): Promise<void> {\n filePath = ensureLeadingSlash(filePath)\n const workspaceFilePath = path.join(this.workspaceDir, filePath)\n await fs.promises.rm(workspaceFilePath)\n this.notifyChange({ type: 'removed', path: filePath })\n }\n\n async readFile(filePath: string): Promise<Uint8Array> {\n filePath = ensureLeadingSlash(filePath)\n const workspaceFilePath = path.join(this.workspaceDir, filePath)\n console.log('Reading file from path:', workspaceFilePath)\n return await fs.promises.readFile(workspaceFilePath)\n }\n\n async listFiles(): Promise<string[]> {\n const files = await fs.promises.readdir(this.workspaceDir, {\n withFileTypes: true,\n recursive: true\n })\n console.log('Files in workspace:', files)\n return files\n .filter(f => f.isFile())\n .map(f => path.resolve(f.parentPath, f.name))\n .map(ensureLeadingSlash)\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 async clear(): Promise<void> {\n const files = await fs.promises.readdir(this.workspaceDir, {\n withFileTypes: true\n })\n for (const file of files) {\n const filePath = path.join(file.parentPath, file.name)\n await fs.promises.rm(filePath, { recursive: true, force: true })\n }\n }\n\n unmount(): void {\n this.changeListeners.clear()\n fs.umount(this.workspaceDir)\n }\n}\n\nfunction ensureLeadingSlash(path: string): string {\n return path.startsWith('/') ? path : `/${path}`\n}\n"],"mappings":"yKAMA,IAAa,EAAb,KAAsD,CACpD,gBAA0B,IAAI,IAE9B,YACE,EAAuB,aACvB,EAA+C,YAC/C,CAFQ,KAAA,aAAA,EACA,KAAA,QAAA,EAGV,MAAM,MAAM,EAAoB,EAAQ,GAAsB,CAC5D,IAAM,EACJ,KAAK,UAAY,YACb,EACA,KAAK,UAAY,MACf,EACA,KAAK,UAAY,MACf,EACA,KACV,GAAI,CAAC,EAAS,MAAU,MAAM,4BAA4B,CAK1D,GAJqB,MAAM,EAAG,SAC3B,OAAO,KAAK,aAAa,CACzB,SAAW,GAAK,CAChB,UAAY,GAAM,CACH,CAChB,GAAI,CAAC,EAAO,MAAU,MAAM,yCAAyC,CACrE,KAAK,SAAS,CAEhB,MAAM,EAAU,CAAE,OAAQ,EAAG,KAAK,cAAe,CAAE,UAAS,OAAM,CAAE,CAAE,CAAC,CAGzE,MAAM,UACJ,EACA,EACe,CACf,EAAW,EAAmB,EAAS,CACvC,IAAM,EAAoB,EAAK,KAAK,KAAK,aAAc,EAAS,CAC1D,EAAM,EAAK,QAAQ,EAAkB,CAC3C,MAAM,EAAG,SAAS,MAAM,EAAK,CAAE,UAAW,GAAM,CAAC,CACjD,IAAM,EACJ,OAAO,GAAY,SAAW,IAAI,aAAa,CAAC,OAAO,EAAQ,CAAG,EACpE,MAAM,EAAG,SAAS,UAAU,EAAmB,EAAa,CAC5D,KAAK,aAAa,CAChB,KAAM,UACN,KAAM,EACP,CAAC,CAGJ,MAAM,WAAW,EAAiC,CAChD,EAAW,EAAmB,EAAS,CACvC,IAAM,EAAoB,EAAK,KAAK,KAAK,aAAc,EAAS,CAChE,MAAM,EAAG,SAAS,GAAG,EAAkB,CACvC,KAAK,aAAa,CAAE,KAAM,UAAW,KAAM,EAAU,CAAC,CAGxD,MAAM,SAAS,EAAuC,CACpD,EAAW,EAAmB,EAAS,CACvC,IAAM,EAAoB,EAAK,KAAK,KAAK,aAAc,EAAS,CAEhE,OADA,QAAQ,IAAI,0BAA2B,EAAkB,CAClD,MAAM,EAAG,SAAS,SAAS,EAAkB,CAGtD,MAAM,WAA+B,CACnC,IAAM,EAAQ,MAAM,EAAG,SAAS,QAAQ,KAAK,aAAc,CACzD,cAAe,GACf,UAAW,GACZ,CAAC,CAEF,OADA,QAAQ,IAAI,sBAAuB,EAAM,CAClC,EACJ,OAAO,GAAK,EAAE,QAAQ,CAAC,CACvB,IAAI,GAAK,EAAK,QAAQ,EAAE,WAAY,EAAE,KAAK,CAAC,CAC5C,IAAI,EAAmB,CAG5B,aAAa,EAA2C,CAEtD,OADA,KAAK,gBAAgB,IAAI,EAAS,KACrB,CACX,KAAK,gBAAgB,OAAO,EAAS,EAIzC,aAAqB,EAA+C,CAClE,IAAK,IAAM,KAAY,KAAK,gBAC1B,EAAS,EAAI,CAIjB,MAAM,OAAuB,CAC3B,IAAM,EAAQ,MAAM,EAAG,SAAS,QAAQ,KAAK,aAAc,CACzD,cAAe,GAChB,CAAC,CACF,IAAK,IAAM,KAAQ,EAAO,CACxB,IAAM,EAAW,EAAK,KAAK,EAAK,WAAY,EAAK,KAAK,CACtD,MAAM,EAAG,SAAS,GAAG,EAAU,CAAE,UAAW,GAAM,MAAO,GAAM,CAAC,EAIpE,SAAgB,CACd,KAAK,gBAAgB,OAAO,CAC5B,EAAG,OAAO,KAAK,aAAa,GAIhC,SAAS,EAAmB,EAAsB,CAChD,OAAOC,EAAK,WAAW,IAAI,CAAGA,EAAO,IAAIA"}
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "@cmdoss/file-manager",
3
+ "version": "0.1.0",
4
+ "license": "MIT",
5
+ "type": "module",
6
+ "exports": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "publishConfig": {
9
+ "access": "public",
10
+ "tag": "latest"
11
+ },
12
+ "peerDependencies": {
13
+ "@zenfs/archives": "^1.3.1",
14
+ "@zenfs/core": "^2.4.2",
15
+ "@zenfs/dom": "^1.2.4"
16
+ },
17
+ "dependencies": {
18
+ "@zenfs/archives": "^1.3.1",
19
+ "@zenfs/core": "^2.4.2",
20
+ "@zenfs/dom": "^1.2.5",
21
+ "@cmdoss/site-builder": "0.1.0"
22
+ },
23
+ "devDependencies": {
24
+ "@types/node": "^22.13.4",
25
+ "tsdown": "^0.15.4"
26
+ },
27
+ "scripts": {
28
+ "dev": "tsdown --platform browser --watch --ignore-watch .turbo",
29
+ "test": "node --test",
30
+ "check-types": "tsc --noEmit",
31
+ "build": "tsdown --platform browser --minify"
32
+ }
33
+ }
@@ -0,0 +1,110 @@
1
+ import type { FileChangedCallback, IFileManager } from '@cmdoss/site-builder'
2
+ import { Iso, Zip } from '@zenfs/archives'
3
+ import { configure, fs } from '@zenfs/core'
4
+ import * as path from '@zenfs/core/path'
5
+ import { IndexedDB } from '@zenfs/dom'
6
+
7
+ export class ZenFsFileManager implements IFileManager {
8
+ private changeListeners = new Set<FileChangedCallback>()
9
+
10
+ constructor(
11
+ private workspaceDir = '/workspace',
12
+ private backend: 'indexeddb' | 'zip' | 'iso' = 'indexeddb'
13
+ ) {}
14
+
15
+ async mount(data?: ArrayBuffer, force = false): Promise<void> {
16
+ const backend =
17
+ this.backend === 'indexeddb'
18
+ ? IndexedDB
19
+ : this.backend === 'zip'
20
+ ? Zip
21
+ : this.backend === 'iso'
22
+ ? Iso
23
+ : null
24
+ if (!backend) throw new Error('Invalid backend specified')
25
+ const isAccessible = await fs.promises
26
+ .access(this.workspaceDir)
27
+ .then(() => true)
28
+ .catch(() => false)
29
+ if (isAccessible) {
30
+ if (!force) throw new Error('Workspace directory is already mounted')
31
+ this.unmount() // Unmount existing instance
32
+ }
33
+ await configure({ mounts: { [this.workspaceDir]: { backend, data } } })
34
+ }
35
+
36
+ async writeFile(
37
+ filePath: string,
38
+ content: string | Uint8Array
39
+ ): Promise<void> {
40
+ filePath = ensureLeadingSlash(filePath)
41
+ const workspaceFilePath = path.join(this.workspaceDir, filePath)
42
+ const dir = path.dirname(workspaceFilePath)
43
+ await fs.promises.mkdir(dir, { recursive: true })
44
+ const contentBytes =
45
+ typeof content === 'string' ? new TextEncoder().encode(content) : content
46
+ await fs.promises.writeFile(workspaceFilePath, contentBytes)
47
+ this.notifyChange({
48
+ type: 'updated',
49
+ path: filePath
50
+ })
51
+ }
52
+
53
+ async removeFile(filePath: string): Promise<void> {
54
+ filePath = ensureLeadingSlash(filePath)
55
+ const workspaceFilePath = path.join(this.workspaceDir, filePath)
56
+ await fs.promises.rm(workspaceFilePath)
57
+ this.notifyChange({ type: 'removed', path: filePath })
58
+ }
59
+
60
+ async readFile(filePath: string): Promise<Uint8Array> {
61
+ filePath = ensureLeadingSlash(filePath)
62
+ const workspaceFilePath = path.join(this.workspaceDir, filePath)
63
+ console.log('Reading file from path:', workspaceFilePath)
64
+ return await fs.promises.readFile(workspaceFilePath)
65
+ }
66
+
67
+ async listFiles(): Promise<string[]> {
68
+ const files = await fs.promises.readdir(this.workspaceDir, {
69
+ withFileTypes: true,
70
+ recursive: true
71
+ })
72
+ console.log('Files in workspace:', files)
73
+ return files
74
+ .filter(f => f.isFile())
75
+ .map(f => path.resolve(f.parentPath, f.name))
76
+ .map(ensureLeadingSlash)
77
+ }
78
+
79
+ onFileChange(callback: FileChangedCallback): () => void {
80
+ this.changeListeners.add(callback)
81
+ return () => {
82
+ this.changeListeners.delete(callback)
83
+ }
84
+ }
85
+
86
+ private notifyChange(arg: Parameters<FileChangedCallback>[0]): void {
87
+ for (const listener of this.changeListeners) {
88
+ listener(arg)
89
+ }
90
+ }
91
+
92
+ async clear(): Promise<void> {
93
+ const files = await fs.promises.readdir(this.workspaceDir, {
94
+ withFileTypes: true
95
+ })
96
+ for (const file of files) {
97
+ const filePath = path.join(file.parentPath, file.name)
98
+ await fs.promises.rm(filePath, { recursive: true, force: true })
99
+ }
100
+ }
101
+
102
+ unmount(): void {
103
+ this.changeListeners.clear()
104
+ fs.umount(this.workspaceDir)
105
+ }
106
+ }
107
+
108
+ function ensureLeadingSlash(path: string): string {
109
+ return path.startsWith('/') ? path : `/${path}`
110
+ }
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './file-manager'
package/tsconfig.json ADDED
@@ -0,0 +1,11 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/tsconfig",
3
+ "extends": "../../configs/tsconfig.library.json",
4
+ "compilerOptions": {
5
+ "lib": ["ES2021", "DOM"],
6
+ "outDir": "/dist",
7
+ "emitDeclarationOnly": true,
8
+ "allowImportingTsExtensions": true
9
+ },
10
+ "include": ["src/**/*"]
11
+ }