@fjell/express-router 4.4.24 → 4.4.26

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.
@@ -37,7 +37,7 @@ class CItemRouter extends ItemRouter {
37
37
  ), this.getPkType());
38
38
  item = await this.postCreateItem(item);
39
39
  this.logger.default("Created Item %j", item);
40
- res.json(item);
40
+ res.status(201).json(item);
41
41
  } catch (err) {
42
42
  if (err instanceof NotFoundError) {
43
43
  this.logger.error("Item Not Found for Create", { message: err?.message, stack: err?.stack });
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/CItemRouter.ts"],
4
- "sourcesContent": ["import {\n ComKey, Item, ItemQuery, LocKey, LocKeyArray, paramsToQuery, PriKey, QueryParams, validatePK\n} from \"@fjell/core\";\nimport { NotFoundError } from \"@fjell/lib\";\nimport { Request, Response } from \"express\";\nimport { ItemRouter, ItemRouterOptions } from \"./ItemRouter.js\";\nimport { Instance } from \"./Instance.js\";\n\ninterface ParsedQuery {\n [key: string]: undefined | string | string[] | ParsedQuery | ParsedQuery[];\n}\n\nexport class CItemRouter<\n T extends Item<S, L1, L2, L3, L4, L5>,\n S extends string,\n L1 extends string,\n L2 extends string = never,\n L3 extends string = never,\n L4 extends string = never,\n L5 extends string = never\n> extends ItemRouter<S, L1, L2, L3, L4, L5> {\n\n private parentRoute: ItemRouter<L1, L2, L3, L4, L5, never>;\n\n constructor(\n lib: Instance<T, S, L1, L2, L3, L4, L5>,\n type: S,\n parentRoute: ItemRouter<L1, L2, L3, L4, L5, never>,\n options: ItemRouterOptions<S, L1, L2, L3, L4, L5> = {},\n ) {\n super(lib as any, type, options);\n this.parentRoute = parentRoute;\n }\n\n public hasParent(): boolean {\n return !!this.parentRoute;\n }\n\n public getIk(res: Response): ComKey<S, L1, L2, L3, L4, L5> {\n const pri = this.getPk(res) as PriKey<S>;\n const loc = this.getLocations(res) as LocKeyArray<L1, L2, L3, L4, L5>;\n return { kt: pri.kt, pk: pri.pk, loc }\n }\n\n public getLKA(res: Response): LocKeyArray<S, L1, L2, L3, L4> {\n /**\n * A location key array is passed to a child router to provide contextfor the items it will\n * be working with. It is always a concatenation of \"My LKA\" + \"Parent LKA\" which will\n * bubble all the way up to the root Primary.\n */\n let lka: LocKey<S | L1 | L2 | L3 | L4>[] = [this.getLk(res)];\n lka = lka.concat(this.parentRoute.getLKA(res) as LocKey<S | L1 | L2 | L3 | L4>[]);\n return lka as LocKeyArray<S, L1, L2, L3, L4>;\n }\n\n public getLocations(res: Response): LocKeyArray<L1, L2, L3, L4, L5> {\n return this.parentRoute.getLKA(res) as LocKeyArray<L1, L2, L3, L4, L5>;\n }\n\n protected createItem = async (req: Request, res: Response) => {\n const libOperations = this.lib.operations;\n this.logger.default('Creating Item', { body: req?.body, query: req?.query, params: req?.params, locals: res?.locals });\n try {\n const itemToCreate = this.convertDates(req.body as Item<S, L1, L2, L3, L4, L5>);\n let item = validatePK(await libOperations.create(\n itemToCreate, { locations: this.getLocations(res) }), this.getPkType()) as Item<S, L1, L2, L3, L4, L5>;\n item = await this.postCreateItem(item);\n this.logger.default('Created Item %j', item);\n res.json(item);\n } catch (err: any) {\n if (err instanceof NotFoundError) {\n this.logger.error('Item Not Found for Create', { message: err?.message, stack: err?.stack });\n res.status(404).json({\n message: \"Item Not Found\",\n });\n } else {\n this.logger.error('General Error in Create', { message: err?.message, stack: err?.stack });\n res.status(500).json({\n message: \"General Error\",\n });\n }\n }\n };\n\n protected findItems = async (req: Request, res: Response) => {\n const libOperations = this.lib.operations;\n const query: ParsedQuery = req.query as unknown as ParsedQuery;\n const finder = query['finder'] as string;\n const finderParams = query['finderParams'] as string;\n const one = query['one'] as string;\n\n let items: Item<S, L1, L2, L3, L4, L5>[] = [];\n\n if (finder) {\n // If finder is defined? Call a finder.\n this.logger.default('Finding Items with Finder', { finder, finderParams, one });\n\n if (one === 'true') {\n const item = await (this.lib as any).findOne(finder, JSON.parse(finderParams), this.getLocations(res));\n items = item ? [item] : [];\n } else {\n items = await libOperations.find(finder, JSON.parse(finderParams), this.getLocations(res));\n }\n } else {\n // TODO: This is once of the more important places to perform some validaation and feedback\n const itemQuery: ItemQuery = paramsToQuery(req.query as QueryParams);\n this.logger.default('Finding Items with Query: %j', itemQuery);\n items = await libOperations.all(itemQuery, this.getLocations(res));\n this.logger.default('Found %d Items with Query', items.length);\n }\n\n res.json(items.map((item: Item<S, L1, L2, L3, L4, L5>) => validatePK(item, this.getPkType())));\n };\n\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import {\n ComKey, Item, ItemQuery, LocKey, LocKeyArray, paramsToQuery, PriKey, QueryParams, validatePK\n} from \"@fjell/core\";\nimport { NotFoundError } from \"@fjell/lib\";\nimport { Request, Response } from \"express\";\nimport { ItemRouter, ItemRouterOptions } from \"./ItemRouter.js\";\nimport { Instance } from \"./Instance.js\";\n\ninterface ParsedQuery {\n [key: string]: undefined | string | string[] | ParsedQuery | ParsedQuery[];\n}\n\nexport class CItemRouter<\n T extends Item<S, L1, L2, L3, L4, L5>,\n S extends string,\n L1 extends string,\n L2 extends string = never,\n L3 extends string = never,\n L4 extends string = never,\n L5 extends string = never\n> extends ItemRouter<S, L1, L2, L3, L4, L5> {\n\n private parentRoute: ItemRouter<L1, L2, L3, L4, L5, never>;\n\n constructor(\n lib: Instance<T, S, L1, L2, L3, L4, L5>,\n type: S,\n parentRoute: ItemRouter<L1, L2, L3, L4, L5, never>,\n options: ItemRouterOptions<S, L1, L2, L3, L4, L5> = {},\n ) {\n super(lib as any, type, options);\n this.parentRoute = parentRoute;\n }\n\n public hasParent(): boolean {\n return !!this.parentRoute;\n }\n\n public getIk(res: Response): ComKey<S, L1, L2, L3, L4, L5> {\n const pri = this.getPk(res) as PriKey<S>;\n const loc = this.getLocations(res) as LocKeyArray<L1, L2, L3, L4, L5>;\n return { kt: pri.kt, pk: pri.pk, loc }\n }\n\n public getLKA(res: Response): LocKeyArray<S, L1, L2, L3, L4> {\n /**\n * A location key array is passed to a child router to provide contextfor the items it will\n * be working with. It is always a concatenation of \"My LKA\" + \"Parent LKA\" which will\n * bubble all the way up to the root Primary.\n */\n let lka: LocKey<S | L1 | L2 | L3 | L4>[] = [this.getLk(res)];\n lka = lka.concat(this.parentRoute.getLKA(res) as LocKey<S | L1 | L2 | L3 | L4>[]);\n return lka as LocKeyArray<S, L1, L2, L3, L4>;\n }\n\n public getLocations(res: Response): LocKeyArray<L1, L2, L3, L4, L5> {\n return this.parentRoute.getLKA(res) as LocKeyArray<L1, L2, L3, L4, L5>;\n }\n\n protected createItem = async (req: Request, res: Response) => {\n const libOperations = this.lib.operations;\n this.logger.default('Creating Item', { body: req?.body, query: req?.query, params: req?.params, locals: res?.locals });\n try {\n const itemToCreate = this.convertDates(req.body as Item<S, L1, L2, L3, L4, L5>);\n let item = validatePK(await libOperations.create(\n itemToCreate, { locations: this.getLocations(res) }), this.getPkType()) as Item<S, L1, L2, L3, L4, L5>;\n item = await this.postCreateItem(item);\n this.logger.default('Created Item %j', item);\n res.status(201).json(item);\n } catch (err: any) {\n if (err instanceof NotFoundError) {\n this.logger.error('Item Not Found for Create', { message: err?.message, stack: err?.stack });\n res.status(404).json({\n message: \"Item Not Found\",\n });\n } else {\n this.logger.error('General Error in Create', { message: err?.message, stack: err?.stack });\n res.status(500).json({\n message: \"General Error\",\n });\n }\n }\n };\n\n protected findItems = async (req: Request, res: Response) => {\n const libOperations = this.lib.operations;\n const query: ParsedQuery = req.query as unknown as ParsedQuery;\n const finder = query['finder'] as string;\n const finderParams = query['finderParams'] as string;\n const one = query['one'] as string;\n\n let items: Item<S, L1, L2, L3, L4, L5>[] = [];\n\n if (finder) {\n // If finder is defined? Call a finder.\n this.logger.default('Finding Items with Finder', { finder, finderParams, one });\n\n if (one === 'true') {\n const item = await (this.lib as any).findOne(finder, JSON.parse(finderParams), this.getLocations(res));\n items = item ? [item] : [];\n } else {\n items = await libOperations.find(finder, JSON.parse(finderParams), this.getLocations(res));\n }\n } else {\n // TODO: This is once of the more important places to perform some validaation and feedback\n const itemQuery: ItemQuery = paramsToQuery(req.query as QueryParams);\n this.logger.default('Finding Items with Query: %j', itemQuery);\n items = await libOperations.all(itemQuery, this.getLocations(res));\n this.logger.default('Found %d Items with Query', items.length);\n }\n\n res.json(items.map((item: Item<S, L1, L2, L3, L4, L5>) => validatePK(item, this.getPkType())));\n };\n\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,15 +1,67 @@
1
1
  import { ComKey, Item, LocKey, LocKeyArray, PriKey } from "@fjell/core";
2
2
  import { Instance } from "./Instance.js";
3
3
  import { Request, Response, Router } from "express";
4
+ /**
5
+ * Router-level action method signature - aligned with library ActionMethod pattern
6
+ * Takes the resolved item key, action parameters, and HTTP context
7
+ */
8
+ export interface RouterActionMethod<S extends string, L1 extends string = never, L2 extends string = never, L3 extends string = never, L4 extends string = never, L5 extends string = never> {
9
+ (ik: PriKey<S> | ComKey<S, L1, L2, L3, L4, L5>, actionParams: Record<string, string | number | boolean | Date | Array<string | number | boolean | Date>>, context: {
10
+ req: Request;
11
+ res: Response;
12
+ }): Promise<any>;
13
+ }
14
+ /**
15
+ * Router-level facet method signature - aligned with library FacetMethod pattern
16
+ * Takes the resolved item key, facet parameters, and HTTP context
17
+ */
18
+ export interface RouterFacetMethod<S extends string, L1 extends string = never, L2 extends string = never, L3 extends string = never, L4 extends string = never, L5 extends string = never> {
19
+ (ik: PriKey<S> | ComKey<S, L1, L2, L3, L4, L5>, facetParams: Record<string, string | number | boolean | Date | Array<string | number | boolean | Date>>, context: {
20
+ req: Request;
21
+ res: Response;
22
+ }): Promise<any>;
23
+ }
24
+ /**
25
+ * Router-level all action method signature - aligned with library AllActionMethod pattern
26
+ * Takes action parameters, optional locations, and HTTP context
27
+ */
28
+ export interface RouterAllActionMethod<L1 extends string = never, L2 extends string = never, L3 extends string = never, L4 extends string = never, L5 extends string = never> {
29
+ (allActionParams: Record<string, string | number | boolean | Date | Array<string | number | boolean | Date>>, locations: LocKeyArray<L1, L2, L3, L4, L5> | [], context: {
30
+ req: Request;
31
+ res: Response;
32
+ }): Promise<any>;
33
+ }
34
+ /**
35
+ * Router-level all facet method signature - aligned with library AllFacetMethod pattern
36
+ * Takes facet parameters, optional locations, and HTTP context
37
+ */
38
+ export interface RouterAllFacetMethod<L1 extends string = never, L2 extends string = never, L3 extends string = never, L4 extends string = never, L5 extends string = never> {
39
+ (allFacetParams: Record<string, string | number | boolean | Date | Array<string | number | boolean | Date>>, locations: LocKeyArray<L1, L2, L3, L4, L5> | [], context: {
40
+ req: Request;
41
+ res: Response;
42
+ }): Promise<any>;
43
+ }
4
44
  export type ItemRouterOptions<S extends string = string, L1 extends string = never, L2 extends string = never, L3 extends string = never, L4 extends string = never, L5 extends string = never> = {
5
- /** Handlers for item actions */
6
- actions?: Record<string, (req: Request, res: Response, ik: PriKey<S> | ComKey<S, L1, L2, L3, L4, L5>) => Promise<void>>;
7
- /** Handlers for item facets */
8
- facets?: Record<string, (req: Request, res: Response, ik: PriKey<S> | ComKey<S, L1, L2, L3, L4, L5>) => Promise<void>>;
9
- /** Handlers for all actions */
10
- allActions?: Record<string, (req: Request, res: Response) => Promise<void>>;
11
- /** Handlers for all facets */
12
- allFacets?: Record<string, (req: Request, res: Response) => Promise<void>>;
45
+ /**
46
+ * Handlers for item actions - aligned with library operation signatures
47
+ * The key in the Record is the action name, method receives resolved item key and parameters
48
+ */
49
+ actions?: Record<string, RouterActionMethod<S, L1, L2, L3, L4, L5>>;
50
+ /**
51
+ * Handlers for item facets - aligned with library operation signatures
52
+ * The key in the Record is the facet name, method receives resolved item key and parameters
53
+ */
54
+ facets?: Record<string, RouterFacetMethod<S, L1, L2, L3, L4, L5>>;
55
+ /**
56
+ * Handlers for all actions - aligned with library operation signatures
57
+ * The key in the Record is the action name, method receives parameters and optional locations
58
+ */
59
+ allActions?: Record<string, RouterAllActionMethod<L1, L2, L3, L4, L5>>;
60
+ /**
61
+ * Handlers for all facets - aligned with library operation signatures
62
+ * The key in the Record is the facet name, method receives parameters and optional locations
63
+ */
64
+ allFacets?: Record<string, RouterAllFacetMethod<L1, L2, L3, L4, L5>>;
13
65
  };
14
66
  export declare class ItemRouter<S extends string, L1 extends string = never, L2 extends string = never, L3 extends string = never, L4 extends string = never, L5 extends string = never> {
15
67
  protected lib: Instance<Item<S, L1, L2, L3, L4, L5>, S, L1, L2, L3, L4, L5>;
@@ -1 +1 @@
1
- {"version":3,"file":"ItemRouter.d.ts","sourceRoot":"","sources":["../src/ItemRouter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ItemRouter.d.ts","sourceRoot":"","sources":["../src/ItemRouter.ts"],"names":[],"mappings":"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"}
@@ -52,7 +52,12 @@ class ItemRouter {
52
52
  if (this.options.allActions && this.options.allActions[allActionKey]) {
53
53
  this.logger.debug("Using router-level all action handler", { allActionKey });
54
54
  try {
55
- await this.options.allActions[allActionKey](req, res);
55
+ const result = await this.options.allActions[allActionKey](
56
+ req.body,
57
+ this.getLKA(res),
58
+ { req, res }
59
+ );
60
+ if (result != null) res.json(result);
56
61
  return;
57
62
  } catch (err) {
58
63
  this.logger.error("Error in router-level all action", { message: err?.message, stack: err?.stack });
@@ -86,7 +91,12 @@ class ItemRouter {
86
91
  if (this.options.allFacets && this.options.allFacets[facetKey]) {
87
92
  this.logger.debug("Using router-level all facet handler", { facetKey });
88
93
  try {
89
- await this.options.allFacets[facetKey](req, res);
94
+ const result = await this.options.allFacets[facetKey](
95
+ req.query,
96
+ this.getLKA(res),
97
+ { req, res }
98
+ );
99
+ if (result != null) res.json(result);
90
100
  return;
91
101
  } catch (err) {
92
102
  this.logger.error("Error in router-level all facet", { message: err?.message, stack: err?.stack });
@@ -122,7 +132,12 @@ class ItemRouter {
122
132
  if (this.options.actions && this.options.actions[actionKey]) {
123
133
  this.logger.debug("Using router-level action handler", { actionKey });
124
134
  try {
125
- await this.options.actions[actionKey](req, res, ik);
135
+ const result = await this.options.actions[actionKey](
136
+ ik,
137
+ req.body,
138
+ { req, res }
139
+ );
140
+ if (result != null) res.json(result);
126
141
  return;
127
142
  } catch (err) {
128
143
  this.logger.error("Error in router-level action", { message: err?.message, stack: err?.stack });
@@ -157,7 +172,12 @@ class ItemRouter {
157
172
  if (this.options.facets && this.options.facets[facetKey]) {
158
173
  this.logger.debug("Using router-level facet handler", { facetKey });
159
174
  try {
160
- await this.options.facets[facetKey](req, res, ik);
175
+ const result = await this.options.facets[facetKey](
176
+ ik,
177
+ req.query,
178
+ { req, res }
179
+ );
180
+ if (result != null) res.json(result);
161
181
  return;
162
182
  } catch (err) {
163
183
  this.logger.error("Error in router-level facet", { message: err?.message, stack: err?.stack });
@@ -189,36 +209,92 @@ class ItemRouter {
189
209
  this.logger.debug("Configuring Router", { pkType: this.getPkType() });
190
210
  router.get("/", this.findItems);
191
211
  router.post("/", this.createItem);
192
- this.logger.default("All Actions supplied to Router", { allActions: libOptions.allActions });
212
+ const registeredAllActions = /* @__PURE__ */ new Set();
213
+ const registeredAllFacets = /* @__PURE__ */ new Set();
214
+ const registeredItemActions = /* @__PURE__ */ new Set();
215
+ const registeredItemFacets = /* @__PURE__ */ new Set();
216
+ this.logger.default("Router All Actions", { allActions: this.options.allActions });
217
+ if (this.options.allActions) {
218
+ Object.keys(this.options.allActions).forEach((actionKey) => {
219
+ this.logger.debug("Configuring Router All Action %s", actionKey);
220
+ router.post(`/${actionKey}`, this.postAllAction);
221
+ registeredAllActions.add(actionKey);
222
+ });
223
+ }
224
+ this.logger.default("Library All Actions", { allActions: libOptions.allActions });
193
225
  if (libOptions.allActions) {
194
226
  Object.keys(libOptions.allActions).forEach((actionKey) => {
195
- this.logger.debug("Configuring All Action %s", actionKey);
196
- router.post(`/${actionKey}`, this.postAllAction);
227
+ if (registeredAllActions.has(actionKey)) {
228
+ this.logger.warning("All Action name collision - router-level handler takes precedence", { actionKey });
229
+ } else {
230
+ this.logger.debug("Configuring Library All Action %s", actionKey);
231
+ router.post(`/${actionKey}`, this.postAllAction);
232
+ registeredAllActions.add(actionKey);
233
+ }
234
+ });
235
+ }
236
+ this.logger.default("Router All Facets", { allFacets: this.options.allFacets });
237
+ if (this.options.allFacets) {
238
+ Object.keys(this.options.allFacets).forEach((facetKey) => {
239
+ this.logger.debug("Configuring Router All Facet %s", facetKey);
240
+ router.get(`/${facetKey}`, this.getAllFacet);
241
+ registeredAllFacets.add(facetKey);
197
242
  });
198
243
  }
199
- this.logger.default("All Facets supplied to Router", { allFacets: libOptions.allFacets });
244
+ this.logger.default("Library All Facets", { allFacets: libOptions.allFacets });
200
245
  if (libOptions.allFacets) {
201
246
  Object.keys(libOptions.allFacets).forEach((facetKey) => {
202
- this.logger.debug("Configuring All Facet %s", facetKey);
203
- router.get(`/${facetKey}`, this.getAllFacet);
247
+ if (registeredAllFacets.has(facetKey)) {
248
+ this.logger.warning("All Facet name collision - router-level handler takes precedence", { facetKey });
249
+ } else {
250
+ this.logger.debug("Configuring Library All Facet %s", facetKey);
251
+ router.get(`/${facetKey}`, this.getAllFacet);
252
+ registeredAllFacets.add(facetKey);
253
+ }
204
254
  });
205
255
  }
206
256
  const itemRouter = Router();
207
257
  itemRouter.get("/", this.getItem);
208
258
  itemRouter.put("/", this.updateItem);
209
259
  itemRouter.delete("/", this.deleteItem);
210
- this.logger.default("Item Actions supplied to Router", { itemActions: libOptions.actions });
260
+ this.logger.default("Router Item Actions", { itemActions: this.options.actions });
261
+ if (this.options.actions) {
262
+ Object.keys(this.options.actions).forEach((actionKey) => {
263
+ this.logger.debug("Configuring Router Item Action %s", actionKey);
264
+ itemRouter.post(`/${actionKey}`, this.postItemAction);
265
+ registeredItemActions.add(actionKey);
266
+ });
267
+ }
268
+ this.logger.default("Library Item Actions", { itemActions: libOptions.actions });
211
269
  if (libOptions.actions) {
212
270
  Object.keys(libOptions.actions).forEach((actionKey) => {
213
- this.logger.debug("Configuring Item Action %s", actionKey);
214
- itemRouter.post(`/${actionKey}`, this.postItemAction);
271
+ if (registeredItemActions.has(actionKey)) {
272
+ this.logger.warning("Item Action name collision - router-level handler takes precedence", { actionKey });
273
+ } else {
274
+ this.logger.debug("Configuring Library Item Action %s", actionKey);
275
+ itemRouter.post(`/${actionKey}`, this.postItemAction);
276
+ registeredItemActions.add(actionKey);
277
+ }
215
278
  });
216
279
  }
217
- this.logger.default("Item Facets supplied to Router", { itemFacets: libOptions.facets });
280
+ this.logger.default("Router Item Facets", { itemFacets: this.options.facets });
281
+ if (this.options.facets) {
282
+ Object.keys(this.options.facets).forEach((facetKey) => {
283
+ this.logger.debug("Configuring Router Item Facet %s", facetKey);
284
+ itemRouter.get(`/${facetKey}`, this.getItemFacet);
285
+ registeredItemFacets.add(facetKey);
286
+ });
287
+ }
288
+ this.logger.default("Library Item Facets", { itemFacets: libOptions.facets });
218
289
  if (libOptions.facets) {
219
290
  Object.keys(libOptions.facets).forEach((facetKey) => {
220
- this.logger.debug("Configuring Item Facet %s", facetKey);
221
- itemRouter.get(`/${facetKey}`, this.getItemFacet);
291
+ if (registeredItemFacets.has(facetKey)) {
292
+ this.logger.warning("Item Facet name collision - router-level handler takes precedence", { facetKey });
293
+ } else {
294
+ this.logger.debug("Configuring Library Item Facet %s", facetKey);
295
+ itemRouter.get(`/${facetKey}`, this.getItemFacet);
296
+ registeredItemFacets.add(facetKey);
297
+ }
222
298
  });
223
299
  }
224
300
  this.logger.debug("Configuring Item Operations under PK Param %s", this.getPkParam());
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/ItemRouter.ts"],
4
- "sourcesContent": ["import {\n ComKey,\n cPK,\n Item,\n ItemEvent,\n LocKey,\n LocKeyArray,\n PriKey,\n validatePK\n} from \"@fjell/core\";\nimport { NotFoundError } from \"@fjell/lib\";\nimport { Instance } from \"./Instance.js\";\nimport deepmerge from \"deepmerge\";\nimport { Request, Response, Router } from \"express\";\nimport LibLogger from \"./logger.js\";\n\nexport type ItemRouterOptions<\n S extends string = string,\n L1 extends string = never,\n L2 extends string = never,\n L3 extends string = never,\n L4 extends string = never,\n L5 extends string = never\n> = {\n /** Handlers for item actions */\n actions?: Record<string, (req: Request, res: Response, ik: PriKey<S> | ComKey<S, L1, L2, L3, L4, L5>) => Promise<void>>;\n /** Handlers for item facets */\n facets?: Record<string, (req: Request, res: Response, ik: PriKey<S> | ComKey<S, L1, L2, L3, L4, L5>) => Promise<void>>;\n /** Handlers for all actions */\n allActions?: Record<string, (req: Request, res: Response) => Promise<void>>;\n /** Handlers for all facets */\n allFacets?: Record<string, (req: Request, res: Response) => Promise<void>>;\n};\n\nexport class ItemRouter<\n S extends string,\n L1 extends string = never,\n L2 extends string = never,\n L3 extends string = never,\n L4 extends string = never,\n L5 extends string = never\n> {\n\n protected lib: Instance<Item<S, L1, L2, L3, L4, L5>, S, L1, L2, L3, L4, L5>;\n private keyType: S;\n protected options: ItemRouterOptions<S, L1, L2, L3, L4, L5>;\n private childRouters: Record<string, Router> = {};\n protected logger;\n\n constructor(\n lib: Instance<Item<S, L1, L2, L3, L4, L5>, S, L1, L2, L3, L4, L5>,\n keyType: S,\n options: ItemRouterOptions<S, L1, L2, L3, L4, L5> = {}\n ) {\n this.lib = lib;\n this.keyType = keyType;\n this.options = options;\n this.logger = LibLogger.get(\"ItemRouter\", keyType);\n }\n\n public getPkType = (): S => {\n return this.keyType;\n }\n\n protected getPkParam = (): string => {\n return `${this.getPkType()}Pk`;\n }\n\n protected getLk(res: Response): LocKey<S> {\n return { kt: this.keyType, lk: res.locals[this.getPkParam()] };\n }\n\n // this is meant to be consumed by children routers\n public getLKA(res: Response): LocKeyArray<S, L1, L2, L3, L4> {\n return [this.getLk(res)] as LocKeyArray<S, L1, L2, L3, L4>;\n }\n\n public getPk(res: Response): PriKey<S> {\n return cPK<S>(res.locals[this.getPkParam()], this.getPkType());\n }\n\n // Unless this is a contained router, the locations will always be an empty array.\n /* eslint-disable */\n protected getLocations(res: Response): LocKeyArray<L1, L2, L3, L4, L5> | [] {\n throw new Error('Method not implemented in an abstract router');\n }\n /* eslint-enable */\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n protected getIk(res: Response): PriKey<S> | ComKey<S, L1, L2, L3, L4, L5> {\n throw new Error('Method not implemented in an abstract router');\n }\n\n protected postAllAction = async (req: Request, res: Response) => {\n const libOptions = this.lib.options;\n const libOperations = this.lib.operations;\n this.logger.debug('Posting All Action', { query: req?.query, params: req?.params, locals: res?.locals });\n const allActionKey = req.path.substring(req.path.lastIndexOf('/') + 1);\n\n // Check for router-level handler first\n if (this.options.allActions && this.options.allActions[allActionKey]) {\n this.logger.debug('Using router-level all action handler', { allActionKey });\n try {\n await this.options.allActions[allActionKey](req, res);\n return;\n } catch (err: any) {\n this.logger.error('Error in router-level all action', { message: err?.message, stack: err?.stack });\n res.status(500).json(err);\n return;\n }\n }\n\n // Fallback to library handler\n if (!libOptions.allActions) {\n this.logger.error('All Actions are not configured');\n res.status(500).json({ error: 'All Actions are not configured' });\n return;\n }\n const allAction = libOptions.allActions[allActionKey];\n if (!allAction) {\n this.logger.error('All Action is not configured', { allActionKey });\n res.status(500).json({ error: 'All Action is not configured' });\n return;\n }\n try {\n res.json(await libOperations.allAction(allActionKey, req.body));\n } catch (err: any) {\n this.logger.error('Error in All Action', { message: err?.message, stack: err?.stack });\n res.status(500).json(err);\n }\n }\n\n protected getAllFacet = async (req: Request, res: Response) => {\n const libOptions = this.lib.options;\n const libOperations = this.lib.operations;\n this.logger.debug('Getting All Facet', { query: req?.query, params: req?.params, locals: res?.locals });\n const facetKey = req.path.substring(req.path.lastIndexOf('/') + 1);\n\n // Check for router-level handler first\n if (this.options.allFacets && this.options.allFacets[facetKey]) {\n this.logger.debug('Using router-level all facet handler', { facetKey });\n try {\n await this.options.allFacets[facetKey](req, res);\n return;\n } catch (err: any) {\n this.logger.error('Error in router-level all facet', { message: err?.message, stack: err?.stack });\n res.status(500).json(err);\n return;\n }\n }\n\n // Fallback to library handler\n if (!libOptions.allFacets) {\n this.logger.error('All Facets are not configured');\n res.status(500).json({ error: 'All Facets are not configured' });\n return;\n }\n const facet = libOptions.allFacets[facetKey];\n if (!facet) {\n this.logger.error('All Facet is not configured', { facetKey });\n res.status(500).json({ error: 'All Facet is not configured' });\n return;\n }\n try {\n const combinedQueryParams = { ...req.query, ...req.params } as Record<string, string | number | boolean | Date | Array<string | number | boolean | Date>>;\n res.json(await libOperations.allFacet(facetKey, combinedQueryParams));\n } catch (err: any) {\n this.logger.error('Error in All Facet', { message: err?.message, stack: err?.stack });\n res.status(500).json(err);\n }\n }\n\n protected postItemAction = async (req: Request, res: Response) => {\n const libOptions = this.lib.options;\n const libOperations = this.lib.operations;\n this.logger.debug('Posting Item Action', { query: req?.query, params: req?.params, locals: res?.locals });\n const ik = this.getIk(res);\n const actionKey = req.path.substring(req.path.lastIndexOf('/') + 1);\n\n // Check for router-level handler first\n if (this.options.actions && this.options.actions[actionKey]) {\n this.logger.debug('Using router-level action handler', { actionKey });\n try {\n await this.options.actions[actionKey](req, res, ik);\n return;\n } catch (err: any) {\n this.logger.error('Error in router-level action', { message: err?.message, stack: err?.stack });\n res.status(500).json(err);\n return;\n }\n }\n\n // Fallback to library handler\n if (!libOptions.actions) {\n this.logger.error('Item Actions are not configured');\n res.status(500).json({ error: 'Item Actions are not configured' });\n return;\n }\n const action = libOptions.actions[actionKey];\n if (!action) {\n this.logger.error('Item Action is not configured', { actionKey });\n res.status(500).json({ error: 'Item Action is not configured' });\n return;\n }\n try {\n res.json(await libOperations.action(ik, actionKey, req.body));\n } catch (err: any) {\n this.logger.error('Error in Item Action', { message: err?.message, stack: err?.stack });\n res.status(500).json(err);\n }\n }\n\n protected getItemFacet = async (req: Request, res: Response) => {\n const libOptions = this.lib.options;\n const libOperations = this.lib.operations;\n this.logger.debug('Getting Item Facet', { query: req?.query, params: req?.params, locals: res?.locals });\n const ik = this.getIk(res);\n const facetKey = req.path.substring(req.path.lastIndexOf('/') + 1);\n\n // Check for router-level handler first\n if (this.options.facets && this.options.facets[facetKey]) {\n this.logger.debug('Using router-level facet handler', { facetKey });\n try {\n await this.options.facets[facetKey](req, res, ik);\n return;\n } catch (err: any) {\n this.logger.error('Error in router-level facet', { message: err?.message, stack: err?.stack });\n res.status(500).json(err);\n return;\n }\n }\n\n // Fallback to library handler\n if (!libOptions.facets) {\n this.logger.error('Item Facets are not configured');\n res.status(500).json({ error: 'Item Facets are not configured' });\n return;\n }\n const facet = libOptions.facets[facetKey];\n if (!facet) {\n this.logger.error('Item Facet is not configured', { facetKey });\n res.status(500).json({ error: 'Item Facet is not configured' });\n return;\n }\n try {\n const combinedQueryParams = { ...req.query, ...req.params } as Record<string, string | number | boolean | Date | Array<string | number | boolean | Date>>;\n res.json(await libOperations.facet(ik, facetKey, combinedQueryParams));\n } catch (err: any) {\n this.logger.error('Error in Item Facet', { message: err?.message, stack: err?.stack });\n res.status(500).json(err);\n }\n }\n\n private configure = (router: Router) => {\n const libOptions = this.lib.options;\n this.logger.debug('Configuring Router', { pkType: this.getPkType() });\n router.get('/', this.findItems);\n router.post('/', this.createItem);\n\n this.logger.default('All Actions supplied to Router', { allActions: libOptions.allActions });\n if (libOptions.allActions) {\n Object.keys(libOptions.allActions).forEach((actionKey) => {\n this.logger.debug('Configuring All Action %s', actionKey);\n // TODO: Ok, this is a bit of a hack, but we need to customize the types of the request handlers\n router.post(`/${actionKey}`, this.postAllAction);\n });\n }\n\n this.logger.default('All Facets supplied to Router', { allFacets: libOptions.allFacets });\n if (libOptions.allFacets) {\n Object.keys(libOptions.allFacets).forEach((facetKey) => {\n this.logger.debug('Configuring All Facet %s', facetKey);\n // TODO: Ok, this is a bit of a hack, but we need to customize the types of the request handlers\n router.get(`/${facetKey}`, this.getAllFacet);\n });\n }\n\n const itemRouter = Router();\n itemRouter.get('/', this.getItem);\n itemRouter.put('/', this.updateItem);\n itemRouter.delete('/', this.deleteItem);\n\n this.logger.default('Item Actions supplied to Router', { itemActions: libOptions.actions });\n if (libOptions.actions) {\n Object.keys(libOptions.actions).forEach((actionKey) => {\n this.logger.debug('Configuring Item Action %s', actionKey);\n // TODO: Ok, this is a bit of a hack, but we need to customize the types of the request handlers\n itemRouter.post(`/${actionKey}`, this.postItemAction)\n });\n }\n\n this.logger.default('Item Facets supplied to Router', { itemFacets: libOptions.facets });\n if (libOptions.facets) {\n Object.keys(libOptions.facets).forEach((facetKey) => {\n this.logger.debug('Configuring Item Facet %s', facetKey);\n // TODO: Ok, this is a bit of a hack, but we need to customize the types of the request handlers\n itemRouter.get(`/${facetKey}`, this.getItemFacet)\n });\n }\n\n this.logger.debug('Configuring Item Operations under PK Param %s', this.getPkParam());\n router.use(`/:${this.getPkParam()}`, this.validatePrimaryKeyValue, itemRouter);\n\n if (this.childRouters) {\n this.configureChildRouters(itemRouter, this.childRouters);\n }\n return router;\n }\n\n private validatePrimaryKeyValue = (req: Request, res: Response, next: any) => {\n const pkParamValue = req.params[this.getPkParam()];\n if (this.validatePKParam(pkParamValue)) {\n res.locals[this.getPkParam()] = pkParamValue;\n next();\n } else {\n this.logger.error('Invalid Primary Key', { pkParamValue, path: req?.originalUrl });\n res.status(500).json({ error: 'Invalid Primary Key', path: req?.originalUrl });\n }\n }\n\n private configureChildRouters = (router: Router, childRouters: Record<string, Router>) => {\n for (const path in childRouters) {\n this.logger.debug('Configuring Child Router at Path %s', path);\n\n router.use(`/${path}`, childRouters[path]);\n }\n return router;\n }\n\n public addChildRouter = (path: string, router: Router) => {\n this.childRouters[path] = router;\n }\n\n /* istanbul ignore next */\n public getRouter(): Router {\n const router = Router();\n this.configure(router);\n return router;\n }\n\n /* istanbul ignore next */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n protected createItem = async (req: Request, res: Response): Promise<void> => {\n throw new Error('Method not implemented in an abstract router');\n };\n\n // TODO: Probably a better way to do this, but this postCreate hook only needs the item.\n /* istanbul ignore next */\n public postCreateItem = async (item: Item<S, L1, L2, L3, L4, L5>): Promise<Item<S, L1, L2, L3, L4, L5>> => {\n this.logger.debug('Post Create Item', { item });\n return item;\n };\n\n protected deleteItem = async (req: Request, res: Response): Promise<void> => {\n const libOperations = this.lib.operations;\n\n this.logger.debug('Deleting Item', { query: req.query, params: req.params, locals: res.locals });\n const ik = this.getIk(res);\n try {\n const removedItem = await libOperations.remove(ik);\n const item = validatePK(removedItem, this.getPkType());\n res.json(item);\n } catch (err: any) {\n if (err instanceof NotFoundError) {\n this.logger.error('Item Not Found for Delete', { ik, message: err?.message, stack: err?.stack });\n res.status(404).json({\n ik,\n message: \"Item Not Found\",\n });\n } else {\n this.logger.error('General Error in Delete', { ik, message: err?.message, stack: err?.stack });\n res.status(500).json({\n ik,\n message: \"General Error\",\n });\n }\n }\n };\n\n /* eslint-disable */\n /* istanbul ignore next */\n protected findItems = async (req: Request, res: Response): Promise<void> => {\n throw new Error('Method not implemented in an abstract router');\n };\n /* eslint-enable */\n\n protected getItem = async (req: Request, res: Response) => {\n const libOperations = this.lib.operations;\n this.logger.debug('Getting Item', { query: req.query, params: req.params, locals: res.locals });\n const ik = this.getIk(res);\n try {\n // TODO: What error does validate PK throw, when can that fail?\n const item = validatePK(await libOperations.get(ik), this.getPkType());\n res.json(item);\n } catch (err: any) {\n if (err instanceof NotFoundError) {\n this.logger.error('Item Not Found', { ik, message: err?.message, stack: err?.stack });\n res.status(404).json({\n ik,\n message: \"Item Not Found\",\n });\n } else {\n this.logger.error('General Error', { ik, message: err?.message, stack: err?.stack });\n res.status(500).json({\n ik,\n message: \"General Error\",\n });\n }\n }\n }\n\n protected updateItem = async (req: Request, res: Response) => {\n const libOperations = this.lib.operations;\n this.logger.debug('Updating Item',\n { body: req?.body, query: req?.query, params: req?.params, locals: res?.locals });\n const ik = this.getIk(res);\n try {\n const itemToUpdate = this.convertDates(req.body as Partial<Item<S, L1, L2, L3, L4, L5>>);\n const retItem = validatePK(await libOperations.update(ik, itemToUpdate), this.getPkType());\n res.json(retItem);\n } catch (err: any) {\n if (err instanceof NotFoundError) {\n this.logger.error('Item Not Found for Update', { ik, message: err?.message, stack: err?.stack });\n res.status(404).json({\n ik,\n message: \"Item Not Found\",\n });\n } else {\n this.logger.error('General Error in Update', { ik, message: err?.message, stack: err?.stack });\n res.status(500).json({\n ik,\n message: \"General Error\",\n });\n }\n }\n };\n\n public convertDates = (item: Partial<Item<S, L1, L2, L3, L4, L5>>): Partial<Item<S, L1, L2, L3, L4, L5>> => {\n const events = item.events as Record<string, ItemEvent>;\n this.logger.debug('Converting Dates', { item });\n if (events) {\n Object.keys(events).forEach((key: string) => {\n Object.assign(events, {\n [key]: deepmerge(events[key], { at: events[key].at ? new Date(events[key].at) : null })\n });\n });\n }\n Object.assign(item, { events });\n return item;\n };\n\n // TODO: Maybe just simplify this and require that everything is a UUID?\n /**\n * This method might be an annoyance, but we need to capture a few cases where someone passes\n * a PK parameter that has an odd string in it.\n *\n * @param pkParamValue The value of the primary key parameter\n * @returns if the value is valid.\n */\n protected validatePKParam = (pkParamValue: string): boolean => {\n let validPkParam = true;\n if (pkParamValue.length <= 0) {\n this.logger.error('Primary Key is an Empty String', { pkParamValue });\n validPkParam = false;\n } else if (pkParamValue === 'undefined') {\n this.logger.error('Primary Key is the string \\'undefined\\'', { pkParamValue });\n validPkParam = false;\n }\n return validPkParam;\n }\n\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import {\n ComKey,\n cPK,\n Item,\n ItemEvent,\n LocKey,\n LocKeyArray,\n PriKey,\n validatePK\n} from \"@fjell/core\";\nimport { NotFoundError } from \"@fjell/lib\";\nimport { Instance } from \"./Instance.js\";\nimport deepmerge from \"deepmerge\";\nimport { Request, Response, Router } from \"express\";\nimport LibLogger from \"./logger.js\";\n\n/**\n * Router-level action method signature - aligned with library ActionMethod pattern\n * Takes the resolved item key, action parameters, and HTTP context\n */\nexport interface RouterActionMethod<\n S extends string,\n L1 extends string = never,\n L2 extends string = never,\n L3 extends string = never,\n L4 extends string = never,\n L5 extends string = never,\n> {\n (\n ik: PriKey<S> | ComKey<S, L1, L2, L3, L4, L5>,\n actionParams: Record<string, string | number | boolean | Date | Array<string | number | boolean | Date>>,\n context: { req: Request, res: Response }\n ): Promise<any>;\n}\n\n/**\n * Router-level facet method signature - aligned with library FacetMethod pattern\n * Takes the resolved item key, facet parameters, and HTTP context\n */\nexport interface RouterFacetMethod<\n S extends string,\n L1 extends string = never,\n L2 extends string = never,\n L3 extends string = never,\n L4 extends string = never,\n L5 extends string = never,\n> {\n (\n ik: PriKey<S> | ComKey<S, L1, L2, L3, L4, L5>,\n facetParams: Record<string, string | number | boolean | Date | Array<string | number | boolean | Date>>,\n context: { req: Request, res: Response }\n ): Promise<any>;\n}\n\n/**\n * Router-level all action method signature - aligned with library AllActionMethod pattern\n * Takes action parameters, optional locations, and HTTP context\n */\nexport interface RouterAllActionMethod<\n L1 extends string = never,\n L2 extends string = never,\n L3 extends string = never,\n L4 extends string = never,\n L5 extends string = never,\n> {\n (\n allActionParams: Record<string, string | number | boolean | Date | Array<string | number | boolean | Date>>,\n locations: LocKeyArray<L1, L2, L3, L4, L5> | [],\n context: { req: Request, res: Response }\n ): Promise<any>;\n}\n\n/**\n * Router-level all facet method signature - aligned with library AllFacetMethod pattern\n * Takes facet parameters, optional locations, and HTTP context\n */\nexport interface RouterAllFacetMethod<\n L1 extends string = never,\n L2 extends string = never,\n L3 extends string = never,\n L4 extends string = never,\n L5 extends string = never,\n> {\n (\n allFacetParams: Record<string, string | number | boolean | Date | Array<string | number | boolean | Date>>,\n locations: LocKeyArray<L1, L2, L3, L4, L5> | [],\n context: { req: Request, res: Response }\n ): Promise<any>;\n}\n\nexport type ItemRouterOptions<\n S extends string = string,\n L1 extends string = never,\n L2 extends string = never,\n L3 extends string = never,\n L4 extends string = never,\n L5 extends string = never\n> = {\n /**\n * Handlers for item actions - aligned with library operation signatures\n * The key in the Record is the action name, method receives resolved item key and parameters\n */\n actions?: Record<string, RouterActionMethod<S, L1, L2, L3, L4, L5>>;\n\n /**\n * Handlers for item facets - aligned with library operation signatures\n * The key in the Record is the facet name, method receives resolved item key and parameters\n */\n facets?: Record<string, RouterFacetMethod<S, L1, L2, L3, L4, L5>>;\n\n /**\n * Handlers for all actions - aligned with library operation signatures\n * The key in the Record is the action name, method receives parameters and optional locations\n */\n allActions?: Record<string, RouterAllActionMethod<L1, L2, L3, L4, L5>>;\n\n /**\n * Handlers for all facets - aligned with library operation signatures\n * The key in the Record is the facet name, method receives parameters and optional locations\n */\n allFacets?: Record<string, RouterAllFacetMethod<L1, L2, L3, L4, L5>>;\n};\n\nexport class ItemRouter<\n S extends string,\n L1 extends string = never,\n L2 extends string = never,\n L3 extends string = never,\n L4 extends string = never,\n L5 extends string = never\n> {\n\n protected lib: Instance<Item<S, L1, L2, L3, L4, L5>, S, L1, L2, L3, L4, L5>;\n private keyType: S;\n protected options: ItemRouterOptions<S, L1, L2, L3, L4, L5>;\n private childRouters: Record<string, Router> = {};\n protected logger;\n\n constructor(\n lib: Instance<Item<S, L1, L2, L3, L4, L5>, S, L1, L2, L3, L4, L5>,\n keyType: S,\n options: ItemRouterOptions<S, L1, L2, L3, L4, L5> = {}\n ) {\n this.lib = lib;\n this.keyType = keyType;\n this.options = options;\n this.logger = LibLogger.get(\"ItemRouter\", keyType);\n }\n\n public getPkType = (): S => {\n return this.keyType;\n }\n\n protected getPkParam = (): string => {\n return `${this.getPkType()}Pk`;\n }\n\n protected getLk(res: Response): LocKey<S> {\n return { kt: this.keyType, lk: res.locals[this.getPkParam()] };\n }\n\n // this is meant to be consumed by children routers\n public getLKA(res: Response): LocKeyArray<S, L1, L2, L3, L4> {\n return [this.getLk(res)] as LocKeyArray<S, L1, L2, L3, L4>;\n }\n\n public getPk(res: Response): PriKey<S> {\n return cPK<S>(res.locals[this.getPkParam()], this.getPkType());\n }\n\n // Unless this is a contained router, the locations will always be an empty array.\n /* eslint-disable */\n protected getLocations(res: Response): LocKeyArray<L1, L2, L3, L4, L5> | [] {\n throw new Error('Method not implemented in an abstract router');\n }\n /* eslint-enable */\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n protected getIk(res: Response): PriKey<S> | ComKey<S, L1, L2, L3, L4, L5> {\n throw new Error('Method not implemented in an abstract router');\n }\n\n protected postAllAction = async (req: Request, res: Response) => {\n const libOptions = this.lib.options;\n const libOperations = this.lib.operations;\n this.logger.debug('Posting All Action', { query: req?.query, params: req?.params, locals: res?.locals });\n const allActionKey = req.path.substring(req.path.lastIndexOf('/') + 1);\n\n // Check for router-level handler first\n if (this.options.allActions && this.options.allActions[allActionKey]) {\n this.logger.debug('Using router-level all action handler', { allActionKey });\n try {\n const result = await this.options.allActions[allActionKey](\n req.body as Record<string, string | number | boolean | Date | Array<string | number | boolean | Date>>,\n this.getLKA(res) as LocKeyArray<L1, L2, L3, L4, L5> | [],\n { req, res }\n );\n if (result != null) res.json(result);\n return;\n } catch (err: any) {\n this.logger.error('Error in router-level all action', { message: err?.message, stack: err?.stack });\n res.status(500).json(err);\n return;\n }\n }\n\n // Fallback to library handler\n if (!libOptions.allActions) {\n this.logger.error('All Actions are not configured');\n res.status(500).json({ error: 'All Actions are not configured' });\n return;\n }\n const allAction = libOptions.allActions[allActionKey];\n if (!allAction) {\n this.logger.error('All Action is not configured', { allActionKey });\n res.status(500).json({ error: 'All Action is not configured' });\n return;\n }\n try {\n res.json(await libOperations.allAction(allActionKey, req.body));\n } catch (err: any) {\n this.logger.error('Error in All Action', { message: err?.message, stack: err?.stack });\n res.status(500).json(err);\n }\n }\n\n protected getAllFacet = async (req: Request, res: Response) => {\n const libOptions = this.lib.options;\n const libOperations = this.lib.operations;\n this.logger.debug('Getting All Facet', { query: req?.query, params: req?.params, locals: res?.locals });\n const facetKey = req.path.substring(req.path.lastIndexOf('/') + 1);\n\n // Check for router-level handler first\n if (this.options.allFacets && this.options.allFacets[facetKey]) {\n this.logger.debug('Using router-level all facet handler', { facetKey });\n try {\n const result = await this.options.allFacets[facetKey](\n req.query as Record<string, string | number | boolean | Date | Array<string | number | boolean | Date>>,\n this.getLKA(res) as LocKeyArray<L1, L2, L3, L4, L5> | [],\n { req, res }\n );\n if (result != null) res.json(result);\n return;\n } catch (err: any) {\n this.logger.error('Error in router-level all facet', { message: err?.message, stack: err?.stack });\n res.status(500).json(err);\n return;\n }\n }\n\n // Fallback to library handler\n if (!libOptions.allFacets) {\n this.logger.error('All Facets are not configured');\n res.status(500).json({ error: 'All Facets are not configured' });\n return;\n }\n const facet = libOptions.allFacets[facetKey];\n if (!facet) {\n this.logger.error('All Facet is not configured', { facetKey });\n res.status(500).json({ error: 'All Facet is not configured' });\n return;\n }\n try {\n const combinedQueryParams = { ...req.query, ...req.params } as Record<string, string | number | boolean | Date | Array<string | number | boolean | Date>>;\n res.json(await libOperations.allFacet(facetKey, combinedQueryParams));\n } catch (err: any) {\n this.logger.error('Error in All Facet', { message: err?.message, stack: err?.stack });\n res.status(500).json(err);\n }\n }\n\n protected postItemAction = async (req: Request, res: Response) => {\n const libOptions = this.lib.options;\n const libOperations = this.lib.operations;\n this.logger.debug('Posting Item Action', { query: req?.query, params: req?.params, locals: res?.locals });\n const ik = this.getIk(res);\n const actionKey = req.path.substring(req.path.lastIndexOf('/') + 1);\n\n // Check for router-level handler first\n if (this.options.actions && this.options.actions[actionKey]) {\n this.logger.debug('Using router-level action handler', { actionKey });\n try {\n const result = await this.options.actions[actionKey](\n ik,\n req.body as Record<string, string | number | boolean | Date | Array<string | number | boolean | Date>>,\n { req, res }\n );\n if (result != null) res.json(result);\n return;\n } catch (err: any) {\n this.logger.error('Error in router-level action', { message: err?.message, stack: err?.stack });\n res.status(500).json(err);\n return;\n }\n }\n\n // Fallback to library handler\n if (!libOptions.actions) {\n this.logger.error('Item Actions are not configured');\n res.status(500).json({ error: 'Item Actions are not configured' });\n return;\n }\n const action = libOptions.actions[actionKey];\n if (!action) {\n this.logger.error('Item Action is not configured', { actionKey });\n res.status(500).json({ error: 'Item Action is not configured' });\n return;\n }\n try {\n res.json(await libOperations.action(ik, actionKey, req.body));\n } catch (err: any) {\n this.logger.error('Error in Item Action', { message: err?.message, stack: err?.stack });\n res.status(500).json(err);\n }\n }\n\n protected getItemFacet = async (req: Request, res: Response) => {\n const libOptions = this.lib.options;\n const libOperations = this.lib.operations;\n this.logger.debug('Getting Item Facet', { query: req?.query, params: req?.params, locals: res?.locals });\n const ik = this.getIk(res);\n const facetKey = req.path.substring(req.path.lastIndexOf('/') + 1);\n\n // Check for router-level handler first\n if (this.options.facets && this.options.facets[facetKey]) {\n this.logger.debug('Using router-level facet handler', { facetKey });\n try {\n const result = await this.options.facets[facetKey](\n ik,\n req.query as Record<string, string | number | boolean | Date | Array<string | number | boolean | Date>>,\n { req, res }\n );\n if (result != null) res.json(result);\n return;\n } catch (err: any) {\n this.logger.error('Error in router-level facet', { message: err?.message, stack: err?.stack });\n res.status(500).json(err);\n return;\n }\n }\n\n // Fallback to library handler\n if (!libOptions.facets) {\n this.logger.error('Item Facets are not configured');\n res.status(500).json({ error: 'Item Facets are not configured' });\n return;\n }\n const facet = libOptions.facets[facetKey];\n if (!facet) {\n this.logger.error('Item Facet is not configured', { facetKey });\n res.status(500).json({ error: 'Item Facet is not configured' });\n return;\n }\n try {\n const combinedQueryParams = { ...req.query, ...req.params } as Record<string, string | number | boolean | Date | Array<string | number | boolean | Date>>;\n res.json(await libOperations.facet(ik, facetKey, combinedQueryParams));\n } catch (err: any) {\n this.logger.error('Error in Item Facet', { message: err?.message, stack: err?.stack });\n res.status(500).json(err);\n }\n }\n\n private configure = (router: Router) => {\n const libOptions = this.lib.options;\n this.logger.debug('Configuring Router', { pkType: this.getPkType() });\n router.get('/', this.findItems);\n router.post('/', this.createItem);\n\n // Track registered routes to detect collisions\n const registeredAllActions = new Set<string>();\n const registeredAllFacets = new Set<string>();\n const registeredItemActions = new Set<string>();\n const registeredItemFacets = new Set<string>();\n\n // Configure router-level allActions first (highest precedence)\n this.logger.default('Router All Actions', { allActions: this.options.allActions });\n if (this.options.allActions) {\n Object.keys(this.options.allActions).forEach((actionKey) => {\n this.logger.debug('Configuring Router All Action %s', actionKey);\n router.post(`/${actionKey}`, this.postAllAction);\n registeredAllActions.add(actionKey);\n });\n }\n\n // Configure library allActions, warn on conflicts\n this.logger.default('Library All Actions', { allActions: libOptions.allActions });\n if (libOptions.allActions) {\n Object.keys(libOptions.allActions).forEach((actionKey) => {\n if (registeredAllActions.has(actionKey)) {\n this.logger.warning('All Action name collision - router-level handler takes precedence', { actionKey });\n } else {\n this.logger.debug('Configuring Library All Action %s', actionKey);\n router.post(`/${actionKey}`, this.postAllAction);\n registeredAllActions.add(actionKey);\n }\n });\n }\n\n // Configure router-level allFacets first (highest precedence)\n this.logger.default('Router All Facets', { allFacets: this.options.allFacets });\n if (this.options.allFacets) {\n Object.keys(this.options.allFacets).forEach((facetKey) => {\n this.logger.debug('Configuring Router All Facet %s', facetKey);\n router.get(`/${facetKey}`, this.getAllFacet);\n registeredAllFacets.add(facetKey);\n });\n }\n\n // Configure library allFacets, warn on conflicts\n this.logger.default('Library All Facets', { allFacets: libOptions.allFacets });\n if (libOptions.allFacets) {\n Object.keys(libOptions.allFacets).forEach((facetKey) => {\n if (registeredAllFacets.has(facetKey)) {\n this.logger.warning('All Facet name collision - router-level handler takes precedence', { facetKey });\n } else {\n this.logger.debug('Configuring Library All Facet %s', facetKey);\n router.get(`/${facetKey}`, this.getAllFacet);\n registeredAllFacets.add(facetKey);\n }\n });\n }\n\n const itemRouter = Router();\n itemRouter.get('/', this.getItem);\n itemRouter.put('/', this.updateItem);\n itemRouter.delete('/', this.deleteItem);\n\n // Configure router-level item actions first (highest precedence)\n this.logger.default('Router Item Actions', { itemActions: this.options.actions });\n if (this.options.actions) {\n Object.keys(this.options.actions).forEach((actionKey) => {\n this.logger.debug('Configuring Router Item Action %s', actionKey);\n itemRouter.post(`/${actionKey}`, this.postItemAction);\n registeredItemActions.add(actionKey);\n });\n }\n\n // Configure library item actions, warn on conflicts\n this.logger.default('Library Item Actions', { itemActions: libOptions.actions });\n if (libOptions.actions) {\n Object.keys(libOptions.actions).forEach((actionKey) => {\n if (registeredItemActions.has(actionKey)) {\n this.logger.warning('Item Action name collision - router-level handler takes precedence', { actionKey });\n } else {\n this.logger.debug('Configuring Library Item Action %s', actionKey);\n itemRouter.post(`/${actionKey}`, this.postItemAction);\n registeredItemActions.add(actionKey);\n }\n });\n }\n\n // Configure router-level item facets first (highest precedence)\n this.logger.default('Router Item Facets', { itemFacets: this.options.facets });\n if (this.options.facets) {\n Object.keys(this.options.facets).forEach((facetKey) => {\n this.logger.debug('Configuring Router Item Facet %s', facetKey);\n itemRouter.get(`/${facetKey}`, this.getItemFacet);\n registeredItemFacets.add(facetKey);\n });\n }\n\n // Configure library item facets, warn on conflicts\n this.logger.default('Library Item Facets', { itemFacets: libOptions.facets });\n if (libOptions.facets) {\n Object.keys(libOptions.facets).forEach((facetKey) => {\n if (registeredItemFacets.has(facetKey)) {\n this.logger.warning('Item Facet name collision - router-level handler takes precedence', { facetKey });\n } else {\n this.logger.debug('Configuring Library Item Facet %s', facetKey);\n itemRouter.get(`/${facetKey}`, this.getItemFacet);\n registeredItemFacets.add(facetKey);\n }\n });\n }\n\n this.logger.debug('Configuring Item Operations under PK Param %s', this.getPkParam());\n router.use(`/:${this.getPkParam()}`, this.validatePrimaryKeyValue, itemRouter);\n\n if (this.childRouters) {\n this.configureChildRouters(itemRouter, this.childRouters);\n }\n return router;\n }\n\n private validatePrimaryKeyValue = (req: Request, res: Response, next: any) => {\n const pkParamValue = req.params[this.getPkParam()];\n if (this.validatePKParam(pkParamValue)) {\n res.locals[this.getPkParam()] = pkParamValue;\n next();\n } else {\n this.logger.error('Invalid Primary Key', { pkParamValue, path: req?.originalUrl });\n res.status(500).json({ error: 'Invalid Primary Key', path: req?.originalUrl });\n }\n }\n\n private configureChildRouters = (router: Router, childRouters: Record<string, Router>) => {\n for (const path in childRouters) {\n this.logger.debug('Configuring Child Router at Path %s', path);\n\n router.use(`/${path}`, childRouters[path]);\n }\n return router;\n }\n\n public addChildRouter = (path: string, router: Router) => {\n this.childRouters[path] = router;\n }\n\n /* istanbul ignore next */\n public getRouter(): Router {\n const router = Router();\n this.configure(router);\n return router;\n }\n\n /* istanbul ignore next */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n protected createItem = async (req: Request, res: Response): Promise<void> => {\n throw new Error('Method not implemented in an abstract router');\n };\n\n // TODO: Probably a better way to do this, but this postCreate hook only needs the item.\n /* istanbul ignore next */\n public postCreateItem = async (item: Item<S, L1, L2, L3, L4, L5>): Promise<Item<S, L1, L2, L3, L4, L5>> => {\n this.logger.debug('Post Create Item', { item });\n return item;\n };\n\n protected deleteItem = async (req: Request, res: Response): Promise<void> => {\n const libOperations = this.lib.operations;\n\n this.logger.debug('Deleting Item', { query: req.query, params: req.params, locals: res.locals });\n const ik = this.getIk(res);\n try {\n const removedItem = await libOperations.remove(ik);\n const item = validatePK(removedItem, this.getPkType());\n res.json(item);\n } catch (err: any) {\n if (err instanceof NotFoundError) {\n this.logger.error('Item Not Found for Delete', { ik, message: err?.message, stack: err?.stack });\n res.status(404).json({\n ik,\n message: \"Item Not Found\",\n });\n } else {\n this.logger.error('General Error in Delete', { ik, message: err?.message, stack: err?.stack });\n res.status(500).json({\n ik,\n message: \"General Error\",\n });\n }\n }\n };\n\n /* eslint-disable */\n /* istanbul ignore next */\n protected findItems = async (req: Request, res: Response): Promise<void> => {\n throw new Error('Method not implemented in an abstract router');\n };\n /* eslint-enable */\n\n protected getItem = async (req: Request, res: Response) => {\n const libOperations = this.lib.operations;\n this.logger.debug('Getting Item', { query: req.query, params: req.params, locals: res.locals });\n const ik = this.getIk(res);\n try {\n // TODO: What error does validate PK throw, when can that fail?\n const item = validatePK(await libOperations.get(ik), this.getPkType());\n res.json(item);\n } catch (err: any) {\n if (err instanceof NotFoundError) {\n this.logger.error('Item Not Found', { ik, message: err?.message, stack: err?.stack });\n res.status(404).json({\n ik,\n message: \"Item Not Found\",\n });\n } else {\n this.logger.error('General Error', { ik, message: err?.message, stack: err?.stack });\n res.status(500).json({\n ik,\n message: \"General Error\",\n });\n }\n }\n }\n\n protected updateItem = async (req: Request, res: Response) => {\n const libOperations = this.lib.operations;\n this.logger.debug('Updating Item',\n { body: req?.body, query: req?.query, params: req?.params, locals: res?.locals });\n const ik = this.getIk(res);\n try {\n const itemToUpdate = this.convertDates(req.body as Partial<Item<S, L1, L2, L3, L4, L5>>);\n const retItem = validatePK(await libOperations.update(ik, itemToUpdate), this.getPkType());\n res.json(retItem);\n } catch (err: any) {\n if (err instanceof NotFoundError) {\n this.logger.error('Item Not Found for Update', { ik, message: err?.message, stack: err?.stack });\n res.status(404).json({\n ik,\n message: \"Item Not Found\",\n });\n } else {\n this.logger.error('General Error in Update', { ik, message: err?.message, stack: err?.stack });\n res.status(500).json({\n ik,\n message: \"General Error\",\n });\n }\n }\n };\n\n public convertDates = (item: Partial<Item<S, L1, L2, L3, L4, L5>>): Partial<Item<S, L1, L2, L3, L4, L5>> => {\n const events = item.events as Record<string, ItemEvent>;\n this.logger.debug('Converting Dates', { item });\n if (events) {\n Object.keys(events).forEach((key: string) => {\n Object.assign(events, {\n [key]: deepmerge(events[key], { at: events[key].at ? new Date(events[key].at) : null })\n });\n });\n }\n Object.assign(item, { events });\n return item;\n };\n\n // TODO: Maybe just simplify this and require that everything is a UUID?\n /**\n * This method might be an annoyance, but we need to capture a few cases where someone passes\n * a PK parameter that has an odd string in it.\n *\n * @param pkParamValue The value of the primary key parameter\n * @returns if the value is valid.\n */\n protected validatePKParam = (pkParamValue: string): boolean => {\n let validPkParam = true;\n if (pkParamValue.length <= 0) {\n this.logger.error('Primary Key is an Empty String', { pkParamValue });\n validPkParam = false;\n } else if (pkParamValue === 'undefined') {\n this.logger.error('Primary Key is the string \\'undefined\\'', { pkParamValue });\n validPkParam = false;\n }\n return validPkParam;\n }\n\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -15,7 +15,7 @@ class PItemRouter extends ItemRouter {
15
15
  let item = validatePK(await libOperations.create(itemToCreate), this.getPkType());
16
16
  item = await this.postCreateItem(item);
17
17
  this.logger.default("Created Item %j", item);
18
- res.json(item);
18
+ res.status(201).json(item);
19
19
  };
20
20
  findItems = async (req, res) => {
21
21
  const libOperations = this.lib.operations;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/PItemRouter.ts"],
4
- "sourcesContent": ["import { Item, ItemQuery, paramsToQuery, PriKey, QueryParams, validatePK } from \"@fjell/core\";\nimport { ItemRouter, ItemRouterOptions } from \"./ItemRouter.js\";\nimport { Instance } from \"./Instance.js\";\nimport { Request, Response } from \"express\";\n\ninterface ParsedQuery {\n [key: string]: undefined | string | string[] | ParsedQuery | ParsedQuery[];\n}\n\nexport class PItemRouter<T extends Item<S>, S extends string> extends ItemRouter<S> {\n\n constructor(lib: Instance<T, S>, keyType: S, options: ItemRouterOptions<S, never, never, never, never, never> = {}) {\n super(lib as any, keyType, options);\n }\n\n public getIk(res: Response): PriKey<S> {\n const pri = this.getPk(res) as PriKey<S>;\n return pri\n }\n\n public createItem = async (req: Request, res: Response) => {\n const libOperations = this.lib.operations;\n this.logger.default('Creating Item', { body: req.body, query: req.query, params: req.params, locals: res.locals });\n const itemToCreate = this.convertDates(req.body as Item<S>);\n let item = validatePK(await libOperations.create(itemToCreate), this.getPkType()) as Item<S>;\n item = await this.postCreateItem(item);\n this.logger.default('Created Item %j', item);\n res.json(item);\n };\n\n protected findItems = async (req: Request, res: Response) => {\n const libOperations = this.lib.operations;\n this.logger.default('Finding Items', { query: req.query, params: req.params, locals: res.locals });\n\n let items: Item<S>[] = [];\n\n const query: ParsedQuery = req.query as unknown as ParsedQuery;\n const finder = query['finder'] as string;\n const finderParams = query['finderParams'] as string;\n const one = query['one'] as string;\n\n if (finder) {\n // If finder is defined? Call a finder.\n this.logger.default('Finding Items with Finder %s %j one:%s', finder, finderParams, one);\n\n if (one === 'true') {\n const item = await (this.lib as any).findOne(finder, JSON.parse(finderParams));\n items = item ? [item] : [];\n } else {\n items = await libOperations.find(finder, JSON.parse(finderParams));\n }\n } else {\n // TODO: This is once of the more important places to perform some validaation and feedback\n const itemQuery: ItemQuery = paramsToQuery(req.query as QueryParams);\n this.logger.default('Finding Items with a query %j', itemQuery);\n items = await libOperations.all(itemQuery);\n }\n\n res.json(items.map((item: Item<S>) => validatePK(item, this.getPkType())));\n };\n\n}\n"],
5
- "mappings": "AAAA,SAA0B,eAAoC,kBAAkB;AAChF,SAAS,kBAAqC;AAQvC,MAAM,oBAAyD,WAAc;AAAA,EAElF,YAAY,KAAqB,SAAY,UAAmE,CAAC,GAAG;AAClH,UAAM,KAAY,SAAS,OAAO;AAAA,EACpC;AAAA,EAEO,MAAM,KAA0B;AACrC,UAAM,MAAM,KAAK,MAAM,GAAG;AAC1B,WAAO;AAAA,EACT;AAAA,EAEO,aAAa,OAAO,KAAc,QAAkB;AACzD,UAAM,gBAAgB,KAAK,IAAI;AAC/B,SAAK,OAAO,QAAQ,iBAAiB,EAAE,MAAM,IAAI,MAAM,OAAO,IAAI,OAAO,QAAQ,IAAI,QAAQ,QAAQ,IAAI,OAAO,CAAC;AACjH,UAAM,eAAe,KAAK,aAAa,IAAI,IAAe;AAC1D,QAAI,OAAO,WAAW,MAAM,cAAc,OAAO,YAAY,GAAG,KAAK,UAAU,CAAC;AAChF,WAAO,MAAM,KAAK,eAAe,IAAI;AACrC,SAAK,OAAO,QAAQ,mBAAmB,IAAI;AAC3C,QAAI,KAAK,IAAI;AAAA,EACf;AAAA,EAEU,YAAY,OAAO,KAAc,QAAkB;AAC3D,UAAM,gBAAgB,KAAK,IAAI;AAC/B,SAAK,OAAO,QAAQ,iBAAiB,EAAE,OAAO,IAAI,OAAO,QAAQ,IAAI,QAAQ,QAAQ,IAAI,OAAO,CAAC;AAEjG,QAAI,QAAmB,CAAC;AAExB,UAAM,QAAqB,IAAI;AAC/B,UAAM,SAAS,MAAM,QAAQ;AAC7B,UAAM,eAAe,MAAM,cAAc;AACzC,UAAM,MAAM,MAAM,KAAK;AAEvB,QAAI,QAAQ;AAEV,WAAK,OAAO,QAAQ,0CAA0C,QAAQ,cAAc,GAAG;AAEvF,UAAI,QAAQ,QAAQ;AAClB,cAAM,OAAO,MAAO,KAAK,IAAY,QAAQ,QAAQ,KAAK,MAAM,YAAY,CAAC;AAC7E,gBAAQ,OAAO,CAAC,IAAI,IAAI,CAAC;AAAA,MAC3B,OAAO;AACL,gBAAQ,MAAM,cAAc,KAAK,QAAQ,KAAK,MAAM,YAAY,CAAC;AAAA,MACnE;AAAA,IACF,OAAO;AAEL,YAAM,YAAuB,cAAc,IAAI,KAAoB;AACnE,WAAK,OAAO,QAAQ,iCAAiC,SAAS;AAC9D,cAAQ,MAAM,cAAc,IAAI,SAAS;AAAA,IAC3C;AAEA,QAAI,KAAK,MAAM,IAAI,CAAC,SAAkB,WAAW,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC;AAAA,EAC3E;AAEF;",
4
+ "sourcesContent": ["import { Item, ItemQuery, paramsToQuery, PriKey, QueryParams, validatePK } from \"@fjell/core\";\nimport { ItemRouter, ItemRouterOptions } from \"./ItemRouter.js\";\nimport { Instance } from \"./Instance.js\";\nimport { Request, Response } from \"express\";\n\ninterface ParsedQuery {\n [key: string]: undefined | string | string[] | ParsedQuery | ParsedQuery[];\n}\n\nexport class PItemRouter<T extends Item<S>, S extends string> extends ItemRouter<S> {\n\n constructor(lib: Instance<T, S>, keyType: S, options: ItemRouterOptions<S, never, never, never, never, never> = {}) {\n super(lib as any, keyType, options);\n }\n\n public getIk(res: Response): PriKey<S> {\n const pri = this.getPk(res) as PriKey<S>;\n return pri\n }\n\n public createItem = async (req: Request, res: Response) => {\n const libOperations = this.lib.operations;\n this.logger.default('Creating Item', { body: req.body, query: req.query, params: req.params, locals: res.locals });\n const itemToCreate = this.convertDates(req.body as Item<S>);\n let item = validatePK(await libOperations.create(itemToCreate), this.getPkType()) as Item<S>;\n item = await this.postCreateItem(item);\n this.logger.default('Created Item %j', item);\n res.status(201).json(item);\n };\n\n protected findItems = async (req: Request, res: Response) => {\n const libOperations = this.lib.operations;\n this.logger.default('Finding Items', { query: req.query, params: req.params, locals: res.locals });\n\n let items: Item<S>[] = [];\n\n const query: ParsedQuery = req.query as unknown as ParsedQuery;\n const finder = query['finder'] as string;\n const finderParams = query['finderParams'] as string;\n const one = query['one'] as string;\n\n if (finder) {\n // If finder is defined? Call a finder.\n this.logger.default('Finding Items with Finder %s %j one:%s', finder, finderParams, one);\n\n if (one === 'true') {\n const item = await (this.lib as any).findOne(finder, JSON.parse(finderParams));\n items = item ? [item] : [];\n } else {\n items = await libOperations.find(finder, JSON.parse(finderParams));\n }\n } else {\n // TODO: This is once of the more important places to perform some validaation and feedback\n const itemQuery: ItemQuery = paramsToQuery(req.query as QueryParams);\n this.logger.default('Finding Items with a query %j', itemQuery);\n items = await libOperations.all(itemQuery);\n }\n\n res.json(items.map((item: Item<S>) => validatePK(item, this.getPkType())));\n };\n\n}\n"],
5
+ "mappings": "AAAA,SAA0B,eAAoC,kBAAkB;AAChF,SAAS,kBAAqC;AAQvC,MAAM,oBAAyD,WAAc;AAAA,EAElF,YAAY,KAAqB,SAAY,UAAmE,CAAC,GAAG;AAClH,UAAM,KAAY,SAAS,OAAO;AAAA,EACpC;AAAA,EAEO,MAAM,KAA0B;AACrC,UAAM,MAAM,KAAK,MAAM,GAAG;AAC1B,WAAO;AAAA,EACT;AAAA,EAEO,aAAa,OAAO,KAAc,QAAkB;AACzD,UAAM,gBAAgB,KAAK,IAAI;AAC/B,SAAK,OAAO,QAAQ,iBAAiB,EAAE,MAAM,IAAI,MAAM,OAAO,IAAI,OAAO,QAAQ,IAAI,QAAQ,QAAQ,IAAI,OAAO,CAAC;AACjH,UAAM,eAAe,KAAK,aAAa,IAAI,IAAe;AAC1D,QAAI,OAAO,WAAW,MAAM,cAAc,OAAO,YAAY,GAAG,KAAK,UAAU,CAAC;AAChF,WAAO,MAAM,KAAK,eAAe,IAAI;AACrC,SAAK,OAAO,QAAQ,mBAAmB,IAAI;AAC3C,QAAI,OAAO,GAAG,EAAE,KAAK,IAAI;AAAA,EAC3B;AAAA,EAEU,YAAY,OAAO,KAAc,QAAkB;AAC3D,UAAM,gBAAgB,KAAK,IAAI;AAC/B,SAAK,OAAO,QAAQ,iBAAiB,EAAE,OAAO,IAAI,OAAO,QAAQ,IAAI,QAAQ,QAAQ,IAAI,OAAO,CAAC;AAEjG,QAAI,QAAmB,CAAC;AAExB,UAAM,QAAqB,IAAI;AAC/B,UAAM,SAAS,MAAM,QAAQ;AAC7B,UAAM,eAAe,MAAM,cAAc;AACzC,UAAM,MAAM,MAAM,KAAK;AAEvB,QAAI,QAAQ;AAEV,WAAK,OAAO,QAAQ,0CAA0C,QAAQ,cAAc,GAAG;AAEvF,UAAI,QAAQ,QAAQ;AAClB,cAAM,OAAO,MAAO,KAAK,IAAY,QAAQ,QAAQ,KAAK,MAAM,YAAY,CAAC;AAC7E,gBAAQ,OAAO,CAAC,IAAI,IAAI,CAAC;AAAA,MAC3B,OAAO;AACL,gBAAQ,MAAM,cAAc,KAAK,QAAQ,KAAK,MAAM,YAAY,CAAC;AAAA,MACnE;AAAA,IACF,OAAO;AAEL,YAAM,YAAuB,cAAc,IAAI,KAAoB;AACnE,WAAK,OAAO,QAAQ,iCAAiC,SAAS;AAC9D,cAAQ,MAAM,cAAc,IAAI,SAAS;AAAA,IAC3C;AAEA,QAAI,KAAK,MAAM,IAAI,CAAC,SAAkB,WAAW,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC;AAAA,EAC3E;AAEF;",
6
6
  "names": []
7
7
  }
@@ -1 +1 @@
1
- {"version":3,"file":"general.d.ts","sourceRoot":"","sources":["../../src/util/general.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,KAAK,GAAI,KAAK,GAAG;;CAI7B,CAAA;AAGD,eAAO,MAAM,aAAa,GAAa,KAAK,GAAG,EAAE,UAAS,GAAG,CAAC,GAAG,CAAa,KAAG,MAuDhF,CAAC"}
1
+ {"version":3,"file":"general.d.ts","sourceRoot":"","sources":["../../src/util/general.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,KAAK,GAAI,KAAK,GAAG;;CAI7B,CAAA;AAGD,eAAO,MAAM,aAAa,GAAa,KAAK,GAAG,EAAE,UAAS,GAAG,CAAC,GAAG,CAAa,KAAG,MAuDhF,CAAC"}
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/util/general.ts"],
4
- "sourcesContent": ["\n/* eslint-disable no-undefined, @typescript-eslint/no-unused-vars */\nexport const clean = (obj: any) => {\n return Object.fromEntries(\n Object.entries(obj).filter(([_, v]) => v !== undefined)\n );\n}\n\n//Recursive implementation of jSON.stringify;\nexport const stringifyJSON = function (obj: any, visited: Set<any> = new Set()): string {\n const arrOfKeyVals: string[] = [];\n const arrVals: string[] = [];\n let objKeys: string[] = [];\n\n /*********CHECK FOR PRIMITIVE TYPES**********/\n if (typeof obj === 'number' || typeof obj === 'boolean' || obj === null)\n return '' + obj;\n else if (typeof obj === 'string')\n return '\"' + obj + '\"';\n\n /*********DETECT CIRCULAR REFERENCES**********/\n if (obj instanceof Object && visited.has(obj)) {\n return '\"(circular)\"';\n }\n\n /*********CHECK FOR ARRAY**********/\n else if (Array.isArray(obj)) {\n //check for empty array\n if (obj[0] === undefined)\n return '[]';\n else {\n // Add array to visited before processing its elements\n visited.add(obj);\n obj.forEach(function (el) {\n arrVals.push(stringifyJSON(el, visited));\n });\n return '[' + arrVals + ']';\n }\n }\n /*********CHECK FOR OBJECT**********/\n else if (obj instanceof Object) {\n // Add object to visited before processing its properties\n visited.add(obj);\n //get object keys\n objKeys = Object.keys(obj);\n //set key output;\n objKeys.forEach(function (key) {\n const keyOut = '\"' + key + '\":';\n const keyValOut = obj[key];\n //skip functions and undefined properties\n if (keyValOut instanceof Function || keyValOut === undefined)\n return; // Skip this entry entirely instead of pushing an empty string\n else if (typeof keyValOut === 'string')\n arrOfKeyVals.push(keyOut + '\"' + keyValOut + '\"');\n else if (typeof keyValOut === 'boolean' || typeof keyValOut === 'number' || keyValOut === null)\n arrOfKeyVals.push(keyOut + keyValOut);\n //check for nested objects, call recursively until no more objects\n else if (keyValOut instanceof Object) {\n arrOfKeyVals.push(keyOut + stringifyJSON(keyValOut, visited));\n }\n });\n return '{' + arrOfKeyVals + '}';\n }\n return '';\n};\n"],
5
- "mappings": "AAEO,MAAM,QAAQ,CAAC,QAAa;AACjC,SAAO,OAAO;AAAA,IACZ,OAAO,QAAQ,GAAG,EAAE,OAAO,CAAC,CAAC,GAAG,CAAC,MAAM,MAAM,MAAS;AAAA,EACxD;AACF;AAGO,MAAM,gBAAgB,SAAU,KAAU,UAAoB,oBAAI,IAAI,GAAW;AACtF,QAAM,eAAyB,CAAC;AAChC,QAAM,UAAoB,CAAC;AAC3B,MAAI,UAAoB,CAAC;AAGzB,MAAI,OAAO,QAAQ,YAAY,OAAO,QAAQ,aAAa,QAAQ;AACjE,WAAO,KAAK;AAAA,WACL,OAAO,QAAQ;AACtB,WAAO,MAAM,MAAM;AAGrB,MAAI,eAAe,UAAU,QAAQ,IAAI,GAAG,GAAG;AAC7C,WAAO;AAAA,EACT,WAGS,MAAM,QAAQ,GAAG,GAAG;AAE3B,QAAI,IAAI,CAAC,MAAM;AACb,aAAO;AAAA,SACJ;AAEH,cAAQ,IAAI,GAAG;AACf,UAAI,QAAQ,SAAU,IAAI;AACxB,gBAAQ,KAAK,cAAc,IAAI,OAAO,CAAC;AAAA,MACzC,CAAC;AACD,aAAO,MAAM,UAAU;AAAA,IACzB;AAAA,EACF,WAES,eAAe,QAAQ;AAE9B,YAAQ,IAAI,GAAG;AAEf,cAAU,OAAO,KAAK,GAAG;AAEzB,YAAQ,QAAQ,SAAU,KAAK;AAC7B,YAAM,SAAS,MAAM,MAAM;AAC3B,YAAM,YAAY,IAAI,GAAG;AAEzB,UAAI,qBAAqB,YAAY,cAAc;AACjD;AAAA,eACO,OAAO,cAAc;AAC5B,qBAAa,KAAK,SAAS,MAAM,YAAY,GAAG;AAAA,eACzC,OAAO,cAAc,aAAa,OAAO,cAAc,YAAY,cAAc;AACxF,qBAAa,KAAK,SAAS,SAAS;AAAA,eAE7B,qBAAqB,QAAQ;AACpC,qBAAa,KAAK,SAAS,cAAc,WAAW,OAAO,CAAC;AAAA,MAC9D;AAAA,IACF,CAAC;AACD,WAAO,MAAM,eAAe;AAAA,EAC9B;AACA,SAAO;AACT;",
4
+ "sourcesContent": ["/* eslint-disable @typescript-eslint/no-unused-vars */\n\n/* eslint-disable no-undefined */\nexport const clean = (obj: any) => {\n return Object.fromEntries(\n Object.entries(obj).filter(([_, v]) => v !== undefined)\n );\n}\n\n//Recursive implementation of jSON.stringify;\nexport const stringifyJSON = function (obj: any, visited: Set<any> = new Set()): string {\n const arrOfKeyVals: string[] = [];\n const arrVals: string[] = [];\n let objKeys: string[] = [];\n\n /*********CHECK FOR PRIMITIVE TYPES**********/\n if (typeof obj === 'number' || typeof obj === 'boolean' || obj === null)\n return '' + obj;\n else if (typeof obj === 'string')\n return '\"' + obj + '\"';\n\n /*********DETECT CIRCULAR REFERENCES**********/\n if (obj instanceof Object && visited.has(obj)) {\n return '\"(circular)\"';\n }\n\n /*********CHECK FOR ARRAY**********/\n else if (Array.isArray(obj)) {\n //check for empty array\n if (obj[0] === undefined)\n return '[]';\n else {\n // Add array to visited before processing its elements\n visited.add(obj);\n obj.forEach(function (el) {\n arrVals.push(stringifyJSON(el, visited));\n });\n return '[' + arrVals + ']';\n }\n }\n /*********CHECK FOR OBJECT**********/\n else if (obj instanceof Object) {\n // Add object to visited before processing its properties\n visited.add(obj);\n //get object keys\n objKeys = Object.keys(obj);\n //set key output;\n objKeys.forEach(function (key) {\n const keyOut = '\"' + key + '\":';\n const keyValOut = obj[key];\n //skip functions and undefined properties\n if (keyValOut instanceof Function || keyValOut === undefined)\n return; // Skip this entry entirely instead of pushing an empty string\n else if (typeof keyValOut === 'string')\n arrOfKeyVals.push(keyOut + '\"' + keyValOut + '\"');\n else if (typeof keyValOut === 'boolean' || typeof keyValOut === 'number' || keyValOut === null)\n arrOfKeyVals.push(keyOut + keyValOut);\n //check for nested objects, call recursively until no more objects\n else if (keyValOut instanceof Object) {\n arrOfKeyVals.push(keyOut + stringifyJSON(keyValOut, visited));\n }\n });\n return '{' + arrOfKeyVals + '}';\n }\n return '';\n};\n"],
5
+ "mappings": "AAGO,MAAM,QAAQ,CAAC,QAAa;AACjC,SAAO,OAAO;AAAA,IACZ,OAAO,QAAQ,GAAG,EAAE,OAAO,CAAC,CAAC,GAAG,CAAC,MAAM,MAAM,MAAS;AAAA,EACxD;AACF;AAGO,MAAM,gBAAgB,SAAU,KAAU,UAAoB,oBAAI,IAAI,GAAW;AACtF,QAAM,eAAyB,CAAC;AAChC,QAAM,UAAoB,CAAC;AAC3B,MAAI,UAAoB,CAAC;AAGzB,MAAI,OAAO,QAAQ,YAAY,OAAO,QAAQ,aAAa,QAAQ;AACjE,WAAO,KAAK;AAAA,WACL,OAAO,QAAQ;AACtB,WAAO,MAAM,MAAM;AAGrB,MAAI,eAAe,UAAU,QAAQ,IAAI,GAAG,GAAG;AAC7C,WAAO;AAAA,EACT,WAGS,MAAM,QAAQ,GAAG,GAAG;AAE3B,QAAI,IAAI,CAAC,MAAM;AACb,aAAO;AAAA,SACJ;AAEH,cAAQ,IAAI,GAAG;AACf,UAAI,QAAQ,SAAU,IAAI;AACxB,gBAAQ,KAAK,cAAc,IAAI,OAAO,CAAC;AAAA,MACzC,CAAC;AACD,aAAO,MAAM,UAAU;AAAA,IACzB;AAAA,EACF,WAES,eAAe,QAAQ;AAE9B,YAAQ,IAAI,GAAG;AAEf,cAAU,OAAO,KAAK,GAAG;AAEzB,YAAQ,QAAQ,SAAU,KAAK;AAC7B,YAAM,SAAS,MAAM,MAAM;AAC3B,YAAM,YAAY,IAAI,GAAG;AAEzB,UAAI,qBAAqB,YAAY,cAAc;AACjD;AAAA,eACO,OAAO,cAAc;AAC5B,qBAAa,KAAK,SAAS,MAAM,YAAY,GAAG;AAAA,eACzC,OAAO,cAAc,aAAa,OAAO,cAAc,YAAY,cAAc;AACxF,qBAAa,KAAK,SAAS,SAAS;AAAA,eAE7B,qBAAqB,QAAQ;AACpC,qBAAa,KAAK,SAAS,cAAc,WAAW,OAAO,CAAC;AAAA,MAC9D;AAAA,IACF,CAAC;AACD,WAAO,MAAM,eAAe;AAAA,EAC9B;AACA,SAAO;AACT;",
6
6
  "names": []
7
7
  }
@@ -39,6 +39,10 @@ export interface Task extends Item<'task'> {
39
39
  const mockUserStorage = new Map<string, User>();
40
40
  const mockTaskStorage = new Map<string, Task>();
41
41
 
42
+ // Counters for unique ID generation
43
+ let userIdCounter = 1000;
44
+ let taskIdCounter = 1000;
45
+
42
46
  // Initialize with some sample data
43
47
  const initializeSampleData = () => {
44
48
  const users: User[] = [
@@ -130,7 +134,7 @@ const createUserOperations = () => {
130
134
 
131
135
  async create(item: User) {
132
136
  console.log(`✨ UserOperations.create() - Creating user: ${item.name}`);
133
- const id = `user-${Date.now().toString()}`;
137
+ const id = `user-${++userIdCounter}`;
134
138
  const newUser: User = {
135
139
  ...item,
136
140
  id,
@@ -170,7 +174,7 @@ const createUserOperations = () => {
170
174
  return false;
171
175
  }
172
176
  mockUserStorage.delete(String(key.pk));
173
- return true;
177
+ return existing;
174
178
  },
175
179
 
176
180
  async find(finder: string, params: any) {
@@ -207,7 +211,7 @@ const createTaskOperations = () => {
207
211
 
208
212
  async create(item: Task) {
209
213
  console.log(`✨ TaskOperations.create() - Creating task: ${item.title}`);
210
- const id = `task-${Date.now().toString()}`;
214
+ const id = `task-${++taskIdCounter}`;
211
215
  const newTask: Task = {
212
216
  ...item,
213
217
  id,
@@ -247,7 +251,7 @@ const createTaskOperations = () => {
247
251
  return false;
248
252
  }
249
253
  mockTaskStorage.delete(String(key.pk));
250
- return true;
254
+ return existing;
251
255
  },
252
256
 
253
257
  async find(finder: string, params: any) {
@@ -86,6 +86,13 @@ const mockReviewStorage = new Map<string, Review>();
86
86
 
87
87
  // ===== Sample Data Initialization =====
88
88
  const initializeSampleData = () => {
89
+ // Clear existing data
90
+ mockCustomerStorage.clear();
91
+ mockProductStorage.clear();
92
+ mockOrderStorage.clear();
93
+ mockOrderItemStorage.clear();
94
+ mockReviewStorage.clear();
95
+
89
96
  // Sample customers
90
97
  const customers: Customer[] = [
91
98
  {
@@ -489,10 +496,19 @@ export const runFullApplicationExample = async (): Promise<{ app: Application }>
489
496
  app.use('/api/customers', (req, res, next) => {
490
497
  // Only validate for direct customer creation, not nested routes like orders
491
498
  if (req.method === 'POST' && req.path === '/') {
492
- const { name, email } = req.body;
499
+ const { name, email, phone, address, tier } = req.body;
493
500
  if (!name || !email) {
494
501
  return res.status(500).json({ error: 'Missing required fields: name and email' });
495
502
  }
503
+ if (!phone || !address || !tier) {
504
+ return res.status(500).json({ error: 'Missing required fields: phone, address, and tier' });
505
+ }
506
+ if (!address.street || !address.city || !address.state || !address.zipCode) {
507
+ return res.status(500).json({ error: 'Missing required address fields: street, city, state, and zipCode' });
508
+ }
509
+ if (!['bronze', 'silver', 'gold', 'platinum'].includes(tier)) {
510
+ return res.status(500).json({ error: 'Invalid tier. Must be bronze, silver, gold, or platinum' });
511
+ }
496
512
  }
497
513
  next();
498
514
  });
@@ -553,7 +569,24 @@ export const runFullApplicationExample = async (): Promise<{ app: Application }>
553
569
  });
554
570
  app.use('/api/customers/:customerPk/orders', orderRouter.getRouter());
555
571
 
556
- // Customer router last to avoid route conflicts
572
+ // Security validation middleware for customer routes - must be BEFORE router
573
+ app.use('/api/customers/:customerPk', (req, res, next) => {
574
+ const { customerPk } = req.params;
575
+
576
+ // Check for path traversal attempts
577
+ if (customerPk.includes('../') || customerPk.includes('..\\') || customerPk.includes('%2e%2e')) {
578
+ return res.status(500).json({ error: 'Path traversal attempt detected' });
579
+ }
580
+
581
+ // Check for null byte injection
582
+ if (customerPk.includes('\x00') || customerPk.includes('%00') || customerPk.includes('\u0000')) {
583
+ return res.status(500).json({ error: 'Null byte injection attempt detected' });
584
+ }
585
+
586
+ next();
587
+ });
588
+
589
+ // Customer router after security validation
557
590
  app.use('/api/customers', customerRouter.getRouter());
558
591
 
559
592
  // Custom find routes for better test compatibility
@@ -1,4 +1,5 @@
1
1
  /* eslint-disable @typescript-eslint/no-unused-vars */
2
+
2
3
  import { CItemRouter, createRegistry, PItemRouter } from '../src';
3
4
  import { ComKey, Item, PriKey } from '@fjell/core';
4
5
  import express from 'express';
@@ -110,141 +111,156 @@ const postInstance = {
110
111
 
111
112
  // Create routers with router-level handlers
112
113
  const userRouter = new PItemRouter(userInstance, 'user', {
113
- // Router-level action handlers
114
+ // Router-level action handlers - aligned with library operation signatures
114
115
  actions: {
115
- activate: async (req: Request, res: Response, ik: PriKey<'user'>) => {
116
+ activate: async (ik: PriKey<'user'>, actionParams: any, _context: { req: Request, res: Response }) => {
116
117
  console.log('Router-level activate action called for user:', ik.pk);
118
+ console.log('Action params:', actionParams);
117
119
  // Custom logic: send activation email, update status, etc.
118
- res.json({
120
+ const result = {
119
121
  message: 'User activated via router handler',
120
122
  userId: ik.pk,
121
123
  timestamp: new Date().toISOString(),
122
124
  emailSent: true
123
- });
125
+ };
126
+ return result;
124
127
  },
125
- deactivate: async (req: Request, res: Response, ik: PriKey<'user'>) => {
128
+ deactivate: async (ik: PriKey<'user'>, actionParams: any, _context: { req: Request, res: Response }) => {
126
129
  console.log('Router-level deactivate action called for user:', ik.pk);
130
+ console.log('Action params:', actionParams);
127
131
  // Custom logic: send deactivation notification, update status, etc.
128
- res.json({
132
+ const result = {
129
133
  message: 'User deactivated via router handler',
130
134
  userId: ik.pk,
131
135
  timestamp: new Date().toISOString(),
132
136
  notificationSent: true
133
- });
137
+ };
138
+ return result;
134
139
  }
135
140
  },
136
141
 
137
- // Router-level facet handlers
142
+ // Router-level facet handlers - aligned with library operation signatures
138
143
  facets: {
139
- profile: async (req: Request, res: Response, ik: PriKey<'user'>) => {
144
+ profile: async (ik: PriKey<'user'>, facetParams: any, _context: { req: Request, res: Response }) => {
140
145
  console.log('Router-level profile facet called for user:', ik.pk);
146
+ console.log('Facet params:', facetParams);
141
147
  // Custom logic: aggregate data from multiple sources
142
- res.json({
148
+ return {
143
149
  userId: ik.pk,
144
150
  basicInfo: { name: 'John Doe', email: 'john@example.com' },
145
151
  extendedInfo: { lastLogin: new Date(), preferences: { theme: 'dark' } },
146
152
  socialInfo: { followers: 150, following: 75 }
147
- });
153
+ };
148
154
  },
149
- stats: async (req: Request, res: Response, ik: PriKey<'user'>) => {
155
+ stats: async (ik: PriKey<'user'>, facetParams: any, _context: { req: Request, res: Response }) => {
150
156
  console.log('Router-level stats facet called for user:', ik.pk);
157
+ console.log('Facet params:', facetParams);
151
158
  // Custom logic: calculate statistics from multiple data sources
152
- res.json({
159
+ return {
153
160
  userId: ik.pk,
154
161
  postsCount: 25,
155
162
  commentsCount: 150,
156
163
  likesReceived: 500,
157
164
  lastActivity: new Date()
158
- });
165
+ };
159
166
  }
160
167
  },
161
168
 
162
- // Router-level all action handlers
169
+ // Router-level all action handlers - aligned with library operation signatures
163
170
  allActions: {
164
- bulkActivate: async (req: Request, res: Response) => {
171
+ bulkActivate: async (allActionParams: any, locations: any, _context: { req: Request, res: Response }) => {
165
172
  console.log('Router-level bulk activate action called');
173
+ console.log('All action params:', allActionParams);
174
+ console.log('Locations:', locations);
166
175
  // Custom logic: batch processing, external service integration
167
- const { userIds } = req.body;
168
- res.json({
176
+ const { userIds } = allActionParams;
177
+ return {
169
178
  message: 'Bulk activation via router handler',
170
- processedUsers: userIds.length,
179
+ processedUsers: userIds?.length || 0,
171
180
  timestamp: new Date().toISOString(),
172
181
  externalServiceCalled: true
173
- });
182
+ };
174
183
  },
175
- bulkDeactivate: async (req: Request, res: Response) => {
184
+ bulkDeactivate: async (allActionParams: any, locations: any, _context: { req: Request, res: Response }) => {
176
185
  console.log('Router-level bulk deactivate action called');
186
+ console.log('All action params:', allActionParams);
187
+ console.log('Locations:', locations);
177
188
  // Custom logic: batch processing, audit logging
178
- const { userIds } = req.body;
179
- res.json({
189
+ const { userIds } = allActionParams;
190
+ return {
180
191
  message: 'Bulk deactivation via router handler',
181
- processedUsers: userIds.length,
192
+ processedUsers: userIds?.length || 0,
182
193
  timestamp: new Date().toISOString(),
183
194
  auditLogged: true
184
- });
195
+ };
185
196
  }
186
197
  },
187
198
 
188
- // Router-level all facet handlers
199
+ // Router-level all facet handlers - aligned with library operation signatures
189
200
  allFacets: {
190
- userStats: async (req: Request, res: Response) => {
201
+ userStats: async (allFacetParams: any, locations: any, _context: { req: Request, res: Response }) => {
191
202
  console.log('Router-level user stats facet called');
203
+ console.log('All facet params:', allFacetParams);
204
+ console.log('Locations:', locations);
192
205
  // Custom logic: aggregate statistics from multiple systems
193
- res.json({
206
+ return {
194
207
  totalUsers: 1250,
195
208
  activeUsers: 890,
196
209
  newUsersThisMonth: 45,
197
210
  topRoles: { admin: 15, user: 1200, guest: 35 },
198
211
  systemHealth: 'excellent'
199
- });
212
+ };
200
213
  },
201
- userCount: async (req: Request, res: Response) => {
214
+ userCount: async (_allFacetParams: any, _locations: any, _context: { req: Request, res: Response }) => {
202
215
  console.log('Router-level user count facet called');
203
216
  // Custom logic: real-time count from cache
204
- res.json({
217
+ return {
205
218
  count: 1250,
206
219
  lastUpdated: new Date().toISOString(),
207
220
  source: 'cache'
208
- });
221
+ };
209
222
  }
210
223
  }
211
224
  } as any);
212
225
 
213
226
  const postRouter = new CItemRouter(postInstance, 'post', userRouter, {
214
- // Router-level action handlers for posts
227
+ // Router-level action handlers for posts - aligned with library operation signatures
215
228
  actions: {
216
- publish: async (req: Request, res: Response, ik: ComKey<'post', 'user'>) => {
229
+ publish: async (ik: ComKey<'post', 'user'>, actionParams: any, _context: { req: Request, res: Response }) => {
217
230
  console.log('Router-level publish action called for post:', ik.pk);
231
+ console.log('Action params:', actionParams);
218
232
  // Custom logic: publish to social media, send notifications
219
- res.json({
233
+ return {
220
234
  message: 'Post published via router handler',
221
235
  postId: ik.pk,
222
236
  authorId: ik.loc[0].lk,
223
237
  publishedAt: new Date().toISOString(),
224
238
  socialMediaPosted: true,
225
239
  notificationsSent: true
226
- });
240
+ };
227
241
  },
228
- unpublish: async (req: Request, res: Response, ik: ComKey<'post', 'user'>) => {
242
+ unpublish: async (ik: ComKey<'post', 'user'>, actionParams: any, _context: { req: Request, res: Response }) => {
229
243
  console.log('Router-level unpublish action called for post:', ik.pk);
244
+ console.log('Action params:', actionParams);
230
245
  // Custom logic: remove from social media, send notifications
231
- res.json({
246
+ return {
232
247
  message: 'Post unpublished via router handler',
233
248
  postId: ik.pk,
234
249
  authorId: ik.loc[0].lk,
235
250
  unpublishedAt: new Date().toISOString(),
236
251
  socialMediaRemoved: true,
237
252
  notificationsSent: true
238
- });
253
+ };
239
254
  }
240
255
  },
241
256
 
242
- // Router-level facet handlers for posts
257
+ // Router-level facet handlers for posts - aligned with library operation signatures
243
258
  facets: {
244
- analytics: async (req: Request, res: Response, ik: ComKey<'post', 'user'>) => {
259
+ analytics: async (ik: ComKey<'post', 'user'>, facetParams: any, _context: { req: Request, res: Response }) => {
245
260
  console.log('Router-level analytics facet called for post:', ik.pk);
261
+ console.log('Facet params:', facetParams);
246
262
  // Custom logic: aggregate analytics from multiple sources
247
- res.json({
263
+ return {
248
264
  postId: ik.pk,
249
265
  views: 1250,
250
266
  likes: 89,
@@ -252,72 +268,81 @@ const postRouter = new CItemRouter(postInstance, 'post', userRouter, {
252
268
  comments: 15,
253
269
  engagementRate: 0.12,
254
270
  topReferrers: ['twitter.com', 'facebook.com', 'linkedin.com']
255
- });
271
+ };
256
272
  },
257
- comments: async (req: Request, res: Response, ik: ComKey<'post', 'user'>) => {
273
+ comments: async (ik: ComKey<'post', 'user'>, facetParams: any, _context: { req: Request, res: Response }) => {
258
274
  console.log('Router-level comments facet called for post:', ik.pk);
275
+ console.log('Facet params:', facetParams);
259
276
  // Custom logic: fetch comments from external service
260
- res.json({
277
+ return {
261
278
  postId: ik.pk,
262
279
  comments: [
263
280
  { id: 'comment_1', text: 'Great post!', author: 'user_2', timestamp: new Date() },
264
281
  { id: 'comment_2', text: 'Very informative', author: 'user_3', timestamp: new Date() }
265
282
  ],
266
283
  totalComments: 2
267
- });
284
+ };
268
285
  }
269
286
  },
270
287
 
271
- // Router-level all action handlers for posts
288
+ // Router-level all action handlers for posts - aligned with library operation signatures
272
289
  allActions: {
273
- bulkPublish: async (req: Request, res: Response) => {
290
+ bulkPublish: async (allActionParams: any, locations: any, _context: { req: Request, res: Response }) => {
274
291
  console.log('Router-level bulk publish action called');
292
+ console.log('All action params:', allActionParams);
293
+ console.log('Locations:', locations);
275
294
  // Custom logic: batch publishing to multiple platforms
276
- const { postIds } = req.body;
277
- res.json({
295
+ const { postIds } = allActionParams;
296
+ return {
278
297
  message: 'Bulk publish via router handler',
279
- processedPosts: postIds.length,
298
+ processedPosts: postIds?.length || 0,
280
299
  timestamp: new Date().toISOString(),
281
300
  platformsUpdated: ['twitter', 'facebook', 'linkedin']
282
- });
301
+ };
283
302
  },
284
- bulkUnpublish: async (req: Request, res: Response) => {
303
+ bulkUnpublish: async (allActionParams: any, locations: any, _context: { req: Request, res: Response }) => {
285
304
  console.log('Router-level bulk unpublish action called');
305
+ console.log('All action params:', allActionParams);
306
+ console.log('Locations:', locations);
286
307
  // Custom logic: batch unpublishing from multiple platforms
287
- const { postIds } = req.body;
288
- res.json({
308
+ const { postIds } = allActionParams;
309
+ return {
289
310
  message: 'Bulk unpublish via router handler',
290
- processedPosts: postIds.length,
311
+ processedPosts: postIds?.length || 0,
291
312
  timestamp: new Date().toISOString(),
292
313
  platformsUpdated: ['twitter', 'facebook', 'linkedin']
293
- });
314
+ };
294
315
  }
295
316
  },
296
317
 
297
- // Router-level all facet handlers for posts
318
+ // Router-level all facet handlers for posts - aligned with library operation signatures
298
319
  allFacets: {
299
- postStats: async (req: Request, res: Response) => {
320
+ postStats: async (allFacetParams: any, locations: any, _context: { req: Request, res: Response }) => {
300
321
  console.log('Router-level post stats facet called');
322
+ console.log('All facet params:', allFacetParams);
323
+ console.log('Locations:', locations);
301
324
  // Custom logic: aggregate post statistics
302
- res.json({
325
+ return {
303
326
  totalPosts: 450,
304
327
  publishedPosts: 380,
305
328
  draftPosts: 70,
306
329
  averageViews: 850,
307
330
  averageLikes: 45,
308
331
  topCategories: ['technology', 'business', 'lifestyle']
309
- });
332
+ };
310
333
  },
311
- postCount: async (req: Request, res: Response) => {
334
+ postCount: async (allFacetParams: any, locations: any, _context: { req: Request, res: Response }) => {
312
335
  console.log('Router-level post count facet called');
336
+ console.log('All facet params:', allFacetParams);
337
+ console.log('Locations:', locations);
313
338
  // Custom logic: real-time count with filtering
314
- res.json({
339
+ return {
315
340
  count: 450,
316
341
  published: 380,
317
342
  draft: 70,
318
343
  lastUpdated: new Date().toISOString(),
319
344
  source: 'database'
320
- });
345
+ };
321
346
  }
322
347
  }
323
348
  } as any);
@@ -0,0 +1,214 @@
1
+ /* eslint-disable @typescript-eslint/no-unused-vars */
2
+ /**
3
+ * Example: Router-Level Options with Name Collision Handling
4
+ *
5
+ * This example demonstrates how router-level actions, facets, allActions, and allFacets
6
+ * take precedence over library-level options with the same names, and how collision
7
+ * warnings are logged when there are conflicts.
8
+ */
9
+
10
+ import { ItemRouter, ItemRouterOptions } from "../src/ItemRouter.js";
11
+ import { ComKey, Item, LocKeyArray, PriKey } from "@fjell/core";
12
+ import { Request, Response } from "express";
13
+
14
+ // Sample Item Types
15
+ type User = Item<"user", "tenant">;
16
+ type Tenant = Item<"tenant">;
17
+
18
+ // Mock library instance with actions/facets that will collide with router options
19
+ const mockLibWithConflicts = {
20
+ operations: {
21
+ get: async () => ({ key: { kt: "user", pk: "user-1" }, name: "John Doe" } as User),
22
+ create: async () => ({ key: { kt: "user", pk: "user-2" }, name: "Jane Doe" } as User),
23
+ update: async () => ({ key: { kt: "user", pk: "user-1" }, name: "John Updated" } as User),
24
+ remove: async () => ({ key: { kt: "user", pk: "user-1" }, name: "John Doe" } as User),
25
+ all: async () => [] as User[],
26
+ find: async () => [] as User[],
27
+ findOne: async () => null,
28
+ action: async (ik: any, actionKey: string) => ({ source: "library", action: actionKey }),
29
+ facet: async (ik: any, facetKey: string) => ({ source: "library", facet: facetKey }),
30
+ allAction: async (actionKey: string) => ({ source: "library", allAction: actionKey }),
31
+ allFacet: async (facetKey: string) => ({ source: "library", allFacet: facetKey })
32
+ },
33
+ options: {
34
+ // These will collide with router-level options
35
+ actions: {
36
+ activate: async () => ({ source: "library", action: "activate" }),
37
+ archive: async () => ({ source: "library", action: "archive" })
38
+ },
39
+ facets: {
40
+ profile: async () => ({ source: "library", facet: "profile" }),
41
+ settings: async () => ({ source: "library", facet: "settings" })
42
+ },
43
+ allActions: {
44
+ bulkUpdate: async () => ({ source: "library", allAction: "bulkUpdate" }),
45
+ export: async () => ({ source: "library", allAction: "export" })
46
+ },
47
+ allFacets: {
48
+ analytics: async () => ({ source: "library", allFacet: "analytics" }),
49
+ dashboard: async () => ({ source: "library", allFacet: "dashboard" })
50
+ }
51
+ }
52
+ };
53
+
54
+ class UserRouter extends ItemRouter<"user", "tenant"> {
55
+ protected getIk(res: Response): ComKey<"user", "tenant"> {
56
+ return {
57
+ kt: "user",
58
+ pk: res.locals.userPk,
59
+ loc: [{ kt: "tenant", lk: res.locals.tenantId || "tenant-1" }]
60
+ };
61
+ }
62
+
63
+ protected getLocations(res: Response): LocKeyArray<"tenant"> {
64
+ return [{ kt: "tenant", lk: res.locals.tenantId || "tenant-1" }];
65
+ }
66
+
67
+ public createItem = async (req: Request, res: Response): Promise<void> => {
68
+ const newUser: User = {
69
+ key: { kt: "user", pk: "user-new", loc: this.getLocations(res) },
70
+ name: req.body.name || "New User",
71
+ email: req.body.email || "new@example.com",
72
+ events: {
73
+ created: { at: new Date() },
74
+ updated: { at: new Date() },
75
+ deleted: { at: null }
76
+ }
77
+ };
78
+ res.json(newUser);
79
+ };
80
+
81
+ public findItems = async (req: Request, res: Response): Promise<void> => {
82
+ const users: User[] = [
83
+ {
84
+ key: { kt: "user", pk: "user-1", loc: this.getLocations(res) },
85
+ name: "John Doe",
86
+ email: "john@example.com",
87
+ events: {
88
+ created: { at: new Date() },
89
+ updated: { at: new Date() },
90
+ deleted: { at: null }
91
+ }
92
+ }
93
+ ];
94
+ res.json(users);
95
+ };
96
+ }
97
+
98
+ /**
99
+ * Router-level options that will take precedence over library options
100
+ * Notice some of these have the same names as the library options
101
+ */
102
+ const routerOptions: ItemRouterOptions<"user", "tenant"> = {
103
+ // These will override library actions with same names
104
+ actions: {
105
+ activate: async (ik, params, { req, res }) => {
106
+ console.log("🚀 Router-level activate action called!");
107
+ return { source: "router", action: "activate", ik, params };
108
+ },
109
+ archive: async (ik, params, { req, res }) => {
110
+ console.log("📦 Router-level archive action called!");
111
+ return { source: "router", action: "archive", ik, params };
112
+ },
113
+ // This one is unique to router
114
+ resetPassword: async (ik, params, { req, res }) => {
115
+ console.log("🔑 Router-level resetPassword action called!");
116
+ return { source: "router", action: "resetPassword", ik, params };
117
+ }
118
+ },
119
+
120
+ // These will override library facets with same names
121
+ facets: {
122
+ profile: async (ik, params, { req, res }) => {
123
+ console.log("👤 Router-level profile facet called!");
124
+ return { source: "router", facet: "profile", ik, params };
125
+ },
126
+ settings: async (ik, params, { req, res }) => {
127
+ console.log("⚙️ Router-level settings facet called!");
128
+ return { source: "router", facet: "settings", ik, params };
129
+ },
130
+ // This one is unique to router
131
+ permissions: async (ik, params, { req, res }) => {
132
+ console.log("🔒 Router-level permissions facet called!");
133
+ return { source: "router", facet: "permissions", ik, params };
134
+ }
135
+ },
136
+
137
+ // These will override library allActions with same names
138
+ allActions: {
139
+ bulkUpdate: async (params, locations, { req, res }) => {
140
+ console.log("📝 Router-level bulkUpdate allAction called!");
141
+ return { source: "router", allAction: "bulkUpdate", params, locations };
142
+ },
143
+ export: async (params, locations, { req, res }) => {
144
+ console.log("📤 Router-level export allAction called!");
145
+ return { source: "router", allAction: "export", params, locations };
146
+ },
147
+ // This one is unique to router
148
+ backup: async (params, locations, { req, res }) => {
149
+ console.log("💾 Router-level backup allAction called!");
150
+ return { source: "router", allAction: "backup", params, locations };
151
+ }
152
+ },
153
+
154
+ // These will override library allFacets with same names
155
+ allFacets: {
156
+ analytics: async (params, locations, { req, res }) => {
157
+ console.log("📊 Router-level analytics allFacet called!");
158
+ return { source: "router", allFacet: "analytics", params, locations };
159
+ },
160
+ dashboard: async (params, locations, { req, res }) => {
161
+ console.log("📈 Router-level dashboard allFacet called!");
162
+ return { source: "router", allFacet: "dashboard", params, locations };
163
+ },
164
+ // This one is unique to router
165
+ reports: async (params, locations, { req, res }) => {
166
+ console.log("📋 Router-level reports allFacet called!");
167
+ return { source: "router", allFacet: "reports", params, locations };
168
+ }
169
+ }
170
+ };
171
+
172
+ export function createRouterWithCollisions() {
173
+ console.log("🎭 Creating UserRouter with router-level options that collide with library options...");
174
+ console.log("⚠️ Watch for collision warnings in the logs!");
175
+
176
+ // Create router with options that will collide with library options
177
+ const userRouter = new UserRouter(mockLibWithConflicts as any, "user", routerOptions);
178
+
179
+ console.log("✅ Router created successfully!");
180
+ console.log("📋 Available endpoints with precedence:");
181
+ console.log(" Actions (router overrides library):");
182
+ console.log(" ✅ POST /users/:userPk/activate (Router-level handler)");
183
+ console.log(" ✅ POST /users/:userPk/archive (Router-level handler)");
184
+ console.log(" 🆕 POST /users/:userPk/resetPassword (Router-only)");
185
+ console.log(" Facets (router overrides library):");
186
+ console.log(" ✅ GET /users/:userPk/profile (Router-level handler)");
187
+ console.log(" ✅ GET /users/:userPk/settings (Router-level handler)");
188
+ console.log(" 🆕 GET /users/:userPk/permissions (Router-only)");
189
+ console.log(" All Actions (router overrides library):");
190
+ console.log(" ✅ POST /users/bulkUpdate (Router-level handler)");
191
+ console.log(" ✅ POST /users/export (Router-level handler)");
192
+ console.log(" 🆕 POST /users/backup (Router-only)");
193
+ console.log(" All Facets (router overrides library):");
194
+ console.log(" ✅ GET /users/analytics (Router-level handler)");
195
+ console.log(" ✅ GET /users/dashboard (Router-level handler)");
196
+ console.log(" 🆕 GET /users/reports (Router-only)");
197
+
198
+ return {
199
+ userRouter,
200
+ expressRouter: userRouter.getRouter()
201
+ };
202
+ }
203
+
204
+ // Example usage
205
+ if (import.meta.url === `file://${process.argv[1]}`) {
206
+ console.log("🚀 Starting Router Options Collision Example...");
207
+ console.log("=".repeat(60));
208
+
209
+ const { userRouter, expressRouter } = createRouterWithCollisions();
210
+
211
+ console.log("=".repeat(60));
212
+ console.log("✅ Example complete! Check the logs above for collision warnings.");
213
+ console.log("💡 Router-level handlers take precedence over library handlers with the same names.");
214
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fjell/express-router",
3
- "version": "4.4.24",
3
+ "version": "4.4.26",
4
4
  "license": "Apache-2.0",
5
5
  "keywords": [
6
6
  "express",