sliftutils 1.2.37 → 1.2.38
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/index.d.ts +11 -0
- package/package.json +1 -1
- package/storage/FileFolderAPI.d.ts +3 -0
- package/storage/FileFolderAPI.tsx +32 -2
- package/storage/IStorage.d.ts +4 -0
- package/storage/IStorage.ts +3 -0
- package/storage/IndexedDBFileFolderAPI.ts +6 -0
- package/storage/PrivateFileSystemStorage.d.ts +4 -0
- package/storage/PrivateFileSystemStorage.ts +11 -0
package/index.d.ts
CHANGED
|
@@ -929,6 +929,9 @@ declare module "sliftutils/storage/FileFolderAPI" {
|
|
|
929
929
|
size: number;
|
|
930
930
|
lastModified: number;
|
|
931
931
|
arrayBuffer(): Promise<ArrayBuffer>;
|
|
932
|
+
slice(start: number, end: number): {
|
|
933
|
+
arrayBuffer(): Promise<ArrayBuffer>;
|
|
934
|
+
};
|
|
932
935
|
}>;
|
|
933
936
|
createWritable(config?: {
|
|
934
937
|
keepExistingData?: boolean;
|
|
@@ -1026,6 +1029,10 @@ declare module "sliftutils/storage/IStorage" {
|
|
|
1026
1029
|
};
|
|
1027
1030
|
export type IStorageRaw = {
|
|
1028
1031
|
get(key: string): Promise<Buffer | undefined>;
|
|
1032
|
+
getRange(key: string, config: {
|
|
1033
|
+
start: number;
|
|
1034
|
+
end: number;
|
|
1035
|
+
}): Promise<Buffer | undefined>;
|
|
1029
1036
|
append(key: string, value: Buffer): Promise<void>;
|
|
1030
1037
|
set(key: string, value: Buffer): Promise<void>;
|
|
1031
1038
|
remove(key: string): Promise<void>;
|
|
@@ -1117,6 +1124,10 @@ declare module "sliftutils/storage/PrivateFileSystemStorage" {
|
|
|
1117
1124
|
private getFileHandle;
|
|
1118
1125
|
private fileExists;
|
|
1119
1126
|
get(key: string): Promise<Buffer | undefined>;
|
|
1127
|
+
getRange(key: string, config: {
|
|
1128
|
+
start: number;
|
|
1129
|
+
end: number;
|
|
1130
|
+
}): Promise<Buffer | undefined>;
|
|
1120
1131
|
set(key: string, value: Buffer): Promise<void>;
|
|
1121
1132
|
append(key: string, value: Buffer): Promise<void>;
|
|
1122
1133
|
remove(key: string): Promise<void>;
|
package/package.json
CHANGED
|
@@ -40,6 +40,9 @@ type FileWrapper = {
|
|
|
40
40
|
size: number;
|
|
41
41
|
lastModified: number;
|
|
42
42
|
arrayBuffer(): Promise<ArrayBuffer>;
|
|
43
|
+
// Matches Blob.slice (which the native File object provides), so the browser
|
|
44
|
+
// implementation works vanilla. End is exclusive, both clamped to the file size.
|
|
45
|
+
slice(start: number, end: number): { arrayBuffer(): Promise<ArrayBuffer> };
|
|
43
46
|
}>;
|
|
44
47
|
createWritable(config?: { keepExistingData?: boolean }): Promise<{
|
|
45
48
|
seek(offset: number): Promise<void>;
|
|
@@ -99,13 +102,29 @@ class NodeJSFileHandleWrapper implements FileWrapper {
|
|
|
99
102
|
|
|
100
103
|
async getFile() {
|
|
101
104
|
const stats = await fs.promises.stat(this.filePath);
|
|
105
|
+
const filePath = this.filePath;
|
|
102
106
|
return {
|
|
103
107
|
size: stats.size,
|
|
104
108
|
lastModified: stats.mtimeMs,
|
|
105
109
|
arrayBuffer: async () => {
|
|
106
|
-
const buffer = await fs.promises.readFile(
|
|
110
|
+
const buffer = await fs.promises.readFile(filePath);
|
|
107
111
|
return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
|
|
108
|
-
}
|
|
112
|
+
},
|
|
113
|
+
slice: (start: number, end: number) => ({
|
|
114
|
+
arrayBuffer: async () => {
|
|
115
|
+
const clampedStart = Math.min(Math.max(start, 0), stats.size);
|
|
116
|
+
const clampedEnd = Math.min(Math.max(end, clampedStart), stats.size);
|
|
117
|
+
const length = clampedEnd - clampedStart;
|
|
118
|
+
const fileHandle = await fs.promises.open(filePath, "r");
|
|
119
|
+
try {
|
|
120
|
+
const buffer = Buffer.alloc(length);
|
|
121
|
+
await fileHandle.read(buffer, 0, length, clampedStart);
|
|
122
|
+
return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
|
|
123
|
+
} finally {
|
|
124
|
+
await fileHandle.close();
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
})
|
|
109
128
|
};
|
|
110
129
|
}
|
|
111
130
|
|
|
@@ -440,6 +459,17 @@ function wrapHandleFiles(handle: DirectoryWrapper): IStorageRaw {
|
|
|
440
459
|
}
|
|
441
460
|
},
|
|
442
461
|
|
|
462
|
+
async getRange(key: string, config: { start: number; end: number }): Promise<Buffer | undefined> {
|
|
463
|
+
try {
|
|
464
|
+
const file = await handle.getFileHandle(key);
|
|
465
|
+
const fileContent = await file.getFile();
|
|
466
|
+
const arrayBuffer = await fileContent.slice(config.start, config.end).arrayBuffer();
|
|
467
|
+
return Buffer.from(arrayBuffer);
|
|
468
|
+
} catch (error) {
|
|
469
|
+
return undefined;
|
|
470
|
+
}
|
|
471
|
+
},
|
|
472
|
+
|
|
443
473
|
async append(key: string, value: Buffer): Promise<void> {
|
|
444
474
|
await appendQueue(key)(async () => {
|
|
445
475
|
// NOTE: Interesting point. Chrome doesn't optimize this to be an append, and instead
|
package/storage/IStorage.d.ts
CHANGED
|
@@ -27,6 +27,10 @@ export type IStorage<T> = {
|
|
|
27
27
|
};
|
|
28
28
|
export type IStorageRaw = {
|
|
29
29
|
get(key: string): Promise<Buffer | undefined>;
|
|
30
|
+
getRange(key: string, config: {
|
|
31
|
+
start: number;
|
|
32
|
+
end: number;
|
|
33
|
+
}): Promise<Buffer | undefined>;
|
|
30
34
|
append(key: string, value: Buffer): Promise<void>;
|
|
31
35
|
set(key: string, value: Buffer): Promise<void>;
|
|
32
36
|
remove(key: string): Promise<void>;
|
package/storage/IStorage.ts
CHANGED
|
@@ -29,6 +29,9 @@ export type IStorage<T> = {
|
|
|
29
29
|
// (/ makes a folder). And there are even more rules, such as lengths per folder, etc, etc.
|
|
30
30
|
export type IStorageRaw = {
|
|
31
31
|
get(key: string): Promise<Buffer | undefined>;
|
|
32
|
+
// Reads bytes in the range [start, end) (end is exclusive, clamped to the file size).
|
|
33
|
+
// Returns undefined if the file doesn't exist.
|
|
34
|
+
getRange(key: string, config: { start: number; end: number }): Promise<Buffer | undefined>;
|
|
32
35
|
// May or may not be efficient in the underlying storage
|
|
33
36
|
append(key: string, value: Buffer): Promise<void>;
|
|
34
37
|
set(key: string, value: Buffer): Promise<void>;
|
|
@@ -44,6 +44,12 @@ class VirtualFileStorage implements FileStorage {
|
|
|
44
44
|
return badBuffer;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
async getRange(key: string, config: { start: number; end: number }): Promise<Buffer | undefined> {
|
|
48
|
+
const fullBuffer = await this.get(key);
|
|
49
|
+
if (!fullBuffer) return undefined;
|
|
50
|
+
return fullBuffer.subarray(config.start, config.end);
|
|
51
|
+
}
|
|
52
|
+
|
|
47
53
|
async append(key: string, value: Buffer): Promise<void> {
|
|
48
54
|
const store = this.getStore("readwrite");
|
|
49
55
|
const fullPath = this.id + key;
|
|
@@ -11,6 +11,10 @@ export declare class PrivateFileSystemStorage implements IStorageRaw {
|
|
|
11
11
|
private getFileHandle;
|
|
12
12
|
private fileExists;
|
|
13
13
|
get(key: string): Promise<Buffer | undefined>;
|
|
14
|
+
getRange(key: string, config: {
|
|
15
|
+
start: number;
|
|
16
|
+
end: number;
|
|
17
|
+
}): Promise<Buffer | undefined>;
|
|
14
18
|
set(key: string, value: Buffer): Promise<void>;
|
|
15
19
|
append(key: string, value: Buffer): Promise<void>;
|
|
16
20
|
remove(key: string): Promise<void>;
|
|
@@ -114,6 +114,17 @@ export class PrivateFileSystemStorage implements IStorageRaw {
|
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
+
public async getRange(key: string, config: { start: number; end: number }): Promise<Buffer | undefined> {
|
|
118
|
+
const fileHandle = await this.getFileHandle(key, false);
|
|
119
|
+
if (!fileHandle) {
|
|
120
|
+
return undefined;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const file = await fileHandle.getFile();
|
|
124
|
+
const arrayBuffer = await file.slice(config.start, config.end).arrayBuffer();
|
|
125
|
+
return Buffer.from(arrayBuffer);
|
|
126
|
+
}
|
|
127
|
+
|
|
117
128
|
public async set(key: string, value: Buffer): Promise<void> {
|
|
118
129
|
try {
|
|
119
130
|
const fileHandle = await this.getFileHandle(key, true);
|