@panorama-industries/effect-vercel-blob 0.0.0 → 0.3.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.
Files changed (143) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +33 -1
  3. package/dist/client.d.ts +8 -0
  4. package/dist/client.d.ts.map +1 -0
  5. package/dist/client.js +8 -0
  6. package/dist/client.js.map +1 -0
  7. package/dist/contracts/blob-client.d.ts +67 -0
  8. package/dist/contracts/blob-client.d.ts.map +1 -0
  9. package/dist/contracts/blob-client.js +11 -0
  10. package/dist/contracts/blob-client.js.map +1 -0
  11. package/dist/contracts/blob-config.d.ts +114 -0
  12. package/dist/contracts/blob-config.d.ts.map +1 -0
  13. package/dist/contracts/blob-config.js +7 -0
  14. package/dist/contracts/blob-config.js.map +1 -0
  15. package/dist/contracts/blob-domain.d.ts +336 -0
  16. package/dist/contracts/blob-domain.d.ts.map +1 -0
  17. package/dist/contracts/blob-domain.js +152 -0
  18. package/dist/contracts/blob-domain.js.map +1 -0
  19. package/dist/contracts/blob-errors.d.ts +125 -0
  20. package/dist/contracts/blob-errors.d.ts.map +1 -0
  21. package/dist/contracts/blob-errors.js +114 -0
  22. package/dist/contracts/blob-errors.js.map +1 -0
  23. package/dist/contracts/blob-signed-urls.d.ts +83 -0
  24. package/dist/contracts/blob-signed-urls.d.ts.map +1 -0
  25. package/dist/contracts/blob-signed-urls.js +10 -0
  26. package/dist/contracts/blob-signed-urls.js.map +1 -0
  27. package/dist/contracts/blob-store.d.ts +153 -0
  28. package/dist/contracts/blob-store.d.ts.map +1 -0
  29. package/dist/contracts/blob-store.js +15 -0
  30. package/dist/contracts/blob-store.js.map +1 -0
  31. package/dist/contracts/blob-uploads.d.ts +101 -0
  32. package/dist/contracts/blob-uploads.d.ts.map +1 -0
  33. package/dist/contracts/blob-uploads.js +17 -0
  34. package/dist/contracts/blob-uploads.js.map +1 -0
  35. package/dist/implementation/blob-client-live.d.ts +37 -0
  36. package/dist/implementation/blob-client-live.d.ts.map +1 -0
  37. package/dist/implementation/blob-client-live.js +213 -0
  38. package/dist/implementation/blob-client-live.js.map +1 -0
  39. package/dist/implementation/blob-config-live.d.ts +49 -0
  40. package/dist/implementation/blob-config-live.d.ts.map +1 -0
  41. package/dist/implementation/blob-config-live.js +82 -0
  42. package/dist/implementation/blob-config-live.js.map +1 -0
  43. package/dist/implementation/blob-live.d.ts +26 -0
  44. package/dist/implementation/blob-live.d.ts.map +1 -0
  45. package/dist/implementation/blob-live.js +26 -0
  46. package/dist/implementation/blob-live.js.map +1 -0
  47. package/dist/implementation/blob-signed-urls-live.d.ts +12 -0
  48. package/dist/implementation/blob-signed-urls-live.d.ts.map +1 -0
  49. package/dist/implementation/blob-signed-urls-live.js +92 -0
  50. package/dist/implementation/blob-signed-urls-live.js.map +1 -0
  51. package/dist/implementation/blob-store-live.d.ts +18 -0
  52. package/dist/implementation/blob-store-live.d.ts.map +1 -0
  53. package/dist/implementation/blob-store-live.js +364 -0
  54. package/dist/implementation/blob-store-live.js.map +1 -0
  55. package/dist/implementation/blob-uploads-live.d.ts +11 -0
  56. package/dist/implementation/blob-uploads-live.d.ts.map +1 -0
  57. package/dist/implementation/blob-uploads-live.js +218 -0
  58. package/dist/implementation/blob-uploads-live.js.map +1 -0
  59. package/dist/index.d.ts +15 -0
  60. package/dist/index.d.ts.map +1 -0
  61. package/dist/index.js +15 -0
  62. package/dist/index.js.map +1 -0
  63. package/dist/internal/blob-errors.d.ts +79 -0
  64. package/dist/internal/blob-errors.d.ts.map +1 -0
  65. package/dist/internal/blob-errors.js +196 -0
  66. package/dist/internal/blob-errors.js.map +1 -0
  67. package/dist/internal/blob-request.d.ts +255 -0
  68. package/dist/internal/blob-request.d.ts.map +1 -0
  69. package/dist/internal/blob-request.js +291 -0
  70. package/dist/internal/blob-request.js.map +1 -0
  71. package/dist/internal/callback.d.ts +70 -0
  72. package/dist/internal/callback.d.ts.map +1 -0
  73. package/dist/internal/callback.js +141 -0
  74. package/dist/internal/callback.js.map +1 -0
  75. package/dist/internal/client-token.d.ts +65 -0
  76. package/dist/internal/client-token.d.ts.map +1 -0
  77. package/dist/internal/client-token.js +80 -0
  78. package/dist/internal/client-token.js.map +1 -0
  79. package/dist/internal/env.d.ts +34 -0
  80. package/dist/internal/env.d.ts.map +1 -0
  81. package/dist/internal/env.js +61 -0
  82. package/dist/internal/env.js.map +1 -0
  83. package/dist/internal/multipart.d.ts +110 -0
  84. package/dist/internal/multipart.d.ts.map +1 -0
  85. package/dist/internal/multipart.js +290 -0
  86. package/dist/internal/multipart.js.map +1 -0
  87. package/dist/internal/presign.d.ts +123 -0
  88. package/dist/internal/presign.d.ts.map +1 -0
  89. package/dist/internal/presign.js +345 -0
  90. package/dist/internal/presign.js.map +1 -0
  91. package/dist/internal/store-id.d.ts +38 -0
  92. package/dist/internal/store-id.d.ts.map +1 -0
  93. package/dist/internal/store-id.js +54 -0
  94. package/dist/internal/store-id.js.map +1 -0
  95. package/dist/internal/urls.d.ts +26 -0
  96. package/dist/internal/urls.d.ts.map +1 -0
  97. package/dist/internal/urls.js +33 -0
  98. package/dist/internal/urls.js.map +1 -0
  99. package/dist/internal/wire.d.ts +55 -0
  100. package/dist/internal/wire.d.ts.map +1 -0
  101. package/dist/internal/wire.js +64 -0
  102. package/dist/internal/wire.js.map +1 -0
  103. package/dist/internal/write-headers.d.ts +56 -0
  104. package/dist/internal/write-headers.d.ts.map +1 -0
  105. package/dist/internal/write-headers.js +82 -0
  106. package/dist/internal/write-headers.js.map +1 -0
  107. package/dist/testing/index.d.ts +2 -0
  108. package/dist/testing/index.d.ts.map +1 -0
  109. package/dist/testing/index.js +2 -0
  110. package/dist/testing/index.js.map +1 -0
  111. package/dist/testing/test-blob-store.d.ts +134 -0
  112. package/dist/testing/test-blob-store.d.ts.map +1 -0
  113. package/dist/testing/test-blob-store.js +718 -0
  114. package/dist/testing/test-blob-store.js.map +1 -0
  115. package/package.json +58 -4
  116. package/src/client.ts +11 -0
  117. package/src/contracts/blob-client.ts +121 -0
  118. package/src/contracts/blob-config.ts +64 -0
  119. package/src/contracts/blob-domain.ts +304 -0
  120. package/src/contracts/blob-errors.ts +161 -0
  121. package/src/contracts/blob-signed-urls.ts +112 -0
  122. package/src/contracts/blob-store.ts +258 -0
  123. package/src/contracts/blob-uploads.ts +151 -0
  124. package/src/implementation/blob-client-live.ts +387 -0
  125. package/src/implementation/blob-config-live.ts +145 -0
  126. package/src/implementation/blob-live.ts +55 -0
  127. package/src/implementation/blob-signed-urls-live.ts +121 -0
  128. package/src/implementation/blob-store-live.ts +528 -0
  129. package/src/implementation/blob-uploads-live.ts +326 -0
  130. package/src/index.ts +18 -0
  131. package/src/internal/blob-errors.ts +325 -0
  132. package/src/internal/blob-request.ts +617 -0
  133. package/src/internal/callback.ts +200 -0
  134. package/src/internal/client-token.ts +132 -0
  135. package/src/internal/env.ts +128 -0
  136. package/src/internal/multipart.ts +526 -0
  137. package/src/internal/presign.ts +477 -0
  138. package/src/internal/store-id.ts +69 -0
  139. package/src/internal/urls.ts +42 -0
  140. package/src/internal/wire.ts +80 -0
  141. package/src/internal/write-headers.ts +118 -0
  142. package/src/testing/index.ts +1 -0
  143. package/src/testing/test-blob-store.ts +1136 -0
@@ -0,0 +1,15 @@
1
+ export * from "./contracts/blob-config.ts";
2
+ export * from "./contracts/blob-domain.ts";
3
+ export * from "./contracts/blob-errors.ts";
4
+ export * from "./contracts/blob-signed-urls.ts";
5
+ export * from "./contracts/blob-store.ts";
6
+ export * from "./contracts/blob-uploads.ts";
7
+ export { type BlobConfigOptions, BlobConfigLive, blobConfigLayer, } from "./implementation/blob-config-live.ts";
8
+ export { storeIdFromDelegationToken } from "./internal/store-id.ts";
9
+ export { downloadUrl } from "./internal/urls.ts";
10
+ export { BlobStoreLive } from "./implementation/blob-store-live.ts";
11
+ export { BlobSignedUrlsLive } from "./implementation/blob-signed-urls-live.ts";
12
+ export { BlobUploadsLive } from "./implementation/blob-uploads-live.ts";
13
+ export { ClientTokenPayload, getPayloadFromClientToken } from "./internal/client-token.ts";
14
+ export { BlobLive, blobLayer, blobLayerConfig } from "./implementation/blob-live.ts";
15
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,4BAA4B,CAAC;AAC3C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,iCAAiC,CAAC;AAChD,cAAc,2BAA2B,CAAC;AAC1C,cAAc,6BAA6B,CAAC;AAC5C,OAAO,EACL,KAAK,iBAAiB,EACtB,cAAc,EACd,eAAe,GAChB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AACpE,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AACpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,2CAA2C,CAAC;AAC/E,OAAO,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAC;AACxE,OAAO,EAAE,kBAAkB,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AAC3F,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,15 @@
1
+ export * from "./contracts/blob-config.js";
2
+ export * from "./contracts/blob-domain.js";
3
+ export * from "./contracts/blob-errors.js";
4
+ export * from "./contracts/blob-signed-urls.js";
5
+ export * from "./contracts/blob-store.js";
6
+ export * from "./contracts/blob-uploads.js";
7
+ export { BlobConfigLive, blobConfigLayer, } from "./implementation/blob-config-live.js";
8
+ export { storeIdFromDelegationToken } from "./internal/store-id.js";
9
+ export { downloadUrl } from "./internal/urls.js";
10
+ export { BlobStoreLive } from "./implementation/blob-store-live.js";
11
+ export { BlobSignedUrlsLive } from "./implementation/blob-signed-urls-live.js";
12
+ export { BlobUploadsLive } from "./implementation/blob-uploads-live.js";
13
+ export { ClientTokenPayload, getPayloadFromClientToken } from "./internal/client-token.js";
14
+ export { BlobLive, blobLayer, blobLayerConfig } from "./implementation/blob-live.js";
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,4BAA4B,CAAC;AAC3C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,iCAAiC,CAAC;AAChD,cAAc,2BAA2B,CAAC;AAC1C,cAAc,6BAA6B,CAAC;AAC5C,OAAO,EAEL,cAAc,EACd,eAAe,GAChB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AACpE,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AACpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,2CAA2C,CAAC;AAC/E,OAAO,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAC;AACxE,OAAO,EAAE,kBAAkB,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AAC3F,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC"}
@@ -0,0 +1,79 @@
1
+ import type { Headers, HttpClientResponse } from "effect/http";
2
+ import { VercelApiError } from "@panorama-industries/effect-vercel-core";
3
+ import { Effect, Option } from "effect";
4
+ import { BlobClientTokenNotAllowed, BlobNotFound, BlobOidcEnvironmentNotAllowed, BlobPreconditionFailed, BlobStoreUnavailable, BlobUploadRejected } from "../contracts/blob-errors.ts";
5
+ /** Every Blob-specific failure an error response can map to. */
6
+ export type BlobDomainError = BlobNotFound | BlobStoreUnavailable | BlobPreconditionFailed | BlobUploadRejected | BlobClientTokenNotAllowed | BlobOidcEnvironmentNotAllowed;
7
+ /** Tag of a {@link BlobDomainError}, used to choose which ones an operation reports. */
8
+ export type BlobDomainErrorTag = BlobDomainError["_tag"];
9
+ /** The domain errors among `K`, plus `VercelApiError` for every other error response. */
10
+ export type BlobApiError<K extends BlobDomainErrorTag = BlobDomainErrorTag> = VercelApiError | Extract<BlobDomainError, {
11
+ readonly _tag: K;
12
+ }>;
13
+ /** An error response (non-2xx) whose body has been read. */
14
+ export interface BlobErrorResponse {
15
+ /** Traced operation name stored in `VercelApiError.operation`, such as `BlobStore.put`. */
16
+ readonly operation: string;
17
+ readonly status: number;
18
+ /** The raw response body; JSON `{"error":{"code","message"}}` when the API produced it. */
19
+ readonly body: string;
20
+ /** Response headers; `Retry-After` is read from them for `rate_limited`. */
21
+ readonly headers: Headers.Headers;
22
+ /** The pathname or URL the call addressed, stored in `BlobNotFound.locator`. */
23
+ readonly locator: string;
24
+ }
25
+ /** What the SDK's `getBlobError` reads from an error body, after its message-based rewrites. */
26
+ export interface BlobErrorCode {
27
+ /** The effective code: `unknown_error` when the body had none or was not JSON. */
28
+ readonly code: string;
29
+ /** The code exactly as the body sent it, if it sent one. */
30
+ readonly bodyCode: Option.Option<string>;
31
+ readonly message: Option.Option<string>;
32
+ }
33
+ /**
34
+ * Read the error code and message from an error body like the SDK's `getBlobError`, including the
35
+ * rewrites it applies to codes older API clients cannot receive: a message about a disallowed
36
+ * `contentType`, a `"pathname"` that does not match the token, `Token expired`, a file length
37
+ * limit, or OIDC being disabled for an environment selects the matching code.
38
+ */
39
+ export declare const blobErrorCode: (body: string) => BlobErrorCode;
40
+ /**
41
+ * The message the store sends with `bad_request`, instead of a dedicated code, when a key does not
42
+ * exist: the source of a copy or rename, or the blob an `ifMatch` write or delete targets.
43
+ */
44
+ export declare const missingKeyMessage = "The specified key does not exist.";
45
+ /**
46
+ * Map an error response to the failure the SDK's `getBlobError` would throw, as a typed error.
47
+ *
48
+ * Domain codes become the errors in `contracts/blob-errors.ts`; `forbidden`, `bad_request` and
49
+ * `rate_limited` become `VercelApiError` with `ApiForbidden`, `ApiBadRequest` and `ApiRateLimited`
50
+ * (with `Retry-After`) whatever the status; every other code becomes the `VercelApiError` matching
51
+ * the status (`vercelApiErrorFromStatus`). `VercelApiError.errorCode` is the code the body sent, if
52
+ * any. A domain code not listed in `domainErrors` is reported as a `VercelApiError` for its status
53
+ * instead, with that code, so an operation only surfaces the domain errors its contract declares.
54
+ *
55
+ * Unlike the SDK, a `bad_request` with {@link missingKeyMessage} becomes `BlobNotFound` for an
56
+ * operation that reports it (a missing copy or rename source), and `BlobPreconditionFailed`
57
+ * otherwise (`ifMatch` on a missing blob, which HTTP treats as a failed precondition).
58
+ *
59
+ * @param now - Current time in epoch milliseconds, to resolve an HTTP-date `Retry-After`.
60
+ * @param domainErrors - Domain errors the operation reports; all of them by default.
61
+ */
62
+ export declare const blobErrorFromResponse: <K extends BlobDomainErrorTag = BlobDomainErrorTag>(response: BlobErrorResponse, now: number, domainErrors?: ReadonlyArray<K>) => BlobApiError<K>;
63
+ /**
64
+ * Read an error response's body and map it with {@link blobErrorFromResponse}. A body that cannot be
65
+ * read counts as not JSON (`unknown_error`).
66
+ */
67
+ export declare const blobErrorFromHttpResponse: <K extends BlobDomainErrorTag = "BlobClientTokenNotAllowed" | "BlobNotFound" | "BlobOidcEnvironmentNotAllowed" | "BlobPreconditionFailed" | "BlobStoreUnavailable" | "BlobUploadRejected">(response: HttpClientResponse.HttpClientResponse, options: {
68
+ readonly operation: string;
69
+ readonly locator: string;
70
+ readonly domainErrors?: ReadonlyArray<K> | undefined;
71
+ }) => Effect.Effect<never, BlobApiError<K>, never>;
72
+ /**
73
+ * Whether the SDK retries a failed attempt: network failures, and error responses whose body code
74
+ * is absent (a body that is not JSON counts as `unknown_error`), `unknown_error`,
75
+ * `service_unavailable` or `internal_server_error`. Never `rate_limited`, a domain error, or any
76
+ * other code. Use it as `vercelApiTransientRetry({ isRetryable })`.
77
+ */
78
+ export declare const isRetryableBlobError: (error: unknown) => boolean;
79
+ //# sourceMappingURL=blob-errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blob-errors.d.ts","sourceRoot":"","sources":["../../src/internal/blob-errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAE/D,OAAO,EAAE,cAAc,EAA4B,MAAM,yCAAyC,CAAC;AACnG,OAAO,EAAS,MAAM,EAAE,MAAM,EAAqB,MAAM,QAAQ,CAAC;AAElE,OAAO,EACL,yBAAyB,EACzB,YAAY,EACZ,6BAA6B,EAC7B,sBAAsB,EAGtB,oBAAoB,EACpB,kBAAkB,EAKnB,MAAM,6BAA6B,CAAC;AAErC,gEAAgE;AAChE,MAAM,MAAM,eAAe,GACvB,YAAY,GACZ,oBAAoB,GACpB,sBAAsB,GACtB,kBAAkB,GAClB,yBAAyB,GACzB,6BAA6B,CAAC;AAElC,wFAAwF;AACxF,MAAM,MAAM,kBAAkB,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;AAEzD,yFAAyF;AACzF,MAAM,MAAM,YAAY,CAAC,CAAC,SAAS,kBAAkB,GAAG,kBAAkB,IACtE,cAAc,GACd,OAAO,CAAC,eAAe,EAAE;IAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;CAAE,CAAC,CAAC;AAEnD,4DAA4D;AAC5D,MAAM,WAAW,iBAAiB;IAChC,2FAA2F;IAC3F,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAE3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAExB,2FAA2F;IAC3F,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,4EAA4E;IAC5E,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC;IAElC,gFAAgF;IAChF,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAeD,gGAAgG;AAChG,MAAM,WAAW,aAAa;IAC5B,kFAAkF;IAClF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,4DAA4D;IAC5D,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAEzC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;CACzC;AAED;;;;;GAKG;AACH,eAAO,MAAM,aAAa,SAAU,MAAM,KAAG,aA6B5C,CAAC;AAIF;;;GAGG;AACH,eAAO,MAAM,iBAAiB,sCAAsC,CAAC;AAsGrE;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,qBAAqB,GAAI,CAAC,SAAS,kBAAkB,GAAG,kBAAkB,YAC3E,iBAAiB,OACtB,MAAM,iBACI,aAAa,CAAC,CAAC,CAAC,KAC9B,YAAY,CAAC,CAAC,CA6BhB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,yBAAyB,GACpC,CAAC,SAAS,kBAAkB;wBAIN,MAAM;sBACR,MAAM;4BACA,aAAa,CAAC,CAAC,CAAC,GAAG,SAAS;kDAkBtD,CAAC;AAQH;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,UAAW,OAAO,KAAG,OAM/C,CAAC"}
@@ -0,0 +1,196 @@
1
+ import { VercelApiError, vercelApiErrorFromStatus } from "@panorama-industries/effect-vercel-core";
2
+ import { Clock, Effect, Option, Predicate, Schema } from "effect";
3
+ import { BlobClientTokenNotAllowed, BlobNotFound, BlobOidcEnvironmentNotAllowed, BlobPreconditionFailed, BlobStoreNotFound, BlobStoreSuspended, BlobStoreUnavailable, BlobUploadRejected, ClientTokenExpired, ContentTypeNotAllowed, FileTooLarge, PathnameMismatch, } from "../contracts/blob-errors.js";
4
+ const ErrorBody = Schema.fromJsonString(Schema.Struct({
5
+ error: Schema.optionalKey(Schema.Struct({
6
+ code: Schema.optionalKey(Schema.String),
7
+ message: Schema.optionalKey(Schema.String),
8
+ })),
9
+ }));
10
+ const decodeErrorBody = Schema.decodeUnknownOption(ErrorBody);
11
+ /**
12
+ * Read the error code and message from an error body like the SDK's `getBlobError`, including the
13
+ * rewrites it applies to codes older API clients cannot receive: a message about a disallowed
14
+ * `contentType`, a `"pathname"` that does not match the token, `Token expired`, a file length
15
+ * limit, or OIDC being disabled for an environment selects the matching code.
16
+ */
17
+ export const blobErrorCode = (body) => {
18
+ const error = Option.flatMap(decodeErrorBody(body), (decoded) => Option.fromUndefinedOr(decoded.error));
19
+ const bodyCode = Option.flatMap(error, (error) => Option.fromUndefinedOr(error.code));
20
+ const message = Option.flatMap(error, (error) => Option.fromUndefinedOr(error.message));
21
+ let code = Option.getOrElse(bodyCode, () => "unknown_error");
22
+ const text = Option.getOrUndefined(message);
23
+ if (text !== undefined) {
24
+ if (text.includes("contentType") && text.includes("is not allowed")) {
25
+ code = "content_type_not_allowed";
26
+ }
27
+ if (text.includes('"pathname"') && text.includes("does not match the token payload")) {
28
+ code = "client_token_pathname_mismatch";
29
+ }
30
+ if (text === "Token expired") {
31
+ code = "client_token_expired";
32
+ }
33
+ if (text.includes("the file length cannot be greater than")) {
34
+ code = "file_too_large";
35
+ }
36
+ if (text.startsWith("OIDC is enabled for this project, but not for the") &&
37
+ text.includes("environment.")) {
38
+ code = "oidc_environment_not_allowed";
39
+ }
40
+ }
41
+ return { code, bodyCode, message };
42
+ };
43
+ const unknownErrorMessage = "Unknown error, please visit https://vercel.com/help.";
44
+ /**
45
+ * The message the store sends with `bad_request`, instead of a dedicated code, when a key does not
46
+ * exist: the source of a copy or rename, or the blob an `ifMatch` write or delete targets.
47
+ */
48
+ export const missingKeyMessage = "The specified key does not exist.";
49
+ const domainError = (code, message, locator) => {
50
+ const text = Option.getOrUndefined(message);
51
+ switch (code) {
52
+ case "not_found":
53
+ return Option.some(new BlobNotFound({ locator }));
54
+ case "store_not_found":
55
+ return Option.some(new BlobStoreUnavailable({ reason: new BlobStoreNotFound() }));
56
+ case "store_suspended":
57
+ return Option.some(new BlobStoreUnavailable({ reason: new BlobStoreSuspended() }));
58
+ case "precondition_failed":
59
+ return Option.some(new BlobPreconditionFailed());
60
+ case "content_type_not_allowed":
61
+ return Option.some(new BlobUploadRejected({
62
+ reason: new ContentTypeNotAllowed({ message: `Content type mismatch, ${text}.` }),
63
+ }));
64
+ case "file_too_large":
65
+ return Option.some(new BlobUploadRejected({
66
+ reason: new FileTooLarge({ message: `File is too large, ${text}.` }),
67
+ }));
68
+ case "client_token_pathname_mismatch":
69
+ return Option.some(new BlobUploadRejected({
70
+ reason: new PathnameMismatch({
71
+ message: `Pathname mismatch, ${text}. Check the pathname used in upload() or put() ` +
72
+ "matches the one from the client token.",
73
+ }),
74
+ }));
75
+ case "client_token_expired":
76
+ return Option.some(new BlobUploadRejected({ reason: new ClientTokenExpired() }));
77
+ case "client_token_not_allowed":
78
+ return Option.some(new BlobClientTokenNotAllowed({
79
+ message: text ??
80
+ "This operation is not available when using a client token. Use a read–write or OIDC token on the server.",
81
+ }));
82
+ case "oidc_environment_not_allowed":
83
+ return Option.some(new BlobOidcEnvironmentNotAllowed({
84
+ message: text ?? "OIDC is enabled for this project, but not for this token's environment.",
85
+ }));
86
+ default:
87
+ return Option.none();
88
+ }
89
+ };
90
+ const rateLimitedMessage = (headers) => {
91
+ const seconds = Number.parseInt(headers["retry-after"] ?? "", 10);
92
+ return `Too many requests please lower the number of concurrent requests${seconds ? ` - try again in ${seconds} seconds` : ""}.`;
93
+ };
94
+ /**
95
+ * The status whose `Api*` reason the SDK's error matches, and that reason's message. Codes the SDK
96
+ * maps regardless of status (`forbidden`, `bad_request`, `rate_limited`) force their status; the
97
+ * rest keep the response's.
98
+ */
99
+ const apiReasonFor = (code, response, message) => {
100
+ const status = response.status;
101
+ switch (code) {
102
+ case "forbidden":
103
+ return {
104
+ status: 403,
105
+ message: "Access denied, please provide a valid token for this resource.",
106
+ };
107
+ case "bad_request":
108
+ return { status: 400, message: Option.getOrElse(message, () => "Bad request") };
109
+ case "rate_limited":
110
+ return {
111
+ status: 429,
112
+ message: rateLimitedMessage(response.headers),
113
+ };
114
+ case "service_unavailable":
115
+ return {
116
+ status,
117
+ message: "The blob service is currently not available. Please try again.",
118
+ };
119
+ default:
120
+ return { status, message: Option.getOrElse(message, () => unknownErrorMessage) };
121
+ }
122
+ };
123
+ /**
124
+ * Map an error response to the failure the SDK's `getBlobError` would throw, as a typed error.
125
+ *
126
+ * Domain codes become the errors in `contracts/blob-errors.ts`; `forbidden`, `bad_request` and
127
+ * `rate_limited` become `VercelApiError` with `ApiForbidden`, `ApiBadRequest` and `ApiRateLimited`
128
+ * (with `Retry-After`) whatever the status; every other code becomes the `VercelApiError` matching
129
+ * the status (`vercelApiErrorFromStatus`). `VercelApiError.errorCode` is the code the body sent, if
130
+ * any. A domain code not listed in `domainErrors` is reported as a `VercelApiError` for its status
131
+ * instead, with that code, so an operation only surfaces the domain errors its contract declares.
132
+ *
133
+ * Unlike the SDK, a `bad_request` with {@link missingKeyMessage} becomes `BlobNotFound` for an
134
+ * operation that reports it (a missing copy or rename source), and `BlobPreconditionFailed`
135
+ * otherwise (`ifMatch` on a missing blob, which HTTP treats as a failed precondition).
136
+ *
137
+ * @param now - Current time in epoch milliseconds, to resolve an HTTP-date `Retry-After`.
138
+ * @param domainErrors - Domain errors the operation reports; all of them by default.
139
+ */
140
+ export const blobErrorFromResponse = (response, now, domainErrors) => {
141
+ const { code, bodyCode, message } = blobErrorCode(response.body);
142
+ const reports = (tag) => domainErrors === undefined || domainErrors.includes(tag);
143
+ if (code === "bad_request" && Option.getOrUndefined(message) === missingKeyMessage) {
144
+ if (reports("BlobNotFound")) {
145
+ return new BlobNotFound({ locator: response.locator });
146
+ }
147
+ if (reports("BlobPreconditionFailed")) {
148
+ return new BlobPreconditionFailed();
149
+ }
150
+ }
151
+ const domain = domainError(code, message, response.locator).pipe(Option.filter((error) => reports(error._tag)));
152
+ if (Option.isSome(domain)) {
153
+ return domain.value;
154
+ }
155
+ const reason = apiReasonFor(code, response, message);
156
+ return vercelApiErrorFromStatus({
157
+ operation: response.operation,
158
+ status: reason.status,
159
+ message: reason.message,
160
+ errorCode: bodyCode,
161
+ headers: response.headers,
162
+ }, now);
163
+ };
164
+ /**
165
+ * Read an error response's body and map it with {@link blobErrorFromResponse}. A body that cannot be
166
+ * read counts as not JSON (`unknown_error`).
167
+ */
168
+ export const blobErrorFromHttpResponse = Effect.fnUntraced(function* (response, options) {
169
+ const body = yield* Effect.orElseSucceed(response.text, () => "");
170
+ const now = yield* Clock.currentTimeMillis;
171
+ return yield* Effect.fail(blobErrorFromResponse({
172
+ operation: options.operation,
173
+ status: response.status,
174
+ body,
175
+ headers: response.headers,
176
+ locator: options.locator,
177
+ }, now, options.domainErrors));
178
+ });
179
+ const retryableCodes = new Set([
180
+ "unknown_error",
181
+ "service_unavailable",
182
+ "internal_server_error",
183
+ ]);
184
+ /**
185
+ * Whether the SDK retries a failed attempt: network failures, and error responses whose body code
186
+ * is absent (a body that is not JSON counts as `unknown_error`), `unknown_error`,
187
+ * `service_unavailable` or `internal_server_error`. Never `rate_limited`, a domain error, or any
188
+ * other code. Use it as `vercelApiTransientRetry({ isRetryable })`.
189
+ */
190
+ export const isRetryableBlobError = (error) => error instanceof VercelApiError &&
191
+ (Predicate.isTagged(error.reason, "ApiNetworkFailure") ||
192
+ Option.match(error.errorCode, {
193
+ onNone: () => true,
194
+ onSome: (code) => retryableCodes.has(code),
195
+ }));
196
+ //# sourceMappingURL=blob-errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blob-errors.js","sourceRoot":"","sources":["../../src/internal/blob-errors.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,255 @@
1
+ import type { OidcTokenUnavailable, VercelOidc } from "@panorama-industries/effect-vercel-core";
2
+ import type { HttpClientResponse } from "effect/http";
3
+ import { VercelApiError } from "@panorama-industries/effect-vercel-core";
4
+ import { Data, Duration, Effect, Redacted, Schema, Stream } from "effect";
5
+ import { HttpClient } from "effect/http";
6
+ import type { BlobConfig } from "../contracts/blob-config.ts";
7
+ import type { BlobBody, OnUploadProgress, PresignedUrlPayload, UploadProgress } from "../contracts/blob-domain.ts";
8
+ import type { BlobApiError, BlobDomainErrorTag } from "./blob-errors.ts";
9
+ /**
10
+ * What every request of one component shares; build it once per layer, from `BlobConfig` with
11
+ * {@link blobRequestSettings} on the server, or from the client options in the browser.
12
+ */
13
+ export interface BlobRequestSettings {
14
+ readonly httpClient: HttpClient.HttpClient;
15
+ /** Blob API base URL; a call's `path` is appended to it after removing trailing slashes. */
16
+ readonly apiUrl: URL;
17
+ /** Sent as `x-api-version`. */
18
+ readonly apiVersion: string;
19
+ /** Retries after the first attempt; a call whose body is a `Stream` makes one attempt only. */
20
+ readonly retries: number;
21
+ /** Send `x-content-length` on every call, not only on calls with upload progress. */
22
+ readonly sendContentLength: boolean;
23
+ /** Sent with every call, after the protocol headers and before the call's own headers. */
24
+ readonly headers: Readonly<Record<string, string>>;
25
+ /**
26
+ * Whether `fetch` can stream request bodies; detected with {@link supportsRequestStreams} when
27
+ * omitted. When false, bodies are sent whole (streams are read into memory first) and upload
28
+ * progress reports only 0 % and 100 %.
29
+ */
30
+ readonly streamRequestBodies?: boolean | undefined;
31
+ }
32
+ /** Settings for server-side services, read from `BlobConfig`. */
33
+ export declare const blobRequestSettings: (config: BlobConfig["Service"], httpClient: HttpClient.HttpClient) => BlobRequestSettings;
34
+ /** How one call authenticates, resolved once per call (before the first attempt). */
35
+ export type BlobRequestAuth = Data.TaggedEnum<{
36
+ /**
37
+ * `authorization: Bearer <token>`, for read-write, OIDC and client tokens. `storeId` goes into
38
+ * `x-vercel-blob-store-id` and the request id.
39
+ */
40
+ Bearer: {
41
+ readonly token: Redacted.Redacted<string>;
42
+ readonly storeId: string;
43
+ };
44
+ /**
45
+ * No `authorization`; the payload's `params`, `vercel-blob-delegation` and
46
+ * `vercel-blob-signature` are set on the query. Take `storeId` from the delegation token with
47
+ * `storeIdFromDelegationToken`.
48
+ */
49
+ Presigned: {
50
+ readonly payload: PresignedUrlPayload;
51
+ readonly storeId: string;
52
+ };
53
+ }>;
54
+ /** Constructors and matchers for {@link BlobRequestAuth}. */
55
+ export declare const BlobRequestAuth: {
56
+ readonly $is: <Tag extends "Bearer" | "Presigned">(tag: Tag) => (u: unknown) => u is Extract<{
57
+ readonly _tag: "Bearer";
58
+ readonly token: Redacted.Redacted<string>;
59
+ readonly storeId: string;
60
+ }, {
61
+ readonly _tag: Tag;
62
+ }> | Extract<{
63
+ readonly _tag: "Presigned";
64
+ readonly payload: PresignedUrlPayload;
65
+ readonly storeId: string;
66
+ }, {
67
+ readonly _tag: Tag;
68
+ }>;
69
+ readonly $match: {
70
+ <Cases extends { readonly [Tag in "Bearer" | "Presigned"]: (args: Extract<{
71
+ readonly _tag: "Bearer";
72
+ readonly token: Redacted.Redacted<string>;
73
+ readonly storeId: string;
74
+ } | {
75
+ readonly _tag: "Presigned";
76
+ readonly payload: PresignedUrlPayload;
77
+ readonly storeId: string;
78
+ }, {
79
+ readonly _tag: Tag;
80
+ }>) => any; }>(cases: Cases): (value: {
81
+ readonly _tag: "Bearer";
82
+ readonly token: Redacted.Redacted<string>;
83
+ readonly storeId: string;
84
+ } | {
85
+ readonly _tag: "Presigned";
86
+ readonly payload: PresignedUrlPayload;
87
+ readonly storeId: string;
88
+ }) => import("effect/Unify").Unify<ReturnType<Cases["Bearer" | "Presigned"]>>;
89
+ <Cases extends { readonly [Tag in "Bearer" | "Presigned"]: (args: Extract<{
90
+ readonly _tag: "Bearer";
91
+ readonly token: Redacted.Redacted<string>;
92
+ readonly storeId: string;
93
+ } | {
94
+ readonly _tag: "Presigned";
95
+ readonly payload: PresignedUrlPayload;
96
+ readonly storeId: string;
97
+ }, {
98
+ readonly _tag: Tag;
99
+ }>) => any; }>(value: {
100
+ readonly _tag: "Bearer";
101
+ readonly token: Redacted.Redacted<string>;
102
+ readonly storeId: string;
103
+ } | {
104
+ readonly _tag: "Presigned";
105
+ readonly payload: PresignedUrlPayload;
106
+ readonly storeId: string;
107
+ }, cases: Cases): import("effect/Unify").Unify<ReturnType<Cases["Bearer" | "Presigned"]>>;
108
+ };
109
+ readonly Bearer: Data.TaggedEnum.ConstructorFrom<{
110
+ readonly _tag: "Bearer";
111
+ readonly token: Redacted.Redacted<string>;
112
+ readonly storeId: string;
113
+ }, "_tag">;
114
+ readonly Presigned: Data.TaggedEnum.ConstructorFrom<{
115
+ readonly _tag: "Presigned";
116
+ readonly payload: PresignedUrlPayload;
117
+ readonly storeId: string;
118
+ }, "_tag">;
119
+ };
120
+ /**
121
+ * The per-call auth of server-side services. `ReadWrite` uses its token. `Oidc` evaluates
122
+ * `VercelOidc.token` on every call; when it is unavailable and `BlobConfig.readWriteToken` is set,
123
+ * the call uses that token and its store id instead, as the SDK falls through to
124
+ * `BLOB_READ_WRITE_TOKEN`. Otherwise it fails with the `OidcTokenUnavailable`.
125
+ */
126
+ export declare const serverBlobAuth: (config: BlobConfig["Service"], oidc: VercelOidc["Service"]) => Effect.Effect<BlobRequestAuth, OidcTokenUnavailable>;
127
+ /** HTTP methods the Blob API uses. */
128
+ export type BlobRequestMethod = "GET" | "PUT" | "POST" | "DELETE";
129
+ /**
130
+ * One Blob API call for {@link BlobRequester} `call`.
131
+ *
132
+ * @template A - Decoded response body; `void` when `response` is omitted.
133
+ * @template E - Failure of a `Stream` body, reported as is (not as a network failure).
134
+ * @template R - Requirements of a `Stream` body.
135
+ * @template EA - Failure of `auth`, such as `OidcTokenUnavailable`.
136
+ * @template K - Domain errors the operation reports; other domain codes become `VercelApiError`.
137
+ */
138
+ export interface BlobApiCall<A, E, R, EA, RA, K extends BlobDomainErrorTag> {
139
+ /** Traced name, such as `BlobStore.put`; stored in `VercelApiError.operation`. */
140
+ readonly operation: string;
141
+ readonly method: BlobRequestMethod;
142
+ /**
143
+ * Path and query appended to the API URL exactly as the SDK appends it: `/?pathname=…` for put,
144
+ * `?url=…` (no slash) for head, `?limit…` for list, `/delete`, `/mpu?pathname=…`. Build queries
145
+ * with `URLSearchParams` so they are encoded like the SDK's.
146
+ */
147
+ readonly path: string;
148
+ readonly auth: Effect.Effect<BlobRequestAuth, EA, RA>;
149
+ /** Decodes the JSON response body (see `internal/wire.ts`); omit to ignore the body. */
150
+ readonly response?: Schema.Decoder<A> | undefined;
151
+ /** Sent last, so they override every other header (including `authorization`). */
152
+ readonly headers?: Readonly<Record<string, string>> | undefined;
153
+ /** Raw request body. Strings, bytes and `Blob`s are resent on retries; streams are not. */
154
+ readonly body?: BlobBody<E, R> | undefined;
155
+ /**
156
+ * A JSON request body, sent as `JSON.stringify(json)` with `content-type: application/json`
157
+ * (before `headers`). Takes precedence over `body`.
158
+ */
159
+ readonly json?: unknown;
160
+ /** What `BlobNotFound.locator` reports for `not_found`; defaults to `path`. */
161
+ readonly locator?: string | undefined;
162
+ /** Domain errors the operation surfaces; all by default. See `blobErrorFromResponse`. */
163
+ readonly domainErrors?: ReadonlyArray<K> | undefined;
164
+ /**
165
+ * Upload progress, reported as the SDK does: `{ loaded: 0, total, percentage: 0 }` before the
166
+ * first attempt, then once per 64 KiB chunk sent (never 100 % while waiting for the response),
167
+ * then `{ loaded, total: loaded, percentage: 100 }` once a successful response arrived. Also sends
168
+ * `x-content-length`. Where `fetch` cannot stream request bodies, only the first and last events
169
+ * are reported.
170
+ */
171
+ readonly onUploadProgress?: OnUploadProgress | undefined;
172
+ /**
173
+ * Minimum time between chunk events (leading and trailing edge, like `throttleit`); the SDK uses
174
+ * 100 ms for `put`. The first and last events are never delayed. Unthrottled when omitted.
175
+ */
176
+ readonly progressInterval?: Duration.Input | undefined;
177
+ }
178
+ /** A GET on a blob's own URL, for `get`: no Blob API headers, no retries. */
179
+ export interface BlobFetchRequest {
180
+ /** Traced name, such as `BlobStore.get`; stored in `VercelApiError.operation`. */
181
+ readonly operation: string;
182
+ readonly url: URL;
183
+ /** Sent as `authorization: Bearer <token>`. */
184
+ readonly token: Redacted.Redacted<string>;
185
+ /** Sent after `authorization`, so they override it; put `if-none-match` here. */
186
+ readonly headers?: Readonly<Record<string, string>> | undefined;
187
+ }
188
+ /** Executes Blob API calls with the SDK's headers, retries, error mapping and progress. */
189
+ export interface BlobRequester {
190
+ /**
191
+ * Send one API call, retrying it like the SDK's `requestApi`, and decode the response.
192
+ *
193
+ * Every attempt carries `x-api-blob-request-id` (`<storeId>:<epoch ms>:<random hex>`, the same
194
+ * for all attempts), `x-api-blob-request-attempt` (`0`, `1`, …), `x-api-version`,
195
+ * `x-vercel-blob-store-id`, `authorization` for bearer auth, `x-content-length` with progress or
196
+ * `sendContentLength`, then the settings' headers, then the call's headers. Network failures and
197
+ * retryable error codes (`isRetryableBlobError`) are retried up to `retries` times with
198
+ * exponential backoff from 1 second; a `Stream` body is sent once.
199
+ *
200
+ * @returns The decoded body; fails with `VercelApiError` (`ApiNetworkFailure` for transport
201
+ * failures, `ApiUnexpectedResponse` for a body `response` cannot decode), a domain error among
202
+ * `domainErrors`, the auth effect's error, or the body stream's error.
203
+ */
204
+ readonly call: <A = void, E = never, R = never, EA = never, RA = never, K extends BlobDomainErrorTag = BlobDomainErrorTag>(call: BlobApiCall<A, E, R, EA, RA, K>) => Effect.Effect<A, BlobApiError<K> | E | EA, R | RA>;
205
+ /**
206
+ * Send a GET to a blob URL and return the response whatever its status; the caller maps 304,
207
+ * 404 and other statuses. Transport failures are `VercelApiError` / `ApiNetworkFailure`.
208
+ */
209
+ readonly fetch: (request: BlobFetchRequest) => Effect.Effect<HttpClientResponse.HttpClientResponse, VercelApiError>;
210
+ }
211
+ /** Size of the chunks a progress-tracked body is sent in, as the SDK's `CHUNK_SIZE`. */
212
+ export declare const progressChunkSize: number;
213
+ /**
214
+ * Regroup a byte stream into chunks of exactly `size` bytes, the last one possibly smaller, like
215
+ * the SDK's `createChunkTransformStream`. Empty input chunks produce nothing.
216
+ */
217
+ export declare const chunkBytes: (size: number) => <E, R>(stream: Stream.Stream<Uint8Array, E, R>) => Stream.Stream<Uint8Array, E, R>;
218
+ /**
219
+ * Bytes a body will send when known up front, as the SDK's `computeBodyLength`: UTF-8 length of a
220
+ * string, byte length, `Blob` size; 0 for a stream.
221
+ */
222
+ export declare const bodyLength: <E, R>(body: BlobBody<E, R>) => number;
223
+ /** A body as a stream of bytes. A `Blob` that cannot be read is a defect. */
224
+ export declare const bodyStream: <E, R>(body: BlobBody<E, R>) => Stream.Stream<Uint8Array, E, R>;
225
+ /**
226
+ * Whether `fetch` can stream a request body here, detected like the SDK's
227
+ * `supportsRequestStreams`: always on Node; never against `http://localhost` (no HTTP/2); otherwise
228
+ * when `Request` reads the `duplex` option and does not type a stream body (Chromium, Edge
229
+ * runtimes, not Safari or Firefox).
230
+ */
231
+ export declare const supportsRequestStreams: (apiUrl: string) => boolean;
232
+ /** Delivers progress events, possibly throttled; see {@link uploadProgressThrottle}. */
233
+ export interface UploadProgressReporter {
234
+ readonly report: (progress: UploadProgress) => Effect.Effect<void>;
235
+ /** Drop any event still waiting for its interval and stop reporting. */
236
+ readonly stop: Effect.Effect<void>;
237
+ }
238
+ /**
239
+ * Throttle progress events like `throttleit`, which the SDK wraps `onUploadProgress` in: the first
240
+ * event after a quiet interval is reported at once, later ones at most once per `interval`, and the
241
+ * latest event of an interval is reported when it ends (earlier ones are dropped).
242
+ *
243
+ * The interval starts now, as if an event had just been reported (callers report 0 % first). Call
244
+ * `stop` before the final 100 % event, which callers report directly so it is never delayed.
245
+ * Without an interval (or a zero one), events are reported immediately.
246
+ */
247
+ export declare const uploadProgressThrottle: (onUploadProgress: OnUploadProgress, interval: Duration.Input | undefined) => Effect.Effect<UploadProgressReporter, never, never>;
248
+ /**
249
+ * Build the {@link BlobRequester} that every service uses for Blob API calls.
250
+ *
251
+ * Requests carry no `traceparent`/`b3` headers (the SDK sends none, and browsers would need CORS
252
+ * approval for them); the HTTP client still records a span per attempt.
253
+ */
254
+ export declare const blobRequester: (settings: BlobRequestSettings) => BlobRequester;
255
+ //# sourceMappingURL=blob-request.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blob-request.d.ts","sourceRoot":"","sources":["../../src/internal/blob-request.ts"],"names":[],"mappings":"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"}