@cratis/arc 21.3.1 → 21.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/queries/QueryFor.js +50 -11
- package/dist/cjs/queries/QueryFor.js.map +1 -1
- package/dist/cjs/queries/QueryHttpRequest.js +0 -0
- package/dist/cjs/queries/QueryHttpRequest.js.map +1 -1
- package/dist/cjs/queries/isAbortError.js +18 -0
- package/dist/cjs/queries/isAbortError.js.map +1 -0
- package/dist/esm/queries/QueryFor.d.ts.map +1 -1
- package/dist/esm/queries/QueryFor.js +50 -11
- package/dist/esm/queries/QueryFor.js.map +1 -1
- package/dist/esm/queries/QueryHttpRequest.d.ts.map +1 -1
- package/dist/esm/queries/QueryHttpRequest.js +0 -0
- package/dist/esm/queries/QueryHttpRequest.js.map +1 -1
- package/dist/esm/queries/for_QueryFor/when_performing/with_a_nullish_transport_rejection.d.ts +2 -0
- package/dist/esm/queries/for_QueryFor/when_performing/with_a_nullish_transport_rejection.d.ts.map +1 -0
- package/dist/esm/queries/for_QueryFor/when_performing/with_a_nullish_transport_rejection.js +22 -0
- package/dist/esm/queries/for_QueryFor/when_performing/with_a_nullish_transport_rejection.js.map +1 -0
- package/dist/esm/queries/for_QueryFor/when_performing/with_an_aborted_request.d.ts +2 -0
- package/dist/esm/queries/for_QueryFor/when_performing/with_an_aborted_request.d.ts.map +1 -0
- package/dist/esm/queries/for_QueryFor/when_performing/with_an_aborted_request.js +21 -0
- package/dist/esm/queries/for_QueryFor/when_performing/with_an_aborted_request.js.map +1 -0
- package/dist/esm/queries/for_QueryFor/when_performing/with_fetch_error.js +7 -18
- package/dist/esm/queries/for_QueryFor/when_performing/with_fetch_error.js.map +1 -1
- package/dist/esm/queries/isAbortError.d.ts +2 -0
- package/dist/esm/queries/isAbortError.d.ts.map +1 -0
- package/dist/esm/queries/isAbortError.js +16 -0
- package/dist/esm/queries/isAbortError.js.map +1 -0
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/queries/QueryFor.ts +51 -11
- package/queries/QueryHttpRequest.ts +0 -0
- package/queries/for_QueryFor/when_performing/with_a_nullish_transport_rejection.ts +40 -0
- package/queries/for_QueryFor/when_performing/with_an_aborted_request.ts +34 -0
- package/queries/for_QueryFor/when_performing/with_fetch_error.ts +13 -20
- package/queries/isAbortError.ts +15 -0
|
@@ -7,6 +7,7 @@ var Globals = require('../Globals.js');
|
|
|
7
7
|
var Sorting = require('./Sorting.js');
|
|
8
8
|
var ParametersHelper = require('../reflection/ParametersHelper.js');
|
|
9
9
|
var QueryHttpRequest = require('./QueryHttpRequest.js');
|
|
10
|
+
var isAbortError = require('./isAbortError.js');
|
|
10
11
|
|
|
11
12
|
// Copyright (c) Cratis. All rights reserved.
|
|
12
13
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
@@ -90,17 +91,55 @@ var QueryHttpRequest = require('./QueryHttpRequest.js');
|
|
|
90
91
|
if (this._microservice?.length > 0) {
|
|
91
92
|
headers[Globals.Globals.microserviceHttpHeader] = this._microservice;
|
|
92
93
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
94
|
+
let response;
|
|
95
|
+
try {
|
|
96
|
+
response = await QueryHttpRequest.executeQueryHttpRequest(this._httpMethod, {
|
|
97
|
+
route: this.route,
|
|
98
|
+
apiBasePath: this._apiBasePath,
|
|
99
|
+
origin: this._origin,
|
|
100
|
+
args: args ?? {},
|
|
101
|
+
parameterValues,
|
|
102
|
+
paging: this.paging,
|
|
103
|
+
sorting: this.sorting,
|
|
104
|
+
headers,
|
|
105
|
+
signal: this.abortController.signal
|
|
106
|
+
});
|
|
107
|
+
} catch (error) {
|
|
108
|
+
// An abort is not a failure - it is this query superseding its own in-flight request above.
|
|
109
|
+
// Rethrowing lets the caller discard the superseded request so it cannot settle over the
|
|
110
|
+
// newer one that now owns the result.
|
|
111
|
+
if (isAbortError.isAbortError(error)) {
|
|
112
|
+
throw error;
|
|
113
|
+
}
|
|
114
|
+
// A dead network, a CORS rejection or a DNS failure never reaches the server, so it is
|
|
115
|
+
// neither an authorization nor a validation outcome - it is reported as an exception, with
|
|
116
|
+
// the default value as data, exactly as every other unsuccessful result from here does.
|
|
117
|
+
// Destructuring a nullish rejection value throws, which would make the `String(error)`
|
|
118
|
+
// fallback written for exactly that case unreachable - so it is coerced to an object first.
|
|
119
|
+
const { message } = error ?? {};
|
|
120
|
+
const failure = {
|
|
121
|
+
...QueryResult.QueryResult.noSuccess,
|
|
122
|
+
data: this.defaultValue,
|
|
123
|
+
isSuccess: false,
|
|
124
|
+
isAuthorized: true,
|
|
125
|
+
isValid: true,
|
|
126
|
+
hasExceptions: true,
|
|
127
|
+
exceptionMessages: [
|
|
128
|
+
message ?? String(error)
|
|
129
|
+
],
|
|
130
|
+
// Left empty on purpose. Every result the server returns has its stack trace blanked
|
|
131
|
+
// unless exception detail is explicitly exposed, and consumers are told to forward
|
|
132
|
+
// this field to a logger - so filling it in here would make a failure that never
|
|
133
|
+
// reached the server the one case that escapes that policy. The message is what
|
|
134
|
+
// diagnoses a transport failure; the browser's own frames add nothing.
|
|
135
|
+
exceptionStackTrace: ''
|
|
136
|
+
};
|
|
137
|
+
// `hasData` is a prototype getter, and a spread copies own properties only - so the literal
|
|
138
|
+
// above would hand every consumer of this public `IQueryResult` member `undefined` instead
|
|
139
|
+
// of a boolean. Restoring the prototype makes it a real {@link QueryResult} again while
|
|
140
|
+
// leaving every field value exactly as it is.
|
|
141
|
+
return Object.setPrototypeOf(failure, QueryResult.QueryResult.prototype);
|
|
142
|
+
}
|
|
104
143
|
try {
|
|
105
144
|
const result = await response.json();
|
|
106
145
|
return new QueryResult.QueryResult(result, this.modelType, this.enumerable);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"QueryFor.js","sources":["../../../queries/QueryFor.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { IQueryFor } from './IQueryFor';\nimport { QueryResult } from \"./QueryResult\";\nimport { QueryValidator } from './QueryValidator';\nimport { ValidateRequestArguments } from './ValidateRequestArguments';\nimport { Constructor } from '@cratis/fundamentals';\nimport { Paging } from './Paging';\nimport { Globals } from '../Globals';\nimport { Sorting } from './Sorting';\nimport { GetHttpHeaders } from '../GetHttpHeaders';\nimport { ParameterDescriptor } from '../reflection/ParameterDescriptor';\nimport { ParametersHelper } from '../reflection/ParametersHelper';\nimport { QueryHttpMethod } from './QueryHttpMethod';\nimport { executeQueryHttpRequest } from './QueryHttpRequest';\n\n/**\n * Represents an implementation of {@link IQueryFor}.\n * @template TDataType Type of data returned by the query.\n */\nexport abstract class QueryFor<TDataType, TParameters = object> implements IQueryFor<TDataType, TParameters> {\n private _microservice: string;\n private _apiBasePath: string;\n private _origin: string;\n private _httpHeadersCallback: GetHttpHeaders;\n private _httpMethod?: QueryHttpMethod;\n abstract readonly route: string;\n /** Backend fully-qualified query name used as cache key. Overridden in generated proxies. */\n readonly queryName?: string;\n /* eslint-disable @typescript-eslint/no-explicit-any */\n readonly validation?: QueryValidator<any>;\n /* eslint-enable @typescript-eslint/no-explicit-any */\n readonly roles: string[] = [];\n abstract readonly parameterDescriptors: ParameterDescriptor[];\n abstract get requiredRequestParameters(): string[];\n abstract defaultValue: TDataType;\n abortController?: AbortController;\n sorting: Sorting;\n paging: Paging;\n parameters: TParameters | undefined;\n\n /**\n * Initializes a new instance of the {@link ObservableQueryFor<,>}} class.\n * @param modelType Type of model, if an enumerable, this is the instance type.\n * @param enumerable Whether or not it is an enumerable.\n */\n constructor(readonly modelType: Constructor, readonly enumerable: boolean) {\n this.sorting = Sorting.none;\n this.paging = Paging.noPaging;\n this._microservice = Globals.microservice ?? '';\n this._apiBasePath = Globals.apiBasePath ?? '';\n this._origin = Globals.origin ?? '';\n this._httpHeadersCallback = () => ({});\n }\n\n /** @inheritdoc */\n setMicroservice(microservice: string) {\n this._microservice = microservice;\n }\n\n /** @inheritdoc */\n setApiBasePath(apiBasePath: string): void {\n this._apiBasePath = apiBasePath;\n }\n\n /** @inheritdoc */\n setOrigin(origin: string): void {\n this._origin = origin;\n }\n\n /** @inheritdoc */\n setHttpHeadersCallback(callback: GetHttpHeaders): void {\n this._httpHeadersCallback = callback;\n }\n\n /** @inheritdoc */\n setHttpMethod(method: QueryHttpMethod): void {\n this._httpMethod = method;\n }\n\n /** @inheritdoc */\n async perform(args?: TParameters): Promise<QueryResult<TDataType>> {\n const noSuccess = { ...QueryResult.noSuccess, ...{ data: this.defaultValue } } as QueryResult<TDataType>;\n\n args = args || this.parameters;\n\n const clientValidationErrors = this.validation?.validate(args as object || {}) || [];\n if (clientValidationErrors.length > 0) {\n return QueryResult.validationFailed(clientValidationErrors, this);\n }\n\n if (!ValidateRequestArguments(this.constructor.name, this.requiredRequestParameters, args as object)) {\n return new Promise<QueryResult<TDataType>>((resolve) => {\n resolve(noSuccess);\n });\n }\n\n if (this.abortController) {\n this.abortController.abort();\n }\n\n this.abortController = new AbortController();\n\n // Collect parameter values from parameterDescriptors that are set\n const parameterValues = ParametersHelper.collectParameterValues(this);\n\n const headers = {\n ... this._httpHeadersCallback?.(), ...\n {\n 'Accept': 'application/json',\n 'Content-Type': 'application/json'\n }\n };\n\n if (this._microservice?.length > 0) {\n headers[Globals.microserviceHttpHeader] = this._microservice;\n }\n\n const response = await executeQueryHttpRequest(this._httpMethod, {\n route: this.route,\n apiBasePath: this._apiBasePath,\n origin: this._origin,\n args: (args as object) ?? {},\n parameterValues,\n paging: this.paging,\n sorting: this.sorting,\n headers,\n signal: this.abortController.signal\n });\n\n try {\n const result = await response.json();\n return new QueryResult(result, this.modelType, this.enumerable);\n } catch {\n return noSuccess;\n }\n }\n}\n"],"names":["QueryFor","_microservice","_apiBasePath","_origin","_httpHeadersCallback","_httpMethod","queryName","validation","roles","abortController","sorting","paging","parameters","enumerable","modelType","Sorting","none","Paging","noPaging","Globals","microservice","apiBasePath","origin","setMicroservice","setApiBasePath","setOrigin","setHttpHeadersCallback","callback","setHttpMethod","method","perform","args","noSuccess","QueryResult","data","defaultValue","clientValidationErrors","validate","length","validationFailed","ValidateRequestArguments","name","requiredRequestParameters","Promise","resolve","abort","AbortController","parameterValues","ParametersHelper","collectParameterValues","headers","microserviceHttpHeader","response","executeQueryHttpRequest","route","signal","result","json"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"QueryFor.js","sources":["../../../queries/QueryFor.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { IQueryFor } from './IQueryFor';\nimport { QueryResult } from \"./QueryResult\";\nimport { QueryValidator } from './QueryValidator';\nimport { ValidateRequestArguments } from './ValidateRequestArguments';\nimport { Constructor } from '@cratis/fundamentals';\nimport { Paging } from './Paging';\nimport { Globals } from '../Globals';\nimport { Sorting } from './Sorting';\nimport { GetHttpHeaders } from '../GetHttpHeaders';\nimport { ParameterDescriptor } from '../reflection/ParameterDescriptor';\nimport { ParametersHelper } from '../reflection/ParametersHelper';\nimport { QueryHttpMethod } from './QueryHttpMethod';\nimport { executeQueryHttpRequest } from './QueryHttpRequest';\nimport { isAbortError } from './isAbortError';\n\n/**\n * Represents an implementation of {@link IQueryFor}.\n * @template TDataType Type of data returned by the query.\n */\nexport abstract class QueryFor<TDataType, TParameters = object> implements IQueryFor<TDataType, TParameters> {\n private _microservice: string;\n private _apiBasePath: string;\n private _origin: string;\n private _httpHeadersCallback: GetHttpHeaders;\n private _httpMethod?: QueryHttpMethod;\n abstract readonly route: string;\n /** Backend fully-qualified query name used as cache key. Overridden in generated proxies. */\n readonly queryName?: string;\n /* eslint-disable @typescript-eslint/no-explicit-any */\n readonly validation?: QueryValidator<any>;\n /* eslint-enable @typescript-eslint/no-explicit-any */\n readonly roles: string[] = [];\n abstract readonly parameterDescriptors: ParameterDescriptor[];\n abstract get requiredRequestParameters(): string[];\n abstract defaultValue: TDataType;\n abortController?: AbortController;\n sorting: Sorting;\n paging: Paging;\n parameters: TParameters | undefined;\n\n /**\n * Initializes a new instance of the {@link ObservableQueryFor<,>}} class.\n * @param modelType Type of model, if an enumerable, this is the instance type.\n * @param enumerable Whether or not it is an enumerable.\n */\n constructor(readonly modelType: Constructor, readonly enumerable: boolean) {\n this.sorting = Sorting.none;\n this.paging = Paging.noPaging;\n this._microservice = Globals.microservice ?? '';\n this._apiBasePath = Globals.apiBasePath ?? '';\n this._origin = Globals.origin ?? '';\n this._httpHeadersCallback = () => ({});\n }\n\n /** @inheritdoc */\n setMicroservice(microservice: string) {\n this._microservice = microservice;\n }\n\n /** @inheritdoc */\n setApiBasePath(apiBasePath: string): void {\n this._apiBasePath = apiBasePath;\n }\n\n /** @inheritdoc */\n setOrigin(origin: string): void {\n this._origin = origin;\n }\n\n /** @inheritdoc */\n setHttpHeadersCallback(callback: GetHttpHeaders): void {\n this._httpHeadersCallback = callback;\n }\n\n /** @inheritdoc */\n setHttpMethod(method: QueryHttpMethod): void {\n this._httpMethod = method;\n }\n\n /** @inheritdoc */\n async perform(args?: TParameters): Promise<QueryResult<TDataType>> {\n const noSuccess = { ...QueryResult.noSuccess, ...{ data: this.defaultValue } } as QueryResult<TDataType>;\n\n args = args || this.parameters;\n\n const clientValidationErrors = this.validation?.validate(args as object || {}) || [];\n if (clientValidationErrors.length > 0) {\n return QueryResult.validationFailed(clientValidationErrors, this);\n }\n\n if (!ValidateRequestArguments(this.constructor.name, this.requiredRequestParameters, args as object)) {\n return new Promise<QueryResult<TDataType>>((resolve) => {\n resolve(noSuccess);\n });\n }\n\n if (this.abortController) {\n this.abortController.abort();\n }\n\n this.abortController = new AbortController();\n\n // Collect parameter values from parameterDescriptors that are set\n const parameterValues = ParametersHelper.collectParameterValues(this);\n\n const headers = {\n ... this._httpHeadersCallback?.(), ...\n {\n 'Accept': 'application/json',\n 'Content-Type': 'application/json'\n }\n };\n\n if (this._microservice?.length > 0) {\n headers[Globals.microserviceHttpHeader] = this._microservice;\n }\n\n let response: Response;\n\n try {\n response = await executeQueryHttpRequest(this._httpMethod, {\n route: this.route,\n apiBasePath: this._apiBasePath,\n origin: this._origin,\n args: (args as object) ?? {},\n parameterValues,\n paging: this.paging,\n sorting: this.sorting,\n headers,\n signal: this.abortController.signal\n });\n } catch (error) {\n // An abort is not a failure - it is this query superseding its own in-flight request above.\n // Rethrowing lets the caller discard the superseded request so it cannot settle over the\n // newer one that now owns the result.\n if (isAbortError(error)) {\n throw error;\n }\n\n // A dead network, a CORS rejection or a DNS failure never reaches the server, so it is\n // neither an authorization nor a validation outcome - it is reported as an exception, with\n // the default value as data, exactly as every other unsuccessful result from here does.\n // Destructuring a nullish rejection value throws, which would make the `String(error)`\n // fallback written for exactly that case unreachable - so it is coerced to an object first.\n const { message } = (error ?? {}) as { message?: string };\n const failure = {\n ...QueryResult.noSuccess,\n data: this.defaultValue,\n isSuccess: false,\n isAuthorized: true,\n isValid: true,\n hasExceptions: true,\n exceptionMessages: [message ?? String(error)],\n // Left empty on purpose. Every result the server returns has its stack trace blanked\n // unless exception detail is explicitly exposed, and consumers are told to forward\n // this field to a logger - so filling it in here would make a failure that never\n // reached the server the one case that escapes that policy. The message is what\n // diagnoses a transport failure; the browser's own frames add nothing.\n exceptionStackTrace: ''\n };\n\n // `hasData` is a prototype getter, and a spread copies own properties only - so the literal\n // above would hand every consumer of this public `IQueryResult` member `undefined` instead\n // of a boolean. Restoring the prototype makes it a real {@link QueryResult} again while\n // leaving every field value exactly as it is.\n return Object.setPrototypeOf(failure, QueryResult.prototype) as QueryResult<TDataType>;\n }\n\n try {\n const result = await response.json();\n return new QueryResult(result, this.modelType, this.enumerable);\n } catch {\n return noSuccess;\n }\n }\n}\n"],"names":["QueryFor","_microservice","_apiBasePath","_origin","_httpHeadersCallback","_httpMethod","queryName","validation","roles","abortController","sorting","paging","parameters","enumerable","modelType","Sorting","none","Paging","noPaging","Globals","microservice","apiBasePath","origin","setMicroservice","setApiBasePath","setOrigin","setHttpHeadersCallback","callback","setHttpMethod","method","perform","args","noSuccess","QueryResult","data","defaultValue","clientValidationErrors","validate","length","validationFailed","ValidateRequestArguments","name","requiredRequestParameters","Promise","resolve","abort","AbortController","parameterValues","ParametersHelper","collectParameterValues","headers","microserviceHttpHeader","response","executeQueryHttpRequest","route","signal","error","isAbortError","message","failure","isSuccess","isAuthorized","isValid","hasExceptions","exceptionMessages","String","exceptionStackTrace","Object","setPrototypeOf","prototype","result","json"],"mappings":"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"}
|
|
Binary file
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"QueryHttpRequest.js","sources":["../../../queries/QueryHttpRequest.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { Paging } from './Paging';\nimport { Sorting } from './Sorting';\nimport { SortDirection } from './SortDirection';\nimport { QueryHttpMethod } from './QueryHttpMethod';\nimport { joinPaths } from '../joinPaths';\nimport { UrlHelpers } from '../UrlHelpers';\nimport { Globals } from '../Globals';\n\n/**\n * Options for building an HTTP request for a query.\n */\nexport interface BuildQueryHttpRequestOptions {\n /** The route template for the query, possibly containing route parameters. */\n route: string;\n /** The base path for the API. */\n apiBasePath: string;\n /** The origin for the API. */\n origin: string;\n /** The arguments used for route-parameter substitution and as query arguments. */\n args: object;\n /** Descriptor-collected parameter values that also form query arguments. */\n parameterValues: object;\n /** The paging for the query. */\n paging: Paging;\n /** The sorting for the query. */\n sorting: Sorting;\n /** The HTTP headers to include. */\n headers: HeadersInit;\n /** Optional abort signal for the request. */\n signal?: AbortSignal;\n}\n\ninterface QueryRequestPayload {\n arguments: object;\n paging?: { page: number; pageSize: number };\n sorting?: { field: string; direction: string };\n}\n\nfunction directionToString(sorting: Sorting): string {\n return sorting.direction === SortDirection.descending ? 'desc' : 'asc';\n}\n\n/**\n * Builds the URL and {@link RequestInit} for performing a query with the given HTTP method.\n *\n * For {@link QueryHttpMethod.Get}, arguments, paging and sorting are placed in the URL query string.\n * For {@link QueryHttpMethod.Query}, route parameters remain in the path while the arguments, paging\n * and sorting are carried in a JSON body envelope.\n * @param method The {@link QueryHttpMethod} to use.\n * @param options The {@link BuildQueryHttpRequestOptions} describing the request.\n * @returns The URL and {@link RequestInit} to pass to {@link fetch}.\n */\nexport function buildQueryHttpRequest(method: QueryHttpMethod, options: BuildQueryHttpRequestOptions): { url: URL; init: RequestInit } {\n const { route, apiBasePath, origin, args, parameterValues, paging, sorting, headers, signal } = options;\n\n const { route: replacedRoute, unusedParameters } = UrlHelpers.replaceRouteParameters(route, args);\n const argumentValues = { ...unusedParameters, ...parameterValues };\n let actualRoute = joinPaths(apiBasePath, replacedRoute);\n\n if (method === QueryHttpMethod.Query) {\n const url = UrlHelpers.createUrlFrom(origin, apiBasePath, actualRoute);\n const payload: QueryRequestPayload = { arguments: argumentValues };\n if (paging.hasPaging) {\n payload.paging = { page: paging.page, pageSize: paging.pageSize };\n }\n if (sorting.hasSorting) {\n payload.sorting = { field: sorting.field, direction: directionToString(sorting) };\n }\n\n const requestHeaders = new Headers(headers);\n if (!requestHeaders.has('Content-Type')) {\n requestHeaders.set('Content-Type', 'application/json');\n }\n\n const init: RequestInit = {\n method: QueryHttpMethod.Query,\n headers: requestHeaders,\n body: JSON.stringify(payload),\n signal\n };\n return { url, init };\n }\n\n const additionalParams: Record<string, string | number> = {};\n if (paging.hasPaging) {\n additionalParams.page = paging.page;\n additionalParams.pageSize = paging.pageSize;\n }\n if (sorting.hasSorting) {\n additionalParams.sortBy = sorting.field;\n additionalParams.sortDirection = directionToString(sorting);\n }\n\n const queryParams = UrlHelpers.buildQueryParams(argumentValues, additionalParams);\n const queryString = queryParams.toString();\n if (queryString) {\n actualRoute += (actualRoute.includes('?') ? '&' : '?') + queryString;\n }\n\n const url = UrlHelpers.createUrlFrom(origin, apiBasePath, actualRoute);\n const init: RequestInit = {\n method: QueryHttpMethod.Get,\n headers,\n signal\n };\n return { url, init };\n}\n\n/**\n * The transport learned for {@link QueryHttpMethod.Auto}, keyed by backend (origin + API base path).\n * Once QUERY is found to be unsupported for a backend it is pinned to GET for the rest of the session;\n * while QUERY works the backend stays absent so each attempt keeps verifying cheaply. Keying by backend\n * means one backend rejecting QUERY does not downgrade queries to other backends.\n */\nconst autoResolvedMethods = new Map<string, QueryHttpMethod>();\n\nfunction backendKey(options: BuildQueryHttpRequestOptions): string {\n return `${options.origin}\u0000${options.apiBasePath}`;\n}\n\n/**\n * Resets the transport learned for {@link QueryHttpMethod.Auto} for every backend, so the next Auto\n * query re-probes for QUERY support. Useful after a network change, or between tests.\n */\nexport function resetQueryHttpMethodResolution(): void {\n autoResolvedMethods.clear();\n}\n\nfunction isMethodUnsupported(status: number): boolean {\n // 405 Method Not Allowed / 501 Not Implemented — the server received the request but will not\n // handle the verb (e.g. QUERY disabled). A missing intermediary surfaces as a thrown TypeError.\n return status === 405 || status === 501;\n}\n\nfunction isAbortError(error: unknown): boolean {\n return (error as { name?: string })?.name === 'AbortError';\n}\n\n/**\n * Performs the query HTTP request for the given method, resolving {@link QueryHttpMethod.Auto} by\n * preferring QUERY and falling back to GET when the server or network path does not support it.\n *\n * Explicit {@link QueryHttpMethod.Get} and {@link QueryHttpMethod.Query} are honored exactly, with no\n * fallback. For Auto, a transport-level failure — a `405`/`501` response, or a network/CORS error from\n * {@link fetch} — falls back to GET and pins the session to GET. Application-level errors (any other\n * status, returned as a normal {@link Response}) are never treated as a fallback signal.\n *\n * The method is resolved in order of precedence: an explicit per-query {@code override}, then\n * {@link Globals.queryHttpMethodResolver} (given the built GET URL), then {@link Globals.queryHttpMethod}.\n * @param override The explicit per-query {@link QueryHttpMethod}, or `undefined` to resolve from globals.\n * @param options The {@link BuildQueryHttpRequestOptions} describing the request.\n * @returns The {@link Response} from the request that was ultimately sent.\n */\nexport async function executeQueryHttpRequest(override: QueryHttpMethod | undefined, options: BuildQueryHttpRequestOptions): Promise<Response> {\n // The GET request is built up front when a resolver needs the URL, and reused if GET is chosen.\n let getRequest: { url: URL; init: RequestInit } | undefined;\n let method: QueryHttpMethod;\n if (override !== undefined) {\n method = override;\n } else if (Globals.queryHttpMethodResolver) {\n getRequest = buildQueryHttpRequest(QueryHttpMethod.Get, options);\n method = Globals.queryHttpMethodResolver({ url: getRequest.url, route: options.route, args: options.args });\n } else {\n method = Globals.queryHttpMethod;\n }\n\n const send = (httpMethod: QueryHttpMethod): Promise<Response> => {\n if (httpMethod === QueryHttpMethod.Get && getRequest) {\n return fetch(getRequest.url, getRequest.init);\n }\n const { url, init } = buildQueryHttpRequest(httpMethod, options);\n return fetch(url, init);\n };\n\n if (method !== QueryHttpMethod.Auto) {\n return send(method);\n }\n\n const key = backendKey(options);\n if (autoResolvedMethods.get(key) === QueryHttpMethod.Get) {\n return send(QueryHttpMethod.Get);\n }\n\n try {\n const response = await send(QueryHttpMethod.Query);\n if (isMethodUnsupported(response.status)) {\n autoResolvedMethods.set(key, QueryHttpMethod.Get);\n return send(QueryHttpMethod.Get);\n }\n autoResolvedMethods.set(key, QueryHttpMethod.Query);\n return response;\n } catch (error) {\n if (isAbortError(error)) {\n throw error;\n }\n autoResolvedMethods.set(key, QueryHttpMethod.Get);\n return send(QueryHttpMethod.Get);\n }\n}\n"],"names":["directionToString","sorting","direction","SortDirection","descending","buildQueryHttpRequest","method","options","route","apiBasePath","origin","args","parameterValues","paging","headers","signal","replacedRoute","unusedParameters","UrlHelpers","replaceRouteParameters","argumentValues","actualRoute","joinPaths","QueryHttpMethod","Query","url","createUrlFrom","payload","arguments","hasPaging","page","pageSize","hasSorting","field","requestHeaders","Headers","has","set","init","body","JSON","stringify","additionalParams","sortBy","sortDirection","queryParams","buildQueryParams","queryString","toString","includes","Get","autoResolvedMethods","Map","backendKey","resetQueryHttpMethodResolution","clear","isMethodUnsupported","status","isAbortError","error","name","executeQueryHttpRequest","override","getRequest","undefined","Globals","queryHttpMethodResolver","queryHttpMethod","send","httpMethod","fetch","Auto","key","get","response"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"QueryHttpRequest.js","sources":["../../../queries/QueryHttpRequest.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { Paging } from './Paging';\nimport { Sorting } from './Sorting';\nimport { SortDirection } from './SortDirection';\nimport { QueryHttpMethod } from './QueryHttpMethod';\nimport { joinPaths } from '../joinPaths';\nimport { UrlHelpers } from '../UrlHelpers';\nimport { Globals } from '../Globals';\nimport { isAbortError } from './isAbortError';\n\n/**\n * Options for building an HTTP request for a query.\n */\nexport interface BuildQueryHttpRequestOptions {\n /** The route template for the query, possibly containing route parameters. */\n route: string;\n /** The base path for the API. */\n apiBasePath: string;\n /** The origin for the API. */\n origin: string;\n /** The arguments used for route-parameter substitution and as query arguments. */\n args: object;\n /** Descriptor-collected parameter values that also form query arguments. */\n parameterValues: object;\n /** The paging for the query. */\n paging: Paging;\n /** The sorting for the query. */\n sorting: Sorting;\n /** The HTTP headers to include. */\n headers: HeadersInit;\n /** Optional abort signal for the request. */\n signal?: AbortSignal;\n}\n\ninterface QueryRequestPayload {\n arguments: object;\n paging?: { page: number; pageSize: number };\n sorting?: { field: string; direction: string };\n}\n\nfunction directionToString(sorting: Sorting): string {\n return sorting.direction === SortDirection.descending ? 'desc' : 'asc';\n}\n\n/**\n * Builds the URL and {@link RequestInit} for performing a query with the given HTTP method.\n *\n * For {@link QueryHttpMethod.Get}, arguments, paging and sorting are placed in the URL query string.\n * For {@link QueryHttpMethod.Query}, route parameters remain in the path while the arguments, paging\n * and sorting are carried in a JSON body envelope.\n * @param method The {@link QueryHttpMethod} to use.\n * @param options The {@link BuildQueryHttpRequestOptions} describing the request.\n * @returns The URL and {@link RequestInit} to pass to {@link fetch}.\n */\nexport function buildQueryHttpRequest(method: QueryHttpMethod, options: BuildQueryHttpRequestOptions): { url: URL; init: RequestInit } {\n const { route, apiBasePath, origin, args, parameterValues, paging, sorting, headers, signal } = options;\n\n const { route: replacedRoute, unusedParameters } = UrlHelpers.replaceRouteParameters(route, args);\n const argumentValues = { ...unusedParameters, ...parameterValues };\n let actualRoute = joinPaths(apiBasePath, replacedRoute);\n\n if (method === QueryHttpMethod.Query) {\n const url = UrlHelpers.createUrlFrom(origin, apiBasePath, actualRoute);\n const payload: QueryRequestPayload = { arguments: argumentValues };\n if (paging.hasPaging) {\n payload.paging = { page: paging.page, pageSize: paging.pageSize };\n }\n if (sorting.hasSorting) {\n payload.sorting = { field: sorting.field, direction: directionToString(sorting) };\n }\n\n const requestHeaders = new Headers(headers);\n if (!requestHeaders.has('Content-Type')) {\n requestHeaders.set('Content-Type', 'application/json');\n }\n\n const init: RequestInit = {\n method: QueryHttpMethod.Query,\n headers: requestHeaders,\n body: JSON.stringify(payload),\n signal\n };\n return { url, init };\n }\n\n const additionalParams: Record<string, string | number> = {};\n if (paging.hasPaging) {\n additionalParams.page = paging.page;\n additionalParams.pageSize = paging.pageSize;\n }\n if (sorting.hasSorting) {\n additionalParams.sortBy = sorting.field;\n additionalParams.sortDirection = directionToString(sorting);\n }\n\n const queryParams = UrlHelpers.buildQueryParams(argumentValues, additionalParams);\n const queryString = queryParams.toString();\n if (queryString) {\n actualRoute += (actualRoute.includes('?') ? '&' : '?') + queryString;\n }\n\n const url = UrlHelpers.createUrlFrom(origin, apiBasePath, actualRoute);\n const init: RequestInit = {\n method: QueryHttpMethod.Get,\n headers,\n signal\n };\n return { url, init };\n}\n\n/**\n * The transport learned for {@link QueryHttpMethod.Auto}, keyed by backend (origin + API base path).\n * Once QUERY is found to be unsupported for a backend it is pinned to GET for the rest of the session;\n * while QUERY works the backend stays absent so each attempt keeps verifying cheaply. Keying by backend\n * means one backend rejecting QUERY does not downgrade queries to other backends.\n */\nconst autoResolvedMethods = new Map<string, QueryHttpMethod>();\n\n// A NUL separator cannot occur in an origin or an API base path, so no pair of backends can\n// produce the same composite key. Written as an escape rather than a literal control byte,\n// which would make git classify this file as binary and hide every diff of it from review.\nfunction backendKey(options: BuildQueryHttpRequestOptions): string {\n return `${options.origin}\\0${options.apiBasePath}`;\n}\n\n/**\n * Resets the transport learned for {@link QueryHttpMethod.Auto} for every backend, so the next Auto\n * query re-probes for QUERY support. Useful after a network change, or between tests.\n */\nexport function resetQueryHttpMethodResolution(): void {\n autoResolvedMethods.clear();\n}\n\nfunction isMethodUnsupported(status: number): boolean {\n // 405 Method Not Allowed / 501 Not Implemented — the server received the request but will not\n // handle the verb (e.g. QUERY disabled). A missing intermediary surfaces as a thrown TypeError.\n return status === 405 || status === 501;\n}\n\n/**\n * Performs the query HTTP request for the given method, resolving {@link QueryHttpMethod.Auto} by\n * preferring QUERY and falling back to GET when the server or network path does not support it.\n *\n * Explicit {@link QueryHttpMethod.Get} and {@link QueryHttpMethod.Query} are honored exactly, with no\n * fallback. For Auto, a transport-level failure — a `405`/`501` response, or a network/CORS error from\n * {@link fetch} — falls back to GET and pins the session to GET. Application-level errors (any other\n * status, returned as a normal {@link Response}) are never treated as a fallback signal.\n *\n * The method is resolved in order of precedence: an explicit per-query {@code override}, then\n * {@link Globals.queryHttpMethodResolver} (given the built GET URL), then {@link Globals.queryHttpMethod}.\n * @param override The explicit per-query {@link QueryHttpMethod}, or `undefined` to resolve from globals.\n * @param options The {@link BuildQueryHttpRequestOptions} describing the request.\n * @returns The {@link Response} from the request that was ultimately sent.\n */\nexport async function executeQueryHttpRequest(override: QueryHttpMethod | undefined, options: BuildQueryHttpRequestOptions): Promise<Response> {\n // The GET request is built up front when a resolver needs the URL, and reused if GET is chosen.\n let getRequest: { url: URL; init: RequestInit } | undefined;\n let method: QueryHttpMethod;\n if (override !== undefined) {\n method = override;\n } else if (Globals.queryHttpMethodResolver) {\n getRequest = buildQueryHttpRequest(QueryHttpMethod.Get, options);\n method = Globals.queryHttpMethodResolver({ url: getRequest.url, route: options.route, args: options.args });\n } else {\n method = Globals.queryHttpMethod;\n }\n\n const send = (httpMethod: QueryHttpMethod): Promise<Response> => {\n if (httpMethod === QueryHttpMethod.Get && getRequest) {\n return fetch(getRequest.url, getRequest.init);\n }\n const { url, init } = buildQueryHttpRequest(httpMethod, options);\n return fetch(url, init);\n };\n\n if (method !== QueryHttpMethod.Auto) {\n return send(method);\n }\n\n const key = backendKey(options);\n if (autoResolvedMethods.get(key) === QueryHttpMethod.Get) {\n return send(QueryHttpMethod.Get);\n }\n\n try {\n const response = await send(QueryHttpMethod.Query);\n if (isMethodUnsupported(response.status)) {\n autoResolvedMethods.set(key, QueryHttpMethod.Get);\n return send(QueryHttpMethod.Get);\n }\n autoResolvedMethods.set(key, QueryHttpMethod.Query);\n return response;\n } catch (error) {\n if (isAbortError(error)) {\n throw error;\n }\n autoResolvedMethods.set(key, QueryHttpMethod.Get);\n return send(QueryHttpMethod.Get);\n }\n}\n"],"names":["directionToString","sorting","direction","SortDirection","descending","buildQueryHttpRequest","method","options","route","apiBasePath","origin","args","parameterValues","paging","headers","signal","replacedRoute","unusedParameters","UrlHelpers","replaceRouteParameters","argumentValues","actualRoute","joinPaths","QueryHttpMethod","Query","url","createUrlFrom","payload","arguments","hasPaging","page","pageSize","hasSorting","field","requestHeaders","Headers","has","set","init","body","JSON","stringify","additionalParams","sortBy","sortDirection","queryParams","buildQueryParams","queryString","toString","includes","Get","autoResolvedMethods","Map","backendKey","resetQueryHttpMethodResolution","clear","isMethodUnsupported","status","executeQueryHttpRequest","override","getRequest","undefined","Globals","queryHttpMethodResolver","queryHttpMethod","send","httpMethod","fetch","Auto","key","get","response","error","isAbortError"],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Copyright (c) Cratis. All rights reserved.
|
|
4
|
+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
5
|
+
/**
|
|
6
|
+
* Determines whether an error is the rejection produced by aborting a request through an
|
|
7
|
+
* {@link AbortSignal} - as opposed to a genuine transport failure.
|
|
8
|
+
*
|
|
9
|
+
* Deliberately kept out of the `queries` barrel: it is an internal detail shared by the query
|
|
10
|
+
* transport and {@link QueryFor}, not public surface for consumers to depend on.
|
|
11
|
+
* @param error The error to inspect.
|
|
12
|
+
* @returns True if the error represents an aborted request, false otherwise.
|
|
13
|
+
*/ function isAbortError(error) {
|
|
14
|
+
return error?.name === 'AbortError';
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
exports.isAbortError = isAbortError;
|
|
18
|
+
//# sourceMappingURL=isAbortError.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isAbortError.js","sources":["../../../queries/isAbortError.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n/**\n * Determines whether an error is the rejection produced by aborting a request through an\n * {@link AbortSignal} - as opposed to a genuine transport failure.\n *\n * Deliberately kept out of the `queries` barrel: it is an internal detail shared by the query\n * transport and {@link QueryFor}, not public surface for consumers to depend on.\n * @param error The error to inspect.\n * @returns True if the error represents an aborted request, false otherwise.\n */\nexport function isAbortError(error: unknown): boolean {\n return (error as { name?: string })?.name === 'AbortError';\n}\n"],"names":["isAbortError","error","name"],"mappings":";;AAAA;AACA;AAEA;;;;;;;;IASO,SAASA,YAAAA,CAAaC,KAAc,EAAA;IACvC,OAAQA,OAA6BC,IAAAA,KAAS,YAAA;AAClD;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"QueryFor.d.ts","sourceRoot":"","sources":["../../../queries/QueryFor.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAElC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AAExE,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"QueryFor.d.ts","sourceRoot":"","sources":["../../../queries/QueryFor.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAElC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AAExE,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAQpD,8BAAsB,QAAQ,CAAC,SAAS,EAAE,WAAW,GAAG,MAAM,CAAE,YAAW,SAAS,CAAC,SAAS,EAAE,WAAW,CAAC;IA0B5F,QAAQ,CAAC,SAAS,EAAE,WAAW;IAAE,QAAQ,CAAC,UAAU,EAAE,OAAO;IAzBzE,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,oBAAoB,CAAiB;IAC7C,OAAO,CAAC,WAAW,CAAC,CAAkB;IACtC,QAAQ,CAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAEhC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAE5B,QAAQ,CAAC,UAAU,CAAC,EAAE,cAAc,CAAC,GAAG,CAAC,CAAC;IAE1C,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,CAAM;IAC9B,QAAQ,CAAC,QAAQ,CAAC,oBAAoB,EAAE,mBAAmB,EAAE,CAAC;IAC9D,QAAQ,KAAK,yBAAyB,IAAI,MAAM,EAAE,CAAC;IACnD,QAAQ,CAAC,YAAY,EAAE,SAAS,CAAC;IACjC,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,WAAW,GAAG,SAAS,CAAC;IAOpC,YAAqB,SAAS,EAAE,WAAW,EAAW,UAAU,EAAE,OAAO,EAOxE;IAGD,eAAe,CAAC,YAAY,EAAE,MAAM,QAEnC;IAGD,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAExC;IAGD,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAE9B;IAGD,sBAAsB,CAAC,QAAQ,EAAE,cAAc,GAAG,IAAI,CAErD;IAGD,aAAa,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAE3C;IAGK,OAAO,CAAC,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,CA8FjE;CACJ"}
|
|
@@ -5,6 +5,7 @@ import { Globals } from '../Globals.js';
|
|
|
5
5
|
import { Sorting } from './Sorting.js';
|
|
6
6
|
import { ParametersHelper } from '../reflection/ParametersHelper.js';
|
|
7
7
|
import { executeQueryHttpRequest } from './QueryHttpRequest.js';
|
|
8
|
+
import { isAbortError } from './isAbortError.js';
|
|
8
9
|
|
|
9
10
|
// Copyright (c) Cratis. All rights reserved.
|
|
10
11
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
@@ -88,17 +89,55 @@ import { executeQueryHttpRequest } from './QueryHttpRequest.js';
|
|
|
88
89
|
if (this._microservice?.length > 0) {
|
|
89
90
|
headers[Globals.microserviceHttpHeader] = this._microservice;
|
|
90
91
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
92
|
+
let response;
|
|
93
|
+
try {
|
|
94
|
+
response = await executeQueryHttpRequest(this._httpMethod, {
|
|
95
|
+
route: this.route,
|
|
96
|
+
apiBasePath: this._apiBasePath,
|
|
97
|
+
origin: this._origin,
|
|
98
|
+
args: args ?? {},
|
|
99
|
+
parameterValues,
|
|
100
|
+
paging: this.paging,
|
|
101
|
+
sorting: this.sorting,
|
|
102
|
+
headers,
|
|
103
|
+
signal: this.abortController.signal
|
|
104
|
+
});
|
|
105
|
+
} catch (error) {
|
|
106
|
+
// An abort is not a failure - it is this query superseding its own in-flight request above.
|
|
107
|
+
// Rethrowing lets the caller discard the superseded request so it cannot settle over the
|
|
108
|
+
// newer one that now owns the result.
|
|
109
|
+
if (isAbortError(error)) {
|
|
110
|
+
throw error;
|
|
111
|
+
}
|
|
112
|
+
// A dead network, a CORS rejection or a DNS failure never reaches the server, so it is
|
|
113
|
+
// neither an authorization nor a validation outcome - it is reported as an exception, with
|
|
114
|
+
// the default value as data, exactly as every other unsuccessful result from here does.
|
|
115
|
+
// Destructuring a nullish rejection value throws, which would make the `String(error)`
|
|
116
|
+
// fallback written for exactly that case unreachable - so it is coerced to an object first.
|
|
117
|
+
const { message } = error ?? {};
|
|
118
|
+
const failure = {
|
|
119
|
+
...QueryResult.noSuccess,
|
|
120
|
+
data: this.defaultValue,
|
|
121
|
+
isSuccess: false,
|
|
122
|
+
isAuthorized: true,
|
|
123
|
+
isValid: true,
|
|
124
|
+
hasExceptions: true,
|
|
125
|
+
exceptionMessages: [
|
|
126
|
+
message ?? String(error)
|
|
127
|
+
],
|
|
128
|
+
// Left empty on purpose. Every result the server returns has its stack trace blanked
|
|
129
|
+
// unless exception detail is explicitly exposed, and consumers are told to forward
|
|
130
|
+
// this field to a logger - so filling it in here would make a failure that never
|
|
131
|
+
// reached the server the one case that escapes that policy. The message is what
|
|
132
|
+
// diagnoses a transport failure; the browser's own frames add nothing.
|
|
133
|
+
exceptionStackTrace: ''
|
|
134
|
+
};
|
|
135
|
+
// `hasData` is a prototype getter, and a spread copies own properties only - so the literal
|
|
136
|
+
// above would hand every consumer of this public `IQueryResult` member `undefined` instead
|
|
137
|
+
// of a boolean. Restoring the prototype makes it a real {@link QueryResult} again while
|
|
138
|
+
// leaving every field value exactly as it is.
|
|
139
|
+
return Object.setPrototypeOf(failure, QueryResult.prototype);
|
|
140
|
+
}
|
|
102
141
|
try {
|
|
103
142
|
const result = await response.json();
|
|
104
143
|
return new QueryResult(result, this.modelType, this.enumerable);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"QueryFor.js","sources":["../../../queries/QueryFor.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { IQueryFor } from './IQueryFor';\nimport { QueryResult } from \"./QueryResult\";\nimport { QueryValidator } from './QueryValidator';\nimport { ValidateRequestArguments } from './ValidateRequestArguments';\nimport { Constructor } from '@cratis/fundamentals';\nimport { Paging } from './Paging';\nimport { Globals } from '../Globals';\nimport { Sorting } from './Sorting';\nimport { GetHttpHeaders } from '../GetHttpHeaders';\nimport { ParameterDescriptor } from '../reflection/ParameterDescriptor';\nimport { ParametersHelper } from '../reflection/ParametersHelper';\nimport { QueryHttpMethod } from './QueryHttpMethod';\nimport { executeQueryHttpRequest } from './QueryHttpRequest';\n\n/**\n * Represents an implementation of {@link IQueryFor}.\n * @template TDataType Type of data returned by the query.\n */\nexport abstract class QueryFor<TDataType, TParameters = object> implements IQueryFor<TDataType, TParameters> {\n private _microservice: string;\n private _apiBasePath: string;\n private _origin: string;\n private _httpHeadersCallback: GetHttpHeaders;\n private _httpMethod?: QueryHttpMethod;\n abstract readonly route: string;\n /** Backend fully-qualified query name used as cache key. Overridden in generated proxies. */\n readonly queryName?: string;\n /* eslint-disable @typescript-eslint/no-explicit-any */\n readonly validation?: QueryValidator<any>;\n /* eslint-enable @typescript-eslint/no-explicit-any */\n readonly roles: string[] = [];\n abstract readonly parameterDescriptors: ParameterDescriptor[];\n abstract get requiredRequestParameters(): string[];\n abstract defaultValue: TDataType;\n abortController?: AbortController;\n sorting: Sorting;\n paging: Paging;\n parameters: TParameters | undefined;\n\n /**\n * Initializes a new instance of the {@link ObservableQueryFor<,>}} class.\n * @param modelType Type of model, if an enumerable, this is the instance type.\n * @param enumerable Whether or not it is an enumerable.\n */\n constructor(readonly modelType: Constructor, readonly enumerable: boolean) {\n this.sorting = Sorting.none;\n this.paging = Paging.noPaging;\n this._microservice = Globals.microservice ?? '';\n this._apiBasePath = Globals.apiBasePath ?? '';\n this._origin = Globals.origin ?? '';\n this._httpHeadersCallback = () => ({});\n }\n\n /** @inheritdoc */\n setMicroservice(microservice: string) {\n this._microservice = microservice;\n }\n\n /** @inheritdoc */\n setApiBasePath(apiBasePath: string): void {\n this._apiBasePath = apiBasePath;\n }\n\n /** @inheritdoc */\n setOrigin(origin: string): void {\n this._origin = origin;\n }\n\n /** @inheritdoc */\n setHttpHeadersCallback(callback: GetHttpHeaders): void {\n this._httpHeadersCallback = callback;\n }\n\n /** @inheritdoc */\n setHttpMethod(method: QueryHttpMethod): void {\n this._httpMethod = method;\n }\n\n /** @inheritdoc */\n async perform(args?: TParameters): Promise<QueryResult<TDataType>> {\n const noSuccess = { ...QueryResult.noSuccess, ...{ data: this.defaultValue } } as QueryResult<TDataType>;\n\n args = args || this.parameters;\n\n const clientValidationErrors = this.validation?.validate(args as object || {}) || [];\n if (clientValidationErrors.length > 0) {\n return QueryResult.validationFailed(clientValidationErrors, this);\n }\n\n if (!ValidateRequestArguments(this.constructor.name, this.requiredRequestParameters, args as object)) {\n return new Promise<QueryResult<TDataType>>((resolve) => {\n resolve(noSuccess);\n });\n }\n\n if (this.abortController) {\n this.abortController.abort();\n }\n\n this.abortController = new AbortController();\n\n // Collect parameter values from parameterDescriptors that are set\n const parameterValues = ParametersHelper.collectParameterValues(this);\n\n const headers = {\n ... this._httpHeadersCallback?.(), ...\n {\n 'Accept': 'application/json',\n 'Content-Type': 'application/json'\n }\n };\n\n if (this._microservice?.length > 0) {\n headers[Globals.microserviceHttpHeader] = this._microservice;\n }\n\n const response = await executeQueryHttpRequest(this._httpMethod, {\n route: this.route,\n apiBasePath: this._apiBasePath,\n origin: this._origin,\n args: (args as object) ?? {},\n parameterValues,\n paging: this.paging,\n sorting: this.sorting,\n headers,\n signal: this.abortController.signal\n });\n\n try {\n const result = await response.json();\n return new QueryResult(result, this.modelType, this.enumerable);\n } catch {\n return noSuccess;\n }\n }\n}\n"],"names":["QueryFor","_microservice","_apiBasePath","_origin","_httpHeadersCallback","_httpMethod","queryName","validation","roles","abortController","sorting","paging","parameters","enumerable","modelType","Sorting","none","Paging","noPaging","Globals","microservice","apiBasePath","origin","setMicroservice","setApiBasePath","setOrigin","setHttpHeadersCallback","callback","setHttpMethod","method","perform","args","noSuccess","QueryResult","data","defaultValue","clientValidationErrors","validate","length","validationFailed","ValidateRequestArguments","name","requiredRequestParameters","Promise","resolve","abort","AbortController","parameterValues","ParametersHelper","collectParameterValues","headers","microserviceHttpHeader","response","executeQueryHttpRequest","route","signal","result","json"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"QueryFor.js","sources":["../../../queries/QueryFor.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { IQueryFor } from './IQueryFor';\nimport { QueryResult } from \"./QueryResult\";\nimport { QueryValidator } from './QueryValidator';\nimport { ValidateRequestArguments } from './ValidateRequestArguments';\nimport { Constructor } from '@cratis/fundamentals';\nimport { Paging } from './Paging';\nimport { Globals } from '../Globals';\nimport { Sorting } from './Sorting';\nimport { GetHttpHeaders } from '../GetHttpHeaders';\nimport { ParameterDescriptor } from '../reflection/ParameterDescriptor';\nimport { ParametersHelper } from '../reflection/ParametersHelper';\nimport { QueryHttpMethod } from './QueryHttpMethod';\nimport { executeQueryHttpRequest } from './QueryHttpRequest';\nimport { isAbortError } from './isAbortError';\n\n/**\n * Represents an implementation of {@link IQueryFor}.\n * @template TDataType Type of data returned by the query.\n */\nexport abstract class QueryFor<TDataType, TParameters = object> implements IQueryFor<TDataType, TParameters> {\n private _microservice: string;\n private _apiBasePath: string;\n private _origin: string;\n private _httpHeadersCallback: GetHttpHeaders;\n private _httpMethod?: QueryHttpMethod;\n abstract readonly route: string;\n /** Backend fully-qualified query name used as cache key. Overridden in generated proxies. */\n readonly queryName?: string;\n /* eslint-disable @typescript-eslint/no-explicit-any */\n readonly validation?: QueryValidator<any>;\n /* eslint-enable @typescript-eslint/no-explicit-any */\n readonly roles: string[] = [];\n abstract readonly parameterDescriptors: ParameterDescriptor[];\n abstract get requiredRequestParameters(): string[];\n abstract defaultValue: TDataType;\n abortController?: AbortController;\n sorting: Sorting;\n paging: Paging;\n parameters: TParameters | undefined;\n\n /**\n * Initializes a new instance of the {@link ObservableQueryFor<,>}} class.\n * @param modelType Type of model, if an enumerable, this is the instance type.\n * @param enumerable Whether or not it is an enumerable.\n */\n constructor(readonly modelType: Constructor, readonly enumerable: boolean) {\n this.sorting = Sorting.none;\n this.paging = Paging.noPaging;\n this._microservice = Globals.microservice ?? '';\n this._apiBasePath = Globals.apiBasePath ?? '';\n this._origin = Globals.origin ?? '';\n this._httpHeadersCallback = () => ({});\n }\n\n /** @inheritdoc */\n setMicroservice(microservice: string) {\n this._microservice = microservice;\n }\n\n /** @inheritdoc */\n setApiBasePath(apiBasePath: string): void {\n this._apiBasePath = apiBasePath;\n }\n\n /** @inheritdoc */\n setOrigin(origin: string): void {\n this._origin = origin;\n }\n\n /** @inheritdoc */\n setHttpHeadersCallback(callback: GetHttpHeaders): void {\n this._httpHeadersCallback = callback;\n }\n\n /** @inheritdoc */\n setHttpMethod(method: QueryHttpMethod): void {\n this._httpMethod = method;\n }\n\n /** @inheritdoc */\n async perform(args?: TParameters): Promise<QueryResult<TDataType>> {\n const noSuccess = { ...QueryResult.noSuccess, ...{ data: this.defaultValue } } as QueryResult<TDataType>;\n\n args = args || this.parameters;\n\n const clientValidationErrors = this.validation?.validate(args as object || {}) || [];\n if (clientValidationErrors.length > 0) {\n return QueryResult.validationFailed(clientValidationErrors, this);\n }\n\n if (!ValidateRequestArguments(this.constructor.name, this.requiredRequestParameters, args as object)) {\n return new Promise<QueryResult<TDataType>>((resolve) => {\n resolve(noSuccess);\n });\n }\n\n if (this.abortController) {\n this.abortController.abort();\n }\n\n this.abortController = new AbortController();\n\n // Collect parameter values from parameterDescriptors that are set\n const parameterValues = ParametersHelper.collectParameterValues(this);\n\n const headers = {\n ... this._httpHeadersCallback?.(), ...\n {\n 'Accept': 'application/json',\n 'Content-Type': 'application/json'\n }\n };\n\n if (this._microservice?.length > 0) {\n headers[Globals.microserviceHttpHeader] = this._microservice;\n }\n\n let response: Response;\n\n try {\n response = await executeQueryHttpRequest(this._httpMethod, {\n route: this.route,\n apiBasePath: this._apiBasePath,\n origin: this._origin,\n args: (args as object) ?? {},\n parameterValues,\n paging: this.paging,\n sorting: this.sorting,\n headers,\n signal: this.abortController.signal\n });\n } catch (error) {\n // An abort is not a failure - it is this query superseding its own in-flight request above.\n // Rethrowing lets the caller discard the superseded request so it cannot settle over the\n // newer one that now owns the result.\n if (isAbortError(error)) {\n throw error;\n }\n\n // A dead network, a CORS rejection or a DNS failure never reaches the server, so it is\n // neither an authorization nor a validation outcome - it is reported as an exception, with\n // the default value as data, exactly as every other unsuccessful result from here does.\n // Destructuring a nullish rejection value throws, which would make the `String(error)`\n // fallback written for exactly that case unreachable - so it is coerced to an object first.\n const { message } = (error ?? {}) as { message?: string };\n const failure = {\n ...QueryResult.noSuccess,\n data: this.defaultValue,\n isSuccess: false,\n isAuthorized: true,\n isValid: true,\n hasExceptions: true,\n exceptionMessages: [message ?? String(error)],\n // Left empty on purpose. Every result the server returns has its stack trace blanked\n // unless exception detail is explicitly exposed, and consumers are told to forward\n // this field to a logger - so filling it in here would make a failure that never\n // reached the server the one case that escapes that policy. The message is what\n // diagnoses a transport failure; the browser's own frames add nothing.\n exceptionStackTrace: ''\n };\n\n // `hasData` is a prototype getter, and a spread copies own properties only - so the literal\n // above would hand every consumer of this public `IQueryResult` member `undefined` instead\n // of a boolean. Restoring the prototype makes it a real {@link QueryResult} again while\n // leaving every field value exactly as it is.\n return Object.setPrototypeOf(failure, QueryResult.prototype) as QueryResult<TDataType>;\n }\n\n try {\n const result = await response.json();\n return new QueryResult(result, this.modelType, this.enumerable);\n } catch {\n return noSuccess;\n }\n }\n}\n"],"names":["QueryFor","_microservice","_apiBasePath","_origin","_httpHeadersCallback","_httpMethod","queryName","validation","roles","abortController","sorting","paging","parameters","enumerable","modelType","Sorting","none","Paging","noPaging","Globals","microservice","apiBasePath","origin","setMicroservice","setApiBasePath","setOrigin","setHttpHeadersCallback","callback","setHttpMethod","method","perform","args","noSuccess","QueryResult","data","defaultValue","clientValidationErrors","validate","length","validationFailed","ValidateRequestArguments","name","requiredRequestParameters","Promise","resolve","abort","AbortController","parameterValues","ParametersHelper","collectParameterValues","headers","microserviceHttpHeader","response","executeQueryHttpRequest","route","signal","error","isAbortError","message","failure","isSuccess","isAuthorized","isValid","hasExceptions","exceptionMessages","String","exceptionStackTrace","Object","setPrototypeOf","prototype","result","json"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"QueryHttpRequest.d.ts","sourceRoot":"","sources":["../../../queries/QueryHttpRequest.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"QueryHttpRequest.d.ts","sourceRoot":"","sources":["../../../queries/QueryHttpRequest.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AASpD,MAAM,WAAW,4BAA4B;IAEzC,KAAK,EAAE,MAAM,CAAC;IAEd,WAAW,EAAE,MAAM,CAAC;IAEpB,MAAM,EAAE,MAAM,CAAC;IAEf,IAAI,EAAE,MAAM,CAAC;IAEb,eAAe,EAAE,MAAM,CAAC;IAExB,MAAM,EAAE,MAAM,CAAC;IAEf,OAAO,EAAE,OAAO,CAAC;IAEjB,OAAO,EAAE,WAAW,CAAC;IAErB,MAAM,CAAC,EAAE,WAAW,CAAC;CACxB;AAsBD,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,eAAe,EAAE,OAAO,EAAE,4BAA4B,GAAG;IAAE,GAAG,EAAE,GAAG,CAAC;IAAC,IAAI,EAAE,WAAW,CAAA;CAAE,CAsDrI;AAqBD,wBAAgB,8BAA8B,IAAI,IAAI,CAErD;AAuBD,wBAAsB,uBAAuB,CAAC,QAAQ,EAAE,eAAe,GAAG,SAAS,EAAE,OAAO,EAAE,4BAA4B,GAAG,OAAO,CAAC,QAAQ,CAAC,CA6C7I"}
|
|
Binary file
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"QueryHttpRequest.js","sources":["../../../queries/QueryHttpRequest.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { Paging } from './Paging';\nimport { Sorting } from './Sorting';\nimport { SortDirection } from './SortDirection';\nimport { QueryHttpMethod } from './QueryHttpMethod';\nimport { joinPaths } from '../joinPaths';\nimport { UrlHelpers } from '../UrlHelpers';\nimport { Globals } from '../Globals';\n\n/**\n * Options for building an HTTP request for a query.\n */\nexport interface BuildQueryHttpRequestOptions {\n /** The route template for the query, possibly containing route parameters. */\n route: string;\n /** The base path for the API. */\n apiBasePath: string;\n /** The origin for the API. */\n origin: string;\n /** The arguments used for route-parameter substitution and as query arguments. */\n args: object;\n /** Descriptor-collected parameter values that also form query arguments. */\n parameterValues: object;\n /** The paging for the query. */\n paging: Paging;\n /** The sorting for the query. */\n sorting: Sorting;\n /** The HTTP headers to include. */\n headers: HeadersInit;\n /** Optional abort signal for the request. */\n signal?: AbortSignal;\n}\n\ninterface QueryRequestPayload {\n arguments: object;\n paging?: { page: number; pageSize: number };\n sorting?: { field: string; direction: string };\n}\n\nfunction directionToString(sorting: Sorting): string {\n return sorting.direction === SortDirection.descending ? 'desc' : 'asc';\n}\n\n/**\n * Builds the URL and {@link RequestInit} for performing a query with the given HTTP method.\n *\n * For {@link QueryHttpMethod.Get}, arguments, paging and sorting are placed in the URL query string.\n * For {@link QueryHttpMethod.Query}, route parameters remain in the path while the arguments, paging\n * and sorting are carried in a JSON body envelope.\n * @param method The {@link QueryHttpMethod} to use.\n * @param options The {@link BuildQueryHttpRequestOptions} describing the request.\n * @returns The URL and {@link RequestInit} to pass to {@link fetch}.\n */\nexport function buildQueryHttpRequest(method: QueryHttpMethod, options: BuildQueryHttpRequestOptions): { url: URL; init: RequestInit } {\n const { route, apiBasePath, origin, args, parameterValues, paging, sorting, headers, signal } = options;\n\n const { route: replacedRoute, unusedParameters } = UrlHelpers.replaceRouteParameters(route, args);\n const argumentValues = { ...unusedParameters, ...parameterValues };\n let actualRoute = joinPaths(apiBasePath, replacedRoute);\n\n if (method === QueryHttpMethod.Query) {\n const url = UrlHelpers.createUrlFrom(origin, apiBasePath, actualRoute);\n const payload: QueryRequestPayload = { arguments: argumentValues };\n if (paging.hasPaging) {\n payload.paging = { page: paging.page, pageSize: paging.pageSize };\n }\n if (sorting.hasSorting) {\n payload.sorting = { field: sorting.field, direction: directionToString(sorting) };\n }\n\n const requestHeaders = new Headers(headers);\n if (!requestHeaders.has('Content-Type')) {\n requestHeaders.set('Content-Type', 'application/json');\n }\n\n const init: RequestInit = {\n method: QueryHttpMethod.Query,\n headers: requestHeaders,\n body: JSON.stringify(payload),\n signal\n };\n return { url, init };\n }\n\n const additionalParams: Record<string, string | number> = {};\n if (paging.hasPaging) {\n additionalParams.page = paging.page;\n additionalParams.pageSize = paging.pageSize;\n }\n if (sorting.hasSorting) {\n additionalParams.sortBy = sorting.field;\n additionalParams.sortDirection = directionToString(sorting);\n }\n\n const queryParams = UrlHelpers.buildQueryParams(argumentValues, additionalParams);\n const queryString = queryParams.toString();\n if (queryString) {\n actualRoute += (actualRoute.includes('?') ? '&' : '?') + queryString;\n }\n\n const url = UrlHelpers.createUrlFrom(origin, apiBasePath, actualRoute);\n const init: RequestInit = {\n method: QueryHttpMethod.Get,\n headers,\n signal\n };\n return { url, init };\n}\n\n/**\n * The transport learned for {@link QueryHttpMethod.Auto}, keyed by backend (origin + API base path).\n * Once QUERY is found to be unsupported for a backend it is pinned to GET for the rest of the session;\n * while QUERY works the backend stays absent so each attempt keeps verifying cheaply. Keying by backend\n * means one backend rejecting QUERY does not downgrade queries to other backends.\n */\nconst autoResolvedMethods = new Map<string, QueryHttpMethod>();\n\nfunction backendKey(options: BuildQueryHttpRequestOptions): string {\n return `${options.origin}\u0000${options.apiBasePath}`;\n}\n\n/**\n * Resets the transport learned for {@link QueryHttpMethod.Auto} for every backend, so the next Auto\n * query re-probes for QUERY support. Useful after a network change, or between tests.\n */\nexport function resetQueryHttpMethodResolution(): void {\n autoResolvedMethods.clear();\n}\n\nfunction isMethodUnsupported(status: number): boolean {\n // 405 Method Not Allowed / 501 Not Implemented — the server received the request but will not\n // handle the verb (e.g. QUERY disabled). A missing intermediary surfaces as a thrown TypeError.\n return status === 405 || status === 501;\n}\n\nfunction isAbortError(error: unknown): boolean {\n return (error as { name?: string })?.name === 'AbortError';\n}\n\n/**\n * Performs the query HTTP request for the given method, resolving {@link QueryHttpMethod.Auto} by\n * preferring QUERY and falling back to GET when the server or network path does not support it.\n *\n * Explicit {@link QueryHttpMethod.Get} and {@link QueryHttpMethod.Query} are honored exactly, with no\n * fallback. For Auto, a transport-level failure — a `405`/`501` response, or a network/CORS error from\n * {@link fetch} — falls back to GET and pins the session to GET. Application-level errors (any other\n * status, returned as a normal {@link Response}) are never treated as a fallback signal.\n *\n * The method is resolved in order of precedence: an explicit per-query {@code override}, then\n * {@link Globals.queryHttpMethodResolver} (given the built GET URL), then {@link Globals.queryHttpMethod}.\n * @param override The explicit per-query {@link QueryHttpMethod}, or `undefined` to resolve from globals.\n * @param options The {@link BuildQueryHttpRequestOptions} describing the request.\n * @returns The {@link Response} from the request that was ultimately sent.\n */\nexport async function executeQueryHttpRequest(override: QueryHttpMethod | undefined, options: BuildQueryHttpRequestOptions): Promise<Response> {\n // The GET request is built up front when a resolver needs the URL, and reused if GET is chosen.\n let getRequest: { url: URL; init: RequestInit } | undefined;\n let method: QueryHttpMethod;\n if (override !== undefined) {\n method = override;\n } else if (Globals.queryHttpMethodResolver) {\n getRequest = buildQueryHttpRequest(QueryHttpMethod.Get, options);\n method = Globals.queryHttpMethodResolver({ url: getRequest.url, route: options.route, args: options.args });\n } else {\n method = Globals.queryHttpMethod;\n }\n\n const send = (httpMethod: QueryHttpMethod): Promise<Response> => {\n if (httpMethod === QueryHttpMethod.Get && getRequest) {\n return fetch(getRequest.url, getRequest.init);\n }\n const { url, init } = buildQueryHttpRequest(httpMethod, options);\n return fetch(url, init);\n };\n\n if (method !== QueryHttpMethod.Auto) {\n return send(method);\n }\n\n const key = backendKey(options);\n if (autoResolvedMethods.get(key) === QueryHttpMethod.Get) {\n return send(QueryHttpMethod.Get);\n }\n\n try {\n const response = await send(QueryHttpMethod.Query);\n if (isMethodUnsupported(response.status)) {\n autoResolvedMethods.set(key, QueryHttpMethod.Get);\n return send(QueryHttpMethod.Get);\n }\n autoResolvedMethods.set(key, QueryHttpMethod.Query);\n return response;\n } catch (error) {\n if (isAbortError(error)) {\n throw error;\n }\n autoResolvedMethods.set(key, QueryHttpMethod.Get);\n return send(QueryHttpMethod.Get);\n }\n}\n"],"names":["directionToString","sorting","direction","SortDirection","descending","buildQueryHttpRequest","method","options","route","apiBasePath","origin","args","parameterValues","paging","headers","signal","replacedRoute","unusedParameters","UrlHelpers","replaceRouteParameters","argumentValues","actualRoute","joinPaths","QueryHttpMethod","Query","url","createUrlFrom","payload","arguments","hasPaging","page","pageSize","hasSorting","field","requestHeaders","Headers","has","set","init","body","JSON","stringify","additionalParams","sortBy","sortDirection","queryParams","buildQueryParams","queryString","toString","includes","Get","autoResolvedMethods","Map","backendKey","resetQueryHttpMethodResolution","clear","isMethodUnsupported","status","isAbortError","error","name","executeQueryHttpRequest","override","getRequest","undefined","Globals","queryHttpMethodResolver","queryHttpMethod","send","httpMethod","fetch","Auto","key","get","response"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"QueryHttpRequest.js","sources":["../../../queries/QueryHttpRequest.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { Paging } from './Paging';\nimport { Sorting } from './Sorting';\nimport { SortDirection } from './SortDirection';\nimport { QueryHttpMethod } from './QueryHttpMethod';\nimport { joinPaths } from '../joinPaths';\nimport { UrlHelpers } from '../UrlHelpers';\nimport { Globals } from '../Globals';\nimport { isAbortError } from './isAbortError';\n\n/**\n * Options for building an HTTP request for a query.\n */\nexport interface BuildQueryHttpRequestOptions {\n /** The route template for the query, possibly containing route parameters. */\n route: string;\n /** The base path for the API. */\n apiBasePath: string;\n /** The origin for the API. */\n origin: string;\n /** The arguments used for route-parameter substitution and as query arguments. */\n args: object;\n /** Descriptor-collected parameter values that also form query arguments. */\n parameterValues: object;\n /** The paging for the query. */\n paging: Paging;\n /** The sorting for the query. */\n sorting: Sorting;\n /** The HTTP headers to include. */\n headers: HeadersInit;\n /** Optional abort signal for the request. */\n signal?: AbortSignal;\n}\n\ninterface QueryRequestPayload {\n arguments: object;\n paging?: { page: number; pageSize: number };\n sorting?: { field: string; direction: string };\n}\n\nfunction directionToString(sorting: Sorting): string {\n return sorting.direction === SortDirection.descending ? 'desc' : 'asc';\n}\n\n/**\n * Builds the URL and {@link RequestInit} for performing a query with the given HTTP method.\n *\n * For {@link QueryHttpMethod.Get}, arguments, paging and sorting are placed in the URL query string.\n * For {@link QueryHttpMethod.Query}, route parameters remain in the path while the arguments, paging\n * and sorting are carried in a JSON body envelope.\n * @param method The {@link QueryHttpMethod} to use.\n * @param options The {@link BuildQueryHttpRequestOptions} describing the request.\n * @returns The URL and {@link RequestInit} to pass to {@link fetch}.\n */\nexport function buildQueryHttpRequest(method: QueryHttpMethod, options: BuildQueryHttpRequestOptions): { url: URL; init: RequestInit } {\n const { route, apiBasePath, origin, args, parameterValues, paging, sorting, headers, signal } = options;\n\n const { route: replacedRoute, unusedParameters } = UrlHelpers.replaceRouteParameters(route, args);\n const argumentValues = { ...unusedParameters, ...parameterValues };\n let actualRoute = joinPaths(apiBasePath, replacedRoute);\n\n if (method === QueryHttpMethod.Query) {\n const url = UrlHelpers.createUrlFrom(origin, apiBasePath, actualRoute);\n const payload: QueryRequestPayload = { arguments: argumentValues };\n if (paging.hasPaging) {\n payload.paging = { page: paging.page, pageSize: paging.pageSize };\n }\n if (sorting.hasSorting) {\n payload.sorting = { field: sorting.field, direction: directionToString(sorting) };\n }\n\n const requestHeaders = new Headers(headers);\n if (!requestHeaders.has('Content-Type')) {\n requestHeaders.set('Content-Type', 'application/json');\n }\n\n const init: RequestInit = {\n method: QueryHttpMethod.Query,\n headers: requestHeaders,\n body: JSON.stringify(payload),\n signal\n };\n return { url, init };\n }\n\n const additionalParams: Record<string, string | number> = {};\n if (paging.hasPaging) {\n additionalParams.page = paging.page;\n additionalParams.pageSize = paging.pageSize;\n }\n if (sorting.hasSorting) {\n additionalParams.sortBy = sorting.field;\n additionalParams.sortDirection = directionToString(sorting);\n }\n\n const queryParams = UrlHelpers.buildQueryParams(argumentValues, additionalParams);\n const queryString = queryParams.toString();\n if (queryString) {\n actualRoute += (actualRoute.includes('?') ? '&' : '?') + queryString;\n }\n\n const url = UrlHelpers.createUrlFrom(origin, apiBasePath, actualRoute);\n const init: RequestInit = {\n method: QueryHttpMethod.Get,\n headers,\n signal\n };\n return { url, init };\n}\n\n/**\n * The transport learned for {@link QueryHttpMethod.Auto}, keyed by backend (origin + API base path).\n * Once QUERY is found to be unsupported for a backend it is pinned to GET for the rest of the session;\n * while QUERY works the backend stays absent so each attempt keeps verifying cheaply. Keying by backend\n * means one backend rejecting QUERY does not downgrade queries to other backends.\n */\nconst autoResolvedMethods = new Map<string, QueryHttpMethod>();\n\n// A NUL separator cannot occur in an origin or an API base path, so no pair of backends can\n// produce the same composite key. Written as an escape rather than a literal control byte,\n// which would make git classify this file as binary and hide every diff of it from review.\nfunction backendKey(options: BuildQueryHttpRequestOptions): string {\n return `${options.origin}\\0${options.apiBasePath}`;\n}\n\n/**\n * Resets the transport learned for {@link QueryHttpMethod.Auto} for every backend, so the next Auto\n * query re-probes for QUERY support. Useful after a network change, or between tests.\n */\nexport function resetQueryHttpMethodResolution(): void {\n autoResolvedMethods.clear();\n}\n\nfunction isMethodUnsupported(status: number): boolean {\n // 405 Method Not Allowed / 501 Not Implemented — the server received the request but will not\n // handle the verb (e.g. QUERY disabled). A missing intermediary surfaces as a thrown TypeError.\n return status === 405 || status === 501;\n}\n\n/**\n * Performs the query HTTP request for the given method, resolving {@link QueryHttpMethod.Auto} by\n * preferring QUERY and falling back to GET when the server or network path does not support it.\n *\n * Explicit {@link QueryHttpMethod.Get} and {@link QueryHttpMethod.Query} are honored exactly, with no\n * fallback. For Auto, a transport-level failure — a `405`/`501` response, or a network/CORS error from\n * {@link fetch} — falls back to GET and pins the session to GET. Application-level errors (any other\n * status, returned as a normal {@link Response}) are never treated as a fallback signal.\n *\n * The method is resolved in order of precedence: an explicit per-query {@code override}, then\n * {@link Globals.queryHttpMethodResolver} (given the built GET URL), then {@link Globals.queryHttpMethod}.\n * @param override The explicit per-query {@link QueryHttpMethod}, or `undefined` to resolve from globals.\n * @param options The {@link BuildQueryHttpRequestOptions} describing the request.\n * @returns The {@link Response} from the request that was ultimately sent.\n */\nexport async function executeQueryHttpRequest(override: QueryHttpMethod | undefined, options: BuildQueryHttpRequestOptions): Promise<Response> {\n // The GET request is built up front when a resolver needs the URL, and reused if GET is chosen.\n let getRequest: { url: URL; init: RequestInit } | undefined;\n let method: QueryHttpMethod;\n if (override !== undefined) {\n method = override;\n } else if (Globals.queryHttpMethodResolver) {\n getRequest = buildQueryHttpRequest(QueryHttpMethod.Get, options);\n method = Globals.queryHttpMethodResolver({ url: getRequest.url, route: options.route, args: options.args });\n } else {\n method = Globals.queryHttpMethod;\n }\n\n const send = (httpMethod: QueryHttpMethod): Promise<Response> => {\n if (httpMethod === QueryHttpMethod.Get && getRequest) {\n return fetch(getRequest.url, getRequest.init);\n }\n const { url, init } = buildQueryHttpRequest(httpMethod, options);\n return fetch(url, init);\n };\n\n if (method !== QueryHttpMethod.Auto) {\n return send(method);\n }\n\n const key = backendKey(options);\n if (autoResolvedMethods.get(key) === QueryHttpMethod.Get) {\n return send(QueryHttpMethod.Get);\n }\n\n try {\n const response = await send(QueryHttpMethod.Query);\n if (isMethodUnsupported(response.status)) {\n autoResolvedMethods.set(key, QueryHttpMethod.Get);\n return send(QueryHttpMethod.Get);\n }\n autoResolvedMethods.set(key, QueryHttpMethod.Query);\n return response;\n } catch (error) {\n if (isAbortError(error)) {\n throw error;\n }\n autoResolvedMethods.set(key, QueryHttpMethod.Get);\n return send(QueryHttpMethod.Get);\n }\n}\n"],"names":["directionToString","sorting","direction","SortDirection","descending","buildQueryHttpRequest","method","options","route","apiBasePath","origin","args","parameterValues","paging","headers","signal","replacedRoute","unusedParameters","UrlHelpers","replaceRouteParameters","argumentValues","actualRoute","joinPaths","QueryHttpMethod","Query","url","createUrlFrom","payload","arguments","hasPaging","page","pageSize","hasSorting","field","requestHeaders","Headers","has","set","init","body","JSON","stringify","additionalParams","sortBy","sortDirection","queryParams","buildQueryParams","queryString","toString","includes","Get","autoResolvedMethods","Map","backendKey","resetQueryHttpMethodResolution","clear","isMethodUnsupported","status","executeQueryHttpRequest","override","getRequest","undefined","Globals","queryHttpMethodResolver","queryHttpMethod","send","httpMethod","fetch","Auto","key","get","response","error","isAbortError"],"mappings":"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"}
|
package/dist/esm/queries/for_QueryFor/when_performing/with_a_nullish_transport_rejection.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"with_a_nullish_transport_rejection.d.ts","sourceRoot":"","sources":["../../../../../queries/for_QueryFor/when_performing/with_a_nullish_transport_rejection.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { a_query_for } from '../given/a_query_for';
|
|
2
|
+
import { given } from '../../../given';
|
|
3
|
+
import { createFetchHelper } from '../../../helpers/fetchHelper';
|
|
4
|
+
describe('with a nullish transport rejection', given(a_query_for, context => {
|
|
5
|
+
let outcome;
|
|
6
|
+
let fetchStub;
|
|
7
|
+
let fetchHelper;
|
|
8
|
+
beforeEach(async () => {
|
|
9
|
+
fetchHelper = createFetchHelper();
|
|
10
|
+
fetchStub = fetchHelper.stubFetch();
|
|
11
|
+
fetchStub.callsFake(() => Promise.reject(undefined));
|
|
12
|
+
context.query.setOrigin('https://api.example.com');
|
|
13
|
+
outcome = await context.query.perform({ id: 'test-id' }).then(result => ({ resolved: true, result }), () => ({ resolved: false }));
|
|
14
|
+
});
|
|
15
|
+
afterEach(() => {
|
|
16
|
+
fetchHelper.restore();
|
|
17
|
+
});
|
|
18
|
+
it('should resolve rather than reject', () => outcome.resolved.should.be.true);
|
|
19
|
+
it('should report that it has exceptions', () => outcome.result.hasExceptions.should.be.true);
|
|
20
|
+
it('should describe the rejection it could not read a message from', () => outcome.result.exceptionMessages.should.deep.equal(['undefined']));
|
|
21
|
+
}));
|
|
22
|
+
//# sourceMappingURL=with_a_nullish_transport_rejection.js.map
|
package/dist/esm/queries/for_QueryFor/when_performing/with_a_nullish_transport_rejection.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"with_a_nullish_transport_rejection.js","sourceRoot":"","sources":["../../../../../queries/for_QueryFor/when_performing/with_a_nullish_transport_rejection.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAGvC,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAGjE,QAAQ,CAAC,oCAAoC,EAAE,KAAK,CAAC,WAAW,EAAE,OAAO,CAAC,EAAE;IACxE,IAAI,OAA4D,CAAC;IACjE,IAAI,SAA0B,CAAC;IAC/B,IAAI,WAAsE,CAAC;IAE3E,UAAU,CAAC,KAAK,IAAI,EAAE;QAClB,WAAW,GAAG,iBAAiB,EAAE,CAAC;QAClC,SAAS,GAAG,WAAW,CAAC,SAAS,EAAE,CAAC;QAIpC,SAAS,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;QAErD,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,yBAAyB,CAAC,CAAC;QAEnD,OAAO,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,IAAI,CACzD,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EACtC,GAAG,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACX,WAAW,CAAC,OAAO,EAAE,CAAC;IAC1B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;IAE/E,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,MAAO,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;IAE/F,EAAE,CAAC,gEAAgE,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,MAAO,CAAC,iBAAiB,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AACnJ,CAAC,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"with_an_aborted_request.d.ts","sourceRoot":"","sources":["../../../../../queries/for_QueryFor/when_performing/with_an_aborted_request.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { a_query_for } from '../given/a_query_for';
|
|
2
|
+
import { given } from '../../../given';
|
|
3
|
+
import { createFetchHelper } from '../../../helpers/fetchHelper';
|
|
4
|
+
describe('with an aborted request', given(a_query_for, context => {
|
|
5
|
+
let rejection;
|
|
6
|
+
let fetchStub;
|
|
7
|
+
let fetchHelper;
|
|
8
|
+
beforeEach(async () => {
|
|
9
|
+
fetchHelper = createFetchHelper();
|
|
10
|
+
fetchStub = fetchHelper.stubFetch();
|
|
11
|
+
fetchStub.rejects(Object.assign(new Error('The operation was aborted'), { name: 'AbortError' }));
|
|
12
|
+
context.query.setOrigin('https://api.example.com');
|
|
13
|
+
rejection = await context.query.perform({ id: 'test-id' }).then(() => undefined, error => error);
|
|
14
|
+
});
|
|
15
|
+
afterEach(() => {
|
|
16
|
+
fetchHelper.restore();
|
|
17
|
+
});
|
|
18
|
+
it('should reject so the superseded request cannot settle a result', () => (rejection !== undefined).should.be.true);
|
|
19
|
+
it('should reject with the abort error', () => rejection.name.should.equal('AbortError'));
|
|
20
|
+
}));
|
|
21
|
+
//# sourceMappingURL=with_an_aborted_request.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"with_an_aborted_request.js","sourceRoot":"","sources":["../../../../../queries/for_QueryFor/when_performing/with_an_aborted_request.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAGvC,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAEjE,QAAQ,CAAC,yBAAyB,EAAE,KAAK,CAAC,WAAW,EAAE,OAAO,CAAC,EAAE;IAC7D,IAAI,SAAkB,CAAC;IACvB,IAAI,SAA0B,CAAC;IAC/B,IAAI,WAAsE,CAAC;IAE3E,UAAU,CAAC,KAAK,IAAI,EAAE;QAClB,WAAW,GAAG,iBAAiB,EAAE,CAAC;QAClC,SAAS,GAAG,WAAW,CAAC,SAAS,EAAE,CAAC;QACpC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,2BAA2B,CAAC,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC;QAEjG,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,yBAAyB,CAAC,CAAC;QAInD,SAAS,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;IACrG,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACX,WAAW,CAAC,OAAO,EAAE,CAAC;IAC1B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gEAAgE,EAAE,GAAG,EAAE,CAAC,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;IAErH,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE,CAAE,SAAmB,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC;AACzG,CAAC,CAAC,CAAC,CAAC"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { a_query_for } from '../given/a_query_for';
|
|
2
2
|
import { given } from '../../../given';
|
|
3
3
|
import { createFetchHelper } from '../../../helpers/fetchHelper';
|
|
4
|
-
import { QueryResult } from '../../QueryResult';
|
|
5
4
|
describe('with fetch error', given(a_query_for, context => {
|
|
6
5
|
let result;
|
|
7
6
|
let fetchStub;
|
|
@@ -11,26 +10,16 @@ describe('with fetch error', given(a_query_for, context => {
|
|
|
11
10
|
fetchStub = fetchHelper.stubFetch();
|
|
12
11
|
fetchStub.rejects(new Error('Network error'));
|
|
13
12
|
context.query.setOrigin('https://api.example.com');
|
|
14
|
-
|
|
15
|
-
result = await context.query.perform({ id: 'test-id' });
|
|
16
|
-
}
|
|
17
|
-
catch {
|
|
18
|
-
const noSuccess = { ...QueryResult.noSuccess, data: context.query.defaultValue };
|
|
19
|
-
result = noSuccess;
|
|
20
|
-
}
|
|
13
|
+
result = await context.query.perform({ id: 'test-id' });
|
|
21
14
|
});
|
|
22
15
|
afterEach(() => {
|
|
23
16
|
fetchHelper.restore();
|
|
24
17
|
});
|
|
25
|
-
it('should
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
it('should
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
it('should return result without data', () => {
|
|
32
|
-
result.data.should.equal('');
|
|
33
|
-
result.isSuccess.should.be.false;
|
|
34
|
-
});
|
|
18
|
+
it('should resolve rather than reject', () => (result !== undefined).should.be.true);
|
|
19
|
+
it('should return an unsuccessful result', () => result.isSuccess.should.be.false);
|
|
20
|
+
it('should report that it has exceptions', () => result.hasExceptions.should.be.true);
|
|
21
|
+
it('should carry the transport error message', () => result.exceptionMessages.should.deep.equal(['Network error']));
|
|
22
|
+
it('should return the default value as data', () => result.data.should.equal(''));
|
|
23
|
+
it('should expose hasData as a boolean', () => (typeof result.hasData).should.equal('boolean'));
|
|
35
24
|
}));
|
|
36
25
|
//# sourceMappingURL=with_fetch_error.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"with_fetch_error.js","sourceRoot":"","sources":["../../../../../queries/for_QueryFor/when_performing/with_fetch_error.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAGvC,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"with_fetch_error.js","sourceRoot":"","sources":["../../../../../queries/for_QueryFor/when_performing/with_fetch_error.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAGvC,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAGjE,QAAQ,CAAC,kBAAkB,EAAE,KAAK,CAAC,WAAW,EAAE,OAAO,CAAC,EAAE;IACtD,IAAI,MAA2B,CAAC;IAChC,IAAI,SAA0B,CAAC;IAC/B,IAAI,WAAsE,CAAC;IAE3E,UAAU,CAAC,KAAK,IAAI,EAAE;QAClB,WAAW,GAAG,iBAAiB,EAAE,CAAC;QAClC,SAAS,GAAG,WAAW,CAAC,SAAS,EAAE,CAAC;QACpC,SAAS,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC;QAE9C,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,yBAAyB,CAAC,CAAC;QAEnD,MAAM,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACX,WAAW,CAAC,OAAO,EAAE,CAAC;IAC1B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;IAErF,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;IAEnF,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;IAEtF,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,iBAAiB,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;IAEpH,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;IAIlF,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE,CAAC,CAAC,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;AACpG,CAAC,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isAbortError.d.ts","sourceRoot":"","sources":["../../../queries/isAbortError.ts"],"names":[],"mappings":"AAYA,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAEpD"}
|