@owlmeans/api 0.1.18-rc.44 → 0.1.18-rc.46
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/README.md +2 -2
- package/agent-meta/manifest.json +2 -2
- package/agent-meta/skills/api/SKILL.md +1 -1
- package/build/index.d.ts +2 -1
- package/build/index.d.ts.map +1 -1
- package/build/service.d.ts +1 -6
- package/build/service.d.ts.map +1 -1
- package/build/service.js +2 -2
- package/build/service.js.map +1 -1
- package/build/status/consts.d.ts +5 -0
- package/build/status/consts.d.ts.map +1 -0
- package/build/status/consts.js +5 -0
- package/build/status/consts.js.map +1 -0
- package/build/status/consts.local.d.ts +10 -0
- package/build/status/consts.local.d.ts.map +1 -0
- package/build/status/consts.local.js +10 -0
- package/build/status/consts.local.js.map +1 -0
- package/build/status/index.d.ts +4 -7
- package/build/status/index.d.ts.map +1 -1
- package/build/status/index.js +3 -2
- package/build/status/index.js.map +1 -1
- package/build/status/marker.d.ts +1 -10
- package/build/status/marker.d.ts.map +1 -1
- package/build/status/marker.js +1 -12
- package/build/status/marker.js.map +1 -1
- package/build/status/types.d.ts +11 -0
- package/build/status/types.d.ts.map +1 -0
- package/build/status/types.js +2 -0
- package/build/status/types.js.map +1 -0
- package/build/types.local.d.ts +6 -0
- package/build/types.local.d.ts.map +1 -0
- package/build/types.local.js +2 -0
- package/build/types.local.js.map +1 -0
- package/build/utils/body.d.ts +18 -13
- package/build/utils/body.d.ts.map +1 -1
- package/build/utils/body.js +8 -6
- package/build/utils/body.js.map +1 -1
- package/build/utils/consts.d.ts +2 -0
- package/build/utils/consts.d.ts.map +1 -0
- package/build/utils/consts.js +2 -0
- package/build/utils/consts.js.map +1 -0
- package/build/utils/consts.local.d.ts +2 -0
- package/build/utils/consts.local.d.ts.map +1 -0
- package/build/utils/consts.local.js +2 -0
- package/build/utils/consts.local.js.map +1 -0
- package/build/utils/handler.d.ts +1 -1
- package/build/utils/handler.d.ts.map +1 -1
- package/build/utils/handler.js +8 -4
- package/build/utils/handler.js.map +1 -1
- package/build/utils/types.d.ts +11 -0
- package/build/utils/types.d.ts.map +1 -0
- package/build/utils/types.js +2 -0
- package/build/utils/types.js.map +1 -0
- package/package.json +14 -13
- package/src/index.ts +2 -1
- package/src/service.ts +4 -11
- package/src/status/consts.local.ts +11 -0
- package/src/status/consts.ts +5 -0
- package/src/status/index.ts +7 -10
- package/src/status/marker.ts +3 -21
- package/src/status/types.ts +11 -0
- package/src/types.local.ts +7 -0
- package/src/utils/body.ts +11 -17
- package/src/utils/consts.local.ts +1 -0
- package/src/utils/consts.ts +1 -0
- package/src/utils/handler.ts +11 -8
- package/src/utils/types.ts +12 -0
- package/tests/body.spec.ts +30 -31
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ HTTP API client service for OwlMeans client contexts — carries entrypoint call
|
|
|
12
12
|
## Installation
|
|
13
13
|
|
|
14
14
|
```bash
|
|
15
|
-
bun add @owlmeans/api@^0.1.18-rc.
|
|
15
|
+
bun add @owlmeans/api@^0.1.18-rc.46
|
|
16
16
|
```
|
|
17
17
|
|
|
18
18
|
## Usage
|
|
@@ -73,7 +73,7 @@ This package ships embedded agent skills under `agent-meta/`. After installing y
|
|
|
73
73
|
your project's skill store (`.agents/skills/`):
|
|
74
74
|
|
|
75
75
|
```sh
|
|
76
|
-
npx @owlmeans/agent-skills@^0.1.18-rc.
|
|
76
|
+
npx @owlmeans/agent-skills@^0.1.18-rc.48
|
|
77
77
|
```
|
|
78
78
|
|
|
79
79
|
The embedded files are version-matched to this package release. Do not edit them
|
package/agent-meta/manifest.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 2,
|
|
3
3
|
"package": "@owlmeans/api",
|
|
4
|
-
"version": "0.1.18-rc.
|
|
5
|
-
"generatedAt": "2026-10-
|
|
4
|
+
"version": "0.1.18-rc.46",
|
|
5
|
+
"generatedAt": "2026-10-05T08:32:19.139Z",
|
|
6
6
|
"canonicalRepo": "https://github.com/owlmeans/common",
|
|
7
7
|
"entries": [
|
|
8
8
|
{
|
package/build/index.d.ts
CHANGED
|
@@ -3,5 +3,6 @@ export * from './consts.js';
|
|
|
3
3
|
export * from './service.js';
|
|
4
4
|
export type * from './types.js';
|
|
5
5
|
export { httpStatusOf, incidentIdOf, isIncidentBody, parseClientMarker, API_CLIENT_MARKER, API_STATUS_MARKER, } from './status/index.js';
|
|
6
|
-
export type { ClientMarker
|
|
6
|
+
export type { ClientMarker } from './status/index.js';
|
|
7
|
+
export type { ResponseStatusCarrier } from './status/types.js';
|
|
7
8
|
//# sourceMappingURL=index.d.ts.map
|
package/build/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,cAAc,CAAA;AAC5B,mBAAmB,YAAY,CAAA;AAC/B,OAAO,EACL,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,iBAAiB,GACpG,MAAM,mBAAmB,CAAA;AAC1B,YAAY,EAAE,YAAY,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,cAAc,CAAA;AAC5B,mBAAmB,YAAY,CAAA;AAC/B,OAAO,EACL,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,iBAAiB,GACpG,MAAM,mBAAmB,CAAA;AAC1B,YAAY,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AACrD,YAAY,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAA"}
|
package/build/service.d.ts
CHANGED
|
@@ -1,10 +1,5 @@
|
|
|
1
|
-
import type { BasicContext } from '@owlmeans/context';
|
|
2
1
|
import type { ApiClient } from './types.js';
|
|
3
|
-
import {
|
|
4
|
-
type Config = BasicClientConfig;
|
|
5
|
-
interface Context<C extends Config = Config> extends BasicContext<C> {
|
|
6
|
-
}
|
|
2
|
+
import type { Config, Context } from './types.local.js';
|
|
7
3
|
export declare const createApiService: (alias?: string) => ApiClient;
|
|
8
4
|
export declare const appendApiClient: <C extends Config, T extends Context<C>>(ctx: T, alias?: string) => T;
|
|
9
|
-
export {};
|
|
10
5
|
//# sourceMappingURL=service.d.ts.map
|
package/build/service.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAQ3C,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AASvD,eAAO,MAAM,gBAAgB,WAAW,MAAM,KAAmB,SAsFhE,CAAA;AAED,eAAO,MAAM,eAAe,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,UAAS,MAAM,KAAmB,CAU/G,CAAA"}
|
package/build/service.js
CHANGED
|
@@ -2,10 +2,10 @@ import { assertContext, createService } from '@owlmeans/context';
|
|
|
2
2
|
import { extractParams } from '@owlmeans/client-route';
|
|
3
3
|
import axios from 'axios';
|
|
4
4
|
import { DEFAULT_ALIAS, UNAUTHORIZED_ERROR } from './consts.js';
|
|
5
|
-
import { requestBodyOf } from './utils/body.js';
|
|
6
5
|
import { processResponse } from './utils/handler.js';
|
|
7
6
|
import { makeSecurityHelper } from '@owlmeans/config';
|
|
8
7
|
import { AUTH_HEADER, DEF_AUTH_SRV, TOKEN_UPDATE } from '@owlmeans/auth-common';
|
|
8
|
+
import { bodyHelper } from './utils/body.js';
|
|
9
9
|
/** Whether a request carried an authentication header of its own. */
|
|
10
10
|
const presented = (headers) => headers != null && Object.entries(headers).some(([key, value]) => key.toLowerCase() === AUTH_HEADER && value != null && value !== '');
|
|
11
11
|
export const createApiService = (alias = DEFAULT_ALIAS) => {
|
|
@@ -32,7 +32,7 @@ export const createApiService = (alias = DEFAULT_ALIAS) => {
|
|
|
32
32
|
const url = helper.makeUrl(module.address(), path, { host: request.host, base: request.base, forceUnsecure: request.unsecure });
|
|
33
33
|
// A scalar JSON body (a string, a number, a boolean) is serialized here, so the server parses
|
|
34
34
|
// back the value the caller sent; objects and arrays are left to axios.
|
|
35
|
-
const body = requestBodyOf(request.body, request.headers, route.method, module.filter?.body);
|
|
35
|
+
const body = bodyHelper.requestBodyOf(request.body, request.headers, route.method, module.filter?.body);
|
|
36
36
|
const transformer = body.verbatim ? data => data : undefined;
|
|
37
37
|
const requestHeaders = body.contentType != null
|
|
38
38
|
? { ...request.headers, 'content-type': body.contentType }
|
package/build/service.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.js","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;
|
|
1
|
+
{"version":3,"file":"service.js","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** The prefix every `ApiClientError` message carries. */
|
|
2
|
+
export declare const API_CLIENT_MARKER = "api:client:";
|
|
3
|
+
/** The marker of an `ApiStatusError`: `api:client:status:<n>[:<incident id>]`. */
|
|
4
|
+
export declare const API_STATUS_MARKER = "api:client:status:";
|
|
5
|
+
//# sourceMappingURL=consts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consts.d.ts","sourceRoot":"","sources":["../../src/status/consts.ts"],"names":[],"mappings":"AAAA,yDAAyD;AACzD,eAAO,MAAM,iBAAiB,gBAAgB,CAAA;AAE9C,kFAAkF;AAClF,eAAO,MAAM,iBAAiB,uBAAgC,CAAA"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** The prefix every `ApiClientError` message carries. */
|
|
2
|
+
export const API_CLIENT_MARKER = 'api:client:';
|
|
3
|
+
/** The marker of an `ApiStatusError`: `api:client:status:<n>[:<incident id>]`. */
|
|
4
|
+
export const API_STATUS_MARKER = `${API_CLIENT_MARKER}status:`;
|
|
5
|
+
//# sourceMappingURL=consts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consts.js","sourceRoot":"","sources":["../../src/status/consts.ts"],"names":[],"mappings":"AAAA,yDAAyD;AACzD,MAAM,CAAC,MAAM,iBAAiB,GAAG,aAAa,CAAA;AAE9C,kFAAkF;AAClF,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAG,iBAAiB,SAAS,CAAA"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare const UUID: RegExp;
|
|
2
|
+
/**
|
|
3
|
+
* `crashed` / `auth` / `forbidden` / `status:<n>` / the legacy bare `<n>`, then an optional
|
|
4
|
+
* `:<incident id>`. The look-ahead refuses a match that runs on into more marker text, so a
|
|
5
|
+
* doubled prefix (a subclass constructor handed a whole marshaled message) resolves to the inner,
|
|
6
|
+
* complete marker.
|
|
7
|
+
*/
|
|
8
|
+
export declare const MARKER: RegExp;
|
|
9
|
+
export declare const NAMED_STATUS: Record<string, number>;
|
|
10
|
+
//# sourceMappingURL=consts.local.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consts.local.d.ts","sourceRoot":"","sources":["../../src/status/consts.local.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,IAAI,QAAoE,CAAA;AAErF;;;;;GAKG;AACH,eAAO,MAAM,MAAM,QAAmG,CAAA;AAEtH,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAA+C,CAAA"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
2
|
+
/**
|
|
3
|
+
* `crashed` / `auth` / `forbidden` / `status:<n>` / the legacy bare `<n>`, then an optional
|
|
4
|
+
* `:<incident id>`. The look-ahead refuses a match that runs on into more marker text, so a
|
|
5
|
+
* doubled prefix (a subclass constructor handed a whole marshaled message) resolves to the inner,
|
|
6
|
+
* complete marker.
|
|
7
|
+
*/
|
|
8
|
+
export const MARKER = /api:client:(?:(crashed|auth|forbidden)|status:(\d{3})|(\d{3}))(?::([\w.-]{1,128}))?(?![\w.:-])/;
|
|
9
|
+
export const NAMED_STATUS = { crashed: 500, auth: 401, forbidden: 403 };
|
|
10
|
+
//# sourceMappingURL=consts.local.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consts.local.js","sourceRoot":"","sources":["../../src/status/consts.local.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,IAAI,GAAG,iEAAiE,CAAA;AAErF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,gGAAgG,CAAA;AAEtH,MAAM,CAAC,MAAM,YAAY,GAA2B,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,CAAA"}
|
package/build/status/index.d.ts
CHANGED
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
export { INCIDENT_ID_HEADER } from '../consts.js';
|
|
2
2
|
export { DENIAL_KIND_HEADER, ACCESS_DENIED_KIND } from '../consts.js';
|
|
3
|
-
export {
|
|
4
|
-
export
|
|
5
|
-
|
|
6
|
-
export interface ResponseStatusCarrier {
|
|
7
|
-
responseStatus?: number;
|
|
8
|
-
denialKind?: string;
|
|
9
|
-
}
|
|
3
|
+
export { parseClientMarker } from './marker.js';
|
|
4
|
+
export { API_CLIENT_MARKER, API_STATUS_MARKER } from './consts.js';
|
|
5
|
+
export type { ClientMarker } from './types.js';
|
|
10
6
|
/** True only for a server-labelled auth/IAM refusal, never an unrelated 403. */
|
|
11
7
|
export declare const isAccessDenied: (error: unknown) => boolean;
|
|
12
8
|
/**
|
|
@@ -28,4 +24,5 @@ export declare const incidentIdOf: (error: unknown) => string | null;
|
|
|
28
24
|
* carries the `ResilientError` separator and is never one.
|
|
29
25
|
*/
|
|
30
26
|
export declare const isIncidentBody: (data: unknown) => data is string;
|
|
27
|
+
export type { ResponseStatusCarrier } from './types.js';
|
|
31
28
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/status/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AACjD,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/status/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AACjD,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AAIrE,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAC/C,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAClE,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAE9C,gFAAgF;AAChF,eAAO,MAAM,cAAc,UAAW,OAAO,KAAG,OAGuB,CAAA;AAavE;;;;;;;;;GASG;AACH,eAAO,MAAM,YAAY,UAAW,OAAO,KAAG,MAAM,GAAG,IAkBtD,CAAA;AAED,iGAAiG;AACjG,eAAO,MAAM,YAAY,UAAW,OAAO,KAAG,MAAM,GAAG,IAUtD,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,cAAc,SAAU,OAAO,KAAG,IAAI,IAAI,MACyC,CAAA;AAEhG,YAAY,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA"}
|
package/build/status/index.js
CHANGED
|
@@ -4,7 +4,9 @@ import { parseClientMarker } from './marker.js';
|
|
|
4
4
|
export { INCIDENT_ID_HEADER } from '../consts.js';
|
|
5
5
|
export { DENIAL_KIND_HEADER, ACCESS_DENIED_KIND } from '../consts.js';
|
|
6
6
|
import { ACCESS_DENIED_KIND } from '../consts.js';
|
|
7
|
-
|
|
7
|
+
import { UUID } from './consts.local.js';
|
|
8
|
+
export { parseClientMarker } from './marker.js';
|
|
9
|
+
export { API_CLIENT_MARKER, API_STATUS_MARKER } from './consts.js';
|
|
8
10
|
/** True only for a server-labelled auth/IAM refusal, never an unrelated 403. */
|
|
9
11
|
export const isAccessDenied = (error) => httpStatusOf(error) === 403
|
|
10
12
|
&& typeof error === 'object' && error != null
|
|
@@ -55,7 +57,6 @@ export const incidentIdOf = (error) => {
|
|
|
55
57
|
}
|
|
56
58
|
return markerOf(error)?.incidentId ?? null;
|
|
57
59
|
};
|
|
58
|
-
const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
59
60
|
/**
|
|
60
61
|
* Whether a response body is a production incident body — the bare incident UUID an
|
|
61
62
|
* `@owlmeans/server-api` boundary sends instead of the marshaled error. A development body
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/status/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAE/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AACjD,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AACrE,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AACjD,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/status/index.ts"],"names":[],"mappings":"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"}
|
package/build/status/marker.d.ts
CHANGED
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
export declare const API_CLIENT_MARKER = "api:client:";
|
|
3
|
-
/** The marker of an `ApiStatusError`: `api:client:status:<n>[:<incident id>]`. */
|
|
4
|
-
export declare const API_STATUS_MARKER = "api:client:status:";
|
|
5
|
-
/** What an `api:client:*` marker states. */
|
|
6
|
-
export interface ClientMarker {
|
|
7
|
-
status?: number;
|
|
8
|
-
incidentId?: string;
|
|
9
|
-
}
|
|
10
|
-
/** Read the first `api:client:*` marker in a text, or `null` when it carries none. */
|
|
1
|
+
import type { ClientMarker } from './types.js';
|
|
11
2
|
export declare const parseClientMarker: (text: string) => ClientMarker | null;
|
|
12
3
|
//# sourceMappingURL=marker.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"marker.d.ts","sourceRoot":"","sources":["../../src/status/marker.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"marker.d.ts","sourceRoot":"","sources":["../../src/status/marker.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAE9C,eAAO,MAAM,iBAAiB,SAAU,MAAM,KAAG,YAAY,GAAG,IAa/D,CAAA"}
|
package/build/status/marker.js
CHANGED
|
@@ -1,16 +1,5 @@
|
|
|
1
|
-
/** The prefix every `ApiClientError` message carries. */
|
|
2
|
-
export const API_CLIENT_MARKER = 'api:client:';
|
|
3
|
-
/** The marker of an `ApiStatusError`: `api:client:status:<n>[:<incident id>]`. */
|
|
4
|
-
export const API_STATUS_MARKER = `${API_CLIENT_MARKER}status:`;
|
|
5
|
-
/**
|
|
6
|
-
* `crashed` / `auth` / `forbidden` / `status:<n>` / the legacy bare `<n>`, then an optional
|
|
7
|
-
* `:<incident id>`. The look-ahead refuses a match that runs on into more marker text, so a
|
|
8
|
-
* doubled prefix (a subclass constructor handed a whole marshaled message) resolves to the inner,
|
|
9
|
-
* complete marker.
|
|
10
|
-
*/
|
|
11
|
-
const MARKER = /api:client:(?:(crashed|auth|forbidden)|status:(\d{3})|(\d{3}))(?::([\w.-]{1,128}))?(?![\w.:-])/;
|
|
12
|
-
const NAMED_STATUS = { crashed: 500, auth: 401, forbidden: 403 };
|
|
13
1
|
/** Read the first `api:client:*` marker in a text, or `null` when it carries none. */
|
|
2
|
+
import { MARKER, NAMED_STATUS } from './consts.local.js';
|
|
14
3
|
export const parseClientMarker = (text) => {
|
|
15
4
|
const match = MARKER.exec(text);
|
|
16
5
|
if (match == null) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"marker.js","sourceRoot":"","sources":["../../src/status/marker.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"marker.js","sourceRoot":"","sources":["../../src/status/marker.ts"],"names":[],"mappings":"AACA,sFAAsF;AACtF,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAGxD,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,IAAY,EAAuB,EAAE;IACrE,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAC/B,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;QAClB,OAAO,IAAI,CAAA;IACb,CAAC;IACD,MAAM,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC,GAAG,KAAK,CAAA;IAC1C,MAAM,IAAI,GAAG,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,CAAA;IAE1E,OAAO;QACL,MAAM,EAAE,IAAI,IAAI,GAAG,IAAI,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;QACrD,0EAA0E;QAC1E,UAAU,EAAE,EAAE,IAAI,IAAI,IAAI,EAAE,KAAK,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS;KAC1D,CAAA;AACH,CAAC,CAAA"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** The HTTP status the API client stamps on an error it rebuilt from a response body. */
|
|
2
|
+
export interface ResponseStatusCarrier {
|
|
3
|
+
responseStatus?: number;
|
|
4
|
+
denialKind?: string;
|
|
5
|
+
}
|
|
6
|
+
/** What an `api:client:*` marker states. */
|
|
7
|
+
export interface ClientMarker {
|
|
8
|
+
status?: number;
|
|
9
|
+
incidentId?: string;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/status/types.ts"],"names":[],"mappings":"AAAA,yFAAyF;AACzF,MAAM,WAAW,qBAAqB;IACpC,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,4CAA4C;AAC5C,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/status/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { BasicClientConfig } from '@owlmeans/client-config';
|
|
2
|
+
import type { BasicContext } from '@owlmeans/context';
|
|
3
|
+
export type Config = BasicClientConfig;
|
|
4
|
+
export interface Context<C extends Config = Config> extends BasicContext<C> {
|
|
5
|
+
}
|
|
6
|
+
//# sourceMappingURL=types.local.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.local.d.ts","sourceRoot":"","sources":["../src/types.local.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAErD,MAAM,MAAM,MAAM,GAAG,iBAAiB,CAAA;AAEtC,MAAM,WAAW,OAAO,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,CAAE,SAAQ,YAAY,CAAC,CAAC,CAAC;CAC1E"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.local.js","sourceRoot":"","sources":["../src/types.local.ts"],"names":[],"mappings":""}
|
package/build/utils/body.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { RouteMethod } from '@owlmeans/route';
|
|
2
|
-
|
|
2
|
+
import type { RequestBody } from './types.js';
|
|
3
3
|
/** The request's own `content-type`, whatever case its key is written in. */
|
|
4
|
-
|
|
4
|
+
declare const contentTypeOf: (headers?: Record<string, unknown>) => string | undefined;
|
|
5
5
|
/** `application/json` or a `+json` suffix type, with or without parameters. */
|
|
6
|
-
|
|
6
|
+
declare const isJsonContentType: (type?: string) => boolean;
|
|
7
7
|
/**
|
|
8
8
|
* The JSON text a scalar body travels as, so the server parses it back to the same value.
|
|
9
9
|
*
|
|
@@ -12,15 +12,7 @@ export declare const isJsonContentType: (type?: string) => boolean;
|
|
|
12
12
|
* itself) — except under a body schema of `type: 'string'`, where only a JSON string literal
|
|
13
13
|
* counts as serialized and `123`, `true` or `{…}` are the text the caller means.
|
|
14
14
|
*/
|
|
15
|
-
|
|
16
|
-
export interface RequestBody {
|
|
17
|
-
/** What axios is handed as `data`. */
|
|
18
|
-
data: unknown;
|
|
19
|
-
/** A `content-type` the request lacked and must carry. */
|
|
20
|
-
contentType?: string;
|
|
21
|
-
/** `data` is final text — axios must not transform it again. */
|
|
22
|
-
verbatim: boolean;
|
|
23
|
-
}
|
|
15
|
+
declare const jsonScalarBody: (body: string | number | boolean, schema?: object) => string;
|
|
24
16
|
/**
|
|
25
17
|
* What a request's body becomes on the wire.
|
|
26
18
|
*
|
|
@@ -30,5 +22,18 @@ export interface RequestBody {
|
|
|
30
22
|
* - Anything else — objects, arrays, a scalar under another content type — goes to axios as it is,
|
|
31
23
|
* which serializes an object or an array as JSON.
|
|
32
24
|
*/
|
|
33
|
-
|
|
25
|
+
declare const requestBodyOf: (body: unknown, headers: Record<string, unknown> | undefined, method?: RouteMethod, schema?: object) => RequestBody;
|
|
26
|
+
export declare const createBodyHelper: () => {
|
|
27
|
+
contentTypeOf: typeof contentTypeOf;
|
|
28
|
+
isJsonContentType: typeof isJsonContentType;
|
|
29
|
+
jsonScalarBody: typeof jsonScalarBody;
|
|
30
|
+
requestBodyOf: typeof requestBodyOf;
|
|
31
|
+
};
|
|
32
|
+
export declare const bodyHelper: {
|
|
33
|
+
contentTypeOf: typeof contentTypeOf;
|
|
34
|
+
isJsonContentType: typeof isJsonContentType;
|
|
35
|
+
jsonScalarBody: typeof jsonScalarBody;
|
|
36
|
+
requestBodyOf: typeof requestBodyOf;
|
|
37
|
+
};
|
|
38
|
+
export {};
|
|
34
39
|
//# sourceMappingURL=body.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"body.d.ts","sourceRoot":"","sources":["../../src/utils/body.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;
|
|
1
|
+
{"version":3,"file":"body.d.ts","sourceRoot":"","sources":["../../src/utils/body.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAG7C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAE7C,6EAA6E;AAC7E,QAAA,MAAM,aAAa,aAAc,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,MAAM,GAAG,SAMnE,CAAA;AAED,+EAA+E;AAC/E,QAAA,MAAM,iBAAiB,UAAW,MAAM,KAAG,OACsC,CAAA;AAoBjF;;;;;;;GAOG;AACH,QAAA,MAAM,cAAc,SAAU,MAAM,GAAG,MAAM,GAAG,OAAO,WAAW,MAAM,KAAG,MAQ1E,CAAA;AAED;;;;;;;;GAQG;AACH,QAAA,MAAM,aAAa,SACX,OAAO,WAAW,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,WAAW,WAAW,WAAW,MAAM,KACjG,WAgBF,CAAA;AAED,eAAO,MAAM,gBAAgB;;;;;CAA8E,CAAA;AAE3G,eAAO,MAAM,UAAU;;;;;CAAqB,CAAA"}
|
package/build/utils/body.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import qs from 'qs';
|
|
2
2
|
import { RouteMethod } from '@owlmeans/route';
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
import { FORM_CONTENT_TYPE } from './consts.local.js';
|
|
4
|
+
import { JSON_CONTENT_TYPE } from './consts.js';
|
|
5
5
|
/** The request's own `content-type`, whatever case its key is written in. */
|
|
6
|
-
|
|
6
|
+
const contentTypeOf = (headers) => {
|
|
7
7
|
const value = Object.entries(headers ?? {}).find(([key]) => key.toLowerCase() === 'content-type')?.[1];
|
|
8
8
|
if (value == null || value === '') {
|
|
9
9
|
return undefined;
|
|
@@ -11,7 +11,7 @@ export const contentTypeOf = (headers) => {
|
|
|
11
11
|
return Array.isArray(value) ? value.join(', ') : `${value}`;
|
|
12
12
|
};
|
|
13
13
|
/** `application/json` or a `+json` suffix type, with or without parameters. */
|
|
14
|
-
|
|
14
|
+
const isJsonContentType = (type) => type != null && /^application\/(?:[^\s;]+\+)?json\s*(?:;|$)/i.test(type.trim());
|
|
15
15
|
/** A JSON value no serializer quotes for us: a string, a number or a boolean. */
|
|
16
16
|
const isScalar = (value) => typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean';
|
|
17
17
|
/** Does the entrypoint's body schema declare a string? */
|
|
@@ -35,7 +35,7 @@ const parse = (text) => {
|
|
|
35
35
|
* itself) — except under a body schema of `type: 'string'`, where only a JSON string literal
|
|
36
36
|
* counts as serialized and `123`, `true` or `{…}` are the text the caller means.
|
|
37
37
|
*/
|
|
38
|
-
|
|
38
|
+
const jsonScalarBody = (body, schema) => {
|
|
39
39
|
if (typeof body !== 'string') {
|
|
40
40
|
return JSON.stringify(body);
|
|
41
41
|
}
|
|
@@ -52,7 +52,7 @@ export const jsonScalarBody = (body, schema) => {
|
|
|
52
52
|
* - Anything else — objects, arrays, a scalar under another content type — goes to axios as it is,
|
|
53
53
|
* which serializes an object or an array as JSON.
|
|
54
54
|
*/
|
|
55
|
-
|
|
55
|
+
const requestBodyOf = (body, headers, method, schema) => {
|
|
56
56
|
const type = contentTypeOf(headers);
|
|
57
57
|
if (body != null && type?.includes(FORM_CONTENT_TYPE) === true) {
|
|
58
58
|
return { data: qs.stringify(body), verbatim: false };
|
|
@@ -68,4 +68,6 @@ export const requestBodyOf = (body, headers, method, schema) => {
|
|
|
68
68
|
}
|
|
69
69
|
return { data: body, verbatim: false };
|
|
70
70
|
};
|
|
71
|
+
export const createBodyHelper = () => ({ contentTypeOf, isJsonContentType, jsonScalarBody, requestBodyOf });
|
|
72
|
+
export const bodyHelper = createBodyHelper();
|
|
71
73
|
//# sourceMappingURL=body.js.map
|
package/build/utils/body.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"body.js","sourceRoot":"","sources":["../../src/utils/body.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAA;AACnB,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;
|
|
1
|
+
{"version":3,"file":"body.js","sourceRoot":"","sources":["../../src/utils/body.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAA;AACnB,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAG/C,6EAA6E;AAC7E,MAAM,aAAa,GAAG,CAAC,OAAiC,EAAsB,EAAE;IAC9E,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,WAAW,EAAE,KAAK,cAAc,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;IACtG,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;QAClC,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,EAAE,CAAA;AAC7D,CAAC,CAAA;AAED,+EAA+E;AAC/E,MAAM,iBAAiB,GAAG,CAAC,IAAa,EAAW,EAAE,CACnD,IAAI,IAAI,IAAI,IAAI,6CAA6C,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAA;AAEjF,iFAAiF;AACjF,MAAM,QAAQ,GAAG,CAAC,KAAc,EAAsC,EAAE,CACtE,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,SAAS,CAAA;AAEtF,0DAA0D;AAC1D,MAAM,cAAc,GAAG,CAAC,MAAe,EAAW,EAAE;IAClD,MAAM,IAAI,GAAI,MAAyC,EAAE,IAAI,CAAA;IAC7D,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;AACjE,CAAC,CAAA;AAED,MAAM,KAAK,GAAG,CAAC,IAAY,EAAoD,EAAE;IAC/E,IAAI,CAAC;QACH,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAA;IAChD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAA;IACxB,CAAC;AACH,CAAC,CAAA;AAED;;;;;;;GAOG;AACH,MAAM,cAAc,GAAG,CAAC,IAA+B,EAAE,MAAe,EAAU,EAAE;IAClF,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;IAC7B,CAAC;IACD,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,CAAA;IAC1B,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,IAAI,OAAO,MAAM,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAA;IAE/F,OAAO,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;AACjD,CAAC,CAAA;AAED;;;;;;;;GAQG;AACH,MAAM,aAAa,GAAG,CACpB,IAAa,EAAE,OAA4C,EAAE,MAAoB,EAAE,MAAe,EACrF,EAAE;IACf,MAAM,IAAI,GAAG,aAAa,CAAC,OAAO,CAAC,CAAA;IACnC,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,EAAE,QAAQ,CAAC,iBAAiB,CAAC,KAAK,IAAI,EAAE,CAAC;QAC/D,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAA;IACtD,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACpB,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAA;IACxC,CAAC;IACD,IAAI,IAAI,IAAI,IAAI,IAAI,MAAM,KAAK,WAAW,CAAC,IAAI,EAAE,CAAC;QAChD,OAAO,EAAE,IAAI,EAAE,cAAc,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,WAAW,EAAE,iBAAiB,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAA;IAC/F,CAAC;IACD,IAAI,iBAAiB,CAAC,IAAI,CAAC,EAAE,CAAC;QAC5B,OAAO,EAAE,IAAI,EAAE,cAAc,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAA;IAC/D,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAA;AACxC,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,EAAE,CAAC,CAAC,EAAE,aAAa,EAAE,iBAAiB,EAAE,cAAc,EAAE,aAAa,EAAE,CAAC,CAAA;AAE3G,MAAM,CAAC,MAAM,UAAU,GAAG,gBAAgB,EAAE,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consts.d.ts","sourceRoot":"","sources":["../../src/utils/consts.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,iBAAiB,qBAAqB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consts.js","sourceRoot":"","sources":["../../src/utils/consts.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,iBAAiB,GAAG,kBAAkB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consts.local.d.ts","sourceRoot":"","sources":["../../src/utils/consts.local.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,iBAAiB,sCAAsC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consts.local.js","sourceRoot":"","sources":["../../src/utils/consts.local.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,iBAAiB,GAAG,mCAAmC,CAAA"}
|
package/build/utils/handler.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type AbstractResponse } from '@owlmeans/entrypoint';
|
|
2
2
|
import type { AxiosResponse } from 'axios';
|
|
3
3
|
import { ApiClientError } from '../errors.js';
|
|
4
4
|
export declare const processResponse: (response: AxiosResponse, reply: AbstractResponse<any>) => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/utils/handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/utils/handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,gBAAgB,EAAqB,MAAM,sBAAsB,CAAA;AAC/E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;AAM1C,OAAO,EAAE,cAAc,EAAuD,MAAM,cAAc,CAAA;AAOlG,eAAO,MAAM,eAAe,aAAc,aAAa,SAAS,gBAAgB,CAAC,GAAG,CAAC,SAqBpF,CAAA;AAkCD;;;;GAIG;AACH,eAAO,MAAM,WAAW,WAAY,MAAM,eAAe,MAAM,KAAG,cAUjE,CAAA"}
|
package/build/utils/handler.js
CHANGED
|
@@ -3,6 +3,8 @@ import { ACCEPTED, CREATED, FINISHED, FORBIDDEN_ERROR, INCIDENT_ID_HEADER, DENIA
|
|
|
3
3
|
import { ResilientError } from '@owlmeans/error';
|
|
4
4
|
import { ApiClientError, ApiStatusError, ServerAuthError, ServerCrashedError } from '../errors.js';
|
|
5
5
|
import { isIncidentBody } from '../status/index.js';
|
|
6
|
+
import { logger } from '@owlmeans/log';
|
|
7
|
+
const log = logger('api');
|
|
6
8
|
export const processResponse = (response, reply) => {
|
|
7
9
|
switch (response.status) {
|
|
8
10
|
case OK:
|
|
@@ -16,9 +18,11 @@ export const processResponse = (response, reply) => {
|
|
|
16
18
|
case FINISHED:
|
|
17
19
|
return processEmptyResponse(response, reply, EntrypointOutcome.Finished);
|
|
18
20
|
default:
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
// A refusal is ordinary traffic (401, 403, 409, 428): debug, and never the headers.
|
|
22
|
+
log.debug('Request answered with a failure', {
|
|
23
|
+
status: response.status, statusText: response.statusText, url: response.config?.url,
|
|
24
|
+
incidentId: headerOf(response.headers, INCIDENT_ID_HEADER),
|
|
25
|
+
});
|
|
22
26
|
reply.reject(failureOf(response));
|
|
23
27
|
}
|
|
24
28
|
};
|
|
@@ -46,7 +50,7 @@ const failureOf = (response) => {
|
|
|
46
50
|
return error;
|
|
47
51
|
}
|
|
48
52
|
catch {
|
|
49
|
-
|
|
53
|
+
log.warn('Server returned an unrecognizable text error', { status: response.status, body: response.data });
|
|
50
54
|
}
|
|
51
55
|
}
|
|
52
56
|
return Object.assign(statusError(response.status, incidentId), { denialKind });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handler.js","sourceRoot":"","sources":["../../src/utils/handler.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"handler.js","sourceRoot":"","sources":["../../src/utils/handler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { createBodyHelper } from './body.js';
|
|
2
|
+
export interface RequestBody {
|
|
3
|
+
/** What axios is handed as `data`. */
|
|
4
|
+
data: unknown;
|
|
5
|
+
/** A `content-type` the request lacked and must carry. */
|
|
6
|
+
contentType?: string;
|
|
7
|
+
/** `data` is final text — axios must not transform it again. */
|
|
8
|
+
verbatim: boolean;
|
|
9
|
+
}
|
|
10
|
+
export type BodyHelper = ReturnType<typeof createBodyHelper>;
|
|
11
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/utils/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAA;AAEjD,MAAM,WAAW,WAAW;IAC1B,sCAAsC;IACtC,IAAI,EAAE,OAAO,CAAA;IACb,0DAA0D;IAC1D,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,gEAAgE;IAChE,QAAQ,EAAE,OAAO,CAAA;CAClB;AAED,MAAM,MAAM,UAAU,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/utils/types.ts"],"names":[],"mappings":""}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@owlmeans/api",
|
|
3
|
-
"version": "0.1.18-rc.
|
|
3
|
+
"version": "0.1.18-rc.46",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -29,21 +29,22 @@
|
|
|
29
29
|
}
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@owlmeans/auth-common": "^0.1.18-rc.
|
|
33
|
-
"@owlmeans/client-config": "^0.1.18-rc.
|
|
34
|
-
"@owlmeans/client-route": "^0.1.18-rc.
|
|
35
|
-
"@owlmeans/config": "^0.1.18-rc.
|
|
36
|
-
"@owlmeans/context": "^0.1.18-rc.
|
|
37
|
-
"@owlmeans/
|
|
38
|
-
"@owlmeans/
|
|
39
|
-
"@owlmeans/
|
|
40
|
-
"
|
|
41
|
-
"
|
|
32
|
+
"@owlmeans/auth-common": "^0.1.18-rc.46",
|
|
33
|
+
"@owlmeans/client-config": "^0.1.18-rc.43",
|
|
34
|
+
"@owlmeans/client-route": "^0.1.18-rc.47",
|
|
35
|
+
"@owlmeans/config": "^0.1.18-rc.43",
|
|
36
|
+
"@owlmeans/context": "^0.1.18-rc.33",
|
|
37
|
+
"@owlmeans/entrypoint": "^0.1.18-rc.40",
|
|
38
|
+
"@owlmeans/error": "^0.1.18-rc.37",
|
|
39
|
+
"@owlmeans/log": "^0.1.18-rc.1",
|
|
40
|
+
"@owlmeans/route": "^0.1.18-rc.34",
|
|
41
|
+
"axios": "^1.20.0",
|
|
42
|
+
"qs": "^6.16.0"
|
|
42
43
|
},
|
|
43
44
|
"devDependencies": {
|
|
44
45
|
"@owlmeans/dep-config": "workspace:*",
|
|
45
|
-
"@owlmeans/resource": "^0.1.18-rc.
|
|
46
|
-
"@types/qs": "^6.
|
|
46
|
+
"@owlmeans/resource": "^0.1.18-rc.39",
|
|
47
|
+
"@types/qs": "^6.15.1",
|
|
47
48
|
"nodemon": "^3.1.14",
|
|
48
49
|
"typescript": "^7.0.2"
|
|
49
50
|
},
|
package/src/index.ts
CHANGED
|
@@ -5,4 +5,5 @@ export type * from './types.js'
|
|
|
5
5
|
export {
|
|
6
6
|
httpStatusOf, incidentIdOf, isIncidentBody, parseClientMarker, API_CLIENT_MARKER, API_STATUS_MARKER,
|
|
7
7
|
} from './status/index.js'
|
|
8
|
-
export type { ClientMarker
|
|
8
|
+
export type { ClientMarker } from './status/index.js'
|
|
9
|
+
export type { ResponseStatusCarrier } from './status/types.js'
|
package/src/service.ts
CHANGED
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
import { assertContext, createService } from '@owlmeans/context'
|
|
2
|
-
import type { BasicContext } from '@owlmeans/context'
|
|
3
2
|
import { extractParams } from '@owlmeans/client-route'
|
|
4
3
|
import type { ApiClient } from './types.js'
|
|
5
4
|
import axios, { AxiosHeaders } from 'axios'
|
|
6
5
|
import type { AxiosRequestTransformer } from 'axios'
|
|
7
6
|
import type { CommonEntrypoint } from '@owlmeans/entrypoint'
|
|
8
7
|
import { DEFAULT_ALIAS, UNAUTHORIZED_ERROR } from './consts.js'
|
|
9
|
-
import { requestBodyOf } from './utils/body.js'
|
|
10
8
|
import { processResponse } from './utils/handler.js'
|
|
11
|
-
import { BasicClientConfig } from '@owlmeans/client-config'
|
|
12
9
|
import { makeSecurityHelper } from '@owlmeans/config'
|
|
13
|
-
import { AUTH_HEADER, DEF_AUTH_SRV, TOKEN_UPDATE } from '@owlmeans/auth-common'
|
|
14
|
-
import type {
|
|
10
|
+
import { AUTH_HEADER, DEF_AUTH_SRV, TOKEN_UPDATE, type AuthService } from '@owlmeans/auth-common'
|
|
11
|
+
import type { Config, Context } from './types.local.js'
|
|
12
|
+
import { bodyHelper } from './utils/body.js'
|
|
15
13
|
|
|
16
14
|
/** Whether a request carried an authentication header of its own. */
|
|
17
15
|
const presented = (headers?: Record<string, unknown>): boolean =>
|
|
@@ -19,11 +17,6 @@ const presented = (headers?: Record<string, unknown>): boolean =>
|
|
|
19
17
|
([key, value]) => key.toLowerCase() === AUTH_HEADER && value != null && value !== ''
|
|
20
18
|
)
|
|
21
19
|
|
|
22
|
-
type Config = BasicClientConfig
|
|
23
|
-
|
|
24
|
-
interface Context<C extends Config = Config> extends BasicContext<C> {
|
|
25
|
-
}
|
|
26
|
-
|
|
27
20
|
export const createApiService = (alias: string = DEFAULT_ALIAS): ApiClient => {
|
|
28
21
|
const location = `api.service:${alias}`
|
|
29
22
|
const client: ApiClient = createService<ApiClient>(alias, {
|
|
@@ -55,7 +48,7 @@ export const createApiService = (alias: string = DEFAULT_ALIAS): ApiClient => {
|
|
|
55
48
|
|
|
56
49
|
// A scalar JSON body (a string, a number, a boolean) is serialized here, so the server parses
|
|
57
50
|
// back the value the caller sent; objects and arrays are left to axios.
|
|
58
|
-
const body = requestBodyOf(request.body, request.headers, route.method, module.filter?.body)
|
|
51
|
+
const body = bodyHelper.requestBodyOf(request.body, request.headers, route.method, module.filter?.body)
|
|
59
52
|
const transformer: AxiosRequestTransformer | undefined = body.verbatim ? data => data : undefined
|
|
60
53
|
const requestHeaders = body.contentType != null
|
|
61
54
|
? { ...request.headers, 'content-type': body.contentType }
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* `crashed` / `auth` / `forbidden` / `status:<n>` / the legacy bare `<n>`, then an optional
|
|
5
|
+
* `:<incident id>`. The look-ahead refuses a match that runs on into more marker text, so a
|
|
6
|
+
* doubled prefix (a subclass constructor handed a whole marshaled message) resolves to the inner,
|
|
7
|
+
* complete marker.
|
|
8
|
+
*/
|
|
9
|
+
export const MARKER = /api:client:(?:(crashed|auth|forbidden)|status:(\d{3})|(\d{3}))(?::([\w.-]{1,128}))?(?![\w.:-])/
|
|
10
|
+
|
|
11
|
+
export const NAMED_STATUS: Record<string, number> = { crashed: 500, auth: 401, forbidden: 403 }
|
package/src/status/index.ts
CHANGED
|
@@ -5,14 +5,11 @@ import { parseClientMarker } from './marker.js'
|
|
|
5
5
|
export { INCIDENT_ID_HEADER } from '../consts.js'
|
|
6
6
|
export { DENIAL_KIND_HEADER, ACCESS_DENIED_KIND } from '../consts.js'
|
|
7
7
|
import { ACCESS_DENIED_KIND } from '../consts.js'
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
export
|
|
13
|
-
responseStatus?: number
|
|
14
|
-
denialKind?: string
|
|
15
|
-
}
|
|
8
|
+
import { UUID } from './consts.local.js'
|
|
9
|
+
import type { ResponseStatusCarrier } from './types.js'
|
|
10
|
+
export { parseClientMarker } from './marker.js'
|
|
11
|
+
export { API_CLIENT_MARKER, API_STATUS_MARKER } from './consts.js'
|
|
12
|
+
export type { ClientMarker } from './types.js'
|
|
16
13
|
|
|
17
14
|
/** True only for a server-labelled auth/IAM refusal, never an unrelated 403. */
|
|
18
15
|
export const isAccessDenied = (error: unknown): boolean =>
|
|
@@ -74,8 +71,6 @@ export const incidentIdOf = (error: unknown): string | null => {
|
|
|
74
71
|
return markerOf(error)?.incidentId ?? null
|
|
75
72
|
}
|
|
76
73
|
|
|
77
|
-
const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i
|
|
78
|
-
|
|
79
74
|
/**
|
|
80
75
|
* Whether a response body is a production incident body — the bare incident UUID an
|
|
81
76
|
* `@owlmeans/server-api` boundary sends instead of the marshaled error. A development body
|
|
@@ -83,3 +78,5 @@ const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i
|
|
|
83
78
|
*/
|
|
84
79
|
export const isIncidentBody = (data: unknown): data is string =>
|
|
85
80
|
typeof data === 'string' && !data.includes(ResilientError.separator) && UUID.test(data.trim())
|
|
81
|
+
|
|
82
|
+
export type { ResponseStatusCarrier } from './types.js'
|
package/src/status/marker.ts
CHANGED
|
@@ -1,26 +1,8 @@
|
|
|
1
|
-
/** The prefix every `ApiClientError` message carries. */
|
|
2
|
-
export const API_CLIENT_MARKER = 'api:client:'
|
|
3
|
-
|
|
4
|
-
/** The marker of an `ApiStatusError`: `api:client:status:<n>[:<incident id>]`. */
|
|
5
|
-
export const API_STATUS_MARKER = `${API_CLIENT_MARKER}status:`
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* `crashed` / `auth` / `forbidden` / `status:<n>` / the legacy bare `<n>`, then an optional
|
|
9
|
-
* `:<incident id>`. The look-ahead refuses a match that runs on into more marker text, so a
|
|
10
|
-
* doubled prefix (a subclass constructor handed a whole marshaled message) resolves to the inner,
|
|
11
|
-
* complete marker.
|
|
12
|
-
*/
|
|
13
|
-
const MARKER = /api:client:(?:(crashed|auth|forbidden)|status:(\d{3})|(\d{3}))(?::([\w.-]{1,128}))?(?![\w.:-])/
|
|
14
|
-
|
|
15
|
-
const NAMED_STATUS: Record<string, number> = { crashed: 500, auth: 401, forbidden: 403 }
|
|
16
|
-
|
|
17
|
-
/** What an `api:client:*` marker states. */
|
|
18
|
-
export interface ClientMarker {
|
|
19
|
-
status?: number
|
|
20
|
-
incidentId?: string
|
|
21
|
-
}
|
|
22
1
|
|
|
23
2
|
/** Read the first `api:client:*` marker in a text, or `null` when it carries none. */
|
|
3
|
+
import { MARKER, NAMED_STATUS } from './consts.local.js'
|
|
4
|
+
import type { ClientMarker } from './types.js'
|
|
5
|
+
|
|
24
6
|
export const parseClientMarker = (text: string): ClientMarker | null => {
|
|
25
7
|
const match = MARKER.exec(text)
|
|
26
8
|
if (match == null) {
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** The HTTP status the API client stamps on an error it rebuilt from a response body. */
|
|
2
|
+
export interface ResponseStatusCarrier {
|
|
3
|
+
responseStatus?: number
|
|
4
|
+
denialKind?: string
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
/** What an `api:client:*` marker states. */
|
|
8
|
+
export interface ClientMarker {
|
|
9
|
+
status?: number
|
|
10
|
+
incidentId?: string
|
|
11
|
+
}
|
package/src/utils/body.ts
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import qs from 'qs'
|
|
2
2
|
import { RouteMethod } from '@owlmeans/route'
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const FORM_CONTENT_TYPE = 'application/x-www-form-urlencoded'
|
|
3
|
+
import { FORM_CONTENT_TYPE } from './consts.local.js'
|
|
4
|
+
import { JSON_CONTENT_TYPE } from './consts.js'
|
|
5
|
+
import type { RequestBody } from './types.js'
|
|
7
6
|
|
|
8
7
|
/** The request's own `content-type`, whatever case its key is written in. */
|
|
9
|
-
|
|
8
|
+
const contentTypeOf = (headers?: Record<string, unknown>): string | undefined => {
|
|
10
9
|
const value = Object.entries(headers ?? {}).find(([key]) => key.toLowerCase() === 'content-type')?.[1]
|
|
11
10
|
if (value == null || value === '') {
|
|
12
11
|
return undefined
|
|
@@ -15,7 +14,7 @@ export const contentTypeOf = (headers?: Record<string, unknown>): string | undef
|
|
|
15
14
|
}
|
|
16
15
|
|
|
17
16
|
/** `application/json` or a `+json` suffix type, with or without parameters. */
|
|
18
|
-
|
|
17
|
+
const isJsonContentType = (type?: string): boolean =>
|
|
19
18
|
type != null && /^application\/(?:[^\s;]+\+)?json\s*(?:;|$)/i.test(type.trim())
|
|
20
19
|
|
|
21
20
|
/** A JSON value no serializer quotes for us: a string, a number or a boolean. */
|
|
@@ -44,7 +43,7 @@ const parse = (text: string): { json: true, value: unknown } | { json: false } =
|
|
|
44
43
|
* itself) — except under a body schema of `type: 'string'`, where only a JSON string literal
|
|
45
44
|
* counts as serialized and `123`, `true` or `{…}` are the text the caller means.
|
|
46
45
|
*/
|
|
47
|
-
|
|
46
|
+
const jsonScalarBody = (body: string | number | boolean, schema?: object): string => {
|
|
48
47
|
if (typeof body !== 'string') {
|
|
49
48
|
return JSON.stringify(body)
|
|
50
49
|
}
|
|
@@ -54,15 +53,6 @@ export const jsonScalarBody = (body: string | number | boolean, schema?: object)
|
|
|
54
53
|
return serialized ? body : JSON.stringify(body)
|
|
55
54
|
}
|
|
56
55
|
|
|
57
|
-
export interface RequestBody {
|
|
58
|
-
/** What axios is handed as `data`. */
|
|
59
|
-
data: unknown
|
|
60
|
-
/** A `content-type` the request lacked and must carry. */
|
|
61
|
-
contentType?: string
|
|
62
|
-
/** `data` is final text — axios must not transform it again. */
|
|
63
|
-
verbatim: boolean
|
|
64
|
-
}
|
|
65
|
-
|
|
66
56
|
/**
|
|
67
57
|
* What a request's body becomes on the wire.
|
|
68
58
|
*
|
|
@@ -72,7 +62,7 @@ export interface RequestBody {
|
|
|
72
62
|
* - Anything else — objects, arrays, a scalar under another content type — goes to axios as it is,
|
|
73
63
|
* which serializes an object or an array as JSON.
|
|
74
64
|
*/
|
|
75
|
-
|
|
65
|
+
const requestBodyOf = (
|
|
76
66
|
body: unknown, headers: Record<string, unknown> | undefined, method?: RouteMethod, schema?: object
|
|
77
67
|
): RequestBody => {
|
|
78
68
|
const type = contentTypeOf(headers)
|
|
@@ -91,3 +81,7 @@ export const requestBodyOf = (
|
|
|
91
81
|
|
|
92
82
|
return { data: body, verbatim: false }
|
|
93
83
|
}
|
|
84
|
+
|
|
85
|
+
export const createBodyHelper = () => ({ contentTypeOf, isJsonContentType, jsonScalarBody, requestBodyOf })
|
|
86
|
+
|
|
87
|
+
export const bodyHelper = createBodyHelper()
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const FORM_CONTENT_TYPE = 'application/x-www-form-urlencoded'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const JSON_CONTENT_TYPE = 'application/json'
|
package/src/utils/handler.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import { EntrypointOutcome } from '@owlmeans/entrypoint'
|
|
1
|
+
import { type AbstractResponse, EntrypointOutcome } from '@owlmeans/entrypoint'
|
|
3
2
|
import type { AxiosResponse } from 'axios'
|
|
4
3
|
import {
|
|
5
4
|
ACCEPTED, CREATED, FINISHED, FORBIDDEN_ERROR, INCIDENT_ID_HEADER, DENIAL_KIND_HEADER,
|
|
@@ -8,7 +7,10 @@ import {
|
|
|
8
7
|
import { ResilientError } from '@owlmeans/error'
|
|
9
8
|
import { ApiClientError, ApiStatusError, ServerAuthError, ServerCrashedError } from '../errors.js'
|
|
10
9
|
import { isIncidentBody } from '../status/index.js'
|
|
11
|
-
import type { ResponseStatusCarrier } from '../status/
|
|
10
|
+
import type { ResponseStatusCarrier } from '../status/types.js'
|
|
11
|
+
import { logger } from '@owlmeans/log'
|
|
12
|
+
|
|
13
|
+
const log = logger('api')
|
|
12
14
|
|
|
13
15
|
export const processResponse = (response: AxiosResponse, reply: AbstractResponse<any>) => {
|
|
14
16
|
switch (response.status) {
|
|
@@ -23,10 +25,11 @@ export const processResponse = (response: AxiosResponse, reply: AbstractResponse
|
|
|
23
25
|
case FINISHED:
|
|
24
26
|
return processEmptyResponse(response, reply, EntrypointOutcome.Finished)
|
|
25
27
|
default:
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
// A refusal is ordinary traffic (401, 403, 409, 428): debug, and never the headers.
|
|
29
|
+
log.debug('Request answered with a failure', {
|
|
30
|
+
status: response.status, statusText: response.statusText, url: response.config?.url,
|
|
31
|
+
incidentId: headerOf(response.headers, INCIDENT_ID_HEADER),
|
|
32
|
+
})
|
|
30
33
|
|
|
31
34
|
reply.reject(failureOf(response))
|
|
32
35
|
}
|
|
@@ -57,7 +60,7 @@ const failureOf = (response: AxiosResponse): Error => {
|
|
|
57
60
|
|
|
58
61
|
return error
|
|
59
62
|
} catch {
|
|
60
|
-
|
|
63
|
+
log.warn('Server returned an unrecognizable text error', { status: response.status, body: response.data })
|
|
61
64
|
}
|
|
62
65
|
}
|
|
63
66
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { createBodyHelper } from './body.js'
|
|
2
|
+
|
|
3
|
+
export interface RequestBody {
|
|
4
|
+
/** What axios is handed as `data`. */
|
|
5
|
+
data: unknown
|
|
6
|
+
/** A `content-type` the request lacked and must carry. */
|
|
7
|
+
contentType?: string
|
|
8
|
+
/** `data` is final text — axios must not transform it again. */
|
|
9
|
+
verbatim: boolean
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type BodyHelper = ReturnType<typeof createBodyHelper>
|
package/tests/body.spec.ts
CHANGED
|
@@ -1,60 +1,59 @@
|
|
|
1
1
|
import { afterAll, beforeAll, describe, expect, test } from 'bun:test'
|
|
2
|
-
import { provideResponse } from '@owlmeans/entrypoint'
|
|
3
|
-
import type { AbstractRequest } from '@owlmeans/entrypoint'
|
|
2
|
+
import { provideResponse, type AbstractRequest } from '@owlmeans/entrypoint'
|
|
4
3
|
import { RouteMethod } from '@owlmeans/route'
|
|
5
4
|
import { createApiService } from '../src/service.js'
|
|
6
|
-
import {
|
|
5
|
+
import { bodyHelper } from '../src/utils/body.js'
|
|
7
6
|
|
|
8
7
|
const STRING = { type: 'string' }
|
|
9
8
|
|
|
10
9
|
describe('what a request body becomes', () => {
|
|
11
10
|
test('a scalar on a POST without a content type is JSON text', () => {
|
|
12
|
-
expect(requestBodyOf('abc', {}, RouteMethod.POST)).toEqual({ data: '"abc"', contentType: 'application/json', verbatim: true })
|
|
13
|
-
expect(requestBodyOf('', {}, RouteMethod.POST).data).toBe('""')
|
|
14
|
-
expect(requestBodyOf(5, {}, RouteMethod.POST).data).toBe('5')
|
|
15
|
-
expect(requestBodyOf(0, {}, RouteMethod.POST).data).toBe('0')
|
|
16
|
-
expect(requestBodyOf(true, {}, RouteMethod.POST).data).toBe('true')
|
|
17
|
-
expect(requestBodyOf(false, {}, RouteMethod.POST).data).toBe('false')
|
|
11
|
+
expect(bodyHelper.requestBodyOf('abc', {}, RouteMethod.POST)).toEqual({ data: '"abc"', contentType: 'application/json', verbatim: true })
|
|
12
|
+
expect(bodyHelper.requestBodyOf('', {}, RouteMethod.POST).data).toBe('""')
|
|
13
|
+
expect(bodyHelper.requestBodyOf(5, {}, RouteMethod.POST).data).toBe('5')
|
|
14
|
+
expect(bodyHelper.requestBodyOf(0, {}, RouteMethod.POST).data).toBe('0')
|
|
15
|
+
expect(bodyHelper.requestBodyOf(true, {}, RouteMethod.POST).data).toBe('true')
|
|
16
|
+
expect(bodyHelper.requestBodyOf(false, {}, RouteMethod.POST).data).toBe('false')
|
|
18
17
|
})
|
|
19
18
|
|
|
20
19
|
test('a scalar under an explicit JSON content type is JSON text, on any method', () => {
|
|
21
|
-
expect(requestBodyOf('abc', { 'Content-Type': 'application/json; charset=utf-8' }, RouteMethod.PUT))
|
|
20
|
+
expect(bodyHelper.requestBodyOf('abc', { 'Content-Type': 'application/json; charset=utf-8' }, RouteMethod.PUT))
|
|
22
21
|
.toEqual({ data: '"abc"', verbatim: true })
|
|
23
|
-
expect(requestBodyOf(7, { 'content-type': 'application/merge-patch+json' }, RouteMethod.PATCH).data).toBe('7')
|
|
22
|
+
expect(bodyHelper.requestBodyOf(7, { 'content-type': 'application/merge-patch+json' }, RouteMethod.PATCH).data).toBe('7')
|
|
24
23
|
})
|
|
25
24
|
|
|
26
25
|
test('already-serialized JSON text is sent as it is', () => {
|
|
27
|
-
expect(requestBodyOf('{"a":1}', {}, RouteMethod.POST).data).toBe('{"a":1}')
|
|
28
|
-
expect(requestBodyOf('[1,2]', {}, RouteMethod.POST).data).toBe('[1,2]')
|
|
29
|
-
expect(requestBodyOf('"abc"', {}, RouteMethod.POST).data).toBe('"abc"')
|
|
30
|
-
expect(requestBodyOf('"abc"', {}, RouteMethod.POST, STRING).data).toBe('"abc"')
|
|
26
|
+
expect(bodyHelper.requestBodyOf('{"a":1}', {}, RouteMethod.POST).data).toBe('{"a":1}')
|
|
27
|
+
expect(bodyHelper.requestBodyOf('[1,2]', {}, RouteMethod.POST).data).toBe('[1,2]')
|
|
28
|
+
expect(bodyHelper.requestBodyOf('"abc"', {}, RouteMethod.POST).data).toBe('"abc"')
|
|
29
|
+
expect(bodyHelper.requestBodyOf('"abc"', {}, RouteMethod.POST, STRING).data).toBe('"abc"')
|
|
31
30
|
})
|
|
32
31
|
|
|
33
32
|
test('under a string body schema, JSON-looking text is the string the caller means', () => {
|
|
34
|
-
expect(jsonScalarBody('123', STRING)).toBe('"123"')
|
|
35
|
-
expect(jsonScalarBody('true', STRING)).toBe('"true"')
|
|
36
|
-
expect(jsonScalarBody('null', { type: ['string', 'null'] })).toBe('"null"')
|
|
37
|
-
expect(jsonScalarBody('{"a":1}', STRING)).toBe('"{\\"a\\":1}"')
|
|
38
|
-
expect(jsonScalarBody('123', { type: 'number' })).toBe('123')
|
|
33
|
+
expect(bodyHelper.jsonScalarBody('123', STRING)).toBe('"123"')
|
|
34
|
+
expect(bodyHelper.jsonScalarBody('true', STRING)).toBe('"true"')
|
|
35
|
+
expect(bodyHelper.jsonScalarBody('null', { type: ['string', 'null'] })).toBe('"null"')
|
|
36
|
+
expect(bodyHelper.jsonScalarBody('{"a":1}', STRING)).toBe('"{\\"a\\":1}"')
|
|
37
|
+
expect(bodyHelper.jsonScalarBody('123', { type: 'number' })).toBe('123')
|
|
39
38
|
})
|
|
40
39
|
|
|
41
40
|
test('objects, arrays and everything outside JSON behave as before', () => {
|
|
42
41
|
const object = { a: 1 }
|
|
43
|
-
expect(requestBodyOf(object, {}, RouteMethod.POST)).toEqual({ data: object, verbatim: false })
|
|
44
|
-
expect(requestBodyOf([1], {}, RouteMethod.POST)).toEqual({ data: [1], verbatim: false })
|
|
45
|
-
expect(requestBodyOf(undefined, {}, RouteMethod.POST)).toEqual({ data: undefined, verbatim: false })
|
|
46
|
-
expect(requestBodyOf('abc', { 'content-type': 'text/plain' }, RouteMethod.POST)).toEqual({ data: 'abc', verbatim: false })
|
|
47
|
-
expect(requestBodyOf('abc', {}, RouteMethod.PUT)).toEqual({ data: 'abc', verbatim: false })
|
|
48
|
-
expect(requestBodyOf({ a: '1', b: ['x'] }, { 'content-type': 'application/x-www-form-urlencoded' }, RouteMethod.POST).data)
|
|
42
|
+
expect(bodyHelper.requestBodyOf(object, {}, RouteMethod.POST)).toEqual({ data: object, verbatim: false })
|
|
43
|
+
expect(bodyHelper.requestBodyOf([1], {}, RouteMethod.POST)).toEqual({ data: [1], verbatim: false })
|
|
44
|
+
expect(bodyHelper.requestBodyOf(undefined, {}, RouteMethod.POST)).toEqual({ data: undefined, verbatim: false })
|
|
45
|
+
expect(bodyHelper.requestBodyOf('abc', { 'content-type': 'text/plain' }, RouteMethod.POST)).toEqual({ data: 'abc', verbatim: false })
|
|
46
|
+
expect(bodyHelper.requestBodyOf('abc', {}, RouteMethod.PUT)).toEqual({ data: 'abc', verbatim: false })
|
|
47
|
+
expect(bodyHelper.requestBodyOf({ a: '1', b: ['x'] }, { 'content-type': 'application/x-www-form-urlencoded' }, RouteMethod.POST).data)
|
|
49
48
|
.toBe('a=1&b%5B0%5D=x')
|
|
50
49
|
})
|
|
51
50
|
|
|
52
51
|
test('the content-type header is read whatever its case', () => {
|
|
53
|
-
expect(contentTypeOf({ 'CONTENT-TYPE': 'application/json' })).toBe('application/json')
|
|
54
|
-
expect(contentTypeOf({ accept: 'application/json' })).toBeUndefined()
|
|
55
|
-
expect(isJsonContentType('application/vnd.api+json')).toBe(true)
|
|
56
|
-
expect(isJsonContentType('application/jsonp')).toBe(false)
|
|
57
|
-
expect(isJsonContentType('text/plain')).toBe(false)
|
|
52
|
+
expect(bodyHelper.contentTypeOf({ 'CONTENT-TYPE': 'application/json' })).toBe('application/json')
|
|
53
|
+
expect(bodyHelper.contentTypeOf({ accept: 'application/json' })).toBeUndefined()
|
|
54
|
+
expect(bodyHelper.isJsonContentType('application/vnd.api+json')).toBe(true)
|
|
55
|
+
expect(bodyHelper.isJsonContentType('application/jsonp')).toBe(false)
|
|
56
|
+
expect(bodyHelper.isJsonContentType('text/plain')).toBe(false)
|
|
58
57
|
})
|
|
59
58
|
})
|
|
60
59
|
|