sliftutils 1.7.10 → 1.7.12

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 (84) hide show
  1. package/.claude/settings.local.json +2 -1
  2. package/examplestorage/exampleserver.ts +0 -2
  3. package/index.d.ts +301 -54
  4. package/misc/dist/environment.ts.cache +3 -3
  5. package/misc/dist/getSecret.ts.cache +139 -0
  6. package/misc/dist/strings.ts.cache +13 -0
  7. package/misc/dist/zip.ts.cache +9 -0
  8. package/misc/getSecret.ts +38 -16
  9. package/misc/https/cloudflareHelpers.d.ts +19 -0
  10. package/misc/https/cloudflareHelpers.ts +69 -0
  11. package/misc/https/dist/certs.ts.cache +115 -179
  12. package/misc/https/dist/cloudflareHelpers.ts.cache +68 -0
  13. package/misc/https/dist/dns.ts.cache +112 -100
  14. package/misc/https/dist/hostServer.ts.cache +130 -0
  15. package/misc/https/dist/httpsCerts.ts.cache +24 -5
  16. package/misc/https/dist/persistentLocalStorage.ts.cache +3 -2
  17. package/misc/https/dns.d.ts +41 -12
  18. package/misc/https/dns.ts +104 -101
  19. package/misc/https/hostServer.d.ts +0 -6
  20. package/misc/https/hostServer.ts +9 -5
  21. package/package.json +2 -2
  22. package/render-utils/dist/observer.tsx.cache +3 -2
  23. package/spec.txt +0 -90
  24. package/storage/ArchivesDisk.d.ts +2 -0
  25. package/storage/ArchivesDisk.ts +7 -3
  26. package/storage/BulkDatabase2/dist/BulkDatabaseBase.ts.cache +1242 -0
  27. package/storage/BulkDatabase2/dist/BulkDatabaseFormat.ts.cache +513 -0
  28. package/storage/BulkDatabase2/dist/BulkDatabaseMerge.ts.cache +352 -0
  29. package/storage/BulkDatabase2/dist/BulkDatabaseReader.ts.cache +306 -0
  30. package/storage/BulkDatabase2/dist/LoadedIndex.ts.cache +435 -0
  31. package/storage/BulkDatabase2/dist/WriteOverlay.ts.cache +58 -0
  32. package/storage/BulkDatabase2/dist/blockCache.ts.cache +179 -0
  33. package/storage/BulkDatabase2/dist/mergeLock.ts.cache +149 -0
  34. package/storage/BulkDatabase2/dist/mergeMarkers.ts.cache +101 -0
  35. package/storage/BulkDatabase2/dist/streamLog.ts.cache +227 -0
  36. package/storage/BulkDatabase2/dist/syncClient.ts.cache +104 -0
  37. package/storage/IArchives.d.ts +47 -15
  38. package/storage/IArchives.ts +86 -31
  39. package/storage/backblaze.d.ts +15 -0
  40. package/storage/backblaze.ts +199 -79
  41. package/storage/dist/ArchivesDisk.ts.cache +373 -0
  42. package/storage/dist/FileFolderAPI.tsx.cache +508 -65
  43. package/storage/dist/IArchives.ts.cache +44 -0
  44. package/storage/dist/IndexedDBFileFolderAPI.ts.cache +8 -2
  45. package/storage/dist/JSONStorage.ts.cache +6 -2
  46. package/storage/dist/PendingManager.tsx.cache +1 -1
  47. package/storage/dist/TransactionStorage.ts.cache +231 -92
  48. package/storage/dist/backblaze.ts.cache +797 -0
  49. package/storage/dist/fileSystemPointer.ts.cache +36 -3
  50. package/storage/dist/remoteFileStorage.ts.cache +495 -0
  51. package/storage/remoteStorage/ArchivesRemote.d.ts +5 -1
  52. package/storage/remoteStorage/ArchivesRemote.ts +28 -8
  53. package/storage/remoteStorage/ArchivesUrl.d.ts +2 -0
  54. package/storage/remoteStorage/ArchivesUrl.ts +16 -4
  55. package/storage/remoteStorage/blobStore.d.ts +63 -3
  56. package/storage/remoteStorage/blobStore.ts +419 -101
  57. package/storage/remoteStorage/createArchives.d.ts +31 -10
  58. package/storage/remoteStorage/createArchives.ts +470 -253
  59. package/storage/remoteStorage/dist/ArchivesRemote.ts.cache +197 -0
  60. package/storage/remoteStorage/dist/ArchivesUrl.ts.cache +85 -0
  61. package/storage/remoteStorage/dist/accessPage.tsx.cache +222 -0
  62. package/storage/remoteStorage/dist/blobStore.ts.cache +837 -0
  63. package/storage/remoteStorage/dist/cliArgs.ts.cache +16 -0
  64. package/storage/remoteStorage/dist/createArchives.ts.cache +610 -0
  65. package/storage/remoteStorage/dist/remoteConfig.ts.cache +206 -0
  66. package/storage/remoteStorage/dist/sourceWrapper.ts.cache +223 -0
  67. package/storage/remoteStorage/dist/storageController.ts.cache +500 -0
  68. package/storage/remoteStorage/dist/storageServer.ts.cache +106 -0
  69. package/storage/remoteStorage/dist/storageServerCli.ts.cache +39 -0
  70. package/storage/remoteStorage/dist/storageServerState.ts.cache +518 -0
  71. package/storage/remoteStorage/remoteConfig.d.ts +8 -0
  72. package/storage/remoteStorage/remoteConfig.ts +105 -5
  73. package/storage/remoteStorage/sourceWrapper.d.ts +41 -0
  74. package/storage/remoteStorage/sourceWrapper.ts +223 -0
  75. package/storage/remoteStorage/spec.md +31 -0
  76. package/storage/remoteStorage/storageController.d.ts +11 -0
  77. package/storage/remoteStorage/storageController.ts +109 -40
  78. package/storage/remoteStorage/storageServer.d.ts +0 -5
  79. package/storage/remoteStorage/storageServer.ts +17 -10
  80. package/storage/remoteStorage/storageServerCli.ts +0 -3
  81. package/storage/remoteStorage/storageServerState.d.ts +7 -1
  82. package/storage/remoteStorage/storageServerState.ts +230 -48
  83. package/testsite/server.ts +0 -2
  84. 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
- private async onAccessDenied(): Promise<void> {
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}). Waiting for access to be granted. See https://${this.parsed.address}:${this.parsed.port}/${this.account} - or grant it with: ${requested.grantAccessCommand}`);
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 (unless waitForAccess is false, in which case denied calls throw).
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) && this.config.waitForAccess !== false) {
128
- await this.onAccessDenied();
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
- // Servers that don't support ranges (ours doesn't) return the full file with a 200
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.data.length } || undefined;
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,28 @@ 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
+ sources: {
45
+ debugName: string;
46
+ fileCount: number;
47
+ byteCount: number;
48
+ }[];
49
+ readerDiskLimit?: number;
50
+ syncing: SyncActivity[];
51
+ };
52
+ computeIndexTotals?(): Promise<{
53
+ fileCount: number;
54
+ byteCount: number;
55
+ sources: {
56
+ debugName: string;
57
+ fileCount: number;
58
+ byteCount: number;
59
+ }[];
60
+ }>;
38
61
  startLargeUpload(): Promise<string>;
39
62
  appendLargeUpload(id: string, data: Buffer): Promise<void>;
40
63
  finishLargeUpload(id: string, key: string): Promise<void>;
@@ -46,10 +69,16 @@ export declare class BlobStore implements IBucketStore {
46
69
  private config?;
47
70
  constructor(folder: string, sources: ArchivesSource[], config?: {
48
71
  onIndexChanged?: ((key: string) => void) | undefined;
72
+ readerDiskLimit?: number | undefined;
49
73
  } | undefined);
50
74
  private stopped;
51
75
  private index;
52
76
  private mem;
77
+ private indexFileCount;
78
+ private indexByteCount;
79
+ private sourceFileCounts;
80
+ private sourceByteCounts;
81
+ private syncActivities;
53
82
  private dirty;
54
83
  private overlay;
55
84
  private sourceStates;
@@ -60,11 +89,38 @@ export declare class BlobStore implements IBucketStore {
60
89
  };
61
90
  dispose(): Promise<void>;
62
91
  private loadIndex;
92
+ private countEntry;
63
93
  private setIndexEntry;
64
94
  private deleteIndexEntry;
95
+ /** The cheap always-current totals plus any in-progress background synchronization. */
96
+ getSyncProgress(): {
97
+ index: {
98
+ fileCount: number;
99
+ byteCount: number;
100
+ };
101
+ sources: {
102
+ debugName: string;
103
+ fileCount: number;
104
+ byteCount: number;
105
+ }[];
106
+ readerDiskLimit?: number;
107
+ syncing: SyncActivity[];
108
+ };
109
+ /** Walks the whole index for exact totals - more expensive than getSyncProgress, but immune to
110
+ * any drift in the maintained counters (and loads the index first, so it's never cold zeros). */
111
+ computeIndexTotals(): Promise<{
112
+ fileCount: number;
113
+ byteCount: number;
114
+ sources: {
115
+ debugName: string;
116
+ fileCount: number;
117
+ byteCount: number;
118
+ }[];
119
+ }>;
65
120
  private flushIndex;
66
121
  private runSourceSync;
67
122
  private scanSource;
123
+ private reconcileSource;
68
124
  private applyScanned;
69
125
  private pollChanges;
70
126
  private copySourceFiles;
@@ -85,12 +141,13 @@ export declare class BlobStore implements IBucketStore {
85
141
  }): Promise<{
86
142
  data: Buffer;
87
143
  writeTime: number;
144
+ size: number;
88
145
  } | undefined>;
89
146
  private cacheRead;
90
147
  set(key: string, data: Buffer, config?: WriteConfig): Promise<void>;
91
- private writeToSources;
92
148
  del(key: string, config?: WriteConfig): Promise<void>;
93
- private deleteFromSources;
149
+ private getWritableSources;
150
+ private writeToSources;
94
151
  getInfo(key: string): Promise<{
95
152
  writeTime: number;
96
153
  size: number;
@@ -107,4 +164,7 @@ export declare class BlobStore implements IBucketStore {
107
164
  finishLargeUpload(id: string, key: string): Promise<void>;
108
165
  cancelLargeUpload(id: string): Promise<void>;
109
166
  private flushOverlay;
167
+ private evicting;
168
+ private enforceDiskLimit;
169
+ private cleanupTombstones;
110
170
  }