@cloudbitmaps/s3 0.20.0 → 0.21.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.
@@ -1,9 +1,5 @@
1
- /** No timeout unless one is set: the value a read takes stays the caller's until in-region measurements justify one. */
2
- export declare const DEFAULT_READ_TIMEOUT_MS = 0;
3
1
  /** Validate a caller's `readTimeoutMs`, defaulting it: an integer from 0 (no timeout) to {@link MAX_TIMER_MS}. */
4
2
  export declare function resolveReadTimeoutMs(value: number | undefined): number;
5
- /** A value as an error message can show it: a string quoted, so `'200'` is not mistaken for `200`, and never a throw. */
6
- export declare function describe(value: unknown): string;
7
3
  /** The options a timed read passes to its `client.send`: the abort signal, or nothing when the timeout is off. */
8
4
  export type ReadSendOptions = {
9
5
  readonly abortSignal: AbortSignal;
@@ -35,7 +35,7 @@
35
35
  import { ObjectStoreRegistry } from '@cloudbitmaps/core/driver-kit';
36
36
  import type { ObjectRegistryStore, ObjectRow } from '@cloudbitmaps/core/driver-kit';
37
37
  import { type S3Client } from '@aws-sdk/client-s3';
38
- export interface S3RegistryDriverOptions {
38
+ interface S3RegistryDriverOptions {
39
39
  /** A constructed S3 client (point its `endpoint` at MinIO for local/integration use). */
40
40
  readonly client: S3Client;
41
41
  /** Target bucket (must already exist). */
@@ -115,3 +115,4 @@ export declare class S3RegistryStore implements ObjectRegistryStore {
115
115
  export declare class S3RegistryDriver extends ObjectStoreRegistry {
116
116
  constructor(options: S3RegistryDriverOptions);
117
117
  }
118
+ export {};
@@ -29,6 +29,12 @@ export declare function isNoSuchUpload(err: unknown): boolean;
29
29
  * apart there; every request that reaches a missing bucket with a body says so.
30
30
  */
31
31
  export declare function isMissingBucket(err: unknown): boolean;
32
+ /**
33
+ * `err`, or the {@link ValidationError} a missing bucket is: it names the bucket and what to check, and carries the
34
+ * service's error as its `cause`. A wiring fault is not an absent object, so it is not a `NotFoundError`: a read
35
+ * re-resolves on that, and would treat a misnamed bucket as a miss it can heal.
36
+ */
37
+ export declare function asMissingBucket(err: unknown, bucket: string): unknown;
32
38
  /**
33
39
  * The object / generation does not exist (GetObject → `NoSuchKey`, HeadObject → `NotFound`; both 404), in a bucket
34
40
  * that does: a 404 that says the bucket is missing is not one.
@@ -43,6 +49,11 @@ export declare function isInvalidRange(err: unknown): boolean;
43
49
  * retried/reclassified.
44
50
  */
45
51
  export declare function isTransient(err: unknown): boolean;
52
+ /**
53
+ * The message a transient S3 fault is handed on with: `transient S3 fault: <name>`, the SDK error's name, which names
54
+ * S3's error code (`SlowDown`, `InternalError`) or the transport failure (`TimeoutError`).
55
+ */
56
+ export declare function transientFaultMessage(err: unknown): string;
46
57
  /** The first and last byte a `Content-Range: bytes <start>-<end>/<total>` header names, or `undefined` if unparseable. */
47
58
  export declare function spanFromContentRange(contentRange: string | undefined): {
48
59
  start: number;
package/dist/storage.d.ts CHANGED
@@ -1,11 +1,10 @@
1
1
  import type { BlobSink, GenKey, IStorageDriver, SegmentRef, StorageCaps, StorageDeleteOptions, TailRead } from '@cloudbitmaps/core/driver-kit';
2
+ import type { Clock, Rng } from '@cloudbitmaps/core';
2
3
  import { type S3Client } from '@aws-sdk/client-s3';
3
4
  import type { SocketAdvisory } from './socket-advisory.js';
4
5
  /** What the throttle backoff waits on. */
5
- interface Sleeper {
6
- sleep(ms: number): Promise<void>;
7
- }
8
- export interface S3StorageDriverOptions {
6
+ type Sleeper = Pick<Clock, 'sleep'>;
7
+ interface S3StorageDriverOptions {
9
8
  /** A constructed S3 client (point its `endpoint` at MinIO for local/integration use). */
10
9
  readonly client: S3Client;
11
10
  /** Target bucket (must already exist). */
@@ -38,6 +37,8 @@ export interface S3StorageDriverOptions {
38
37
  readonly sockets?: SocketAdvisory;
39
38
  /** What the backoff before re-sending a throttled commit waits on; real time when absent. */
40
39
  readonly clock?: Sleeper;
40
+ /** Where the jitter of that backoff is drawn from; `Math.random` when absent. */
41
+ readonly rng?: Rng;
41
42
  /**
42
43
  * Whether a delete given `ifVersion` is sent with `If-Match`, so it removes the object only while it is the one that
43
44
  * ETag names. Defaults as the registry's option does: on when the host the client resolves is an AWS S3 host and the
@@ -56,6 +57,7 @@ export declare class S3StorageDriver implements IStorageDriver {
56
57
  private readonly partBytes;
57
58
  private readonly readTimeoutMs;
58
59
  private readonly clock;
60
+ private readonly rng;
59
61
  private readonly sockets;
60
62
  private readonly explicitConditionalDelete;
61
63
  private probed;
@@ -88,10 +90,10 @@ export declare class S3StorageDriver implements IStorageDriver {
88
90
  /** Map S3 read errors to the driver vocabulary; pass everything else through {@link mapError}. */
89
91
  private mapReadError;
90
92
  /**
91
- * Reclassify a transient S3 fault (throttle/5xx/dropped connection) as a retryable {@link TransientError},
92
- * so the store's read retry can ride it out and a write's caller can tell it from a deterministic failure;
93
- * everything else propagates unchanged. The final fallback at every `client.send` site, so callers and the
94
- * read retry only ever see typed errors.
93
+ * Reclassify a transient S3 fault (throttle/5xx/dropped connection) as a retryable {@link TransientError}, so the
94
+ * store's read retry can ride it out and a write's caller can tell it from a deterministic failure, and a missing
95
+ * bucket as a `ValidationError` that names it; everything else propagates unchanged. The final fallback at every
96
+ * `client.send` site, so callers and the read retry only ever see typed errors.
95
97
  */
96
98
  private mapError;
97
99
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudbitmaps/s3",
3
- "version": "0.20.0",
3
+ "version": "0.21.0",
4
4
  "description": "S3 and S3-compatible storage (R2, MinIO, Ceph, Wasabi, B2) for CloudBitmaps",
5
5
  "keywords": [
6
6
  "cloudbitmaps",
@@ -53,7 +53,7 @@
53
53
  },
54
54
  "dependencies": {
55
55
  "@aws-sdk/client-s3": ">=3.700.0 <4",
56
- "@cloudbitmaps/core": "^0.20.0"
56
+ "@cloudbitmaps/core": "^0.21.0"
57
57
  },
58
58
  "devDependencies": {
59
59
  "@types/node": "^22.0.0",
package/dist/keys.d.ts DELETED
@@ -1,17 +0,0 @@
1
- import type { GenKey, SegmentRef } from '@cloudbitmaps/core/driver-kit';
2
- /** Validate a caller-supplied key prefix. The rule is shared with every other object store. */
3
- export { normalizeObjectPrefix as normalizeS3Prefix } from '@cloudbitmaps/core/driver-kit';
4
- /**
5
- * The S3 key prefix shared by all of a segment's generations: `<prefix><ns>/segments/<segment>.`. Used
6
- * both as the `ListObjectsV2` prefix and as the string stripped by {@link parseGenerationFromKey}.
7
- */
8
- export declare function segmentObjectPrefix(prefix: string | undefined, ref: SegmentRef): string;
9
- /** The full S3 key of one `.crbm` generation: `<segmentPrefix><gen>.crbm`. */
10
- export declare function storageObjectKey(prefix: string | undefined, key: GenKey): string;
11
- /**
12
- * Parse a generation number out of a full object key, given its segment prefix, or `null` if it doesn't
13
- * match. Canonical decimal only — no leading zeros (so `…s.07.crbm` can't alias `…s.7.crbm`) and within
14
- * safe-integer range. This also rejects a *different* segment whose name merely shares the prefix (e.g. a
15
- * key for segment `s.x` won't parse under segment `s`'s prefix, since its middle isn't all digits).
16
- */
17
- export declare function parseGenerationFromKey(segmentPrefix: string, objectKey: string): number | null;