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.
Files changed (34) hide show
  1. package/.claude/settings.local.json +2 -1
  2. package/index.d.ts +42 -1
  3. package/misc/dist/getSecret.ts.cache +2 -2
  4. package/misc/dist/strings.ts.cache +2 -2
  5. package/misc/dist/yaml.ts.cache +2 -2
  6. package/misc/dist/yamlBase.ts.cache +2 -2
  7. package/misc/https/dist/certs.ts.cache +2 -2
  8. package/misc/https/dist/persistentLocalStorage.ts.cache +2 -2
  9. package/package.json +2 -2
  10. package/storage/BulkDatabase2/dist/BulkDatabaseBase.ts.cache +2 -2
  11. package/storage/BulkDatabase2/dist/BulkDatabaseFormat.ts.cache +2 -2
  12. package/storage/BulkDatabase2/dist/BulkDatabaseMerge.ts.cache +2 -2
  13. package/storage/BulkDatabase2/dist/BulkDatabaseReader.ts.cache +2 -2
  14. package/storage/BulkDatabase2/dist/LoadedIndex.ts.cache +2 -2
  15. package/storage/BulkDatabase2/dist/WriteOverlay.ts.cache +2 -2
  16. package/storage/BulkDatabase2/dist/blockCache.ts.cache +2 -2
  17. package/storage/BulkDatabase2/dist/mergeLock.ts.cache +2 -2
  18. package/storage/BulkDatabase2/dist/mergeMarkers.ts.cache +2 -2
  19. package/storage/BulkDatabase2/dist/streamLog.ts.cache +2 -2
  20. package/storage/BulkDatabase2/dist/syncClient.ts.cache +2 -2
  21. package/storage/dist/embeddingFormats.ts.cache +2 -2
  22. package/storage/proxydatabase/dist/Database.ts.cache +2 -2
  23. package/storage/proxydatabase/dist/ivfEmbeddingDatabase.ts.cache +123 -61
  24. package/storage/proxydatabase/dist/transactionSet.ts.cache +16 -4
  25. package/storage/remoteStorage/blobStore.d.ts +11 -0
  26. package/storage/remoteStorage/blobStore.ts +8 -3
  27. package/storage/remoteStorage/createArchives.d.ts +16 -0
  28. package/storage/remoteStorage/createArchives.ts +30 -2
  29. package/storage/remoteStorage/sourceWrapper.ts +1 -1
  30. package/storage/remoteStorage/storageController.d.ts +2 -0
  31. package/storage/remoteStorage/storageController.ts +9 -9
  32. package/storage/remoteStorage/storageServerState.d.ts +13 -1
  33. package/storage/remoteStorage/storageServerState.ts +64 -9
  34. 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 { ArchivesRemote } from "./ArchivesRemote";
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
- let remote = this.remote;
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
- let progress = bucket?.store.getSyncProgress?.();
336
- return {
337
- supportsChangesAfter: !bucket || !!bucket.store.getChangesAfter,
338
- remoteConfig: bucket?.routing,
339
- index: progress?.index,
340
- indexSources: progress?.sources,
341
- readerDiskLimit: progress?.readerDiskLimit,
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
- let progress = bucket?.store.getSyncProgress?.();
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.16:
1948
- version "1.2.16"
1949
- resolved "https://registry.yarnpkg.com/socket-function/-/socket-function-1.2.16.tgz#6ad7fc1971202d9768582b0212f086675fba61b5"
1950
- integrity sha512-o3GATr5Fa+496StsPWJIb0yytY/XRMZjJQ4cgb1LOQIfFv7uJUJ3NZtcldMeN/kOmqI0hBaMvhRLC3VHke9awA==
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"