sliftutils 1.7.54 → 1.7.56
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 +9 -3
- package/package.json +1 -1
- package/storage/IArchives.d.ts +1 -0
- package/storage/IArchives.ts +2 -0
- package/storage/dist/IArchives.ts.cache +2 -2
- package/storage/remoteStorage/blobStore.d.ts +2 -0
- package/storage/remoteStorage/blobStore.ts +23 -1
- package/storage/remoteStorage/createArchives.d.ts +4 -1
- package/storage/remoteStorage/createArchives.ts +46 -13
- package/storage/remoteStorage/dist/blobStore.ts.cache +28 -4
- package/storage/remoteStorage/dist/createArchives.ts.cache +48 -16
- package/storage/remoteStorage/dist/sourceWrapper.ts.cache +28 -14
- package/storage/remoteStorage/dist/storageController.ts.cache +5 -4
- package/storage/remoteStorage/dist/storageServerState.ts.cache +6 -4
- package/storage/remoteStorage/sourceWrapper.d.ts +2 -2
- package/storage/remoteStorage/sourceWrapper.ts +22 -10
- package/storage/remoteStorage/storageController.ts +3 -2
- package/storage/remoteStorage/storageServerState.ts +2 -0
|
@@ -37,11 +37,11 @@ export declare class SourceWrapper {
|
|
|
37
37
|
private pings;
|
|
38
38
|
private pingTimer;
|
|
39
39
|
private loggedConnected;
|
|
40
|
-
/** Starts measuring this source's latency
|
|
40
|
+
/** Starts measuring this source's latency, which decides which hosts reads and variable-shard writes prefer. Hosted remotes ping over their API connection; URL-only sources (read-only mode, backblaze without credentials) probe over plain HTTPS instead - the client NEEDS their latency too, or it cannot rank the hosts it reads from. Our own local server counts as 0; only sources with neither form stay Infinity. */
|
|
41
41
|
startPinging(): void;
|
|
42
42
|
/** Seeds the latency estimate before the first ping lands (e.g. from the initial routing fetch), so variable-shard picking has something immediately. Real pings take over from the first measurement on. */
|
|
43
43
|
seedLatency(ms: number): void;
|
|
44
|
-
/** Median of the recent pings. Sources
|
|
44
|
+
/** Median of the recent pings (API or URL-form, whichever this source measures). Sources with no measurements yet sort last (Infinity), except our own in-process server, which is the best possible target (0). */
|
|
45
45
|
getLatency(): number;
|
|
46
46
|
/** Writes always go through the API, so a permission error throws to the caller on every write (and access granted in the meantime is picked up automatically). */
|
|
47
47
|
write<T>(run: (archives: IArchives) => Promise<T>): Promise<T>;
|
|
@@ -204,16 +204,30 @@ export class SourceWrapper {
|
|
|
204
204
|
private pingTimer: ReturnType<typeof setInterval> | undefined;
|
|
205
205
|
private loggedConnected = false;
|
|
206
206
|
|
|
207
|
-
/** Starts measuring this source's latency
|
|
207
|
+
/** Starts measuring this source's latency, which decides which hosts reads and variable-shard writes prefer. Hosted remotes ping over their API connection; URL-only sources (read-only mode, backblaze without credentials) probe over plain HTTPS instead - the client NEEDS their latency too, or it cannot rank the hosts it reads from. Our own local server counts as 0; only sources with neither form stay Infinity. */
|
|
208
208
|
public startPinging(): void {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
// Latency only decides which shard a variable-shard write materializes into, and a source whose window has passed never receives writes - so measuring it is pointless traffic
|
|
209
|
+
if (this.pingTimer || this.disposed) return;
|
|
210
|
+
// A source whose window has passed never receives reads or writes - measuring it is pointless traffic
|
|
212
211
|
if (this.config.validWindow[1] <= Date.now()) return;
|
|
212
|
+
const remote = this.remote;
|
|
213
|
+
const url = this.url;
|
|
214
|
+
let probe: () => Promise<void>;
|
|
215
|
+
if (remote) {
|
|
216
|
+
probe = async () => {
|
|
217
|
+
await remote.ping();
|
|
218
|
+
};
|
|
219
|
+
} else if (url) {
|
|
220
|
+
// A 1-byte ranged read of the routing file transfers essentially nothing, and unlike an explicit OPTIONS request it needs no CORS preflight (backblaze's CORS rules only allow download operations) - so it works from the browser, which is exactly where URL-only mode runs
|
|
221
|
+
probe = async () => {
|
|
222
|
+
await url.getInfo(ROUTING_FILE);
|
|
223
|
+
};
|
|
224
|
+
} else {
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
213
227
|
let measure = async () => {
|
|
214
228
|
let start = Date.now();
|
|
215
229
|
try {
|
|
216
|
-
await
|
|
230
|
+
await probe();
|
|
217
231
|
} catch {
|
|
218
232
|
// A failed ping is also our earliest down-detection
|
|
219
233
|
this.noteFailure();
|
|
@@ -241,12 +255,10 @@ export class SourceWrapper {
|
|
|
241
255
|
this.pings.push(ms);
|
|
242
256
|
}
|
|
243
257
|
|
|
244
|
-
/** Median of the recent pings. Sources
|
|
258
|
+
/** Median of the recent pings (API or URL-form, whichever this source measures). Sources with no measurements yet sort last (Infinity), except our own in-process server, which is the best possible target (0). */
|
|
245
259
|
public getLatency(): number {
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
return Infinity;
|
|
249
|
-
}
|
|
260
|
+
// Our own in-process server: hosted (type remote), api present, but no remote connection - it IS us
|
|
261
|
+
if (!this.remote && this.config.type === "remote" && this.api) return 0;
|
|
250
262
|
if (!this.pings.length) return Infinity;
|
|
251
263
|
let sorted = [...this.pings];
|
|
252
264
|
sort(sorted, x => x);
|
|
@@ -59,10 +59,11 @@ export type AccessState = {
|
|
|
59
59
|
|
|
60
60
|
const sessions = new Map<string, string>();
|
|
61
61
|
|
|
62
|
+
// We must never serve anything that can be evaluated as code (html, js - and svg, which can embed <script> and runs it when visited as a document). Otherwise a user could host a file and, by visiting it, run it on our domain - giving them access to all of our keys and cookies. PDF stays: browser PDF viewers run any embedded PDF scripting in a sandbox with no access to the serving origin's cookies or DOM.
|
|
62
63
|
const CONTENT_TYPES: { [ext: string]: string } = {
|
|
63
|
-
|
|
64
|
+
css: "text/css; charset=utf-8", json: "application/json; charset=utf-8",
|
|
64
65
|
txt: "text/plain; charset=utf-8", png: "image/png", jpg: "image/jpeg", jpeg: "image/jpeg", gif: "image/gif",
|
|
65
|
-
|
|
66
|
+
webp: "image/webp", mp4: "video/mp4", webm: "video/webm",
|
|
66
67
|
mp3: "audio/mpeg", wav: "audio/wav", pdf: "application/pdf",
|
|
67
68
|
};
|
|
68
69
|
|
|
@@ -510,6 +510,7 @@ function buildBucket(account: string, bucketName: string, routing: RemoteConfig,
|
|
|
510
510
|
validWindow: spec.validWindow,
|
|
511
511
|
route: spec.route,
|
|
512
512
|
noFullSync: spec.noFullSync,
|
|
513
|
+
intermediate: spec.sourceConfig?.intermediate,
|
|
513
514
|
identity: sourceIdentity(spec.sourceConfig),
|
|
514
515
|
}));
|
|
515
516
|
store = new BlobStore(folder, sources, {
|
|
@@ -609,6 +610,7 @@ async function checkRoutingChanged(account: string, bucketName: string, config?:
|
|
|
609
610
|
validWindow: spec.validWindow,
|
|
610
611
|
route: spec.route,
|
|
611
612
|
noFullSync: spec.noFullSync,
|
|
613
|
+
intermediate: sourceConfig.intermediate,
|
|
612
614
|
create: () => createApiArchives(sourceConfig),
|
|
613
615
|
};
|
|
614
616
|
}));
|