@cloudbitmaps/gcs 0.18.2 → 0.19.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/README.md +20 -9
- package/dist/backend.d.ts +10 -5
- package/dist/bucket-presence.d.ts +37 -0
- package/dist/crc32c.d.ts +5 -0
- package/dist/gcs-errors.d.ts +8 -1
- package/dist/index.js +350 -130
- package/dist/index.js.map +4 -4
- package/dist/read-client.d.ts +6 -0
- package/dist/registry.d.ts +1 -0
- package/dist/storage.d.ts +3 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -39,7 +39,7 @@ It builds its own client from Application Default Credentials. Any other key is
|
|
|
39
39
|
|---|---|
|
|
40
40
|
| `bucket` (required) | the bucket |
|
|
41
41
|
| `prefix` | a key prefix for everything this store writes |
|
|
42
|
-
| `client` | your own `Storage` client. Pass it as `client`; `storage` is refused, since in `CloudRoaring` that word means the backend.
|
|
42
|
+
| `client` | your own `Storage` client. Pass it as `client`; `storage` is refused, since in `CloudRoaring` that word means the backend. Its downloads go through a twin of it with the SDK's retries off, and its single-request conditional writes are sent without them; a client no twin can be built from safely, such as a test stub, is refused (see below) |
|
|
43
43
|
| `projectId`, `apiEndpoint` | build a client for you, such as one for fake-gcs-server; refused beside `client` |
|
|
44
44
|
| `simpleUploadThresholdBytes`, `maxObjectBytes` | the size up to which an object is one simple request (default 8 MiB) and the largest object (default 5 TiB, GCS's maximum) |
|
|
45
45
|
| `readTimeoutMs` | cut off a read that has run this long, in milliseconds (see below); `0`, the default, sets no timeout |
|
|
@@ -54,14 +54,25 @@ It builds its own client from Application Default Credentials. Any other key is
|
|
|
54
54
|
- **The write-once guarantee rides GCS preconditions** (`ifGenerationMatch`), so nothing else needs enabling.
|
|
55
55
|
- **Never add a lifecycle rule that expires current objects or the `registry/` prefix.**
|
|
56
56
|
- **The SDK does not retry downloads; the driver does.** In `@google-cloud/storage` 7.x and 8.x (checked on 7.22.0 and
|
|
57
|
-
8.1.0), a download the SDK retries after any status it retries (408, 429, 500, 502, 503 or 504) can crash the process
|
|
58
|
-
`ERR_STREAM_UNABLE_TO_PIPE`, thrown outside any promise, even though the retried request succeeded. The client
|
|
59
|
-
`GcsStorage` builds therefore sends each download once, and the driver runs a download again itself, up to three
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
57
|
+
8.1.0), a download the SDK retries after any status it retries (408, 429, 500, 502, 503 or 504) can crash the process
|
|
58
|
+
with `ERR_STREAM_UNABLE_TO_PIPE`, thrown outside any promise, even though the retried request succeeded. The client
|
|
59
|
+
`GcsStorage` builds therefore sends each download once, and the driver runs a download again itself, up to three more
|
|
60
|
+
times with backoff, after a connection fault (refused, reset, timed out, a DNS failure, a body cut off) or a 408, 429,
|
|
61
|
+
500, 502, 503 or 504, and after nothing else (not a missing credentials file or a TLS failure). That holds for every
|
|
62
|
+
caller, including a store built with `retry: false`. The client's listings, deletes, resumable uploads and the
|
|
63
|
+
metadata read that settles a write keep its retry settings (under which the SDK sends a delete with no precondition
|
|
64
|
+
once); a single-request conditional write (a registry row, a small generation) is sent without them. **A client you
|
|
65
|
+
pass as `client` keeps its own retries for those requests**: its downloads go through a twin of it, built from its own
|
|
66
|
+
class with the same credentials object, endpoint, project, user agent, timeout, checksum generator and interceptors
|
|
67
|
+
and the SDK's retries off. A `Storage` client is always used through its twin, which must have taken the settings that
|
|
68
|
+
decide where and how a download goes: the same credentials object, URL and endpoint, and retry settings of its own,
|
|
69
|
+
which are then turned off over any its class set. The backend refuses, when it is built, a client whose twin would not
|
|
70
|
+
(a subclass that builds from options of its own), one whose class overrides `bucket` (as a test double built on
|
|
71
|
+
`Storage` does), and one whose `bucket` is replaced on the instance (as by a test stub). Stub `Storage.prototype` (or
|
|
72
|
+
`Bucket.prototype`, `File.prototype`) instead, which reaches the twin; a stub on the client's instance does not. A
|
|
73
|
+
test double that is not a `Storage` client is used as it is when it has `retryOptions: { autoRetry: false }`, and
|
|
74
|
+
refused without it; with the SDK's module mocked, pass the mock as `client`. What is set on a client after the backend
|
|
75
|
+
was built, other than an interceptor, is not carried to the twin.
|
|
65
76
|
- **A client `timeout` does not bound a download on `@google-cloud/storage` 8.x**, so a read whose server stalls waits
|
|
66
77
|
for it. Measured against a local server that never answers: still pending after 12 s with `timeout: 2000`.
|
|
67
78
|
**`readTimeoutMs` does, and it is off unless you set it.** It bounds each read as a whole: a generation's tail (with
|
package/dist/backend.d.ts
CHANGED
|
@@ -19,11 +19,16 @@ export interface GcsStorageOptions {
|
|
|
19
19
|
/**
|
|
20
20
|
* A constructed `@google-cloud/storage` client. One is built from the ambient credentials when absent. Its retry
|
|
21
21
|
* options apply to every request except the single-request conditional writes, which the driver sends without
|
|
22
|
-
* that retry whatever they say
|
|
23
|
-
* its own backoff. In `@google-cloud/storage` 7.x and 8.x a download the SDK retries after a 408,
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
22
|
+
* that retry whatever they say (a registry row once, and a generation's object again only after a throttle, under
|
|
23
|
+
* its own backoff), and the downloads. In `@google-cloud/storage` 7.x and 8.x a download the SDK retries after a 408,
|
|
24
|
+
* 429, 500, 502, 503 or 504 can crash the process with `ERR_STREAM_UNABLE_TO_PIPE`, so downloads go through a twin of
|
|
25
|
+
* this client, built from its own class with the same credentials object, endpoint and settings and the SDK's retries
|
|
26
|
+
* off over any its class set, and the driver retries them itself. A client whose twin would use other credentials or
|
|
27
|
+
* another endpoint (a subclass that builds from options of its own), whose class overrides `bucket` (a test double
|
|
28
|
+
* built on `Storage`), or whose `bucket` is replaced on the instance (a test stub; stub `Storage.prototype` instead)
|
|
29
|
+
* is refused at construction. A test double that is not a `Storage` client is used as it is when it has
|
|
30
|
+
* `retryOptions: { autoRetry: false }`, and refused without it. What is set on the client after the backend was
|
|
31
|
+
* built, other than an interceptor, is not carried to the twin.
|
|
27
32
|
*/
|
|
28
33
|
readonly client?: GcsClient;
|
|
29
34
|
/** Project id for the client built when `client` is absent (refused beside `client`). Falls back to the SDK's own resolution. */
|
|
@@ -0,0 +1,37 @@
|
|
|
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
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
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;
|
package/dist/gcs-errors.d.ts
CHANGED
|
@@ -18,8 +18,15 @@ export declare function isPreconditionFailed(err: unknown): boolean;
|
|
|
18
18
|
* an upload sent again after one must still tell a landed first send apart.
|
|
19
19
|
*/
|
|
20
20
|
export declare function isThrottle(err: unknown): boolean;
|
|
21
|
-
/** The object / generation does not exist (GCS returns 404). */
|
|
21
|
+
/** The object / generation does not exist (GCS returns 404), in a bucket that does. */
|
|
22
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;
|
|
23
30
|
/** A range request started past EOF (HTTP 416 Requested Range Not Satisfiable). */
|
|
24
31
|
export declare function isInvalidRange(err: unknown): boolean;
|
|
25
32
|
/** A download that failed in transit rather than with an HTTP status: one of {@link TRANSPORT_CODES}. */
|