@venizia/ignis-kernel 0.2.1-3 → 0.2.1-5

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 (57) hide show
  1. package/dist/cjs/base/controllers/factory/controller.d.ts +56 -2
  2. package/dist/cjs/base/controllers/factory/controller.d.ts.map +1 -1
  3. package/dist/cjs/base/controllers/rest/base.d.ts +70 -3
  4. package/dist/cjs/base/controllers/rest/base.d.ts.map +1 -1
  5. package/dist/cjs/base/controllers/rest/base.js +30 -3
  6. package/dist/cjs/base/controllers/rest/base.js.map +1 -1
  7. package/dist/cjs/base/controllers/rest/extras.d.ts +49 -0
  8. package/dist/cjs/base/controllers/rest/extras.d.ts.map +1 -0
  9. package/dist/cjs/base/controllers/rest/extras.js +153 -0
  10. package/dist/cjs/base/controllers/rest/extras.js.map +1 -0
  11. package/dist/cjs/base/controllers/rest/index.d.ts +1 -0
  12. package/dist/cjs/base/controllers/rest/index.d.ts.map +1 -1
  13. package/dist/cjs/base/controllers/rest/index.js +1 -0
  14. package/dist/cjs/base/controllers/rest/index.js.map +1 -1
  15. package/dist/cjs/base/repositories/common/extra-request.d.ts +26 -0
  16. package/dist/cjs/base/repositories/common/extra-request.d.ts.map +1 -0
  17. package/dist/cjs/base/repositories/common/extra-request.js +21 -0
  18. package/dist/cjs/base/repositories/common/extra-request.js.map +1 -0
  19. package/dist/cjs/base/repositories/common/response-reader.d.ts +53 -0
  20. package/dist/cjs/base/repositories/common/response-reader.d.ts.map +1 -0
  21. package/dist/cjs/base/repositories/common/response-reader.js +100 -0
  22. package/dist/cjs/base/repositories/common/response-reader.js.map +1 -0
  23. package/dist/cjs/base/repositories/common/types/results.d.ts +2 -1
  24. package/dist/cjs/base/repositories/common/types/results.d.ts.map +1 -1
  25. package/dist/cjs/repository.d.ts +3 -0
  26. package/dist/cjs/repository.d.ts.map +1 -1
  27. package/dist/cjs/repository.js +7 -1
  28. package/dist/cjs/repository.js.map +1 -1
  29. package/dist/esm/base/controllers/factory/controller.d.ts +56 -2
  30. package/dist/esm/base/controllers/factory/controller.d.ts.map +1 -1
  31. package/dist/esm/base/controllers/rest/base.d.ts +70 -3
  32. package/dist/esm/base/controllers/rest/base.d.ts.map +1 -1
  33. package/dist/esm/base/controllers/rest/base.js +30 -3
  34. package/dist/esm/base/controllers/rest/base.js.map +1 -1
  35. package/dist/esm/base/controllers/rest/extras.d.ts +49 -0
  36. package/dist/esm/base/controllers/rest/extras.d.ts.map +1 -0
  37. package/dist/esm/base/controllers/rest/extras.js +149 -0
  38. package/dist/esm/base/controllers/rest/extras.js.map +1 -0
  39. package/dist/esm/base/controllers/rest/index.d.ts +1 -0
  40. package/dist/esm/base/controllers/rest/index.d.ts.map +1 -1
  41. package/dist/esm/base/controllers/rest/index.js +1 -0
  42. package/dist/esm/base/controllers/rest/index.js.map +1 -1
  43. package/dist/esm/base/repositories/common/extra-request.d.ts +26 -0
  44. package/dist/esm/base/repositories/common/extra-request.d.ts.map +1 -0
  45. package/dist/esm/base/repositories/common/extra-request.js +17 -0
  46. package/dist/esm/base/repositories/common/extra-request.js.map +1 -0
  47. package/dist/esm/base/repositories/common/response-reader.d.ts +53 -0
  48. package/dist/esm/base/repositories/common/response-reader.d.ts.map +1 -0
  49. package/dist/esm/base/repositories/common/response-reader.js +96 -0
  50. package/dist/esm/base/repositories/common/response-reader.js.map +1 -0
  51. package/dist/esm/base/repositories/common/types/results.d.ts +2 -1
  52. package/dist/esm/base/repositories/common/types/results.d.ts.map +1 -1
  53. package/dist/esm/repository.d.ts +3 -0
  54. package/dist/esm/repository.d.ts.map +1 -1
  55. package/dist/esm/repository.js +4 -0
  56. package/dist/esm/repository.js.map +1 -1
  57. package/package.json +2 -2
@@ -79,6 +79,9 @@ export declare class ControllerFactory extends BaseHelper {
79
79
  context: RequestContext;
80
80
  payload: ResponseData;
81
81
  }): ResponseData | import("@venizia/ignis-helpers/common").TNullable<ResponseSchema>;
82
+ getRequestedExtras(opts: {
83
+ context: import("../common").TRouteContext<RouteEnv>;
84
+ }): Array<import("..").IRequestedExtra>;
82
85
  respond<R>(opts: {
83
86
  context: import("../common").TRouteContext<RouteEnv>;
84
87
  format: import("../common").TResponseFormat;
@@ -87,10 +90,61 @@ export declare class ControllerFactory extends BaseHelper {
87
90
  data?: import("@venizia/ignis-helpers/common").TNullable<R>;
88
91
  };
89
92
  range?: import("../../repositories").TDataRange;
90
- }): import("@venizia/ignis-helpers/common").TNullable<R> | {
93
+ extra?: never;
94
+ }): R | {
91
95
  count: number;
92
96
  data?: import("@venizia/ignis-helpers/common").TNullable<R>;
93
- };
97
+ } | null | undefined;
98
+ respond<R, Extra extends Record<string, import("..").TResponseExtra>>(opts: {
99
+ context: import("../common").TRouteContext<RouteEnv>;
100
+ format: import("../common").TResponseFormat;
101
+ payload: {
102
+ count: number;
103
+ data?: import("@venizia/ignis-helpers/common").TNullable<R>;
104
+ };
105
+ range?: import("../../repositories").TDataRange;
106
+ extra: Extra;
107
+ }): Promise<R | {
108
+ count: number;
109
+ data?: import("@venizia/ignis-helpers/common").TNullable<R>;
110
+ } | {
111
+ count?: number;
112
+ data?: import("@venizia/ignis-helpers/common").TNullable<R>;
113
+ extra: Partial<Record<keyof Extra, unknown>>;
114
+ } | null | undefined>;
115
+ respond<R>(opts: {
116
+ context: import("../common").TRouteContext<RouteEnv>;
117
+ format: import("../common").TResponseFormat;
118
+ payload: {
119
+ count: number;
120
+ data?: import("@venizia/ignis-helpers/common").TNullable<R>;
121
+ };
122
+ range?: import("../../repositories").TDataRange;
123
+ extra?: Record<string, import("..").TResponseExtra>;
124
+ }): ValueOrPromise<R | {
125
+ count?: number;
126
+ data?: import("@venizia/ignis-helpers/common").TNullable<R>;
127
+ extra?: Record<string, unknown>;
128
+ } | null | undefined>;
129
+ respondWithExtra<R>(opts: {
130
+ context: import("../common").TRouteContext<RouteEnv>;
131
+ payload: {
132
+ count: number;
133
+ data?: import("@venizia/ignis-helpers/common").TNullable<R>;
134
+ };
135
+ extra: Record<string, import("..").TResponseExtra>;
136
+ }): Promise<R | {
137
+ count: number;
138
+ data?: import("@venizia/ignis-helpers/common").TNullable<R>;
139
+ } | {
140
+ count: number;
141
+ data: import("@venizia/ignis-helpers/common").TNullable<R>;
142
+ extra: Record<string, unknown>;
143
+ } | {
144
+ data: import("@venizia/ignis-helpers/common").TNullable<R>;
145
+ extra: Record<string, unknown>;
146
+ count?: undefined;
147
+ } | null | undefined>;
94
148
  setListHeaders(opts: {
95
149
  context: import("../common").TRouteContext<RouteEnv>;
96
150
  count: number;
@@ -1 +1 @@
1
- {"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../../../../src/base/controllers/factory/controller.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAC9D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2CAA2C,CAAC;AAClF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AACpE,OAAO,EAAE,UAAU,EAAY,MAAM,6BAA6B,CAAC;AAEnE,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AACxC,OAAO,KAAK,EACV,sBAAsB,EACtB,mBAAmB,EACnB,iBAAiB,EACjB,oBAAoB,EACrB,MAAM,WAAW,CAAC;AAKnB,6EAA6E;AAC7E,qBAAa,iBAAkB,SAAQ,UAAU;;IAK/C,MAAM,CAAC,oBAAoB,CACzB,OAAO,SAAS,cAAc,CAAC,gBAAgB,CAAC,GAAG,cAAc,CAAC,gBAAgB,CAAC,EACnF,MAAM,SAAS,mBAAmB,GAAG,mBAAmB,EACxD,QAAQ,SAAS,GAAG,GAAG,GAAG,EAC1B,WAAW,SAAS,MAAM,GAAG,EAAE,EAC/B,QAAQ,SAAS,MAAM,GAAG,GAAG,EAC7B,mBAAmB,SAAS,MAAM,GAAG,EAAE,EACvC,WAAW,SAAS,MAAM,GAAG,iBAAiB,CAAC,OAAO,CAAC,EACvD,cAAc,SAAS,MAAM,GAAG,oBAAoB,CAAC,OAAO,CAAC,EAC7D,OAAO,EAAE,sBAAsB,CAAC,OAAO,EAAE,MAAM,CAAC;yBAwCtB,kBAAkB,CAAC,WAAW,EAAE,cAAc,CAAC;YAUvE,iGAAiG;uBAC7E,cAAc,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBADkB,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyF/D"}
1
+ {"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../../../../src/base/controllers/factory/controller.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAC9D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2CAA2C,CAAC;AAClF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AACpE,OAAO,EAAE,UAAU,EAAY,MAAM,6BAA6B,CAAC;AAEnE,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AACxC,OAAO,KAAK,EACV,sBAAsB,EACtB,mBAAmB,EACnB,iBAAiB,EACjB,oBAAoB,EACrB,MAAM,WAAW,CAAC;AAKnB,6EAA6E;AAC7E,qBAAa,iBAAkB,SAAQ,UAAU;;IAK/C,MAAM,CAAC,oBAAoB,CACzB,OAAO,SAAS,cAAc,CAAC,gBAAgB,CAAC,GAAG,cAAc,CAAC,gBAAgB,CAAC,EACnF,MAAM,SAAS,mBAAmB,GAAG,mBAAmB,EACxD,QAAQ,SAAS,GAAG,GAAG,GAAG,EAC1B,WAAW,SAAS,MAAM,GAAG,EAAE,EAC/B,QAAQ,SAAS,MAAM,GAAG,GAAG,EAC7B,mBAAmB,SAAS,MAAM,GAAG,EAAE,EACvC,WAAW,SAAS,MAAM,GAAG,iBAAiB,CAAC,OAAO,CAAC,EACvD,cAAc,SAAS,MAAM,GAAG,oBAAoB,CAAC,OAAO,CAAC,EAC7D,OAAO,EAAE,sBAAsB,CAAC,OAAO,EAAE,MAAM,CAAC;yBAwCtB,kBAAkB,CAAC,WAAW,EAAE,cAAc,CAAC;YAUvE,iGAAiG;uBAC7E,cAAc,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBADkB,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyF/D"}
@@ -5,6 +5,7 @@ import type { Env, Schema } from 'hono';
5
5
  import type { TResponseFormat } from '../common/constants';
6
6
  import type { IAuthRouteConfig, IBindRouteOptions, IDefineRouteOptions, TRouteContext, TRouteHandler } from '../common/types';
7
7
  import { AbstractRestController } from './abstract';
8
+ import type { IRequestedExtra, TResponseExtra } from './extras';
8
9
  /** `Content-Range` of a page: inclusive `end`, and `records * /<total>` (no space) when the page is empty. Exported so a route that writes the header itself uses the one formatter. */
9
10
  export declare const toContentRange: (opts: {
10
11
  range: TDataRange;
@@ -29,7 +30,21 @@ export declare abstract class BaseRestController<RouteEnv extends Env = Env, Rou
29
30
  context: RequestContext;
30
31
  payload: ResponseData;
31
32
  }): TNullable<ResponseSchema> | ResponseData;
32
- /** The one response call. Sets `X-Response-Format`, and with `range` (a list) also `Content-Range` - `payload.count` is the rows of THIS response, never the total - then normalizes count/data per the request-count header. */
33
+ /** `x-request-extra`, parsed: `name`, `-name` (a default switched off) and `name(key,key)`. */
34
+ getRequestedExtras(opts: {
35
+ context: TRouteContext<RouteEnv>;
36
+ }): Array<IRequestedExtra>;
37
+ /**
38
+ * The one response call. Sets `X-Response-Format`, and with `range` (a list) also `Content-Range` -
39
+ * `payload.count` is the rows of THIS response, never the total - then normalizes count/data per
40
+ * the request-count header.
41
+ *
42
+ * `extra` offers figures beside the rows (see {@link TResponseExtra}): each runs when the client
43
+ * names it in `x-request-extra`, or always when it is a default. When any runs, the body is
44
+ * `{ data, extra }` (with `count` when it is requested); when none does, nothing is computed and the
45
+ * body is what it would be without `extra`. A name the route does not offer is a 400 listing the
46
+ * ones it does.
47
+ */
33
48
  respond<R>(opts: {
34
49
  context: TRouteContext<RouteEnv>;
35
50
  format: TResponseFormat;
@@ -38,10 +53,62 @@ export declare abstract class BaseRestController<RouteEnv extends Env = Env, Rou
38
53
  data?: TNullable<R>;
39
54
  };
40
55
  range?: TDataRange;
41
- }): TNullable<R> | {
56
+ extra?: never;
57
+ }): R | {
58
+ count: number;
59
+ data?: TNullable<R>;
60
+ } | null | undefined;
61
+ respond<R, Extra extends Record<string, TResponseExtra>>(opts: {
62
+ context: TRouteContext<RouteEnv>;
63
+ format: TResponseFormat;
64
+ payload: {
65
+ count: number;
66
+ data?: TNullable<R>;
67
+ };
68
+ range?: TDataRange;
69
+ extra: Extra;
70
+ }): Promise<R | {
42
71
  count: number;
43
72
  data?: TNullable<R>;
44
- };
73
+ } | {
74
+ count?: number;
75
+ data?: TNullable<R>;
76
+ extra: Partial<Record<keyof Extra, unknown>>;
77
+ } | null | undefined>;
78
+ respond<R>(opts: {
79
+ context: TRouteContext<RouteEnv>;
80
+ format: TResponseFormat;
81
+ payload: {
82
+ count: number;
83
+ data?: TNullable<R>;
84
+ };
85
+ range?: TDataRange;
86
+ extra?: Record<string, TResponseExtra>;
87
+ }): ValueOrPromise<R | {
88
+ count?: number;
89
+ data?: TNullable<R>;
90
+ extra?: Record<string, unknown>;
91
+ } | null | undefined>;
92
+ /** The `extra` half of `respond`: resolves what was asked against what is offered, runs it in parallel. */
93
+ respondWithExtra<R>(opts: {
94
+ context: TRouteContext<RouteEnv>;
95
+ payload: {
96
+ count: number;
97
+ data?: TNullable<R>;
98
+ };
99
+ extra: Record<string, TResponseExtra>;
100
+ }): Promise<R | {
101
+ count: number;
102
+ data?: TNullable<R>;
103
+ } | {
104
+ count: number;
105
+ data: TNullable<R>;
106
+ extra: Record<string, unknown>;
107
+ } | {
108
+ data: TNullable<R>;
109
+ extra: Record<string, unknown>;
110
+ count?: undefined;
111
+ } | null | undefined>;
45
112
  /** The list headers without the body, for a list whose body is not a `{ count, data }` envelope: `Content-Range`, `X-Response-Count` = rows in THIS response, `X-Response-Format: array`. Pass a `range`, or `offset` + `total` for an engine that reports those (a search page): the range is derived with the same inclusive-end rule. */
46
113
  setListHeaders(opts: {
47
114
  context: TRouteContext<RouteEnv>;
@@ -1 +1 @@
1
- {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../../../src/base/controllers/rest/base.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAE3D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;AACnE,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAGxF,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAExC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,KAAK,EACV,gBAAgB,EAChB,iBAAiB,EACjB,mBAAmB,EACnB,aAAa,EACb,aAAa,EACd,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAEpD,wLAAwL;AACxL,eAAO,MAAM,cAAc,GAAI,MAAM;IAAE,KAAK,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,KAAG,MAI3E,CAAC;AAEF,2GAA2G;AAC3G,8BAAsB,kBAAkB,CACtC,QAAQ,SAAS,GAAG,GAAG,GAAG,EAC1B,WAAW,SAAS,MAAM,GAAG,EAAE,EAC/B,QAAQ,SAAS,MAAM,GAAG,GAAG,EAC7B,mBAAmB,SAAS,MAAM,GAAG,EAAE,EACvC,WAAW,SAAS,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CACvF,SAAQ,sBAAsB,CAC9B,QAAQ,EACR,WAAW,EACX,QAAQ,EACR,mBAAmB,EACnB,WAAW,CACZ;IACC,0FAA0F;IAC1F,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,CAAA;KAAE;IAWzE,uJAAuJ;IACvJ,kBAAkB,CAChB,cAAc,SAAS,OAAO,EAC9B,cAAc,SAAS,aAAa,CAAC,QAAQ,CAAC,GAAG,aAAa,CAAC,QAAQ,CAAC,EACxE,YAAY,SAAS;QACnB,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,CAAC,EAAE,SAAS,CAAC,cAAc,CAAC,CAAC;KAClC,GAAG;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,SAAS,CAAC,cAAc,CAAC,CAAA;KAAE,EACvD,IAAI,EAAE;QAAE,OAAO,EAAE,cAAc,CAAC;QAAC,OAAO,EAAE,YAAY,CAAA;KAAE;IAc1D,iOAAiO;IACjO,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE;QACf,OAAO,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;QACjC,MAAM,EAAE,eAAe,CAAC;QACxB,OAAO,EAAE;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,IAAI,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,CAAA;SAAE,CAAC;QAChD,KAAK,CAAC,EAAE,UAAU,CAAC;KACpB;eArBc,MAAM;;;IAgCrB,4UAA4U;IAC5U,cAAc,CACZ,IAAI,EAAE;QAAE,OAAO,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,CAC1D;QAAE,KAAK,EAAE,UAAU,CAAA;KAAE,GAAG;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAC1D;IAaH,mPAAmP;IACnP,aAAa,CAAC,YAAY,GAAG,OAAO,EAAE,IAAI,EAAE;QAAE,OAAO,EAAE,aAAa,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAA;KAAE,GACrE,UAAU,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;IAGxE,uFAAuF;IACvF,SAAS,CAAC,WAAW,SAAS,gBAAgB,EAAE,IAAI,EAAE;QACpD,OAAO,EAAE,WAAW,CAAC;KACtB,GAAG,iBAAiB,CAAC,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,CAAC;IAcnE,uEAAuE;IACvE,WAAW,CAAC,WAAW,SAAS,gBAAgB,EAAE,YAAY,GAAG,OAAO,EAAE,IAAI,EAAE;QAC9E,OAAO,EAAE,WAAW,CAAC;QACrB,OAAO,EAAE,aAAa,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;QAC/C,IAAI,CAAC,EAAE,IAAI,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC;KACzD,GAAG,mBAAmB,CAAC,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,CAAC;IAarE,sEAAsE;IACtE,cAAc,CAAC,WAAW,SAAS,gBAAgB,EAAE,YAAY,GAAG,OAAO,EAAE,IAAI,EAAE;QACjF,OAAO,EAAE,WAAW,CAAC;QACrB,OAAO,EAAE,aAAa,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;QAC/C,IAAI,CAAC,EAAE,IAAI,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC;KACzD,GAAG,mBAAmB,CAAC,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,CAAC;CAYtE"}
1
+ {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../../../src/base/controllers/rest/base.ts"],"names":[],"mappings":"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"}
@@ -6,6 +6,7 @@ const common_1 = require("@venizia/ignis-helpers/common");
6
6
  const core_1 = require("@venizia/ignis-helpers/core");
7
7
  const constants_1 = require("../common/constants");
8
8
  const abstract_1 = require("./abstract");
9
+ const extras_1 = require("./extras");
9
10
  /** `Content-Range` of a page: inclusive `end`, and `records * /<total>` (no space) when the page is empty. Exported so a route that writes the header itself uses the one formatter. */
10
11
  const toContentRange = (opts) => {
11
12
  const { range, count } = opts;
@@ -37,14 +38,40 @@ class BaseRestController extends abstract_1.AbstractRestController {
37
38
  }
38
39
  return payload.data;
39
40
  }
40
- /** The one response call. Sets `X-Response-Format`, and with `range` (a list) also `Content-Range` - `payload.count` is the rows of THIS response, never the total - then normalizes count/data per the request-count header. */
41
+ /** `x-request-extra`, parsed: `name`, `-name` (a default switched off) and `name(key,key)`. */
42
+ getRequestedExtras(opts) {
43
+ return extras_1.ResponseExtras.parse({ header: opts.context.req.header(common_1.HTTP.Headers.REQUEST_EXTRA) });
44
+ }
41
45
  respond(opts) {
42
- const { context, format, payload, range } = opts;
46
+ const { context, format, payload, range, extra } = opts;
43
47
  if (range) {
44
48
  context.header(common_1.HTTP.Headers.CONTENT_RANGE, (0, exports.toContentRange)({ range, count: payload.count }));
45
49
  }
46
50
  context.header(common_1.HTTP.Headers.RESPONSE_FORMAT, format);
47
- return this.normalizeCountData({ context, payload });
51
+ if (!extra) {
52
+ return this.normalizeCountData({ context, payload });
53
+ }
54
+ return this.respondWithExtra({ context, payload, extra });
55
+ }
56
+ /** The `extra` half of `respond`: resolves what was asked against what is offered, runs it in parallel. */
57
+ async respondWithExtra(opts) {
58
+ const { context, payload, extra } = opts;
59
+ const plan = extras_1.ResponseExtras.resolve({
60
+ requested: this.getRequestedExtras({ context }),
61
+ offered: extra,
62
+ });
63
+ if (plan.size === 0) {
64
+ return this.normalizeCountData({ context, payload });
65
+ }
66
+ const computed = await extras_1.ResponseExtras.compute({ plan, offered: extra });
67
+ // Rows still counted in the header; the body is an object, since an array cannot carry extras.
68
+ // `x-response-extra` marks it, so a client unwraps `{ data, extra }` only when the server says so.
69
+ context.header(common_1.HTTP.Headers.RESPONSE_COUNT_DATA, payload.count.toString());
70
+ context.header(common_1.HTTP.Headers.RESPONSE_EXTRA, Object.keys(computed).join(','));
71
+ const useCountData = (0, core_1.toBoolean)(context.req.header(common_1.HTTP.Headers.REQUEST_COUNT_DATA) ?? 'true');
72
+ return useCountData
73
+ ? { count: payload.count, data: payload.data, extra: computed }
74
+ : { data: payload.data, extra: computed };
48
75
  }
49
76
  /** The list headers without the body, for a list whose body is not a `{ count, data }` envelope: `Content-Range`, `X-Response-Count` = rows in THIS response, `X-Response-Format: array`. Pass a `range`, or `offset` + `total` for an engine that reports those (a search page): the range is derived with the same inclusive-end rule. */
50
77
  setListHeaders(opts) {
@@ -1 +1 @@
1
- {"version":3,"file":"base.js","sourceRoot":"","sources":["../../../../../src/base/controllers/rest/base.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"base.js","sourceRoot":"","sources":["../../../../../src/base/controllers/rest/base.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ import type { ValueOrPromise } from '@venizia/ignis-helpers/common';
2
+ /**
3
+ * A figure a list route offers beside its rows:
4
+ * - a function runs when the client names it;
5
+ * - `{ isDefault: true, compute }` always runs, unless the client switches it off with `-name`;
6
+ * - `{ keys, compute }` is a group - the client names the keys it wants (`facets(status,tag)`), and
7
+ * `compute` receives exactly those, so one aggregate pass serves them all.
8
+ */
9
+ export type TResponseExtra = (() => ValueOrPromise<unknown>) | {
10
+ isDefault: boolean;
11
+ compute: () => ValueOrPromise<unknown>;
12
+ keys?: never;
13
+ } | {
14
+ keys: ReadonlyArray<string>;
15
+ compute: (opts: {
16
+ keys: Array<string>;
17
+ }) => ValueOrPromise<unknown>;
18
+ isDefault?: never;
19
+ };
20
+ /** One entry of `x-request-extra`: `name`, `-name` (a default switched off), `-*` (every default off) or `name(key,key)`. */
21
+ export interface IRequestedExtra {
22
+ name: string;
23
+ isExcluded: boolean;
24
+ keys?: Array<string>;
25
+ }
26
+ /** Parses `x-request-extra` and resolves it against what a route offers. */
27
+ export declare class ResponseExtras {
28
+ /** The entries of the header, in the order written. Malformed input is a 400 naming it. */
29
+ static parse(opts: {
30
+ header?: string | null;
31
+ }): Array<IRequestedExtra>;
32
+ /**
33
+ * What to compute: the asked-for extras and the defaults, minus the ones switched off - each with the
34
+ * keys asked for, de-duplicated in the order asked. Every name and key is checked against `offered`.
35
+ */
36
+ static resolve(opts: {
37
+ requested: Array<IRequestedExtra>;
38
+ offered: Record<string, TResponseExtra>;
39
+ }): Map<string, Array<string> | undefined>;
40
+ /** Runs the plan in parallel; each value under its name. */
41
+ static compute(opts: {
42
+ plan: Map<string, Array<string> | undefined>;
43
+ offered: Record<string, TResponseExtra>;
44
+ }): Promise<Record<string, unknown>>;
45
+ /** Commas inside `( )` belong to the keys, not to the list of extras. */
46
+ private static splitTopLevel;
47
+ private static badRequest;
48
+ }
49
+ //# sourceMappingURL=extras.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extras.d.ts","sourceRoot":"","sources":["../../../../../src/base/controllers/rest/extras.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAIpE;;;;;;GAMG;AACH,MAAM,MAAM,cAAc,GACtB,CAAC,MAAM,cAAc,CAAC,OAAO,CAAC,CAAC,GAC/B;IAAE,SAAS,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,cAAc,CAAC,OAAO,CAAC,CAAC;IAAC,IAAI,CAAC,EAAE,KAAK,CAAA;CAAE,GAC5E;IACE,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAC5B,OAAO,EAAE,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,CAAA;KAAE,KAAK,cAAc,CAAC,OAAO,CAAC,CAAC;IACpE,SAAS,CAAC,EAAE,KAAK,CAAC;CACnB,CAAC;AAEN,6HAA6H;AAC7H,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,OAAO,CAAC;IACpB,IAAI,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;CACtB;AASD,4EAA4E;AAC5E,qBAAa,cAAc;IACzB,2FAA2F;IAC3F,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,KAAK,CAAC,eAAe,CAAC;IAmCtE;;;OAGG;IACH,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE;QACnB,SAAS,EAAE,KAAK,CAAC,eAAe,CAAC,CAAC;QAClC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;KACzC,GAAG,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC;IA6E1C,4DAA4D;WAC/C,OAAO,CAAC,IAAI,EAAE;QACzB,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC,CAAC;QAC7C,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;KACzC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAyBpC,yEAAyE;IACzE,OAAO,CAAC,MAAM,CAAC,aAAa;IAyB5B,OAAO,CAAC,MAAM,CAAC,UAAU;CAM1B"}
@@ -0,0 +1,153 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ResponseExtras = void 0;
4
+ const common_1 = require("@venizia/ignis-helpers/common");
5
+ const core_1 = require("@venizia/ignis-helpers/core");
6
+ /** A name or a key: letters, digits, `_`, `.` and `-` inside. Anything else is refused, never evaluated. */
7
+ const IDENTIFIER = /^[A-Za-z_][\w.-]*$/;
8
+ const ENTRY = /^(-?)([^()\s]+)(?:\(([^()]*)\))?$/;
9
+ /** `-*`: every default off - for a read that wants the rows alone. */
10
+ const ALL_DEFAULTS = '*';
11
+ /** Parses `x-request-extra` and resolves it against what a route offers. */
12
+ class ResponseExtras {
13
+ /** The entries of the header, in the order written. Malformed input is a 400 naming it. */
14
+ static parse(opts) {
15
+ const header = opts.header?.trim() ?? '';
16
+ if (header === '') {
17
+ return [];
18
+ }
19
+ const entries = [];
20
+ for (const raw of ResponseExtras.splitTopLevel({ header })) {
21
+ const match = raw.trim().match(ENTRY);
22
+ const name = match?.[2];
23
+ const isAllDefaultsOff = match?.[1] === '-' && name === ALL_DEFAULTS && match[3] === undefined;
24
+ if (!match || !name || (!isAllDefaultsOff && !IDENTIFIER.test(name))) {
25
+ throw ResponseExtras.badRequest({ message: `Malformed extra '${raw.trim()}'` });
26
+ }
27
+ const keys = match[3] === undefined
28
+ ? undefined
29
+ : match[3]
30
+ .split(',')
31
+ .map(key => key.trim())
32
+ .filter(key => key.length > 0);
33
+ if (keys?.some(key => !IDENTIFIER.test(key))) {
34
+ throw ResponseExtras.badRequest({ message: `Malformed key in extra '${raw.trim()}'` });
35
+ }
36
+ entries.push({ name, isExcluded: match[1] === '-', keys });
37
+ }
38
+ return entries;
39
+ }
40
+ /**
41
+ * What to compute: the asked-for extras and the defaults, minus the ones switched off - each with the
42
+ * keys asked for, de-duplicated in the order asked. Every name and key is checked against `offered`.
43
+ */
44
+ static resolve(opts) {
45
+ const { requested, offered } = opts;
46
+ const offeredNames = Object.keys(offered).join(', ') || 'none';
47
+ const plan = new Map();
48
+ const excluded = new Set();
49
+ let isEveryDefaultOff = false;
50
+ for (const entry of requested) {
51
+ if (entry.isExcluded && entry.name === ALL_DEFAULTS) {
52
+ isEveryDefaultOff = true;
53
+ continue;
54
+ }
55
+ if (!Object.hasOwn(offered, entry.name)) {
56
+ throw ResponseExtras.badRequest({
57
+ message: `Unknown extra requested: ${entry.name} | This route offers: ${offeredNames}`,
58
+ });
59
+ }
60
+ if (entry.isExcluded) {
61
+ if (entry.keys !== undefined) {
62
+ throw ResponseExtras.badRequest({
63
+ message: `Switching '${entry.name}' off takes no keys`,
64
+ });
65
+ }
66
+ excluded.add(entry.name);
67
+ continue;
68
+ }
69
+ const definition = offered[entry.name];
70
+ const isGroup = typeof definition !== 'function' && definition.keys !== undefined;
71
+ if (!isGroup) {
72
+ if (entry.keys !== undefined) {
73
+ throw ResponseExtras.badRequest({ message: `Extra '${entry.name}' takes no keys` });
74
+ }
75
+ plan.set(entry.name, undefined);
76
+ continue;
77
+ }
78
+ if (!entry.keys?.length) {
79
+ throw ResponseExtras.badRequest({
80
+ message: `Extra '${entry.name}' needs keys: ${definition.keys.join(', ')} | Name them as ${entry.name}(key,key)`,
81
+ });
82
+ }
83
+ const unknown = entry.keys.filter(key => !definition.keys.includes(key));
84
+ if (unknown.length > 0) {
85
+ throw ResponseExtras.badRequest({
86
+ message: `Unknown key for extra '${entry.name}': ${unknown.join(', ')} | It offers: ${definition.keys.join(', ')}`,
87
+ });
88
+ }
89
+ plan.set(entry.name, [...new Set([...(plan.get(entry.name) ?? []), ...entry.keys])]);
90
+ }
91
+ for (const [name, definition] of Object.entries(offered)) {
92
+ // A group needs keys, so it never runs unasked, whatever its declaration claims.
93
+ const isDefault = typeof definition !== 'function' &&
94
+ definition.keys === undefined &&
95
+ definition.isDefault === true;
96
+ if (isDefault && !isEveryDefaultOff && !plan.has(name)) {
97
+ plan.set(name, undefined);
98
+ }
99
+ }
100
+ for (const name of excluded) {
101
+ plan.delete(name);
102
+ }
103
+ return plan;
104
+ }
105
+ /** Runs the plan in parallel; each value under its name. */
106
+ static async compute(opts) {
107
+ const { plan, offered } = opts;
108
+ const names = [...plan.keys()];
109
+ // Async, so an extra that throws synchronously becomes a rejection Promise.all owns, never an
110
+ // unhandled one left behind by a sibling already running.
111
+ const values = await Promise.all(names.map(async (name) => {
112
+ const definition = offered[name];
113
+ if (typeof definition === 'function') {
114
+ return definition();
115
+ }
116
+ if (definition.keys !== undefined) {
117
+ return definition.compute({ keys: plan.get(name) ?? [] });
118
+ }
119
+ return definition.compute();
120
+ }));
121
+ return Object.fromEntries(names.map((name, index) => [name, values[index]]));
122
+ }
123
+ /** Commas inside `( )` belong to the keys, not to the list of extras. */
124
+ static splitTopLevel(opts) {
125
+ const parts = [];
126
+ let depth = 0;
127
+ let current = '';
128
+ for (const character of opts.header) {
129
+ if (character === '(') {
130
+ depth++;
131
+ }
132
+ else if (character === ')') {
133
+ depth--;
134
+ }
135
+ if (character === ',' && depth === 0) {
136
+ parts.push(current);
137
+ current = '';
138
+ continue;
139
+ }
140
+ current += character;
141
+ }
142
+ parts.push(current);
143
+ return parts.filter(part => part.trim().length > 0);
144
+ }
145
+ static badRequest(opts) {
146
+ return (0, core_1.getError)({
147
+ statusCode: common_1.HTTP.ResultCodes.RS_4.BadRequest,
148
+ message: `[x-request-extra] ${opts.message}`,
149
+ });
150
+ }
151
+ }
152
+ exports.ResponseExtras = ResponseExtras;
153
+ //# sourceMappingURL=extras.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extras.js","sourceRoot":"","sources":["../../../../../src/base/controllers/rest/extras.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
1
  export * from './abstract';
2
2
  export * from './base';
3
+ export * from './extras';
3
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/base/controllers/rest/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,QAAQ,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/base/controllers/rest/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,QAAQ,CAAC;AACvB,cAAc,UAAU,CAAC"}
@@ -16,4 +16,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./abstract"), exports);
18
18
  __exportStar(require("./base"), exports);
19
+ __exportStar(require("./extras"), exports);
19
20
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/base/controllers/rest/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,6CAA2B;AAC3B,yCAAuB"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/base/controllers/rest/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,6CAA2B;AAC3B,yCAAuB;AACvB,2CAAyB"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * The extras a client asks for, by name: `true` asks for a plain extra, a list of keys asks for a
3
+ * group (`facets: ['status', 'tag']`), `false` switches a default off.
4
+ */
5
+ export type TExtraRequest = Record<string, boolean | ReadonlyArray<string>>;
6
+ /**
7
+ * What may come back for `Extra`: a group keyed by the keys asked for. Every entry is optional - a
8
+ * route that offers no extras, or an older server, answers none - and the route may add defaults.
9
+ */
10
+ export type TExtraResult<Extra extends TExtraRequest> = {
11
+ [K in keyof Extra as Extra[K] extends false ? never : K]?: Extra[K] extends ReadonlyArray<infer Key extends string> ? Record<Key, unknown> : unknown;
12
+ } & Record<string, unknown>;
13
+ /** The client half of the list-extras contract: what goes in `x-request-extra`. */
14
+ export declare class HttpExtraRequest {
15
+ /**
16
+ * The header value for what a call asks for - `name`, `-name`, `name(key,key)` - led by `-*` when
17
+ * the call wants the rows alone, every default off. `undefined` when it asks for nothing.
18
+ */
19
+ static toHeader(opts: {
20
+ extra?: TExtraRequest;
21
+ isEveryDefaultOff?: boolean;
22
+ }): string | undefined;
23
+ /** The header name, for a client that sets headers itself. */
24
+ static readonly HEADER: "x-request-extra";
25
+ }
26
+ //# sourceMappingURL=extra-request.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extra-request.d.ts","sourceRoot":"","sources":["../../../../../src/base/repositories/common/extra-request.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC;AAE5E;;;GAGG;AACH,MAAM,MAAM,YAAY,CAAC,KAAK,SAAS,aAAa,IAAI;KACrD,CAAC,IAAI,MAAM,KAAK,IAAI,KAAK,CAAC,CAAC,CAAC,SAAS,KAAK,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,SAAS,aAAa,CACvF,MAAM,GAAG,SAAS,MAAM,CACzB,GACG,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,GACpB,OAAO;CACZ,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE5B,mFAAmF;AACnF,qBAAa,gBAAgB;IAC3B;;;OAGG;IACH,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE;QACpB,KAAK,CAAC,EAAE,aAAa,CAAC;QACtB,iBAAiB,CAAC,EAAE,OAAO,CAAC;KAC7B,GAAG,MAAM,GAAG,SAAS;IAWtB,8DAA8D;IAC9D,MAAM,CAAC,QAAQ,CAAC,MAAM,oBAA8B;CACrD"}
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HttpExtraRequest = void 0;
4
+ const common_1 = require("@venizia/ignis-helpers/common");
5
+ /** The client half of the list-extras contract: what goes in `x-request-extra`. */
6
+ class HttpExtraRequest {
7
+ /**
8
+ * The header value for what a call asks for - `name`, `-name`, `name(key,key)` - led by `-*` when
9
+ * the call wants the rows alone, every default off. `undefined` when it asks for nothing.
10
+ */
11
+ static toHeader(opts) {
12
+ const { extra = {}, isEveryDefaultOff = false } = opts;
13
+ const entries = Object.entries(extra).map(([name, value]) => value === true ? name : value === false ? `-${name}` : `${name}(${value.join(',')})`);
14
+ const tokens = isEveryDefaultOff ? ['-*', ...entries] : entries;
15
+ return tokens.length > 0 ? tokens.join(',') : undefined;
16
+ }
17
+ /** The header name, for a client that sets headers itself. */
18
+ static { this.HEADER = common_1.HTTP.Headers.REQUEST_EXTRA; }
19
+ }
20
+ exports.HttpExtraRequest = HttpExtraRequest;
21
+ //# sourceMappingURL=extra-request.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extra-request.js","sourceRoot":"","sources":["../../../../../src/base/repositories/common/extra-request.ts"],"names":[],"mappings":";;;AAAA,0DAAqD;AAoBrD,mFAAmF;AACnF,MAAa,gBAAgB;IAC3B;;;OAGG;IACH,MAAM,CAAC,QAAQ,CAAC,IAGf;QACC,MAAM,EAAE,KAAK,GAAG,EAAE,EAAE,iBAAiB,GAAG,KAAK,EAAE,GAAG,IAAI,CAAC;QAEvD,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAC1D,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CACrF,CAAC;QACF,MAAM,MAAM,GAAG,iBAAiB,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;QAEhE,OAAO,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC1D,CAAC;IAED,8DAA8D;aAC9C,WAAM,GAAG,aAAI,CAAC,OAAO,CAAC,aAAa,CAAC;;AApBtD,4CAqBC"}
@@ -0,0 +1,53 @@
1
+ import type { TResponsedError } from '@venizia/ignis-helpers/core';
2
+ /**
3
+ * What an IGNIS server answers - `Content-Range`, the error envelope - read once, here, for every
4
+ * client of that server: the http connector, and a client that reads it without the connector.
5
+ */
6
+ export declare class HttpResponseReader {
7
+ static isPlainObject(value: unknown): value is Record<string, unknown>;
8
+ /** An empty string reads as absent, so a fallback still applies. */
9
+ static toText(value: unknown): string | undefined;
10
+ /**
11
+ * A `Content-Range` header as the IGNIS server writes it: `records 0-24/137` -> skip 0, total 137;
12
+ * an empty page, `records *\/137` -> total 137. Anything else, including an absent header or an
13
+ * unknown total, is `undefined`.
14
+ */
15
+ static parseContentRange(opts: {
16
+ header?: string | null;
17
+ }): {
18
+ skip?: number;
19
+ total: number;
20
+ } | undefined;
21
+ /**
22
+ * The IGNIS error envelope - `{ message, statusCode, normalized: { text, code, args }, requestId,
23
+ * extra, details }` - read off a parsed response body. A server configured with `error.rootKey`
24
+ * wraps it under that key; pass the same `rootKey` to unwrap it. A body without that key, or with a
25
+ * non-object under it (a proxy's `{ error: 'Bad Gateway' }`), is read as it stands.
26
+ *
27
+ * A body that is not a plain object yields `{}`; any other body yields its known fields, each
28
+ * `undefined` when absent or mistyped. An empty string reads as absent.
29
+ */
30
+ static readErrorEnvelope(opts: {
31
+ body: unknown;
32
+ rootKey?: string;
33
+ }): TResponsedError;
34
+ /** A failed response's envelope. A body that is not JSON yields `{}`, and the status alone still describes it. */
35
+ static readError(opts: {
36
+ response: Response;
37
+ rootKey?: string;
38
+ }): Promise<TResponsedError>;
39
+ /**
40
+ * A body the server marked with `x-response-extra` carries `extra` beside its rows. `body` is what
41
+ * the route answers without extras: the `{ count, data }` envelope when the count was asked for in
42
+ * the body, the rows otherwise. Any other body is returned as it stands - an unmarked object is
43
+ * never unwrapped, so a row that has `data` and `extra` columns of its own is never misread.
44
+ */
45
+ static readExtra(opts: {
46
+ body: unknown;
47
+ headers: Pick<Headers, 'has'>;
48
+ }): {
49
+ body: unknown;
50
+ extra?: Record<string, unknown>;
51
+ };
52
+ }
53
+ //# sourceMappingURL=response-reader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"response-reader.d.ts","sourceRoot":"","sources":["../../../../../src/base/repositories/common/response-reader.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAEnE;;;GAGG;AACH,qBAAa,kBAAkB;IAC7B,MAAM,CAAC,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAMtE,oEAAoE;IACpE,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS;IAIjD;;;;OAIG;IACH,MAAM,CAAC,iBAAiB,CAAC,IAAI,EAAE;QAC7B,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KACxB,GAAG;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS;IAoBhD;;;;;;;;OAQG;IACH,MAAM,CAAC,iBAAiB,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,eAAe;IA4BpF,kHAAkH;WACrG,SAAS,CAAC,IAAI,EAAE;QAAE,QAAQ,EAAE,QAAQ,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,eAAe,CAAC;IAahG;;;;;OAKG;IACH,MAAM,CAAC,SAAS,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;KAAE,GAAG;QACxE,IAAI,EAAE,OAAO,CAAC;QACd,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACjC;CAeF"}