sliftutils 1.7.11 → 1.7.13
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/.claude/settings.local.json +2 -1
- package/index.d.ts +42 -1
- package/misc/dist/getSecret.ts.cache +2 -2
- package/misc/dist/strings.ts.cache +2 -2
- package/misc/dist/yaml.ts.cache +2 -2
- package/misc/dist/yamlBase.ts.cache +2 -2
- package/misc/https/dist/certs.ts.cache +2 -2
- package/misc/https/dist/persistentLocalStorage.ts.cache +2 -2
- package/package.json +2 -2
- package/storage/BulkDatabase2/dist/BulkDatabaseBase.ts.cache +2 -2
- package/storage/BulkDatabase2/dist/BulkDatabaseFormat.ts.cache +2 -2
- package/storage/BulkDatabase2/dist/BulkDatabaseMerge.ts.cache +2 -2
- package/storage/BulkDatabase2/dist/BulkDatabaseReader.ts.cache +2 -2
- package/storage/BulkDatabase2/dist/LoadedIndex.ts.cache +2 -2
- package/storage/BulkDatabase2/dist/WriteOverlay.ts.cache +2 -2
- package/storage/BulkDatabase2/dist/blockCache.ts.cache +2 -2
- package/storage/BulkDatabase2/dist/mergeLock.ts.cache +2 -2
- package/storage/BulkDatabase2/dist/mergeMarkers.ts.cache +2 -2
- package/storage/BulkDatabase2/dist/streamLog.ts.cache +2 -2
- package/storage/BulkDatabase2/dist/syncClient.ts.cache +2 -2
- package/storage/dist/embeddingFormats.ts.cache +2 -2
- package/storage/proxydatabase/dist/Database.ts.cache +2 -2
- package/storage/proxydatabase/dist/ivfEmbeddingDatabase.ts.cache +123 -61
- package/storage/proxydatabase/dist/transactionSet.ts.cache +16 -4
- package/storage/remoteStorage/blobStore.d.ts +11 -0
- package/storage/remoteStorage/blobStore.ts +8 -3
- package/storage/remoteStorage/createArchives.d.ts +16 -0
- package/storage/remoteStorage/createArchives.ts +30 -2
- package/storage/remoteStorage/sourceWrapper.ts +1 -1
- package/storage/remoteStorage/storageController.d.ts +2 -0
- package/storage/remoteStorage/storageController.ts +9 -9
- package/storage/remoteStorage/storageServerState.d.ts +13 -1
- package/storage/remoteStorage/storageServerState.ts +64 -9
- package/yarn.lock +4 -4
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
/// <reference types="node" />
|
|
3
3
|
import { IArchives, RemoteConfig, RemoteConfigBase, HostedConfig, BackblazeConfig, ArchiveFileInfo, ArchivesConfig, ArchivesSyncStatus } from "../IArchives";
|
|
4
|
+
import { ServerBucketInfo } from "./storageServerState";
|
|
4
5
|
export declare function createApiArchives(source: HostedConfig | BackblazeConfig): IArchives;
|
|
5
6
|
export declare class ArchivesChain implements IArchives {
|
|
6
7
|
private configured;
|
|
@@ -83,3 +84,18 @@ export declare class ArchivesChain implements IArchives {
|
|
|
83
84
|
dispose(): void;
|
|
84
85
|
}
|
|
85
86
|
export declare function createArchives(config: RemoteConfig | RemoteConfigBase): ArchivesChain;
|
|
87
|
+
/** Every bucket an account has on one storage server - active and inactive - with each bucket's
|
|
88
|
+
* configuration. One authenticated call (the normal trust system applies): no ArchivesChain, no
|
|
89
|
+
* synchronization, and inactive buckets on the server stay inactive. Any URL addressing the
|
|
90
|
+
* server works (a bucket routing URL, or just https://host:port). */
|
|
91
|
+
export declare function listServerBuckets(config: {
|
|
92
|
+
url: string;
|
|
93
|
+
account: string;
|
|
94
|
+
}): Promise<ServerBucketInfo[]>;
|
|
95
|
+
/** Live info for one bucket given its routing URL (getConfig: routing config, index totals, disk
|
|
96
|
+
* limit, in-progress synchronization). One authenticated call to that server - a light, safe
|
|
97
|
+
* alternative to instantiating an ArchivesChain, which would start synchronization machinery. */
|
|
98
|
+
export declare function getBucketInfo(config: {
|
|
99
|
+
url: string;
|
|
100
|
+
accountName?: string;
|
|
101
|
+
}): Promise<ArchivesConfig>;
|
|
@@ -11,9 +11,11 @@ import {
|
|
|
11
11
|
normalizeRemoteConfig, normalizeSource, parseRoutingData, serializeRemoteConfig,
|
|
12
12
|
getRoute, routeContains, parseVariableRoute,
|
|
13
13
|
} from "./remoteConfig";
|
|
14
|
-
import {
|
|
14
|
+
import { SocketFunction } from "socket-function/SocketFunction";
|
|
15
|
+
import { ArchivesRemote, parseStorageUrl, authenticateStorage } from "./ArchivesRemote";
|
|
15
16
|
import { ArchivesBackblaze } from "../backblaze";
|
|
16
|
-
import { getStorageServerConfigOptional, getLocalArchives } from "./storageServerState";
|
|
17
|
+
import { getStorageServerConfigOptional, getLocalArchives, ServerBucketInfo } from "./storageServerState";
|
|
18
|
+
import { RemoteStorageController, STORAGE_NOT_AUTHENTICATED } from "./storageController";
|
|
17
19
|
import { SourceWrapper, RETRY_START_DELAY, RETRY_MAX_DELAY, RETRY_GROWTH } from "./sourceWrapper";
|
|
18
20
|
|
|
19
21
|
// Turns a RemoteConfig into a usable IArchives (createArchives). Initialization is lazy: on the
|
|
@@ -610,3 +612,29 @@ export class ArchivesChain implements IArchives {
|
|
|
610
612
|
export function createArchives(config: RemoteConfig | RemoteConfigBase): ArchivesChain {
|
|
611
613
|
return new ArchivesChain(config);
|
|
612
614
|
}
|
|
615
|
+
|
|
616
|
+
/** Every bucket an account has on one storage server - active and inactive - with each bucket's
|
|
617
|
+
* configuration. One authenticated call (the normal trust system applies): no ArchivesChain, no
|
|
618
|
+
* synchronization, and inactive buckets on the server stay inactive. Any URL addressing the
|
|
619
|
+
* server works (a bucket routing URL, or just https://host:port). */
|
|
620
|
+
export async function listServerBuckets(config: { url: string; account: string }): Promise<ServerBucketInfo[]> {
|
|
621
|
+
SocketFunction.ENABLE_CLIENT_MODE = true;
|
|
622
|
+
let parsed = parseStorageUrl(config.url);
|
|
623
|
+
let nodeId = SocketFunction.connect({ address: parsed.address, port: parsed.port });
|
|
624
|
+
let controller = RemoteStorageController.nodes[nodeId];
|
|
625
|
+
try {
|
|
626
|
+
return await controller.listBuckets(config.account);
|
|
627
|
+
} catch (e) {
|
|
628
|
+
if (!String((e as Error).stack ?? e).includes(STORAGE_NOT_AUTHENTICATED)) throw e;
|
|
629
|
+
await authenticateStorage({ address: parsed.address, port: parsed.port, nodeId });
|
|
630
|
+
return await controller.listBuckets(config.account);
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
/** Live info for one bucket given its routing URL (getConfig: routing config, index totals, disk
|
|
635
|
+
* limit, in-progress synchronization). One authenticated call to that server - a light, safe
|
|
636
|
+
* alternative to instantiating an ArchivesChain, which would start synchronization machinery. */
|
|
637
|
+
export async function getBucketInfo(config: { url: string; accountName?: string }): Promise<ArchivesConfig> {
|
|
638
|
+
let remote = new ArchivesRemote({ url: config.url, accountName: config.accountName, waitForAccess: false });
|
|
639
|
+
return await remote.getConfig();
|
|
640
|
+
}
|
|
@@ -165,7 +165,7 @@ export class SourceWrapper {
|
|
|
165
165
|
/** Starts measuring this source's latency (for variable-shard target preference). Only hosted
|
|
166
166
|
* remotes are pinged; our own local server counts as 0, everything else as Infinity. */
|
|
167
167
|
public startPinging(): void {
|
|
168
|
-
|
|
168
|
+
const remote = this.remote;
|
|
169
169
|
if (!remote || this.pingTimer || this.disposed) return;
|
|
170
170
|
let measure = async () => {
|
|
171
171
|
let start = Date.now();
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
/// <reference types="node" />
|
|
3
3
|
import { ArchiveFileInfo, ArchivesConfig, ArchivesSyncStatus } from "../IArchives";
|
|
4
|
+
import { ServerBucketInfo } from "./storageServerState";
|
|
4
5
|
export declare const REMOTE_STORAGE_CLASS_GUID = "RemoteStorageController-b7e42a91";
|
|
5
6
|
export declare const STORAGE_AUTH_PURPOSE = "remoteStorage-auth-1";
|
|
6
7
|
export declare const STORAGE_NOT_AUTHENTICATED = "REMOTE_STORAGE_NOT_AUTHENTICATED_cf2f7b1e";
|
|
@@ -71,6 +72,7 @@ export declare const RemoteStorageController: import("socket-function/SocketFunc
|
|
|
71
72
|
}) => Promise<ArchiveFileInfo[]>;
|
|
72
73
|
getChangesAfter: (account: string, bucketName: string, time: number) => Promise<ArchiveFileInfo[]>;
|
|
73
74
|
getArchivesConfig: (account: string, bucketName: string) => Promise<ArchivesConfig>;
|
|
75
|
+
listBuckets: (account: string) => Promise<ServerBucketInfo[]>;
|
|
74
76
|
getIndexInfo: (account: string, bucketName: string) => Promise<{
|
|
75
77
|
fileCount: number;
|
|
76
78
|
byteCount: number;
|
|
@@ -13,6 +13,7 @@ import { ROUTING_FILE } from "./remoteConfig";
|
|
|
13
13
|
import {
|
|
14
14
|
getStorageServerConfig, getTrust, getRequests, getLoadedBucket, writeBucketFile,
|
|
15
15
|
deleteBucketFile, assertWritesAllowed, assertMutable, LoadedBucket,
|
|
16
|
+
getBucketConfig, listAccountBuckets, ServerBucketInfo,
|
|
16
17
|
} from "./storageServerState";
|
|
17
18
|
|
|
18
19
|
// The remote storage server's API. Authentication uses certs.ts machine identities: a client
|
|
@@ -332,15 +333,13 @@ class RemoteStorageControllerBase {
|
|
|
332
333
|
async getArchivesConfig(account: string, bucketName: string): Promise<ArchivesConfig> {
|
|
333
334
|
let bucket = await getBucket(account, bucketName);
|
|
334
335
|
// Missing buckets say true, matching what they become once created (the default store type)
|
|
335
|
-
|
|
336
|
-
return
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
syncing: progress?.syncing,
|
|
343
|
-
};
|
|
336
|
+
if (!bucket) return { supportsChangesAfter: true };
|
|
337
|
+
return getBucketConfig(bucket);
|
|
338
|
+
}
|
|
339
|
+
/** Every bucket the account has on this host - active and inactive - with each bucket's
|
|
340
|
+
* configuration. Inactive buckets stay inactive (their routing is read straight off disk). */
|
|
341
|
+
async listBuckets(account: string): Promise<ServerBucketInfo[]> {
|
|
342
|
+
return await listAccountBuckets(account);
|
|
344
343
|
}
|
|
345
344
|
/** Walks the whole index for exact totals (overall and per holding source) - more expensive
|
|
346
345
|
* than the maintained counters that getArchivesConfig returns, but immune to counter drift. */
|
|
@@ -522,6 +521,7 @@ export const RemoteStorageController = SocketFunction.register(
|
|
|
522
521
|
getChangesAfter: { hooks: [accountAccess] },
|
|
523
522
|
getArchivesConfig: { hooks: [accountAccess] },
|
|
524
523
|
getIndexInfo: { hooks: [accountAccess] },
|
|
524
|
+
listBuckets: { hooks: [accountAccess] },
|
|
525
525
|
getSyncStatus: { hooks: [accountAccess] },
|
|
526
526
|
startLargeFile: { hooks: [accountAccess] },
|
|
527
527
|
uploadPart: { hooks: [uploadAccess] },
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
/// <reference types="node" />
|
|
3
3
|
import { IBucketStore } from "./blobStore";
|
|
4
|
-
import { RemoteConfig, HostedConfig, IArchives } from "../IArchives";
|
|
4
|
+
import { RemoteConfig, HostedConfig, IArchives, ArchivesConfig } from "../IArchives";
|
|
5
5
|
import type { IStorage } from "../IStorage";
|
|
6
6
|
import type { AccessRequest, TrustRecord } from "./storageController";
|
|
7
7
|
export type StorageServerConfig = {
|
|
@@ -39,5 +39,17 @@ export declare function assertMutable(bucket: LoadedBucket, filePath: string, wr
|
|
|
39
39
|
export declare function writeBucketFile(account: string, bucketName: string, filePath: string, data: Buffer, config?: {
|
|
40
40
|
lastModified?: number;
|
|
41
41
|
}): Promise<void>;
|
|
42
|
+
export declare function getBucketConfig(bucket: LoadedBucket): ArchivesConfig;
|
|
43
|
+
export type ServerBucketInfo = {
|
|
44
|
+
bucketName: string;
|
|
45
|
+
active: boolean;
|
|
46
|
+
config?: ArchivesConfig;
|
|
47
|
+
error?: string;
|
|
48
|
+
};
|
|
49
|
+
/** Every bucket the account has on this server, active or not, each with its configuration.
|
|
50
|
+
* Inactive buckets are inspected straight from disk WITHOUT loading them - loading would start
|
|
51
|
+
* their synchronization, and old invalid buckets must stay inert (their parse error is reported
|
|
52
|
+
* instead). */
|
|
53
|
+
export declare function listAccountBuckets(account: string): Promise<ServerBucketInfo[]>;
|
|
42
54
|
export declare function deleteBucketFile(account: string, bucketName: string, filePath: string): Promise<void>;
|
|
43
55
|
export declare function getLocalArchives(account: string, bucketName: string): IArchives;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import path from "path";
|
|
2
|
+
import fs from "fs";
|
|
2
3
|
import { getFileStorageNested2 } from "../FileFolderAPI";
|
|
3
4
|
import { TransactionStorage } from "../TransactionStorage";
|
|
4
5
|
import { JSONStorage } from "../JSONStorage";
|
|
@@ -416,6 +417,67 @@ export async function writeBucketFile(account: string, bucketName: string, fileP
|
|
|
416
417
|
await loaded.store.set(filePath, data, { ...getWriteConfig(loaded, writeTime, route), lastModified: writeTime });
|
|
417
418
|
}
|
|
418
419
|
|
|
420
|
+
export function getBucketConfig(bucket: LoadedBucket): ArchivesConfig {
|
|
421
|
+
let progress = bucket.store.getSyncProgress?.();
|
|
422
|
+
return {
|
|
423
|
+
supportsChangesAfter: !!bucket.store.getChangesAfter,
|
|
424
|
+
remoteConfig: bucket.routing,
|
|
425
|
+
index: progress?.index,
|
|
426
|
+
indexSources: progress?.sources,
|
|
427
|
+
readerDiskLimit: progress?.readerDiskLimit,
|
|
428
|
+
syncing: progress?.syncing,
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
export type ServerBucketInfo = {
|
|
433
|
+
bucketName: string;
|
|
434
|
+
// Loaded in memory (created or accessed since startup), so its synchronization is running
|
|
435
|
+
active: boolean;
|
|
436
|
+
config?: ArchivesConfig;
|
|
437
|
+
error?: string;
|
|
438
|
+
};
|
|
439
|
+
|
|
440
|
+
/** Every bucket the account has on this server, active or not, each with its configuration.
|
|
441
|
+
* Inactive buckets are inspected straight from disk WITHOUT loading them - loading would start
|
|
442
|
+
* their synchronization, and old invalid buckets must stay inert (their parse error is reported
|
|
443
|
+
* instead). */
|
|
444
|
+
export async function listAccountBuckets(account: string): Promise<ServerBucketInfo[]> {
|
|
445
|
+
let accountFolder = path.join(getStorageServerConfig().folder, "buckets2", account);
|
|
446
|
+
let names: string[];
|
|
447
|
+
try {
|
|
448
|
+
names = await fs.promises.readdir(accountFolder);
|
|
449
|
+
} catch {
|
|
450
|
+
return [];
|
|
451
|
+
}
|
|
452
|
+
let results: ServerBucketInfo[] = [];
|
|
453
|
+
for (let bucketName of names) {
|
|
454
|
+
let loadedPromise = buckets.get(`${account}/${bucketName}`);
|
|
455
|
+
if (loadedPromise) {
|
|
456
|
+
try {
|
|
457
|
+
let loaded = await loadedPromise;
|
|
458
|
+
if (loaded) {
|
|
459
|
+
results.push({ bucketName, active: true, config: getBucketConfig(loaded) });
|
|
460
|
+
continue;
|
|
461
|
+
}
|
|
462
|
+
} catch (e) {
|
|
463
|
+
results.push({ bucketName, active: true, error: String((e as Error).stack ?? e).slice(0, 500) });
|
|
464
|
+
continue;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
try {
|
|
468
|
+
let data = await new ArchivesDisk(getBucketFolder(account, bucketName)).get(ROUTING_FILE);
|
|
469
|
+
if (!data) {
|
|
470
|
+
results.push({ bucketName, active: false, error: `No routing file (${ROUTING_FILE})` });
|
|
471
|
+
continue;
|
|
472
|
+
}
|
|
473
|
+
results.push({ bucketName, active: false, config: { remoteConfig: parseRoutingData(data) } });
|
|
474
|
+
} catch (e) {
|
|
475
|
+
results.push({ bucketName, active: false, error: String((e as Error).stack ?? e).slice(0, 500) });
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
return results;
|
|
479
|
+
}
|
|
480
|
+
|
|
419
481
|
export async function deleteBucketFile(account: string, bucketName: string, filePath: string): Promise<void> {
|
|
420
482
|
if (filePath === ROUTING_FILE) {
|
|
421
483
|
throw new Error(`The routing config ${JSON.stringify(ROUTING_FILE)} cannot be deleted (overwrite it to change the bucket's configuration)`);
|
|
@@ -498,15 +560,8 @@ class ArchivesLocalBucket implements IArchives {
|
|
|
498
560
|
public async getConfig(): Promise<ArchivesConfig> {
|
|
499
561
|
let bucket = await this.getBucket();
|
|
500
562
|
// Missing buckets say true, matching what they become once created (the default store type)
|
|
501
|
-
|
|
502
|
-
return
|
|
503
|
-
supportsChangesAfter: !bucket || !!bucket.store.getChangesAfter,
|
|
504
|
-
remoteConfig: bucket?.routing,
|
|
505
|
-
index: progress?.index,
|
|
506
|
-
indexSources: progress?.sources,
|
|
507
|
-
readerDiskLimit: progress?.readerDiskLimit,
|
|
508
|
-
syncing: progress?.syncing,
|
|
509
|
-
};
|
|
563
|
+
if (!bucket) return { supportsChangesAfter: true };
|
|
564
|
+
return getBucketConfig(bucket);
|
|
510
565
|
}
|
|
511
566
|
public async hasWriteAccess(): Promise<boolean> {
|
|
512
567
|
return true;
|
package/yarn.lock
CHANGED
|
@@ -1944,10 +1944,10 @@ slash@^3.0.0:
|
|
|
1944
1944
|
resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
|
|
1945
1945
|
integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
|
|
1946
1946
|
|
|
1947
|
-
socket-function@^1.2.
|
|
1948
|
-
version "1.2.
|
|
1949
|
-
resolved "https://registry.yarnpkg.com/socket-function/-/socket-function-1.2.
|
|
1950
|
-
integrity sha512-
|
|
1947
|
+
socket-function@^1.2.17:
|
|
1948
|
+
version "1.2.17"
|
|
1949
|
+
resolved "https://registry.yarnpkg.com/socket-function/-/socket-function-1.2.17.tgz#d6f28be00253d4a0a73dab6f0981c9af8e750a49"
|
|
1950
|
+
integrity sha512-HGQ8YmGwS5xLG03v9koa8l4PIPVIDmi177a/sdfa6KSGRkaxTWwinfakun4rddZNnlxb7Iu6NFSUl0TfTyv7/w==
|
|
1951
1951
|
dependencies:
|
|
1952
1952
|
"@types/pako" "^2.0.3"
|
|
1953
1953
|
"@types/ws" "^8.5.3"
|