sliftutils 1.7.10 → 1.7.11
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/examplestorage/exampleserver.ts +0 -2
- package/index.d.ts +290 -54
- package/misc/dist/environment.ts.cache +3 -3
- package/misc/dist/getSecret.ts.cache +139 -0
- package/misc/dist/strings.ts.cache +13 -0
- package/misc/dist/zip.ts.cache +9 -0
- package/misc/getSecret.ts +38 -16
- package/misc/https/cloudflareHelpers.d.ts +19 -0
- package/misc/https/cloudflareHelpers.ts +69 -0
- package/misc/https/dist/certs.ts.cache +115 -179
- package/misc/https/dist/cloudflareHelpers.ts.cache +68 -0
- package/misc/https/dist/dns.ts.cache +112 -100
- package/misc/https/dist/hostServer.ts.cache +130 -0
- package/misc/https/dist/httpsCerts.ts.cache +24 -5
- package/misc/https/dist/persistentLocalStorage.ts.cache +3 -2
- package/misc/https/dns.d.ts +41 -12
- package/misc/https/dns.ts +104 -101
- package/misc/https/hostServer.d.ts +0 -6
- package/misc/https/hostServer.ts +9 -5
- package/package.json +2 -2
- package/render-utils/dist/observer.tsx.cache +3 -2
- package/spec.txt +0 -90
- package/storage/ArchivesDisk.d.ts +2 -0
- package/storage/ArchivesDisk.ts +7 -3
- package/storage/BulkDatabase2/dist/BulkDatabaseBase.ts.cache +1242 -0
- package/storage/BulkDatabase2/dist/BulkDatabaseFormat.ts.cache +513 -0
- package/storage/BulkDatabase2/dist/BulkDatabaseMerge.ts.cache +352 -0
- package/storage/BulkDatabase2/dist/BulkDatabaseReader.ts.cache +306 -0
- package/storage/BulkDatabase2/dist/LoadedIndex.ts.cache +435 -0
- package/storage/BulkDatabase2/dist/WriteOverlay.ts.cache +58 -0
- package/storage/BulkDatabase2/dist/blockCache.ts.cache +179 -0
- package/storage/BulkDatabase2/dist/mergeLock.ts.cache +149 -0
- package/storage/BulkDatabase2/dist/mergeMarkers.ts.cache +101 -0
- package/storage/BulkDatabase2/dist/streamLog.ts.cache +227 -0
- package/storage/BulkDatabase2/dist/syncClient.ts.cache +104 -0
- package/storage/IArchives.d.ts +47 -15
- package/storage/IArchives.ts +86 -31
- package/storage/backblaze.d.ts +15 -0
- package/storage/backblaze.ts +199 -79
- package/storage/dist/ArchivesDisk.ts.cache +373 -0
- package/storage/dist/FileFolderAPI.tsx.cache +508 -65
- package/storage/dist/IArchives.ts.cache +44 -0
- package/storage/dist/IndexedDBFileFolderAPI.ts.cache +8 -2
- package/storage/dist/JSONStorage.ts.cache +6 -2
- package/storage/dist/PendingManager.tsx.cache +1 -1
- package/storage/dist/TransactionStorage.ts.cache +231 -92
- package/storage/dist/backblaze.ts.cache +797 -0
- package/storage/dist/fileSystemPointer.ts.cache +36 -3
- package/storage/dist/remoteFileStorage.ts.cache +495 -0
- package/storage/remoteStorage/ArchivesRemote.d.ts +5 -1
- package/storage/remoteStorage/ArchivesRemote.ts +28 -8
- package/storage/remoteStorage/ArchivesUrl.d.ts +2 -0
- package/storage/remoteStorage/ArchivesUrl.ts +16 -4
- package/storage/remoteStorage/blobStore.d.ts +52 -3
- package/storage/remoteStorage/blobStore.ts +414 -101
- package/storage/remoteStorage/createArchives.d.ts +31 -10
- package/storage/remoteStorage/createArchives.ts +470 -253
- package/storage/remoteStorage/dist/ArchivesRemote.ts.cache +197 -0
- package/storage/remoteStorage/dist/ArchivesUrl.ts.cache +85 -0
- package/storage/remoteStorage/dist/accessPage.tsx.cache +222 -0
- package/storage/remoteStorage/dist/blobStore.ts.cache +837 -0
- package/storage/remoteStorage/dist/cliArgs.ts.cache +16 -0
- package/storage/remoteStorage/dist/createArchives.ts.cache +610 -0
- package/storage/remoteStorage/dist/remoteConfig.ts.cache +206 -0
- package/storage/remoteStorage/dist/sourceWrapper.ts.cache +223 -0
- package/storage/remoteStorage/dist/storageController.ts.cache +500 -0
- package/storage/remoteStorage/dist/storageServer.ts.cache +106 -0
- package/storage/remoteStorage/dist/storageServerCli.ts.cache +39 -0
- package/storage/remoteStorage/dist/storageServerState.ts.cache +518 -0
- package/storage/remoteStorage/remoteConfig.d.ts +8 -0
- package/storage/remoteStorage/remoteConfig.ts +105 -5
- package/storage/remoteStorage/sourceWrapper.d.ts +41 -0
- package/storage/remoteStorage/sourceWrapper.ts +223 -0
- package/storage/remoteStorage/spec.md +31 -0
- package/storage/remoteStorage/storageController.d.ts +11 -0
- package/storage/remoteStorage/storageController.ts +109 -40
- package/storage/remoteStorage/storageServer.d.ts +0 -5
- package/storage/remoteStorage/storageServer.ts +17 -10
- package/storage/remoteStorage/storageServerCli.ts +0 -3
- package/storage/remoteStorage/storageServerState.d.ts +7 -1
- package/storage/remoteStorage/storageServerState.ts +230 -48
- package/testsite/server.ts +0 -2
- package/yarn.lock +11 -6
|
@@ -73,6 +73,14 @@ export class ArchivesRemote implements IArchives {
|
|
|
73
73
|
return `remoteStorage/${this.parsed.address}:${this.parsed.port}/${this.account}/${this.bucketName}`;
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
public isConnected(): boolean {
|
|
77
|
+
return SocketFunction.isNodeConnected(this.nodeId);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
public async ping(): Promise<void> {
|
|
81
|
+
await this.controller.ping();
|
|
82
|
+
}
|
|
83
|
+
|
|
76
84
|
private async authenticate(): Promise<void> {
|
|
77
85
|
await authenticateStorage({ address: this.parsed.address, port: this.parsed.port, nodeId: this.nodeId });
|
|
78
86
|
}
|
|
@@ -103,17 +111,24 @@ export class ArchivesRemote implements IArchives {
|
|
|
103
111
|
};
|
|
104
112
|
}
|
|
105
113
|
|
|
106
|
-
|
|
114
|
+
public async hasWriteAccess(): Promise<boolean> {
|
|
115
|
+
let state = await this.callAuthed(() => this.controller.getAccessState(this.account));
|
|
116
|
+
return !!state.hasAccess;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Registers our access request server-side (so an admin has a requestId to grant) and logs the
|
|
120
|
+
// grant instructions, at most once a minute
|
|
121
|
+
private async registerAccessRequest(): Promise<void> {
|
|
107
122
|
let requested = await this.callAuthed(() => this.controller.requestAccess(this.account));
|
|
108
123
|
if (Date.now() - this.lastDeniedLog > timeInMinute) {
|
|
109
124
|
this.lastDeniedLog = Date.now();
|
|
110
|
-
console.log(`No access to storage account ${JSON.stringify(this.account)} on ${this.parsed.address}:${this.parsed.port} (our machine ${requested.machineId}, ip ${requested.ip}).
|
|
125
|
+
console.log(`No access to storage account ${JSON.stringify(this.account)} on ${this.parsed.address}:${this.parsed.port} (our machine ${requested.machineId}, ip ${requested.ip}). See https://${this.parsed.address}:${this.parsed.port}/${this.account} - or grant it with: ${requested.grantAccessCommand}`);
|
|
111
126
|
}
|
|
112
|
-
await delay(ACCESS_RETRY_DELAY);
|
|
113
127
|
}
|
|
114
128
|
|
|
115
129
|
// Runs a call, authenticating (and re-authenticating after reconnects) and waiting for account
|
|
116
|
-
// access as needed
|
|
130
|
+
// access as needed. With waitForAccess false, denied calls throw immediately instead - but the
|
|
131
|
+
// access request is still registered (in the background), so the denial is grantable.
|
|
117
132
|
private async call<T>(fnc: () => Promise<T>): Promise<T> {
|
|
118
133
|
while (true) {
|
|
119
134
|
try {
|
|
@@ -124,8 +139,13 @@ export class ArchivesRemote implements IArchives {
|
|
|
124
139
|
await this.authenticate();
|
|
125
140
|
continue;
|
|
126
141
|
}
|
|
127
|
-
if (message.includes(STORAGE_ACCESS_DENIED)
|
|
128
|
-
|
|
142
|
+
if (message.includes(STORAGE_ACCESS_DENIED)) {
|
|
143
|
+
if (this.config.waitForAccess === false) {
|
|
144
|
+
void this.registerAccessRequest().catch(() => { });
|
|
145
|
+
throw e;
|
|
146
|
+
}
|
|
147
|
+
await this.registerAccessRequest();
|
|
148
|
+
await delay(ACCESS_RETRY_DELAY);
|
|
129
149
|
continue;
|
|
130
150
|
}
|
|
131
151
|
throw e;
|
|
@@ -137,9 +157,9 @@ export class ArchivesRemote implements IArchives {
|
|
|
137
157
|
let result = await this.get2(fileName, config);
|
|
138
158
|
return result && result.data || undefined;
|
|
139
159
|
}
|
|
140
|
-
public async get2(fileName: string, config?: { range?: { start: number; end: number } }): Promise<{ data: Buffer; writeTime: number } | undefined> {
|
|
160
|
+
public async get2(fileName: string, config?: { range?: { start: number; end: number } }): Promise<{ data: Buffer; writeTime: number; size: number } | undefined> {
|
|
141
161
|
let result = await this.call(() => this.controller.get2(this.account, this.bucketName, fileName, config?.range));
|
|
142
|
-
return result && { data: Buffer.from(result.data), writeTime: result.writeTime } || undefined;
|
|
162
|
+
return result && { data: Buffer.from(result.data), writeTime: result.writeTime, size: result.size } || undefined;
|
|
143
163
|
}
|
|
144
164
|
public async set(fileName: string, data: Buffer, config?: { lastModified?: number }): Promise<void> {
|
|
145
165
|
await this.call(() => this.controller.set(this.account, this.bucketName, fileName, data, config?.lastModified));
|
|
@@ -20,6 +20,7 @@ export declare class ArchivesUrl implements IArchives {
|
|
|
20
20
|
}): Promise<{
|
|
21
21
|
data: Buffer;
|
|
22
22
|
writeTime: number;
|
|
23
|
+
size: number;
|
|
23
24
|
} | undefined>;
|
|
24
25
|
getInfo(fileName: string): Promise<{
|
|
25
26
|
writeTime: number;
|
|
@@ -43,4 +44,5 @@ export declare class ArchivesUrl implements IArchives {
|
|
|
43
44
|
}): Promise<ArchiveFileInfo[]>;
|
|
44
45
|
getURL(path: string): Promise<string>;
|
|
45
46
|
getConfig(): Promise<ArchivesConfig>;
|
|
47
|
+
hasWriteAccess(): Promise<boolean>;
|
|
46
48
|
}
|
|
@@ -23,7 +23,7 @@ export class ArchivesUrl implements IArchives {
|
|
|
23
23
|
let result = await this.get2(fileName, config);
|
|
24
24
|
return result && result.data || undefined;
|
|
25
25
|
}
|
|
26
|
-
public async get2(fileName: string, config?: { range?: { start: number; end: number } }): Promise<{ data: Buffer; writeTime: number } | undefined> {
|
|
26
|
+
public async get2(fileName: string, config?: { range?: { start: number; end: number } }): Promise<{ data: Buffer; writeTime: number; size: number } | undefined> {
|
|
27
27
|
let url = buildFileUrl(this.base, fileName);
|
|
28
28
|
let headers: Record<string, string> = {};
|
|
29
29
|
let range = config?.range;
|
|
@@ -36,17 +36,25 @@ export class ArchivesUrl implements IArchives {
|
|
|
36
36
|
throw new Error(`Read of ${url} failed: ${response.status} ${response.statusText}`);
|
|
37
37
|
}
|
|
38
38
|
let data = Buffer.from(await response.arrayBuffer());
|
|
39
|
-
//
|
|
39
|
+
// A real 206 only returns the requested slice, so the full size lives in Content-Range's total.
|
|
40
|
+
let size = data.length;
|
|
41
|
+
let contentRange = response.headers.get("content-range");
|
|
42
|
+
let total = contentRange && Number(contentRange.split("/")[1]);
|
|
43
|
+
if (total && Number.isFinite(total)) {
|
|
44
|
+
size = total;
|
|
45
|
+
}
|
|
46
|
+
// Servers that don't support ranges return the full file with a 200 (ours serves real
|
|
47
|
+
// 206s, but backblaze friendly URLs and proxies may not)
|
|
40
48
|
if (range && response.status === 200) {
|
|
41
49
|
data = data.subarray(Math.min(range.start, data.length), Math.min(range.end, data.length));
|
|
42
50
|
}
|
|
43
51
|
let lastModified = response.headers.get("last-modified");
|
|
44
52
|
let writeTime = lastModified && new Date(lastModified).getTime() || 0;
|
|
45
|
-
return { data, writeTime };
|
|
53
|
+
return { data, writeTime, size };
|
|
46
54
|
}
|
|
47
55
|
public async getInfo(fileName: string): Promise<{ writeTime: number; size: number } | undefined> {
|
|
48
56
|
let result = await this.get2(fileName);
|
|
49
|
-
return result && { writeTime: result.writeTime, size: result.
|
|
57
|
+
return result && { writeTime: result.writeTime, size: result.size } || undefined;
|
|
50
58
|
}
|
|
51
59
|
|
|
52
60
|
public async set(fileName: string, data: Buffer, config?: { lastModified?: number }): Promise<void> {
|
|
@@ -71,4 +79,8 @@ export class ArchivesUrl implements IArchives {
|
|
|
71
79
|
public async getConfig(): Promise<ArchivesConfig> {
|
|
72
80
|
return {};
|
|
73
81
|
}
|
|
82
|
+
|
|
83
|
+
public async hasWriteAccess(): Promise<boolean> {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
74
86
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
/// <reference types="node" />
|
|
3
|
-
import { ArchiveFileInfo, ArchivesSource, ArchivesSyncStatus } from "../IArchives";
|
|
3
|
+
import { ArchiveFileInfo, ArchivesSource, ArchivesSyncStatus, SyncActivity } from "../IArchives";
|
|
4
4
|
export declare const DEFAULT_FAST_WRITE_DELAY: number;
|
|
5
5
|
export type WriteConfig = {
|
|
6
6
|
fast?: boolean;
|
|
@@ -22,6 +22,7 @@ export type IBucketStore = {
|
|
|
22
22
|
}): Promise<{
|
|
23
23
|
data: Buffer;
|
|
24
24
|
writeTime: number;
|
|
25
|
+
size: number;
|
|
25
26
|
} | undefined>;
|
|
26
27
|
set(fileName: string, data: Buffer, config?: WriteConfig): Promise<void>;
|
|
27
28
|
del(fileName: string, config?: WriteConfig): Promise<void>;
|
|
@@ -35,6 +36,17 @@ export type IBucketStore = {
|
|
|
35
36
|
}): Promise<ArchiveFileInfo[]>;
|
|
36
37
|
getChangesAfter?(time: number): Promise<ArchiveFileInfo[]>;
|
|
37
38
|
getSyncStatus?(): Promise<ArchivesSyncStatus>;
|
|
39
|
+
getSyncProgress?(): {
|
|
40
|
+
index: {
|
|
41
|
+
fileCount: number;
|
|
42
|
+
byteCount: number;
|
|
43
|
+
};
|
|
44
|
+
syncing: SyncActivity[];
|
|
45
|
+
};
|
|
46
|
+
computeIndexTotals?(): Promise<{
|
|
47
|
+
fileCount: number;
|
|
48
|
+
byteCount: number;
|
|
49
|
+
}>;
|
|
38
50
|
startLargeUpload(): Promise<string>;
|
|
39
51
|
appendLargeUpload(id: string, data: Buffer): Promise<void>;
|
|
40
52
|
finishLargeUpload(id: string, key: string): Promise<void>;
|
|
@@ -46,10 +58,16 @@ export declare class BlobStore implements IBucketStore {
|
|
|
46
58
|
private config?;
|
|
47
59
|
constructor(folder: string, sources: ArchivesSource[], config?: {
|
|
48
60
|
onIndexChanged?: ((key: string) => void) | undefined;
|
|
61
|
+
readerDiskLimit?: number | undefined;
|
|
49
62
|
} | undefined);
|
|
50
63
|
private stopped;
|
|
51
64
|
private index;
|
|
52
65
|
private mem;
|
|
66
|
+
private indexFileCount;
|
|
67
|
+
private indexByteCount;
|
|
68
|
+
private sourceFileCounts;
|
|
69
|
+
private sourceByteCounts;
|
|
70
|
+
private syncActivities;
|
|
53
71
|
private dirty;
|
|
54
72
|
private overlay;
|
|
55
73
|
private sourceStates;
|
|
@@ -60,11 +78,38 @@ export declare class BlobStore implements IBucketStore {
|
|
|
60
78
|
};
|
|
61
79
|
dispose(): Promise<void>;
|
|
62
80
|
private loadIndex;
|
|
81
|
+
private countEntry;
|
|
63
82
|
private setIndexEntry;
|
|
64
83
|
private deleteIndexEntry;
|
|
84
|
+
/** The cheap always-current totals plus any in-progress background synchronization. */
|
|
85
|
+
getSyncProgress(): {
|
|
86
|
+
index: {
|
|
87
|
+
fileCount: number;
|
|
88
|
+
byteCount: number;
|
|
89
|
+
};
|
|
90
|
+
sources: {
|
|
91
|
+
debugName: string;
|
|
92
|
+
fileCount: number;
|
|
93
|
+
byteCount: number;
|
|
94
|
+
}[];
|
|
95
|
+
readerDiskLimit?: number;
|
|
96
|
+
syncing: SyncActivity[];
|
|
97
|
+
};
|
|
98
|
+
/** Walks the whole index for exact totals - more expensive than getSyncProgress, but immune to
|
|
99
|
+
* any drift in the maintained counters (and loads the index first, so it's never cold zeros). */
|
|
100
|
+
computeIndexTotals(): Promise<{
|
|
101
|
+
fileCount: number;
|
|
102
|
+
byteCount: number;
|
|
103
|
+
sources: {
|
|
104
|
+
debugName: string;
|
|
105
|
+
fileCount: number;
|
|
106
|
+
byteCount: number;
|
|
107
|
+
}[];
|
|
108
|
+
}>;
|
|
65
109
|
private flushIndex;
|
|
66
110
|
private runSourceSync;
|
|
67
111
|
private scanSource;
|
|
112
|
+
private reconcileSource;
|
|
68
113
|
private applyScanned;
|
|
69
114
|
private pollChanges;
|
|
70
115
|
private copySourceFiles;
|
|
@@ -85,12 +130,13 @@ export declare class BlobStore implements IBucketStore {
|
|
|
85
130
|
}): Promise<{
|
|
86
131
|
data: Buffer;
|
|
87
132
|
writeTime: number;
|
|
133
|
+
size: number;
|
|
88
134
|
} | undefined>;
|
|
89
135
|
private cacheRead;
|
|
90
136
|
set(key: string, data: Buffer, config?: WriteConfig): Promise<void>;
|
|
91
|
-
private writeToSources;
|
|
92
137
|
del(key: string, config?: WriteConfig): Promise<void>;
|
|
93
|
-
private
|
|
138
|
+
private getWritableSources;
|
|
139
|
+
private writeToSources;
|
|
94
140
|
getInfo(key: string): Promise<{
|
|
95
141
|
writeTime: number;
|
|
96
142
|
size: number;
|
|
@@ -107,4 +153,7 @@ export declare class BlobStore implements IBucketStore {
|
|
|
107
153
|
finishLargeUpload(id: string, key: string): Promise<void>;
|
|
108
154
|
cancelLargeUpload(id: string): Promise<void>;
|
|
109
155
|
private flushOverlay;
|
|
156
|
+
private evicting;
|
|
157
|
+
private enforceDiskLimit;
|
|
158
|
+
private cleanupTombstones;
|
|
110
159
|
}
|