@auto-engineer/file-store 0.1.1 → 0.1.3

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 (44) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/.turbo/turbo-test.log +6 -11
  3. package/.turbo/turbo-type-check.log +1 -1
  4. package/CHANGELOG.md +12 -0
  5. package/dist/src/{LightningFileStore.d.ts → InMemoryFileStore.d.ts} +6 -10
  6. package/dist/src/InMemoryFileStore.d.ts.map +1 -0
  7. package/dist/src/InMemoryFileStore.js +60 -0
  8. package/dist/src/InMemoryFileStore.js.map +1 -0
  9. package/dist/src/index.d.ts +0 -2
  10. package/dist/src/index.d.ts.map +1 -1
  11. package/dist/src/index.js +0 -2
  12. package/dist/src/index.js.map +1 -1
  13. package/dist/src/path.d.ts +0 -2
  14. package/dist/src/path.d.ts.map +1 -1
  15. package/dist/src/path.js +0 -13
  16. package/dist/src/path.js.map +1 -1
  17. package/dist/src/types.d.ts +0 -7
  18. package/dist/src/types.d.ts.map +1 -1
  19. package/dist/tsconfig.tsbuildinfo +1 -1
  20. package/package.json +2 -30
  21. package/src/InMemoryFileStore.ts +68 -0
  22. package/src/index.ts +0 -2
  23. package/src/path.ts +0 -14
  24. package/src/types.ts +0 -9
  25. package/tsconfig.json +1 -1
  26. package/dist/src/FileWatcher.d.ts +0 -20
  27. package/dist/src/FileWatcher.d.ts.map +0 -1
  28. package/dist/src/FileWatcher.js +0 -70
  29. package/dist/src/FileWatcher.js.map +0 -1
  30. package/dist/src/LightningFileStore.d.ts.map +0 -1
  31. package/dist/src/LightningFileStore.js +0 -105
  32. package/dist/src/LightningFileStore.js.map +0 -1
  33. package/dist/src/LightningFileStore.specs.d.ts +0 -2
  34. package/dist/src/LightningFileStore.specs.d.ts.map +0 -1
  35. package/dist/src/LightningFileStore.specs.js +0 -86
  36. package/dist/src/LightningFileStore.specs.js.map +0 -1
  37. package/dist/src/text-helpers.d.ts +0 -7
  38. package/dist/src/text-helpers.d.ts.map +0 -1
  39. package/dist/src/text-helpers.js +0 -9
  40. package/dist/src/text-helpers.js.map +0 -1
  41. package/src/FileWatcher.ts +0 -73
  42. package/src/LightningFileStore.specs.ts +0 -109
  43. package/src/LightningFileStore.ts +0 -126
  44. package/src/text-helpers.ts +0 -16
@@ -0,0 +1,68 @@
1
+ import { IFileStore } from './types';
2
+
3
+ export class InMemoryFileStore implements IFileStore {
4
+ private files = new Map<string, Uint8Array>();
5
+
6
+ private norm(p: string) {
7
+ if (!p) return '/';
8
+ return p.startsWith('/') ? p : `/${p}`;
9
+ }
10
+
11
+ async write(path: string, data: Uint8Array): Promise<void> {
12
+ this.files.set(this.norm(path), new Uint8Array(data));
13
+ }
14
+
15
+ async read(path: string): Promise<Uint8Array | null> {
16
+ const buf = this.files.get(this.norm(path));
17
+ return buf ? new Uint8Array(buf) : null;
18
+ }
19
+
20
+ async remove(path: string): Promise<void> {
21
+ const prefix = this.norm(path);
22
+ for (const key of Array.from(this.files.keys())) {
23
+ if (key === prefix || key.startsWith(prefix.endsWith('/') ? prefix : prefix + '/')) {
24
+ this.files.delete(key);
25
+ }
26
+ }
27
+ }
28
+
29
+ async exists(path: string): Promise<boolean> {
30
+ const p = this.norm(path);
31
+ if (this.files.has(p)) return true;
32
+ for (const key of this.files.keys()) {
33
+ if (key.startsWith(p.endsWith('/') ? p : p + '/')) return true;
34
+ }
35
+ return false;
36
+ }
37
+
38
+ async listTree(root: string = '/'): Promise<Array<{ path: string; type: 'file' | 'dir'; size: number }>> {
39
+ const r = this.norm(root);
40
+ const files = Array.from(this.files.entries()).filter(
41
+ ([p]) => p === r || p.startsWith(r.endsWith('/') ? r : r + '/'),
42
+ );
43
+
44
+ const dirs = new Set<string>(['/']);
45
+ for (const [p] of files) {
46
+ const parts = p.split('/').filter(Boolean);
47
+ let cur = '';
48
+ for (let i = 0; i < parts.length - 1; i++) {
49
+ cur += '/' + parts[i];
50
+ dirs.add(cur || '/');
51
+ }
52
+ }
53
+
54
+ const out: Array<{ path: string; type: 'file' | 'dir'; size: number }> = [];
55
+ for (const d of Array.from(dirs)) {
56
+ if (d === '/' || d.startsWith(r.endsWith('/') ? r : r + '/')) {
57
+ out.push({ path: d, type: 'dir', size: 0 });
58
+ }
59
+ }
60
+
61
+ for (const [p, buf] of files) {
62
+ out.push({ path: p, type: 'file', size: buf.byteLength });
63
+ }
64
+
65
+ out.sort((a, b) => (a.type === b.type ? a.path.localeCompare(b.path) : a.type === 'dir' ? -1 : 1));
66
+ return out;
67
+ }
68
+ }
package/src/index.ts CHANGED
@@ -1,4 +1,2 @@
1
1
  export * from './types';
2
- export { LightningFileStore } from './LightningFileStore';
3
2
  export { NodeFileStore } from './NodeFileStore';
4
- export * from './FileWatcher';
package/src/path.ts CHANGED
@@ -1,15 +1 @@
1
1
  export const toPosix = (p: string) => p.replace(/\\/g, '/');
2
-
3
- export const dirname = (p: string) => {
4
- const n = toPosix(p);
5
- const i = n.lastIndexOf('/');
6
- return i <= 0 ? '/' : n.slice(0, i);
7
- };
8
-
9
- export const join = (...parts: string[]) => {
10
- const filtered = parts.filter(Boolean);
11
- if (!filtered.length) return '/';
12
- const absolute = filtered[0].startsWith('/');
13
- const joined = toPosix(filtered.map((s) => s.replace(/^\/+|\/+$/g, '')).join('/'));
14
- return absolute ? `/${joined}` : joined;
15
- };
package/src/types.ts CHANGED
@@ -7,12 +7,3 @@ export interface IFileStore {
7
7
  }
8
8
 
9
9
  export type ChangeKind = 'created' | 'updated' | 'deleted';
10
-
11
- export type FileEncoding = 'utf8' | 'base64';
12
-
13
- export type FileChange = {
14
- path: string;
15
- kind: ChangeKind;
16
- hash?: string;
17
- size?: number;
18
- };
package/tsconfig.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "extends": "../../tsconfig.base.json",
3
3
  "compilerOptions": {
4
4
  "outDir": "./dist",
5
- "types": ["vitest/globals", "node", "md5", "picomatch"],
5
+ "types": ["vitest/globals", "node"],
6
6
  "lib": ["ES2022", "DOM"],
7
7
  "composite": true
8
8
  },
@@ -1,20 +0,0 @@
1
- import { EventEmitter } from 'eventemitter3';
2
- import type { FileChange, FileEncoding, IFileStore } from './types';
3
- type Events = {
4
- change: (c: FileChange) => void;
5
- };
6
- export declare class FileWatcher {
7
- private store;
8
- private bus;
9
- private index;
10
- constructor(store: IFileStore);
11
- onChange(cb: (c: FileChange) => void): () => EventEmitter<Events, any>;
12
- watch(glob: string | string[], cb: (c: FileChange) => void): () => EventEmitter<Events, any>;
13
- writeFile(path: string, content: string | ArrayBuffer | Uint8Array, enc?: FileEncoding): Promise<void>;
14
- deleteFile(path: string): Promise<void>;
15
- seed(root?: string): Promise<void>;
16
- private computeExistingHash;
17
- private toBytes;
18
- }
19
- export {};
20
- //# sourceMappingURL=FileWatcher.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"FileWatcher.d.ts","sourceRoot":"","sources":["../../src/FileWatcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAG7C,OAAO,KAAK,EAAc,UAAU,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAEhF,KAAK,MAAM,GAAG;IAAE,MAAM,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,CAAA;CAAE,CAAC;AAElD,qBAAa,WAAW;IACtB,OAAO,CAAC,KAAK,CAAa;IAC1B,OAAO,CAAC,GAAG,CAA8B;IACzC,OAAO,CAAC,KAAK,CAA6B;gBAE9B,KAAK,EAAE,UAAU;IAI7B,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI;IAKpC,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI;IAOpD,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,WAAW,GAAG,UAAU,EAAE,GAAG,GAAE,YAAqB;IAW9F,UAAU,CAAC,IAAI,EAAE,MAAM;IAQvB,IAAI,CAAC,IAAI,SAAM;YAUP,mBAAmB;IASjC,OAAO,CAAC,OAAO;CAMhB"}
@@ -1,70 +0,0 @@
1
- import { EventEmitter } from 'eventemitter3';
2
- import picomatch from 'picomatch';
3
- import md5 from 'md5';
4
- export class FileWatcher {
5
- constructor(store) {
6
- this.bus = new EventEmitter();
7
- this.index = new Map();
8
- this.store = store;
9
- }
10
- onChange(cb) {
11
- this.bus.on('change', cb);
12
- return () => this.bus.off('change', cb);
13
- }
14
- watch(glob, cb) {
15
- const isMatch = picomatch(glob, { dot: true });
16
- return this.onChange((c) => {
17
- if (isMatch(c.path))
18
- cb(c);
19
- });
20
- }
21
- async writeFile(path, content, enc = 'utf8') {
22
- const data = this.toBytes(content, enc);
23
- const prevHash = this.index.get(path) ?? (await this.computeExistingHash(path));
24
- const nextHash = md5(data);
25
- if (prevHash === nextHash)
26
- return;
27
- await this.store.write(path, data);
28
- this.index.set(path, nextHash);
29
- const kind = prevHash !== undefined ? 'updated' : 'created';
30
- this.bus.emit('change', { path, kind, hash: nextHash, size: data.byteLength });
31
- }
32
- async deleteFile(path) {
33
- const existed = await this.store.exists(path);
34
- if (!existed)
35
- return;
36
- await this.store.remove(path);
37
- this.index.delete(path);
38
- this.bus.emit('change', { path, kind: 'deleted' });
39
- }
40
- async seed(root = '/') {
41
- const entries = await this.store.listTree(root);
42
- for (const e of entries) {
43
- if (e.type === 'file') {
44
- const buf = await this.store.read(e.path);
45
- if (buf)
46
- this.index.set(e.path, md5(buf));
47
- }
48
- }
49
- }
50
- async computeExistingHash(path) {
51
- if (!(await this.store.exists(path)))
52
- return undefined;
53
- const buf = await this.store.read(path);
54
- if (!buf)
55
- return undefined;
56
- const h = md5(buf);
57
- this.index.set(path, h);
58
- return h;
59
- }
60
- toBytes(content, enc) {
61
- if (content instanceof Uint8Array)
62
- return content;
63
- if (content instanceof ArrayBuffer)
64
- return new Uint8Array(content);
65
- if (enc === 'base64')
66
- return Uint8Array.from(atob(content), (c) => c.charCodeAt(0));
67
- return new TextEncoder().encode(content);
68
- }
69
- }
70
- //# sourceMappingURL=FileWatcher.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"FileWatcher.js","sourceRoot":"","sources":["../../src/FileWatcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,SAAS,MAAM,WAAW,CAAC;AAClC,OAAO,GAAG,MAAM,KAAK,CAAC;AAKtB,MAAM,OAAO,WAAW;IAKtB,YAAY,KAAiB;QAHrB,QAAG,GAAG,IAAI,YAAY,EAAU,CAAC;QACjC,UAAK,GAAG,IAAI,GAAG,EAAkB,CAAC;QAGxC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,CAAC;IAED,QAAQ,CAAC,EAA2B;QAClC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QAC1B,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IAC1C,CAAC;IAED,KAAK,CAAC,IAAuB,EAAE,EAA2B;QACxD,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/C,OAAO,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE;YACzB,IAAI,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;gBAAE,EAAE,CAAC,CAAC,CAAC,CAAC;QAC7B,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,IAAY,EAAE,OAA0C,EAAE,MAAoB,MAAM;QAClG,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QACxC,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC;QAChF,MAAM,QAAQ,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC;QAC3B,IAAI,QAAQ,KAAK,QAAQ;YAAE,OAAO;QAClC,MAAM,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QACnC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QAC/B,MAAM,IAAI,GAAe,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;QACxE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC;IACjF,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,IAAY;QAC3B,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC9C,IAAI,CAAC,OAAO;YAAE,OAAO;QACrB,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC9B,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACxB,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;IACrD,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,GAAG;QACnB,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAChD,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;YACxB,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;gBACtB,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;gBAC1C,IAAI,GAAG;oBAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;YAC5C,CAAC;QACH,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,mBAAmB,CAAC,IAAY;QAC5C,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAAE,OAAO,SAAS,CAAC;QACvD,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxC,IAAI,CAAC,GAAG;YAAE,OAAO,SAAS,CAAC;QAC3B,MAAM,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;QACnB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QACxB,OAAO,CAAC,CAAC;IACX,CAAC;IAEO,OAAO,CAAC,OAA0C,EAAE,GAAiB;QAC3E,IAAI,OAAO,YAAY,UAAU;YAAE,OAAO,OAAO,CAAC;QAClD,IAAI,OAAO,YAAY,WAAW;YAAE,OAAO,IAAI,UAAU,CAAC,OAAO,CAAC,CAAC;QACnE,IAAI,GAAG,KAAK,QAAQ;YAAE,OAAO,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;QACpF,OAAO,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC3C,CAAC;CACF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"LightningFileStore.d.ts","sourceRoot":"","sources":["../../src/LightningFileStore.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAsB1C,qBAAa,kBAAmB,YAAW,UAAU;IACnD,OAAO,CAAC,EAAE,CAAsB;IAChC,OAAO,CAAC,GAAG,CAAsB;gBAErB,IAAI,SAAU;IAKpB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAKpD,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAQ9C,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAOtC,QAAQ,CAAC,IAAI,GAAE,MAAY,GAAG,OAAO,CAAC,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,GAAG,KAAK,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IA+BlG,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAe3B,eAAe;IAS7B,OAAO,CAAC,mBAAmB;YAKb,MAAM;CAarB"}
@@ -1,105 +0,0 @@
1
- import LightningFS from '@isomorphic-git/lightning-fs';
2
- import { dirname } from './path.js';
3
- export class LightningFileStore {
4
- constructor(name = 'pocfs') {
5
- this.fs = new LightningFS(name);
6
- this.pfs = this.fs.promises;
7
- }
8
- async write(path, data) {
9
- await this.mkdirp(dirname(path));
10
- await this.pfs.writeFile(path, data);
11
- }
12
- async read(path) {
13
- try {
14
- return await this.pfs.readFile(path);
15
- }
16
- catch {
17
- return null;
18
- }
19
- }
20
- async exists(path) {
21
- return await this.pfs
22
- .stat(path)
23
- .then(() => true)
24
- .catch(() => false);
25
- }
26
- async listTree(root = '/') {
27
- const out = [];
28
- const walk = async (p) => {
29
- let st = null;
30
- try {
31
- st = await this.pfs.stat(p);
32
- }
33
- catch {
34
- return;
35
- }
36
- if (st !== null && st.isDirectory()) {
37
- out.push({ path: p, type: 'dir', size: 0 });
38
- let entries = [];
39
- try {
40
- entries = await this.pfs.readdir(p);
41
- }
42
- catch {
43
- /* ignore */
44
- }
45
- for (const name of entries) {
46
- const child = p === '/' ? `/${name}` : `${p}/${name}`;
47
- await walk(child);
48
- }
49
- }
50
- else {
51
- out.push({ path: p, type: 'file', size: st?.size ?? 0 });
52
- }
53
- };
54
- await walk(root);
55
- out.sort((a, b) => (a.type === b.type ? a.path.localeCompare(b.path) : a.type === 'dir' ? -1 : 1));
56
- return out;
57
- }
58
- async remove(path) {
59
- if (!path)
60
- return;
61
- try {
62
- const st = await this.pfs.stat(path);
63
- if (st.isDirectory()) {
64
- await this.removeDirectory(path);
65
- }
66
- else {
67
- await this.pfs.unlink(path);
68
- }
69
- }
70
- catch (err) {
71
- if (this.isFileNotFoundError(err))
72
- return;
73
- throw err;
74
- }
75
- }
76
- async removeDirectory(path) {
77
- const entries = await this.pfs.readdir(path).catch(() => []);
78
- for (const name of entries) {
79
- const child = path === '/' ? `/${name}` : `${path}/${name}`;
80
- await this.remove(child);
81
- }
82
- await this.pfs.rmdir(path);
83
- }
84
- isFileNotFoundError(err) {
85
- if (err instanceof Error && 'code' in err && err.code === 'ENOENT')
86
- return true;
87
- return err === null || err === undefined;
88
- }
89
- async mkdirp(path) {
90
- if (!path || path === '/')
91
- return;
92
- const parts = path.split('/').filter(Boolean);
93
- let cur = '';
94
- for (const part of parts) {
95
- cur += '/' + part;
96
- const exists = await this.pfs
97
- .stat(cur)
98
- .then(() => true)
99
- .catch(() => false);
100
- if (!exists)
101
- await this.pfs.mkdir(cur);
102
- }
103
- }
104
- }
105
- //# sourceMappingURL=LightningFileStore.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"LightningFileStore.js","sourceRoot":"","sources":["../../src/LightningFileStore.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- import 'fake-indexeddb/auto';
2
- //# sourceMappingURL=LightningFileStore.specs.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"LightningFileStore.specs.d.ts","sourceRoot":"","sources":["../../src/LightningFileStore.specs.ts"],"names":[],"mappings":"AAEA,OAAO,qBAAqB,CAAC"}
@@ -1,86 +0,0 @@
1
- // @vitest-environment jsdom
2
- import { describe, it, expect, beforeEach } from 'vitest';
3
- import 'fake-indexeddb/auto';
4
- import { LightningFileStore } from './LightningFileStore.js';
5
- const te = new TextEncoder();
6
- const td = new TextDecoder();
7
- const resetIDBs = async () => await new Promise((res, rej) => {
8
- const dbs = ['flowfs-test', 'flowfs-complex-test'];
9
- let done = 0;
10
- for (const name of dbs) {
11
- const req = indexedDB.deleteDatabase(name);
12
- req.onerror = () => rej(req.error);
13
- req.onsuccess = () => {
14
- done += 1;
15
- if (done === dbs.length)
16
- res();
17
- };
18
- }
19
- });
20
- beforeEach(async () => {
21
- await resetIDBs();
22
- });
23
- describe('LightningFS FileStore (basic ops)', () => {
24
- it('writes and reads a file', async () => {
25
- const fs = new LightningFileStore('flowfs-test');
26
- await fs.write('/test.txt', te.encode('hello world'));
27
- const buf = await fs.read('/test.txt');
28
- expect(buf).not.toBeNull();
29
- expect(td.decode(buf)).toBe('hello world');
30
- });
31
- it('checks file existence', async () => {
32
- const fs = new LightningFileStore('flowfs-test');
33
- await fs.write('/exists.txt', te.encode('ok'));
34
- expect(await fs.exists('/exists.txt')).toBe(true);
35
- expect(await fs.exists('/missing.txt')).toBe(false);
36
- });
37
- it('supports nested directories (mkdir -p style) for write/read', async () => {
38
- const fs = new LightningFileStore('flowfs-test');
39
- await fs.write('/nested/deep/file.txt', te.encode('nested content'));
40
- const buf = await fs.read('/nested/deep/file.txt');
41
- expect(buf).not.toBeNull();
42
- expect(td.decode(buf)).toBe('nested content');
43
- });
44
- it('lists directory contents via listTree()', async () => {
45
- const fs = new LightningFileStore('flowfs-test');
46
- await fs.write('/a.txt', te.encode('a'));
47
- await fs.write('/dir/b.txt', te.encode('b'));
48
- const tree = await fs.listTree('/');
49
- const paths = tree.map((e) => e.path).sort();
50
- expect(paths).toContain('/');
51
- expect(paths).toContain('/a.txt');
52
- expect(paths).toContain('/dir');
53
- expect(paths).toContain('/dir/b.txt');
54
- const root = tree.find((e) => e.path === '/');
55
- const dir = tree.find((e) => e.path === '/dir');
56
- const file = tree.find((e) => e.path === '/a.txt');
57
- expect(root?.type).toBe('dir');
58
- expect(dir?.type).toBe('dir');
59
- expect(file?.type).toBe('file');
60
- });
61
- });
62
- describe('LightningFS FileStore (complex structure)', () => {
63
- it('creates and verifies a multi-level project layout', async () => {
64
- const fs = new LightningFileStore('flowfs-complex-test');
65
- await fs.write('/src/flows/items.flow.ts', te.encode('items flow'));
66
- await fs.write('/src/flows/orders.flow.ts', te.encode('orders flow'));
67
- await fs.write('/src/integrations/user.integration.ts', te.encode('user integration'));
68
- await fs.write('/config/settings.json', te.encode('{"key":"value"}'));
69
- expect(await fs.exists('/src/flows/items.flow.ts')).toBe(true);
70
- expect(await fs.exists('/src/flows/orders.flow.ts')).toBe(true);
71
- expect(await fs.exists('/src/integrations/user.integration.ts')).toBe(true);
72
- expect(await fs.exists('/config/settings.json')).toBe(true);
73
- const tree = await fs.listTree('/src');
74
- const paths = tree.map((e) => e.path);
75
- expect(paths).toContain('/src');
76
- expect(paths).toContain('/src/flows');
77
- expect(paths).toContain('/src/integrations');
78
- expect(paths).toContain('/src/flows/items.flow.ts');
79
- expect(paths).toContain('/src/flows/orders.flow.ts');
80
- // verify content
81
- const itemsBuf = await fs.read('/src/flows/items.flow.ts');
82
- expect(itemsBuf).not.toBeNull();
83
- expect(td.decode(itemsBuf)).toBe('items flow');
84
- });
85
- });
86
- //# sourceMappingURL=LightningFileStore.specs.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"LightningFileStore.specs.js","sourceRoot":"","sources":["../../src/LightningFileStore.specs.ts"],"names":[],"mappings":"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"}
@@ -1,7 +0,0 @@
1
- export declare function readText(fs: {
2
- read(path: string): Promise<Uint8Array | null>;
3
- }, path: string): Promise<string | null>;
4
- export declare function writeText(fs: {
5
- write(path: string, data: Uint8Array): Promise<void>;
6
- }, path: string, text: string): Promise<void>;
7
- //# sourceMappingURL=text-helpers.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"text-helpers.d.ts","sourceRoot":"","sources":["../../src/text-helpers.ts"],"names":[],"mappings":"AAAA,wBAAsB,QAAQ,CAC5B,EAAE,EAAE;IAAE,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAA;CAAE,EACtD,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAGxB;AAED,wBAAsB,SAAS,CAC7B,EAAE,EAAE;IAAE,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,EAC5D,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,CAAC,CAGf"}
@@ -1,9 +0,0 @@
1
- export async function readText(fs, path) {
2
- const buf = await fs.read(path);
3
- return buf ? new TextDecoder().decode(buf) : null;
4
- }
5
- export async function writeText(fs, path, text) {
6
- const buf = new TextEncoder().encode(text);
7
- await fs.write(path, buf);
8
- }
9
- //# sourceMappingURL=text-helpers.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"text-helpers.js","sourceRoot":"","sources":["../../src/text-helpers.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,EAAsD,EACtD,IAAY;IAEZ,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChC,OAAO,GAAG,CAAC,CAAC,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACpD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,EAA4D,EAC5D,IAAY,EACZ,IAAY;IAEZ,MAAM,GAAG,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC3C,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;AAC5B,CAAC"}
@@ -1,73 +0,0 @@
1
- import { EventEmitter } from 'eventemitter3';
2
- import picomatch from 'picomatch';
3
- import md5 from 'md5';
4
- import type { ChangeKind, FileChange, FileEncoding, IFileStore } from './types';
5
-
6
- type Events = { change: (c: FileChange) => void };
7
-
8
- export class FileWatcher {
9
- private store: IFileStore;
10
- private bus = new EventEmitter<Events>();
11
- private index = new Map<string, string>();
12
-
13
- constructor(store: IFileStore) {
14
- this.store = store;
15
- }
16
-
17
- onChange(cb: (c: FileChange) => void) {
18
- this.bus.on('change', cb);
19
- return () => this.bus.off('change', cb);
20
- }
21
-
22
- watch(glob: string | string[], cb: (c: FileChange) => void) {
23
- const isMatch = picomatch(glob, { dot: true });
24
- return this.onChange((c) => {
25
- if (isMatch(c.path)) cb(c);
26
- });
27
- }
28
-
29
- async writeFile(path: string, content: string | ArrayBuffer | Uint8Array, enc: FileEncoding = 'utf8') {
30
- const data = this.toBytes(content, enc);
31
- const prevHash = this.index.get(path) ?? (await this.computeExistingHash(path));
32
- const nextHash = md5(data);
33
- if (prevHash === nextHash) return;
34
- await this.store.write(path, data);
35
- this.index.set(path, nextHash);
36
- const kind: ChangeKind = prevHash !== undefined ? 'updated' : 'created';
37
- this.bus.emit('change', { path, kind, hash: nextHash, size: data.byteLength });
38
- }
39
-
40
- async deleteFile(path: string) {
41
- const existed = await this.store.exists(path);
42
- if (!existed) return;
43
- await this.store.remove(path);
44
- this.index.delete(path);
45
- this.bus.emit('change', { path, kind: 'deleted' });
46
- }
47
-
48
- async seed(root = '/') {
49
- const entries = await this.store.listTree(root);
50
- for (const e of entries) {
51
- if (e.type === 'file') {
52
- const buf = await this.store.read(e.path);
53
- if (buf) this.index.set(e.path, md5(buf));
54
- }
55
- }
56
- }
57
-
58
- private async computeExistingHash(path: string) {
59
- if (!(await this.store.exists(path))) return undefined;
60
- const buf = await this.store.read(path);
61
- if (!buf) return undefined;
62
- const h = md5(buf);
63
- this.index.set(path, h);
64
- return h;
65
- }
66
-
67
- private toBytes(content: string | ArrayBuffer | Uint8Array, enc: FileEncoding): Uint8Array {
68
- if (content instanceof Uint8Array) return content;
69
- if (content instanceof ArrayBuffer) return new Uint8Array(content);
70
- if (enc === 'base64') return Uint8Array.from(atob(content), (c) => c.charCodeAt(0));
71
- return new TextEncoder().encode(content);
72
- }
73
- }
@@ -1,109 +0,0 @@
1
- // @vitest-environment jsdom
2
- import { describe, it, expect, beforeEach } from 'vitest';
3
- import 'fake-indexeddb/auto';
4
- import { LightningFileStore } from './LightningFileStore';
5
-
6
- const te = new TextEncoder();
7
- const td = new TextDecoder();
8
-
9
- const resetIDBs = async () =>
10
- await new Promise<void>((res, rej) => {
11
- const dbs = ['flowfs-test', 'flowfs-complex-test'];
12
- let done = 0;
13
- for (const name of dbs) {
14
- const req = indexedDB.deleteDatabase(name);
15
- req.onerror = () => rej(req.error);
16
- req.onsuccess = () => {
17
- done += 1;
18
- if (done === dbs.length) res();
19
- };
20
- }
21
- });
22
-
23
- beforeEach(async () => {
24
- await resetIDBs();
25
- });
26
-
27
- describe('LightningFS FileStore (basic ops)', () => {
28
- it('writes and reads a file', async () => {
29
- const fs = new LightningFileStore('flowfs-test');
30
-
31
- await fs.write('/test.txt', te.encode('hello world'));
32
- const buf = await fs.read('/test.txt');
33
-
34
- expect(buf).not.toBeNull();
35
- expect(td.decode(buf!)).toBe('hello world');
36
- });
37
-
38
- it('checks file existence', async () => {
39
- const fs = new LightningFileStore('flowfs-test');
40
-
41
- await fs.write('/exists.txt', te.encode('ok'));
42
-
43
- expect(await fs.exists('/exists.txt')).toBe(true);
44
- expect(await fs.exists('/missing.txt')).toBe(false);
45
- });
46
-
47
- it('supports nested directories (mkdir -p style) for write/read', async () => {
48
- const fs = new LightningFileStore('flowfs-test');
49
-
50
- await fs.write('/nested/deep/file.txt', te.encode('nested content'));
51
- const buf = await fs.read('/nested/deep/file.txt');
52
-
53
- expect(buf).not.toBeNull();
54
- expect(td.decode(buf!)).toBe('nested content');
55
- });
56
-
57
- it('lists directory contents via listTree()', async () => {
58
- const fs = new LightningFileStore('flowfs-test');
59
-
60
- await fs.write('/a.txt', te.encode('a'));
61
- await fs.write('/dir/b.txt', te.encode('b'));
62
-
63
- const tree = await fs.listTree('/');
64
-
65
- const paths = tree.map((e) => e.path).sort();
66
- expect(paths).toContain('/');
67
- expect(paths).toContain('/a.txt');
68
- expect(paths).toContain('/dir');
69
- expect(paths).toContain('/dir/b.txt');
70
-
71
- const root = tree.find((e) => e.path === '/');
72
- const dir = tree.find((e) => e.path === '/dir');
73
- const file = tree.find((e) => e.path === '/a.txt');
74
-
75
- expect(root?.type).toBe('dir');
76
- expect(dir?.type).toBe('dir');
77
- expect(file?.type).toBe('file');
78
- });
79
- });
80
-
81
- describe('LightningFS FileStore (complex structure)', () => {
82
- it('creates and verifies a multi-level project layout', async () => {
83
- const fs = new LightningFileStore('flowfs-complex-test');
84
-
85
- await fs.write('/src/flows/items.flow.ts', te.encode('items flow'));
86
- await fs.write('/src/flows/orders.flow.ts', te.encode('orders flow'));
87
- await fs.write('/src/integrations/user.integration.ts', te.encode('user integration'));
88
- await fs.write('/config/settings.json', te.encode('{"key":"value"}'));
89
-
90
- expect(await fs.exists('/src/flows/items.flow.ts')).toBe(true);
91
- expect(await fs.exists('/src/flows/orders.flow.ts')).toBe(true);
92
- expect(await fs.exists('/src/integrations/user.integration.ts')).toBe(true);
93
- expect(await fs.exists('/config/settings.json')).toBe(true);
94
-
95
- const tree = await fs.listTree('/src');
96
- const paths = tree.map((e) => e.path);
97
-
98
- expect(paths).toContain('/src');
99
- expect(paths).toContain('/src/flows');
100
- expect(paths).toContain('/src/integrations');
101
- expect(paths).toContain('/src/flows/items.flow.ts');
102
- expect(paths).toContain('/src/flows/orders.flow.ts');
103
-
104
- // verify content
105
- const itemsBuf = await fs.read('/src/flows/items.flow.ts');
106
- expect(itemsBuf).not.toBeNull();
107
- expect(td.decode(itemsBuf!)).toBe('items flow');
108
- });
109
- });