@owlmeans/api 0.1.18-rc.45 → 0.1.18-rc.47

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/README.md +2 -2
  2. package/agent-meta/manifest.json +2 -2
  3. package/agent-meta/skills/api/SKILL.md +22 -20
  4. package/build/index.d.ts +3 -2
  5. package/build/index.d.ts.map +1 -1
  6. package/build/index.js +1 -1
  7. package/build/index.js.map +1 -1
  8. package/build/service.d.ts +1 -6
  9. package/build/service.d.ts.map +1 -1
  10. package/build/service.js +6 -6
  11. package/build/service.js.map +1 -1
  12. package/build/status/consts.d.ts +5 -0
  13. package/build/status/consts.d.ts.map +1 -0
  14. package/build/status/consts.js +5 -0
  15. package/build/status/consts.js.map +1 -0
  16. package/build/status/consts.local.d.ts +10 -0
  17. package/build/status/consts.local.d.ts.map +1 -0
  18. package/build/status/consts.local.js +10 -0
  19. package/build/status/consts.local.js.map +1 -0
  20. package/build/status/helper.d.ts +4 -0
  21. package/build/status/helper.d.ts.map +1 -0
  22. package/build/status/helper.js +49 -0
  23. package/build/status/helper.js.map +1 -0
  24. package/build/status/index.d.ts +5 -27
  25. package/build/status/index.d.ts.map +1 -1
  26. package/build/status/index.js +6 -62
  27. package/build/status/index.js.map +1 -1
  28. package/build/status/marker.d.ts +1 -10
  29. package/build/status/marker.d.ts.map +1 -1
  30. package/build/status/marker.js +1 -12
  31. package/build/status/marker.js.map +1 -1
  32. package/build/status/types.d.ts +35 -0
  33. package/build/status/types.d.ts.map +1 -0
  34. package/build/status/types.js +2 -0
  35. package/build/status/types.js.map +1 -0
  36. package/build/types.local.d.ts +6 -0
  37. package/build/types.local.d.ts.map +1 -0
  38. package/build/types.local.js +2 -0
  39. package/build/types.local.js.map +1 -0
  40. package/build/utils/body/types.d.ts +36 -0
  41. package/build/utils/body/types.d.ts.map +1 -0
  42. package/build/utils/body/types.js +2 -0
  43. package/build/utils/body/types.js.map +1 -0
  44. package/build/utils/body.d.ts +3 -33
  45. package/build/utils/body.d.ts.map +1 -1
  46. package/build/utils/body.js +51 -66
  47. package/build/utils/body.js.map +1 -1
  48. package/build/utils/consts.d.ts +2 -0
  49. package/build/utils/consts.d.ts.map +1 -0
  50. package/build/utils/consts.js +2 -0
  51. package/build/utils/consts.js.map +1 -0
  52. package/build/utils/consts.local.d.ts +2 -0
  53. package/build/utils/consts.local.d.ts.map +1 -0
  54. package/build/utils/consts.local.js +2 -0
  55. package/build/utils/consts.local.js.map +1 -0
  56. package/build/utils/index.d.ts +2 -1
  57. package/build/utils/index.d.ts.map +1 -1
  58. package/build/utils/index.js +1 -1
  59. package/build/utils/index.js.map +1 -1
  60. package/build/utils/response/types.d.ts +15 -0
  61. package/build/utils/response/types.d.ts.map +1 -0
  62. package/build/utils/response/types.js +2 -0
  63. package/build/utils/response/types.js.map +1 -0
  64. package/build/utils/response.d.ts +4 -0
  65. package/build/utils/response.d.ts.map +1 -0
  66. package/build/utils/response.js +99 -0
  67. package/build/utils/response.js.map +1 -0
  68. package/package.json +14 -14
  69. package/src/index.ts +3 -2
  70. package/src/service.ts +8 -15
  71. package/src/status/consts.local.ts +11 -0
  72. package/src/status/consts.ts +5 -0
  73. package/src/status/helper.ts +63 -0
  74. package/src/status/index.ts +7 -81
  75. package/src/status/marker.ts +3 -21
  76. package/src/status/types.ts +36 -0
  77. package/src/types.local.ts +7 -0
  78. package/src/utils/body/types.ts +37 -0
  79. package/src/utils/body.ts +53 -76
  80. package/src/utils/consts.local.ts +1 -0
  81. package/src/utils/consts.ts +1 -0
  82. package/src/utils/index.ts +2 -1
  83. package/src/utils/response/types.ts +15 -0
  84. package/src/utils/response.ts +117 -0
  85. package/tests/body.spec.ts +30 -31
  86. package/tests/handler.spec.ts +45 -45
  87. package/build/utils/handler.d.ts +0 -11
  88. package/build/utils/handler.d.ts.map +0 -1
  89. package/build/utils/handler.js +0 -95
  90. package/build/utils/handler.js.map +0 -1
  91. package/src/utils/handler.ts +0 -111
@@ -0,0 +1,36 @@
1
+ import type { RouteMethod } from '@owlmeans/route';
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
+ /** How a request's body travels: its content type and the text a scalar body becomes. */
11
+ export interface BodyUtils {
12
+ /** The request's own `content-type`, whatever case its key is written in. */
13
+ contentTypeOf: (headers?: Record<string, unknown>) => string | undefined;
14
+ /** `application/json` or a `+json` suffix type, with or without parameters. */
15
+ isJsonContentType: (type?: string) => boolean;
16
+ /**
17
+ * The JSON text a scalar body travels as, so the server parses it back to the same value.
18
+ *
19
+ * A number or a boolean is `JSON.stringify`'d. A string is a value unless it is already JSON text:
20
+ * one that does not parse is quoted; one that parses is sent as it is (the caller serialized it
21
+ * itself) — except under a body schema of `type: 'string'`, where only a JSON string literal
22
+ * counts as serialized and `123`, `true` or `{…}` are the text the caller means.
23
+ */
24
+ jsonScalarBody: (body: string | number | boolean, schema?: object) => string;
25
+ /**
26
+ * What a request's body becomes on the wire.
27
+ *
28
+ * - A `x-www-form-urlencoded` request: the body through `qs`.
29
+ * - A string, number or boolean under a JSON `content-type` — the caller's, or `application/json`
30
+ * supplied for a `POST` that names none — becomes JSON text ({@link BodyUtils.jsonScalarBody}).
31
+ * - Anything else — objects, arrays, a scalar under another content type — goes to axios as it is,
32
+ * which serializes an object or an array as JSON.
33
+ */
34
+ requestBodyOf: (body: unknown, headers: Record<string, unknown> | undefined, method?: RouteMethod, schema?: object) => RequestBody;
35
+ }
36
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/utils/body/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAElD,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,yFAAyF;AACzF,MAAM,WAAW,SAAS;IACxB,6EAA6E;IAC7E,aAAa,EAAE,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,GAAG,SAAS,CAAA;IACxE,+EAA+E;IAC/E,iBAAiB,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,KAAK,OAAO,CAAA;IAC7C;;;;;;;OAOG;IACH,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,MAAM,CAAA;IAC5E;;;;;;;;OAQG;IACH,aAAa,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAAE,MAAM,CAAC,EAAE,WAAW,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,WAAW,CAAA;CACnI"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/utils/body/types.ts"],"names":[],"mappings":""}
@@ -1,34 +1,4 @@
1
- import { RouteMethod } from '@owlmeans/route';
2
- export declare const JSON_CONTENT_TYPE = "application/json";
3
- /** The request's own `content-type`, whatever case its key is written in. */
4
- export declare const contentTypeOf: (headers?: Record<string, unknown>) => string | undefined;
5
- /** `application/json` or a `+json` suffix type, with or without parameters. */
6
- export declare const isJsonContentType: (type?: string) => boolean;
7
- /**
8
- * The JSON text a scalar body travels as, so the server parses it back to the same value.
9
- *
10
- * A number or a boolean is `JSON.stringify`'d. A string is a value unless it is already JSON text:
11
- * one that does not parse is quoted; one that parses is sent as it is (the caller serialized it
12
- * itself) — except under a body schema of `type: 'string'`, where only a JSON string literal
13
- * counts as serialized and `123`, `true` or `{…}` are the text the caller means.
14
- */
15
- export declare const jsonScalarBody: (body: string | number | boolean, schema?: object) => string;
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
- }
24
- /**
25
- * What a request's body becomes on the wire.
26
- *
27
- * - A `x-www-form-urlencoded` request: the body through `qs`.
28
- * - A string, number or boolean under a JSON `content-type` — the caller's, or `application/json`
29
- * supplied for a `POST` that names none — becomes JSON text ({@link jsonScalarBody}).
30
- * - Anything else — objects, arrays, a scalar under another content type — goes to axios as it is,
31
- * which serializes an object or an array as JSON.
32
- */
33
- export declare const requestBodyOf: (body: unknown, headers: Record<string, unknown> | undefined, method?: RouteMethod, schema?: object) => RequestBody;
1
+ import type { BodyUtils } from './body/types.js';
2
+ export declare const createBodyUtils: () => BodyUtils;
3
+ export declare const bodyUtils: BodyUtils;
34
4
  //# 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;AAE7C,eAAO,MAAM,iBAAiB,qBAAqB,CAAA;AAInD,6EAA6E;AAC7E,eAAO,MAAM,aAAa,aAAc,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,MAAM,GAAG,SAM1E,CAAA;AAED,+EAA+E;AAC/E,eAAO,MAAM,iBAAiB,UAAW,MAAM,KAAG,OAC+B,CAAA;AAoBjF;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,SAAU,MAAM,GAAG,MAAM,GAAG,OAAO,WAAW,MAAM,KAAG,MAQjF,CAAA;AAED,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;;;;;;;;GAQG;AACH,eAAO,MAAM,aAAa,SAClB,OAAO,WAAW,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,WAAW,WAAW,WAAW,MAAM,KACjG,WAgBF,CAAA"}
1
+ {"version":3,"file":"body.d.ts","sourceRoot":"","sources":["../../src/utils/body.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAe,MAAM,iBAAiB,CAAA;AAE7D,eAAO,MAAM,eAAe,QAAO,SA6DlC,CAAA;AAED,eAAO,MAAM,SAAS,WAAoB,CAAA"}
@@ -1,71 +1,56 @@
1
1
  import qs from 'qs';
2
2
  import { RouteMethod } from '@owlmeans/route';
3
- export const JSON_CONTENT_TYPE = 'application/json';
4
- const FORM_CONTENT_TYPE = 'application/x-www-form-urlencoded';
5
- /** The request's own `content-type`, whatever case its key is written in. */
6
- export const contentTypeOf = (headers) => {
7
- const value = Object.entries(headers ?? {}).find(([key]) => key.toLowerCase() === 'content-type')?.[1];
8
- if (value == null || value === '') {
9
- return undefined;
10
- }
11
- return Array.isArray(value) ? value.join(', ') : `${value}`;
12
- };
13
- /** `application/json` or a `+json` suffix type, with or without parameters. */
14
- export const isJsonContentType = (type) => type != null && /^application\/(?:[^\s;]+\+)?json\s*(?:;|$)/i.test(type.trim());
15
- /** A JSON value no serializer quotes for us: a string, a number or a boolean. */
16
- const isScalar = (value) => typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean';
17
- /** Does the entrypoint's body schema declare a string? */
18
- const stringContract = (schema) => {
19
- const type = schema?.type;
20
- return (Array.isArray(type) ? type : [type]).includes('string');
21
- };
22
- const parse = (text) => {
23
- try {
24
- return { json: true, value: JSON.parse(text) };
25
- }
26
- catch {
27
- return { json: false };
28
- }
29
- };
30
- /**
31
- * The JSON text a scalar body travels as, so the server parses it back to the same value.
32
- *
33
- * A number or a boolean is `JSON.stringify`'d. A string is a value unless it is already JSON text:
34
- * one that does not parse is quoted; one that parses is sent as it is (the caller serialized it
35
- * itself) — except under a body schema of `type: 'string'`, where only a JSON string literal
36
- * counts as serialized and `123`, `true` or `{…}` are the text the caller means.
37
- */
38
- export const jsonScalarBody = (body, schema) => {
39
- if (typeof body !== 'string') {
40
- return JSON.stringify(body);
41
- }
42
- const parsed = parse(body);
43
- const serialized = parsed.json && (!stringContract(schema) || typeof parsed.value === 'string');
44
- return serialized ? body : JSON.stringify(body);
45
- };
46
- /**
47
- * What a request's body becomes on the wire.
48
- *
49
- * - A `x-www-form-urlencoded` request: the body through `qs`.
50
- * - A string, number or boolean under a JSON `content-type` — the caller's, or `application/json`
51
- * supplied for a `POST` that names none — becomes JSON text ({@link jsonScalarBody}).
52
- * - Anything else — objects, arrays, a scalar under another content type — goes to axios as it is,
53
- * which serializes an object or an array as JSON.
54
- */
55
- export const requestBodyOf = (body, headers, method, schema) => {
56
- const type = contentTypeOf(headers);
57
- if (body != null && type?.includes(FORM_CONTENT_TYPE) === true) {
58
- return { data: qs.stringify(body), verbatim: false };
59
- }
60
- if (!isScalar(body)) {
3
+ import { FORM_CONTENT_TYPE } from './consts.local.js';
4
+ import { JSON_CONTENT_TYPE } from './consts.js';
5
+ export const createBodyUtils = () => {
6
+ const contentTypeOf = (headers) => {
7
+ const value = Object.entries(headers ?? {}).find(([key]) => key.toLowerCase() === 'content-type')?.[1];
8
+ if (value == null || value === '') {
9
+ return undefined;
10
+ }
11
+ return Array.isArray(value) ? value.join(', ') : `${value}`;
12
+ };
13
+ const isJsonContentType = (type) => type != null && /^application\/(?:[^\s;]+\+)?json\s*(?:;|$)/i.test(type.trim());
14
+ /** A JSON value no serializer quotes for us: a string, a number or a boolean. */
15
+ const isScalar = (value) => typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean';
16
+ /** Does the entrypoint's body schema declare a string? */
17
+ const stringContract = (schema) => {
18
+ const type = schema?.type;
19
+ return (Array.isArray(type) ? type : [type]).includes('string');
20
+ };
21
+ const parse = (text) => {
22
+ try {
23
+ return { json: true, value: JSON.parse(text) };
24
+ }
25
+ catch {
26
+ return { json: false };
27
+ }
28
+ };
29
+ const jsonScalarBody = (body, schema) => {
30
+ if (typeof body !== 'string') {
31
+ return JSON.stringify(body);
32
+ }
33
+ const parsed = parse(body);
34
+ const serialized = parsed.json && (!stringContract(schema) || typeof parsed.value === 'string');
35
+ return serialized ? body : JSON.stringify(body);
36
+ };
37
+ const requestBodyOf = (body, headers, method, schema) => {
38
+ const type = contentTypeOf(headers);
39
+ if (body != null && type?.includes(FORM_CONTENT_TYPE) === true) {
40
+ return { data: qs.stringify(body), verbatim: false };
41
+ }
42
+ if (!isScalar(body)) {
43
+ return { data: body, verbatim: false };
44
+ }
45
+ if (type == null && method === RouteMethod.POST) {
46
+ return { data: jsonScalarBody(body, schema), contentType: JSON_CONTENT_TYPE, verbatim: true };
47
+ }
48
+ if (isJsonContentType(type)) {
49
+ return { data: jsonScalarBody(body, schema), verbatim: true };
50
+ }
61
51
  return { data: body, verbatim: false };
62
- }
63
- if (type == null && method === RouteMethod.POST) {
64
- return { data: jsonScalarBody(body, schema), contentType: JSON_CONTENT_TYPE, verbatim: true };
65
- }
66
- if (isJsonContentType(type)) {
67
- return { data: jsonScalarBody(body, schema), verbatim: true };
68
- }
69
- return { data: body, verbatim: false };
52
+ };
53
+ return { contentTypeOf, isJsonContentType, jsonScalarBody, requestBodyOf };
70
54
  };
55
+ export const bodyUtils = createBodyUtils();
71
56
  //# sourceMappingURL=body.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"body.js","sourceRoot":"","sources":["../../src/utils/body.ts"],"names":[],"mappings":"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"}
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,MAAM,CAAC,MAAM,eAAe,GAAG,GAAc,EAAE;IAC7C,MAAM,aAAa,GAAG,CAAC,OAAiC,EAAsB,EAAE;QAC9E,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;QACtG,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;YAClC,OAAO,SAAS,CAAA;QAClB,CAAC;QACD,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,EAAE,CAAA;IAC7D,CAAC,CAAA;IAED,MAAM,iBAAiB,GAAG,CAAC,IAAa,EAAW,EAAE,CACnD,IAAI,IAAI,IAAI,IAAI,6CAA6C,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAA;IAEjF,iFAAiF;IACjF,MAAM,QAAQ,GAAG,CAAC,KAAc,EAAsC,EAAE,CACtE,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,SAAS,CAAA;IAEtF,0DAA0D;IAC1D,MAAM,cAAc,GAAG,CAAC,MAAe,EAAW,EAAE;QAClD,MAAM,IAAI,GAAI,MAAyC,EAAE,IAAI,CAAA;QAC7D,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;IACjE,CAAC,CAAA;IAED,MAAM,KAAK,GAAG,CAAC,IAAY,EAAoD,EAAE;QAC/E,IAAI,CAAC;YACH,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAA;QAChD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAA;QACxB,CAAC;IACH,CAAC,CAAA;IAED,MAAM,cAAc,GAAG,CAAC,IAA+B,EAAE,MAAe,EAAU,EAAE;QAClF,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC7B,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;QAC7B,CAAC;QACD,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,CAAA;QAC1B,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,IAAI,OAAO,MAAM,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAA;QAE/F,OAAO,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;IACjD,CAAC,CAAA;IAED,MAAM,aAAa,GAAG,CACpB,IAAa,EAAE,OAA4C,EAAE,MAAoB,EAAE,MAAe,EACrF,EAAE;QACf,MAAM,IAAI,GAAG,aAAa,CAAC,OAAO,CAAC,CAAA;QACnC,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,EAAE,QAAQ,CAAC,iBAAiB,CAAC,KAAK,IAAI,EAAE,CAAC;YAC/D,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAA;QACtD,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YACpB,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAA;QACxC,CAAC;QACD,IAAI,IAAI,IAAI,IAAI,IAAI,MAAM,KAAK,WAAW,CAAC,IAAI,EAAE,CAAC;YAChD,OAAO,EAAE,IAAI,EAAE,cAAc,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,WAAW,EAAE,iBAAiB,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAA;QAC/F,CAAC;QACD,IAAI,iBAAiB,CAAC,IAAI,CAAC,EAAE,CAAC;YAC5B,OAAO,EAAE,IAAI,EAAE,cAAc,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAA;QAC/D,CAAC;QAED,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAA;IACxC,CAAC,CAAA;IAED,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,cAAc,EAAE,aAAa,EAAE,CAAA;AAC5E,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,SAAS,GAAG,eAAe,EAAE,CAAA"}
@@ -0,0 +1,2 @@
1
+ export declare const JSON_CONTENT_TYPE = "application/json";
2
+ //# sourceMappingURL=consts.d.ts.map
@@ -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,2 @@
1
+ export const JSON_CONTENT_TYPE = 'application/json';
2
+ //# sourceMappingURL=consts.js.map
@@ -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,2 @@
1
+ export declare const FORM_CONTENT_TYPE = "application/x-www-form-urlencoded";
2
+ //# sourceMappingURL=consts.local.d.ts.map
@@ -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,2 @@
1
+ export const FORM_CONTENT_TYPE = 'application/x-www-form-urlencoded';
2
+ //# sourceMappingURL=consts.local.js.map
@@ -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"}
@@ -1,2 +1,3 @@
1
- export * from './handler.js';
1
+ export type * from './response/types.js';
2
+ export * from './response.js';
2
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AACA,cAAc,cAAc,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AACA,mBAAmB,qBAAqB,CAAA;AACxC,cAAc,eAAe,CAAA"}
@@ -1,2 +1,2 @@
1
- export * from './handler.js';
1
+ export * from './response.js';
2
2
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AACA,cAAc,cAAc,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAEA,cAAc,eAAe,CAAA"}
@@ -0,0 +1,15 @@
1
+ import type { AbstractResponse } from '@owlmeans/entrypoint';
2
+ import type { AxiosResponse } from 'axios';
3
+ import type { ApiClientError } from '../../errors.js';
4
+ /** Turns an axios answer into the entrypoint reply: a resolved value or a typed failure. */
5
+ export interface ResponseUtils {
6
+ /** Resolves `reply` with a 2xx answer's value, or rejects it with the failure of any other status. */
7
+ processResponse: (response: AxiosResponse, reply: AbstractResponse<any>) => void;
8
+ /**
9
+ * The typed error of a bare status: `ServerCrashedError` (500), `ServerAuthError` (401),
10
+ * `ApiClientError('forbidden[:<id>]')` (403), `ApiStatusError` (`api:client:status:<n>[:<id>]`)
11
+ * for every other one.
12
+ */
13
+ statusError: (status: number, incidentId?: string) => ApiClientError;
14
+ }
15
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/utils/response/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAC5D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;AAC1C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAErD,4FAA4F;AAC5F,MAAM,WAAW,aAAa;IAC5B,sGAAsG;IACtG,eAAe,EAAE,CAAC,QAAQ,EAAE,aAAa,EAAE,KAAK,EAAE,gBAAgB,CAAC,GAAG,CAAC,KAAK,IAAI,CAAA;IAChF;;;;OAIG;IACH,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,KAAK,cAAc,CAAA;CACrE"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/utils/response/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,4 @@
1
+ import type { ResponseUtils } from './response/types.js';
2
+ export declare const createResponseUtils: () => ResponseUtils;
3
+ export declare const responseUtils: ResponseUtils;
4
+ //# sourceMappingURL=response.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"response.d.ts","sourceRoot":"","sources":["../../src/utils/response.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAExD,eAAO,MAAM,mBAAmB,QAAO,aAqGtC,CAAA;AAED,eAAO,MAAM,aAAa,eAAwB,CAAA"}
@@ -0,0 +1,99 @@
1
+ import { EntrypointOutcome } from '@owlmeans/entrypoint';
2
+ import { ACCEPTED, CREATED, FINISHED, FORBIDDEN_ERROR, INCIDENT_ID_HEADER, DENIAL_KIND_HEADER, ACCESS_DENIED_KIND, OK, SERVER_ERROR, UNAUTHORIZED_ERROR, } from '../consts.js';
3
+ import { ResilientError } from '@owlmeans/error';
4
+ import { ApiClientError, ApiStatusError, ServerAuthError, ServerCrashedError } from '../errors.js';
5
+ import { apiStatusHelper } from '../status/helper.js';
6
+ import { logger } from '@owlmeans/log';
7
+ export const createResponseUtils = () => {
8
+ const log = logger('api');
9
+ const processResponse = (response, reply) => {
10
+ switch (response.status) {
11
+ case OK:
12
+ reply.resolve(response.data, EntrypointOutcome.Ok);
13
+ return;
14
+ case ACCEPTED:
15
+ reply.resolve(response.data, EntrypointOutcome.Accepted);
16
+ return;
17
+ case CREATED:
18
+ return processEmptyResponse(response, reply, EntrypointOutcome.Created);
19
+ case FINISHED:
20
+ return processEmptyResponse(response, reply, EntrypointOutcome.Finished);
21
+ default:
22
+ // A refusal is ordinary traffic (401, 403, 409, 428): debug, and never the headers.
23
+ log.debug('Request answered with a failure', {
24
+ status: response.status, statusText: response.statusText, url: response.config?.url,
25
+ incidentId: headerOf(response.headers, INCIDENT_ID_HEADER),
26
+ });
27
+ reply.reject(failureOf(response));
28
+ }
29
+ };
30
+ /**
31
+ * The error a non-2xx answer rejects with — always carrying the HTTP status and, when the server
32
+ * sent one, its incident id.
33
+ *
34
+ * A development body is the marshaled `ResilientError`: it is rebuilt into its own class and
35
+ * stamped with `responseStatus`. Anything else — the bare incident id of a production body, a
36
+ * proxy's HTML, a framework's JSON — becomes the status error of {@link statusError}.
37
+ */
38
+ const failureOf = (response) => {
39
+ const incidentId = headerOf(response.headers, INCIDENT_ID_HEADER)
40
+ ?? (apiStatusHelper.isIncidentBody(response.data) ? response.data.trim() : undefined);
41
+ const denialKind = response.status === FORBIDDEN_ERROR
42
+ && headerOf(response.headers, DENIAL_KIND_HEADER) === ACCESS_DENIED_KIND
43
+ ? ACCESS_DENIED_KIND : undefined;
44
+ if (typeof response.data === 'string' && response.data.includes(ResilientError.separator)) {
45
+ try {
46
+ const error = ResilientError.ensure(response.data, true);
47
+ error.incidentId ??= incidentId;
48
+ Object.assign(error, {
49
+ responseStatus: response.status, denialKind,
50
+ });
51
+ return error;
52
+ }
53
+ catch {
54
+ log.warn('Server returned an unrecognizable text error', { status: response.status, body: response.data });
55
+ }
56
+ }
57
+ return Object.assign(statusError(response.status, incidentId), { denialKind });
58
+ };
59
+ /**
60
+ * The typed error of a bare status: `ServerCrashedError` (500), `ServerAuthError` (401),
61
+ * `ApiClientError('forbidden[:<id>]')` (403), `ApiStatusError` (`api:client:status:<n>[:<id>]`)
62
+ * for every other one.
63
+ */
64
+ const statusError = (status, incidentId) => {
65
+ const error = status === SERVER_ERROR ? new ServerCrashedError(incidentId)
66
+ : status === UNAUTHORIZED_ERROR ? new ServerAuthError(incidentId)
67
+ : status === FORBIDDEN_ERROR ? new ApiClientError(incidentId != null ? `forbidden:${incidentId}` : 'forbidden')
68
+ : new ApiStatusError(status, incidentId);
69
+ if (incidentId != null) {
70
+ error.incidentId = incidentId;
71
+ }
72
+ return Object.assign(error, { responseStatus: status });
73
+ };
74
+ /** One response header, from an `AxiosHeaders` instance or a plain header object alike. */
75
+ const headerOf = (headers, name) => {
76
+ if (headers == null || typeof headers !== 'object') {
77
+ return undefined;
78
+ }
79
+ const get = headers.get;
80
+ const viaGet = typeof get === 'function' ? get.call(headers, name) : undefined;
81
+ const value = viaGet ?? Object.entries(headers).find(([key]) => key.toLowerCase() === name.toLowerCase())?.[1];
82
+ const first = Array.isArray(value) ? value[0] : value;
83
+ return typeof first === 'string' && first.trim() !== '' ? first.trim() : undefined;
84
+ };
85
+ const processEmptyResponse = (response, reply, outcome) => {
86
+ if (response.data != null && response.data != '') {
87
+ reply.resolve(response.data, outcome);
88
+ return;
89
+ }
90
+ if (response.headers.toJSON != null && typeof response.headers.toJSON === 'function') {
91
+ reply.resolve(response.headers.toJSON(), outcome);
92
+ return;
93
+ }
94
+ reply.resolve(response.headers, outcome);
95
+ };
96
+ return { processResponse, statusError };
97
+ };
98
+ export const responseUtils = createResponseUtils();
99
+ //# sourceMappingURL=response.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"response.js","sourceRoot":"","sources":["../../src/utils/response.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@owlmeans/api",
3
- "version": "0.1.18-rc.45",
3
+ "version": "0.1.18-rc.47",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -29,22 +29,22 @@
29
29
  }
30
30
  },
31
31
  "dependencies": {
32
- "@owlmeans/auth-common": "^0.1.18-rc.45",
33
- "@owlmeans/client-config": "^0.1.18-rc.42",
34
- "@owlmeans/client-route": "^0.1.18-rc.46",
35
- "@owlmeans/config": "^0.1.18-rc.42",
36
- "@owlmeans/context": "^0.1.18-rc.32",
37
- "@owlmeans/entrypoint": "^0.1.18-rc.39",
38
- "@owlmeans/error": "^0.1.18-rc.36",
39
- "@owlmeans/log": "^0.1.18-rc.0",
40
- "@owlmeans/route": "^0.1.18-rc.33",
41
- "axios": "^1.7.7",
42
- "qs": "^6.13.0"
32
+ "@owlmeans/auth-common": "^0.1.18-rc.47",
33
+ "@owlmeans/client-config": "^0.1.18-rc.44",
34
+ "@owlmeans/client-route": "^0.1.18-rc.48",
35
+ "@owlmeans/config": "^0.1.18-rc.44",
36
+ "@owlmeans/context": "^0.1.18-rc.34",
37
+ "@owlmeans/entrypoint": "^0.1.18-rc.41",
38
+ "@owlmeans/error": "^0.1.18-rc.38",
39
+ "@owlmeans/log": "^0.1.18-rc.2",
40
+ "@owlmeans/route": "^0.1.18-rc.35",
41
+ "axios": "^1.20.0",
42
+ "qs": "^6.16.0"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@owlmeans/dep-config": "workspace:*",
46
- "@owlmeans/resource": "^0.1.18-rc.38",
47
- "@types/qs": "^6.9.16",
46
+ "@owlmeans/resource": "^0.1.18-rc.40",
47
+ "@types/qs": "^6.15.1",
48
48
  "nodemon": "^3.1.14",
49
49
  "typescript": "^7.0.2"
50
50
  },
package/src/index.ts CHANGED
@@ -3,6 +3,7 @@ export * from './consts.js'
3
3
  export * from './service.js'
4
4
  export type * from './types.js'
5
5
  export {
6
- httpStatusOf, incidentIdOf, isIncidentBody, parseClientMarker, API_CLIENT_MARKER, API_STATUS_MARKER,
6
+ httpStatusOf, apiStatusHelper, createApiStatusHelper, parseClientMarker, API_CLIENT_MARKER, API_STATUS_MARKER,
7
7
  } from './status/index.js'
8
- export type { ClientMarker, ResponseStatusCarrier } from './status/index.js'
8
+ export type { ClientMarker, ApiStatusHelper } 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
- import { extractParams } from '@owlmeans/client-route'
2
+ import { clientRouteHelper } 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
- import { processResponse } from './utils/handler.js'
11
- import { BasicClientConfig } from '@owlmeans/client-config'
8
+ import { responseUtils } from './utils/response.js'
12
9
  import { makeSecurityHelper } from '@owlmeans/config'
13
- import { AUTH_HEADER, DEF_AUTH_SRV, TOKEN_UPDATE } from '@owlmeans/auth-common'
14
- import type { AuthService } from '@owlmeans/auth-common'
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 { bodyUtils } 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, {
@@ -35,7 +28,7 @@ export const createApiService = (alias: string = DEFAULT_ALIAS): ApiClient => {
35
28
  const module = context.entrypoint<CommonEntrypoint>(request.alias)
36
29
  const route = module.route.route
37
30
  let path = module.path()
38
- const params = extractParams(path)
31
+ const params = clientRouteHelper.extractParams(path)
39
32
  path = params.reduce((path, param) => {
40
33
  type Key = keyof typeof request.params
41
34
  if (request.params[param as Key] == null) {
@@ -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 = bodyUtils.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 }
@@ -101,7 +94,7 @@ export const createApiService = (alias: string = DEFAULT_ALIAS): ApiClient => {
101
94
  await context.service<AuthService>(DEF_AUTH_SRV).update(undefined)
102
95
  }
103
96
 
104
- processResponse(response, reply)
97
+ responseUtils.processResponse(response, reply)
105
98
 
106
99
  return [reply.error ?? reply.value, reply.outcome] as any
107
100
  }
@@ -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 }
@@ -0,0 +1,5 @@
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:`