@warp-drive-mirror/utilities 5.10.0-alpha.2 → 5.10.0-alpha.21

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 (131) hide show
  1. package/README.md +92 -7
  2. package/cjs-dist/string.cjs +23 -8
  3. package/cjs-dist/string.cjs.map +1 -1
  4. package/dist/-private.d.ts +0 -2
  5. package/dist/-private.d.ts.map +1 -1
  6. package/dist/-private.js +1 -1
  7. package/dist/active-record.d.ts +21 -6
  8. package/dist/active-record.d.ts.map +1 -1
  9. package/dist/active-record.js +17 -8
  10. package/dist/active-record.js.map +1 -1
  11. package/dist/{builder-utils-BkXwUT0x.js → builder-utils-bjXbHa-m.js} +2 -3
  12. package/dist/{builder-utils-BkXwUT0x.js.map → builder-utils-bjXbHa-m.js.map} +1 -1
  13. package/dist/derivations.d.ts +3 -2
  14. package/dist/derivations.d.ts.map +1 -1
  15. package/dist/derivations.js +7 -2
  16. package/dist/derivations.js.map +1 -1
  17. package/dist/handlers.d.ts +26 -9
  18. package/dist/handlers.d.ts.map +1 -1
  19. package/dist/handlers.js +29 -9
  20. package/dist/handlers.js.map +1 -1
  21. package/dist/{index-BeMAuqgZ.d.ts → index-Dv5kZpGe.d.ts} +47 -3
  22. package/dist/index-Dv5kZpGe.d.ts.map +1 -0
  23. package/dist/index.d.ts +1 -1
  24. package/dist/index.js +54 -8
  25. package/dist/index.js.map +1 -1
  26. package/dist/{inflections-DzBsjJqj.js → inflections-CWdUh2K_.js} +2 -3
  27. package/dist/{inflections-DzBsjJqj.js.map → inflections-CWdUh2K_.js.map} +1 -1
  28. package/dist/json-api.d.ts +51 -11
  29. package/dist/json-api.d.ts.map +1 -1
  30. package/dist/json-api.js +43 -12
  31. package/dist/json-api.js.map +1 -1
  32. package/dist/rest.d.ts +20 -6
  33. package/dist/rest.d.ts.map +1 -1
  34. package/dist/rest.js +17 -8
  35. package/dist/rest.js.map +1 -1
  36. package/dist/{string-CWmAluxh.js → string-DFhbMVCj.js} +23 -6
  37. package/dist/string-DFhbMVCj.js.map +1 -0
  38. package/dist/string.d.ts +19 -4
  39. package/dist/string.d.ts.map +1 -1
  40. package/dist/string.js +1 -1
  41. package/dist/unpkg/dev/-private.js +1 -1
  42. package/dist/unpkg/dev/active-record.js +17 -8
  43. package/dist/unpkg/dev/active-record.js.map +1 -1
  44. package/dist/unpkg/dev/{builder-utils-BkXwUT0x.js → builder-utils-bjXbHa-m.js} +2 -3
  45. package/dist/unpkg/dev/{builder-utils-BkXwUT0x.js.map → builder-utils-bjXbHa-m.js.map} +1 -1
  46. package/dist/unpkg/dev/derivations.js +7 -2
  47. package/dist/unpkg/dev/derivations.js.map +1 -1
  48. package/dist/unpkg/dev/handlers.js +29 -9
  49. package/dist/unpkg/dev/handlers.js.map +1 -1
  50. package/dist/unpkg/dev/index.js +54 -8
  51. package/dist/unpkg/dev/index.js.map +1 -1
  52. package/dist/unpkg/dev/{inflections-DzBsjJqj.js → inflections-CWdUh2K_.js} +2 -3
  53. package/dist/unpkg/dev/{inflections-DzBsjJqj.js.map → inflections-CWdUh2K_.js.map} +1 -1
  54. package/dist/unpkg/dev/json-api.js +43 -12
  55. package/dist/unpkg/dev/json-api.js.map +1 -1
  56. package/dist/unpkg/dev/rest.js +17 -8
  57. package/dist/unpkg/dev/rest.js.map +1 -1
  58. package/dist/unpkg/dev/{string-j4ur-TDs.js → string-D9jrClhQ.js} +23 -6
  59. package/dist/unpkg/dev/string-D9jrClhQ.js.map +1 -0
  60. package/dist/unpkg/dev/string.js +1 -1
  61. package/dist/unpkg/dev-deprecated/-private.js +1 -1
  62. package/dist/unpkg/dev-deprecated/active-record.js +17 -8
  63. package/dist/unpkg/dev-deprecated/active-record.js.map +1 -1
  64. package/dist/unpkg/dev-deprecated/{builder-utils-BkXwUT0x.js → builder-utils-bjXbHa-m.js} +2 -3
  65. package/dist/unpkg/dev-deprecated/{builder-utils-BkXwUT0x.js.map → builder-utils-bjXbHa-m.js.map} +1 -1
  66. package/dist/unpkg/dev-deprecated/derivations.js +7 -2
  67. package/dist/unpkg/dev-deprecated/derivations.js.map +1 -1
  68. package/dist/unpkg/dev-deprecated/handlers.js +29 -9
  69. package/dist/unpkg/dev-deprecated/handlers.js.map +1 -1
  70. package/dist/unpkg/dev-deprecated/index.js +54 -8
  71. package/dist/unpkg/dev-deprecated/index.js.map +1 -1
  72. package/dist/unpkg/dev-deprecated/{inflections-DzBsjJqj.js → inflections-CWdUh2K_.js} +2 -3
  73. package/dist/unpkg/dev-deprecated/{inflections-DzBsjJqj.js.map → inflections-CWdUh2K_.js.map} +1 -1
  74. package/dist/unpkg/dev-deprecated/json-api.js +43 -12
  75. package/dist/unpkg/dev-deprecated/json-api.js.map +1 -1
  76. package/dist/unpkg/dev-deprecated/rest.js +17 -8
  77. package/dist/unpkg/dev-deprecated/rest.js.map +1 -1
  78. package/dist/unpkg/dev-deprecated/{string-j4ur-TDs.js → string-D9jrClhQ.js} +23 -6
  79. package/dist/unpkg/dev-deprecated/string-D9jrClhQ.js.map +1 -0
  80. package/dist/unpkg/dev-deprecated/string.js +1 -1
  81. package/dist/unpkg/prod/-private.js +1 -1
  82. package/dist/unpkg/prod/active-record.js +17 -8
  83. package/dist/unpkg/prod/active-record.js.map +1 -1
  84. package/dist/unpkg/prod/builder-utils-bjXbHa-m.js +15 -0
  85. package/dist/unpkg/prod/{builder-utils-BkXwUT0x.js.map → builder-utils-bjXbHa-m.js.map} +1 -1
  86. package/dist/unpkg/prod/derivations.js +7 -2
  87. package/dist/unpkg/prod/derivations.js.map +1 -1
  88. package/dist/unpkg/prod/handlers.js +29 -9
  89. package/dist/unpkg/prod/handlers.js.map +1 -1
  90. package/dist/unpkg/prod/index.js +54 -8
  91. package/dist/unpkg/prod/index.js.map +1 -1
  92. package/dist/unpkg/prod/inflections-CWdUh2K_.js +79 -0
  93. package/dist/unpkg/prod/{inflections-DzBsjJqj.js.map → inflections-CWdUh2K_.js.map} +1 -1
  94. package/dist/unpkg/prod/json-api.js +43 -12
  95. package/dist/unpkg/prod/json-api.js.map +1 -1
  96. package/dist/unpkg/prod/rest.js +17 -8
  97. package/dist/unpkg/prod/rest.js.map +1 -1
  98. package/dist/unpkg/prod/string-Du9nRZEd.js +300 -0
  99. package/dist/unpkg/prod/string-Du9nRZEd.js.map +1 -0
  100. package/dist/unpkg/prod/string.js +1 -1
  101. package/dist/unpkg/prod-deprecated/-private.js +1 -1
  102. package/dist/unpkg/prod-deprecated/active-record.js +17 -8
  103. package/dist/unpkg/prod-deprecated/active-record.js.map +1 -1
  104. package/dist/unpkg/prod-deprecated/{builder-utils-BkXwUT0x.js → builder-utils-bjXbHa-m.js} +2 -3
  105. package/dist/unpkg/prod-deprecated/{builder-utils-BkXwUT0x.js.map → builder-utils-bjXbHa-m.js.map} +1 -1
  106. package/dist/unpkg/prod-deprecated/derivations.js +7 -2
  107. package/dist/unpkg/prod-deprecated/derivations.js.map +1 -1
  108. package/dist/unpkg/prod-deprecated/handlers.js +29 -9
  109. package/dist/unpkg/prod-deprecated/handlers.js.map +1 -1
  110. package/dist/unpkg/prod-deprecated/index.js +54 -8
  111. package/dist/unpkg/prod-deprecated/index.js.map +1 -1
  112. package/dist/unpkg/prod-deprecated/{inflections-DzBsjJqj.js → inflections-CWdUh2K_.js} +2 -3
  113. package/dist/unpkg/prod-deprecated/{inflections-DzBsjJqj.js.map → inflections-CWdUh2K_.js.map} +1 -1
  114. package/dist/unpkg/prod-deprecated/json-api.js +43 -12
  115. package/dist/unpkg/prod-deprecated/json-api.js.map +1 -1
  116. package/dist/unpkg/prod-deprecated/rest.js +17 -8
  117. package/dist/unpkg/prod-deprecated/rest.js.map +1 -1
  118. package/dist/unpkg/prod-deprecated/{string-T1ahjLdj.js → string-Du9nRZEd.js} +23 -6
  119. package/dist/unpkg/prod-deprecated/string-Du9nRZEd.js.map +1 -0
  120. package/dist/unpkg/prod-deprecated/string.js +1 -1
  121. package/logos/README.md +1 -1
  122. package/package.json +9 -9
  123. package/dist/index-BeMAuqgZ.d.ts.map +0 -1
  124. package/dist/string-CWmAluxh.js.map +0 -1
  125. package/dist/unpkg/dev/string-j4ur-TDs.js.map +0 -1
  126. package/dist/unpkg/dev-deprecated/string-j4ur-TDs.js.map +0 -1
  127. package/dist/unpkg/prod/builder-utils-BkXwUT0x.js +0 -16
  128. package/dist/unpkg/prod/inflections-DzBsjJqj.js +0 -80
  129. package/dist/unpkg/prod/string-T1ahjLdj.js +0 -283
  130. package/dist/unpkg/prod/string-T1ahjLdj.js.map +0 -1
  131. package/dist/unpkg/prod-deprecated/string-T1ahjLdj.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"active-record.js","names":["recordIdentifierFor","buildBaseURL","pluralize","underscore","copyForwardUrlOptions","macroCondition","getGlobalConfig","isExisting","identifier","id","type","deleteRecord","record","options","WarpDrive","env","DEBUG","test","Error","urlOptions","op","resourcePath","url","headers","Headers","append","method","data","records","createRecord","updateRecord","patch"],"sources":["../src/-private/active-record/find-record.ts","../src/-private/active-record/query.ts","../src/-private/active-record/save-record.ts"],"sourcesContent":["import type { ReactiveDataDocument } from '@warp-drive-mirror/core/reactive';\nimport type { TypeFromInstance } from '@warp-drive-mirror/core/types/record';\nimport type {\n FindRecordOptions,\n FindRecordRequestOptions,\n RemotelyAccessibleIdentifier,\n} from '@warp-drive-mirror/core/types/request';\nimport type { Meta } from '@warp-drive-mirror/core/types/spec/json-api-raw';\n\nimport { buildBaseURL, buildQueryParams, type FindRecordUrlOptions } from '../../index.ts';\nimport { pluralize, underscore } from '../../string.ts';\nimport { copyForwardUrlOptions, extractCacheOptions } from '../builder-utils.ts';\n\n/**\n * Builds request options to fetch a single resource by a known id or identifier\n * configured for the url and header expectations of most ActiveRecord APIs.\n *\n * **Basic Usage**\n *\n * ```ts\n * import { findRecord } from '@warp-drive-mirror/utilities/active-record';\n *\n * const data = await store.request(findRecord('person', '1'));\n * ```\n *\n * **With Options**\n *\n * ```ts\n * import { findRecord } from '@warp-drive-mirror/utilities/active-record';\n *\n * const options = findRecord('person', '1', { include: ['pets', 'friends'] });\n * const data = await store.request(options);\n * ```\n *\n * **With an Identifier**\n *\n * ```ts\n * import { findRecord } from '@warp-drive-mirror/utilities/active-record';\n *\n * const options = findRecord({ type: 'person', id: '1' }, { include: ['pets', 'friends'] });\n * const data = await store.request(options);\n * ```\n *\n * **Supplying Options to Modify the Request Behavior**\n *\n * The following options are supported:\n *\n * - `host` - The host to use for the request, defaults to the `host` configured with `setBuildURLConfig`.\n * - `namespace` - The namespace to use for the request, defaults to the `namespace` configured with `setBuildURLConfig`.\n * - `resourcePath` - The resource path to use for the request, defaults to pluralizing and underscoring the supplied type\n * - `reload` - Whether to forcibly reload the request if it is already in the store, not supplying this\n * option will delegate to the store's CachePolicy, defaulting to `false` if none is configured.\n * - `backgroundReload` - Whether to reload the request if it is already in the store, but to also resolve the\n * promise with the cached value, not supplying this option will delegate to the store's CachePolicy,\n * defaulting to `false` if none is configured.\n * - `urlParamsSetting` - an object containing options for how to serialize the query params (see `buildQueryParams`)\n *\n * ```ts\n * import { findRecord } from '@warp-drive-mirror/utilities/active-record';\n *\n * const options = findRecord('person', '1', { include: ['pets', 'friends'] }, { namespace: 'api/v2' });\n * const data = await store.request(options);\n * ```\n *\n * @public\n * @param identifier\n * @param options\n */\nexport function findRecord<T, M extends Meta | undefined = Meta | undefined, E extends object = object>(\n identifier: RemotelyAccessibleIdentifier<TypeFromInstance<T>>,\n options?: FindRecordOptions\n): FindRecordRequestOptions<ReactiveDataDocument<T, M, E>, T>;\nexport function findRecord(\n identifier: RemotelyAccessibleIdentifier,\n options?: FindRecordOptions\n): FindRecordRequestOptions;\nexport function findRecord<T, M extends Meta | undefined = Meta | undefined, E extends object = object>(\n type: TypeFromInstance<T>,\n id: string,\n options?: FindRecordOptions\n): FindRecordRequestOptions<ReactiveDataDocument<T, M, E>, T>;\nexport function findRecord(type: string, id: string, options?: FindRecordOptions): FindRecordRequestOptions;\nexport function findRecord(\n arg1: string | RemotelyAccessibleIdentifier,\n arg2: string | FindRecordOptions | undefined,\n arg3?: FindRecordOptions\n): FindRecordRequestOptions {\n const identifier: RemotelyAccessibleIdentifier = typeof arg1 === 'string' ? { type: arg1, id: arg2 as string } : arg1;\n const options = ((typeof arg1 === 'string' ? arg3 : arg2) || {}) as FindRecordOptions;\n const cacheOptions = extractCacheOptions(options);\n const urlOptions: FindRecordUrlOptions = {\n identifier,\n op: 'findRecord',\n resourcePath: pluralize(underscore(identifier.type)),\n };\n\n copyForwardUrlOptions(urlOptions, options);\n\n const url = buildBaseURL(urlOptions);\n const headers = new Headers();\n headers.append('Accept', 'application/json;charset=utf-8');\n\n return {\n url: options.include?.length\n ? `${url}?${buildQueryParams({ include: options.include }, options.urlParamsSettings)}`\n : url,\n method: 'GET',\n headers,\n cacheOptions,\n op: 'findRecord',\n records: [identifier],\n };\n}\n\n/** @deprecated use {@link ReactiveDataDocument} instead */\nexport type FindRecordResultDocument<\n T,\n M extends Meta | undefined = Meta | undefined,\n E extends object = object,\n> = ReactiveDataDocument<T, M, E>;\n","import type { ReactiveDataDocument } from '@warp-drive-mirror/core/reactive';\nimport type { QueryParamsSource } from '@warp-drive-mirror/core/types/params';\nimport type { TypeFromInstance } from '@warp-drive-mirror/core/types/record';\nimport type { ConstrainedRequestOptions, QueryRequestOptions } from '@warp-drive-mirror/core/types/request';\nimport type { Meta } from '@warp-drive-mirror/core/types/spec/json-api-raw';\n\nimport { buildBaseURL, buildQueryParams, type QueryUrlOptions } from '../../index.ts';\nimport { pluralize, underscore } from '../../string';\nimport { copyForwardUrlOptions, extractCacheOptions } from '../builder-utils.ts';\n\n/**\n * Builds request options to query for resources, usually by a primary\n * type, configured for the url and header expectations of most ActiveRecord APIs.\n *\n * **Basic Usage**\n *\n * ```ts\n * import { query } from '@warp-drive-mirror/utilities/active-record';\n *\n * const data = await store.request(query('person'));\n * ```\n *\n * **With Query Params**\n *\n * ```ts\n * import { query } from '@warp-drive-mirror/utilities/active-record';\n *\n * const options = query('person', { include: ['pets', 'friends'] });\n * const data = await store.request(options);\n * ```\n *\n * **Supplying Options to Modify the Request Behavior**\n *\n * The following options are supported:\n *\n * - `host` - The host to use for the request, defaults to the `host` configured with `setBuildURLConfig`.\n * - `namespace` - The namespace to use for the request, defaults to the `namespace` configured with `setBuildURLConfig`.\n * - `resourcePath` - The resource path to use for the request, defaults to pluralizing and underscoring the supplied type\n * - `reload` - Whether to forcibly reload the request if it is already in the store, not supplying this\n * option will delegate to the store's CachePolicy, defaulting to `false` if none is configured.\n * - `backgroundReload` - Whether to reload the request if it is already in the store, but to also resolve the\n * promise with the cached value, not supplying this option will delegate to the store's CachePolicy,\n * defaulting to `false` if none is configured.\n * - `urlParamsSetting` - an object containing options for how to serialize the query params (see `buildQueryParams`)\n *\n * ```ts\n * import { query } from '@warp-drive-mirror/utilities/active-record';\n *\n * const options = query('person', { include: ['pets', 'friends'] }, { reload: true });\n * const data = await store.request(options);\n * ```\n *\n * @public\n * @param identifier\n * @param query\n * @param options\n */\nexport function query<T, M extends Meta | undefined = Meta | undefined, E extends object = object>(\n type: TypeFromInstance<T>,\n query?: QueryParamsSource,\n options?: ConstrainedRequestOptions\n): QueryRequestOptions<ReactiveDataDocument<T[], M, E>>;\nexport function query(\n type: string,\n query?: QueryParamsSource,\n options?: ConstrainedRequestOptions\n): QueryRequestOptions;\nexport function query(\n type: string,\n // oxlint-disable-next-line no-shadow\n query: QueryParamsSource = {},\n options: ConstrainedRequestOptions = {}\n): QueryRequestOptions {\n const cacheOptions = extractCacheOptions(options);\n const urlOptions: QueryUrlOptions = {\n identifier: { type },\n op: 'query',\n resourcePath: pluralize(underscore(type)),\n };\n\n copyForwardUrlOptions(urlOptions, options);\n\n const url = buildBaseURL(urlOptions);\n const headers = new Headers();\n headers.append('Accept', 'application/json;charset=utf-8');\n const queryString = buildQueryParams(query, options.urlParamsSettings);\n\n return {\n url: queryString ? `${url}?${queryString}` : url,\n method: 'GET',\n headers,\n cacheOptions,\n op: 'query',\n };\n}\n","import { recordIdentifierFor } from '@warp-drive-mirror/core';\nimport { assert } from '@warp-drive-mirror/core/build-config/macros';\nimport type { ReactiveDataDocument } from '@warp-drive-mirror/core/reactive';\nimport type { PersistedResourceKey, ResourceKey } from '@warp-drive-mirror/core/types/identifier';\nimport type { TypedRecordInstance } from '@warp-drive-mirror/core/types/record';\nimport type {\n ConstrainedRequestOptions,\n CreateRequestOptions,\n DeleteRequestOptions,\n UpdateRequestOptions,\n} from '@warp-drive-mirror/core/types/request';\nimport type { Meta } from '@warp-drive-mirror/core/types/spec/json-api-raw';\n\nimport {\n buildBaseURL,\n type CreateRecordUrlOptions,\n type DeleteRecordUrlOptions,\n type UpdateRecordUrlOptions,\n} from '../../index.ts';\nimport { pluralize, underscore } from '../../string';\nimport { copyForwardUrlOptions } from '../builder-utils.ts';\n\nfunction isExisting(identifier: ResourceKey): identifier is PersistedResourceKey {\n return 'id' in identifier && identifier.id !== null && 'type' in identifier && identifier.type !== null;\n}\n\n/**\n * Builds request options to delete record for resources,\n * configured for the url, method and header expectations of ActiveRecord APIs.\n *\n * **Basic Usage**\n *\n * ```ts\n * import { deleteRecord } from '@warp-drive-mirror/utilities/active-record';\n *\n * const person = store.peekRecord('person', '1');\n *\n * // mark record as deleted\n * store.deleteRecord(person);\n *\n * // persist deletion\n * const data = await store.request(deleteRecord(person));\n * ```\n *\n * **Supplying Options to Modify the Request Behavior**\n *\n * The following options are supported:\n *\n * - `host` - The host to use for the request, defaults to the `host` configured with `setBuildURLConfig`.\n * - `namespace` - The namespace to use for the request, defaults to the `namespace` configured with `setBuildURLConfig`.\n * - `resourcePath` - The resource path to use for the request, defaults to pluralizing the supplied type\n * - `reload` - Whether to forcibly reload the request if it is already in the store, not supplying this\n * option will delegate to the store's CachePolicy, defaulting to `false` if none is configured.\n * - `backgroundReload` - Whether to reload the request if it is already in the store, but to also resolve the\n * promise with the cached value, not supplying this option will delegate to the store's CachePolicy,\n * defaulting to `false` if none is configured.\n * - `urlParamsSetting` - an object containing options for how to serialize the query params (see `buildQueryParams`)\n *\n * ```ts\n * import { deleteRecord } from '@warp-drive-mirror/utilities/active-record';\n *\n * const person = store.peekRecord('person', '1');\n *\n * // mark record as deleted\n * store.deleteRecord(person);\n *\n * // persist deletion\n * const options = deleteRecord(person, { namespace: 'api/v1' });\n * const data = await store.request(options);\n * ```\n *\n * @public\n * @param record\n * @param options\n */\nexport function deleteRecord<T>(record: T, options?: ConstrainedRequestOptions): DeleteRequestOptions<T>;\nexport function deleteRecord(record: unknown, options?: ConstrainedRequestOptions): DeleteRequestOptions;\nexport function deleteRecord(record: unknown, options: ConstrainedRequestOptions = {}): DeleteRequestOptions {\n const identifier = recordIdentifierFor(record);\n assert(`Expected to be given a record instance`, identifier);\n assert(`Cannot delete a record that does not have an associated type and id.`, isExisting(identifier));\n\n const urlOptions: DeleteRecordUrlOptions = {\n identifier: identifier,\n op: 'deleteRecord',\n resourcePath: pluralize(underscore(identifier.type)),\n };\n\n copyForwardUrlOptions(urlOptions, options);\n\n const url = buildBaseURL(urlOptions);\n const headers = new Headers();\n headers.append('Accept', 'application/json;charset=utf-8');\n\n return {\n url,\n method: 'DELETE',\n headers,\n op: 'deleteRecord',\n data: {\n record: identifier,\n },\n records: [identifier],\n };\n}\n\n/**\n * Builds request options to create new record for resources,\n * configured for the url, method and header expectations of most ActiveRecord APIs.\n *\n * **Basic Usage**\n *\n * ```ts\n * import { createRecord } from '@warp-drive-mirror/utilities/active-record';\n *\n * const person = store.createRecord('person', { name: 'Ted' });\n * const data = await store.request(createRecord(person));\n * ```\n *\n * **Supplying Options to Modify the Request Behavior**\n *\n * The following options are supported:\n *\n * - `host` - The host to use for the request, defaults to the `host` configured with `setBuildURLConfig`.\n * - `namespace` - The namespace to use for the request, defaults to the `namespace` configured with `setBuildURLConfig`.\n * - `resourcePath` - The resource path to use for the request, defaults to pluralizing the supplied type\n * - `reload` - Whether to forcibly reload the request if it is already in the store, not supplying this\n * option will delegate to the store's CachePolicy, defaulting to `false` if none is configured.\n * - `backgroundReload` - Whether to reload the request if it is already in the store, but to also resolve the\n * promise with the cached value, not supplying this option will delegate to the store's CachePolicy,\n * defaulting to `false` if none is configured.\n * - `urlParamsSetting` - an object containing options for how to serialize the query params (see `buildQueryParams`)\n *\n * ```ts\n * import { createRecord } from '@warp-drive-mirror/utilities/active-record';\n *\n * const person = store.createRecord('person', { name: 'Ted' });\n * const options = createRecord(person, { namespace: 'api/v1' });\n * const data = await store.request(options);\n * ```\n *\n * @public\n * @param record\n * @param options\n */\nexport function createRecord<T>(record: T, options?: ConstrainedRequestOptions): CreateRequestOptions<T>;\nexport function createRecord(record: unknown, options?: ConstrainedRequestOptions): CreateRequestOptions;\nexport function createRecord(record: unknown, options: ConstrainedRequestOptions = {}): CreateRequestOptions {\n const identifier = recordIdentifierFor(record);\n assert(`Expected to be given a record instance`, identifier);\n\n const urlOptions: CreateRecordUrlOptions = {\n identifier: identifier,\n op: 'createRecord',\n resourcePath: pluralize(underscore(identifier.type)),\n };\n\n copyForwardUrlOptions(urlOptions, options);\n\n const url = buildBaseURL(urlOptions);\n const headers = new Headers();\n headers.append('Accept', 'application/json;charset=utf-8');\n\n return {\n url,\n method: 'POST',\n headers,\n op: 'createRecord',\n data: {\n record: identifier,\n },\n records: [identifier],\n };\n}\n\n/**\n * Builds request options to update existing record for resources,\n * configured for the url, method and header expectations of most ActiveRecord APIs.\n *\n * **Basic Usage**\n *\n * ```ts\n * import { updateRecord } from '@warp-drive-mirror/utilities/active-record';\n *\n * const person = store.peekRecord('person', '1');\n * person.name = 'Chris';\n * const data = await store.request(updateRecord(person));\n * ```\n *\n * **Supplying Options to Modify the Request Behavior**\n *\n * The following options are supported:\n *\n * - `patch` - Allows caller to specify whether to use a PATCH request instead of a PUT request, defaults to `false`.\n * - `host` - The host to use for the request, defaults to the `host` configured with `setBuildURLConfig`.\n * - `namespace` - The namespace to use for the request, defaults to the `namespace` configured with `setBuildURLConfig`.\n * - `resourcePath` - The resource path to use for the request, defaults to pluralizing the supplied type\n * - `reload` - Whether to forcibly reload the request if it is already in the store, not supplying this\n * option will delegate to the store's CachePolicy, defaulting to `false` if none is configured.\n * - `backgroundReload` - Whether to reload the request if it is already in the store, but to also resolve the\n * promise with the cached value, not supplying this option will delegate to the store's CachePolicy,\n * defaulting to `false` if none is configured.\n * - `urlParamsSetting` - an object containing options for how to serialize the query params (see `buildQueryParams`)\n *\n * ```ts\n * import { updateRecord } from '@warp-drive-mirror/utilities/active-record';\n *\n * const person = store.peekRecord('person', '1');\n * person.name = 'Chris';\n * const options = updateRecord(person, { patch: true });\n * const data = await store.request(options);\n * ```\n *\n * @public\n * @param record\n * @param options\n */\nexport function updateRecord<\n T extends TypedRecordInstance,\n RT extends TypedRecordInstance = T,\n M extends Meta | undefined = Meta | undefined,\n E extends object = object,\n>(\n record: T,\n options?: ConstrainedRequestOptions & { patch?: boolean }\n): UpdateRequestOptions<ReactiveDataDocument<RT, M, E>, T>;\nexport function updateRecord(\n record: unknown,\n options?: ConstrainedRequestOptions & { patch?: boolean }\n): UpdateRequestOptions;\nexport function updateRecord(\n record: unknown,\n options: ConstrainedRequestOptions & { patch?: boolean } = {}\n): UpdateRequestOptions {\n const identifier = recordIdentifierFor(record);\n assert(`Expected to be given a record instance`, identifier);\n assert(`Cannot update a record that does not have an associated type and id.`, isExisting(identifier));\n\n const urlOptions: UpdateRecordUrlOptions = {\n identifier: identifier,\n op: 'updateRecord',\n resourcePath: pluralize(underscore(identifier.type)),\n };\n\n copyForwardUrlOptions(urlOptions, options);\n\n const url = buildBaseURL(urlOptions);\n const headers = new Headers();\n headers.append('Accept', 'application/json;charset=utf-8');\n\n return {\n url,\n method: options.patch ? 'PATCH' : 'PUT',\n headers,\n op: 'updateRecord',\n data: {\n record: identifier,\n },\n records: [identifier],\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"active-record.js","names":["recordIdentifierFor","buildBaseURL","pluralize","underscore","copyForwardUrlOptions","macroCondition","getGlobalConfig","isExisting","identifier","id","type","deleteRecord","record","options","WarpDrive","env","DEBUG","test","Error","urlOptions","op","resourcePath","url","headers","Headers","append","method","data","records","createRecord","updateRecord","patch"],"sources":["../src/-private/active-record/find-record.ts","../src/-private/active-record/query.ts","../src/-private/active-record/save-record.ts"],"sourcesContent":["import type { ReactiveDataDocument } from '@warp-drive-mirror/core/reactive';\nimport type { TypeFromInstance } from '@warp-drive-mirror/core/types/record';\nimport type {\n FindRecordOptions,\n FindRecordRequestOptions,\n RemotelyAccessibleIdentifier,\n} from '@warp-drive-mirror/core/types/request';\nimport type { Meta } from '@warp-drive-mirror/core/types/spec/json-api-raw';\n\nimport { buildBaseURL, buildQueryParams, type FindRecordUrlOptions } from '../../index.ts';\nimport { pluralize, underscore } from '../../string.ts';\nimport { copyForwardUrlOptions, extractCacheOptions } from '../builder-utils.ts';\n\n/**\n * Builds request options to fetch a single resource by a known id or identifier\n * configured for the url and header expectations of most ActiveRecord APIs.\n *\n * See the [Builders](/guides/the-manual/requests/builders) guide for what request builders do and\n * when to use one.\n *\n * **Basic Usage**\n *\n * ```ts\n * import { findRecord } from '@warp-drive-mirror/utilities/active-record';\n *\n * const data = await store.request(findRecord('person', '1'));\n * ```\n *\n * **With Options**\n *\n * ```ts\n * import { findRecord } from '@warp-drive-mirror/utilities/active-record';\n *\n * const options = findRecord('person', '1', { include: ['pets', 'friends'] });\n * const data = await store.request(options);\n * ```\n *\n * **With an Identifier**\n *\n * ```ts\n * import { findRecord } from '@warp-drive-mirror/utilities/active-record';\n *\n * const options = findRecord({ type: 'person', id: '1' }, { include: ['pets', 'friends'] });\n * const data = await store.request(options);\n * ```\n *\n * **Supplying Options to Modify the Request Behavior**\n *\n * The following options are supported:\n *\n * - `host` - The host to use for the request, defaults to the `host` configured with `setBuildURLConfig`.\n * - `namespace` - The namespace to use for the request, defaults to the `namespace` configured with `setBuildURLConfig`.\n * - `resourcePath` - The resource path to use for the request, defaults to pluralizing and underscoring the supplied type\n * - `reload` - Whether to forcibly reload the request if it is already in the store, not supplying this\n * option will delegate to the store's CachePolicy, defaulting to `false` if none is configured.\n * - `backgroundReload` - Whether to reload the request if it is already in the store, but to also resolve the\n * promise with the cached value, not supplying this option will delegate to the store's CachePolicy,\n * defaulting to `false` if none is configured.\n * - `urlParamsSetting` - an object containing options for how to serialize the query params (see `buildQueryParams`)\n *\n * ```ts\n * import { findRecord } from '@warp-drive-mirror/utilities/active-record';\n *\n * const options = findRecord('person', '1', { include: ['pets', 'friends'] }, { namespace: 'api/v2' });\n * const data = await store.request(options);\n * ```\n *\n * @summary Builds a `GET` request for one resource by type and id, using ActiveRecord-style pluralized, underscored\n * URLs.\n * @public\n * @param identifier\n * @param options\n */\nexport function findRecord<T, M extends Meta | undefined = Meta | undefined, E extends object = object>(\n identifier: RemotelyAccessibleIdentifier<TypeFromInstance<T>>,\n options?: FindRecordOptions\n): FindRecordRequestOptions<ReactiveDataDocument<T, M, E>, T>;\nexport function findRecord(\n identifier: RemotelyAccessibleIdentifier,\n options?: FindRecordOptions\n): FindRecordRequestOptions;\nexport function findRecord<T, M extends Meta | undefined = Meta | undefined, E extends object = object>(\n type: TypeFromInstance<T>,\n id: string,\n options?: FindRecordOptions\n): FindRecordRequestOptions<ReactiveDataDocument<T, M, E>, T>;\nexport function findRecord(type: string, id: string, options?: FindRecordOptions): FindRecordRequestOptions;\nexport function findRecord(\n arg1: string | RemotelyAccessibleIdentifier,\n arg2: string | FindRecordOptions | undefined,\n arg3?: FindRecordOptions\n): FindRecordRequestOptions {\n const identifier: RemotelyAccessibleIdentifier = typeof arg1 === 'string' ? { type: arg1, id: arg2 as string } : arg1;\n const options = ((typeof arg1 === 'string' ? arg3 : arg2) || {}) as FindRecordOptions;\n const cacheOptions = extractCacheOptions(options);\n const urlOptions: FindRecordUrlOptions = {\n identifier,\n op: 'findRecord',\n resourcePath: pluralize(underscore(identifier.type)),\n };\n\n copyForwardUrlOptions(urlOptions, options);\n\n const url = buildBaseURL(urlOptions);\n const headers = new Headers();\n headers.append('Accept', 'application/json;charset=utf-8');\n\n return {\n url: options.include?.length\n ? `${url}?${buildQueryParams({ include: options.include }, options.urlParamsSettings)}`\n : url,\n method: 'GET',\n headers,\n cacheOptions,\n op: 'findRecord',\n records: [identifier],\n };\n}\n\n/** @deprecated use {@link ReactiveDataDocument} instead */\nexport type FindRecordResultDocument<\n T,\n M extends Meta | undefined = Meta | undefined,\n E extends object = object,\n> = ReactiveDataDocument<T, M, E>;\n","import type { ReactiveDataDocument } from '@warp-drive-mirror/core/reactive';\nimport type { QueryParamsSource } from '@warp-drive-mirror/core/types/params';\nimport type { TypeFromInstance } from '@warp-drive-mirror/core/types/record';\nimport type { ConstrainedRequestOptions, QueryRequestOptions } from '@warp-drive-mirror/core/types/request';\nimport type { Meta } from '@warp-drive-mirror/core/types/spec/json-api-raw';\n\nimport { buildBaseURL, buildQueryParams, type QueryUrlOptions } from '../../index.ts';\nimport { pluralize, underscore } from '../../string';\nimport { copyForwardUrlOptions, extractCacheOptions } from '../builder-utils.ts';\n\n/**\n * Builds request options to query for resources, usually by a primary\n * type, configured for the url and header expectations of most ActiveRecord APIs.\n *\n * See the [Builders](/guides/the-manual/requests/builders) guide for what request builders do and\n * when to use one.\n *\n * **Basic Usage**\n *\n * ```ts\n * import { query } from '@warp-drive-mirror/utilities/active-record';\n *\n * const data = await store.request(query('person'));\n * ```\n *\n * **With Query Params**\n *\n * ```ts\n * import { query } from '@warp-drive-mirror/utilities/active-record';\n *\n * const options = query('person', { include: ['pets', 'friends'] });\n * const data = await store.request(options);\n * ```\n *\n * **Supplying Options to Modify the Request Behavior**\n *\n * The following options are supported:\n *\n * - `host` - The host to use for the request, defaults to the `host` configured with `setBuildURLConfig`.\n * - `namespace` - The namespace to use for the request, defaults to the `namespace` configured with `setBuildURLConfig`.\n * - `resourcePath` - The resource path to use for the request, defaults to pluralizing and underscoring the supplied type\n * - `reload` - Whether to forcibly reload the request if it is already in the store, not supplying this\n * option will delegate to the store's CachePolicy, defaulting to `false` if none is configured.\n * - `backgroundReload` - Whether to reload the request if it is already in the store, but to also resolve the\n * promise with the cached value, not supplying this option will delegate to the store's CachePolicy,\n * defaulting to `false` if none is configured.\n * - `urlParamsSetting` - an object containing options for how to serialize the query params (see `buildQueryParams`)\n *\n * ```ts\n * import { query } from '@warp-drive-mirror/utilities/active-record';\n *\n * const options = query('person', { include: ['pets', 'friends'] }, { reload: true });\n * const data = await store.request(options);\n * ```\n *\n * @summary Builds a `GET` request that queries a resource type with query params, using ActiveRecord-style URLs.\n * @public\n * @param identifier\n * @param query\n * @param options\n */\nexport function query<T, M extends Meta | undefined = Meta | undefined, E extends object = object>(\n type: TypeFromInstance<T>,\n query?: QueryParamsSource,\n options?: ConstrainedRequestOptions\n): QueryRequestOptions<ReactiveDataDocument<T[], M, E>>;\nexport function query(\n type: string,\n query?: QueryParamsSource,\n options?: ConstrainedRequestOptions\n): QueryRequestOptions;\nexport function query(\n type: string,\n // oxlint-disable-next-line no-shadow\n query: QueryParamsSource = {},\n options: ConstrainedRequestOptions = {}\n): QueryRequestOptions {\n const cacheOptions = extractCacheOptions(options);\n const urlOptions: QueryUrlOptions = {\n identifier: { type },\n op: 'query',\n resourcePath: pluralize(underscore(type)),\n };\n\n copyForwardUrlOptions(urlOptions, options);\n\n const url = buildBaseURL(urlOptions);\n const headers = new Headers();\n headers.append('Accept', 'application/json;charset=utf-8');\n const queryString = buildQueryParams(query, options.urlParamsSettings);\n\n return {\n url: queryString ? `${url}?${queryString}` : url,\n method: 'GET',\n headers,\n cacheOptions,\n op: 'query',\n };\n}\n","import { recordIdentifierFor } from '@warp-drive-mirror/core';\nimport { assert } from '@warp-drive-mirror/core/build-config/macros';\nimport type { ReactiveDataDocument } from '@warp-drive-mirror/core/reactive';\nimport type { PersistedResourceKey, ResourceKey } from '@warp-drive-mirror/core/types/identifier';\nimport type { TypedRecordInstance } from '@warp-drive-mirror/core/types/record';\nimport type {\n ConstrainedRequestOptions,\n CreateRequestOptions,\n DeleteRequestOptions,\n UpdateRequestOptions,\n} from '@warp-drive-mirror/core/types/request';\nimport type { Meta } from '@warp-drive-mirror/core/types/spec/json-api-raw';\n\nimport {\n buildBaseURL,\n type CreateRecordUrlOptions,\n type DeleteRecordUrlOptions,\n type UpdateRecordUrlOptions,\n} from '../../index.ts';\nimport { pluralize, underscore } from '../../string';\nimport { copyForwardUrlOptions } from '../builder-utils.ts';\n\nfunction isExisting(identifier: ResourceKey): identifier is PersistedResourceKey {\n return 'id' in identifier && identifier.id !== null && 'type' in identifier && identifier.type !== null;\n}\n\n/**\n * Builds request options to delete record for resources,\n * configured for the url, method and header expectations of ActiveRecord APIs.\n *\n * See the [Builders](/guides/the-manual/requests/builders) guide for what request builders do and\n * when to use one.\n *\n * **Basic Usage**\n *\n * ```ts\n * import { deleteRecord } from '@warp-drive-mirror/utilities/active-record';\n *\n * const person = store.peekRecord('person', '1');\n *\n * // mark record as deleted\n * store.deleteRecord(person);\n *\n * // persist deletion\n * const data = await store.request(deleteRecord(person));\n * ```\n *\n * **Supplying Options to Modify the Request Behavior**\n *\n * The following options are supported:\n *\n * - `host` - The host to use for the request, defaults to the `host` configured with `setBuildURLConfig`.\n * - `namespace` - The namespace to use for the request, defaults to the `namespace` configured with `setBuildURLConfig`.\n * - `resourcePath` - The resource path to use for the request, defaults to pluralizing the supplied type\n * - `reload` - Whether to forcibly reload the request if it is already in the store, not supplying this\n * option will delegate to the store's CachePolicy, defaulting to `false` if none is configured.\n * - `backgroundReload` - Whether to reload the request if it is already in the store, but to also resolve the\n * promise with the cached value, not supplying this option will delegate to the store's CachePolicy,\n * defaulting to `false` if none is configured.\n * - `urlParamsSetting` - an object containing options for how to serialize the query params (see `buildQueryParams`)\n *\n * ```ts\n * import { deleteRecord } from '@warp-drive-mirror/utilities/active-record';\n *\n * const person = store.peekRecord('person', '1');\n *\n * // mark record as deleted\n * store.deleteRecord(person);\n *\n * // persist deletion\n * const options = deleteRecord(person, { namespace: 'api/v1' });\n * const data = await store.request(options);\n * ```\n *\n * @summary Builds a `DELETE` request that persists deletion of an existing record, using ActiveRecord-style URLs.\n * @public\n * @param record\n * @param options\n */\nexport function deleteRecord<T>(record: T, options?: ConstrainedRequestOptions): DeleteRequestOptions<T>;\nexport function deleteRecord(record: unknown, options?: ConstrainedRequestOptions): DeleteRequestOptions;\nexport function deleteRecord(record: unknown, options: ConstrainedRequestOptions = {}): DeleteRequestOptions {\n const identifier = recordIdentifierFor(record);\n assert(`Expected to be given a record instance`, identifier);\n assert(`Cannot delete a record that does not have an associated type and id.`, isExisting(identifier));\n\n const urlOptions: DeleteRecordUrlOptions = {\n identifier: identifier,\n op: 'deleteRecord',\n resourcePath: pluralize(underscore(identifier.type)),\n };\n\n copyForwardUrlOptions(urlOptions, options);\n\n const url = buildBaseURL(urlOptions);\n const headers = new Headers();\n headers.append('Accept', 'application/json;charset=utf-8');\n\n return {\n url,\n method: 'DELETE',\n headers,\n op: 'deleteRecord',\n data: {\n record: identifier,\n },\n records: [identifier],\n };\n}\n\n/**\n * Builds request options to create new record for resources,\n * configured for the url, method and header expectations of most ActiveRecord APIs.\n *\n * See the [Builders](/guides/the-manual/requests/builders) guide for what request builders do and\n * when to use one.\n *\n * **Basic Usage**\n *\n * ```ts\n * import { createRecord } from '@warp-drive-mirror/utilities/active-record';\n *\n * const person = store.createRecord('person', { name: 'Ted' });\n * const data = await store.request(createRecord(person));\n * ```\n *\n * **Supplying Options to Modify the Request Behavior**\n *\n * The following options are supported:\n *\n * - `host` - The host to use for the request, defaults to the `host` configured with `setBuildURLConfig`.\n * - `namespace` - The namespace to use for the request, defaults to the `namespace` configured with `setBuildURLConfig`.\n * - `resourcePath` - The resource path to use for the request, defaults to pluralizing the supplied type\n * - `reload` - Whether to forcibly reload the request if it is already in the store, not supplying this\n * option will delegate to the store's CachePolicy, defaulting to `false` if none is configured.\n * - `backgroundReload` - Whether to reload the request if it is already in the store, but to also resolve the\n * promise with the cached value, not supplying this option will delegate to the store's CachePolicy,\n * defaulting to `false` if none is configured.\n * - `urlParamsSetting` - an object containing options for how to serialize the query params (see `buildQueryParams`)\n *\n * ```ts\n * import { createRecord } from '@warp-drive-mirror/utilities/active-record';\n *\n * const person = store.createRecord('person', { name: 'Ted' });\n * const options = createRecord(person, { namespace: 'api/v1' });\n * const data = await store.request(options);\n * ```\n *\n * @summary Builds a `POST` request that saves a newly created record, using ActiveRecord-style URLs.\n * @public\n * @param record\n * @param options\n */\nexport function createRecord<T>(record: T, options?: ConstrainedRequestOptions): CreateRequestOptions<T>;\nexport function createRecord(record: unknown, options?: ConstrainedRequestOptions): CreateRequestOptions;\nexport function createRecord(record: unknown, options: ConstrainedRequestOptions = {}): CreateRequestOptions {\n const identifier = recordIdentifierFor(record);\n assert(`Expected to be given a record instance`, identifier);\n\n const urlOptions: CreateRecordUrlOptions = {\n identifier: identifier,\n op: 'createRecord',\n resourcePath: pluralize(underscore(identifier.type)),\n };\n\n copyForwardUrlOptions(urlOptions, options);\n\n const url = buildBaseURL(urlOptions);\n const headers = new Headers();\n headers.append('Accept', 'application/json;charset=utf-8');\n\n return {\n url,\n method: 'POST',\n headers,\n op: 'createRecord',\n data: {\n record: identifier,\n },\n records: [identifier],\n };\n}\n\n/**\n * Builds request options to update existing record for resources,\n * configured for the url, method and header expectations of most ActiveRecord APIs.\n *\n * See the [Builders](/guides/the-manual/requests/builders) guide for what request builders do and\n * when to use one.\n *\n * **Basic Usage**\n *\n * ```ts\n * import { updateRecord } from '@warp-drive-mirror/utilities/active-record';\n *\n * const person = store.peekRecord('person', '1');\n * person.name = 'Chris';\n * const data = await store.request(updateRecord(person));\n * ```\n *\n * **Supplying Options to Modify the Request Behavior**\n *\n * The following options are supported:\n *\n * - `patch` - Allows caller to specify whether to use a PATCH request instead of a PUT request, defaults to `false`.\n * - `host` - The host to use for the request, defaults to the `host` configured with `setBuildURLConfig`.\n * - `namespace` - The namespace to use for the request, defaults to the `namespace` configured with `setBuildURLConfig`.\n * - `resourcePath` - The resource path to use for the request, defaults to pluralizing the supplied type\n * - `reload` - Whether to forcibly reload the request if it is already in the store, not supplying this\n * option will delegate to the store's CachePolicy, defaulting to `false` if none is configured.\n * - `backgroundReload` - Whether to reload the request if it is already in the store, but to also resolve the\n * promise with the cached value, not supplying this option will delegate to the store's CachePolicy,\n * defaulting to `false` if none is configured.\n * - `urlParamsSetting` - an object containing options for how to serialize the query params (see `buildQueryParams`)\n *\n * ```ts\n * import { updateRecord } from '@warp-drive-mirror/utilities/active-record';\n *\n * const person = store.peekRecord('person', '1');\n * person.name = 'Chris';\n * const options = updateRecord(person, { patch: true });\n * const data = await store.request(options);\n * ```\n *\n * @summary Builds a `PUT` (or `PATCH`) request that saves changes to an existing record, using ActiveRecord-style URLs.\n * @public\n * @param record\n * @param options\n */\nexport function updateRecord<\n T extends TypedRecordInstance,\n RT extends TypedRecordInstance = T,\n M extends Meta | undefined = Meta | undefined,\n E extends object = object,\n>(\n record: T,\n options?: ConstrainedRequestOptions & { patch?: boolean }\n): UpdateRequestOptions<ReactiveDataDocument<RT, M, E>, T>;\nexport function updateRecord(\n record: unknown,\n options?: ConstrainedRequestOptions & { patch?: boolean }\n): UpdateRequestOptions;\nexport function updateRecord(\n record: unknown,\n options: ConstrainedRequestOptions & { patch?: boolean } = {}\n): UpdateRequestOptions {\n const identifier = recordIdentifierFor(record);\n assert(`Expected to be given a record instance`, identifier);\n assert(`Cannot update a record that does not have an associated type and id.`, isExisting(identifier));\n\n const urlOptions: UpdateRecordUrlOptions = {\n identifier: identifier,\n op: 'updateRecord',\n resourcePath: pluralize(underscore(identifier.type)),\n };\n\n copyForwardUrlOptions(urlOptions, options);\n\n const url = buildBaseURL(urlOptions);\n const headers = new Headers();\n headers.append('Accept', 'application/json;charset=utf-8');\n\n return {\n url,\n method: options.patch ? 'PATCH' : 'PUT',\n headers,\n op: 'updateRecord',\n data: {\n record: identifier,\n },\n records: [identifier],\n };\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- //#region src/-private/builder-utils.ts
1
+ // src/-private/builder-utils.ts
2
2
  function copyForwardUrlOptions(urlOptions, options) {
3
3
  if ("host" in options) urlOptions.host = options.host;
4
4
  if ("namespace" in options) urlOptions.namespace = options.namespace;
@@ -11,6 +11,5 @@ function extractCacheOptions(options) {
11
11
  return cacheOptions;
12
12
  }
13
13
 
14
- //#endregion
15
14
  export { extractCacheOptions as n, copyForwardUrlOptions as t };
16
- //# sourceMappingURL=builder-utils-BkXwUT0x.js.map
15
+ //# sourceMappingURL=builder-utils-bjXbHa-m.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"builder-utils-BkXwUT0x.js","names":[],"sources":["../src/-private/builder-utils.ts"],"sourcesContent":["import type { CacheOptions, ConstrainedRequestOptions } from '@warp-drive-mirror/core/types/request';\n\nimport type { UrlOptions } from '../index.ts';\n\nexport function copyForwardUrlOptions(urlOptions: UrlOptions, options: ConstrainedRequestOptions): void {\n if ('host' in options) {\n urlOptions.host = options.host;\n }\n if ('namespace' in options) {\n urlOptions.namespace = options.namespace;\n }\n if ('resourcePath' in options) {\n urlOptions.resourcePath = options.resourcePath;\n }\n}\n\nexport function extractCacheOptions(options: ConstrainedRequestOptions): CacheOptions {\n const cacheOptions: CacheOptions = {};\n if ('reload' in options) {\n cacheOptions.reload = options.reload;\n }\n if ('backgroundReload' in options) {\n cacheOptions.backgroundReload = options.backgroundReload;\n }\n return cacheOptions;\n}\n"],"mappings":";AAIA,SAAgB,sBAAsB,YAAwB,SAA0C;CACtG,IAAI,UAAU,SACZ,WAAW,OAAO,QAAQ;CAE5B,IAAI,eAAe,SACjB,WAAW,YAAY,QAAQ;CAEjC,IAAI,kBAAkB,SACpB,WAAW,eAAe,QAAQ;AAEtC;AAEA,SAAgB,oBAAoB,SAAkD;CACpF,MAAM,eAA6B,CAAC;CACpC,IAAI,YAAY,SACd,aAAa,SAAS,QAAQ;CAEhC,IAAI,sBAAsB,SACxB,aAAa,mBAAmB,QAAQ;CAE1C,OAAO;AACT"}
1
+ {"version":3,"file":"builder-utils-bjXbHa-m.js","names":[],"sources":["../src/-private/builder-utils.ts"],"sourcesContent":["import type { CacheOptions, ConstrainedRequestOptions } from '@warp-drive-mirror/core/types/request';\n\nimport type { UrlOptions } from '../index.ts';\n\nexport function copyForwardUrlOptions(urlOptions: UrlOptions, options: ConstrainedRequestOptions): void {\n if ('host' in options) {\n urlOptions.host = options.host;\n }\n if ('namespace' in options) {\n urlOptions.namespace = options.namespace;\n }\n if ('resourcePath' in options) {\n urlOptions.resourcePath = options.resourcePath;\n }\n}\n\nexport function extractCacheOptions(options: ConstrainedRequestOptions): CacheOptions {\n const cacheOptions: CacheOptions = {};\n if ('reload' in options) {\n cacheOptions.reload = options.reload;\n }\n if ('backgroundReload' in options) {\n cacheOptions.backgroundReload = options.backgroundReload;\n }\n return cacheOptions;\n}\n"],"mappings":";AAIA,SAAgB,sBAAsB,YAAwB,SAA0C;CACtG,IAAI,UAAU,SACZ,WAAW,OAAO,QAAQ;CAE5B,IAAI,eAAe,SACjB,WAAW,YAAY,QAAQ;CAEjC,IAAI,kBAAkB,SACpB,WAAW,eAAe,QAAQ;AAEtC;AAEA,SAAgB,oBAAoB,SAAkD;CACpF,MAAM,eAA6B,CAAC;CACpC,IAAI,YAAY,SACd,aAAa,SAAS,QAAQ;CAEhC,IAAI,sBAAsB,SACxB,aAAa,mBAAmB,QAAQ;CAE1C,OAAO;AACT"}
@@ -1,6 +1,5 @@
1
1
  import { Type } from "@warp-drive-mirror/core/types/symbols";
2
2
  import { ReactiveResource } from "@warp-drive-mirror/core/reactive";
3
- //#region src/derivations.d.ts
4
3
  interface ConcatDerivation {
5
4
  (record: ReactiveResource & {
6
5
  [key: string]: unknown;
@@ -13,6 +12,8 @@ interface ConcatDerivation {
13
12
  *
14
13
  * Generally you should not need to import and use this function directly.
15
14
  *
15
+ * @summary Derivation registered as `concat` that joins a record's listed `fields` into one string with an optional
16
+ * `separator`.
16
17
  * @example
17
18
  * {
18
19
  * name: 'fullName',
@@ -25,5 +26,5 @@ interface ConcatDerivation {
25
26
  * }
26
27
  */
27
28
  export declare const concat: ConcatDerivation;
28
- //#endregion
29
+ export {};
29
30
  //# sourceMappingURL=derivations.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"derivations.d.ts","names":[],"sources":["../src/derivations.ts"],"mappings":";;;UAGU;GAEN,QAAQ;;KACR,SAAS,gCACT;GAED;;;;;;;;;;;;;;;;;;;qBAoBU,QAAQ"}
1
+ {"version":3,"file":"derivations.d.ts","names":[],"sources":["../src/derivations.ts"],"mappings":";;UAQU;GAEN,QAAQ;;KACR,SAAS,gCACT;GAED;;;;;;;;;;;;;;;;;;;;;qBAsBU,QAAQ"}
@@ -1,12 +1,18 @@
1
1
  import { Type } from "@warp-drive-mirror/core/types/symbols";
2
2
 
3
- //#region src/derivations.ts
3
+ // src/derivations.ts
4
+ /**
5
+ * @module
6
+ * @summary The `concat` derivation, which joins a record's listed fields into one string with an optional separator.
7
+ */
4
8
  /**
5
9
  * A derivation for use by {@link ReactiveResource} that joins the given fields
6
10
  * with the optional separator (or '' if no separator is provided).
7
11
  *
8
12
  * Generally you should not need to import and use this function directly.
9
13
  *
14
+ * @summary Derivation registered as `concat` that joins a record's listed `fields` into one string with an optional
15
+ * `separator`.
10
16
  * @example
11
17
  * {
12
18
  * name: 'fullName',
@@ -25,6 +31,5 @@ const concat = (record, options, _prop) => {
25
31
  };
26
32
  concat[Type] = "concat";
27
33
 
28
- //#endregion
29
34
  export { concat };
30
35
  //# sourceMappingURL=derivations.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"derivations.js","names":["Type","concat","record","options","_prop","Error","opts","fields","map","field","join","separator"],"sources":["../src/derivations.ts"],"sourcesContent":["import type { ReactiveResource } from '@warp-drive-mirror/core/reactive';\nimport { Type } from '@warp-drive-mirror/core/types/symbols';\n\ninterface ConcatDerivation {\n (\n record: ReactiveResource & { [key: string]: unknown },\n options: Record<string, unknown> | null,\n _prop: string\n ): string;\n [Type]: 'concat';\n}\n\n/**\n * A derivation for use by {@link ReactiveResource} that joins the given fields\n * with the optional separator (or '' if no separator is provided).\n *\n * Generally you should not need to import and use this function directly.\n *\n * @example\n * {\n * name: 'fullName',\n * kind: 'derived',\n * type: 'concat',\n * options: {\n * fields: ['firstName', 'lastName'],\n * separator: ' ',\n * },\n * }\n */\nexport const concat: ConcatDerivation = (\n record: ReactiveResource & { [key: string]: unknown },\n options: Record<string, unknown> | null,\n _prop: string\n) => {\n if (!options) {\n throw new Error(`options is required`);\n }\n // SAFETY: we cast internally to a more specific type, for our own use\n // SAFETY: but provide the more general signature to the schema service\n const opts = options as { fields: string[]; separator?: string };\n return opts.fields.map((field) => record[field]).join(opts.separator ?? '');\n};\nconcat[Type] = 'concat';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AA6BA,MAAaC,UACXC,QACAC,SACAC,UACG;CACH,IAAI,CAACD,SACH,MAAM,IAAIE,MAAM,qBAAqB;CAIvC,MAAMC,OAAOH;CACb,OAAOG,KAAKC,OAAOC,KAAKC,UAAUP,OAAOO,MAAM,CAAC,CAACC,KAAKJ,KAAKK,aAAa,EAAE;AAC5E;AACAV,OAAOD,QAAQ"}
1
+ {"version":3,"file":"derivations.js","names":["Type","concat","record","options","_prop","Error","opts","fields","map","field","join","separator"],"sources":["../src/derivations.ts"],"sourcesContent":["/**\n * @module\n * @summary The `concat` derivation, which joins a record's listed fields into one string with an optional separator.\n */\n\nimport type { ReactiveResource } from '@warp-drive-mirror/core/reactive';\nimport { Type } from '@warp-drive-mirror/core/types/symbols';\n\ninterface ConcatDerivation {\n (\n record: ReactiveResource & { [key: string]: unknown },\n options: Record<string, unknown> | null,\n _prop: string\n ): string;\n [Type]: 'concat';\n}\n\n/**\n * A derivation for use by {@link ReactiveResource} that joins the given fields\n * with the optional separator (or '' if no separator is provided).\n *\n * Generally you should not need to import and use this function directly.\n *\n * @summary Derivation registered as `concat` that joins a record's listed `fields` into one string with an optional\n * `separator`.\n * @example\n * {\n * name: 'fullName',\n * kind: 'derived',\n * type: 'concat',\n * options: {\n * fields: ['firstName', 'lastName'],\n * separator: ' ',\n * },\n * }\n */\nexport const concat: ConcatDerivation = (\n record: ReactiveResource & { [key: string]: unknown },\n options: Record<string, unknown> | null,\n _prop: string\n) => {\n if (!options) {\n throw new Error(`options is required`);\n }\n // SAFETY: we cast internally to a more specific type, for our own use\n // SAFETY: but provide the more general signature to the schema service\n const opts = options as { fields: string[]; separator?: string };\n return opts.fields.map((field) => record[field]).join(opts.separator ?? '');\n};\nconcat[Type] = 'concat';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAoCA,MAAaC,UACXC,QACAC,SACAC,UACG;CACH,IAAI,CAACD,SACH,MAAM,IAAIE,MAAM,qBAAqB;CAIvC,MAAMC,OAAOH;CACb,OAAOG,KAAKC,OAAOC,KAAKC,UAAUP,OAAOO,MAAM,CAAC,CAACC,KAAKJ,KAAKK,aAAa,EAAE;AAC5E;AACAV,OAAOD,QAAQ"}
@@ -1,13 +1,21 @@
1
1
  import { RequestContext, StructuredDataDocument } from "@warp-drive-mirror/core/types/request";
2
2
  import { Future, Handler, NextFn } from "@warp-drive-mirror/core/request";
3
- //#region src/-private/handlers/auto-compress.d.ts
4
3
  /**
5
4
  * Whether the browser supports `ReadableStream` as a request body
6
5
  * in a `POST` request.
7
6
  *
7
+ * @summary Whether the current browser can send a `ReadableStream` as a `fetch` request body, detected once at
8
+ * module load.
8
9
  * @group Constants
9
10
  */
10
11
  export declare const SupportsRequestStreams: boolean;
12
+ /**
13
+ * The minimum body size, per body type, at which {@link AutoCompress} compresses a request
14
+ * body. Passed as {@link CompressionOptions.constraints}.
15
+ *
16
+ * @summary Minimum request body sizes, per body type, at which `AutoCompress` compresses a body.
17
+ * @public
18
+ */
11
19
  interface Constraints {
12
20
  /**
13
21
  * The minimum size at which to compress blobs
@@ -41,8 +49,10 @@ interface Constraints {
41
49
  String?: number;
42
50
  }
43
51
  /**
44
- * Options for configuring the AutoCompress handler.
52
+ * Options for configuring the {@link AutoCompress} handler.
45
53
  *
54
+ * @summary Options for `new AutoCompress()`: the compression format, size constraints and whether to stream the body.
55
+ * @public
46
56
  */
47
57
  interface CompressionOptions {
48
58
  /**
@@ -145,6 +155,8 @@ interface CompressionOptions {
145
155
  * }
146
156
  * ```
147
157
  *
158
+ * @summary Request handler that compresses large `POST`, `PUT`, `PATCH`, and `DELETE` bodies with `CompressionStream`,
159
+ * optionally streaming them.
148
160
  * @group Handlers
149
161
  * @public
150
162
  * @since 5.5.0
@@ -163,8 +175,6 @@ export declare class AutoCompress implements Handler {
163
175
  constructor(options?: CompressionOptions);
164
176
  request<T>({ request }: RequestContext, next: NextFn<T>): Promise<T> | Future<T>;
165
177
  }
166
- //#endregion
167
- //#region src/-private/handlers/gated.d.ts
168
178
  /**
169
179
  * If CheckFn returns true, the wrapped handler will be used.
170
180
  * If CheckFn returns false, the wrapped handler will be skipped.
@@ -172,6 +182,8 @@ export declare class AutoCompress implements Handler {
172
182
  type CheckFn = (context: RequestContext) => boolean;
173
183
  /**
174
184
  *
185
+ * @summary Request handler that wraps another handler and runs it only when a check function returns true for the
186
+ * request.
175
187
  * @group Handlers
176
188
  * @public
177
189
  */
@@ -187,8 +199,6 @@ export declare class Gate implements Handler {
187
199
  constructor(handler: Handler, checkFn: CheckFn);
188
200
  request<T = unknown>(context: RequestContext, next: NextFn<T>): Promise<T | StructuredDataDocument<T>> | Future<T>;
189
201
  }
190
- //#endregion
191
- //#region src/-private/handlers/meta-doc.d.ts
192
202
  /**
193
203
  * MetaDocHandler processes requests that are marked as meta requests.
194
204
  *
@@ -232,22 +242,24 @@ export declare class Gate implements Handler {
232
242
  * Errors are not processed by this handler, so if the request fails and the error response
233
243
  * is not in {json:api} format additional processing may be needed.
234
244
  *
245
+ * @summary Request handler that wraps the whole response body in `meta` for requests with `options.isMetaRequest` set.
235
246
  * @group Handlers
236
247
  */
237
248
  export declare const MetaDocHandler: Handler;
238
- //#endregion
239
- //#region src/-private/handlers/utils.d.ts
240
249
  /**
241
250
  * A unique identifier for the current browser tab
242
251
  * useful for observability/tracing and deduping
243
252
  * across multiple tabs.
244
253
  *
254
+ * @summary Random UUID identifying the current browser tab, kept in `sessionStorage` across reloads, for request
255
+ * tracing.
245
256
  * @group Constants
246
257
  */
247
258
  export declare const TAB_ID: string;
248
259
  /**
249
260
  * The epoch seconds at which the tab id was generated
250
261
  *
262
+ * @summary Epoch seconds recorded when this module loaded, paired with `TAB_ID` in trace headers.
251
263
  * @group Constants
252
264
  */
253
265
  export declare const TAB_ASSIGNED: number;
@@ -260,6 +272,8 @@ export declare const TAB_ASSIGNED: number;
260
272
  *
261
273
  * Follows the template: `Root=1-${now}-${uuidv4};TabId=1-${epochSeconds}-${tab-uuid}`
262
274
  *
275
+ * @summary Sets an `X-Amzn-Trace-Id` header carrying a per-request id and the tab id, so requests can be traced to
276
+ * their browser tab.
263
277
  * @group Utility Functions
264
278
  */
265
279
  export declare function addTraceHeader(headers: Headers): Headers;
@@ -267,6 +281,7 @@ export declare function addTraceHeader(headers: Headers): Headers;
267
281
  * Source: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cloudfront-limits.html
268
282
  * As of 2024-12-05 the maximum URL length is 8192 bytes.
269
283
  *
284
+ * @summary The 8192-byte URL length limit, taken from AWS CloudFront, that `assertInvalidUrlLength` checks against.
270
285
  * @group Constants
271
286
  */
272
287
  export declare const MAX_URL_LENGTH = 8192;
@@ -275,8 +290,10 @@ export declare const MAX_URL_LENGTH = 8192;
275
290
  *
276
291
  * See also {@link MAX_URL_LENGTH}
277
292
  *
293
+ * @summary Dev-mode assertion that throws when a URL is longer than `MAX_URL_LENGTH`, suggesting a `POST` or `QUERY`
294
+ * request instead.
278
295
  * @group Utility Functions
279
296
  */
280
297
  export declare function assertInvalidUrlLength(url: string | undefined): void;
281
- //#endregion
298
+ export type { CompressionOptions, Constraints };
282
299
  //# sourceMappingURL=handlers.d.ts.map
@@ -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;;;;;;;;UAuBI;;;;;;EAMf;;;;;;EAMA;;;;;;EAMA;;;;;;EAMA;;;;;;EAMA;;;;;;;;UASe;;;;;;;;EAQf,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;;;;;;KCrN3E,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
@@ -1,6 +1,6 @@
1
1
  import { getGlobalConfig, macroCondition } from "@embroider/macros";
2
2
 
3
- //#region src/-private/handlers/auto-compress.ts
3
+ // src/-private/handlers/auto-compress.ts
4
4
  function isCompressibleMethod(method) {
5
5
  return method === "POST" || method === "PUT" || method === "PATCH" || method === "DELETE";
6
6
  }
@@ -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 = (() => {
@@ -23,8 +25,17 @@ const SupportsRequestStreams = (() => {
23
25
  return duplexAccessed && !hasContentType;
24
26
  })();
25
27
  /**
26
- * Options for configuring the AutoCompress handler.
28
+ * The minimum body size, per body type, at which {@link AutoCompress} compresses a request
29
+ * body. Passed as {@link CompressionOptions.constraints}.
27
30
  *
31
+ * @summary Minimum request body sizes, per body type, at which `AutoCompress` compresses a body.
32
+ * @public
33
+ */
34
+ /**
35
+ * Options for configuring the {@link AutoCompress} handler.
36
+ *
37
+ * @summary Options for `new AutoCompress()`: the compression format, size constraints and whether to stream the body.
38
+ * @public
28
39
  */
29
40
  const DEFAULT_CONSTRAINTS = {
30
41
  Blob: 1e3,
@@ -58,6 +69,8 @@ const TypedArray = Object.getPrototypeOf(Uint8Array);
58
69
  * }
59
70
  * ```
60
71
  *
72
+ * @summary Request handler that compresses large `POST`, `PUT`, `PATCH`, and `DELETE` bodies with `CompressionStream`,
73
+ * optionally streaming them.
61
74
  * @group Handlers
62
75
  * @public
63
76
  * @since 5.5.0
@@ -119,14 +132,15 @@ function encodingForFormat(format) {
119
132
  }
120
133
  }
121
134
 
122
- //#endregion
123
- //#region src/-private/handlers/gated.ts
135
+ // src/-private/handlers/gated.ts
124
136
  /**
125
137
  * If CheckFn returns true, the wrapped handler will be used.
126
138
  * If CheckFn returns false, the wrapped handler will be skipped.
127
139
  */
128
140
  /**
129
141
  *
142
+ * @summary Request handler that wraps another handler and runs it only when a check function returns true for the
143
+ * request.
130
144
  * @group Handlers
131
145
  * @public
132
146
  */
@@ -147,8 +161,7 @@ var Gate = class {
147
161
  }
148
162
  };
149
163
 
150
- //#endregion
151
- //#region src/-private/handlers/meta-doc.ts
164
+ // src/-private/handlers/meta-doc.ts
152
165
  /**
153
166
  * MetaDocHandler processes requests that are marked as meta requests.
154
167
  *
@@ -192,6 +205,7 @@ var Gate = class {
192
205
  * Errors are not processed by this handler, so if the request fails and the error response
193
206
  * is not in {json:api} format additional processing may be needed.
194
207
  *
208
+ * @summary Request handler that wraps the whole response body in `meta` for requests with `options.isMetaRequest` set.
195
209
  * @group Handlers
196
210
  */
197
211
  const MetaDocHandler = { request(context, next) {
@@ -204,8 +218,7 @@ function processResponse(response) {
204
218
  return { meta: response.content };
205
219
  }
206
220
 
207
- //#endregion
208
- //#region src/-private/handlers/utils.ts
221
+ // src/-private/handlers/utils.ts
209
222
  if (typeof FastBoot === "undefined") globalThis.addEventListener("beforeunload", function() {
210
223
  sessionStorage.setItem("tab-closed", "true");
211
224
  });
@@ -224,12 +237,15 @@ function getTabId() {
224
237
  * useful for observability/tracing and deduping
225
238
  * across multiple tabs.
226
239
  *
240
+ * @summary Random UUID identifying the current browser tab, kept in `sessionStorage` across reloads, for request
241
+ * tracing.
227
242
  * @group Constants
228
243
  */
229
244
  const TAB_ID = getTabId();
230
245
  /**
231
246
  * The epoch seconds at which the tab id was generated
232
247
  *
248
+ * @summary Epoch seconds recorded when this module loaded, paired with `TAB_ID` in trace headers.
233
249
  * @group Constants
234
250
  */
235
251
  const TAB_ASSIGNED = Math.floor(Date.now() / 1e3);
@@ -242,6 +258,8 @@ const TAB_ASSIGNED = Math.floor(Date.now() / 1e3);
242
258
  *
243
259
  * Follows the template: `Root=1-${now}-${uuidv4};TabId=1-${epochSeconds}-${tab-uuid}`
244
260
  *
261
+ * @summary Sets an `X-Amzn-Trace-Id` header carrying a per-request id and the tab id, so requests can be traced to
262
+ * their browser tab.
245
263
  * @group Utility Functions
246
264
  */
247
265
  function addTraceHeader(headers) {
@@ -253,6 +271,7 @@ function addTraceHeader(headers) {
253
271
  * Source: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cloudfront-limits.html
254
272
  * As of 2024-12-05 the maximum URL length is 8192 bytes.
255
273
  *
274
+ * @summary The 8192-byte URL length limit, taken from AWS CloudFront, that `assertInvalidUrlLength` checks against.
256
275
  * @group Constants
257
276
  */
258
277
  const MAX_URL_LENGTH = 8192;
@@ -261,6 +280,8 @@ const MAX_URL_LENGTH = 8192;
261
280
  *
262
281
  * See also {@link MAX_URL_LENGTH}
263
282
  *
283
+ * @summary Dev-mode assertion that throws when a URL is longer than `MAX_URL_LENGTH`, suggesting a `POST` or `QUERY`
284
+ * request instead.
264
285
  * @group Utility Functions
265
286
  */
266
287
  function assertInvalidUrlLength(url) {
@@ -269,6 +290,5 @@ function assertInvalidUrlLength(url) {
269
290
  })(!url || url.length <= 8192);
270
291
  }
271
292
 
272
- //#endregion
273
293
  export { AutoCompress, Gate, MAX_URL_LENGTH, MetaDocHandler, SupportsRequestStreams, TAB_ASSIGNED, TAB_ID, addTraceHeader, assertInvalidUrlLength };
274
294
  //# sourceMappingURL=handlers.js.map
@@ -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\n/**\n * The minimum body size, per body type, at which {@link AutoCompress} compresses a request\n * body. Passed as {@link CompressionOptions.constraints}.\n *\n * @summary Minimum request body sizes, per body type, at which `AutoCompress` compresses a body.\n * @public\n */\nexport interface 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 {@link AutoCompress} handler.\n *\n * @summary Options for `new AutoCompress()`: the compression format, size constraints and whether to stream the body.\n * @public\n */\nexport interface 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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"}