partial-content 1.0.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 (81) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/LICENSE +21 -0
  3. package/README.md +601 -0
  4. package/SECURITY.md +92 -0
  5. package/dist/azure.d.ts +79 -0
  6. package/dist/azure.d.ts.map +1 -0
  7. package/dist/azure.js +251 -0
  8. package/dist/azure.js.map +1 -0
  9. package/dist/content-disposition.d.ts +74 -0
  10. package/dist/content-disposition.d.ts.map +1 -0
  11. package/dist/content-disposition.js +253 -0
  12. package/dist/content-disposition.js.map +1 -0
  13. package/dist/fs.d.ts +86 -0
  14. package/dist/fs.d.ts.map +1 -0
  15. package/dist/fs.js +375 -0
  16. package/dist/fs.js.map +1 -0
  17. package/dist/gcs.d.ts +72 -0
  18. package/dist/gcs.d.ts.map +1 -0
  19. package/dist/gcs.js +202 -0
  20. package/dist/gcs.js.map +1 -0
  21. package/dist/hono.d.ts +92 -0
  22. package/dist/hono.d.ts.map +1 -0
  23. package/dist/hono.js +61 -0
  24. package/dist/hono.js.map +1 -0
  25. package/dist/http.d.ts +70 -0
  26. package/dist/http.d.ts.map +1 -0
  27. package/dist/http.js +281 -0
  28. package/dist/http.js.map +1 -0
  29. package/dist/index.d.ts +21 -0
  30. package/dist/index.d.ts.map +1 -0
  31. package/dist/index.js +27 -0
  32. package/dist/index.js.map +1 -0
  33. package/dist/kernel.d.ts +541 -0
  34. package/dist/kernel.d.ts.map +1 -0
  35. package/dist/kernel.js +1218 -0
  36. package/dist/kernel.js.map +1 -0
  37. package/dist/memory.d.ts +55 -0
  38. package/dist/memory.d.ts.map +1 -0
  39. package/dist/memory.js +107 -0
  40. package/dist/memory.js.map +1 -0
  41. package/dist/mime.d.ts +49 -0
  42. package/dist/mime.d.ts.map +1 -0
  43. package/dist/mime.js +150 -0
  44. package/dist/mime.js.map +1 -0
  45. package/dist/node.d.ts +84 -0
  46. package/dist/node.d.ts.map +1 -0
  47. package/dist/node.js +215 -0
  48. package/dist/node.js.map +1 -0
  49. package/dist/object-store.d.ts +472 -0
  50. package/dist/object-store.d.ts.map +1 -0
  51. package/dist/object-store.js +335 -0
  52. package/dist/object-store.js.map +1 -0
  53. package/dist/r2.d.ts +94 -0
  54. package/dist/r2.d.ts.map +1 -0
  55. package/dist/r2.js +150 -0
  56. package/dist/r2.js.map +1 -0
  57. package/dist/s3.d.ts +49 -0
  58. package/dist/s3.d.ts.map +1 -0
  59. package/dist/s3.js +263 -0
  60. package/dist/s3.js.map +1 -0
  61. package/dist/web.d.ts +336 -0
  62. package/dist/web.d.ts.map +1 -0
  63. package/dist/web.js +1094 -0
  64. package/dist/web.js.map +1 -0
  65. package/docs/DESIGN.md +426 -0
  66. package/package.json +182 -0
  67. package/src/azure.ts +329 -0
  68. package/src/content-disposition.ts +300 -0
  69. package/src/fs.ts +469 -0
  70. package/src/gcs.ts +290 -0
  71. package/src/hono.ts +123 -0
  72. package/src/http.ts +351 -0
  73. package/src/index.ts +85 -0
  74. package/src/kernel.ts +1498 -0
  75. package/src/memory.ts +148 -0
  76. package/src/mime.ts +160 -0
  77. package/src/node.ts +261 -0
  78. package/src/object-store.ts +665 -0
  79. package/src/r2.ts +232 -0
  80. package/src/s3.ts +324 -0
  81. package/src/web.ts +1603 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gcs.js","sourceRoot":"","sources":["../src/gcs.ts"],"names":[],"mappings":"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"}
package/dist/hono.d.ts ADDED
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Hono middleware adapter for partial-content.
3
+ *
4
+ * Wraps an {@link ObjectStore} into a Hono-compatible middleware that handles
5
+ * the full HTTP file-serving protocol (200, 206, 304, 412, 416, HEAD).
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { Hono } from "hono";
10
+ * import { serveObject } from "partial-content/hono";
11
+ * import { s3Store } from "partial-content/s3";
12
+ *
13
+ * const store = s3Store({ client, bucket: "documents" });
14
+ * const app = new Hono();
15
+ *
16
+ * app.get("/files/:key", serveObject(store, {
17
+ * key: (c) => c.req.param("key"),
18
+ * disposition: "inline",
19
+ * }));
20
+ * ```
21
+ *
22
+ * @packageDocumentation
23
+ */
24
+ import { type ServeObjectOptions } from "./web.js";
25
+ import type { ObjectStore } from "./index.js";
26
+ export type { ServeObjectOptions, ServeContext } from "./web.js";
27
+ export type { ObjectStore } from "./index.js";
28
+ /**
29
+ * Minimal Hono context interface.
30
+ *
31
+ * We declare just enough of the Hono Context shape to avoid a hard
32
+ * dependency on the `hono` package. Users who import `partial-content/hono`
33
+ * will have `hono` installed (it's an optional peer dep), but we don't
34
+ * want to force TypeScript resolution on it at build time for the
35
+ * published package.
36
+ */
37
+ interface HonoContext {
38
+ req: {
39
+ raw: Request;
40
+ param: (name: string) => string;
41
+ header: (name: string) => string | undefined;
42
+ method: string;
43
+ };
44
+ }
45
+ /** Hono handler return type. */
46
+ type HonoResponse = Response | Promise<Response>;
47
+ export interface HonoServeOptions extends ServeObjectOptions {
48
+ /**
49
+ * Extract the storage key from the Hono context.
50
+ *
51
+ * @example
52
+ * ```ts
53
+ * key: (c) => c.req.param("key")
54
+ * key: (c) => c.req.param("path")
55
+ * ```
56
+ */
57
+ key: (c: HonoContext) => string | Promise<string>;
58
+ /**
59
+ * Extract the MIME type from the Hono context.
60
+ * When omitted, defaults to "application/octet-stream".
61
+ */
62
+ mime?: (c: HonoContext) => string | undefined;
63
+ /**
64
+ * Extract the filename from the Hono context (for Content-Disposition).
65
+ * When omitted, no filename is set.
66
+ */
67
+ filename?: (c: HonoContext) => string | undefined;
68
+ }
69
+ /**
70
+ * Create a Hono middleware handler that serves files from an {@link ObjectStore}.
71
+ *
72
+ * Uses the standard Request/Response API under the hood, so it works on
73
+ * all Hono runtimes (Cloudflare Workers, Bun, Deno, Node.js).
74
+ *
75
+ * @example
76
+ * ```typescript
77
+ * import { Hono } from "hono";
78
+ * import { serveObject } from "partial-content/hono";
79
+ * import { s3Store } from "partial-content/s3";
80
+ *
81
+ * const app = new Hono();
82
+ * const store = s3Store({ client, bucket: "media" });
83
+ *
84
+ * app.get("/media/:key", serveObject(store, {
85
+ * key: (c) => c.req.param("key"),
86
+ * disposition: "inline",
87
+ * cacheControl: "public, max-age=31536000, immutable",
88
+ * }));
89
+ * ```
90
+ */
91
+ export declare function serveObject(store: ObjectStore, opts: HonoServeOptions): (c: HonoContext) => HonoResponse;
92
+ //# sourceMappingURL=hono.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hono.d.ts","sourceRoot":"","sources":["../src/hono.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAiC,KAAK,kBAAkB,EAAqB,MAAM,UAAU,CAAC;AACrG,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAG9C,YAAY,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACjE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAI9C;;;;;;;;GAQG;AACH,UAAU,WAAW;IACnB,GAAG,EAAE;QACH,GAAG,EAAE,OAAO,CAAC;QACb,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;QAChC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;QAC7C,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;CACH;AAED,gCAAgC;AAChC,KAAK,YAAY,GAAG,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;AAIjD,MAAM,WAAW,gBAAiB,SAAQ,kBAAkB;IAC1D;;;;;;;;OAQG;IACH,GAAG,EAAE,CAAC,CAAC,EAAE,WAAW,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAElD;;;OAGG;IACH,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,WAAW,KAAK,MAAM,GAAG,SAAS,CAAC;IAE9C;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,CAAC,EAAE,WAAW,KAAK,MAAM,GAAG,SAAS,CAAC;CACnD;AAID;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,WAAW,EAClB,IAAI,EAAE,gBAAgB,GACrB,CAAC,CAAC,EAAE,WAAW,KAAK,YAAY,CAclC"}
package/dist/hono.js ADDED
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Hono middleware adapter for partial-content.
3
+ *
4
+ * Wraps an {@link ObjectStore} into a Hono-compatible middleware that handles
5
+ * the full HTTP file-serving protocol (200, 206, 304, 412, 416, HEAD).
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { Hono } from "hono";
10
+ * import { serveObject } from "partial-content/hono";
11
+ * import { s3Store } from "partial-content/s3";
12
+ *
13
+ * const store = s3Store({ client, bucket: "documents" });
14
+ * const app = new Hono();
15
+ *
16
+ * app.get("/files/:key", serveObject(store, {
17
+ * key: (c) => c.req.param("key"),
18
+ * disposition: "inline",
19
+ * }));
20
+ * ```
21
+ *
22
+ * @packageDocumentation
23
+ */
24
+ import { serveObject as serveObjectWeb } from "./web.js";
25
+ // ─── Factory ────────────────────────────────────────────────────────────────
26
+ /**
27
+ * Create a Hono middleware handler that serves files from an {@link ObjectStore}.
28
+ *
29
+ * Uses the standard Request/Response API under the hood, so it works on
30
+ * all Hono runtimes (Cloudflare Workers, Bun, Deno, Node.js).
31
+ *
32
+ * @example
33
+ * ```typescript
34
+ * import { Hono } from "hono";
35
+ * import { serveObject } from "partial-content/hono";
36
+ * import { s3Store } from "partial-content/s3";
37
+ *
38
+ * const app = new Hono();
39
+ * const store = s3Store({ client, bucket: "media" });
40
+ *
41
+ * app.get("/media/:key", serveObject(store, {
42
+ * key: (c) => c.req.param("key"),
43
+ * disposition: "inline",
44
+ * cacheControl: "public, max-age=31536000, immutable",
45
+ * }));
46
+ * ```
47
+ */
48
+ export function serveObject(store, opts) {
49
+ const { key: keyFn, mime: mimeFn, filename: filenameFn, ...serveOpts } = opts;
50
+ const handler = serveObjectWeb(store, serveOpts);
51
+ return async function honoHandler(c) {
52
+ const key = await keyFn(c);
53
+ const ctx = {
54
+ key,
55
+ mime: mimeFn?.(c),
56
+ filename: filenameFn?.(c),
57
+ };
58
+ return handler(c.req.raw, ctx);
59
+ };
60
+ }
61
+ //# sourceMappingURL=hono.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hono.js","sourceRoot":"","sources":["../src/hono.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,WAAW,IAAI,cAAc,EAA8C,MAAM,UAAU,CAAC;AAyDrG,+EAA+E;AAE/E;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,WAAW,CACzB,KAAkB,EAClB,IAAsB;IAEtB,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,SAAS,EAAE,GAAG,IAAI,CAAC;IAC9E,MAAM,OAAO,GAAG,cAAc,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;IAEjD,OAAO,KAAK,UAAU,WAAW,CAAC,CAAc;QAC9C,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;QAC3B,MAAM,GAAG,GAAiB;YACxB,GAAG;YACH,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;YACjB,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC;SAC1B,CAAC;QAEF,OAAO,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACjC,CAAC,CAAC;AACJ,CAAC"}
package/dist/http.d.ts ADDED
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Generic HTTP ObjectStore adapter for partial-content.
3
+ *
4
+ * Serves from ANY range-capable HTTP origin using plain `fetch`: Supabase
5
+ * Storage, S3/GCS/Azure presigned URLs, CDN origins, internal file services,
6
+ * or another partial-content server. Zero dependencies, every runtime.
7
+ *
8
+ * Capabilities mapped straight onto HTTP semantics:
9
+ * - `headObject` -> `HEAD` (metadata from Content-Length / ETag / Last-Modified)
10
+ * - `getObject` -> `GET` with `Range: bytes=...`
11
+ * - Pinned reads -> `If-Match` (origin 412 becomes {@link ObjectChangedError})
12
+ * - RFC 9530 -> `Repr-Digest: sha-256=:...:` response header is extracted
13
+ *
14
+ * Caveats:
15
+ * - The origin must send `Content-Length` (range-capable origins always do).
16
+ * - Presigned URLs are signed per-method: a GET-presigned URL will reject the
17
+ * HEAD probe. Presign both methods in `url()` (it receives the key only;
18
+ * return method-agnostic URLs, or front the origin with a service that
19
+ * accepts both).
20
+ * - Origins that ignore `If-Match` are still safe: the web adapter's
21
+ * response-side guard (actual Content-Range + GET validators) remains.
22
+ *
23
+ * @example Supabase Storage (authenticated)
24
+ * ```typescript
25
+ * import { httpStore } from "partial-content/http";
26
+ * import { serveObject } from "partial-content/web";
27
+ *
28
+ * const store = httpStore({
29
+ * url: (key) => `${SUPABASE_URL}/storage/v1/object/documents/${key}`,
30
+ * headers: { Authorization: `Bearer ${serviceRoleKey}` },
31
+ * });
32
+ *
33
+ * export const GET = serveObject(store, { disposition: "inline" });
34
+ * ```
35
+ *
36
+ * @packageDocumentation
37
+ */
38
+ import { ObjectNotFoundError, ObjectChangedError, StoreUnavailableError, type ObjectStore } from "./index.js";
39
+ export { ObjectNotFoundError, ObjectChangedError, StoreUnavailableError };
40
+ export interface HttpStoreOptions {
41
+ /** Build the absolute URL for a storage key. */
42
+ url: (key: string) => string | URL;
43
+ /**
44
+ * Request headers (e.g. Authorization). A static record, or a function of
45
+ * the key for per-object credentials.
46
+ */
47
+ headers?: Record<string, string> | ((key: string) => Record<string, string>);
48
+ /**
49
+ * Fetch implementation. Defaults to the global `fetch`.
50
+ * Inject for testing or to add retries/instrumentation. This is also the
51
+ * SSRF hook: when `url()` incorporates untrusted input, supply a fetch
52
+ * that validates resolved addresses (see SECURITY.md).
53
+ */
54
+ fetch?: typeof globalThis.fetch;
55
+ /**
56
+ * Redirect policy for origin requests. Defaults to `"error"`: a serving layer
57
+ * whose `url()` may incorporate untrusted keys must not let a compromised or
58
+ * misconfigured origin bounce the store to internal endpoints (cloud metadata
59
+ * IPs) via a 3xx. Object-storage origins answer GET/HEAD with a direct 200, so
60
+ * the safe default costs nothing there. Set `"follow"` explicitly for origins
61
+ * that legitimately redirect (some presigned-URL or CDN front-door flows);
62
+ * pair it with a validating `fetch` (see SECURITY.md) when keys are untrusted.
63
+ */
64
+ redirect?: "follow" | "error" | "manual";
65
+ }
66
+ /**
67
+ * Create an {@link ObjectStore} backed by any range-capable HTTP origin.
68
+ */
69
+ export declare function httpStore(opts: HttpStoreOptions): ObjectStore;
70
+ //# sourceMappingURL=http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,qBAAqB,EAIrB,KAAK,WAAW,EAIjB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,CAAC;AAI1E,MAAM,WAAW,gBAAgB;IAC/B,gDAAgD;IAChD,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,GAAG,GAAG,CAAC;IACnC;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC7E;;;;;OAKG;IACH,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAChC;;;;;;;;OAQG;IACH,QAAQ,CAAC,EAAE,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAAC;CAC1C;AAID;;GAEG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,gBAAgB,GAAG,WAAW,CA8K7D"}
package/dist/http.js ADDED
@@ -0,0 +1,281 @@
1
+ /**
2
+ * Generic HTTP ObjectStore adapter for partial-content.
3
+ *
4
+ * Serves from ANY range-capable HTTP origin using plain `fetch`: Supabase
5
+ * Storage, S3/GCS/Azure presigned URLs, CDN origins, internal file services,
6
+ * or another partial-content server. Zero dependencies, every runtime.
7
+ *
8
+ * Capabilities mapped straight onto HTTP semantics:
9
+ * - `headObject` -> `HEAD` (metadata from Content-Length / ETag / Last-Modified)
10
+ * - `getObject` -> `GET` with `Range: bytes=...`
11
+ * - Pinned reads -> `If-Match` (origin 412 becomes {@link ObjectChangedError})
12
+ * - RFC 9530 -> `Repr-Digest: sha-256=:...:` response header is extracted
13
+ *
14
+ * Caveats:
15
+ * - The origin must send `Content-Length` (range-capable origins always do).
16
+ * - Presigned URLs are signed per-method: a GET-presigned URL will reject the
17
+ * HEAD probe. Presign both methods in `url()` (it receives the key only;
18
+ * return method-agnostic URLs, or front the origin with a service that
19
+ * accepts both).
20
+ * - Origins that ignore `If-Match` are still safe: the web adapter's
21
+ * response-side guard (actual Content-Range + GET validators) remains.
22
+ *
23
+ * @example Supabase Storage (authenticated)
24
+ * ```typescript
25
+ * import { httpStore } from "partial-content/http";
26
+ * import { serveObject } from "partial-content/web";
27
+ *
28
+ * const store = httpStore({
29
+ * url: (key) => `${SUPABASE_URL}/storage/v1/object/documents/${key}`,
30
+ * headers: { Authorization: `Bearer ${serviceRoleKey}` },
31
+ * });
32
+ *
33
+ * export const GET = serveObject(store, { disposition: "inline" });
34
+ * ```
35
+ *
36
+ * @packageDocumentation
37
+ */
38
+ import { ObjectNotFoundError, ObjectChangedError, StoreUnavailableError, resolveServedRange, parseRetryAfterSeconds, isOpenEndedRange, } from "./index.js";
39
+ // Re-export for convenience
40
+ export { ObjectNotFoundError, ObjectChangedError, StoreUnavailableError };
41
+ // ─── Factory ────────────────────────────────────────────────────────────────
42
+ /**
43
+ * Create an {@link ObjectStore} backed by any range-capable HTTP origin.
44
+ */
45
+ export function httpStore(opts) {
46
+ const doFetch = opts.fetch ?? globalThis.fetch;
47
+ const redirect = opts.redirect ?? "error";
48
+ function requestHeaders(key) {
49
+ const base = typeof opts.headers === "function"
50
+ ? opts.headers(key)
51
+ : opts.headers ?? {};
52
+ return {
53
+ ...base,
54
+ // Byte accounting depends on the origin NOT transparently compressing:
55
+ // a gzip'd body would break Content-Length/Content-Range math. Server
56
+ // runtimes (undici, Bun, Deno, Workers) honor this; identity is also
57
+ // what object-storage origins serve anyway.
58
+ "Accept-Encoding": "identity",
59
+ };
60
+ }
61
+ return {
62
+ supportsRange: true,
63
+ // 206 bounds/total are parsed from the origin's actual Content-Range
64
+ // (an origin ignoring Range degrades to 200): the orchestrator may skip
65
+ // the validating HEAD for plain range requests.
66
+ authoritativeRange: true,
67
+ async headObject(key, headOpts) {
68
+ const response = await doFetch(opts.url(key), {
69
+ method: "HEAD",
70
+ headers: requestHeaders(key),
71
+ signal: headOpts?.signal,
72
+ redirect,
73
+ });
74
+ // HEAD bodies are empty; no need to drain before throwing.
75
+ if (response.status === 404)
76
+ throw new ObjectNotFoundError(key);
77
+ if (isUnavailableStatus(response.status)) {
78
+ throw new StoreUnavailableError(key, { retryAfterSeconds: parseRetryAfter(response) });
79
+ }
80
+ if (!response.ok) {
81
+ throw new Error(`httpStore HEAD ${key} failed: ${response.status}`);
82
+ }
83
+ const headEncoding = nonIdentityEncoding(response);
84
+ if (headEncoding) {
85
+ throw new Error(`httpStore HEAD ${key}: origin returned Content-Encoding: ${headEncoding}; ` +
86
+ `Content-Length would report the compressed size, so range serving requires an identity-coded body`);
87
+ }
88
+ const contentLength = parseSize(response.headers.get("content-length"));
89
+ if (contentLength === undefined) {
90
+ throw new Error(`httpStore HEAD ${key}: origin sent no Content-Length; range serving requires sized responses`);
91
+ }
92
+ return {
93
+ contentLength,
94
+ etag: response.headers.get("etag") ?? undefined,
95
+ lastModified: response.headers.get("last-modified") ?? undefined,
96
+ digest: extractSha256Digest(response.headers.get("repr-digest")),
97
+ };
98
+ },
99
+ async getObject(key, getOpts) {
100
+ const { range, signal, ifMatch } = getOpts ?? {};
101
+ const headers = requestHeaders(key);
102
+ // Open-ended fast-path ranges carry the OPEN_ENDED sentinel end; emit
103
+ // the bare `bytes=a-` form rather than a 16-digit last-byte-pos.
104
+ if (range) {
105
+ headers["Range"] = isOpenEndedRange(range)
106
+ ? `bytes=${range.start}-`
107
+ : `bytes=${range.start}-${range.end}`;
108
+ }
109
+ // Pin the read to the validated representation. Origins that honor
110
+ // If-Match (S3, Azure, nginx, another partial-content server) answer
111
+ // 412 when the object changed; origins that ignore it fall through to
112
+ // the caller's response-side guard. Weak validators are never sent:
113
+ // RFC 9110 mandates strong comparison for If-Match, so a `W/` ETag
114
+ // would be rejected by every compliant origin on every attempt.
115
+ if (ifMatch && !ifMatch.startsWith("W/")) {
116
+ headers["If-Match"] = ifMatch;
117
+ }
118
+ const response = await doFetch(opts.url(key), {
119
+ method: "GET",
120
+ headers,
121
+ signal,
122
+ redirect,
123
+ });
124
+ if (response.status === 404) {
125
+ await drain(response);
126
+ throw new ObjectNotFoundError(key);
127
+ }
128
+ if (response.status === 412) {
129
+ await drain(response);
130
+ throw new ObjectChangedError(key);
131
+ }
132
+ if (isUnavailableStatus(response.status)) {
133
+ const retryAfterSeconds = parseRetryAfter(response);
134
+ await drain(response);
135
+ throw new StoreUnavailableError(key, { retryAfterSeconds });
136
+ }
137
+ if (response.status !== 200 && response.status !== 206) {
138
+ await drain(response);
139
+ throw new Error(`httpStore GET ${key} failed: ${response.status}`);
140
+ }
141
+ // The fetch runtime transparently decodes a compressed body while
142
+ // Content-Length / Content-Range still describe the encoded bytes, so
143
+ // every byte count below would be wrong. Refuse rather than stream a
144
+ // body that disagrees with its own headers.
145
+ const getEncoding = nonIdentityEncoding(response);
146
+ if (getEncoding) {
147
+ await drain(response);
148
+ throw new Error(`httpStore GET ${key}: origin returned Content-Encoding: ${getEncoding}; ` +
149
+ `range and length accounting require an identity-coded body`);
150
+ }
151
+ const headerLength = parseSize(response.headers.get("content-length"));
152
+ let served;
153
+ let contentLength;
154
+ let totalSize;
155
+ if (response.status === 206) {
156
+ // A 206 MUST carry a parseable single-range Content-Range; without
157
+ // one the body's bounds are unknowable and serving it as anything
158
+ // would silently truncate or corrupt the client's view.
159
+ const contentRangeHeader = response.headers.get("content-range");
160
+ const resolved = contentRangeHeader ? resolveServedRange(contentRangeHeader) : null;
161
+ if (!resolved) {
162
+ await drain(response);
163
+ throw new Error(`httpStore GET ${key}: origin sent 206 with ${contentRangeHeader ? `unparseable Content-Range "${contentRangeHeader}"` : "no Content-Range"}`);
164
+ }
165
+ served = resolved.served;
166
+ // Content-Length, or derived from the actual Content-Range when the
167
+ // origin streams chunked 206s.
168
+ contentLength = headerLength ?? (resolved.served.end - resolved.served.start + 1);
169
+ // A proxied origin streaming a generated/transcoded body legitimately
170
+ // does not know its full length and sends `bytes a-b/*` (the resolver's
171
+ // `undefined` total). Propagate that so the served response repeats `*`
172
+ // honestly instead of fabricating a total that would draw a spurious
173
+ // 416 on a later range past the invented end.
174
+ totalSize = resolved.totalSize;
175
+ }
176
+ else {
177
+ if (headerLength === undefined) {
178
+ await drain(response);
179
+ throw new Error(`httpStore GET ${key}: origin sent no Content-Length; range serving requires sized responses`);
180
+ }
181
+ contentLength = headerLength;
182
+ totalSize = contentLength;
183
+ }
184
+ return {
185
+ body: response.body ?? emptyStream(),
186
+ contentLength,
187
+ totalSize,
188
+ range: served,
189
+ etag: response.headers.get("etag") ?? undefined,
190
+ lastModified: response.headers.get("last-modified") ?? undefined,
191
+ digest: extractSha256Digest(response.headers.get("repr-digest")),
192
+ };
193
+ },
194
+ };
195
+ }
196
+ // ─── Internal Helpers ───────────────────────────────────────────────────────
197
+ /**
198
+ * Return the response's `Content-Encoding` when the origin transfer-compressed
199
+ * the body despite our `Accept-Encoding: identity` request, or `null` when the
200
+ * body is identity-coded. A compressed body is transparently decoded by the
201
+ * fetch runtime, but `Content-Length` keeps reporting the compressed size,
202
+ * which breaks all downstream byte accounting.
203
+ */
204
+ function nonIdentityEncoding(response) {
205
+ const enc = response.headers.get("content-encoding");
206
+ return enc && enc.trim().toLowerCase() !== "identity" ? enc : null;
207
+ }
208
+ /** Parse a Content-Length header into a non-negative integer, or undefined. */
209
+ function parseSize(value) {
210
+ if (!value || !/^\d+$/.test(value.trim()))
211
+ return undefined;
212
+ const n = Number(value.trim());
213
+ return Number.isSafeInteger(n) ? n : undefined;
214
+ }
215
+ /**
216
+ * Whether an origin status means "transiently unavailable, retry" (mapped to
217
+ * a 503, not a 502): `503 Service Unavailable` and `429 Too Many Requests`.
218
+ */
219
+ function isUnavailableStatus(status) {
220
+ return status === 503 || status === 429;
221
+ }
222
+ /**
223
+ * Parse this origin response's `Retry-After` (RFC 9110 Section 10.2.3) into
224
+ * whole seconds via the shared parser: delay-seconds directly, or an HTTP-date
225
+ * as the non-negative delta from now. Returns undefined when absent/unparseable.
226
+ */
227
+ function parseRetryAfter(response) {
228
+ return parseRetryAfterSeconds(response.headers.get("retry-after"), { allowHttpDate: true });
229
+ }
230
+ /**
231
+ * Extract the raw base64 SHA-256 from an RFC 9530 Repr-Digest header
232
+ * (`sha-256=:BASE64:`), or undefined when absent / different algorithm.
233
+ */
234
+ function extractSha256Digest(header) {
235
+ if (!header)
236
+ return undefined;
237
+ const match = /sha-256=:([A-Za-z0-9+/]+=*):/i.exec(header);
238
+ return match ? match[1] : undefined;
239
+ }
240
+ /**
241
+ * Consume up to `maxBytes` of an error/refusal body so the connection can be
242
+ * reused, then cancel. A bare `response.arrayBuffer()` would buffer the ENTIRE
243
+ * body -- and these paths include the malformed-206 and encoding-refusal
244
+ * branches whose body is the real (potentially whole-object) payload, plus the
245
+ * fetch runtime transparently INFLATES a compressed body during buffering. A
246
+ * hostile or misconfigured origin could then drive per-request OOM (a
247
+ * decompression bomb) just to make the adapter throw. Reading a small bounded
248
+ * prefix keeps connection reuse for genuine 404/412 error bodies while capping
249
+ * the cost; anything larger sacrifices one pooled connection, which is cheap.
250
+ */
251
+ async function drain(response, maxBytes = 64 * 1024) {
252
+ const body = response.body;
253
+ if (!body)
254
+ return;
255
+ try {
256
+ const reader = body.getReader();
257
+ let seen = 0;
258
+ for (;;) {
259
+ const { done, value } = await reader.read();
260
+ if (done)
261
+ return;
262
+ seen += value.byteLength;
263
+ if (seen > maxBytes) {
264
+ await reader.cancel();
265
+ return;
266
+ }
267
+ }
268
+ }
269
+ catch {
270
+ // Body already consumed or connection gone; nothing to release.
271
+ }
272
+ }
273
+ /** A closed empty stream for bodyless 200s (zero-byte objects). */
274
+ function emptyStream() {
275
+ return new ReadableStream({
276
+ start(controller) {
277
+ controller.close();
278
+ },
279
+ });
280
+ }
281
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * partial-content
3
+ *
4
+ * RFC-compliant HTTP Range Requests, Conditional Requests, and
5
+ * Content-Disposition. Pure functions, zero dependencies, any runtime.
6
+ *
7
+ * @packageDocumentation
8
+ */
9
+ export { parseRangeHeader, parseContentRange, buildRangeResponseHeaders, build416Headers, OPEN_ENDED, isOpenEndedRange, } from "./kernel.js";
10
+ export { parseRanges, MAX_RANGES_DEFAULT, generateMultipartBoundary, buildMultipartPartHeader, multipartEpilogue, buildMultipartHeaders, } from "./kernel.js";
11
+ export { sanitizeHeaderValue } from "./kernel.js";
12
+ export { isConditionalFresh, isPreconditionFailure, isRangeFresh, build304Headers, build412Headers, evaluateConditionalRequest, evaluateConditionalWrite, } from "./kernel.js";
13
+ export { clientWantsDigest } from "./kernel.js";
14
+ export { generateETag } from "./kernel.js";
15
+ export { fromNodeHeaders } from "./kernel.js";
16
+ export type { ParsedRange, ParsedContentRange, RangeResponseHeaderOpts, RangeResponseHeaders, EvaluatedRequest, EvaluatedWrite, ETagSource, RangeSet, MultipartResponse, } from "./kernel.js";
17
+ export type { CancelSignal, ObjectStore, ObjectMetadata, ObjectStream, ServedRange, ResolvedContentRange, HeadObjectOptions, GetObjectOptions, StoreErrorClassifiers, } from "./object-store.js";
18
+ export { ObjectNotFoundError, ObjectChangedError, StoreUnavailableError, nodeStreamToWeb, guardStreamLength, resolveServedRange, classifyStoreRead, parseRetryAfterSeconds } from "./object-store.js";
19
+ export { buildContentDisposition } from "./content-disposition.js";
20
+ export type { ContentDispositionOptions } from "./content-disposition.js";
21
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,yBAAyB,EACzB,eAAe,EACf,UAAU,EACV,gBAAgB,GACjB,MAAM,aAAa,CAAC;AAGrB,OAAO,EACL,WAAW,EACX,kBAAkB,EAClB,yBAAyB,EACzB,wBAAwB,EACxB,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,aAAa,CAAC;AAGrB,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAGlD,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,YAAY,EACZ,eAAe,EACf,eAAe,EACf,0BAA0B,EAC1B,wBAAwB,GACzB,MAAM,aAAa,CAAC;AAGrB,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAGhD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAG9C,YAAY,EACV,WAAW,EACX,kBAAkB,EAClB,uBAAuB,EACvB,oBAAoB,EACpB,gBAAgB,EAChB,cAAc,EACd,UAAU,EACV,QAAQ,EACR,iBAAiB,GAClB,MAAM,aAAa,CAAC;AAGrB,YAAY,EACV,YAAY,EACZ,WAAW,EACX,cAAc,EACd,YAAY,EACZ,WAAW,EACX,oBAAoB,EACpB,iBAAiB,EACjB,gBAAgB,EAChB,qBAAqB,GACtB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,eAAe,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAGtM,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AACnE,YAAY,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,27 @@
1
+ /**
2
+ * partial-content
3
+ *
4
+ * RFC-compliant HTTP Range Requests, Conditional Requests, and
5
+ * Content-Disposition. Pure functions, zero dependencies, any runtime.
6
+ *
7
+ * @packageDocumentation
8
+ */
9
+ // ─── Range Requests (RFC 7233) ──────────────────────────────────────────────
10
+ export { parseRangeHeader, parseContentRange, buildRangeResponseHeaders, build416Headers, OPEN_ENDED, isOpenEndedRange, } from "./kernel.js";
11
+ // ─── Multiple Ranges (multipart/byteranges) ─────────────────────────────────
12
+ export { parseRanges, MAX_RANGES_DEFAULT, generateMultipartBoundary, buildMultipartPartHeader, multipartEpilogue, buildMultipartHeaders, } from "./kernel.js";
13
+ // ─── Header Safety ──────────────────────────────────────────────────────────
14
+ export { sanitizeHeaderValue } from "./kernel.js";
15
+ // ─── Conditional Requests (RFC 9110 / RFC 7232) ─────────────────────────────
16
+ export { isConditionalFresh, isPreconditionFailure, isRangeFresh, build304Headers, build412Headers, evaluateConditionalRequest, evaluateConditionalWrite, } from "./kernel.js";
17
+ // ─── Digest Negotiation (RFC 9530) ──────────────────────────────────────────
18
+ export { clientWantsDigest } from "./kernel.js";
19
+ // ─── ETag Generation ────────────────────────────────────────────────────────
20
+ export { generateETag } from "./kernel.js";
21
+ // ─── Adapters ───────────────────────────────────────────────────────────────
22
+ export { fromNodeHeaders } from "./kernel.js";
23
+ // ─── Storage Primitives ─────────────────────────────────────────────────────
24
+ export { ObjectNotFoundError, ObjectChangedError, StoreUnavailableError, nodeStreamToWeb, guardStreamLength, resolveServedRange, classifyStoreRead, parseRetryAfterSeconds } from "./object-store.js";
25
+ // ─── Content-Disposition (RFC 6266 / RFC 8187) ──────────────────────────────
26
+ export { buildContentDisposition } from "./content-disposition.js";
27
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,+EAA+E;AAC/E,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,yBAAyB,EACzB,eAAe,EACf,UAAU,EACV,gBAAgB,GACjB,MAAM,aAAa,CAAC;AAErB,+EAA+E;AAC/E,OAAO,EACL,WAAW,EACX,kBAAkB,EAClB,yBAAyB,EACzB,wBAAwB,EACxB,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,aAAa,CAAC;AAErB,+EAA+E;AAC/E,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAElD,+EAA+E;AAC/E,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,YAAY,EACZ,eAAe,EACf,eAAe,EACf,0BAA0B,EAC1B,wBAAwB,GACzB,MAAM,aAAa,CAAC;AAErB,+EAA+E;AAC/E,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,+EAA+E;AAC/E,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,+EAA+E;AAC/E,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AA4B9C,+EAA+E;AAC/E,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,eAAe,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAEtM,+EAA+E;AAC/E,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC"}