@warp-drive-mirror/utilities 5.10.0-alpha.12 → 5.10.0-alpha.13

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 (101) hide show
  1. package/README.md +9 -0
  2. package/cjs-dist/string.cjs +19 -0
  3. package/cjs-dist/string.cjs.map +1 -1
  4. package/dist/active-record.d.ts +21 -0
  5. package/dist/active-record.d.ts.map +1 -1
  6. package/dist/active-record.js +13 -1
  7. package/dist/active-record.js.map +1 -1
  8. package/dist/derivations.d.ts +2 -0
  9. package/dist/derivations.d.ts.map +1 -1
  10. package/dist/derivations.js +6 -0
  11. package/dist/derivations.js.map +1 -1
  12. package/dist/handlers.d.ts +15 -0
  13. package/dist/handlers.d.ts.map +1 -1
  14. package/dist/handlers.js +15 -0
  15. package/dist/handlers.js.map +1 -1
  16. package/dist/{index-D6QIwzqm.d.ts → index-Ds06tKwC.d.ts} +39 -1
  17. package/dist/index-Ds06tKwC.d.ts.map +1 -0
  18. package/dist/index.d.ts +1 -1
  19. package/dist/index.js +39 -0
  20. package/dist/index.js.map +1 -1
  21. package/dist/json-api.d.ts +36 -1
  22. package/dist/json-api.d.ts.map +1 -1
  23. package/dist/json-api.js +23 -1
  24. package/dist/json-api.js.map +1 -1
  25. package/dist/rest.d.ts +20 -0
  26. package/dist/rest.d.ts.map +1 -1
  27. package/dist/rest.js +13 -1
  28. package/dist/rest.js.map +1 -1
  29. package/dist/{string-CWmAluxh.js → string-BZACNuLp.js} +20 -1
  30. package/dist/string-BZACNuLp.js.map +1 -0
  31. package/dist/string.d.ts +19 -0
  32. package/dist/string.d.ts.map +1 -1
  33. package/dist/string.js +1 -1
  34. package/dist/unpkg/dev/active-record.js +13 -1
  35. package/dist/unpkg/dev/active-record.js.map +1 -1
  36. package/dist/unpkg/dev/derivations.js +6 -0
  37. package/dist/unpkg/dev/derivations.js.map +1 -1
  38. package/dist/unpkg/dev/handlers.js +15 -0
  39. package/dist/unpkg/dev/handlers.js.map +1 -1
  40. package/dist/unpkg/dev/index.js +39 -0
  41. package/dist/unpkg/dev/index.js.map +1 -1
  42. package/dist/unpkg/dev/json-api.js +23 -1
  43. package/dist/unpkg/dev/json-api.js.map +1 -1
  44. package/dist/unpkg/dev/rest.js +13 -1
  45. package/dist/unpkg/dev/rest.js.map +1 -1
  46. package/dist/unpkg/dev/{string-j4ur-TDs.js → string-I8KHJXV7.js} +20 -1
  47. package/dist/unpkg/dev/string-I8KHJXV7.js.map +1 -0
  48. package/dist/unpkg/dev/string.js +1 -1
  49. package/dist/unpkg/dev-deprecated/active-record.js +13 -1
  50. package/dist/unpkg/dev-deprecated/active-record.js.map +1 -1
  51. package/dist/unpkg/dev-deprecated/derivations.js +6 -0
  52. package/dist/unpkg/dev-deprecated/derivations.js.map +1 -1
  53. package/dist/unpkg/dev-deprecated/handlers.js +15 -0
  54. package/dist/unpkg/dev-deprecated/handlers.js.map +1 -1
  55. package/dist/unpkg/dev-deprecated/index.js +39 -0
  56. package/dist/unpkg/dev-deprecated/index.js.map +1 -1
  57. package/dist/unpkg/dev-deprecated/json-api.js +23 -1
  58. package/dist/unpkg/dev-deprecated/json-api.js.map +1 -1
  59. package/dist/unpkg/dev-deprecated/rest.js +13 -1
  60. package/dist/unpkg/dev-deprecated/rest.js.map +1 -1
  61. package/dist/unpkg/dev-deprecated/{string-j4ur-TDs.js → string-I8KHJXV7.js} +20 -1
  62. package/dist/unpkg/dev-deprecated/string-I8KHJXV7.js.map +1 -0
  63. package/dist/unpkg/dev-deprecated/string.js +1 -1
  64. package/dist/unpkg/prod/active-record.js +13 -1
  65. package/dist/unpkg/prod/active-record.js.map +1 -1
  66. package/dist/unpkg/prod/derivations.js +6 -0
  67. package/dist/unpkg/prod/derivations.js.map +1 -1
  68. package/dist/unpkg/prod/handlers.js +15 -0
  69. package/dist/unpkg/prod/handlers.js.map +1 -1
  70. package/dist/unpkg/prod/index.js +39 -0
  71. package/dist/unpkg/prod/index.js.map +1 -1
  72. package/dist/unpkg/prod/json-api.js +23 -1
  73. package/dist/unpkg/prod/json-api.js.map +1 -1
  74. package/dist/unpkg/prod/rest.js +13 -1
  75. package/dist/unpkg/prod/rest.js.map +1 -1
  76. package/dist/unpkg/prod/string-D8BEYx2W.js +302 -0
  77. package/dist/unpkg/prod/string-D8BEYx2W.js.map +1 -0
  78. package/dist/unpkg/prod/string.js +1 -1
  79. package/dist/unpkg/prod-deprecated/active-record.js +13 -1
  80. package/dist/unpkg/prod-deprecated/active-record.js.map +1 -1
  81. package/dist/unpkg/prod-deprecated/derivations.js +6 -0
  82. package/dist/unpkg/prod-deprecated/derivations.js.map +1 -1
  83. package/dist/unpkg/prod-deprecated/handlers.js +15 -0
  84. package/dist/unpkg/prod-deprecated/handlers.js.map +1 -1
  85. package/dist/unpkg/prod-deprecated/index.js +39 -0
  86. package/dist/unpkg/prod-deprecated/index.js.map +1 -1
  87. package/dist/unpkg/prod-deprecated/json-api.js +23 -1
  88. package/dist/unpkg/prod-deprecated/json-api.js.map +1 -1
  89. package/dist/unpkg/prod-deprecated/rest.js +13 -1
  90. package/dist/unpkg/prod-deprecated/rest.js.map +1 -1
  91. package/dist/unpkg/prod-deprecated/{string-T1ahjLdj.js → string-D8BEYx2W.js} +20 -1
  92. package/dist/unpkg/prod-deprecated/string-D8BEYx2W.js.map +1 -0
  93. package/dist/unpkg/prod-deprecated/string.js +1 -1
  94. package/package.json +6 -6
  95. package/dist/index-D6QIwzqm.d.ts.map +0 -1
  96. package/dist/string-CWmAluxh.js.map +0 -1
  97. package/dist/unpkg/dev/string-j4ur-TDs.js.map +0 -1
  98. package/dist/unpkg/dev-deprecated/string-j4ur-TDs.js.map +0 -1
  99. package/dist/unpkg/prod/string-T1ahjLdj.js +0 -283
  100. package/dist/unpkg/prod/string-T1ahjLdj.js.map +0 -1
  101. package/dist/unpkg/prod-deprecated/string-T1ahjLdj.js.map +0 -1
@@ -5,6 +5,8 @@ import { Future, Handler, NextFn } from "@warp-drive-mirror/core/request";
5
5
  * Whether the browser supports `ReadableStream` as a request body
6
6
  * in a `POST` request.
7
7
  *
8
+ * @summary Whether the current browser can send a `ReadableStream` as a `fetch` request body, detected once at
9
+ * module load.
8
10
  * @group Constants
9
11
  */
10
12
  export declare const SupportsRequestStreams: boolean;
@@ -145,6 +147,8 @@ interface CompressionOptions {
145
147
  * }
146
148
  * ```
147
149
  *
150
+ * @summary Request handler that compresses large `POST`, `PUT`, `PATCH`, and `DELETE` bodies with `CompressionStream`,
151
+ * optionally streaming them.
148
152
  * @group Handlers
149
153
  * @public
150
154
  * @since 5.5.0
@@ -172,6 +176,8 @@ export declare class AutoCompress implements Handler {
172
176
  type CheckFn = (context: RequestContext) => boolean;
173
177
  /**
174
178
  *
179
+ * @summary Request handler that wraps another handler and runs it only when a check function returns true for the
180
+ * request.
175
181
  * @group Handlers
176
182
  * @public
177
183
  */
@@ -232,6 +238,7 @@ export declare class Gate implements Handler {
232
238
  * Errors are not processed by this handler, so if the request fails and the error response
233
239
  * is not in {json:api} format additional processing may be needed.
234
240
  *
241
+ * @summary Request handler that wraps the whole response body in `meta` for requests with `options.isMetaRequest` set.
235
242
  * @group Handlers
236
243
  */
237
244
  export declare const MetaDocHandler: Handler;
@@ -242,12 +249,15 @@ export declare const MetaDocHandler: Handler;
242
249
  * useful for observability/tracing and deduping
243
250
  * across multiple tabs.
244
251
  *
252
+ * @summary Random UUID identifying the current browser tab, kept in `sessionStorage` across reloads, for request
253
+ * tracing.
245
254
  * @group Constants
246
255
  */
247
256
  export declare const TAB_ID: string;
248
257
  /**
249
258
  * The epoch seconds at which the tab id was generated
250
259
  *
260
+ * @summary Epoch seconds recorded when this module loaded, paired with `TAB_ID` in trace headers.
251
261
  * @group Constants
252
262
  */
253
263
  export declare const TAB_ASSIGNED: number;
@@ -260,6 +270,8 @@ export declare const TAB_ASSIGNED: number;
260
270
  *
261
271
  * Follows the template: `Root=1-${now}-${uuidv4};TabId=1-${epochSeconds}-${tab-uuid}`
262
272
  *
273
+ * @summary Sets an `X-Amzn-Trace-Id` header carrying a per-request id and the tab id, so requests can be traced to
274
+ * their browser tab.
263
275
  * @group Utility Functions
264
276
  */
265
277
  export declare function addTraceHeader(headers: Headers): Headers;
@@ -267,6 +279,7 @@ export declare function addTraceHeader(headers: Headers): Headers;
267
279
  * Source: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cloudfront-limits.html
268
280
  * As of 2024-12-05 the maximum URL length is 8192 bytes.
269
281
  *
282
+ * @summary The 8192-byte URL length limit, taken from AWS CloudFront, that `assertInvalidUrlLength` checks against.
270
283
  * @group Constants
271
284
  */
272
285
  export declare const MAX_URL_LENGTH = 8192;
@@ -275,6 +288,8 @@ export declare const MAX_URL_LENGTH = 8192;
275
288
  *
276
289
  * See also {@link MAX_URL_LENGTH}
277
290
  *
291
+ * @summary Dev-mode assertion that throws when a URL is longer than `MAX_URL_LENGTH`, suggesting a `POST` or `QUERY`
292
+ * request instead.
278
293
  * @group Utility Functions
279
294
  */
280
295
  export declare function assertInvalidUrlLength(url: string | undefined): void;
@@ -1 +1 @@
1
- {"version":3,"file":"handlers.d.ts","names":[],"sources":["../src/-private/handlers/auto-compress.ts","../src/-private/handlers/gated.ts","../src/-private/handlers/meta-doc.ts","../src/-private/handlers/utils.ts"],"mappings":";;;;;;;;;qBAca;UAgBH;;;;;;EAMR;;;;;;EAMA;;;;;;EAMA;;;;;;EAMA;;;;;;EAMA;;;;;;UAOQ;;;;;;;;EAQR,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4BT;;;;;;;;EASA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiCA,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAwCH,wBAAwB;;;;;EAKnC,SAAiB,SAAS;;;;IAIxB,aAAa,SAAS;;EAGxB,YAAY,UAAS;EAUrB,QAAQ,KAAK,WAAW,gBAAgB,MAAM,OAAO,KAAK,QAAQ,KAAK,OAAO;;;;;;;;KCxM3E,WAAW,SAAS;;;;;;qBAOZ,gBAAgB;;;;EAI3B,SAAiB;;;;EAIjB,SAAiB;EAEjB,YAAY,SAAS,SAAS,SAAS;EAKvC,QAAQ,aAAa,SAAS,gBAAgB,MAAM,OAAO,KAAK,QAAQ,IAAI,uBAAuB,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBCoBrG,gBAAgB;;;;;;;;;;qBCdhB;;;;;;qBAMA;;;;;;;;;;;;wBAaG,eAAe,SAAS,UAAU;;;;;;;qBAarC;;;;;;;;wBASG,uBAAuB"}
1
+ {"version":3,"file":"handlers.d.ts","names":[],"sources":["../src/-private/handlers/auto-compress.ts","../src/-private/handlers/gated.ts","../src/-private/handlers/meta-doc.ts","../src/-private/handlers/utils.ts"],"mappings":";;;;;;;;;;;qBAgBa;UAgBH;;;;;;EAMR;;;;;;EAMA;;;;;;EAMA;;;;;;EAMA;;;;;;EAMA;;;;;;UAOQ;;;;;;;;EAQR,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4BT;;;;;;;;EASA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiCA,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBA0CH,wBAAwB;;;;;EAKnC,SAAiB,SAAS;;;;IAIxB,aAAa,SAAS;;EAGxB,YAAY,UAAS;EAUrB,QAAQ,KAAK,WAAW,gBAAgB,MAAM,OAAO,KAAK,QAAQ,KAAK,OAAO;;;;;;;;KC5M3E,WAAW,SAAS;;;;;;;;qBASZ,gBAAgB;;;;EAI3B,SAAiB;;;;EAIjB,SAAiB;EAEjB,YAAY,SAAS,SAAS,SAAS;EAKvC,QAAQ,aAAa,SAAS,gBAAgB,MAAM,OAAO,KAAK,QAAQ,IAAI,uBAAuB,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBCmBrG,gBAAgB;;;;;;;;;;;;qBCbhB;;;;;;;qBAOA;;;;;;;;;;;;;;wBAeG,eAAe,SAAS,UAAU;;;;;;;;qBAcrC;;;;;;;;;;wBAWG,uBAAuB"}
package/dist/handlers.js CHANGED
@@ -8,6 +8,8 @@ function isCompressibleMethod(method) {
8
8
  * Whether the browser supports `ReadableStream` as a request body
9
9
  * in a `POST` request.
10
10
  *
11
+ * @summary Whether the current browser can send a `ReadableStream` as a `fetch` request body, detected once at
12
+ * module load.
11
13
  * @group Constants
12
14
  */
13
15
  const SupportsRequestStreams = (() => {
@@ -58,6 +60,8 @@ const TypedArray = Object.getPrototypeOf(Uint8Array);
58
60
  * }
59
61
  * ```
60
62
  *
63
+ * @summary Request handler that compresses large `POST`, `PUT`, `PATCH`, and `DELETE` bodies with `CompressionStream`,
64
+ * optionally streaming them.
61
65
  * @group Handlers
62
66
  * @public
63
67
  * @since 5.5.0
@@ -127,6 +131,8 @@ function encodingForFormat(format) {
127
131
  */
128
132
  /**
129
133
  *
134
+ * @summary Request handler that wraps another handler and runs it only when a check function returns true for the
135
+ * request.
130
136
  * @group Handlers
131
137
  * @public
132
138
  */
@@ -192,6 +198,7 @@ var Gate = class {
192
198
  * Errors are not processed by this handler, so if the request fails and the error response
193
199
  * is not in {json:api} format additional processing may be needed.
194
200
  *
201
+ * @summary Request handler that wraps the whole response body in `meta` for requests with `options.isMetaRequest` set.
195
202
  * @group Handlers
196
203
  */
197
204
  const MetaDocHandler = { request(context, next) {
@@ -224,12 +231,15 @@ function getTabId() {
224
231
  * useful for observability/tracing and deduping
225
232
  * across multiple tabs.
226
233
  *
234
+ * @summary Random UUID identifying the current browser tab, kept in `sessionStorage` across reloads, for request
235
+ * tracing.
227
236
  * @group Constants
228
237
  */
229
238
  const TAB_ID = getTabId();
230
239
  /**
231
240
  * The epoch seconds at which the tab id was generated
232
241
  *
242
+ * @summary Epoch seconds recorded when this module loaded, paired with `TAB_ID` in trace headers.
233
243
  * @group Constants
234
244
  */
235
245
  const TAB_ASSIGNED = Math.floor(Date.now() / 1e3);
@@ -242,6 +252,8 @@ const TAB_ASSIGNED = Math.floor(Date.now() / 1e3);
242
252
  *
243
253
  * Follows the template: `Root=1-${now}-${uuidv4};TabId=1-${epochSeconds}-${tab-uuid}`
244
254
  *
255
+ * @summary Sets an `X-Amzn-Trace-Id` header carrying a per-request id and the tab id, so requests can be traced to
256
+ * their browser tab.
245
257
  * @group Utility Functions
246
258
  */
247
259
  function addTraceHeader(headers) {
@@ -253,6 +265,7 @@ function addTraceHeader(headers) {
253
265
  * Source: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cloudfront-limits.html
254
266
  * As of 2024-12-05 the maximum URL length is 8192 bytes.
255
267
  *
268
+ * @summary The 8192-byte URL length limit, taken from AWS CloudFront, that `assertInvalidUrlLength` checks against.
256
269
  * @group Constants
257
270
  */
258
271
  const MAX_URL_LENGTH = 8192;
@@ -261,6 +274,8 @@ const MAX_URL_LENGTH = 8192;
261
274
  *
262
275
  * See also {@link MAX_URL_LENGTH}
263
276
  *
277
+ * @summary Dev-mode assertion that throws when a URL is longer than `MAX_URL_LENGTH`, suggesting a `POST` or `QUERY`
278
+ * request instead.
264
279
  * @group Utility Functions
265
280
  */
266
281
  function assertInvalidUrlLength(url) {
@@ -1 +1 @@
1
- {"version":3,"file":"handlers.js","names":["isCompressibleMethod","method","SupportsRequestStreams","duplexAccessed","hasContentType","Request","body","ReadableStream","duplex","headers","has","DEFAULT_CONSTRAINTS","Blob","ArrayBuffer","TypedArray","DataView","String","Object","getPrototypeOf","Uint8Array","AutoCompress","constructor","options","opts","format","constraints","assign","allowStreaming","forceStreaming","request","next","shouldCompress","compress","canCompress","length","size","byteLength","response","Response","stream","pipeThrough","CompressionStream","Headers","set","encodingForFormat","req","resp","blob","then","type","macroCondition","getGlobalConfig","WarpDrive","env","DEBUG","test","Error","Gate","constructor","handler","checkFn","request","context","next","FastBoot","globalThis","addEventListener","sessionStorage","setItem","getTabId","crypto","randomUUID","tabId","getItem","tabClosed","newTabId","TAB_ID","TAB_ASSIGNED","Math","floor","Date","now","addTraceHeader","headers","set","MAX_URL_LENGTH","assertInvalidUrlLength","url","macroCondition","getGlobalConfig","WarpDrive","env","DEBUG","test","Error","length"],"sources":["../src/-private/handlers/auto-compress.ts","../src/-private/handlers/gated.ts","../src/-private/handlers/meta-doc.ts","../src/-private/handlers/utils.ts"],"sourcesContent":["import { assert } from '@warp-drive-mirror/core/build-config/macros';\nimport type { Future, Handler, NextFn } from '@warp-drive-mirror/core/request';\nimport type { HTTPMethod, RequestContext } from '@warp-drive-mirror/core/types/request';\n\nfunction isCompressibleMethod(method?: HTTPMethod): boolean {\n return method === 'POST' || method === 'PUT' || method === 'PATCH' || method === 'DELETE';\n}\n\n/**\n * Whether the browser supports `ReadableStream` as a request body\n * in a `POST` request.\n *\n * @group Constants\n */\nexport const SupportsRequestStreams: boolean = (() => {\n let duplexAccessed = false;\n\n const hasContentType = new Request('', {\n body: new ReadableStream(),\n method: 'POST',\n // @ts-expect-error untyped\n get duplex() {\n duplexAccessed = true;\n return 'half';\n },\n }).headers.has('Content-Type');\n\n return duplexAccessed && !hasContentType;\n})();\n\ninterface Constraints {\n /**\n * The minimum size at which to compress blobs\n *\n * @default 1000\n */\n Blob?: number;\n /**\n * The minimum size at which to compress array buffers\n *\n * @default 1000\n */\n ArrayBuffer?: number;\n /**\n * The minimum size at which to compress typed arrays\n *\n * @default 1000\n */\n TypedArray?: number;\n /**\n * The minimum size at which to compress data views\n *\n * @default 1000\n */\n DataView?: number;\n /**\n * The minimum size at which to compress strings\n *\n * @default 1000\n */\n String?: number;\n}\n\n/**\n * Options for configuring the AutoCompress handler.\n *\n */\ninterface CompressionOptions {\n /**\n * The compression format to use. Must be a valid\n * compression format supported by [CompressionStream](https://developer.mozilla.org/en-US/docs/Web/API/CompressionStream)\n *\n * The default is `gzip`.\n *\n */\n format?: CompressionFormat;\n\n /**\n * Some browsers support `ReadableStream` as a request body. This option\n * enables passing the compression stream as the request body instead of\n * the final compressed body when the browser supports doing so.\n *\n * This comes with several caveats:\n *\n * - the request will be put into `duplex: 'half'` mode. This should be\n * transparent to you, but it is worth noting.\n * - the request mode cannot be `no-cors` as requests with a `ReadableStream`\n * have no content length and thus are a new form of request that triggers\n * cors requirements and a preflight request.\n * - http/1.x is not supported.\n *\n * For additional reading about the restrictions of using `ReadableStream`\n * as a request body, see the [Chromium Documentation](https://developer.chrome.com/docs/capabilities/web-apis/fetch-streaming-requests#restrictions)\n *\n * Streaming can be enabled per-request in browsers which support it by\n * setting `request.options.allowStreaming` to `true`.\n *\n * Streaming can be forced even when the browser does not support it by setting\n * `request.options.forceStreaming` to `true`. This is useful if later handlers\n * in the chain can handle the request body as a stream.\n *\n * @default false\n */\n allowStreaming?: boolean;\n\n /**\n * If `true`, the request will be forced into streaming mode even\n * if the browser does not support it. This is useful if later handlers\n * in the chain can handle the request body as a stream.\n *\n * @default false\n */\n forceStreaming?: boolean;\n\n /**\n * The constraints for the request body. This is used to determine\n * whether to compress the request body or not.\n *\n * The defaults are:\n *\n * ```ts\n * {\n * Blob: 1000, // blob.size\n * ArrayBuffer: 1000, // buffer.byteLength\n * TypedArray: 1000, // array.byteLength\n * DataView: 1000, // view.byteLength\n * String: 1000, // string.length\n * }\n * ```\n *\n * The following body types are never compressed unless explicitly\n * configured by the request:\n * - `FormData`\n * - `URLSearchParams`\n * - `ReadableStream`\n *\n * A request.options.compress value of `false` will disable\n * compression for a request body of any type. While a value of\n * `true` will enable compression for the request.\n *\n * An undefined value will use the default, a value of `0` will\n * enable compression for all values, and a value of `-1` will\n * disable compression.\n *\n */\n constraints?: Constraints;\n}\n\nconst DEFAULT_CONSTRAINTS = {\n Blob: 1000,\n ArrayBuffer: 1000,\n TypedArray: 1000,\n DataView: 1000,\n String: 1000,\n};\nconst TypedArray = Object.getPrototypeOf(Uint8Array) as typeof Uint8Array;\n\n/**\n * A request handler that automatically compresses the request body\n * if the request body is a string, array buffer, blob, or form data.\n *\n * This uses the [CompressionStream API](https://developer.mozilla.org/en-US/docs/Web/API/CompressionStream)\n *\n * The compression format as well as the kinds of data to compress can be\n * configured using the `format` and `constraints` options.\n *\n * ```diff\n * +import { AutoCompress } from '@ember-data-mirror/request-utils/handlers';\n * import Fetch from '@ember-data-mirror/request/fetch';\n * import RequestManager from '@ember-data-mirror/request';\n * import Store from '@ember-data-mirror/store';\n *\n * class AppStore extends Store {\n * requestManager = new RequestManager()\n * .use([\n * + new AutoCompress(),\n * Fetch\n * ]);\n * }\n * ```\n *\n * @group Handlers\n * @public\n * @since 5.5.0\n */\nexport class AutoCompress implements Handler {\n /**\n * The resolved options this handler was configured with, with all\n * defaults (including `constraints` defaults) applied.\n */\n declare options: Required<CompressionOptions> & {\n /**\n * The resolved size constraints used to decide whether to compress a given request body.\n */\n constraints: Required<Constraints>;\n };\n\n constructor(options: CompressionOptions = {}) {\n const opts = {\n format: options.format ?? 'gzip',\n constraints: Object.assign({}, DEFAULT_CONSTRAINTS, options.constraints),\n allowStreaming: options.allowStreaming ?? false,\n forceStreaming: options.forceStreaming ?? false,\n };\n this.options = opts;\n }\n\n request<T>({ request }: RequestContext, next: NextFn<T>): Promise<T> | Future<T> {\n const { constraints } = this.options;\n const { body } = request;\n\n const shouldCompress =\n !!body &&\n isCompressibleMethod(request.method) &&\n request.options?.compress !== false &&\n // prettier-ignore\n (request.options?.compress ? true\n : typeof body === 'string' || body instanceof String ? canCompress('String', constraints, body.length)\n : body instanceof Blob ? canCompress('Blob', constraints, body.size)\n : body instanceof ArrayBuffer ? canCompress('ArrayBuffer', constraints, body.byteLength)\n : body instanceof DataView ? canCompress('DataView', constraints, body.byteLength)\n : body instanceof TypedArray ? canCompress('TypedArray', constraints, body.byteLength)\n : false);\n\n if (!shouldCompress) return next(request);\n\n // A convenient way to convert all of the supported body types to a readable\n // stream is to use a `Response` object body\n const response = new Response(request.body);\n const stream = response.body?.pipeThrough(new CompressionStream(this.options.format));\n const headers = new Headers(request.headers);\n headers.set('Content-Encoding', encodingForFormat(this.options.format));\n\n //\n // For browsers that support it, `fetch` can receive a `ReadableStream` as\n // the body, so all we need to do is to create a new `ReadableStream` and\n // compress it on the fly\n //\n const forceStreaming = request.options?.forceStreaming ?? this.options.forceStreaming;\n const allowStreaming = request.options?.allowStreaming ?? this.options.allowStreaming;\n if (forceStreaming || (SupportsRequestStreams && allowStreaming)) {\n const req = Object.assign({}, request, {\n body: stream,\n headers,\n });\n if (SupportsRequestStreams) {\n // @ts-expect-error untyped\n req.duplex = 'half';\n }\n\n return next(req);\n\n //\n // For non-chromium browsers, we have to \"pull\" the stream to get the final\n // bytes and supply the final byte array as the new request body.\n //\n }\n\n // we need to pull the stream to get the final bytes\n const resp = new Response(stream);\n return resp.blob().then((blob) => {\n const req = Object.assign({}, request, {\n body: blob,\n headers,\n });\n return next(req);\n }) as Promise<T>;\n }\n}\n\nfunction canCompress(type: keyof Constraints, constraints: Required<Constraints>, size: number): boolean {\n // if we have a value of 0, we can compress anything\n if (constraints[type] === 0) return true;\n if (constraints[type] === -1) return false;\n return size >= constraints[type];\n}\n\nfunction encodingForFormat(format: CompressionFormat): string {\n switch (format) {\n case 'gzip':\n case 'deflate':\n case 'deflate-raw':\n return format;\n default:\n assert(`Unsupported compression format: ${format as unknown as string}`);\n // @ts-expect-error - unreachable code is reachable in production\n return format;\n }\n}\n","import type { Future, Handler, NextFn } from '@warp-drive-mirror/core/request';\nimport type { RequestContext, StructuredDataDocument } from '@warp-drive-mirror/core/types/request';\n\n/**\n * If CheckFn returns true, the wrapped handler will be used.\n * If CheckFn returns false, the wrapped handler will be skipped.\n */\ntype CheckFn = (context: RequestContext) => boolean;\n\n/**\n *\n * @group Handlers\n * @public\n */\nexport class Gate implements Handler {\n /**\n * The wrapped handler to invoke when {@link Gate.checkFn | checkFn} returns `true`.\n */\n declare handler: Handler;\n /**\n * The predicate used to decide whether {@link Gate.handler | handler} should run for a given request.\n */\n declare checkFn: CheckFn;\n\n constructor(handler: Handler, checkFn: CheckFn) {\n this.handler = handler;\n this.checkFn = checkFn;\n }\n\n request<T = unknown>(context: RequestContext, next: NextFn<T>): Promise<T | StructuredDataDocument<T>> | Future<T> {\n if (this.checkFn(context)) {\n return this.handler.request(context, next);\n }\n return next(context.request);\n }\n}\n","import type { StoreRequestContext } from '@warp-drive-mirror/core';\nimport type { Handler, NextFn } from '@warp-drive-mirror/core/request';\nimport type { StructuredDataDocument } from '@warp-drive-mirror/core/types/request';\n\n/**\n * MetaDocHandler processes requests that are marked as meta requests.\n *\n * It treats the response body as \"entirely meta\" transforming\n *\n * ```ts\n * {\n * some: \"key\",\n * another: \"thing\"\n * }\n * ```\n *\n * into\n *\n * ```ts\n * {\n * \t meta: {\n * some: \"key\",\n * another: \"thing\"\n * }\n * }\n * ```\n *\n * To activate this handler, a request should specify\n *\n * ```ts\n * options.isMetaRequest = true\n * ```\n *\n * For instance\n *\n * ```ts\n * store.request({\n * url: '/example',\n * options: {\n * isMetaRequest: true\n * }\n * });\n * ```\n *\n * Errors are not processed by this handler, so if the request fails and the error response\n * is not in {json:api} format additional processing may be needed.\n *\n * @group Handlers\n */\nexport const MetaDocHandler: Handler = {\n request<T>(context: StoreRequestContext, next: NextFn<T>): Promise<T | StructuredDataDocument<T> | Awaited<T>> {\n if (!context.request.options?.isMetaRequest) {\n return next(context.request);\n }\n\n return next(context.request).then((response) => {\n return processResponse<T>(response);\n });\n },\n};\n\nfunction processResponse<T>(response: StructuredDataDocument<T>): T {\n return {\n meta: response.content,\n } as T;\n}\n","import { assert } from '@warp-drive-mirror/core/build-config/macros';\n\nif (typeof FastBoot === 'undefined') {\n globalThis.addEventListener('beforeunload', function () {\n sessionStorage.setItem('tab-closed', 'true');\n });\n}\n\nfunction getTabId() {\n if (typeof sessionStorage === 'undefined') {\n return crypto.randomUUID();\n }\n\n const tabId = sessionStorage.getItem('tab-id');\n if (tabId) {\n const tabClosed = sessionStorage.getItem('tab-closed');\n if (tabClosed === 'true') {\n return tabId;\n }\n\n // fall through to generate a new tab id\n }\n\n const newTabId = crypto.randomUUID();\n sessionStorage.setItem('tab-id', newTabId);\n return newTabId;\n}\n\n/**\n * A unique identifier for the current browser tab\n * useful for observability/tracing and deduping\n * across multiple tabs.\n *\n * @group Constants\n */\nexport const TAB_ID: string = getTabId();\n/**\n * The epoch seconds at which the tab id was generated\n *\n * @group Constants\n */\nexport const TAB_ASSIGNED: number = Math.floor(Date.now() / 1000);\n\n/**\n * Adds the `X-Amzn-Trace-Id` header to support observability\n * tooling around request routing.\n *\n * This makes use of the {@link TAB_ID} and {@link TAB_ASSIGNED}\n * to enable tracking the browser tab of origin across multiple requests.\n *\n * Follows the template: `Root=1-${now}-${uuidv4};TabId=1-${epochSeconds}-${tab-uuid}`\n *\n * @group Utility Functions\n */\nexport function addTraceHeader(headers: Headers): Headers {\n const now = Math.floor(Date.now() / 1000);\n headers.set('X-Amzn-Trace-Id', `Root=1-${now}-${crypto.randomUUID()};TabId=1-${TAB_ASSIGNED}-${TAB_ID}`);\n\n return headers;\n}\n\n/**\n * Source: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cloudfront-limits.html\n * As of 2024-12-05 the maximum URL length is 8192 bytes.\n *\n * @group Constants\n */\nexport const MAX_URL_LENGTH = 8192;\n\n/**\n * This assertion takes a URL and throws an error if the URL is longer than the maximum URL length.\n *\n * See also {@link MAX_URL_LENGTH}\n *\n * @group Utility Functions\n */\nexport function assertInvalidUrlLength(url: string | undefined): void {\n assert(\n `URL length ${url?.length} exceeds the maximum URL length of ${MAX_URL_LENGTH} bytes.\\n\\nConsider converting this request query a \\`/query\\` endpoint instead of a GET, or upgrade the current endpoint to be able to receive a POST request directly (ideally specifying the header HTTP-Method-Override: QUERY)\\n\\nThe Invalid URL is:\\n\\n${url}`,\n !url || url.length <= MAX_URL_LENGTH\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"handlers.js","names":["isCompressibleMethod","method","SupportsRequestStreams","duplexAccessed","hasContentType","Request","body","ReadableStream","duplex","headers","has","DEFAULT_CONSTRAINTS","Blob","ArrayBuffer","TypedArray","DataView","String","Object","getPrototypeOf","Uint8Array","AutoCompress","constructor","options","opts","format","constraints","assign","allowStreaming","forceStreaming","request","next","shouldCompress","compress","canCompress","length","size","byteLength","response","Response","stream","pipeThrough","CompressionStream","Headers","set","encodingForFormat","req","resp","blob","then","type","macroCondition","getGlobalConfig","WarpDrive","env","DEBUG","test","Error","Gate","constructor","handler","checkFn","request","context","next","FastBoot","globalThis","addEventListener","sessionStorage","setItem","getTabId","crypto","randomUUID","tabId","getItem","tabClosed","newTabId","TAB_ID","TAB_ASSIGNED","Math","floor","Date","now","addTraceHeader","headers","set","MAX_URL_LENGTH","assertInvalidUrlLength","url","macroCondition","getGlobalConfig","WarpDrive","env","DEBUG","test","Error","length"],"sources":["../src/-private/handlers/auto-compress.ts","../src/-private/handlers/gated.ts","../src/-private/handlers/meta-doc.ts","../src/-private/handlers/utils.ts"],"sourcesContent":["import { assert } from '@warp-drive-mirror/core/build-config/macros';\nimport type { Future, Handler, NextFn } from '@warp-drive-mirror/core/request';\nimport type { HTTPMethod, RequestContext } from '@warp-drive-mirror/core/types/request';\n\nfunction isCompressibleMethod(method?: HTTPMethod): boolean {\n return method === 'POST' || method === 'PUT' || method === 'PATCH' || method === 'DELETE';\n}\n\n/**\n * Whether the browser supports `ReadableStream` as a request body\n * in a `POST` request.\n *\n * @summary Whether the current browser can send a `ReadableStream` as a `fetch` request body, detected once at\n * module load.\n * @group Constants\n */\nexport const SupportsRequestStreams: boolean = (() => {\n let duplexAccessed = false;\n\n const hasContentType = new Request('', {\n body: new ReadableStream(),\n method: 'POST',\n // @ts-expect-error untyped\n get duplex() {\n duplexAccessed = true;\n return 'half';\n },\n }).headers.has('Content-Type');\n\n return duplexAccessed && !hasContentType;\n})();\n\ninterface Constraints {\n /**\n * The minimum size at which to compress blobs\n *\n * @default 1000\n */\n Blob?: number;\n /**\n * The minimum size at which to compress array buffers\n *\n * @default 1000\n */\n ArrayBuffer?: number;\n /**\n * The minimum size at which to compress typed arrays\n *\n * @default 1000\n */\n TypedArray?: number;\n /**\n * The minimum size at which to compress data views\n *\n * @default 1000\n */\n DataView?: number;\n /**\n * The minimum size at which to compress strings\n *\n * @default 1000\n */\n String?: number;\n}\n\n/**\n * Options for configuring the AutoCompress handler.\n *\n */\ninterface CompressionOptions {\n /**\n * The compression format to use. Must be a valid\n * compression format supported by [CompressionStream](https://developer.mozilla.org/en-US/docs/Web/API/CompressionStream)\n *\n * The default is `gzip`.\n *\n */\n format?: CompressionFormat;\n\n /**\n * Some browsers support `ReadableStream` as a request body. This option\n * enables passing the compression stream as the request body instead of\n * the final compressed body when the browser supports doing so.\n *\n * This comes with several caveats:\n *\n * - the request will be put into `duplex: 'half'` mode. This should be\n * transparent to you, but it is worth noting.\n * - the request mode cannot be `no-cors` as requests with a `ReadableStream`\n * have no content length and thus are a new form of request that triggers\n * cors requirements and a preflight request.\n * - http/1.x is not supported.\n *\n * For additional reading about the restrictions of using `ReadableStream`\n * as a request body, see the [Chromium Documentation](https://developer.chrome.com/docs/capabilities/web-apis/fetch-streaming-requests#restrictions)\n *\n * Streaming can be enabled per-request in browsers which support it by\n * setting `request.options.allowStreaming` to `true`.\n *\n * Streaming can be forced even when the browser does not support it by setting\n * `request.options.forceStreaming` to `true`. This is useful if later handlers\n * in the chain can handle the request body as a stream.\n *\n * @default false\n */\n allowStreaming?: boolean;\n\n /**\n * If `true`, the request will be forced into streaming mode even\n * if the browser does not support it. This is useful if later handlers\n * in the chain can handle the request body as a stream.\n *\n * @default false\n */\n forceStreaming?: boolean;\n\n /**\n * The constraints for the request body. This is used to determine\n * whether to compress the request body or not.\n *\n * The defaults are:\n *\n * ```ts\n * {\n * Blob: 1000, // blob.size\n * ArrayBuffer: 1000, // buffer.byteLength\n * TypedArray: 1000, // array.byteLength\n * DataView: 1000, // view.byteLength\n * String: 1000, // string.length\n * }\n * ```\n *\n * The following body types are never compressed unless explicitly\n * configured by the request:\n * - `FormData`\n * - `URLSearchParams`\n * - `ReadableStream`\n *\n * A request.options.compress value of `false` will disable\n * compression for a request body of any type. While a value of\n * `true` will enable compression for the request.\n *\n * An undefined value will use the default, a value of `0` will\n * enable compression for all values, and a value of `-1` will\n * disable compression.\n *\n */\n constraints?: Constraints;\n}\n\nconst DEFAULT_CONSTRAINTS = {\n Blob: 1000,\n ArrayBuffer: 1000,\n TypedArray: 1000,\n DataView: 1000,\n String: 1000,\n};\nconst TypedArray = Object.getPrototypeOf(Uint8Array) as typeof Uint8Array;\n\n/**\n * A request handler that automatically compresses the request body\n * if the request body is a string, array buffer, blob, or form data.\n *\n * This uses the [CompressionStream API](https://developer.mozilla.org/en-US/docs/Web/API/CompressionStream)\n *\n * The compression format as well as the kinds of data to compress can be\n * configured using the `format` and `constraints` options.\n *\n * ```diff\n * +import { AutoCompress } from '@ember-data-mirror/request-utils/handlers';\n * import Fetch from '@ember-data-mirror/request/fetch';\n * import RequestManager from '@ember-data-mirror/request';\n * import Store from '@ember-data-mirror/store';\n *\n * class AppStore extends Store {\n * requestManager = new RequestManager()\n * .use([\n * + new AutoCompress(),\n * Fetch\n * ]);\n * }\n * ```\n *\n * @summary Request handler that compresses large `POST`, `PUT`, `PATCH`, and `DELETE` bodies with `CompressionStream`,\n * optionally streaming them.\n * @group Handlers\n * @public\n * @since 5.5.0\n */\nexport class AutoCompress implements Handler {\n /**\n * The resolved options this handler was configured with, with all\n * defaults (including `constraints` defaults) applied.\n */\n declare options: Required<CompressionOptions> & {\n /**\n * The resolved size constraints used to decide whether to compress a given request body.\n */\n constraints: Required<Constraints>;\n };\n\n constructor(options: CompressionOptions = {}) {\n const opts = {\n format: options.format ?? 'gzip',\n constraints: Object.assign({}, DEFAULT_CONSTRAINTS, options.constraints),\n allowStreaming: options.allowStreaming ?? false,\n forceStreaming: options.forceStreaming ?? false,\n };\n this.options = opts;\n }\n\n request<T>({ request }: RequestContext, next: NextFn<T>): Promise<T> | Future<T> {\n const { constraints } = this.options;\n const { body } = request;\n\n const shouldCompress =\n !!body &&\n isCompressibleMethod(request.method) &&\n request.options?.compress !== false &&\n // prettier-ignore\n (request.options?.compress ? true\n : typeof body === 'string' || body instanceof String ? canCompress('String', constraints, body.length)\n : body instanceof Blob ? canCompress('Blob', constraints, body.size)\n : body instanceof ArrayBuffer ? canCompress('ArrayBuffer', constraints, body.byteLength)\n : body instanceof DataView ? canCompress('DataView', constraints, body.byteLength)\n : body instanceof TypedArray ? canCompress('TypedArray', constraints, body.byteLength)\n : false);\n\n if (!shouldCompress) return next(request);\n\n // A convenient way to convert all of the supported body types to a readable\n // stream is to use a `Response` object body\n const response = new Response(request.body);\n const stream = response.body?.pipeThrough(new CompressionStream(this.options.format));\n const headers = new Headers(request.headers);\n headers.set('Content-Encoding', encodingForFormat(this.options.format));\n\n //\n // For browsers that support it, `fetch` can receive a `ReadableStream` as\n // the body, so all we need to do is to create a new `ReadableStream` and\n // compress it on the fly\n //\n const forceStreaming = request.options?.forceStreaming ?? this.options.forceStreaming;\n const allowStreaming = request.options?.allowStreaming ?? this.options.allowStreaming;\n if (forceStreaming || (SupportsRequestStreams && allowStreaming)) {\n const req = Object.assign({}, request, {\n body: stream,\n headers,\n });\n if (SupportsRequestStreams) {\n // @ts-expect-error untyped\n req.duplex = 'half';\n }\n\n return next(req);\n\n //\n // For non-chromium browsers, we have to \"pull\" the stream to get the final\n // bytes and supply the final byte array as the new request body.\n //\n }\n\n // we need to pull the stream to get the final bytes\n const resp = new Response(stream);\n return resp.blob().then((blob) => {\n const req = Object.assign({}, request, {\n body: blob,\n headers,\n });\n return next(req);\n }) as Promise<T>;\n }\n}\n\nfunction canCompress(type: keyof Constraints, constraints: Required<Constraints>, size: number): boolean {\n // if we have a value of 0, we can compress anything\n if (constraints[type] === 0) return true;\n if (constraints[type] === -1) return false;\n return size >= constraints[type];\n}\n\nfunction encodingForFormat(format: CompressionFormat): string {\n switch (format) {\n case 'gzip':\n case 'deflate':\n case 'deflate-raw':\n return format;\n default:\n assert(`Unsupported compression format: ${format as unknown as string}`);\n // @ts-expect-error - unreachable code is reachable in production\n return format;\n }\n}\n","import type { Future, Handler, NextFn } from '@warp-drive-mirror/core/request';\nimport type { RequestContext, StructuredDataDocument } from '@warp-drive-mirror/core/types/request';\n\n/**\n * If CheckFn returns true, the wrapped handler will be used.\n * If CheckFn returns false, the wrapped handler will be skipped.\n */\ntype CheckFn = (context: RequestContext) => boolean;\n\n/**\n *\n * @summary Request handler that wraps another handler and runs it only when a check function returns true for the\n * request.\n * @group Handlers\n * @public\n */\nexport class Gate implements Handler {\n /**\n * The wrapped handler to invoke when {@link Gate.checkFn | checkFn} returns `true`.\n */\n declare handler: Handler;\n /**\n * The predicate used to decide whether {@link Gate.handler | handler} should run for a given request.\n */\n declare checkFn: CheckFn;\n\n constructor(handler: Handler, checkFn: CheckFn) {\n this.handler = handler;\n this.checkFn = checkFn;\n }\n\n request<T = unknown>(context: RequestContext, next: NextFn<T>): Promise<T | StructuredDataDocument<T>> | Future<T> {\n if (this.checkFn(context)) {\n return this.handler.request(context, next);\n }\n return next(context.request);\n }\n}\n","import type { StoreRequestContext } from '@warp-drive-mirror/core';\nimport type { Handler, NextFn } from '@warp-drive-mirror/core/request';\nimport type { StructuredDataDocument } from '@warp-drive-mirror/core/types/request';\n\n/**\n * MetaDocHandler processes requests that are marked as meta requests.\n *\n * It treats the response body as \"entirely meta\" transforming\n *\n * ```ts\n * {\n * some: \"key\",\n * another: \"thing\"\n * }\n * ```\n *\n * into\n *\n * ```ts\n * {\n * \t meta: {\n * some: \"key\",\n * another: \"thing\"\n * }\n * }\n * ```\n *\n * To activate this handler, a request should specify\n *\n * ```ts\n * options.isMetaRequest = true\n * ```\n *\n * For instance\n *\n * ```ts\n * store.request({\n * url: '/example',\n * options: {\n * isMetaRequest: true\n * }\n * });\n * ```\n *\n * Errors are not processed by this handler, so if the request fails and the error response\n * is not in {json:api} format additional processing may be needed.\n *\n * @summary Request handler that wraps the whole response body in `meta` for requests with `options.isMetaRequest` set.\n * @group Handlers\n */\nexport const MetaDocHandler: Handler = {\n request<T>(context: StoreRequestContext, next: NextFn<T>): Promise<T | StructuredDataDocument<T> | Awaited<T>> {\n if (!context.request.options?.isMetaRequest) {\n return next(context.request);\n }\n\n return next(context.request).then((response) => {\n return processResponse<T>(response);\n });\n },\n};\n\nfunction processResponse<T>(response: StructuredDataDocument<T>): T {\n return {\n meta: response.content,\n } as T;\n}\n","import { assert } from '@warp-drive-mirror/core/build-config/macros';\n\nif (typeof FastBoot === 'undefined') {\n globalThis.addEventListener('beforeunload', function () {\n sessionStorage.setItem('tab-closed', 'true');\n });\n}\n\nfunction getTabId() {\n if (typeof sessionStorage === 'undefined') {\n return crypto.randomUUID();\n }\n\n const tabId = sessionStorage.getItem('tab-id');\n if (tabId) {\n const tabClosed = sessionStorage.getItem('tab-closed');\n if (tabClosed === 'true') {\n return tabId;\n }\n\n // fall through to generate a new tab id\n }\n\n const newTabId = crypto.randomUUID();\n sessionStorage.setItem('tab-id', newTabId);\n return newTabId;\n}\n\n/**\n * A unique identifier for the current browser tab\n * useful for observability/tracing and deduping\n * across multiple tabs.\n *\n * @summary Random UUID identifying the current browser tab, kept in `sessionStorage` across reloads, for request\n * tracing.\n * @group Constants\n */\nexport const TAB_ID: string = getTabId();\n/**\n * The epoch seconds at which the tab id was generated\n *\n * @summary Epoch seconds recorded when this module loaded, paired with `TAB_ID` in trace headers.\n * @group Constants\n */\nexport const TAB_ASSIGNED: number = Math.floor(Date.now() / 1000);\n\n/**\n * Adds the `X-Amzn-Trace-Id` header to support observability\n * tooling around request routing.\n *\n * This makes use of the {@link TAB_ID} and {@link TAB_ASSIGNED}\n * to enable tracking the browser tab of origin across multiple requests.\n *\n * Follows the template: `Root=1-${now}-${uuidv4};TabId=1-${epochSeconds}-${tab-uuid}`\n *\n * @summary Sets an `X-Amzn-Trace-Id` header carrying a per-request id and the tab id, so requests can be traced to\n * their browser tab.\n * @group Utility Functions\n */\nexport function addTraceHeader(headers: Headers): Headers {\n const now = Math.floor(Date.now() / 1000);\n headers.set('X-Amzn-Trace-Id', `Root=1-${now}-${crypto.randomUUID()};TabId=1-${TAB_ASSIGNED}-${TAB_ID}`);\n\n return headers;\n}\n\n/**\n * Source: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cloudfront-limits.html\n * As of 2024-12-05 the maximum URL length is 8192 bytes.\n *\n * @summary The 8192-byte URL length limit, taken from AWS CloudFront, that `assertInvalidUrlLength` checks against.\n * @group Constants\n */\nexport const MAX_URL_LENGTH = 8192;\n\n/**\n * This assertion takes a URL and throws an error if the URL is longer than the maximum URL length.\n *\n * See also {@link MAX_URL_LENGTH}\n *\n * @summary Dev-mode assertion that throws when a URL is longer than `MAX_URL_LENGTH`, suggesting a `POST` or `QUERY`\n * request instead.\n * @group Utility Functions\n */\nexport function assertInvalidUrlLength(url: string | undefined): void {\n assert(\n `URL length ${url?.length} exceeds the maximum URL length of ${MAX_URL_LENGTH} bytes.\\n\\nConsider converting this request query a \\`/query\\` endpoint instead of a GET, or upgrade the current endpoint to be able to receive a POST request directly (ideally specifying the header HTTP-Method-Override: QUERY)\\n\\nThe Invalid URL is:\\n\\n${url}`,\n !url || url.length <= MAX_URL_LENGTH\n );\n}\n"],"mappings":"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"}
@@ -4,6 +4,7 @@ import { QueryParamsSerializationOptions, QueryParamsSource, Serializable } from
4
4
  * The global configuration used by {@link buildBaseURL} when a call does
5
5
  * not provide its own `host`/`namespace`. Set via {@link setBuildURLConfig}.
6
6
  *
7
+ * @summary The global `host` and `namespace` that `buildBaseURL` prefixes onto URLs when a call does not pass its own.
7
8
  * @public
8
9
  */
9
10
  interface BuildURLConfig {
@@ -23,6 +24,10 @@ interface BuildURLConfig {
23
24
  * These values may still be overridden by passing
24
25
  * them to buildBaseURL directly.
25
26
  *
27
+ * The [Basic Usage](/guides/the-manual/cookbook/basic-usage#step-2-configure-some-request-defaults)
28
+ * guide sets these defaults through the `@warp-drive-mirror/utilities/json-api` version of this function,
29
+ * which also sets this global configuration.
30
+ *
26
31
  * This method may be called as many times as needed.
27
32
  * host values of `''` or `'/'` are equivalent.
28
33
  *
@@ -49,12 +54,14 @@ interface BuildURLConfig {
49
54
  * });
50
55
  * ```
51
56
  *
57
+ * @summary Sets the app-wide default `host` and `namespace` used by `buildBaseURL` and the request builders.
52
58
  * @public
53
59
  */
54
60
  declare function setBuildURLConfig(config: BuildURLConfig): void;
55
61
  /**
56
62
  * {@link buildBaseURL} options for a `findRecord` request.
57
63
  *
64
+ * @summary Options passed to `buildBaseURL` to build the URL for fetching one resource by type and id.
58
65
  * @public
59
66
  */
60
67
  interface FindRecordUrlOptions {
@@ -91,6 +98,7 @@ interface FindRecordUrlOptions {
91
98
  /**
92
99
  * {@link buildBaseURL} options for a `query` request.
93
100
  *
101
+ * @summary Options passed to `buildBaseURL` to build the URL for querying a collection of one resource type.
94
102
  * @public
95
103
  */
96
104
  interface QueryUrlOptions {
@@ -123,6 +131,8 @@ interface QueryUrlOptions {
123
131
  /**
124
132
  * {@link buildBaseURL} options for a `findMany` request.
125
133
  *
134
+ * @summary Options passed to `buildBaseURL` to build the URL for fetching several resources, pathed by the first
135
+ * identifier's type.
126
136
  * @public
127
137
  */
128
138
  interface FindManyUrlOptions {
@@ -159,6 +169,8 @@ interface FindManyUrlOptions {
159
169
  /**
160
170
  * {@link buildBaseURL} options for a `findRelatedCollection` request.
161
171
  *
172
+ * @summary Options passed to `buildBaseURL` to build the URL for a record's has-many relationship, ending in the
173
+ * field name.
162
174
  * @public
163
175
  */
164
176
  interface FindRelatedCollectionUrlOptions {
@@ -199,6 +211,8 @@ interface FindRelatedCollectionUrlOptions {
199
211
  /**
200
212
  * {@link buildBaseURL} options for a `findRelatedRecord` request.
201
213
  *
214
+ * @summary Options passed to `buildBaseURL` to build the URL for a record's belongs-to relationship, ending in the
215
+ * field name.
202
216
  * @public
203
217
  */
204
218
  interface FindRelatedResourceUrlOptions {
@@ -239,6 +253,7 @@ interface FindRelatedResourceUrlOptions {
239
253
  /**
240
254
  * {@link buildBaseURL} options for a `createRecord` request.
241
255
  *
256
+ * @summary Options passed to `buildBaseURL` to build the collection URL a new record of a given type is saved to.
242
257
  * @public
243
258
  */
244
259
  interface CreateRecordUrlOptions {
@@ -271,6 +286,7 @@ interface CreateRecordUrlOptions {
271
286
  /**
272
287
  * {@link buildBaseURL} options for an `updateRecord` request.
273
288
  *
289
+ * @summary Options passed to `buildBaseURL` to build the URL for saving changes to an existing record by type and id.
274
290
  * @public
275
291
  */
276
292
  interface UpdateRecordUrlOptions {
@@ -307,6 +323,7 @@ interface UpdateRecordUrlOptions {
307
323
  /**
308
324
  * {@link buildBaseURL} options for a `deleteRecord` request.
309
325
  *
326
+ * @summary Options passed to `buildBaseURL` to build the URL for deleting an existing record by type and id.
310
327
  * @public
311
328
  */
312
329
  interface DeleteRecordUrlOptions {
@@ -344,6 +361,7 @@ interface DeleteRecordUrlOptions {
344
361
  * {@link buildBaseURL} options for building a URL directly from a `resourcePath`
345
362
  * without an associated request operation.
346
363
  *
364
+ * @summary Options passed to `buildBaseURL` to build a URL from an explicit `resourcePath` with no request `op`.
347
365
  * @public
348
366
  */
349
367
  interface GenericUrlOptions {
@@ -373,6 +391,7 @@ interface GenericUrlOptions {
373
391
  * - {@link DeleteRecordUrlOptions}
374
392
  * - {@link GenericUrlOptions}
375
393
  *
394
+ * @summary Any of the option shapes `buildBaseURL` accepts, one per request `op` plus a generic `resourcePath` form.
376
395
  * @public
377
396
  */
378
397
  type UrlOptions = FindRecordUrlOptions | QueryUrlOptions | FindManyUrlOptions | FindRelatedCollectionUrlOptions | FindRelatedResourceUrlOptions | CreateRecordUrlOptions | UpdateRecordUrlOptions | DeleteRecordUrlOptions | GenericUrlOptions;
@@ -381,6 +400,9 @@ type UrlOptions = FindRecordUrlOptions | QueryUrlOptions | FindManyUrlOptions |
381
400
  * Does not include support for building query params (see `buildQueryParams`)
382
401
  * so that it may be composed cleanly with other query-params strategies.
383
402
  *
403
+ * See the [Builders](/guides/the-manual/requests/builders) guide for writing your own request
404
+ * builders.
405
+ *
384
406
  * Usage:
385
407
  *
386
408
  * ```ts
@@ -410,6 +432,7 @@ type UrlOptions = FindRecordUrlOptions | QueryUrlOptions | FindManyUrlOptions |
410
432
  * - 'findRecord' 'query' 'findMany' 'findRelatedCollection' 'findRelatedRecord'` 'createRecord' 'updateRecord' 'deleteRecord'
411
433
  * - Depending on the value of `op`, `identifier` or `identifiers` will be required.
412
434
  *
435
+ * @summary Joins host, namespace, resource path, id, and relationship field into a request URL without query params.
413
436
  * @public
414
437
  */
415
438
  declare function buildBaseURL(urlOptions: UrlOptions): string;
@@ -417,6 +440,11 @@ declare function buildBaseURL(urlOptions: UrlOptions): string;
417
440
  * filter out keys of an object that have falsy values or point to empty arrays
418
441
  * returning a new object with only those keys that have truthy values / non-empty arrays
419
442
  *
443
+ * See [Cache Keys for Requests](/guides/the-manual/requests/builders#cache-keys-for-requests) for
444
+ * why builders need stable query params.
445
+ *
446
+ * @summary Returns a copy of an object without keys whose values are `undefined`, `null`, empty strings, or empty
447
+ * arrays.
420
448
  * @public
421
449
  * @param source object to filter keys with empty values from
422
450
  * @return A new object with the keys that contained empty values removed
@@ -426,6 +454,9 @@ declare function filterEmpty(source: Record<string, Serializable>): Record<strin
426
454
  * Sorts query params by both key and value returning a new URLSearchParams
427
455
  * object with the keys inserted in sorted order.
428
456
  *
457
+ * See [Cache Keys for Requests](/guides/the-manual/requests/builders#cache-keys-for-requests) for
458
+ * why builders need stable query params.
459
+ *
429
460
  * Treats `included` specially, splicing it into an array if it is a string and sorting the array.
430
461
  *
431
462
  * The `params` given are never mutated: neither the object itself nor any array
@@ -440,6 +471,8 @@ declare function filterEmpty(source: Record<string, Serializable>): Record<strin
440
471
  * 'repeat': appends the key for every value e.g. `&ids=1&ids=2`
441
472
  * 'comma' (default): appends the key once with a comma separated list of values e.g. `&ids=1,2`
442
473
  *
474
+ * @summary Builds a `URLSearchParams` with keys and array values sorted, so equivalent queries produce identical
475
+ * params.
443
476
  * @public
444
477
  * @return A {@link URLSearchParams} with keys inserted in sorted order
445
478
  */
@@ -447,6 +480,9 @@ declare function sortQueryParams(params: QueryParamsSource, options?: QueryParam
447
480
  /**
448
481
  * Sorts query params by both key and value, returning a query params string
449
482
  *
483
+ * See [Cache Keys for Requests](/guides/the-manual/requests/builders#cache-keys-for-requests) for
484
+ * why builders need stable query params.
485
+ *
450
486
  * Treats `included` specially, splicing it into an array if it is a string and sorting the array.
451
487
  *
452
488
  * The `params` given are never mutated: neither the object itself nor any array
@@ -461,10 +497,12 @@ declare function sortQueryParams(params: QueryParamsSource, options?: QueryParam
461
497
  * 'repeat': appends the key for every value e.g. `ids=1&ids=2`
462
498
  * 'comma' (default): appends the key once with a comma separated list of values e.g. `ids=1,2`
463
499
  *
500
+ * @summary Serializes query params into a string with keys and array values sorted, so equivalent queries share one
501
+ * URL.
464
502
  * @public
465
503
  * @return A sorted query params string without the leading `?`
466
504
  */
467
505
  declare function buildQueryParams(params: QueryParamsSource, options?: QueryParamsSerializationOptions): string;
468
506
  //#endregion
469
507
  export { FindRecordUrlOptions as a, GenericUrlOptions as c, UrlOptions as d, buildBaseURL as f, sortQueryParams as g, setBuildURLConfig as h, FindManyUrlOptions as i, QueryUrlOptions as l, filterEmpty as m, CreateRecordUrlOptions as n, FindRelatedCollectionUrlOptions as o, buildQueryParams as p, DeleteRecordUrlOptions as r, FindRelatedResourceUrlOptions as s, BuildURLConfig as t, UpdateRecordUrlOptions as u };
470
- //# sourceMappingURL=index-D6QIwzqm.d.ts.map
508
+ //# sourceMappingURL=index-Ds06tKwC.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-Ds06tKwC.d.ts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;;;;;UAqBiB;;;;EAIf;;;;EAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAgDc,kBAAkB,QAAQ;;;;;;;UA8BzB;;;;EAIf;;;;EAIA;;;;IAIE;;;;IAIA;;;;;EAKF;;;;EAIA;;;;EAIA;;;;;;;;UASe;;;;EAIf;;;;EAIA;;;;IAIE;;;;;EAKF;;;;EAIA;;;;EAIA;;;;;;;;;UAUe;;;;EAIf;;;;EAIA;;;;IAIE;;;;IAIA;;;;;EAKF;;;;EAIA;;;;EAIA;;;;;;;;;UASe;;;;EAIf;;;;EAIA;;;;IAIE;;;;IAIA;;;;;EAKF;;;;EAIA;;;;EAIA;;;;EAIA;;;;;;;;;UAUe;;;;EAIf;;;;EAIA;;;;IAIE;;;;IAIA;;;;;EAKF;;;;EAIA;;;;EAIA;;;;EAIA;;;;;;;;UASe;;;;EAIf;;;;EAIA;;;;IAIE;;;;;EAKF;;;;EAIA;;;;EAIA;;;;;;;;UASe;;;;EAIf;;;;EAIA;;;;IAIE;;;;IAIA;;;;;EAKF;;;;EAIA;;;;EAIA;;;;;;;;UASe;;;;EAIf;;;;EAIA;;;;IAIE;;;;IAIA;;;;;EAKF;;;;EAIA;;;;EAIA;;;;;;;;;UAUe;;;;EAIf;;;;EAIA;;;;EAIA;;;;;;;;;;;;;;;;;;KAmBU,aACR,uBACA,kBACA,qBACA,kCACA,gCACA,yBACA,yBACA,yBACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAyEY,aAAa,YAAY;;;;;;;;;;;;;;iBAiIzB,YAAY,QAAQ,eAAe,gBAAgB,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAwClE,gBAAgB,QAAQ,mBAAmB,UAAU,kCAAkC;;;;;;;;;;;;;;;;;;;;;;;;;;iBAwFvF,iBAAiB,QAAQ,mBAAmB,UAAU"}
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { a as FindRecordUrlOptions, c as GenericUrlOptions, d as UrlOptions, f as buildBaseURL, g as sortQueryParams, h as setBuildURLConfig, i as FindManyUrlOptions, l as QueryUrlOptions, m as filterEmpty, n as CreateRecordUrlOptions, o as FindRelatedCollectionUrlOptions, p as buildQueryParams, r as DeleteRecordUrlOptions, s as FindRelatedResourceUrlOptions, t as BuildURLConfig, u as UpdateRecordUrlOptions } from "./index-D6QIwzqm.js";
1
+ import { a as FindRecordUrlOptions, c as GenericUrlOptions, d as UrlOptions, f as buildBaseURL, g as sortQueryParams, h as setBuildURLConfig, i as FindManyUrlOptions, l as QueryUrlOptions, m as filterEmpty, n as CreateRecordUrlOptions, o as FindRelatedCollectionUrlOptions, p as buildQueryParams, r as DeleteRecordUrlOptions, s as FindRelatedResourceUrlOptions, t as BuildURLConfig, u as UpdateRecordUrlOptions } from "./index-Ds06tKwC.js";
2
2
  export { BuildURLConfig, CreateRecordUrlOptions, DeleteRecordUrlOptions, FindManyUrlOptions, FindRecordUrlOptions, FindRelatedCollectionUrlOptions, FindRelatedResourceUrlOptions, GenericUrlOptions, QueryUrlOptions, UpdateRecordUrlOptions, UrlOptions, buildBaseURL, buildQueryParams, filterEmpty, setBuildURLConfig, sortQueryParams };
package/dist/index.js CHANGED
@@ -3,6 +3,7 @@ import { getGlobalConfig, macroCondition } from "@embroider/macros";
3
3
 
4
4
  //#region src/index.ts
5
5
  /**
6
+ * @summary Helpers for building request URLs and sorted query strings, with a configurable global host and namespace.
6
7
  * @module
7
8
  * @mergeModuleWith <project>
8
9
  */
@@ -10,6 +11,7 @@ import { getGlobalConfig, macroCondition } from "@embroider/macros";
10
11
  * The global configuration used by {@link buildBaseURL} when a call does
11
12
  * not provide its own `host`/`namespace`. Set via {@link setBuildURLConfig}.
12
13
  *
14
+ * @summary The global `host` and `namespace` that `buildBaseURL` prefixes onto URLs when a call does not pass its own.
13
15
  * @public
14
16
  */
15
17
  const CONFIG = getOrSetGlobal("CONFIG", {
@@ -23,6 +25,10 @@ const CONFIG = getOrSetGlobal("CONFIG", {
23
25
  * These values may still be overridden by passing
24
26
  * them to buildBaseURL directly.
25
27
  *
28
+ * The [Basic Usage](/guides/the-manual/cookbook/basic-usage#step-2-configure-some-request-defaults)
29
+ * guide sets these defaults through the `@warp-drive-mirror/utilities/json-api` version of this function,
30
+ * which also sets this global configuration.
31
+ *
26
32
  * This method may be called as many times as needed.
27
33
  * host values of `''` or `'/'` are equivalent.
28
34
  *
@@ -49,6 +55,7 @@ const CONFIG = getOrSetGlobal("CONFIG", {
49
55
  * });
50
56
  * ```
51
57
  *
58
+ * @summary Sets the app-wide default `host` and `namespace` used by `buildBaseURL` and the request builders.
52
59
  * @public
53
60
  */
54
61
  function setBuildURLConfig(config) {
@@ -73,47 +80,59 @@ function setBuildURLConfig(config) {
73
80
  /**
74
81
  * {@link buildBaseURL} options for a `findRecord` request.
75
82
  *
83
+ * @summary Options passed to `buildBaseURL` to build the URL for fetching one resource by type and id.
76
84
  * @public
77
85
  */
78
86
  /**
79
87
  * {@link buildBaseURL} options for a `query` request.
80
88
  *
89
+ * @summary Options passed to `buildBaseURL` to build the URL for querying a collection of one resource type.
81
90
  * @public
82
91
  */
83
92
  /**
84
93
  * {@link buildBaseURL} options for a `findMany` request.
85
94
  *
95
+ * @summary Options passed to `buildBaseURL` to build the URL for fetching several resources, pathed by the first
96
+ * identifier's type.
86
97
  * @public
87
98
  */
88
99
  /**
89
100
  * {@link buildBaseURL} options for a `findRelatedCollection` request.
90
101
  *
102
+ * @summary Options passed to `buildBaseURL` to build the URL for a record's has-many relationship, ending in the
103
+ * field name.
91
104
  * @public
92
105
  */
93
106
  /**
94
107
  * {@link buildBaseURL} options for a `findRelatedRecord` request.
95
108
  *
109
+ * @summary Options passed to `buildBaseURL` to build the URL for a record's belongs-to relationship, ending in the
110
+ * field name.
96
111
  * @public
97
112
  */
98
113
  /**
99
114
  * {@link buildBaseURL} options for a `createRecord` request.
100
115
  *
116
+ * @summary Options passed to `buildBaseURL` to build the collection URL a new record of a given type is saved to.
101
117
  * @public
102
118
  */
103
119
  /**
104
120
  * {@link buildBaseURL} options for an `updateRecord` request.
105
121
  *
122
+ * @summary Options passed to `buildBaseURL` to build the URL for saving changes to an existing record by type and id.
106
123
  * @public
107
124
  */
108
125
  /**
109
126
  * {@link buildBaseURL} options for a `deleteRecord` request.
110
127
  *
128
+ * @summary Options passed to `buildBaseURL` to build the URL for deleting an existing record by type and id.
111
129
  * @public
112
130
  */
113
131
  /**
114
132
  * {@link buildBaseURL} options for building a URL directly from a `resourcePath`
115
133
  * without an associated request operation.
116
134
  *
135
+ * @summary Options passed to `buildBaseURL` to build a URL from an explicit `resourcePath` with no request `op`.
117
136
  * @public
118
137
  */
119
138
  /**
@@ -129,6 +148,7 @@ function setBuildURLConfig(config) {
129
148
  * - {@link DeleteRecordUrlOptions}
130
149
  * - {@link GenericUrlOptions}
131
150
  *
151
+ * @summary Any of the option shapes `buildBaseURL` accepts, one per request `op` plus a generic `resourcePath` form.
132
152
  * @public
133
153
  */
134
154
  const OPERATIONS_WITH_PRIMARY_RECORDS = /* @__PURE__ */ new Set([
@@ -155,6 +175,9 @@ function resourcePathForType(options) {
155
175
  * Does not include support for building query params (see `buildQueryParams`)
156
176
  * so that it may be composed cleanly with other query-params strategies.
157
177
  *
178
+ * See the [Builders](/guides/the-manual/requests/builders) guide for writing your own request
179
+ * builders.
180
+ *
158
181
  * Usage:
159
182
  *
160
183
  * ```ts
@@ -184,6 +207,7 @@ function resourcePathForType(options) {
184
207
  * - 'findRecord' 'query' 'findMany' 'findRelatedCollection' 'findRelatedRecord'` 'createRecord' 'updateRecord' 'deleteRecord'
185
208
  * - Depending on the value of `op`, `identifier` or `identifiers` will be required.
186
209
  *
210
+ * @summary Joins host, namespace, resource path, id, and relationship field into a request URL without query params.
187
211
  * @public
188
212
  */
189
213
  function buildBaseURL(urlOptions) {
@@ -285,6 +309,11 @@ function handleInclude(include) {
285
309
  * filter out keys of an object that have falsy values or point to empty arrays
286
310
  * returning a new object with only those keys that have truthy values / non-empty arrays
287
311
  *
312
+ * See [Cache Keys for Requests](/guides/the-manual/requests/builders#cache-keys-for-requests) for
313
+ * why builders need stable query params.
314
+ *
315
+ * @summary Returns a copy of an object without keys whose values are `undefined`, `null`, empty strings, or empty
316
+ * arrays.
288
317
  * @public
289
318
  * @param source object to filter keys with empty values from
290
319
  * @return A new object with the keys that contained empty values removed
@@ -303,6 +332,9 @@ function filterEmpty(source) {
303
332
  * Sorts query params by both key and value returning a new URLSearchParams
304
333
  * object with the keys inserted in sorted order.
305
334
  *
335
+ * See [Cache Keys for Requests](/guides/the-manual/requests/builders#cache-keys-for-requests) for
336
+ * why builders need stable query params.
337
+ *
306
338
  * Treats `included` specially, splicing it into an array if it is a string and sorting the array.
307
339
  *
308
340
  * The `params` given are never mutated: neither the object itself nor any array
@@ -317,6 +349,8 @@ function filterEmpty(source) {
317
349
  * 'repeat': appends the key for every value e.g. `&ids=1&ids=2`
318
350
  * 'comma' (default): appends the key once with a comma separated list of values e.g. `&ids=1,2`
319
351
  *
352
+ * @summary Builds a `URLSearchParams` with keys and array values sorted, so equivalent queries produce identical
353
+ * params.
320
354
  * @public
321
355
  * @return A {@link URLSearchParams} with keys inserted in sorted order
322
356
  */
@@ -365,6 +399,9 @@ function sortQueryParams(params, options) {
365
399
  /**
366
400
  * Sorts query params by both key and value, returning a query params string
367
401
  *
402
+ * See [Cache Keys for Requests](/guides/the-manual/requests/builders#cache-keys-for-requests) for
403
+ * why builders need stable query params.
404
+ *
368
405
  * Treats `included` specially, splicing it into an array if it is a string and sorting the array.
369
406
  *
370
407
  * The `params` given are never mutated: neither the object itself nor any array
@@ -379,6 +416,8 @@ function sortQueryParams(params, options) {
379
416
  * 'repeat': appends the key for every value e.g. `ids=1&ids=2`
380
417
  * 'comma' (default): appends the key once with a comma separated list of values e.g. `ids=1,2`
381
418
  *
419
+ * @summary Serializes query params into a string with keys and array values sorted, so equivalent queries share one
420
+ * URL.
382
421
  * @public
383
422
  * @return A sorted query params string without the leading `?`
384
423
  */