sliftutils 1.7.9 → 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/bin/storageserver.js +4 -0
- package/{teststorage → examplestorage}/browser.tsx +18 -22
- package/{teststorage/server.ts → examplestorage/exampleserver.ts} +4 -6
- package/index.d.ts +770 -84
- 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 -8
- package/misc/https/dns.ts +104 -106
- package/misc/https/hostServer.d.ts +0 -3
- package/misc/https/hostServer.ts +12 -8
- package/package.json +3 -2
- package/render-utils/dist/observer.tsx.cache +3 -2
- package/spec.txt +0 -55
- package/storage/ArchivesDisk.d.ts +67 -0
- package/storage/ArchivesDisk.ts +369 -0
- 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 +127 -1
- package/storage/IArchives.ts +201 -1
- package/storage/backblaze.d.ts +29 -2
- package/storage/backblaze.ts +214 -78
- 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 +34 -18
- package/storage/remoteStorage/ArchivesRemote.ts +85 -65
- package/storage/remoteStorage/ArchivesUrl.d.ts +48 -0
- package/storage/remoteStorage/ArchivesUrl.ts +86 -0
- package/storage/remoteStorage/accessPage.tsx +111 -28
- package/storage/remoteStorage/blobStore.d.ts +128 -25
- package/storage/remoteStorage/blobStore.ts +757 -290
- package/storage/remoteStorage/cliArgs.d.ts +1 -0
- package/storage/remoteStorage/cliArgs.ts +9 -0
- package/storage/remoteStorage/createArchives.d.ts +85 -0
- package/storage/remoteStorage/createArchives.ts +612 -0
- 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/grantAccess.js +4 -0
- package/storage/remoteStorage/grantAccessCli.d.ts +1 -0
- package/storage/remoteStorage/grantAccessCli.ts +27 -0
- package/storage/remoteStorage/remoteConfig.d.ts +29 -0
- package/storage/remoteStorage/remoteConfig.ts +194 -0
- 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 +30 -27
- package/storage/remoteStorage/storageController.ts +297 -159
- package/storage/remoteStorage/storageServer.d.ts +6 -0
- package/storage/remoteStorage/storageServer.ts +88 -94
- package/storage/remoteStorage/storageServerCli.d.ts +1 -0
- package/storage/remoteStorage/storageServerCli.ts +38 -0
- package/storage/remoteStorage/storageServerState.d.ts +43 -0
- package/storage/remoteStorage/storageServerState.ts +540 -0
- package/testsite/server.ts +0 -2
- package/yarn.lock +11 -6
|
@@ -1,132 +1,126 @@
|
|
|
1
|
-
process.env.NODE_ENV = "production";
|
|
2
1
|
import os from "os";
|
|
3
2
|
import path from "path";
|
|
3
|
+
import fsp from "fs/promises";
|
|
4
4
|
import { SocketFunction } from "socket-function/SocketFunction";
|
|
5
5
|
import { getExternalIP } from "socket-function/src/networking";
|
|
6
6
|
import { RequireController } from "socket-function/require/RequireController";
|
|
7
7
|
import { hostServer } from "../../misc/https/hostServer";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import { BlobStore } from "./blobStore";
|
|
12
|
-
import {
|
|
13
|
-
RemoteStorageController, setStorageServerState,
|
|
14
|
-
AccessRequest, TrustRecord, BucketConfig,
|
|
15
|
-
} from "./storageController";
|
|
16
|
-
import { authenticateStorage } from "./ArchivesRemote";
|
|
8
|
+
import { RemoteStorageController } from "./storageController";
|
|
9
|
+
import { setStorageServerConfig, setWritesRejectedReason } from "./storageServerState";
|
|
10
|
+
import { parseStorageUrl } from "./ArchivesRemote";
|
|
17
11
|
// Import browser code, so it is allowed to be required by the client
|
|
18
12
|
import "./accessPage";
|
|
19
13
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
//
|
|
23
|
-
//
|
|
24
|
-
|
|
25
|
-
// --listAccess <ip> lists pending access requests from that IP (with requestIds)
|
|
26
|
-
// --grantAccess <requestId> trusts the machine from that request for the requested account
|
|
14
|
+
const DEFAULT_LOW_SPACE_THRESHOLD_BYTES = 25 * 1024 ** 3;
|
|
15
|
+
const DISK_SPACE_CHECK_INTERVAL_MS = 15 * 60 * 1000;
|
|
16
|
+
// Below this fraction of the warn threshold, we start rejecting writes so the server itself doesn't
|
|
17
|
+
// tip the machine into instability. Reads/deletes still work so users can free space.
|
|
18
|
+
const HARD_REJECT_FRACTION = 0.1;
|
|
27
19
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
process.on("uncaughtException", (error) => {
|
|
32
|
-
console.error("Uncaught exception:", error);
|
|
33
|
-
});
|
|
20
|
+
// The remote storage server, as a library function: consumers call hostStorageServer() from their
|
|
21
|
+
// own process to start hosting (or use the storageserver bin, see storageServerCli.ts). The
|
|
22
|
+
// grantAccess.js bootstrap (next to this file) is what the access page's shown SSH command points at.
|
|
34
23
|
|
|
35
|
-
|
|
36
|
-
//
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
24
|
+
export type HostStorageServerConfig = {
|
|
25
|
+
// Full URL of this storage server, e.g. "https://1-2-3-4.example.com:4444". The subdomain must
|
|
26
|
+
// be an ip domain - this machine's external IP with dashes, or 127-0-0-1 for local testing
|
|
27
|
+
// (see the validation in hostStorageServer). The domain and port are extracted from it (bucket
|
|
28
|
+
// routing URLs clients use look like
|
|
29
|
+
// https://1-2-3-4.example.com:4444/file/<account>/<bucketName>/storage/storagerouting.json).
|
|
30
|
+
url: string;
|
|
31
|
+
folder: string;
|
|
32
|
+
// When free space on the folder's drive drops below this many bytes, the server console.errors
|
|
33
|
+
// every 15 minutes. Below 10% of it, the server also rejects write operations (creating files,
|
|
34
|
+
// large uploads, new buckets) — reads, findInfo, and deletes still work so the user can free
|
|
35
|
+
// space. Default 25 GiB.
|
|
36
|
+
lowSpaceThresholdBytes?: number;
|
|
37
|
+
};
|
|
40
38
|
|
|
41
|
-
function
|
|
42
|
-
|
|
43
|
-
if (index < 0) return undefined;
|
|
44
|
-
let value = process.argv[index + 1];
|
|
45
|
-
if (!value || value.startsWith("--")) {
|
|
46
|
-
throw new Error(`Missing value for --${name}`);
|
|
47
|
-
}
|
|
48
|
-
return value;
|
|
39
|
+
function formatBytes(bytes: number): string {
|
|
40
|
+
return `${(bytes / 1024 ** 3).toFixed(2)} GiB`;
|
|
49
41
|
}
|
|
50
42
|
|
|
51
|
-
async function
|
|
52
|
-
let
|
|
53
|
-
let
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
console.log(`No access requests from ${config.listAccess}`);
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
console.log(`Access requests from ${config.listAccess}:`);
|
|
62
|
-
for (let request of requests) {
|
|
63
|
-
console.log(` --grantAccess ${request.requestId} (account ${request.account}, machine ${request.machineId}, requested ${new Date(request.time).toISOString()})`);
|
|
64
|
-
}
|
|
65
|
-
console.log(`Grant one with: ${getServerCommand(`--domain ${config.domain} --port ${config.port} --grantAccess <requestId>`)}`);
|
|
43
|
+
async function checkDiskSpace(config: { folder: string; threshold: number }): Promise<void> {
|
|
44
|
+
let { folder, threshold } = config;
|
|
45
|
+
let stats = await fsp.statfs(folder);
|
|
46
|
+
let free = Number(stats.bavail) * Number(stats.bsize);
|
|
47
|
+
let hardLimit = threshold * HARD_REJECT_FRACTION;
|
|
48
|
+
if (free >= threshold) {
|
|
49
|
+
setWritesRejectedReason(undefined);
|
|
66
50
|
return;
|
|
67
51
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
52
|
+
let under = threshold - free;
|
|
53
|
+
let rejecting = free < hardLimit;
|
|
54
|
+
console.error(
|
|
55
|
+
`Storage folder ${folder} is low on disk: ${formatBytes(free)} free`
|
|
56
|
+
+ ` (warn threshold ${formatBytes(threshold)}, ${formatBytes(under)} under;`
|
|
57
|
+
+ ` hard-reject threshold ${formatBytes(hardLimit)}${rejecting ? ", REACHED — write ops now rejected" : ""}).`
|
|
58
|
+
);
|
|
59
|
+
if (rejecting) {
|
|
60
|
+
setWritesRejectedReason(
|
|
61
|
+
`Storage server is out of disk space: only ${formatBytes(free)} free on ${folder}`
|
|
62
|
+
+ ` (hard-reject threshold ${formatBytes(hardLimit)}, warn threshold ${formatBytes(threshold)}).`
|
|
63
|
+
+ ` Write operations (create/append/new bucket) are rejected; reads, findInfo, and deletes still work — please free space.`
|
|
64
|
+
);
|
|
65
|
+
} else {
|
|
66
|
+
setWritesRejectedReason(undefined);
|
|
71
67
|
}
|
|
72
68
|
}
|
|
73
69
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
70
|
+
// Full path to the grantAccess CLI bootstrap that lives next to this file. The SSH command shown on
|
|
71
|
+
// the access page invokes it via `node <path> ...` (found through __dirname so consumers don't have
|
|
72
|
+
// to know where our source lives).
|
|
73
|
+
function getGrantAccessCliPath(): string {
|
|
74
|
+
return path.join(__dirname, "grantAccess.js");
|
|
75
|
+
}
|
|
78
76
|
|
|
79
|
-
|
|
80
|
-
let
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
77
|
+
export async function hostStorageServer(config: HostStorageServerConfig): Promise<void> {
|
|
78
|
+
let { url, folder } = config;
|
|
79
|
+
let { address: domain, port } = parseStorageUrl(url);
|
|
80
|
+
let rootDomain = domain.split(".").slice(-2).join(".");
|
|
81
|
+
let externalIP = (await getExternalIP()).trim();
|
|
82
|
+
// The subdomain must be an ip domain: the domain's A record points at exactly one machine, so a
|
|
83
|
+
// dynamic name would let the same script run on two servers and silently fight over it. Encoding
|
|
84
|
+
// the IP makes that mistake fail loudly - the wrong machine's domain just doesn't match.
|
|
85
|
+
let allowedDomains = [`127-0-0-1.${rootDomain}`, `${externalIP.replaceAll(".", "-")}.${rootDomain}`];
|
|
86
|
+
if (!allowedDomains.includes(domain)) {
|
|
87
|
+
throw new Error(`The storage server domain is based on the machine's IP (the subdomain is the IP with dots replaced by dashes). Expected ${allowedDomains.join(" or ")}, was ${domain}. Your external IP is ${externalIP}.`);
|
|
84
88
|
}
|
|
85
|
-
|
|
86
|
-
let
|
|
87
|
-
|
|
88
|
-
let cloudflareApiTokenPath = getArg("cloudflareApiTokenPath");
|
|
89
|
-
if (!cloudflareApiTokenPath) throw new Error(`--cloudflareApiTokenPath is required (path to a Cloudflare API token file, for HTTPS certs)`);
|
|
90
|
-
|
|
91
|
-
let root = await getFileStorageNested2(path.resolve(folder));
|
|
92
|
-
let system = await root.folder.getStorage("system");
|
|
93
|
-
let trust = new JSONStorage<TrustRecord>(new TransactionStorage(await system.folder.getStorage("trust"), "storageTrust"));
|
|
94
|
-
let requests = new JSONStorage<AccessRequest[]>(new TransactionStorage(await system.folder.getStorage("requests"), "storageRequests"));
|
|
95
|
-
let buckets = new JSONStorage<BucketConfig>(new TransactionStorage(await system.folder.getStorage("buckets"), "storageBuckets"));
|
|
96
|
-
|
|
97
|
-
setStorageServerState({
|
|
89
|
+
await fsp.mkdir(folder, { recursive: true });
|
|
90
|
+
let lowSpaceThreshold = config.lowSpaceThresholdBytes ?? DEFAULT_LOW_SPACE_THRESHOLD_BYTES;
|
|
91
|
+
setStorageServerConfig({
|
|
98
92
|
domain,
|
|
99
93
|
port,
|
|
100
|
-
rootDomain
|
|
101
|
-
sshTarget: `${os.userInfo().username}@${
|
|
102
|
-
serverCommand:
|
|
103
|
-
|
|
104
|
-
trust,
|
|
105
|
-
requests,
|
|
106
|
-
buckets,
|
|
94
|
+
rootDomain,
|
|
95
|
+
sshTarget: `${os.userInfo().username}@${externalIP}`,
|
|
96
|
+
serverCommand: `node ${getGrantAccessCliPath()} --url ${url}`,
|
|
97
|
+
folder: path.resolve(folder),
|
|
107
98
|
});
|
|
108
99
|
|
|
109
100
|
RequireController.allowAllNodeModules();
|
|
110
101
|
SocketFunction.expose(RequireController);
|
|
111
102
|
SocketFunction.expose(RemoteStorageController);
|
|
112
|
-
//
|
|
113
|
-
// name, see
|
|
103
|
+
// Every HTTP path goes through httpEntry: /file/<account>/<bucketName>/... serves public
|
|
104
|
+
// bucket files, everything else serves the access page (the path is the account name, see
|
|
105
|
+
// accessPage.tsx).
|
|
114
106
|
// A full URL, so the page resolves modules from the origin root even when served at
|
|
115
|
-
// /accountName (a relative require would resolve inside the account path)
|
|
116
|
-
SocketFunction.setDefaultHTTPCall(
|
|
107
|
+
// /accountName (a relative require would resolve inside the account path).
|
|
108
|
+
SocketFunction.setDefaultHTTPCall(RemoteStorageController, "httpEntry", {
|
|
117
109
|
requireCalls: [`https://${domain}:${port}/./storage/remoteStorage/accessPage.tsx`],
|
|
118
110
|
});
|
|
119
111
|
|
|
112
|
+
// Initial check so a server starting under-limit immediately rejects writes; then keep checking
|
|
113
|
+
// every 15 minutes so recovery (freed disk space) is picked up automatically.
|
|
114
|
+
await checkDiskSpace({ folder, threshold: lowSpaceThreshold });
|
|
115
|
+
let interval = setInterval(() => {
|
|
116
|
+
void checkDiskSpace({ folder, threshold: lowSpaceThreshold })
|
|
117
|
+
.catch(e => console.error(`Disk space check failed for ${folder}:`, e));
|
|
118
|
+
}, DISK_SPACE_CHECK_INTERVAL_MS);
|
|
119
|
+
(interval as { unref?: () => void }).unref?.();
|
|
120
|
+
|
|
120
121
|
await hostServer({
|
|
121
122
|
domain,
|
|
122
123
|
port,
|
|
123
|
-
cloudflareApiTokenPath,
|
|
124
124
|
setDNSRecord: true,
|
|
125
125
|
});
|
|
126
|
-
console.log(`Storage server running at https://${domain}:${port}`);
|
|
127
126
|
}
|
|
128
|
-
|
|
129
|
-
main().catch(e => {
|
|
130
|
-
console.error(e);
|
|
131
|
-
process.exit(1);
|
|
132
|
-
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
process.env.NODE_ENV = "production";
|
|
2
|
+
import { hostStorageServer } from "./storageServer";
|
|
3
|
+
import { getArg } from "./cliArgs";
|
|
4
|
+
|
|
5
|
+
// Hosts a storage server from the command line (via the storageserver bin, see package.json).
|
|
6
|
+
|
|
7
|
+
process.on("unhandledRejection", (error) => {
|
|
8
|
+
console.error("Unhandled promise rejection:", error);
|
|
9
|
+
});
|
|
10
|
+
process.on("uncaughtException", (error) => {
|
|
11
|
+
console.error("Uncaught exception:", error);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
async function main() {
|
|
15
|
+
let url = getArg("url");
|
|
16
|
+
if (!url) throw new Error(`--url is required (ex: --url https://storage.example.com:4444)`);
|
|
17
|
+
let folder = getArg("folder");
|
|
18
|
+
if (!folder) throw new Error(`--folder is required (the folder all data is stored in)`);
|
|
19
|
+
let lowSpaceThresholdBytes: number | undefined;
|
|
20
|
+
let lowSpaceThreshold = getArg("lowSpaceThreshold");
|
|
21
|
+
if (lowSpaceThreshold) {
|
|
22
|
+
lowSpaceThresholdBytes = +lowSpaceThreshold;
|
|
23
|
+
if (isNaN(lowSpaceThresholdBytes)) {
|
|
24
|
+
throw new Error(`--lowSpaceThreshold must be a number of bytes, was ${JSON.stringify(lowSpaceThreshold)}`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
await hostStorageServer({
|
|
29
|
+
url,
|
|
30
|
+
folder,
|
|
31
|
+
lowSpaceThresholdBytes,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
main().catch(e => {
|
|
36
|
+
console.error(e);
|
|
37
|
+
process.exit(1);
|
|
38
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
/// <reference types="node" />
|
|
3
|
+
import { IBucketStore } from "./blobStore";
|
|
4
|
+
import { RemoteConfig, HostedConfig, IArchives } from "../IArchives";
|
|
5
|
+
import type { IStorage } from "../IStorage";
|
|
6
|
+
import type { AccessRequest, TrustRecord } from "./storageController";
|
|
7
|
+
export type StorageServerConfig = {
|
|
8
|
+
domain: string;
|
|
9
|
+
port: number;
|
|
10
|
+
rootDomain: string;
|
|
11
|
+
sshTarget: string;
|
|
12
|
+
serverCommand: string;
|
|
13
|
+
folder: string;
|
|
14
|
+
};
|
|
15
|
+
export declare function setStorageServerConfig(value: StorageServerConfig): void;
|
|
16
|
+
export declare function getStorageServerConfig(): StorageServerConfig;
|
|
17
|
+
export declare function getStorageServerConfigOptional(): StorageServerConfig | undefined;
|
|
18
|
+
export declare function setWritesRejectedReason(reason: string | undefined): void;
|
|
19
|
+
export declare function getWritesRejectedReason(): string | undefined;
|
|
20
|
+
export declare function assertWritesAllowed(): void;
|
|
21
|
+
export declare function getTrust(): Promise<IStorage<TrustRecord>>;
|
|
22
|
+
export declare function getRequests(): Promise<IStorage<AccessRequest[]>>;
|
|
23
|
+
/** Makes machineIds the complete trust list for the account: machines not in the list lose access, machines already trusted keep their existing record, and missing ones are added. */
|
|
24
|
+
export declare function setTrustedMachines(config: {
|
|
25
|
+
account: string;
|
|
26
|
+
machineIds: string[];
|
|
27
|
+
}): Promise<void>;
|
|
28
|
+
export type LoadedBucket = {
|
|
29
|
+
account: string;
|
|
30
|
+
bucketName: string;
|
|
31
|
+
routing: RemoteConfig;
|
|
32
|
+
routingJSON: string;
|
|
33
|
+
selfEntries: HostedConfig[];
|
|
34
|
+
self: HostedConfig | undefined;
|
|
35
|
+
store: IBucketStore;
|
|
36
|
+
};
|
|
37
|
+
export declare function getLoadedBucket(account: string, bucketName: string): Promise<LoadedBucket | undefined>;
|
|
38
|
+
export declare function assertMutable(bucket: LoadedBucket, filePath: string, writeTime: number): Promise<void>;
|
|
39
|
+
export declare function writeBucketFile(account: string, bucketName: string, filePath: string, data: Buffer, config?: {
|
|
40
|
+
lastModified?: number;
|
|
41
|
+
}): Promise<void>;
|
|
42
|
+
export declare function deleteBucketFile(account: string, bucketName: string, filePath: string): Promise<void>;
|
|
43
|
+
export declare function getLocalArchives(account: string, bucketName: string): IArchives;
|