@legit-sdk/core 0.1.7

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,780 @@
1
+ import * as nodeFs from 'node:fs';
2
+ import { MakeDirectoryOptions, Mode } from 'node:fs';
3
+ import * as memfs_lib_node_types_misc_js from 'memfs/lib/node/types/misc.js';
4
+ import { IDir, TFileHandleReadResult, TData, TMode, IStats, TTime, TFileHandleWriteResult, TFileHandleWritevResult, TFileHandleReadvResult, IFileHandle, TDataOut, IDirent, PathLike } from 'memfs/lib/node/types/misc.js';
5
+ import { IAppendFileOptions, IStatOptions, IReadFileOptions, IWriteFileOptions, IReadableWebStreamOptions } from 'memfs/lib/node/types/options.js';
6
+ import { PathLike as PathLike$1 } from 'fs';
7
+ import { IFs } from 'memfs';
8
+ import { FsClient } from 'isomorphic-git';
9
+ import { fileSave, FileWithHandle } from 'browser-fs-access';
10
+
11
+ type CompositeSubFsDir = Pick<IDir, "path" | "close" | "read" | typeof Symbol.asyncIterator>;
12
+
13
+ type FileHandleDelegate = {
14
+ fileType: () => number;
15
+ open: (filePath: string, flags: string, mode?: number) => Promise<CompositFsFileHandle>;
16
+ /**
17
+ * @returns a unique number per subfs
18
+ */
19
+ close: (fh: CompositFsFileHandle) => void;
20
+ dataSync: (fh: CompositFsFileHandle) => Promise<void>;
21
+ read: (fh: CompositFsFileHandle, buffer: Buffer | Uint8Array, offset: number, length: number, position: number) => Promise<TFileHandleReadResult>;
22
+ appendFile: (fh: CompositFsFileHandle, data: TData, options?: IAppendFileOptions | string) => Promise<void>;
23
+ fchmod: (fh: CompositFsFileHandle, mode: TMode) => Promise<void>;
24
+ fchown: (fh: CompositFsFileHandle, uid: number, gid: number) => Promise<void>;
25
+ ftruncate(fh: CompositFsFileHandle, len?: number): Promise<void>;
26
+ fstat(fh: CompositFsFileHandle, options?: IStatOptions): Promise<IStats>;
27
+ futimes(fh: CompositFsFileHandle, atime: TTime, mtime: TTime): Promise<void>;
28
+ write(fh: CompositFsFileHandle, buffer: Buffer | ArrayBufferView | DataView, offset?: number, length?: number, position?: number): Promise<TFileHandleWriteResult>;
29
+ writev(fh: CompositFsFileHandle, buffers: ArrayBufferView[], position?: number | null): Promise<TFileHandleWritevResult>;
30
+ readv(fh: CompositFsFileHandle, buffers: ArrayBufferView[], position?: number | null): Promise<TFileHandleReadvResult>;
31
+ };
32
+
33
+ type CompositeSubFs = Pick<typeof nodeFs.promises, 'access' | 'link' | 'readdir' | 'readlink' | 'unlink' | 'rename' | 'rmdir' | 'symlink'> & {
34
+ readFile(path: nodeFs.PathLike | IFileHandle, options?: IReadFileOptions | string): Promise<TDataOut>;
35
+ stat(path: nodeFs.PathLike, opts?: IStatOptions & {
36
+ bigint?: false;
37
+ }): Promise<IStats<number>>;
38
+ stat(path: nodeFs.PathLike, opts: IStatOptions & {
39
+ bigint: true;
40
+ }): Promise<IStats<bigint>>;
41
+ stat(path: nodeFs.PathLike, opts?: IStatOptions): Promise<IStats<number> | IStats<bigint>>;
42
+ lstat(path: nodeFs.PathLike, opts?: IStatOptions & {
43
+ bigint?: false;
44
+ }): Promise<IStats<number>>;
45
+ lstat(path: nodeFs.PathLike, opts: IStatOptions & {
46
+ bigint: true;
47
+ }): Promise<IStats<bigint>>;
48
+ lstat(path: nodeFs.PathLike, opts?: IStatOptions): Promise<IStats<number> | IStats<bigint>>;
49
+ mkdir: (path: nodeFs.PathLike, options?: MakeDirectoryOptions | Mode | null) => Promise<void>;
50
+ fileType: () => number;
51
+ writeFile: (path: string, data: TData, options: IWriteFileOptions | string) => Promise<void>;
52
+ opendir(dirPath: nodeFs.PathLike, options?: nodeFs.OpenDirOptions): Promise<CompositeSubFsDir>;
53
+ lookup: (path: string) => Promise<number>;
54
+ responsible(filePath: string): Promise<boolean>;
55
+ resolvePath: (fd: number) => string;
56
+ } & FileHandleDelegate;
57
+
58
+ interface ICompositFsFileHandle {
59
+ subFsFileDescriptor: number;
60
+ fsType: number;
61
+ fd: number;
62
+ appendFile(data: TData, options?: IAppendFileOptions | string): Promise<void>;
63
+ chmod(mode: TMode): Promise<void>;
64
+ chown(uid: number, gid: number): Promise<void>;
65
+ close(): Promise<void>;
66
+ datasync(): Promise<void>;
67
+ readableWebStream(options?: IReadableWebStreamOptions): ReadableStream;
68
+ read(buffer: Buffer | Uint8Array, offset: number, length: number, position: number): Promise<TFileHandleReadResult>;
69
+ readv(buffers: ArrayBufferView[], position?: number | null): Promise<TFileHandleReadvResult>;
70
+ stat(options?: IStatOptions): Promise<IStats>;
71
+ truncate(len?: number): Promise<void>;
72
+ utimes(atime: TTime, mtime: TTime): Promise<void>;
73
+ write(buffer: Buffer | ArrayBufferView | DataView, offset?: number, length?: number, position?: number): Promise<TFileHandleWriteResult>;
74
+ writev(buffers: ArrayBufferView[], position?: number | null): Promise<TFileHandleWritevResult>;
75
+ sync(): Promise<void>;
76
+ }
77
+ /**
78
+ * While a filehandle in node env usually is an independent (from its fs) entity to keep fs operatons colocated per type (vritual, managed... files) we
79
+ * wrap the filehandle in a SubFsFileHandle and forward all operations to there origin filesystem
80
+ */
81
+ declare class CompositFsFileHandle implements ICompositFsFileHandle {
82
+ private delegate;
83
+ get fsType(): number;
84
+ private _subFsFileDescriptor;
85
+ get subFsFileDescriptor(): number;
86
+ handleType: string;
87
+ private _compositFsFileDescriptor;
88
+ get fd(): number;
89
+ realize(compositeFd: number): void;
90
+ constructor(args: {
91
+ fs: FileHandleDelegate;
92
+ subFsFileDescriptor: number;
93
+ parentFsFileDescriptors: number[];
94
+ });
95
+ readableWebStream(options?: IReadableWebStreamOptions): ReadableStream;
96
+ appendFile(data: TData, options?: IAppendFileOptions | string): Promise<void>;
97
+ chmod(mode: TMode): Promise<void>;
98
+ chown(uid: number, gid: number): Promise<void>;
99
+ close(): Promise<void>;
100
+ datasync(): Promise<void>;
101
+ read(buffer: Buffer | Uint8Array, offset: number, length: number, position: number): Promise<TFileHandleReadResult>;
102
+ readv(buffers: ArrayBufferView[], position?: number | null): Promise<TFileHandleReadvResult>;
103
+ stat(options?: IStatOptions): Promise<IStats>;
104
+ truncate(len?: number): Promise<void>;
105
+ utimes(atime: TTime, mtime: TTime): Promise<void>;
106
+ write(buffer: Buffer | ArrayBufferView | DataView, offset?: number, length?: number, position?: number): Promise<TFileHandleWriteResult>;
107
+ writev(buffers: ArrayBufferView[], position?: number | null): Promise<TFileHandleWritevResult>;
108
+ sync(): Promise<void>;
109
+ }
110
+
111
+ declare class CompositeFsDir {
112
+ private entries;
113
+ private currentIndex;
114
+ private closed;
115
+ private compositFs;
116
+ private dirPath;
117
+ private initialized;
118
+ constructor(compositFs: CompositeFs, dirPath: string);
119
+ private initialize;
120
+ [Symbol.asyncIterator](): AsyncIterableIterator<IDirent>;
121
+ read(): Promise<nodeFs.Dirent | null>;
122
+ close(): Promise<void>;
123
+ get path(): string;
124
+ }
125
+
126
+ /**
127
+ *
128
+ * The CompositFs handles distribution of file operations to its sub filesystems and keeps track of open file handles.
129
+ * open returns a CompositFsFileHandle that wraps the real filehandle from the responsible SubFs and allows
130
+ * to forward operations
131
+ *
132
+ * Each SubFs determines if it is responsible for a given path. The Composite fs probes each subsystem for responsibility.
133
+ *
134
+ * The responisbility is probed in the following order:
135
+ *
136
+ * hiddenFilesFileSystem -> ephemeralFilesFileSystem -> other subFs in order of addition -> passThroughFileSystem
137
+ *
138
+ * Composit fs consists of two special sub filesystems:
139
+ *
140
+ * HiddenFilesSubFs - a filesystem that makes files inaccessible from the user
141
+ * -> this is useful if you want to protect files like .git from being accessed or modified by the user
142
+ *
143
+ * EphemeralFilesSubFs - a filesystem that provides files that only exist in memory and are not persisted
144
+ * -> this is usefull when you mount the compositfs as a Network drive for example via NFS to provide a space OS specific User files like .DS_
145
+ *
146
+ * Beyond those special subsystems additional systems cann be plugged in - the order matters
147
+ * and "the other" sub systems added via addSubFs
148
+ *
149
+
150
+ *
151
+ * Renames over subfs bounderies are are managed by this fs
152
+ *
153
+ * writeFile and readFile open a short living filehandle to execute the operations
154
+ *
155
+ *
156
+ */
157
+ declare class CompositeFs {
158
+ promises: {
159
+ access: (filePath: string, mode?: number) => Promise<void>;
160
+ opendir: (dirPath: nodeFs.PathLike, options?: nodeFs.OpenDirOptions) => Promise<CompositeFsDir>;
161
+ mkdir: (dirPath: string, options?: any) => Promise<void>;
162
+ readdir: (dirPath: nodeFs.PathLike, options?: any) => Promise<string[]>;
163
+ open: (filePath: string, flags: string, mode?: number) => Promise<CompositFsFileHandle>;
164
+ stat: (path: nodeFs.PathLike, opts?: {
165
+ bigint?: boolean;
166
+ }) => Promise<nodeFs.Stats | nodeFs.BigIntStats>;
167
+ lstat: (path: nodeFs.PathLike, opts?: {
168
+ bigint?: boolean;
169
+ }) => Promise<nodeFs.Stats | nodeFs.BigIntStats>;
170
+ link: (existingPath: nodeFs.PathLike, newPath: nodeFs.PathLike) => Promise<void>;
171
+ readlink: (path: nodeFs.PathLike, options?: nodeFs.ObjectEncodingOptions | BufferEncoding | null) => Promise<any>;
172
+ unlink: (filePath: nodeFs.PathLike) => Promise<void>;
173
+ rename: (oldPath: nodeFs.PathLike, newPath: nodeFs.PathLike) => Promise<void>;
174
+ rmdir: (dirPath: nodeFs.PathLike, options?: nodeFs.RmDirOptions) => Promise<void>;
175
+ symlink: (target: nodeFs.PathLike, path: nodeFs.PathLike, type?: string | null) => Promise<void>;
176
+ readFile: (typeof nodeFs.promises)['readFile'];
177
+ writeFile: (file: nodeFs.PathOrFileDescriptor, data: string | Buffer | Uint8Array, options?: any) => Promise<void>;
178
+ getFilehandle: (fd: number) => CompositFsFileHandle | undefined;
179
+ };
180
+ gitRoot: string;
181
+ ephemeralFilesFileSystem: CompositeSubFs | undefined;
182
+ hiddenFilesFileSystem: CompositeSubFs | undefined;
183
+ passThroughFileSystem: CompositeSubFs;
184
+ subFilesystems: CompositeSubFs[];
185
+ parentFs: CompositeFs | undefined;
186
+ name: string;
187
+ pathToFileDescriptors: Map<
188
+ /** path */
189
+ string, number[]>;
190
+ openFileHandles: Map<number, CompositFsFileHandle>;
191
+ private getNextFileDescriptor;
192
+ constructor({ name, parentFs, storageFs, gitRoot, }: {
193
+ name: string;
194
+ parentFs: CompositeFs | undefined;
195
+ storageFs: typeof nodeFs | undefined;
196
+ gitRoot: string;
197
+ });
198
+ getFilehandle(fd: number): CompositFsFileHandle | undefined;
199
+ setEphemeralFilesSubFs(subFs: CompositeSubFs): void;
200
+ setHiddenFilesSubFs(subFs: CompositeSubFs): void;
201
+ addSubFs(subFs: CompositeSubFs): void;
202
+ /**
203
+ * helper function that takes a filePath and returns the fs that is responsible Sub filesystem for it
204
+ * @param filePath
205
+ * @returns
206
+ */
207
+ private getResponsibleFs;
208
+ access(filePath: string, mode?: number): Promise<void>;
209
+ opendir(dirPath: nodeFs.PathLike, options?: nodeFs.OpenDirOptions): Promise<CompositeFsDir>;
210
+ mkdir(dirPath: string, options?: any): Promise<void>;
211
+ /**
212
+ * Read dir needs to check if one subfs takes control.
213
+ *
214
+ * TODO also implement the option to return stats
215
+ *
216
+ * @param dirPath
217
+ * @param options
218
+ * @returns
219
+ */
220
+ readdir(dirPath: nodeFs.PathLike, options?: any): Promise<string[]>;
221
+ open(filePath: string, flags: string, mode?: number): Promise<CompositFsFileHandle>;
222
+ close(fh: CompositFsFileHandle): Promise<void>;
223
+ stat(path: nodeFs.PathLike, opts?: {
224
+ bigint?: false;
225
+ }): Promise<nodeFs.Stats>;
226
+ stat(path: nodeFs.PathLike, opts: {
227
+ bigint: true;
228
+ }): Promise<nodeFs.BigIntStats>;
229
+ stat(path: nodeFs.PathLike, opts?: {
230
+ bigint?: boolean;
231
+ }): Promise<nodeFs.Stats | nodeFs.BigIntStats>;
232
+ lstat(path: nodeFs.PathLike, opts?: {
233
+ bigint?: false;
234
+ }): Promise<nodeFs.Stats>;
235
+ lstat(path: nodeFs.PathLike, opts: {
236
+ bigint: true;
237
+ }): Promise<nodeFs.BigIntStats>;
238
+ lstat(path: nodeFs.PathLike, opts?: {
239
+ bigint?: boolean;
240
+ }): Promise<nodeFs.Stats | nodeFs.BigIntStats>;
241
+ link(existingPath: nodeFs.PathLike, newPath: nodeFs.PathLike): Promise<void>;
242
+ readlink(path: nodeFs.PathLike, options?: nodeFs.ObjectEncodingOptions | BufferEncoding | null): Promise<void>;
243
+ unlink(filePath: nodeFs.PathLike): Promise<void>;
244
+ rename(oldPath: nodeFs.PathLike, newPath: nodeFs.PathLike): Promise<void>;
245
+ rmdir(dirPath: nodeFs.PathLike, options?: nodeFs.RmDirOptions): Promise<void>;
246
+ symlink(target: nodeFs.PathLike, path: nodeFs.PathLike, type?: string | null): Promise<void>;
247
+ readFile(path: nodeFs.PathOrFileDescriptor, options?: {
248
+ encoding?: null;
249
+ flag?: string;
250
+ } | null): Promise<Buffer>;
251
+ readFile(path: nodeFs.PathOrFileDescriptor, options: {
252
+ encoding: BufferEncoding;
253
+ flag?: string;
254
+ } | BufferEncoding): Promise<string>;
255
+ writeFile(file: nodeFs.PathOrFileDescriptor, data: string | Buffer | Uint8Array, options?: {
256
+ encoding?: BufferEncoding;
257
+ mode?: number;
258
+ flag?: string;
259
+ } | BufferEncoding | null): Promise<void>;
260
+ }
261
+
262
+ declare abstract class BaseCompositeSubFs implements CompositeSubFs {
263
+ protected toStr(p: any): string;
264
+ protected compositFs: CompositeFs;
265
+ protected gitRoot: string;
266
+ constructor({ parentFs, gitRoot, }: {
267
+ parentFs: CompositeFs;
268
+ gitRoot: string;
269
+ });
270
+ abstract responsible(filePath: string): Promise<boolean>;
271
+ abstract fileType(): number;
272
+ open(path: PathLike, flags: string, mode?: number): Promise<CompositFsFileHandle>;
273
+ access(path: PathLike, mode?: number): Promise<void>;
274
+ stat(path: PathLike, opts?: {
275
+ bigint?: false;
276
+ }): Promise<nodeFs.Stats>;
277
+ stat(path: PathLike, opts: {
278
+ bigint: true;
279
+ }): Promise<nodeFs.BigIntStats>;
280
+ stat(path: PathLike, opts?: {
281
+ bigint?: boolean;
282
+ }): Promise<nodeFs.Stats | nodeFs.BigIntStats>;
283
+ lstat(path: PathLike, opts?: {
284
+ bigint?: false;
285
+ }): Promise<nodeFs.Stats>;
286
+ lstat(path: PathLike, opts: {
287
+ bigint: true;
288
+ }): Promise<nodeFs.BigIntStats>;
289
+ lstat(path: PathLike, opts?: {
290
+ bigint?: boolean;
291
+ }): Promise<nodeFs.Stats | nodeFs.BigIntStats>;
292
+ opendir(path: PathLike, options?: nodeFs.OpenDirOptions): Promise<CompositeSubFsDir>;
293
+ link(existingPath: PathLike, newPath: PathLike): Promise<void>;
294
+ mkdir(path: PathLike, options?: nodeFs.MakeDirectoryOptions | nodeFs.Mode | null): Promise<void>;
295
+ readdir(path: PathLike, options?: (nodeFs.ObjectEncodingOptions & {
296
+ withFileTypes?: false | undefined;
297
+ recursive?: boolean | undefined;
298
+ }) | BufferEncoding | null): Promise<string[]>;
299
+ readdir(path: PathLike, options?: {
300
+ encoding: 'buffer';
301
+ withFileTypes?: false | undefined;
302
+ recursive?: boolean | undefined;
303
+ } | 'buffer' | null): Promise<Buffer[]>;
304
+ readdir(path: PathLike, options?: (nodeFs.ObjectEncodingOptions & {
305
+ withFileTypes?: false | undefined;
306
+ recursive?: boolean | undefined;
307
+ }) | BufferEncoding | null): Promise<string[] | Buffer[]>;
308
+ readdir(path: PathLike, options: nodeFs.ObjectEncodingOptions & {
309
+ withFileTypes: true;
310
+ recursive?: boolean | undefined;
311
+ }): Promise<nodeFs.Dirent[]>;
312
+ readlink(path: PathLike, ...args: any[]): Promise<any>;
313
+ unlink(path: PathLike): Promise<void>;
314
+ rename(oldPath: PathLike, newPath: PathLike): Promise<void>;
315
+ rmdir(path: PathLike, ...args: any[]): Promise<void>;
316
+ symlink(target: PathLike, path: PathLike, type?: string | null): Promise<void>;
317
+ lookup(filePath: string): Promise<number>;
318
+ resolvePath(fd: number): string;
319
+ close(fh: CompositFsFileHandle): Promise<void>;
320
+ dataSync(fh: CompositFsFileHandle): Promise<void>;
321
+ read(fh: CompositFsFileHandle, buffer: Buffer | Uint8Array, offset: number, length: number, position: number): Promise<TFileHandleReadResult>;
322
+ appendFile(fh: CompositFsFileHandle, data: TData, options?: IAppendFileOptions | string): Promise<void>;
323
+ fchmod(fh: CompositFsFileHandle, mode: TMode): Promise<void>;
324
+ fchown(fh: CompositFsFileHandle, uid: number, gid: number): Promise<void>;
325
+ ftruncate(fh: CompositFsFileHandle, len?: number): Promise<void>;
326
+ fstat(fh: CompositFsFileHandle, options?: IStatOptions): Promise<IStats>;
327
+ futimes(fh: CompositFsFileHandle, atime: TTime, mtime: TTime): Promise<void>;
328
+ write(fh: CompositFsFileHandle, buffer: Buffer | ArrayBufferView | DataView, offset?: number, length?: number, position?: number): Promise<TFileHandleWriteResult>;
329
+ writev(fh: CompositFsFileHandle, buffers: ArrayBufferView[], position?: number | null): Promise<TFileHandleWritevResult>;
330
+ readv(fh: CompositFsFileHandle, buffers: ArrayBufferView[], position?: number | null): Promise<TFileHandleReadvResult>;
331
+ readFile(path: PathLike | IFileHandle, options?: IReadFileOptions | string): Promise<TDataOut>;
332
+ writeFile(path: string, data: TData, options: IWriteFileOptions | string): Promise<void>;
333
+ }
334
+
335
+ /**
336
+ * FS utilized to hide files, it is responsible for files found in hiddenFiles
337
+ *
338
+ * For those files it fails on open, close etc.
339
+ */
340
+ declare class HiddenFileSubFs extends BaseCompositeSubFs {
341
+ private ig;
342
+ constructor({ parentFs, gitRoot, hiddenFiles, }: {
343
+ parentFs: CompositeFs;
344
+ gitRoot: string;
345
+ hiddenFiles: string[];
346
+ });
347
+ responsible(filePath: string): Promise<boolean>;
348
+ fileType(): number;
349
+ private error;
350
+ open(path: PathLike$1, flags: string, mode?: number): Promise<CompositFsFileHandle>;
351
+ access(path: PathLike$1): Promise<void>;
352
+ stat(path: PathLike$1): Promise<any>;
353
+ lstat(path: PathLike$1): Promise<any>;
354
+ opendir(path: PathLike$1): Promise<any>;
355
+ link(existingPath: PathLike$1): Promise<void>;
356
+ mkdir(path: PathLike$1): Promise<any>;
357
+ readdir(path: PathLike$1): Promise<any>;
358
+ readlink(path: PathLike$1): Promise<any>;
359
+ unlink(path: PathLike$1): Promise<void>;
360
+ rename(oldPath: PathLike$1): Promise<void>;
361
+ rmdir(path: PathLike$1): Promise<void>;
362
+ symlink(_target: PathLike$1, path: PathLike$1): Promise<void>;
363
+ lookup(filePath: string): Promise<number>;
364
+ resolvePath(fd: number): string;
365
+ close(fh: CompositFsFileHandle): Promise<void>;
366
+ dataSync(fh: CompositFsFileHandle): Promise<void>;
367
+ read(fh: CompositFsFileHandle, buffer: Buffer | Uint8Array, offset: number, length: number, position: number): Promise<any>;
368
+ }
369
+
370
+ /**
371
+ * FS utilized to provide ephemeral storage using in-memory filesystem
372
+ * Files matching ephemeralPatterns are stored in memory and lost on restart
373
+ */
374
+ declare class EphemeralSubFs extends BaseCompositeSubFs {
375
+ private openFh;
376
+ private memFs;
377
+ private ig;
378
+ patterns: string[];
379
+ private normalizePath;
380
+ constructor({ parentFs, gitRoot, ephemeralPatterns, }: {
381
+ parentFs: CompositeFs;
382
+ gitRoot: string;
383
+ ephemeralPatterns: string[];
384
+ });
385
+ responsible(filePath: string): Promise<boolean>;
386
+ fileType(): number;
387
+ open(filePath: string, flags: string, mode?: number): Promise<CompositFsFileHandle>;
388
+ access(filePath: PathLike$1, mode?: number): Promise<void>;
389
+ stat(path: PathLike$1, opts?: {
390
+ bigint?: false;
391
+ }): Promise<nodeFs.Stats>;
392
+ stat(path: PathLike$1, opts: {
393
+ bigint: true;
394
+ }): Promise<nodeFs.BigIntStats>;
395
+ stat(path: PathLike$1, opts?: {
396
+ bigint?: boolean;
397
+ }): Promise<nodeFs.Stats | nodeFs.BigIntStats>;
398
+ lstat(path: PathLike$1, opts?: {
399
+ bigint?: false;
400
+ }): Promise<nodeFs.Stats>;
401
+ lstat(path: PathLike$1, opts: {
402
+ bigint: true;
403
+ }): Promise<nodeFs.BigIntStats>;
404
+ lstat(path: PathLike$1, opts?: {
405
+ bigint?: boolean;
406
+ }): Promise<nodeFs.Stats | nodeFs.BigIntStats>;
407
+ opendir(folderPath: nodeFs.PathLike, options?: nodeFs.OpenDirOptions): Promise<memfs_lib_node_types_misc_js.IDir>;
408
+ link(existingPath: PathLike$1, newPath: PathLike$1): Promise<void>;
409
+ mkdir(dirPath: PathLike$1, options?: nodeFs.MakeDirectoryOptions | nodeFs.Mode | null): Promise<void>;
410
+ readdir(path: PathLike$1, ...args: any[]): Promise<any>;
411
+ readlink(path: PathLike$1): Promise<any>;
412
+ unlink(path: PathLike$1): Promise<void>;
413
+ rename(oldPath: PathLike$1, newPath: PathLike$1): Promise<void>;
414
+ rmdir(path: PathLike$1, options?: nodeFs.RmDirOptions): Promise<void>;
415
+ symlink(target: PathLike$1, path: PathLike$1, type?: string | null): Promise<void>;
416
+ lookup(filePath: string): Promise<number>;
417
+ close(fh: CompositFsFileHandle): Promise<void>;
418
+ dataSync(fh: CompositFsFileHandle): Promise<void>;
419
+ read(fh: CompositFsFileHandle, buffer: Buffer | Uint8Array, offset: number, length: number, position: number): Promise<TFileHandleReadResult>;
420
+ fchmod(fh: CompositFsFileHandle, mode: TMode): Promise<void>;
421
+ fchown(fh: CompositFsFileHandle, uid: number, gid: number): Promise<void>;
422
+ write(fh: CompositFsFileHandle, buffer: Buffer | ArrayBufferView | DataView, offset?: number, length?: number, position?: number): Promise<TFileHandleWriteResult>;
423
+ ftruncate(fh: CompositFsFileHandle, len?: number): Promise<void>;
424
+ resolvePath(fd: number): string;
425
+ fstat(fh: CompositFsFileHandle, options?: IStatOptions): Promise<IStats>;
426
+ futimes(fh: CompositFsFileHandle, atime: TTime, mtime: TTime): Promise<void>;
427
+ writev(fh: CompositFsFileHandle, buffers: ArrayBufferView[], position?: number | null): Promise<TFileHandleWritevResult>;
428
+ readv(fh: CompositFsFileHandle, buffers: ArrayBufferView[], position?: number | null): Promise<TFileHandleReadvResult>;
429
+ readFile(path: PathLike$1 | IFileHandle, options?: IReadFileOptions | string): Promise<TDataOut>;
430
+ writeFile(filePath: string, data: TData, options: IWriteFileOptions | string): Promise<void>;
431
+ }
432
+
433
+ /**
434
+ * FS utilized to provide pass-through access to the underlying filesystem
435
+ */
436
+ declare class PassThroughSubFs extends BaseCompositeSubFs {
437
+ private openFh;
438
+ private memFs;
439
+ private targetFs;
440
+ constructor({ parentFs, gitRoot, }: {
441
+ parentFs: CompositeFs;
442
+ gitRoot: string;
443
+ });
444
+ responsible(filePath: string): Promise<boolean>;
445
+ fileType(): number;
446
+ open(filePath: string, flags: string, mode?: number): Promise<CompositFsFileHandle>;
447
+ access(filePath: PathLike$1, mode?: number): Promise<void>;
448
+ stat(path: PathLike$1, opts?: {
449
+ bigint?: false;
450
+ }): Promise<nodeFs.Stats>;
451
+ stat(path: PathLike$1, opts: {
452
+ bigint: true;
453
+ }): Promise<nodeFs.BigIntStats>;
454
+ stat(path: PathLike$1, opts?: {
455
+ bigint?: boolean;
456
+ }): Promise<nodeFs.Stats | nodeFs.BigIntStats>;
457
+ lstat(path: PathLike$1, opts?: {
458
+ bigint?: false;
459
+ }): Promise<nodeFs.Stats>;
460
+ lstat(path: PathLike$1, opts: {
461
+ bigint: true;
462
+ }): Promise<nodeFs.BigIntStats>;
463
+ lstat(path: PathLike$1, opts?: {
464
+ bigint?: boolean;
465
+ }): Promise<nodeFs.Stats | nodeFs.BigIntStats>;
466
+ opendir(folderPath: nodeFs.PathLike, options?: nodeFs.OpenDirOptions): Promise<CompositeFsDir>;
467
+ link(existingPath: PathLike$1, newPath: PathLike$1): Promise<void>;
468
+ mkdir(dirPath: PathLike$1, options?: nodeFs.MakeDirectoryOptions | nodeFs.Mode | null): Promise<void>;
469
+ readdir(path: PathLike$1, ...args: any[]): Promise<any>;
470
+ readlink(path: PathLike$1, ...args: any[]): Promise<any>;
471
+ unlink(path: PathLike$1): Promise<void>;
472
+ rename(oldPath: PathLike$1, newPath: PathLike$1): Promise<void>;
473
+ rmdir(path: PathLike$1, options?: nodeFs.RmDirOptions): Promise<void>;
474
+ symlink(target: PathLike$1, path: PathLike$1, type?: string | null): Promise<void>;
475
+ lookup(filePath: string): Promise<number>;
476
+ close(fh: CompositFsFileHandle): Promise<void>;
477
+ dataSync(fh: CompositFsFileHandle): Promise<void>;
478
+ read(fh: CompositFsFileHandle, buffer: Buffer | Uint8Array, offset: number, length: number, position: number): Promise<TFileHandleReadResult>;
479
+ fchmod(fh: CompositFsFileHandle, mode: TMode): Promise<void>;
480
+ fchown(fh: CompositFsFileHandle, uid: number, gid: number): Promise<void>;
481
+ write(fh: CompositFsFileHandle, buffer: Buffer | ArrayBufferView | DataView, offset?: number, length?: number, position?: number): Promise<TFileHandleWriteResult>;
482
+ ftruncate(fh: CompositFsFileHandle, len?: number): Promise<void>;
483
+ resolvePath(fd: number): string;
484
+ fstat(fh: CompositFsFileHandle, options?: IStatOptions): Promise<IStats>;
485
+ futimes(fh: CompositFsFileHandle, atime: TTime, mtime: TTime): Promise<void>;
486
+ writev(fh: CompositFsFileHandle, buffers: ArrayBufferView[], position?: number | null): Promise<TFileHandleWritevResult>;
487
+ readv(fh: CompositFsFileHandle, buffers: ArrayBufferView[], position?: number | null): Promise<TFileHandleReadvResult>;
488
+ readFile(path: PathLike$1 | IFileHandle, options?: IReadFileOptions | string): Promise<TDataOut>;
489
+ writeFile(path: string, data: TData, options: IWriteFileOptions | string): Promise<void>;
490
+ }
491
+
492
+ type VirtualFile = {
493
+ type: 'file';
494
+ content?: string | Buffer;
495
+ oid?: string | undefined;
496
+ mode?: number;
497
+ size?: number;
498
+ } | {
499
+ type: 'directory';
500
+ content: string[];
501
+ oid?: string | undefined;
502
+ mode?: number;
503
+ };
504
+ interface VirtualFileArgs {
505
+ cacheFs: IFs;
506
+ filePath: string;
507
+ fs: CompositeFs;
508
+ gitRoot: string;
509
+ nodeFs?: any;
510
+ pathParams: any;
511
+ }
512
+ type VirtualFileDefinition = {
513
+ type: string;
514
+ getFile: (args: VirtualFileArgs) => Promise<VirtualFile | undefined>;
515
+ getStats: (args: VirtualFileArgs) => Promise<nodeFs.Stats>;
516
+ onFileChanged?: (args: VirtualFileArgs) => Promise<void>;
517
+ writeFile?: (args: VirtualFileArgs & {
518
+ content: Buffer | string;
519
+ }) => Promise<void>;
520
+ unlink?: (args: VirtualFileArgs) => Promise<void>;
521
+ rename: (args: VirtualFileArgs & {
522
+ newPath: string;
523
+ newPathParams: any;
524
+ }) => Promise<void>;
525
+ mkdir: (args: VirtualFileArgs & {
526
+ options?: nodeFs.MakeDirectoryOptions | nodeFs.Mode | null;
527
+ }) => Promise<void>;
528
+ };
529
+
530
+ /**
531
+ * 1. Path Structure Complexity
532
+ - Your nested .legit paths (e.g., /.legit/branch/my-branch-name/.legit/head) create redundancy
533
+ - Consider flattening: /.legit/branches/my-branch-name/head vs /.legit/branch/my-branch-name/.legit/head
534
+
535
+ Reason for the concept: i need to distinguish .legit files from other folders, therefore i wanted to introduce .letgit as a reserved folder independent from the depth or if repeated
536
+ Any problems you see with this?
537
+
538
+
539
+ 2. Write Operations on Historical Data
540
+ - Writing to /.legit/history/commits/... paths is conceptually problematic - commits are immutable
541
+ - Consider read-only for historical data, write-only for branch operations
542
+
543
+ 100% with you commits should be read only folders
544
+
545
+ 3. Branch Head Management
546
+ - Using git tags for head tracking (my-branch-name_legithead) pollutes the tag namespace
547
+ - Alternative: Use a dedicated ref namespace like refs/legit/heads/my-branch-name
548
+
549
+ Reason for the concept: i see the point with pollution of tag namespace BUT this will help existing tools to display the concept - i would start with tags and move refs to a later point in time
550
+ - what speaks against this?
551
+
552
+ 4. Conflict with Existing Virtual Files
553
+ - Current implementation has .status.gitbox, .branch.gitbox files
554
+ - Need strategy to migrate or maintain compatibility
555
+
556
+ Context: the hole thing is a non published poc so no need to migrate - just an implementation change needed
557
+
558
+ Architectural Challenges
559
+
560
+ 1. Performance
561
+ - Git operations (especially history traversal) can be expensive
562
+ - Current memfs caching might not scale for large repos
563
+ - Consider lazy loading and bounded caches
564
+
565
+ Future problem - lets not premature optimation or clear doubts?
566
+
567
+ 2. Consistency
568
+ - Multiple write paths (working copy, branches) need careful coordination
569
+ - Race conditions between git operations and filesystem operations
570
+
571
+ Lets postpone this for now
572
+
573
+ 3. Error Handling
574
+ - Git operations can fail (conflicts, invalid commits)
575
+ - Need clear error propagation through the FS layer
576
+
577
+ Lets discuss this deeper - dont understand the problem here.
578
+
579
+ Implementation Approach
580
+
581
+ Phase 1: Read-Only Git Views
582
+ // Start with immutable views
583
+ /.legit/status // Current git status
584
+ /.legit/commits/{sha}/path/to/file // Historical file access
585
+ /.legit/branches/ // List branches
586
+ /.legit/refs/heads/{branch}/path // Branch file access
587
+
588
+ Phase 2: Branch Operations
589
+ // Add write capabilities
590
+ /.legit/refs/heads/{branch}/.meta/head // Track branch head
591
+ /.legit/refs/heads/{branch}/path // Write to branch
592
+
593
+ Phase 3: Advanced Features
594
+ // Commit creation, branch management
595
+ /.legit/stage/ // Staging area
596
+ /.legit/commit // Trigger commit
597
+
598
+ Plan sounds good!
599
+
600
+
601
+ Next Steps
602
+
603
+ 1. Refine the path structure - Simplify and avoid nested .legit directories
604
+ - no please take my points into consideratio
605
+
606
+ 2. Create a proof-of-concept - Start with read-only status and commit access
607
+ - sounds good
608
+
609
+ 3. Build test infrastructure - Set up git fixture creation and FS testing utilities
610
+ - absolutly
611
+
612
+ 4. Implement incrementally - Phase approach to reduce complexity
613
+
614
+ alreight
615
+
616
+ The architecture supports your vision, but consider starting simpler and evolving based on real usage patterns.
617
+
618
+
619
+
620
+ /.legit/status // Git status info
621
+ /.legit/commits/{sha(0,1)}/{sha(2..20)}/path/to/file // Historical files
622
+ /.legit/branches/ // List branches
623
+ /.legit/branches/{name}/path/to/file // Branch files (read/write)
624
+ /.legit/branches/{name}/.legit/head // read/write of the head commit of the branch {name}
625
+ /.legit/branches/{name}/.legit/tip // read/write of the tip of the branch {name} - keeping this allows undo redo ops
626
+
627
+
628
+ */
629
+ declare class GitSubFs extends BaseCompositeSubFs implements CompositeSubFs {
630
+ private static readonly LEGIT_DIR;
631
+ private static pathRouter;
632
+ private memFs;
633
+ private openFh;
634
+ private virtualFiles;
635
+ private legitFileNames;
636
+ constructor({ parentFs, gitRoot, virtualFiles, }: {
637
+ parentFs: CompositeFs;
638
+ gitRoot: string;
639
+ virtualFiles?: VirtualFileDefinition[];
640
+ });
641
+ responsible(filePath: string): Promise<boolean>;
642
+ private isLegitPath;
643
+ private getRouteHandler;
644
+ /**
645
+ * Opens a virtual file from the Git-based virtual file system.
646
+ *
647
+ * This method retrieves a virtual file descriptor for the given `filePath`, checks if the file is writable
648
+ * based on its type and the provided `flags`, and ensures that write operations are only allowed for
649
+ * certain file types (e.g., "branch-file", "branch-head", "branch-tip"). It then loads the file's content
650
+ * into the in-memory file system (`memFs`), ensures parent directories exist, and finally opens the file,
651
+ * returning a `CompositFsFileHandle` for further operations.
652
+ *
653
+ * @param filePath - The path to the virtual file to open.
654
+ * @param flags - The file system flags indicating the desired open mode (e.g., "r" for read, "w" for write, "a" for append, "x" for exclusive creation).
655
+ * - "r": Open file for reading. An exception occurs if the file does not exist.
656
+ * - "w": Open file for writing. The file is created (if it does not exist) or truncated (if it exists).
657
+ * - "a": Open file for appending. The file is created if it does not exist.
658
+ * - "x": Exclusive flag. Used with "w" or "a" to fail if the file exists.
659
+ * - Combinations like "wx", "ax", etc., are also supported.
660
+ * @param mode - Optional file mode (permission and sticky bits) to use if creating a file.
661
+ * @returns A promise that resolves to a `CompositFsFileHandle` for the opened file.
662
+ * @throws If the file is not a virtual legit file, if write operations are not allowed for the file type,
663
+ * or if the file does not exist.
664
+ */
665
+ open(filePath: string, flags: string, mode?: number): Promise<CompositFsFileHandle>;
666
+ mkdir(path: PathLike, options?: nodeFs.MakeDirectoryOptions | nodeFs.Mode | null): Promise<void>;
667
+ access(path: PathLike, mode?: number): Promise<void>;
668
+ futimes(fh: CompositFsFileHandle, atime: TTime, mtime: TTime): Promise<void>;
669
+ fstat(fh: CompositFsFileHandle, options?: IStatOptions): Promise<IStats>;
670
+ ftruncate(fh: CompositFsFileHandle, len?: number): Promise<void>;
671
+ stat(path: PathLike, opts?: {
672
+ bigint?: false;
673
+ }): Promise<nodeFs.Stats>;
674
+ stat(path: PathLike, opts: {
675
+ bigint: true;
676
+ }): Promise<nodeFs.BigIntStats>;
677
+ stat(path: PathLike, opts?: {
678
+ bigint?: boolean;
679
+ }): Promise<nodeFs.Stats | nodeFs.BigIntStats>;
680
+ lstat(path: PathLike, opts?: {
681
+ bigint?: false;
682
+ }): Promise<nodeFs.Stats>;
683
+ lstat(path: PathLike, opts: {
684
+ bigint: true;
685
+ }): Promise<nodeFs.BigIntStats>;
686
+ lstat(path: PathLike, opts?: {
687
+ bigint?: boolean;
688
+ }): Promise<nodeFs.Stats | nodeFs.BigIntStats>;
689
+ readdir(path: PathLike, options?: (nodeFs.ObjectEncodingOptions & {
690
+ withFileTypes?: false | undefined;
691
+ recursive?: boolean | undefined;
692
+ }) | BufferEncoding | null): Promise<string[]>;
693
+ readdir(path: PathLike, options?: {
694
+ encoding: 'buffer';
695
+ withFileTypes?: false | undefined;
696
+ recursive?: boolean | undefined;
697
+ } | 'buffer' | null): Promise<Buffer[]>;
698
+ readdir(path: PathLike, options?: (nodeFs.ObjectEncodingOptions & {
699
+ withFileTypes?: false | undefined;
700
+ recursive?: boolean | undefined;
701
+ }) | BufferEncoding | null): Promise<string[] | Buffer[]>;
702
+ readdir(path: PathLike, options: nodeFs.ObjectEncodingOptions & {
703
+ withFileTypes: true;
704
+ recursive?: boolean | undefined;
705
+ }): Promise<nodeFs.Dirent[]>;
706
+ read(fh: CompositFsFileHandle, buffer: Buffer | Uint8Array, offset: number, length: number, position: number): Promise<TFileHandleReadResult>;
707
+ /**
708
+ *
709
+ * Writes (parts) of a buffer to a specific position in the file
710
+ *
711
+ * - a write leads to a new commit and on flush since the point in time a flush may occur may vary a read operation may
712
+ * not see changed done on the read lays.
713
+ *
714
+ *
715
+ * @param fh
716
+ * @param buffer
717
+ * @param offset
718
+ * @param length
719
+ * @param position
720
+ * @returns
721
+ */
722
+ write(fh: CompositFsFileHandle, buffer: Buffer | ArrayBufferView | DataView, offset?: number, length?: number, position?: number): Promise<TFileHandleWriteResult>;
723
+ close(fh: CompositFsFileHandle): Promise<void>;
724
+ dataSync(fh: CompositFsFileHandle): Promise<void>;
725
+ readFile(path: PathLike | IFileHandle, options?: IReadFileOptions | string): Promise<TDataOut>;
726
+ writeFile(path: string, data: TData, options: IWriteFileOptions | string): Promise<void>;
727
+ rename(oldPath: PathLike, newPath: PathLike): Promise<void>;
728
+ fchmod(fh: CompositFsFileHandle, mode: TMode): Promise<void>;
729
+ unlink(path: PathLike): Promise<void>;
730
+ fileType(): number;
731
+ }
732
+
733
+ type Operation = {
734
+ oid: string;
735
+ parentOids: string[];
736
+ message: string;
737
+ };
738
+ declare const gitBranchOperationsVirtualFile: VirtualFileDefinition;
739
+
740
+ declare function initLegitFs(storageFs: typeof nodeFs, gitRoot: string): Promise<CompositeFs>;
741
+ /**
742
+ * Creates and configures a LegitFs instance with CompositeFs, GitSubFs, HiddenFileSubFs, and EphemeralSubFs.
743
+ */
744
+ declare function openLegitFs(storageFs: typeof nodeFs, gitRoot: string): CompositeFs;
745
+
746
+ declare const createGitSyncService: ({ fs, gitRepoPath, originPrefix, corsProxy, user, password, }: {
747
+ fs: FsClient;
748
+ gitRepoPath: string;
749
+ originPrefix: string;
750
+ corsProxy?: string | undefined;
751
+ user: string;
752
+ password: string;
753
+ }) => {
754
+ clone: (url: string) => Promise<void>;
755
+ start: () => void;
756
+ stop: () => void;
757
+ };
758
+
759
+ type FileAccess = {
760
+ fileSave: typeof fileSave;
761
+ };
762
+ declare function getLegitFsAccess(legitFs: ReturnType<typeof openLegitFs>): Promise<FileAccess & {
763
+ openFile: (filePath: string) => Promise<FileWithHandle>;
764
+ }>;
765
+
766
+ type User = {
767
+ name: string;
768
+ email: string;
769
+ timestamp: number;
770
+ };
771
+
772
+ type HistoryItem = {
773
+ oid: string;
774
+ message: string;
775
+ parent: string[];
776
+ author: User;
777
+ };
778
+
779
+ export { CompositeFs, EphemeralSubFs, GitSubFs, HiddenFileSubFs, PassThroughSubFs, createGitSyncService, getLegitFsAccess, gitBranchOperationsVirtualFile, initLegitFs, openLegitFs };
780
+ export type { HistoryItem, Operation, User };