@cloudbitmaps/gcs 0.20.0 → 0.22.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudbitmaps/gcs",
3
- "version": "0.20.0",
3
+ "version": "0.22.0",
4
4
  "description": "Google Cloud Storage for CloudBitmaps",
5
5
  "keywords": [
6
6
  "cloudbitmaps",
@@ -49,7 +49,7 @@
49
49
  },
50
50
  "dependencies": {
51
51
  "@google-cloud/storage": "^7 || ^8",
52
- "@cloudbitmaps/core": "^0.20.0"
52
+ "@cloudbitmaps/core": "^0.22.0"
53
53
  },
54
54
  "devDependencies": {
55
55
  "@types/node": "^22.0.0",
@@ -1,37 +0,0 @@
1
- /**
2
- * Whether the bucket a driver names exists, asked when a request first answers 404.
3
- *
4
- * GCS answers a missing bucket and a missing object with the same status and reason (`404 notFound`), and a
5
- * GCS-compatible server may not even word them apart. Read as a missing object, a misnamed or deleted bucket would
6
- * answer every read as an empty segment. An object listing tells them apart: it names no object, so its 404 can only
7
- * be the bucket's.
8
- *
9
- * ```
10
- * a request answers 404 ──▶ confirm() ──▶ bucket seen before? ── yes ──▶ the 404 is an object's
11
- * │ no
12
- * ▼
13
- * list one object in the bucket
14
- * ├─ answered ──────────▶ remember the bucket; the 404 is an object's
15
- * ├─ 404 ───────────────▶ reject: the bucket does not exist
16
- * ├─ transient ─────────▶ reject: TransientError (asked again next time)
17
- * ├─ 403 ───────────────▶ remember it as unknowable; the 404 is an object's
18
- * └─ anything else ─────▶ the 404 is an object's (asked again next time)
19
- * ```
20
- *
21
- * A process pays one listing at most while its bucket exists, and concurrent 404s share it. An identity without
22
- * `storage.objects.list` is answered `403`, which says nothing about the bucket, so its 404s read as they always did.
23
- * Any other failure (a credential that could not be fetched, a 401) says nothing either, but may not last, so it is
24
- * not remembered. Once seen, the bucket is not asked about again: one deleted later in the process's life reads as an
25
- * empty store, as it did before this check, while every write to it fails.
26
- */
27
- import type { Storage } from '@google-cloud/storage';
28
- export declare class BucketPresence {
29
- private readonly storage;
30
- private readonly bucket;
31
- private settled;
32
- private asking;
33
- constructor(storage: Storage, bucket: string);
34
- /** Resolve when a 404 can be read as an object's; reject when the bucket does not exist or the listing failed in transit. */
35
- confirm(): Promise<void>;
36
- private ask;
37
- }
package/dist/crc32c.d.ts DELETED
@@ -1,5 +0,0 @@
1
- /**
2
- * CRC32C (Castagnoli) of some bytes, in the form GCS takes in an object's `crc32c` metadata: the 4-byte big-endian
3
- * value, base64-encoded. Computed here rather than through the SDK so it is the same on every major the driver accepts.
4
- */
5
- export declare function crc32cBase64(bytes: Uint8Array): string;
@@ -1,8 +0,0 @@
1
- import { type Deadline } from './read-timeout.js';
2
- /** Under a deadline, a retry is not sent with less than this left of it. */
3
- export declare const MIN_RETRY_MS = 10;
4
- /**
5
- * Call `download`, and again after each retryable fault, up to {@link RETRIES} more times, within `deadline` when there
6
- * is one; rethrow the last error, or the deadline's once it has passed.
7
- */
8
- export declare function retryDownload<T>(download: () => Promise<T>, deadline?: Deadline): Promise<T>;
@@ -1,46 +0,0 @@
1
- /**
2
- * Pure helpers for classifying Google Cloud Storage SDK errors (the transient class mirrors S3's).
3
- *
4
- * SDK-free + side-effect-free — they only read structural shapes off the thrown value (`err.code`,
5
- * `err.response.status`, `err.name`), so the GCS-specific translation is unit-testable without a live GCS or
6
- * an emulator, and without importing `@google-cloud/storage`. GCS's `ApiError` carries the HTTP status on
7
- * `.code` (a number); dropped/timed-out sockets surface as a Node error with a string `.code` (`ECONNRESET`,
8
- * `ETIMEDOUT`, …).
9
- */
10
- /**
11
- * A conditional `ifGenerationMatch: 0` write lost the write-once race — the object already existed, so GCS
12
- * returns **412 Precondition Failed**. Maps to `WriteConflictError` (caller OCC), never a blind retry.
13
- */
14
- export declare function isPreconditionFailed(err: unknown): boolean;
15
- /**
16
- * GCS asked the client to slow down: `429` (`rateLimitExceeded`) or `503` (`backendError`), which the SDK raises as an
17
- * `ApiError` with the status as a numeric `code`. GCS does not document that a throttled request was not applied, so
18
- * an upload sent again after one must still tell a landed first send apart.
19
- */
20
- export declare function isThrottle(err: unknown): boolean;
21
- /** The object / generation does not exist (GCS returns 404), in a bucket that does. */
22
- export declare function isNotFound(err: unknown): boolean;
23
- /**
24
- * The bucket itself does not exist: a wiring fault, never an absent object. Read as one, a misnamed or deleted bucket
25
- * would answer every read as an empty segment. GCS gives both the same status and reason (`404 notFound`), so only its
26
- * message tells them apart: on a download the message is the response body as it came, JSON or text, and elsewhere
27
- * the message and each `errors[].message` are GCS's own. A wording this does not match reads as an absent object.
28
- */
29
- export declare function isMissingBucket(err: unknown): boolean;
30
- /** A range request started past EOF (HTTP 416 Requested Range Not Satisfiable). */
31
- export declare function isInvalidRange(err: unknown): boolean;
32
- /** A download that failed in transit rather than with an HTTP status: one of {@link TRANSPORT_CODES}. */
33
- export declare function isTransportFault(err: unknown): boolean;
34
- /**
35
- * Whether the driver retries a failed download, which it does in the SDK's place: the statuses the SDK's predicate
36
- * retries (408, 429, 500, 502, 503 and 504, as a number or a string `code`), the connection faults it names in any
37
- * `errors[].reason`, and every {@link isTransportFault}, which the SDK retried before any response came. A 404, 412,
38
- * 416 or 403, a 501 or 505, a credentials or TLS failure, and every other answer reach the caller on the first attempt.
39
- */
40
- export declare function isDownloadRetryable(err: unknown): boolean;
41
- /**
42
- * A transient GCS fault that is safe to retry: throttling (429), a request timeout (408), any 5xx, or a dropped/timed-out socket.
43
- * Excludes the deterministic, caller-meaningful outcomes (412/404/416) — those must never be reclassified as
44
- * a blind transient (a retried doomed conditional write would just fail again, and mask an OCC conflict).
45
- */
46
- export declare function isTransient(err: unknown): boolean;
package/dist/keys.d.ts DELETED
@@ -1,31 +0,0 @@
1
- /**
2
- * Logical-ref → GCS object-name mapping for {@link GcsStorageDriver}.
3
- *
4
- * Pure string logic, no SDK dependency — unit-testable without GCS or an emulator. Uses the **same
5
- * backend-agnostic `.crbm` object-name scheme** as the S3 + LocalFs storage drivers
6
- * (`<prefix><ns>/segments/<segment>.<gen>.crbm`), so a segment reads identically whichever storage backend holds
7
- * it. The default (absent) namespace maps to `_default`, which cannot collide with a real namespace because a
8
- * caller's `_default` encodes to `%5Fdefault` while the sentinel is emitted literally.
9
- *
10
- * The storage-key layout is shared, not copied: `prefixPart` and the name encoders come from
11
- * `@cloudbitmaps/core/driver-kit`, so a segment written by one driver reads identically under another. Two
12
- * drivers disagreeing about how a name becomes a key would be a silent cross-driver incompatibility on the
13
- * same bucket, which is exactly the kind of thing a local copy drifts into.
14
- */
15
- import type { GenKey, SegmentRef } from '@cloudbitmaps/core/driver-kit';
16
- /** Validate a caller-supplied key prefix. The rule is shared with every other object store. */
17
- export { normalizeObjectPrefix as normalizeGcsPrefix } from '@cloudbitmaps/core/driver-kit';
18
- /**
19
- * The GCS object-name prefix shared by all of a segment's generations: `<prefix><ns>/segments/<segment>.`.
20
- * Used both as the `getFiles` prefix and as the string stripped by {@link parseGenerationFromName}.
21
- */
22
- export declare function segmentObjectPrefix(prefix: string | undefined, ref: SegmentRef): string;
23
- /** The full GCS object name of one `.crbm` generation: `<segmentPrefix><gen>.crbm`. */
24
- export declare function storageObjectName(prefix: string | undefined, key: GenKey): string;
25
- /**
26
- * Parse a generation number out of a full object name, given its segment prefix, or `null` if it doesn't
27
- * match. Canonical decimal only — no leading zeros (so `…s.07.crbm` can't alias `…s.7.crbm`) and within
28
- * safe-integer range. Also rejects a *different* segment whose name merely shares the prefix (its middle
29
- * isn't all digits).
30
- */
31
- export declare function parseGenerationFromName(segmentPrefix: string, objectName: string): number | null;
@@ -1,6 +0,0 @@
1
- import type { Storage } from '@google-cloud/storage';
2
- /**
3
- * A twin of `client` that sends each download once, or `client` itself when it is a test double whose retries are off.
4
- * `supplied`: the caller handed `client` in, rather than the backend building it.
5
- */
6
- export declare function downloadClient(client: Storage, supplied: boolean): Storage;
@@ -1,52 +0,0 @@
1
- /**
2
- * `readOnce` — read one object, or one range of it, in a single GET, with the response headers in hand.
3
- *
4
- * `file.download()` returns only the bytes. The headers carry what a caller needs alongside them — the object's
5
- * `generation` (the registry's version fence) and, on a ranged read, the object's total size in `Content-Range` — so
6
- * this reads through `createReadStream`, which announces the raw response before any data flows. Both come from the
7
- * same response as the bytes, so they describe one observation of the object.
8
- *
9
- * **Everything on the wire is untrusted.** The advertised `Content-Length` is checked against `maxBytes` before the
10
- * first byte is buffered, and the bytes are counted as they arrive, so a response that understates its length (or
11
- * omits it) still cannot make the caller hold more than `maxBytes`. The headers are returned as received; each caller
12
- * parses the ones it relies on strictly.
13
- *
14
- * **Every download stays off the SDK's shared connection pool.** When a download fails part-way — a body cut off, a
15
- * refused response, a timeout — the SDK destroys the HTTP agent the request went out on, to free its socket. By default
16
- * that is one keep-alive agent the whole process shares (teeny-request's, for every request with `forever: true`), so
17
- * every other request in flight on any client is reset with it, uploads included. {@link downloadFile} sets
18
- * `forever: false` on its own requests, through the SDK's request interceptors: they then go out on Node's global
19
- * agent, which the SDK never destroys, and on `@google-cloud/storage` 8.x a destroyed download closes its own socket
20
- * and nothing else. The cost: the global agent closes a connection idle for 5 seconds, where the SDK's pool keeps it,
21
- * so a read after a longer pause opens a new one; and it is shared with the process's other `http` and `https` code.
22
- */
23
- import type { Storage } from '@google-cloud/storage';
24
- import type { Deadline } from './read-timeout.js';
25
- type GcsFile = ReturnType<ReturnType<Storage['bucket']>['file']>;
26
- /** A handle on `name` for downloading: its requests stay off the SDK's shared agent. The client is not touched. */
27
- export declare function downloadFile(storage: Storage, bucket: string, name: string): GcsFile;
28
- export interface ObjectRead {
29
- /** The HTTP status of the response (200 for a whole object, 206 for a range). */
30
- readonly status: number;
31
- /** The response headers, lower-cased as Node delivers them. */
32
- readonly headers: Readonly<Record<string, string | string[] | undefined>>;
33
- /** The body, at most `maxBytes` long. */
34
- readonly bytes: Uint8Array;
35
- }
36
- /** The value of a header that must appear once, or `undefined` when it is absent, repeated or empty. */
37
- export declare function singleHeader(headers: ObjectRead['headers'], name: string): string | undefined;
38
- /**
39
- * GET `file` (with the SDK's `createReadStream` options), buffering at most `maxBytes`. `oversize` builds the error
40
- * thrown when the advertised or actual length passes the cap, so each caller reports it in its own vocabulary.
41
- * Transport and HTTP errors reject as the SDK raises them (a 404 carries `code: 404`).
42
- *
43
- * With a `deadline`, a read still unsettled when it passes rejects with its `ReadTimedOut`; one asked for after it has
44
- * passed is not sent. The deadline belongs to the whole driver read, so an attempt gets only what is left of it.
45
- */
46
- export declare function readOnce(file: GcsFile, options: {
47
- start?: number;
48
- end?: number;
49
- validation?: false;
50
- decompress?: false;
51
- }, maxBytes: number, oversize: (size: number | undefined) => Error, deadline?: Deadline): Promise<ObjectRead>;
52
- export {};
@@ -1,28 +0,0 @@
1
- /** Validate a caller's `readTimeoutMs`, defaulting it: an integer from 0 (no timeout) to {@link MAX_TIMER_MS}. */
2
- export declare function resolveReadTimeoutMs(value: unknown): number;
3
- /** A read the driver gave up on when its deadline passed. Coded `ETIMEDOUT`, as a timed-out connection is. */
4
- export declare class ReadTimedOut extends Error {
5
- readonly code = "ETIMEDOUT";
6
- constructor(read: string, ms: number, cause?: unknown);
7
- }
8
- /** One driver read's deadline: `ms` from when it is made. `read` names the read in the error, e.g. `tail read of s.3`. */
9
- export declare class Deadline {
10
- readonly ms: number;
11
- readonly read: string;
12
- private readonly endsAt;
13
- constructor(ms: number, read: string);
14
- /** What is left of it, in milliseconds: 0 once it has passed. */
15
- remaining(): number;
16
- /** The error a read fails with once this has passed; `cause` is the last attempt's own error, if one failed. */
17
- expired(cause?: unknown): ReadTimedOut;
18
- }
19
- /** The deadline a read made now runs under, or none when `ms` is 0 (no timeout). */
20
- export declare function startDeadline(ms: number, read: string): Deadline | undefined;
21
- /**
22
- * Make the request `send` starts, and settle with it, or with {@link ReadTimedOut} once `deadline` has passed; a
23
- * deadline already passed sends nothing. For a request the SDK cannot cancel: a metadata read is one callback-style
24
- * request that returns no handle to abort it, so at the deadline this stops waiting and the request runs on until it is
25
- * answered or its connection closes. The race keeps a handler on the request, so what it settles with then is dropped
26
- * rather than raised.
27
- */
28
- export declare function withDeadline<T>(send: () => Promise<T>, deadline: Deadline | undefined): Promise<T>;
@@ -1,89 +0,0 @@
1
- /**
2
- * `GcsRegistryDriver` — an {@link IRegistryDriver} over Google Cloud Storage.
3
- *
4
- * Lets a **GCS deployment run on one bucket alone** — storage `.crbm` generations and the registry in the same
5
- * place, with no second cloud involved.
6
- *
7
- * The protocol (an ABA-safe OCC token, the delete and its tombstone, the bounded retry, the key layout) lives once
8
- * in {@link ObjectStoreRegistry}; this file is only the I/O calls GCS makes. A delete removes a row for good, under
9
- * `ifGenerationMatch: <generation>`, when `conditionalDelete` is `true`. It is off by default, on the public endpoint too:
10
- * no run against real GCS has verified that the service applies the precondition to a delete, and fake-gcs-server
11
- * accepts it and ignores it, so CI cannot show it.
12
- *
13
- * **The atomic swap is offloaded to GCS's object preconditions.** `ifGenerationMatch: 0` is create-only
14
- * ("only if it does not exist") and `ifGenerationMatch: <generation>` is compare-and-swap — the same pair S3
15
- * spells `If-None-Match: *` / `If-Match: <etag>`. A lost race returns `412` → {@link WriteConflictError}. Each write
16
- * is one request sent once ({@link saveOnce}), so a `412` means another write got there first, never this one meeting
17
- * itself after a lost response. A transient failure reaches the caller as {@link TransientError}: the write may or may
18
- * not have landed, and the caller re-reads the row to learn where it stands.
19
- *
20
- * **The version fence is the object's `generation`, not its ETag**: GCS mutates the generation on every
21
- * overwrite and it is the value `ifGenerationMatch` compares, so it is the only correct fence here. (Note
22
- * the unrelated collision of vocabulary — a GCS *object generation* has nothing to do with a CloudBitmaps
23
- * `.crbm` *generation*.) Reads are strongly consistent, satisfying the registry's `strongRead` contract.
24
- *
25
- * **Deployment requirements** (a policy that violates these silently corrupts the registry):
26
- * - The principal needs `storage.objects.get`, `create`, `update`, `list` and, to remove rows, `delete` on the
27
- * bucket. Without `list`
28
- * the registry cannot enumerate, and a missing-object read may surface as `403` rather than `404`.
29
- * - **Do not apply an Object Lifecycle rule to the `registry/` prefix that deletes a live object** (one on
30
- * noncurrent versions only is safe), and do not enable a retention
31
- * policy that blocks overwrite or deletion; see {@link ObjectStoreRegistry}.
32
- * - Object versioning is neither required nor used; the driver always reads the live generation. A read is one
33
- * GET whose `x-goog-generation` header and body describe the same object, so a concurrent overwrite is simply
34
- * observed as the older or the newer row, never as a torn pair or a missing one.
35
- */
36
- import { ObjectStoreRegistry } from '@cloudbitmaps/core/driver-kit';
37
- import type { ObjectRegistryStore, ObjectRow } from '@cloudbitmaps/core/driver-kit';
38
- import type { Storage } from '@google-cloud/storage';
39
- export interface GcsRegistryDriverOptions {
40
- /** A constructed `@google-cloud/storage` `Storage` client (point `apiEndpoint` at fake-gcs-server locally). */
41
- readonly storage: Storage;
42
- /** The client the downloads go through; `storage` when absent (see `GcsStorageDriverOptions.readStorage`). */
43
- readonly readStorage?: Storage;
44
- /** Target bucket (must already exist). */
45
- readonly bucket: string;
46
- /** Optional object-name prefix under which all registry objects live (e.g. `cloudbitmaps/`). */
47
- readonly prefix?: string;
48
- /** Injected clock for `createdAt`/`updatedAt`; defaults to `Date.now`. */
49
- readonly now?: () => number;
50
- /**
51
- * Cut off a read of a registry row once it has run this long, in milliseconds, every attempt included; `0` (the
52
- * default) sets no timeout. Timed as the storage driver's reads are (see `GcsStorageDriverOptions.readTimeoutMs`);
53
- * the writes and listings are not timed.
54
- */
55
- readonly readTimeoutMs?: number;
56
- /**
57
- * Whether a delete removes a row for good, by an object delete sent with `ifGenerationMatch: <the generation it
58
- * read>`, rather than leaving a tombstone. Defaults to `false`, on the public endpoint too: whether real GCS applies
59
- * `ifGenerationMatch` to a delete has not been verified by a run against the service, and fake-gcs-server accepts the
60
- * precondition and ignores it, so CI cannot show it. Set `true` to remove rows for good.
61
- */
62
- readonly conditionalDelete?: boolean;
63
- }
64
- /** The calls {@link ObjectStoreRegistry} needs, in GCS's dialect. Exported for the tests that drive one directly. */
65
- export declare class GcsRegistryStore implements ObjectRegistryStore {
66
- private readonly storage;
67
- private readonly readStorage;
68
- private readonly bucket;
69
- private readonly readTimeoutMs;
70
- readonly conditionalDelete: boolean;
71
- readonly label = "GCS";
72
- private readonly presence;
73
- constructor(storage: Storage, readStorage: Storage, bucket: string, readTimeoutMs: number, conditionalDelete: boolean);
74
- /** A handle on one registry object. */
75
- private file;
76
- /** The same file handle on the download client, off the SDK's shared agent ({@link downloadFile}). */
77
- private downloadable;
78
- read(key: string): Promise<ObjectRow | null>;
79
- write(key: string, body: Uint8Array, expect: 'absent' | {
80
- version: string;
81
- }): Promise<void>;
82
- delete(key: string, expect: {
83
- version: string;
84
- }): Promise<void>;
85
- listKeys(prefix: string): AsyncIterable<string>;
86
- }
87
- export declare class GcsRegistryDriver extends ObjectStoreRegistry {
88
- constructor(options: GcsRegistryDriverOptions);
89
- }
@@ -1,18 +0,0 @@
1
- /**
2
- * Make an error the SDK raised safe to throw, or to keep as a `cause`: a copy of it with no credential and none of the
3
- * live transport.
4
- *
5
- * The SDK keeps the request it sent on the error (`response.request`, `config.headers`, the raw request line), and
6
- * through that request the HTTP agent it shares with every other call, whose sockets hold the raw text, bearer token
7
- * included, of requests still in flight. An application that logs the error or its cause chain would write a live
8
- * access token. The error is therefore replaced by a copy built from what it is: its prototype, name, message, stack,
9
- * code, status and other plain data; `response` reduced to its status; the request, agent, socket and config dropped.
10
- * Nothing live is ever changed, only read, and the copy is made from plain data alone, so no depth or size limit can
11
- * stop short of a secret. A credential header or header line in the plain data that is kept is redacted.
12
- */
13
- /**
14
- * `err` as it is safe to throw: a credential-free copy of an error that holds the SDK's request or response, and any
15
- * other value as it is (a timeout, a connection fault or an error of the driver's own holds no credential, and keeps
16
- * its identity).
17
- */
18
- export declare function scrubCredentials<T>(err: T): T;
@@ -1,5 +0,0 @@
1
- import type { CreateWriteStreamOptions, Storage } from '@google-cloud/storage';
2
- type GcsFile = ReturnType<ReturnType<Storage['bucket']>['file']>;
3
- /** Upload `body` to `file` in one request, sent once; resolves once GCS has stored it and its checksum matched. */
4
- export declare function saveOnce(file: GcsFile, body: Uint8Array, options: CreateWriteStreamOptions): Promise<void>;
5
- export {};
package/dist/storage.d.ts DELETED
@@ -1,106 +0,0 @@
1
- import type { BlobSink, GenKey, IStorageDriver, SegmentRef, StorageCaps, StorageDeleteOptions, TailRead } from '@cloudbitmaps/core/driver-kit';
2
- import type { Storage } from '@google-cloud/storage';
3
- /** What the throttle backoff waits on. */
4
- interface Sleeper {
5
- sleep(ms: number): Promise<void>;
6
- }
7
- export interface GcsStorageDriverOptions {
8
- /** A constructed `@google-cloud/storage` `Storage` client (point `apiEndpoint` at fake-gcs-server locally). */
9
- readonly storage: Storage;
10
- /**
11
- * The client the downloads go through; `storage` when absent. `GcsStorage` passes one built with the SDK's request
12
- * retries off (the read client built in its constructor), because a download the SDK retries can crash the process;
13
- * the driver retries a download itself instead.
14
- */
15
- readonly readStorage?: Storage;
16
- /** Target bucket (must already exist). */
17
- readonly bucket: string;
18
- /** Optional object-name prefix under which all objects live (e.g. `cloudbitmaps/`). */
19
- readonly prefix?: string;
20
- /** Largest object this driver will write/advertise (default = GCS's 5 TiB max). Must be a positive safe integer. */
21
- readonly maxObjectBytes?: number;
22
- /** Bytes at/under which a single non-resumable upload is used instead of a resumable stream (default 8 MiB).
23
- * Must be a positive safe integer. */
24
- readonly simpleUploadThresholdBytes?: number;
25
- /**
26
- * Cut off a read that has run this long, in milliseconds: a tail read (with the metadata read it falls back on for
27
- * an empty object) or a range read, every attempt and the backoff between them included. `0` (the default) sets no
28
- * timeout. The clock starts at the call into the driver, so a credential fetch counts, and runs until the body has
29
- * ended; when it passes the read throws `TransientError` and no further attempt starts. Uploads, deletes and
30
- * listings are not timed. A non-negative safe integer no larger than 2,147,483,647.
31
- */
32
- readonly readTimeoutMs?: number;
33
- /** What the backoff before re-sending a throttled upload waits on; real time when absent. */
34
- readonly clock?: Sleeper;
35
- /**
36
- * Whether a delete given `ifVersion` is sent with `ifGenerationMatch`, so it removes the object only while it is the
37
- * one that generation names. Defaults to `false`, on the public endpoint too, as the registry's option does: whether
38
- * real GCS applies `ifGenerationMatch` to a delete has not been verified by a run against the service, and
39
- * fake-gcs-server accepts the precondition and ignores it. Set `true` once you have. Until it is set, a delete
40
- * decided from one read of an object removes whatever is under the name by then: on GCS the window in which an
41
- * erasure's stalled delete takes a generation a load put under the number since stays open.
42
- */
43
- readonly conditionalDelete?: boolean;
44
- }
45
- export declare class GcsStorageDriver implements IStorageDriver {
46
- private readonly storage;
47
- private readonly readStorage;
48
- private readonly bucket;
49
- private readonly prefix;
50
- private readonly maxObjectBytes;
51
- private readonly threshold;
52
- private readonly readTimeoutMs;
53
- private readonly clock;
54
- private readonly presence;
55
- private readonly conditionalDelete;
56
- constructor(options: GcsStorageDriverOptions);
57
- capabilities(): StorageCaps;
58
- private file;
59
- /** The same object on the download client, off the SDK's shared agent ({@link downloadFile}). */
60
- private downloadable;
61
- /** The deadline a read of `key` made now runs under, every attempt included, named for its error; none when off. */
62
- private deadline;
63
- putImmutable(key: GenKey, write: (sink: BlobSink) => Promise<void>): Promise<{
64
- size: number;
65
- sha256: string;
66
- }>;
67
- getRange(key: GenKey, offset: number, length: number): Promise<Uint8Array>;
68
- /**
69
- * Refuse a range response unless it is exactly the bytes asked for. A 206 must name them in `Content-Range: bytes
70
- * a-b/total`, starting at `offset`, and hold that many; a 200 (a server that ignored the range) is the whole object,
71
- * which is the range only when the range starts at 0. A short read means the range ran past the end of the object:
72
- * out of bounds, never a partial result.
73
- */
74
- private checkRange;
75
- private badRange;
76
- getTail(key: GenKey, maxBytes: number): Promise<TailRead>;
77
- /**
78
- * The object's size from its metadata, validated, and its generation when the metadata names a usable one. Read on the
79
- * download client and retried as a download is, within the calling read's `deadline` ({@link withDeadline}), so
80
- * nothing but the one request in flight runs past it.
81
- */
82
- private metadataOf;
83
- /**
84
- * The object's total size from a tail response, refused unless every header agrees with the bytes received. A 206
85
- * must carry `Content-Range: bytes a-b/total` that names exactly the suffix asked for and exactly the bytes held;
86
- * a 200 (a server that ignored the range) is the whole object, and is accepted only when it fits in the request.
87
- */
88
- private tailSize;
89
- private badTail;
90
- delete(key: GenKey, options?: StorageDeleteOptions): Promise<void>;
91
- /** Whether an object is under the name, from its metadata. A read that fails in any other way throws. */
92
- private exists;
93
- list(ref: SegmentRef): AsyncIterable<GenKey>;
94
- /** A read's error, once a 404 is known to be the object's and not the bucket's ({@link BucketPresence}). */
95
- private readFailure;
96
- /** Map GCS read errors to the driver vocabulary; pass everything else through {@link mapError}. */
97
- private mapReadError;
98
- /**
99
- * Reclassify a transient GCS fault (throttle/5xx/dropped connection) as a retryable {@link TransientError},
100
- * so the store's read retry can ride it out and a write's caller can tell it from a deterministic failure;
101
- * everything else propagates unchanged. The final fallback at every client-call site: an HTTP status and a fault
102
- * in transit arrive typed, and anything else (a checksum mismatch, a credentials failure) as the SDK raised it.
103
- */
104
- private mapError;
105
- }
106
- export {};