@cloudbitmaps/gcs 0.21.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/README.md +32 -1
- package/dist/backend.d.ts +14 -10
- package/dist/index.js +333 -54
- package/dist/index.js.map +2 -2
- package/package.json +2 -2
- package/dist/bucket-presence.d.ts +0 -37
- package/dist/crc32c.d.ts +0 -5
- package/dist/defined.d.ts +0 -8
- package/dist/download-retry.d.ts +0 -8
- package/dist/gcs-errors.d.ts +0 -60
- package/dist/read-client.d.ts +0 -6
- package/dist/read-once.d.ts +0 -52
- package/dist/read-timeout.d.ts +0 -28
- package/dist/registry.d.ts +0 -90
- package/dist/scrub-error.d.ts +0 -18
- package/dist/send-once.d.ts +0 -5
- package/dist/storage.d.ts +0 -109
package/README.md
CHANGED
|
@@ -14,7 +14,14 @@ second service to run.
|
|
|
14
14
|
pnpm add @cloudbitmaps/roaring @cloudbitmaps/gcs
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
`roaring` needs its one install script to fetch its native binary, and newer clients run a dependency's script only if you allow it. Allow it before you install:
|
|
18
|
+
|
|
19
|
+
- **npm 12:** add `{ "allowScripts": { "roaring": true } }` to your `package.json`. Without it the install exits 0 and the package throws at `import`. npm 11 runs the script but warns until you allow it the same way.
|
|
20
|
+
- **pnpm 11 and later:** put `allowBuilds: { roaring: true }` in a `pnpm-workspace.yaml` beside your `package.json`. Those versions no longer read the `package.json` `pnpm` key. Without it the install exits 1 with `ERR_PNPM_IGNORED_BUILDS`.
|
|
21
|
+
- **pnpm 10:** add `{ "pnpm": { "onlyBuiltDependencies": ["roaring"] } }` to your `package.json`. Without it the install exits 0 and the package throws at `import`.
|
|
22
|
+
- **pnpm 9:** nothing extra.
|
|
23
|
+
|
|
24
|
+
[Details](https://github.com/cloudbitmaps/cloudbitmaps/blob/main/docs/guide/getting-started.md#cannot-find-module-buildreleaseroaringnode-after-a-successful-install).
|
|
18
25
|
|
|
19
26
|
`@google-cloud/storage` (`^7 || ^8`) is a real dependency of this package, so installing it is the whole step.
|
|
20
27
|
`@cloudbitmaps/core`, the engine underneath, arrives with it and you never name it.
|
|
@@ -109,6 +116,30 @@ It builds its own client from Application Default Credentials. Any other key is
|
|
|
109
116
|
store's clock).
|
|
110
117
|
|
|
111
118
|
The [production checklist](https://github.com/cloudbitmaps/cloudbitmaps/blob/main/docs/guide/production.md) covers each item, and the ones every backend shares: backups of the data and the registry, and a schedule for your loads.
|
|
119
|
+
- **The driver redacts the credentials it recognises from an error before it throws it.** The SDK keeps the response it
|
|
120
|
+
got on the error (`response`), and through it the request it sent, with the bearer token in its `Authorization`
|
|
121
|
+
header, and the HTTP agent it shares with other calls; a resumable upload's or a token request's error keeps the
|
|
122
|
+
request's `config`. On a download, and wherever a body lists no errors, the SDK makes the response body the error's
|
|
123
|
+
message, so a proxy's page or a JSON body that quotes the request puts the token in the message. In the error the
|
|
124
|
+
driver throws, the value under a credential's name is replaced by `[redacted]` (`authorization`,
|
|
125
|
+
`x-goog-encryption-key`, `x-goog-api-key`, `X-Goog-Signature`, `X-Goog-Credential`, `access_token`, `refresh_token`,
|
|
126
|
+
`client_secret`, `private_key` and the like; a service account's `client_email` and `private_key_id` are kept), and so
|
|
127
|
+
are the value after one in a header list or under one in a map, the value beside one in a record (a `{ name, value }`
|
|
128
|
+
pair, a `{ th, td }` row; a number, a boolean, and the `message`, `reason` and `location` of a Google error item are
|
|
129
|
+
kept), and, anywhere in its text, a credential header line; an `Authorization` value, an encryption key, an API key,
|
|
130
|
+
an OAuth token or client secret, or a signed URL's signature or credential after its name; a cookie header's value
|
|
131
|
+
after its name; a bearer token after its scheme; a Google access token (`ya29.`) or a JWT on its own; a V2 signed
|
|
132
|
+
URL's `Signature=`; a PEM private key's body; the text of an element named for a credential, such as the
|
|
133
|
+
`<CanonicalRequest>` a service quotes back; and the text of the cell after one that names a credential (a
|
|
134
|
+
`<th>`/`<td>` row, a `<dt>`/`<dd>` pair, after a heading or a caption too). A credential in another form is not
|
|
135
|
+
recognised (a header table laid out by column, a user and password written into a URL, a colon written as an HTML
|
|
136
|
+
entity such as `:` in a body a download quotes as it came), and a text these steps cannot finish is replaced
|
|
137
|
+
whole. An SDK error that carries its transport or shows a credential, and every error it reaches (its `cause` chain,
|
|
138
|
+
an `AggregateError`'s `errors`), is thrown as a copy: a native error with the same prototype, name, message, stack,
|
|
139
|
+
`code`, `status` and `errors`, with `response` reduced to its status and status text, so classification is unchanged,
|
|
140
|
+
without `config`, the request, its agent or socket, any function or accessor property, or anything nested deeper than
|
|
141
|
+
ten levels. The live error is never changed, and an error that holds only plain data and shows no credential is thrown
|
|
142
|
+
as it is.
|
|
112
143
|
|
|
113
144
|
## Documentation
|
|
114
145
|
|
package/dist/backend.d.ts
CHANGED
|
@@ -1,16 +1,10 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `GcsStorage` — the Google Cloud Storage backend as one object: generations and pointer, one bucket, stated once.
|
|
3
|
-
*
|
|
4
|
-
* See {@link StorageBackend} for why the two halves are configured together rather than separately.
|
|
5
|
-
*
|
|
6
|
-
* **A note on the word.** `@google-cloud/storage` names its own client class `Storage`, so the driver option
|
|
7
|
-
* that takes it is also called `storage` — which, since this library calls its durable tier storage too, reads
|
|
8
|
-
* as the same word meaning two things. That is why this class builds the client itself: `new GcsStorage({ bucket })`
|
|
9
|
-
* never makes you write `{ storage: storage }`. Supply `client` when you need your own.
|
|
10
|
-
*/
|
|
11
1
|
import { STORAGE_BACKEND } from '@cloudbitmaps/core/driver-kit';
|
|
12
2
|
import type { IRegistryDriver, IStorageDriver, StorageBackend } from '@cloudbitmaps/core/driver-kit';
|
|
13
3
|
import { Storage as GcsClient } from '@google-cloud/storage';
|
|
4
|
+
/**
|
|
5
|
+
* What {@link GcsStorage} takes: a `bucket`, and either a `client` or the two settings that build one (`projectId`,
|
|
6
|
+
* `apiEndpoint`), never both.
|
|
7
|
+
*/
|
|
14
8
|
export interface GcsStorageOptions {
|
|
15
9
|
/** Target bucket (must already exist). */
|
|
16
10
|
readonly bucket: string;
|
|
@@ -77,6 +71,16 @@ export interface GcsStorageOptions {
|
|
|
77
71
|
* for a client pointed at an emulator that is production traffic from a wiring typo.
|
|
78
72
|
*/
|
|
79
73
|
export declare const GCS_STORAGE_OPTION_KEYS: readonly ["bucket", "prefix", "client", "projectId", "apiEndpoint", "maxObjectBytes", "simpleUploadThresholdBytes", "now", "readTimeoutMs", "conditionalDelete"];
|
|
74
|
+
/**
|
|
75
|
+
* `GcsStorage` — the Google Cloud Storage backend as one object: generations and pointer, one bucket, stated once.
|
|
76
|
+
*
|
|
77
|
+
* See {@link StorageBackend} for why the two halves are configured together rather than separately.
|
|
78
|
+
*
|
|
79
|
+
* **A note on the word.** `@google-cloud/storage` names its own client class `Storage`, so the driver option
|
|
80
|
+
* that takes it is also called `storage` — which, since this library calls its durable tier storage too, reads
|
|
81
|
+
* as the same word meaning two things. That is why this class builds the client itself: `new GcsStorage({ bucket })`
|
|
82
|
+
* never makes you write `{ storage: storage }`. Supply `client` when you need your own.
|
|
83
|
+
*/
|
|
80
84
|
export declare class GcsStorage implements StorageBackend {
|
|
81
85
|
/** Cross-bundle brand, stamped non-enumerably in the constructor so a spread cannot carry it. */
|
|
82
86
|
readonly [STORAGE_BACKEND]: true;
|
package/dist/index.js
CHANGED
|
@@ -13,14 +13,12 @@ function defined(values) {
|
|
|
13
13
|
|
|
14
14
|
// src/storage.ts
|
|
15
15
|
import {
|
|
16
|
+
errorKind,
|
|
16
17
|
NotFoundError,
|
|
17
18
|
TransientError as TransientError2,
|
|
18
19
|
ValidationError as ValidationError3,
|
|
19
20
|
WriteConflictError,
|
|
20
21
|
concatBytes,
|
|
21
|
-
isNotFoundError,
|
|
22
|
-
isValidationError,
|
|
23
|
-
isWriteConflictError,
|
|
24
22
|
normalizeObjectPrefix,
|
|
25
23
|
parseGenerationFromKey,
|
|
26
24
|
requireBool,
|
|
@@ -121,7 +119,8 @@ function transientFaultMessage(err) {
|
|
|
121
119
|
}
|
|
122
120
|
|
|
123
121
|
// src/scrub-error.ts
|
|
124
|
-
|
|
122
|
+
import { types } from "node:util";
|
|
123
|
+
var TRANSPORT = /* @__PURE__ */ new Set([
|
|
125
124
|
"request",
|
|
126
125
|
"agent",
|
|
127
126
|
"socket",
|
|
@@ -131,73 +130,349 @@ var DROPPED = /* @__PURE__ */ new Set([
|
|
|
131
130
|
"res",
|
|
132
131
|
"config"
|
|
133
132
|
]);
|
|
134
|
-
var
|
|
135
|
-
var
|
|
133
|
+
var RESPONSE_FIELDS = ["status", "statusText", "statusCode", "statusMessage"];
|
|
134
|
+
var CREDENTIAL_NAMES = [
|
|
135
|
+
"authorization",
|
|
136
|
+
"proxy-authorization",
|
|
137
|
+
"cookie",
|
|
138
|
+
"set-cookie",
|
|
139
|
+
"x-api-key",
|
|
140
|
+
"x-goog-api-key",
|
|
141
|
+
"x-goog-encryption-key",
|
|
142
|
+
"x-goog-copy-source-encryption-key",
|
|
143
|
+
"encryption-key",
|
|
144
|
+
"encryption-key-base64",
|
|
145
|
+
"x-goog-signature",
|
|
146
|
+
"x-goog-credential",
|
|
147
|
+
"signature",
|
|
148
|
+
"signature-provided",
|
|
149
|
+
"canonical-request",
|
|
150
|
+
"token",
|
|
151
|
+
"access-token",
|
|
152
|
+
"refresh-token",
|
|
153
|
+
"id-token",
|
|
154
|
+
"subject-token",
|
|
155
|
+
"client-secret",
|
|
156
|
+
"private-key",
|
|
157
|
+
"assertion"
|
|
158
|
+
];
|
|
159
|
+
var fold = (name) => name.trim().replace(/:$/, "").replace(/[-_]/g, "").toLowerCase();
|
|
160
|
+
var CREDENTIAL_NAME = new Set(CREDENTIAL_NAMES.map(fold));
|
|
161
|
+
var LONGEST_NAME = 64;
|
|
162
|
+
var CREDENTIAL_LINES = /^((?:proxy-)?authorization|cookie|set-cookie|x-api-key|x-goog-api-key|x-goog-(?:copy-source-)?encryption-key):[^\r\n]*/gim;
|
|
163
|
+
var AUTHORIZATION_VALUE = /((?:proxy-)?authorization\\?["']?\s*(?::|=|%3D)\s*\\?["']?)(?:[A-Za-z][\w-]*(?:\s+|%20|\+))?[^\s&"'<>\\,;]+/gi;
|
|
164
|
+
var COOKIE_VALUE = /(?<![\w-])((?:set-)?cookie\\?["']?\s*:\s*\\?["']?)[^\r\n"'<>\\]+/gi;
|
|
165
|
+
var NAMED = "x-goog-(?:copy-source-)?encryption-key|x-goog-api-key|x-goog-signature|x-goog-credential|(?:access|refresh|id|subject)[-_]token|client[-_]secret";
|
|
166
|
+
var NAMED_SECRET = new RegExp(
|
|
167
|
+
`((?:${NAMED})\\\\?["']?\\s*(?::|=|%3D)\\s*\\\\?["']?)[^\\s&"'<>\\\\,;]+`,
|
|
168
|
+
"gi"
|
|
169
|
+
);
|
|
170
|
+
var BEARER = /\b(Bearer)(\s+|%20|\+)(?=[A-Za-z0-9\-._~+/]{16})[A-Za-z0-9\-._~+/]+=*/gi;
|
|
171
|
+
var TOKEN_TEXT = /ya29\.(?=[A-Za-z0-9_.-]{16})[A-Za-z0-9_.-]+|(?<![A-Za-z0-9_-])eyJ(?=[A-Za-z0-9_-]{8})[A-Za-z0-9_-]+\.eyJ(?=[A-Za-z0-9_-]{8})[A-Za-z0-9_-]+\.(?=[A-Za-z0-9_-]{16})[A-Za-z0-9_-]+/g;
|
|
172
|
+
var SIGNATURE_NAME = /Signature(?:=|%3D)/gi;
|
|
173
|
+
var SIGNATURE_RUN = /[A-Za-z0-9+/=_.-]*/y;
|
|
174
|
+
var SIGNATURE_MIN = 16;
|
|
175
|
+
var PEM_OPEN = /-----BEGIN [A-Z0-9 ]{0,40}PRIVATE KEY-----/y;
|
|
176
|
+
var PEM_CLOSE = /-----END [A-Z0-9 ]{0,40}PRIVATE KEY-----/y;
|
|
177
|
+
var ELEMENT = /(<([A-Za-z][\w.:-]{0,63})>)([^<]*)(<\/\2>)/g;
|
|
178
|
+
var CELL = /(<([A-Za-z][\w-]{0,15})\b[^<>]{0,256}>\s{0,32}([^<>\s](?:[^<>]{0,62}[^<>\s])?)\s{0,32}<\/\2\s{0,32}>(?:\s{0,32}<\/[A-Za-z][\w-]{0,15}\s{0,32}>){0,4}(?:\s{0,32}<[A-Za-z][\w-]{0,15}\b[^<>]{0,256}>){1,4})([^<]*)/g;
|
|
136
179
|
var REDACTED = "[redacted]";
|
|
180
|
+
var MAX_DEPTH = 10;
|
|
137
181
|
var isPlain = (value) => {
|
|
138
182
|
const proto = Object.getPrototypeOf(value);
|
|
139
183
|
return proto === Object.prototype || proto === null;
|
|
140
184
|
};
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
185
|
+
var isError = (value) => value instanceof Error || types.isNativeError(value);
|
|
186
|
+
var isCredentialName = (text) => text.length <= LONGEST_NAME && CREDENTIAL_NAME.has(fold(text));
|
|
187
|
+
function redactText(text) {
|
|
188
|
+
try {
|
|
189
|
+
const named = redactPrivateKeys(text).replace(CREDENTIAL_LINES, `$1: ${REDACTED}`).replace(AUTHORIZATION_VALUE, `$1${REDACTED}`).replace(COOKIE_VALUE, `$1${REDACTED}`).replace(NAMED_SECRET, `$1${REDACTED}`).replace(BEARER, `$1$2${REDACTED}`).replace(TOKEN_TEXT, REDACTED);
|
|
190
|
+
return redactCells(
|
|
191
|
+
redactSignatures(named).replace(
|
|
192
|
+
ELEMENT,
|
|
193
|
+
(whole, open, tag, inner, close) => isCredentialName(tag) && inner.trim() !== "" ? `${open}${REDACTED}${close}` : whole
|
|
194
|
+
)
|
|
195
|
+
);
|
|
196
|
+
} catch {
|
|
197
|
+
return REDACTED;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
function redactPrivateKeys(text) {
|
|
201
|
+
let out = "";
|
|
202
|
+
let from = 0;
|
|
203
|
+
for (let at = text.indexOf("-----BEGIN "); at !== -1; at = text.indexOf("-----BEGIN ", Math.max(at + 1, from))) {
|
|
204
|
+
PEM_OPEN.lastIndex = at;
|
|
205
|
+
const open = PEM_OPEN.exec(text);
|
|
206
|
+
if (open === null) continue;
|
|
207
|
+
const body = at + open[0].length;
|
|
208
|
+
const end = text.indexOf("-----END", body);
|
|
209
|
+
let close = "";
|
|
210
|
+
if (end !== -1) {
|
|
211
|
+
PEM_CLOSE.lastIndex = end;
|
|
212
|
+
close = PEM_CLOSE.exec(text)?.[0] ?? "";
|
|
213
|
+
}
|
|
214
|
+
out += `${text.slice(from, body)}${REDACTED}${close}`;
|
|
215
|
+
from = end === -1 ? text.length : end + close.length;
|
|
216
|
+
}
|
|
217
|
+
return from === 0 ? text : out + text.slice(from);
|
|
218
|
+
}
|
|
219
|
+
function redactSignatures(text) {
|
|
220
|
+
let out = "";
|
|
221
|
+
let from = 0;
|
|
222
|
+
SIGNATURE_NAME.lastIndex = 0;
|
|
223
|
+
for (let m = SIGNATURE_NAME.exec(text); m !== null; m = SIGNATURE_NAME.exec(text)) {
|
|
224
|
+
const start = m.index + m[0].length;
|
|
225
|
+
let end = start;
|
|
226
|
+
for (; ; ) {
|
|
227
|
+
SIGNATURE_RUN.lastIndex = end;
|
|
228
|
+
SIGNATURE_RUN.exec(text);
|
|
229
|
+
end = SIGNATURE_RUN.lastIndex;
|
|
230
|
+
if (text[end] !== "%" || text.startsWith("%26", end)) break;
|
|
231
|
+
end += 1;
|
|
232
|
+
}
|
|
233
|
+
if (end - start >= SIGNATURE_MIN) {
|
|
234
|
+
out += `${text.slice(from, start)}${REDACTED}`;
|
|
235
|
+
from = end;
|
|
236
|
+
}
|
|
237
|
+
SIGNATURE_NAME.lastIndex = end;
|
|
238
|
+
}
|
|
239
|
+
return from === 0 ? text : out + text.slice(from);
|
|
240
|
+
}
|
|
241
|
+
function redactCells(text) {
|
|
242
|
+
let out = "";
|
|
243
|
+
let from = 0;
|
|
244
|
+
CELL.lastIndex = 0;
|
|
245
|
+
for (let m = CELL.exec(text); m !== null; m = CELL.exec(text)) {
|
|
246
|
+
const [whole, head, , name, value] = m;
|
|
247
|
+
if (isCredentialName(name) && value.trim() !== "") {
|
|
248
|
+
out += `${text.slice(from, m.index)}${head}${REDACTED}`;
|
|
249
|
+
from = m.index + whole.length;
|
|
250
|
+
} else {
|
|
251
|
+
CELL.lastIndex = m.index + 1;
|
|
252
|
+
}
|
|
146
253
|
}
|
|
147
|
-
return out;
|
|
254
|
+
return from === 0 ? text : out + text.slice(from);
|
|
255
|
+
}
|
|
256
|
+
var OMIT = /* @__PURE__ */ Symbol("omit");
|
|
257
|
+
var INDEX = /^(?:0|[1-9]\d*)$/;
|
|
258
|
+
var isIndex = (key) => typeof key === "string" && INDEX.test(key) && Number(key) < 2 ** 32 - 1;
|
|
259
|
+
function hasNamedKeys(value) {
|
|
260
|
+
if (!Array.isArray(value)) return Reflect.ownKeys(value).length > 0;
|
|
261
|
+
return Reflect.ownKeys(value).some((key) => key !== "length" && !isIndex(key));
|
|
262
|
+
}
|
|
263
|
+
function define(copy, key, value, enumerable) {
|
|
264
|
+
Object.defineProperty(copy, key, { value, writable: true, configurable: true, enumerable });
|
|
265
|
+
}
|
|
266
|
+
function copyOf(value, ctx, depth) {
|
|
267
|
+
if (typeof value === "string") {
|
|
268
|
+
const clean = redactText(value);
|
|
269
|
+
if (clean !== value) ctx.changed = true;
|
|
270
|
+
return clean;
|
|
271
|
+
}
|
|
272
|
+
if (typeof value === "function" || typeof value === "symbol") {
|
|
273
|
+
ctx.changed = true;
|
|
274
|
+
return OMIT;
|
|
275
|
+
}
|
|
276
|
+
if (typeof value !== "object" || value === null) return value;
|
|
277
|
+
if (ctx.copies.has(value)) return ctx.copies.get(value);
|
|
278
|
+
if (depth > MAX_DEPTH) {
|
|
279
|
+
ctx.changed = true;
|
|
280
|
+
return OMIT;
|
|
281
|
+
}
|
|
282
|
+
if (Array.isArray(value)) return copyList(value, ctx, depth);
|
|
283
|
+
if (value instanceof Map) return copyMap(value, ctx, depth);
|
|
284
|
+
if (value instanceof Set) return copySet(value, ctx, depth);
|
|
285
|
+
return copyRecord(value, ctx, depth);
|
|
286
|
+
}
|
|
287
|
+
function copyList(value, ctx, depth) {
|
|
288
|
+
const list = new Array(value.length);
|
|
289
|
+
ctx.copies.set(value, list);
|
|
290
|
+
if (hasNamedKeys(value)) ctx.changed = true;
|
|
291
|
+
let hidden = false;
|
|
292
|
+
let last = -1;
|
|
293
|
+
for (const key of Reflect.ownKeys(value)) {
|
|
294
|
+
if (!isIndex(key)) continue;
|
|
295
|
+
const index = Number(key);
|
|
296
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
297
|
+
if (descriptor === void 0 || !("value" in descriptor)) {
|
|
298
|
+
ctx.changed = true;
|
|
299
|
+
hidden = false;
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
const item = descriptor.value;
|
|
303
|
+
if (hidden && index === last + 1 && item != null) {
|
|
304
|
+
list[index] = REDACTED;
|
|
305
|
+
if (item !== REDACTED) ctx.changed = true;
|
|
306
|
+
} else {
|
|
307
|
+
const kept = copyOf(item, ctx, depth + 1);
|
|
308
|
+
if (kept === OMIT) delete list[index];
|
|
309
|
+
else list[index] = kept;
|
|
310
|
+
}
|
|
311
|
+
hidden = typeof item === "string" && isCredentialName(item);
|
|
312
|
+
last = index;
|
|
313
|
+
}
|
|
314
|
+
return list;
|
|
315
|
+
}
|
|
316
|
+
function copyMap(value, ctx, depth) {
|
|
317
|
+
const map = /* @__PURE__ */ new Map();
|
|
318
|
+
ctx.copies.set(value, map);
|
|
319
|
+
if (hasNamedKeys(value)) ctx.changed = true;
|
|
320
|
+
for (const [k, v] of value) {
|
|
321
|
+
const key = copyOf(k, ctx, depth + 1);
|
|
322
|
+
if (key === OMIT) continue;
|
|
323
|
+
if (typeof k === "string" && isCredentialName(k) && v != null) {
|
|
324
|
+
map.set(key, REDACTED);
|
|
325
|
+
if (v !== REDACTED) ctx.changed = true;
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
const kept = copyOf(v, ctx, depth + 1);
|
|
329
|
+
if (kept !== OMIT) map.set(key, kept);
|
|
330
|
+
}
|
|
331
|
+
return map;
|
|
332
|
+
}
|
|
333
|
+
function copySet(value, ctx, depth) {
|
|
334
|
+
const set = /* @__PURE__ */ new Set();
|
|
335
|
+
ctx.copies.set(value, set);
|
|
336
|
+
if (hasNamedKeys(value)) ctx.changed = true;
|
|
337
|
+
for (const v of value) {
|
|
338
|
+
const kept = copyOf(v, ctx, depth + 1);
|
|
339
|
+
if (kept !== OMIT) set.add(kept);
|
|
340
|
+
}
|
|
341
|
+
return set;
|
|
148
342
|
}
|
|
149
|
-
function
|
|
150
|
-
|
|
151
|
-
if (
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
for (const item of value) list.push(clean(item, copies));
|
|
159
|
-
return list;
|
|
160
|
-
}
|
|
161
|
-
const isError = value instanceof Error;
|
|
162
|
-
if (!isError && !isPlain(value)) return void 0;
|
|
163
|
-
const copy = Object.create(Object.getPrototypeOf(value));
|
|
164
|
-
copies.set(value, copy);
|
|
343
|
+
function copyRecord(value, ctx, depth) {
|
|
344
|
+
const errorLike = isError(value);
|
|
345
|
+
if (!errorLike && !isPlain(value)) {
|
|
346
|
+
ctx.changed = true;
|
|
347
|
+
return OMIT;
|
|
348
|
+
}
|
|
349
|
+
const copy = errorLike ? Object.setPrototypeOf(new Error(), Object.getPrototypeOf(value)) : Object.create(Object.getPrototypeOf(value));
|
|
350
|
+
ctx.copies.set(value, copy);
|
|
351
|
+
if (errorLike) delete copy.stack;
|
|
165
352
|
for (const key of Reflect.ownKeys(value)) {
|
|
166
|
-
if (typeof key === "string" &&
|
|
353
|
+
if (typeof key === "string" && TRANSPORT.has(key)) {
|
|
354
|
+
ctx.changed = true;
|
|
355
|
+
} else if (errorLike && key === "stack") {
|
|
356
|
+
copyStack(value, copy, ctx, depth);
|
|
357
|
+
} else {
|
|
358
|
+
copyField(value, copy, key, ctx, depth);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
if (errorLike) keepSlotFields(value, copy, ctx, depth);
|
|
362
|
+
redactPairs(value, copy, errorLike, ctx);
|
|
363
|
+
return copy;
|
|
364
|
+
}
|
|
365
|
+
var DESCRIBING = /* @__PURE__ */ new Set([
|
|
366
|
+
"message",
|
|
367
|
+
"domain",
|
|
368
|
+
"reason",
|
|
369
|
+
"location",
|
|
370
|
+
"locationType",
|
|
371
|
+
"extendedHelp"
|
|
372
|
+
]);
|
|
373
|
+
function redactPairs(original, copy, errorLike, ctx) {
|
|
374
|
+
const names = Reflect.ownKeys(original).filter((key) => {
|
|
375
|
+
if (typeof key !== "string" || DESCRIBING.has(key)) return false;
|
|
376
|
+
const held = Object.getOwnPropertyDescriptor(original, key)?.value;
|
|
377
|
+
return typeof held === "string" && isCredentialName(held);
|
|
378
|
+
});
|
|
379
|
+
if (names.length === 0) return;
|
|
380
|
+
const values = errorLike ? names.filter((key) => /name$/i.test(key)).map((key) => `${key.slice(0, -4)}value`.toLowerCase()) : void 0;
|
|
381
|
+
for (const key of Reflect.ownKeys(copy)) {
|
|
382
|
+
if (typeof key !== "string" || names.includes(key) || DESCRIBING.has(key)) continue;
|
|
383
|
+
if (values !== void 0 && !values.includes(key.toLowerCase())) continue;
|
|
384
|
+
const descriptor = Object.getOwnPropertyDescriptor(copy, key);
|
|
385
|
+
if (descriptor?.value == null || descriptor.value === REDACTED) continue;
|
|
386
|
+
if (typeof descriptor.value !== "string" && typeof descriptor.value !== "object") continue;
|
|
387
|
+
define(copy, key, REDACTED, descriptor.enumerable ?? false);
|
|
388
|
+
ctx.changed = true;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
function isSummary(value) {
|
|
392
|
+
return isPlain(value) && Reflect.ownKeys(value).every((key) => {
|
|
393
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
394
|
+
const held = descriptor?.value;
|
|
395
|
+
return typeof key === "string" && RESPONSE_FIELDS.includes(key) && (typeof held === "number" || typeof held === "string");
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
function copyResponse(response, ctx, depth) {
|
|
399
|
+
if (isSummary(response)) return copyOf(response, ctx, depth);
|
|
400
|
+
ctx.changed = true;
|
|
401
|
+
const summary = {};
|
|
402
|
+
for (const key of RESPONSE_FIELDS) {
|
|
167
403
|
let held;
|
|
168
404
|
try {
|
|
169
|
-
held =
|
|
405
|
+
held = response[key];
|
|
170
406
|
} catch {
|
|
171
407
|
continue;
|
|
172
408
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
else if (key === "response" && typeof held === "object" && held !== null) {
|
|
177
|
-
kept = responseSummary(held);
|
|
178
|
-
} else kept = clean(held, copies);
|
|
179
|
-
if (kept === void 0 && held !== void 0) continue;
|
|
180
|
-
Object.defineProperty(copy, key, {
|
|
181
|
-
value: kept,
|
|
182
|
-
writable: true,
|
|
183
|
-
configurable: true,
|
|
184
|
-
enumerable: descriptor?.enumerable ?? true
|
|
185
|
-
});
|
|
409
|
+
if (typeof held === "number" || typeof held === "string") {
|
|
410
|
+
summary[key] = copyOf(held, ctx, depth + 1);
|
|
411
|
+
}
|
|
186
412
|
}
|
|
187
|
-
return
|
|
413
|
+
return summary;
|
|
188
414
|
}
|
|
189
|
-
function
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
415
|
+
function copyStack(original, copy, ctx, depth) {
|
|
416
|
+
let stack;
|
|
417
|
+
try {
|
|
418
|
+
stack = original.stack;
|
|
419
|
+
} catch {
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
const kept = copyOf(stack, ctx, depth + 1);
|
|
423
|
+
if (kept !== OMIT) define(copy, "stack", kept, false);
|
|
424
|
+
}
|
|
425
|
+
function copyField(original, copy, key, ctx, depth) {
|
|
426
|
+
const descriptor = Object.getOwnPropertyDescriptor(original, key);
|
|
427
|
+
if (descriptor === void 0) return;
|
|
428
|
+
if (!("value" in descriptor)) {
|
|
429
|
+
ctx.changed = true;
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
const name = typeof key === "string" ? redactText(key) : key;
|
|
433
|
+
if (name !== key) ctx.changed = true;
|
|
434
|
+
const held = descriptor.value;
|
|
435
|
+
let kept;
|
|
436
|
+
if (typeof key === "string" && isCredentialName(key) && held != null) {
|
|
437
|
+
kept = REDACTED;
|
|
438
|
+
if (held !== REDACTED) ctx.changed = true;
|
|
439
|
+
} else if (key === "response" && typeof held === "object" && held !== null) {
|
|
440
|
+
kept = copyResponse(held, ctx, depth + 1);
|
|
441
|
+
} else {
|
|
442
|
+
kept = copyOf(held, ctx, depth + 1);
|
|
443
|
+
if (kept === OMIT) return;
|
|
444
|
+
}
|
|
445
|
+
Object.defineProperty(copy, name, {
|
|
446
|
+
value: kept,
|
|
447
|
+
writable: descriptor.writable ?? true,
|
|
448
|
+
configurable: true,
|
|
449
|
+
enumerable: descriptor.enumerable ?? false
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
function keepSlotFields(original, copy, ctx, depth) {
|
|
453
|
+
for (const key of ["name", "message", "code"]) {
|
|
454
|
+
if (Object.prototype.hasOwnProperty.call(original, key)) continue;
|
|
455
|
+
let held;
|
|
456
|
+
try {
|
|
457
|
+
held = original[key];
|
|
458
|
+
} catch {
|
|
459
|
+
continue;
|
|
460
|
+
}
|
|
461
|
+
let read = OMIT;
|
|
462
|
+
try {
|
|
463
|
+
read = copy[key];
|
|
464
|
+
} catch {
|
|
465
|
+
}
|
|
466
|
+
if (read === held) continue;
|
|
467
|
+
const kept = copyOf(held, ctx, depth + 1);
|
|
468
|
+
if (kept !== OMIT) define(copy, key, kept, false);
|
|
194
469
|
}
|
|
195
|
-
const cause = err.cause;
|
|
196
|
-
return typeof cause === "object" && cause !== null && holdsTransport(cause, seen);
|
|
197
470
|
}
|
|
198
471
|
function scrubCredentials(err) {
|
|
199
472
|
if (typeof err !== "object" || err === null) return err;
|
|
200
|
-
|
|
473
|
+
const ctx = { copies: /* @__PURE__ */ new WeakMap(), changed: false };
|
|
474
|
+
const copy = copyOf(err, ctx, 0);
|
|
475
|
+
return ctx.changed && copy !== OMIT ? copy : err;
|
|
201
476
|
}
|
|
202
477
|
|
|
203
478
|
// src/bucket-presence.ts
|
|
@@ -415,6 +690,10 @@ var REAL_TIME = {
|
|
|
415
690
|
sleep: (ms) => new Promise((resolve) => setTimeout(resolve, ms))
|
|
416
691
|
};
|
|
417
692
|
var REAL_RNG = { next: () => Math.random() };
|
|
693
|
+
function isTypedPassThrough(err) {
|
|
694
|
+
const kind = errorKind(err);
|
|
695
|
+
return kind === "ValidationError" || kind === "WriteConflictError" || kind === "NotFoundError";
|
|
696
|
+
}
|
|
418
697
|
var DEFAULT_UPLOAD_THRESHOLD_BYTES = 8 * 1024 * 1024;
|
|
419
698
|
var GcsStorageDriver = class {
|
|
420
699
|
storage;
|
|
@@ -486,7 +765,7 @@ var GcsStorageDriver = class {
|
|
|
486
765
|
`generation already exists (write-once): ${key.segment}.${key.generation}`
|
|
487
766
|
);
|
|
488
767
|
}
|
|
489
|
-
if (
|
|
768
|
+
if (isTypedPassThrough(err)) throw err;
|
|
490
769
|
if (isNotFound(err)) await this.presence.confirm();
|
|
491
770
|
throw this.mapError(err);
|
|
492
771
|
}
|
|
@@ -707,7 +986,7 @@ var GcsStorageDriver = class {
|
|
|
707
986
|
/** Map GCS read errors to the driver vocabulary; pass everything else through {@link mapError}. */
|
|
708
987
|
mapReadError(err, key) {
|
|
709
988
|
err = scrubCredentials(err);
|
|
710
|
-
if (
|
|
989
|
+
if (errorKind(err) === "ValidationError") return err;
|
|
711
990
|
if (isNotFound(err))
|
|
712
991
|
return new NotFoundError(`no such generation: ${key.segment}.${key.generation}`);
|
|
713
992
|
if (isInvalidRange(err)) {
|