@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.
- package/.turbo/turbo-build.log +14 -0
- package/.turbo/turbo-test.log +14 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/package.json +33 -0
- package/src/file-manager.ts +110 -0
- package/src/index.ts +1 -0
- package/tsconfig.json +11 -0
|
@@ -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
|
+
[34mℹ[39m tsdown [2mv0.15.4[22m powered by rolldown [2mv1.0.0-beta.43[22m
|
|
6
|
+
[34mℹ[39m entry: [34msrc/index.ts[39m
|
|
7
|
+
[34mℹ[39m tsconfig: [34mtsconfig.json[39m
|
|
8
|
+
[34mℹ[39m Build start
|
|
9
|
+
[34mℹ[39m [2mdist/[22m[1mindex.js[22m [2m1.87 kB[22m [2m│ gzip: 0.82 kB[22m
|
|
10
|
+
[34mℹ[39m [2mdist/[22mindex.js.map [2m5.55 kB[22m [2m│ gzip: 1.92 kB[22m
|
|
11
|
+
[34mℹ[39m [2mdist/[22mindex.d.ts.map [2m0.73 kB[22m [2m│ gzip: 0.35 kB[22m
|
|
12
|
+
[34mℹ[39m [2mdist/[22m[32m[1mindex.d.ts[22m[39m [2m0.79 kB[22m [2m│ gzip: 0.41 kB[22m
|
|
13
|
+
[34mℹ[39m 4 files, total: 8.94 kB
|
|
14
|
+
[32m✔[39m Build complete in [32m236ms[39m
|
package/dist/index.d.ts
ADDED
|
@@ -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
|
+
}
|