@api-client/core 0.20.6 → 0.20.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/build/src/modeling/ExposedEntity.d.ts.map +1 -1
  2. package/build/src/modeling/ExposedEntity.js +55 -4
  3. package/build/src/modeling/ExposedEntity.js.map +1 -1
  4. package/build/src/modeling/RuntimeApiModel.d.ts.map +1 -1
  5. package/build/src/modeling/RuntimeApiModel.js +6 -2
  6. package/build/src/modeling/RuntimeApiModel.js.map +1 -1
  7. package/build/src/modeling/generators/RuntimeModelGenerator.d.ts +15 -0
  8. package/build/src/modeling/generators/RuntimeModelGenerator.d.ts.map +1 -0
  9. package/build/src/modeling/generators/RuntimeModelGenerator.js +78 -0
  10. package/build/src/modeling/generators/RuntimeModelGenerator.js.map +1 -0
  11. package/build/src/modeling/helpers/endpointHelpers.d.ts +6 -1
  12. package/build/src/modeling/helpers/endpointHelpers.d.ts.map +1 -1
  13. package/build/src/modeling/helpers/endpointHelpers.js +43 -4
  14. package/build/src/modeling/helpers/endpointHelpers.js.map +1 -1
  15. package/build/src/modeling/validation/api_model_rules.d.ts.map +1 -1
  16. package/build/src/modeling/validation/api_model_rules.js +17 -0
  17. package/build/src/modeling/validation/api_model_rules.js.map +1 -1
  18. package/build/tsconfig.tsbuildinfo +1 -1
  19. package/package.json +3 -3
  20. package/src/modeling/ExposedEntity.ts +62 -4
  21. package/src/modeling/RuntimeApiModel.ts +7 -2
  22. package/src/modeling/generators/RuntimeModelGenerator.ts +79 -0
  23. package/src/modeling/helpers/endpointHelpers.ts +51 -4
  24. package/src/modeling/validation/api_model_rules.ts +19 -0
  25. package/tests/unit/modeling/RuntimeApiModel.spec.ts +17 -3
  26. package/tests/unit/modeling/exposed_entity.spec.ts +95 -0
  27. package/tests/unit/modeling/generators/RuntimeModelGenerator.spec.ts +192 -0
  28. package/tests/unit/modeling/helpers/endpointHelpers.spec.ts +10 -3
  29. package/tests/unit/modeling/validation/api_model_rules.spec.ts +35 -0
@@ -1 +1 @@
1
- {"version":3,"file":"ExposedEntity.d.ts","sourceRoot":"","sources":["../../../src/modeling/ExposedEntity.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAEtD,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAC5C,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAuC,MAAM,oBAAoB,CAAA;AAC1G,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAE7C,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AAClD,OAAO,EAAE,KAAK,aAAa,EAAqB,MAAM,kBAAkB,CAAA;AACxE,OAAO,EAAE,yBAAyB,EAAE,MAAM,sCAAsC,CAAA;AAChF,OAAO,KAAK,EACV,iBAAiB,EACjB,aAAa,EACb,eAAe,EACf,mBAAmB,EACnB,kBAAkB,EACnB,MAAM,YAAY,CAAA;AAEnB;;;;;;;;;;;;;GAaG;AACH,qBAAa,aAAc,SAAQ,WAAW;;IAC5C;;OAEG;IACH,IAAI,EAAE,OAAO,iBAAiB,CAAA;IAE9B;;;OAGG;IACH,GAAG,EAAE,MAAM,CAAA;IAEX;;OAEG;IACS,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAA;IAE9C;;;;;;OAMG;IACH,aAAa,EAAE,OAAO,CAAA;IAEtB;;;OAGG;IACS,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,SAAS,CAAA;IAEvD;;;OAGG;IACS,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAEzC;;;;;OAKG;IACH,MAAM,CAAC,EAAE,OAAO,CAAA;IAEhB;;;;OAIG;IACH,MAAM,CAAC,EAAE,eAAe,CAAA;IAExB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,aAAa,CAAA;IAE7B;;OAEG;IACS,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,CAAA;IAEtC;;OAEG;IACS,QAAQ,CAAC,UAAU,EAAE,UAAU,EAAE,GAAG,SAAS,CAAA;IAEzD;;OAEG;IACS,QAAQ,CAAC,YAAY,EAAE,yBAAyB,GAAG,SAAS,CAAA;IAExE;;;;;OAKG;IACuB,QAAQ,CAAC,kBAAkB,EAAE,kBAAkB,GAAG,SAAS,CAAA;IAErF;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IAcnB;;OAEG;IACH,GAAG,EAAE,QAAQ,CAAA;IAEb,MAAM,CAAC,YAAY,CAAC,KAAK,GAAE,OAAO,CAAC,mBAAmB,CAAM,GAAG,mBAAmB;gBAmDtE,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC;IAyBjE,YAAY;IAaZ,MAAM,IAAI,mBAAmB;IAoC7B;;;;;;;;OAQG;IACH,iBAAiB,CAAC,IAAI,EAAE,MAAM;IA4C9B;;;;;;;;OAQG;IACH,eAAe,CAAC,IAAI,EAAE,MAAM;IA6E5B;;;;;OAKG;IACH,uBAAuB,IAAI,MAAM;IAcjC;;;;;;OAMG;IACH,yBAAyB,IAAI,MAAM,GAAG,SAAS;IAe/C;;OAEG;IACH,WAAW,IAAI,UAAU,EAAE;IAc3B;;OAEG;IACH,kBAAkB,IAAI,yBAAyB,EAAE;IAgBjD;;;OAGG;IACH,sBAAsB,IAAI,aAAa,EAAE;IAgBzC;;;;OAIG;IACH,SAAS,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM;IAY1C;;OAEG;IACH,aAAa,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM;IAI7C;;;;;OAKG;IACH,iBAAiB,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM;IAYjD;;;;;;;OAOG;IACH,wBAAwB,IAAI,IAAI;CA+BjC"}
1
+ {"version":3,"file":"ExposedEntity.d.ts","sourceRoot":"","sources":["../../../src/modeling/ExposedEntity.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAEtD,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAC5C,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAuC,MAAM,oBAAoB,CAAA;AAC1G,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAE7C,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AAClD,OAAO,EAAE,KAAK,aAAa,EAAqB,MAAM,kBAAkB,CAAA;AACxE,OAAO,EAAE,yBAAyB,EAAE,MAAM,sCAAsC,CAAA;AAChF,OAAO,KAAK,EACV,iBAAiB,EACjB,aAAa,EACb,eAAe,EACf,mBAAmB,EACnB,kBAAkB,EACnB,MAAM,YAAY,CAAA;AAEnB;;;;;;;;;;;;;GAaG;AACH,qBAAa,aAAc,SAAQ,WAAW;;IAC5C;;OAEG;IACH,IAAI,EAAE,OAAO,iBAAiB,CAAA;IAE9B;;;OAGG;IACH,GAAG,EAAE,MAAM,CAAA;IAEX;;OAEG;IACS,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAA;IAE9C;;;;;;OAMG;IACH,aAAa,EAAE,OAAO,CAAA;IAEtB;;;OAGG;IACS,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,SAAS,CAAA;IAEvD;;;OAGG;IACS,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAEzC;;;;;OAKG;IACH,MAAM,CAAC,EAAE,OAAO,CAAA;IAEhB;;;;OAIG;IACH,MAAM,CAAC,EAAE,eAAe,CAAA;IAExB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,aAAa,CAAA;IAE7B;;OAEG;IACS,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,CAAA;IAEtC;;OAEG;IACS,QAAQ,CAAC,UAAU,EAAE,UAAU,EAAE,GAAG,SAAS,CAAA;IAEzD;;OAEG;IACS,QAAQ,CAAC,YAAY,EAAE,yBAAyB,GAAG,SAAS,CAAA;IAExE;;;;;OAKG;IACuB,QAAQ,CAAC,kBAAkB,EAAE,kBAAkB,GAAG,SAAS,CAAA;IAErF;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IAcnB;;OAEG;IACH,GAAG,EAAE,QAAQ,CAAA;IAEb,MAAM,CAAC,YAAY,CAAC,KAAK,GAAE,OAAO,CAAC,mBAAmB,CAAM,GAAG,mBAAmB;gBAmDtE,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC;IAyBjE,YAAY;IAaZ,MAAM,IAAI,mBAAmB;IAoC7B;;;;;;;;OAQG;IACH,iBAAiB,CAAC,IAAI,EAAE,MAAM;IA6D9B;;;;;;;;OAQG;IACH,eAAe,CAAC,IAAI,EAAE,MAAM;IAsH5B;;;;;OAKG;IACH,uBAAuB,IAAI,MAAM;IAcjC;;;;;;OAMG;IACH,yBAAyB,IAAI,MAAM,GAAG,SAAS;IAe/C;;OAEG;IACH,WAAW,IAAI,UAAU,EAAE;IAc3B;;OAEG;IACH,kBAAkB,IAAI,yBAAyB,EAAE;IAgBjD;;;OAGG;IACH,sBAAsB,IAAI,aAAa,EAAE;IAgBzC;;;;OAIG;IACH,SAAS,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM;IAY1C;;OAEG;IACH,aAAa,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM;IAI7C;;;;;OAKG;IACH,iBAAiB,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM;IAYjD;;;;;;;OAOG;IACH,wBAAwB,IAAI,IAAI;CA+BjC"}
@@ -4,7 +4,7 @@ import { Exception } from '../exceptions/exception.js';
4
4
  import { ExposedEntityKind } from '../models/kinds.js';
5
5
  import { nanoid } from '../nanoid.js';
6
6
  import { createActionFromKind, restoreAction } from './actions/index.js';
7
- import { ensureLeadingSlash, joinPaths } from './helpers/endpointHelpers.js';
7
+ import { ensureLeadingSlash, joinPaths, paramNameFor } from './helpers/endpointHelpers.js';
8
8
  import { restoreAccessRule } from './rules/index.js';
9
9
  import { RateLimitingConfiguration } from './rules/RateLimitingConfiguration.js';
10
10
  /**
@@ -312,16 +312,29 @@ let ExposedEntity = (() => {
312
312
  });
313
313
  }
314
314
  }
315
- // Preserve current parameter name if present, otherwise default to {id}
316
- let param = '{id}';
317
- if (this.resourcePath) {
315
+ // Preserve current parameter name if present, otherwise default to semantic param name
316
+ let param = '';
317
+ if (this.resourcePath && this.resourcePath !== '/') {
318
318
  const curSegments = this.resourcePath.split('/').filter(Boolean);
319
319
  const maybeParam = curSegments[1];
320
320
  if (maybeParam && /^\{[A-Za-z_][A-Za-z0-9_]*\}$/.test(maybeParam)) {
321
321
  param = maybeParam;
322
322
  }
323
323
  }
324
+ if (!param) {
325
+ const entityObj = this.api.domain?.findEntity(this.entity.key, this.entity.domain);
326
+ if (!entityObj || !entityObj.info.name) {
327
+ // Never fall back to a default like '{id}' here. Silent param generation failures must throw
328
+ // to prevent runtime/OAS collisions.
329
+ throw new Exception('Cannot generate a semantic parameter name because the associated entity or its name is missing.', {
330
+ code: 'E_ENTITY_NOT_FOUND',
331
+ help: 'Ensure the exposed entity points to a valid domain entity with a defined name.',
332
+ });
333
+ }
334
+ param = `{${paramNameFor(entityObj.info.name)}}`;
335
+ }
324
336
  const nextResource = `${normalizedCollection}/${param}`;
337
+ this.#validateParameterCollisions(nextResource);
325
338
  this.collectionPath = normalizedCollection;
326
339
  this.resourcePath = nextResource;
327
340
  // rely on ApiModel.exposes deep observation to notify on property sets
@@ -374,6 +387,7 @@ let ExposedEntity = (() => {
374
387
  });
375
388
  }
376
389
  if (this.resourcePath !== cleaned) {
390
+ this.#validateParameterCollisions(`/${s1}/${s2}`);
377
391
  this.resourcePath = `/${s1}/${s2}`;
378
392
  }
379
393
  return;
@@ -396,9 +410,46 @@ let ExposedEntity = (() => {
396
410
  }
397
411
  }
398
412
  if (this.resourcePath !== cleaned) {
413
+ this.#validateParameterCollisions(`/${segments[0]}`);
399
414
  this.resourcePath = `/${segments[0]}`;
400
415
  }
401
416
  }
417
+ #checkDuplicatesInPaths(paths) {
418
+ const absolute = paths.join('/');
419
+ const params = [...absolute.matchAll(/\{([^}]+)\}/g)].map((m) => m[1]);
420
+ const seen = new Set();
421
+ for (const p of params) {
422
+ if (seen.has(p)) {
423
+ throw new Exception(`Duplicate path parameter "{${p}}" detected in branch hierarchy.`, {
424
+ code: 'E_PATH_PARAM_COLLISION',
425
+ help: 'Change the parameter name in either this resource or its ancestor to ensure unique parameter names.',
426
+ });
427
+ }
428
+ seen.add(p);
429
+ }
430
+ }
431
+ #validateDescendantCollisions(parentKey, ancestorPaths) {
432
+ for (const exposure of this.api.exposes.values()) {
433
+ if (exposure.parent?.key === parentKey) {
434
+ const currentPaths = [...ancestorPaths, exposure.resourcePath];
435
+ this.#checkDuplicatesInPaths(currentPaths);
436
+ this.#validateDescendantCollisions(exposure.key, currentPaths);
437
+ }
438
+ }
439
+ }
440
+ #validateParameterCollisions(tempResourcePath) {
441
+ const paths = [tempResourcePath];
442
+ let parentKey = this.parent?.key;
443
+ while (parentKey) {
444
+ const parent = this.api.exposes.get(parentKey);
445
+ if (!parent)
446
+ break;
447
+ paths.unshift(parent.resourcePath);
448
+ parentKey = parent.parent?.key;
449
+ }
450
+ this.#checkDuplicatesInPaths(paths);
451
+ this.#validateDescendantCollisions(this.key, paths);
452
+ }
402
453
  /**
403
454
  * Computes the absolute path for this exposure's resource endpoint by
404
455
  * walking up the exposure tree using `parent.key` until reaching a root exposure.
@@ -1 +1 @@
1
- {"version":3,"file":"ExposedEntity.js","sourceRoot":"","sources":["../../../src/modeling/ExposedEntity.ts"],"names":[],"mappings":"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","sourcesContent":["import { observed, toRaw } from '../decorators/observed.js'\nimport { Exception } from '../exceptions/exception.js'\nimport { ExposedEntityKind } from '../models/kinds.js'\nimport { nanoid } from '../nanoid.js'\nimport { Action } from './actions/Action.js'\nimport { ActionKind, type ApiActionSchema, createActionFromKind, restoreAction } from './actions/index.js'\nimport type { ApiModel } from './ApiModel.js'\nimport { ensureLeadingSlash, joinPaths } from './helpers/endpointHelpers.js'\nimport { AccessRule } from './rules/AccessRule.js'\nimport { type RateLimitRule, restoreAccessRule } from './rules/index.js'\nimport { RateLimitingConfiguration } from './rules/RateLimitingConfiguration.js'\nimport type {\n AssociationTarget,\n ExposeOptions,\n ExposeParentRef,\n ExposedEntitySchema,\n PaginationContract,\n} from './types.js'\n\n/**\n * A class that specializes in representing an exposed Data Entity within an API Model.\n *\n * ## Design Note\n * This class enforces strict path constraints (e.g., single-segment collection paths like `/users`,\n * two-segment resource paths like `/users/{id}`).\n * This is an intentional design choice to support a UI paradigm for non-technical users, ensuring that\n * path segments are configured individually at each level of the exposure hierarchy.\n *\n * Flexibility is achieved by chaining exposed entities (parent/child relationships), where the final\n * absolute path is composed of all ancestral paths. See `getAbsoluteResourcePath()` and `getAbsoluteCollectionPath()`.\n *\n * @fires change - Emitted when the exposed entity has changed.\n */\nexport class ExposedEntity extends EventTarget {\n /**\n * The exposed entity kind recognizable by the ecosystem.\n */\n kind: typeof ExposedEntityKind\n\n /**\n * The unique key of the exposed entity.\n * This is a stable identifier that does not change across versions.\n */\n key: string\n\n /**\n * A pointer to a Data Entity from the Data Domain.\n */\n @observed() accessor entity: AssociationTarget\n\n /**\n * Indicates whether this exposure has a collection endpoint.\n * A collection endpoint is optional for nested exposures where the association is 1:1\n * and the schema is embedded directly under the parent resource.\n *\n * Note that this property is not observed for changes as it is immutable after creation.\n */\n hasCollection: boolean\n\n /**\n * Path to the collection endpoint for this exposure.\n * Starts with '/'. Not set for 1:1 nested exposures where collection does not exist.\n */\n @observed() accessor collectionPath: string | undefined\n\n /**\n * Path to the resource endpoint for this exposure.\n * Starts with '/'. For 1:1 nested exposures the resource path typically does not include an id segment.\n */\n @observed() accessor resourcePath: string\n\n /**\n * Whether this exposure is a root exposure (top-level collection).\n * If this is set then the `parent` reference must be populated.\n *\n * Note that this property is not observed for changes as it is immutable after creation.\n */\n isRoot?: boolean\n\n /**\n * Parent reference when this exposure was created via following an association.\n *\n * Note that this property is not observed for changes as it is immutable after creation.\n */\n parent?: ExposeParentRef\n\n /**\n * Expose-time config used to create this exposure (persisted for auditing/UI).\n * This is only populated for the root exposure. All children exposures inherit this config.\n *\n * Note that this property is not observed for changes as it is immutable after creation.\n */\n exposeOptions?: ExposeOptions\n\n /**\n * The list of enabled API actions for this exposure (List/Read/Create/etc.)\n */\n @observed() accessor actions: Action[]\n\n /**\n * Optional array of access rules that define the access control policies for this exposure.\n */\n @observed() accessor accessRule: AccessRule[] | undefined\n\n /**\n * Optional configuration for rate limiting for this exposure.\n */\n @observed() accessor rateLimiting: RateLimitingConfiguration | undefined\n\n /**\n * Pagination contract for this exposure.\n * Defines a list of fields that can be used for filtering, sorting, and searching.\n * The pagination contract is only valid for that specific exposure. It cannot be inherited\n * by other exposures.\n */\n @observed({ deep: true }) accessor paginationContract: PaginationContract | undefined\n\n /**\n * When true, generation for this exposure hit configured limits\n *\n * Note that this property is not observed for changes as it is immutable after creation.\n */\n truncated?: boolean\n\n /**\n * When the notifying flag is set to true,\n * the domain is pending a notification.\n * No other notifications will be sent until\n * the current notification is sent.\n */\n #notifying = false\n /**\n * When the initializing flag is set to true,\n * the domain is not notified of changes.\n */\n #initializing = true\n /**\n * A reference to the parent API Model instance.\n */\n api: ApiModel\n\n static createSchema(input: Partial<ExposedEntitySchema> = {}): ExposedEntitySchema {\n const {\n key = nanoid(),\n entity = { key: '' },\n collectionPath,\n resourcePath = '/',\n hasCollection = true,\n isRoot,\n parent,\n exposeOptions,\n actions = [],\n accessRule,\n rateLimiting,\n truncated,\n paginationContract,\n } = input\n const result: ExposedEntitySchema = {\n kind: ExposedEntityKind,\n key,\n entity: { ...entity },\n hasCollection,\n resourcePath,\n actions: actions.map((a) => ({ ...a })),\n }\n if (collectionPath !== undefined) {\n result.collectionPath = collectionPath\n }\n if (isRoot !== undefined) {\n result.isRoot = isRoot\n }\n if (parent !== undefined) {\n result.parent = { ...parent }\n }\n if (exposeOptions !== undefined) {\n result.exposeOptions = { ...exposeOptions }\n }\n if (Array.isArray(accessRule)) {\n result.accessRule = accessRule.map((ar) => ({ ...ar }))\n }\n if (rateLimiting !== undefined) {\n result.rateLimiting = { ...rateLimiting }\n }\n if (truncated !== undefined) {\n result.truncated = truncated\n }\n if (paginationContract !== undefined) {\n result.paginationContract = structuredClone(paginationContract)\n }\n return result\n }\n\n constructor(model: ApiModel, state?: Partial<ExposedEntitySchema>) {\n super()\n this.api = model\n const init = ExposedEntity.createSchema(state)\n this.kind = init.kind\n this.key = init.key\n this.entity = init.entity\n this.hasCollection = init.hasCollection\n this.collectionPath = init.collectionPath\n this.resourcePath = init.resourcePath\n this.isRoot = init.isRoot\n this.parent = init.parent\n this.exposeOptions = init.exposeOptions\n this.actions = init.actions ? init.actions.map((a) => restoreAction(this, a)) : []\n this.accessRule = init.accessRule ? init.accessRule.map((ar) => restoreAccessRule(this, ar)) : []\n if (init.rateLimiting) {\n this.rateLimiting = new RateLimitingConfiguration(init.rateLimiting)\n }\n this.truncated = init.truncated\n if (init.paginationContract) {\n this.paginationContract = structuredClone(init.paginationContract)\n }\n this.#initializing = false\n }\n\n notifyChange() {\n if (this.#notifying || this.#initializing) {\n return\n }\n this.#notifying = true\n queueMicrotask(() => {\n this.#notifying = false\n const event = new Event('change')\n this.dispatchEvent(event)\n this.api.notifyChange()\n })\n }\n\n toJSON(): ExposedEntitySchema {\n const result: ExposedEntitySchema = {\n kind: this.kind,\n key: this.key,\n entity: { ...this.entity },\n resourcePath: this.resourcePath,\n actions: this.actions.map((a) => a.toJSON()),\n hasCollection: this.hasCollection,\n }\n if (this.collectionPath !== undefined) {\n result.collectionPath = this.collectionPath\n }\n if (this.isRoot !== undefined) {\n result.isRoot = this.isRoot\n }\n if (this.parent !== undefined) {\n result.parent = { ...this.parent }\n }\n if (this.exposeOptions !== undefined) {\n result.exposeOptions = { ...this.exposeOptions }\n }\n if (Array.isArray(this.accessRule) && this.accessRule.length > 0) {\n result.accessRule = this.accessRule.map((ar) => ar.toJSON())\n }\n if (this.rateLimiting !== undefined) {\n result.rateLimiting = this.rateLimiting.toJSON()\n }\n if (this.truncated !== undefined) {\n result.truncated = this.truncated\n }\n if (this.paginationContract) {\n result.paginationContract = structuredClone(toRaw(this, this.paginationContract))\n }\n return result\n }\n\n /**\n * Sets a new collection path for this exposed entity.\n *\n * It:\n * - updates the collectionPath property\n * - updates the absoluteCollectionPath property accordingly\n * - updates the resourcePath accordingly.\n * @param path The new path to set.\n */\n setCollectionPath(path: string) {\n if (!this.hasCollection) {\n throw new Exception(`Cannot set collection path on an exposure that does not have a collection`, {\n code: 'E_PATH_MISSING',\n help: 'The exposed entity you are trying to set a collection path for does not have a collection.',\n })\n }\n const cleaned = ensureLeadingSlash(path)\n // Ensure exactly one non-empty segment\n const segments = cleaned.split('/').filter(Boolean)\n if (segments.length !== 1) {\n throw new Exception(`Collection path must contain exactly one segment. Received: \"${path}\"`, {\n code: 'E_PATH_SEGMENT_SIZE',\n help: 'The set path must have a single path segment (e.g., `/products`)',\n })\n }\n const normalizedCollection = `/${segments[0]}`\n\n // Check for collision if this is a root entity\n if (this.isRoot) {\n const collision = this.api.findCollectionPathCollision(normalizedCollection, this.key)\n if (collision) {\n throw new Exception(`Collection path \"${normalizedCollection}\" is already in use by another root entity.`, {\n code: 'E_PATH_INUSE',\n help: 'The set path is already in use by another root entity.',\n })\n }\n }\n\n // Preserve current parameter name if present, otherwise default to {id}\n let param = '{id}'\n if (this.resourcePath) {\n const curSegments = this.resourcePath.split('/').filter(Boolean)\n const maybeParam = curSegments[1]\n if (maybeParam && /^\\{[A-Za-z_][A-Za-z0-9_]*\\}$/.test(maybeParam)) {\n param = maybeParam\n }\n }\n const nextResource = `${normalizedCollection}/${param}`\n this.collectionPath = normalizedCollection\n this.resourcePath = nextResource\n // rely on ApiModel.exposes deep observation to notify on property sets\n }\n\n /**\n * Sets a new resource path for this exposed entity.\n *\n * Rules:\n * - Must start with '/'.\n * - If this exposure has a collection, the path must be exactly the collection path plus a single\n * parameter segment (e.g. `/products/{productId}`) and only the parameter name may vary.\n * - If this exposure does NOT have a collection, the path can be any two segments (e.g. `/profile/{id}` or `/a/b`).\n */\n setResourcePath(path: string) {\n const cleaned = ensureLeadingSlash(path)\n const segments = cleaned.split('/').filter(Boolean)\n\n if (this.hasCollection) {\n if (!this.collectionPath) {\n // Why do we throw this error? We should just create it from the resource path...\n throw new Exception('Cannot set resource path: missing collection path for this exposure', {\n code: 'E_PATH_MISSING',\n help: 'Set the collection path on the exposed entity first.',\n })\n }\n const colSegments = this.collectionPath.split('/').filter(Boolean)\n if (colSegments.length !== 1) {\n throw new Exception(`Invalid stored collection path \"${this.collectionPath}\"`, {\n code: 'E_PATH_SEGMENT_SIZE',\n help: 'The set collection path must have a single path segment (e.g., `/products`)',\n })\n }\n if (segments.length !== 2) {\n throw new Exception(\n `Resource path must be exactly two segments (collection + parameter). Received: \"${cleaned}\"`,\n {\n code: 'E_PATH_SEGMENT_SIZE',\n help: 'The set resource path must have exactly two segments (collection + parameter).',\n }\n )\n }\n const [s1, s2] = segments\n if (s1 !== colSegments[0]) {\n throw new Exception(\n `Resource path must start with the collection segment \"${colSegments[0]}\". Received: \"${s1}\"`,\n {\n code: 'E_PATH_MISMATCH',\n help: 'Set the resource path to the same value as the collection path + the parameter value.',\n }\n )\n }\n // s2 must be a parameter segment {name}\n if (!/^\\{[A-Za-z_][A-Za-z0-9_]*\\}$/.test(s2)) {\n throw new Exception(`The second segment must be a parameter in braces, e.g. {id}. Received: \"${s2}\"`, {\n code: 'E_PARAMETER_INVALID',\n help: 'Use the braces to surround the parameter name, e.g., {productId}.',\n })\n }\n if (this.resourcePath !== cleaned) {\n this.resourcePath = `/${s1}/${s2}`\n }\n return\n }\n\n // No collection: allow exactly one segment\n if (segments.length !== 1) {\n throw new Exception(\n `Resource path must contain exactly one segment when no collection is present. Received: \"${cleaned}\"`,\n {\n code: 'E_PATH_SEGMENT_SIZE',\n help: 'The set resource path must have exactly one segment.',\n }\n )\n }\n // Check for collision if this is a root entity (singleton case)\n if (this.isRoot) {\n const collision = this.api.findResourcePathCollision(cleaned, this.key)\n if (collision) {\n throw new Exception(`Resource path \"${cleaned}\" is already in use by another root entity.`, {\n code: 'E_PATH_INUSE',\n help: 'The set path is already in use by another root entity.',\n })\n }\n }\n\n if (this.resourcePath !== cleaned) {\n this.resourcePath = `/${segments[0]}`\n }\n }\n\n /**\n * Computes the absolute path for this exposure's resource endpoint by\n * walking up the exposure tree using `parent.key` until reaching a root exposure.\n * The absolute path is composed by concatenating each ancestor's resource path\n * with this exposure's resource path.\n */\n getAbsoluteResourcePath(): string {\n let absolute = ensureLeadingSlash(this.resourcePath)\n // Traverse parents, always joining with the parent's resource path\n let parentKey = this.parent?.key\n while (parentKey) {\n const parent = this.api.exposes.get(parentKey)\n if (!parent) break\n const parentResource = ensureLeadingSlash(parent.resourcePath)\n absolute = joinPaths(parentResource, absolute)\n parentKey = parent.parent?.key\n }\n return absolute\n }\n\n /**\n * Computes the absolute path for this exposure's collection endpoint (if any)\n * by walking up the exposure tree using `parent.key` until reaching a root exposure.\n * The absolute path is composed by concatenating each ancestor's resource path\n * with this exposure's collection path.\n * Returns undefined if this exposure has no collection.\n */\n getAbsoluteCollectionPath(): string | undefined {\n if (!this.hasCollection || !this.collectionPath) return undefined\n let absolute = ensureLeadingSlash(this.collectionPath)\n // Traverse parents, always joining with the parent's resource path\n let parentKey = this.parent?.key\n while (parentKey) {\n const parent = this.api.exposes.get(parentKey)\n if (!parent) break\n const parentResource = ensureLeadingSlash(parent.resourcePath)\n absolute = joinPaths(parentResource, absolute)\n parentKey = parent.parent?.key\n }\n return absolute\n }\n\n /**\n * Returns all access rules for this exposure, including the ones from all the parents up to the API.\n */\n getAllRules(): AccessRule[] {\n const rules: AccessRule[] = []\n this.api.accessRule.forEach((rule) => rules.push(rule))\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n let current: ExposedEntity | undefined = this\n while (current) {\n if (current.accessRule) {\n rules.push(...current.accessRule)\n }\n current = current.parent ? this.api.exposes.get(current.parent.key) : undefined\n }\n return rules\n }\n\n /**\n * Returns all rate limiters for this exposure, including the ones from all the parents up to the API.\n */\n getAllRateLimiters(): RateLimitingConfiguration[] {\n const rateLimiters: RateLimitingConfiguration[] = []\n if (this.api.rateLimiting) {\n rateLimiters.push(this.api.rateLimiting)\n }\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n let current: ExposedEntity | undefined = this\n while (current) {\n if (current.rateLimiting) {\n rateLimiters.push(current.rateLimiting)\n }\n current = current.parent ? this.api.exposes.get(current.parent.key) : undefined\n }\n return rateLimiters\n }\n\n /**\n * Returns all rate limiter rules for this exposure, including the ones from all the parents up to the API.\n * Similar to the getAllRules() method, but it flattens the rate limiters into a single list of rules.\n */\n getAllRateLimiterRules(): RateLimitRule[] {\n const rules: RateLimitRule[] = []\n if (this.api.rateLimiting) {\n rules.push(...this.api.rateLimiting.rules)\n }\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n let current: ExposedEntity | undefined = this\n while (current) {\n if (current.rateLimiting) {\n rules.push(...current.rateLimiting.rules)\n }\n current = current.parent ? this.api.exposes.get(current.parent.key) : undefined\n }\n return rules\n }\n\n /**\n * Adds an action to the exposure.\n * @param schema The schema of the action to add.\n * @returns The added action.\n */\n addAction(schema: ApiActionSchema): Action {\n if (this.actions.some((action) => action.kind === schema.kind)) {\n throw new Exception(`Action of kind \"${schema.kind}\" already exists for this exposure`, {\n code: 'E_ACTION_USED',\n help: \"There's no need to add an API action again.\",\n })\n }\n const action = restoreAction(this, schema)\n this.actions.push(action)\n return action\n }\n\n /**\n * @deprecated Use {@link addActionFromKind()} instead.\n */\n addCrudAction(actionKind: ActionKind): Action {\n return this.addActionFromKind(actionKind)\n }\n\n /**\n * Adds an action of a given kind to the exposure.\n *\n * @param actionKind The kind of the action to add.\n * @returns The added action.\n */\n addActionFromKind(actionKind: ActionKind): Action {\n if (this.actions.some((action) => action.kind === actionKind)) {\n throw new Exception(`Action of kind \"${actionKind}\" already exists for this exposure`, {\n code: 'E_ACTION_USED',\n help: \"There's no need to add an API action again.\",\n })\n }\n const action = createActionFromKind(this, actionKind)\n this.actions.push(action)\n return action\n }\n\n /**\n * Scans for the indexed and search properties in the `DomainEntity`\n * and recreates the `paginationContract` with all indexed/searched fields.\n *\n * Note, this is a destructive action designed as a helper function when creating\n * an exposed entity to fill up default values. Should not be used if the user\n * didn't request that.\n */\n createPaginationContract(): void {\n const entity = this.api.domain?.findEntity(this.entity.key, this.entity.domain)\n if (!entity) {\n throw new Exception(`Entity \"${this.entity.key}\" not found\"`, {\n code: 'E_ENTITY_NOT_FOUND',\n help: 'The set entity does not exist.',\n })\n }\n if (!this.paginationContract) {\n this.paginationContract = {\n filterableFields: [],\n searchableFields: [],\n sortableFields: [],\n }\n } else {\n this.paginationContract.filterableFields = []\n this.paginationContract.searchableFields = []\n this.paginationContract.sortableFields = []\n }\n for (const prop of entity.properties) {\n // indexed properties allow sorting and filtering in the List action.\n if (prop.index) {\n this.paginationContract.filterableFields.push(prop.key)\n this.paginationContract.sortableFields.push(prop.key)\n }\n // search properties allow full-text search in the Search action.\n if (prop.search) {\n this.paginationContract.searchableFields.push(prop.key)\n }\n }\n }\n}\n"]}
1
+ {"version":3,"file":"ExposedEntity.js","sourceRoot":"","sources":["../../../src/modeling/ExposedEntity.ts"],"names":[],"mappings":"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","sourcesContent":["import { observed, toRaw } from '../decorators/observed.js'\nimport { Exception } from '../exceptions/exception.js'\nimport { ExposedEntityKind } from '../models/kinds.js'\nimport { nanoid } from '../nanoid.js'\nimport { Action } from './actions/Action.js'\nimport { ActionKind, type ApiActionSchema, createActionFromKind, restoreAction } from './actions/index.js'\nimport type { ApiModel } from './ApiModel.js'\nimport { ensureLeadingSlash, joinPaths, paramNameFor } from './helpers/endpointHelpers.js'\nimport { AccessRule } from './rules/AccessRule.js'\nimport { type RateLimitRule, restoreAccessRule } from './rules/index.js'\nimport { RateLimitingConfiguration } from './rules/RateLimitingConfiguration.js'\nimport type {\n AssociationTarget,\n ExposeOptions,\n ExposeParentRef,\n ExposedEntitySchema,\n PaginationContract,\n} from './types.js'\n\n/**\n * A class that specializes in representing an exposed Data Entity within an API Model.\n *\n * ## Design Note\n * This class enforces strict path constraints (e.g., single-segment collection paths like `/users`,\n * two-segment resource paths like `/users/{id}`).\n * This is an intentional design choice to support a UI paradigm for non-technical users, ensuring that\n * path segments are configured individually at each level of the exposure hierarchy.\n *\n * Flexibility is achieved by chaining exposed entities (parent/child relationships), where the final\n * absolute path is composed of all ancestral paths. See `getAbsoluteResourcePath()` and `getAbsoluteCollectionPath()`.\n *\n * @fires change - Emitted when the exposed entity has changed.\n */\nexport class ExposedEntity extends EventTarget {\n /**\n * The exposed entity kind recognizable by the ecosystem.\n */\n kind: typeof ExposedEntityKind\n\n /**\n * The unique key of the exposed entity.\n * This is a stable identifier that does not change across versions.\n */\n key: string\n\n /**\n * A pointer to a Data Entity from the Data Domain.\n */\n @observed() accessor entity: AssociationTarget\n\n /**\n * Indicates whether this exposure has a collection endpoint.\n * A collection endpoint is optional for nested exposures where the association is 1:1\n * and the schema is embedded directly under the parent resource.\n *\n * Note that this property is not observed for changes as it is immutable after creation.\n */\n hasCollection: boolean\n\n /**\n * Path to the collection endpoint for this exposure.\n * Starts with '/'. Not set for 1:1 nested exposures where collection does not exist.\n */\n @observed() accessor collectionPath: string | undefined\n\n /**\n * Path to the resource endpoint for this exposure.\n * Starts with '/'. For 1:1 nested exposures the resource path typically does not include an id segment.\n */\n @observed() accessor resourcePath: string\n\n /**\n * Whether this exposure is a root exposure (top-level collection).\n * If this is set then the `parent` reference must be populated.\n *\n * Note that this property is not observed for changes as it is immutable after creation.\n */\n isRoot?: boolean\n\n /**\n * Parent reference when this exposure was created via following an association.\n *\n * Note that this property is not observed for changes as it is immutable after creation.\n */\n parent?: ExposeParentRef\n\n /**\n * Expose-time config used to create this exposure (persisted for auditing/UI).\n * This is only populated for the root exposure. All children exposures inherit this config.\n *\n * Note that this property is not observed for changes as it is immutable after creation.\n */\n exposeOptions?: ExposeOptions\n\n /**\n * The list of enabled API actions for this exposure (List/Read/Create/etc.)\n */\n @observed() accessor actions: Action[]\n\n /**\n * Optional array of access rules that define the access control policies for this exposure.\n */\n @observed() accessor accessRule: AccessRule[] | undefined\n\n /**\n * Optional configuration for rate limiting for this exposure.\n */\n @observed() accessor rateLimiting: RateLimitingConfiguration | undefined\n\n /**\n * Pagination contract for this exposure.\n * Defines a list of fields that can be used for filtering, sorting, and searching.\n * The pagination contract is only valid for that specific exposure. It cannot be inherited\n * by other exposures.\n */\n @observed({ deep: true }) accessor paginationContract: PaginationContract | undefined\n\n /**\n * When true, generation for this exposure hit configured limits\n *\n * Note that this property is not observed for changes as it is immutable after creation.\n */\n truncated?: boolean\n\n /**\n * When the notifying flag is set to true,\n * the domain is pending a notification.\n * No other notifications will be sent until\n * the current notification is sent.\n */\n #notifying = false\n /**\n * When the initializing flag is set to true,\n * the domain is not notified of changes.\n */\n #initializing = true\n /**\n * A reference to the parent API Model instance.\n */\n api: ApiModel\n\n static createSchema(input: Partial<ExposedEntitySchema> = {}): ExposedEntitySchema {\n const {\n key = nanoid(),\n entity = { key: '' },\n collectionPath,\n resourcePath = '/',\n hasCollection = true,\n isRoot,\n parent,\n exposeOptions,\n actions = [],\n accessRule,\n rateLimiting,\n truncated,\n paginationContract,\n } = input\n const result: ExposedEntitySchema = {\n kind: ExposedEntityKind,\n key,\n entity: { ...entity },\n hasCollection,\n resourcePath,\n actions: actions.map((a) => ({ ...a })),\n }\n if (collectionPath !== undefined) {\n result.collectionPath = collectionPath\n }\n if (isRoot !== undefined) {\n result.isRoot = isRoot\n }\n if (parent !== undefined) {\n result.parent = { ...parent }\n }\n if (exposeOptions !== undefined) {\n result.exposeOptions = { ...exposeOptions }\n }\n if (Array.isArray(accessRule)) {\n result.accessRule = accessRule.map((ar) => ({ ...ar }))\n }\n if (rateLimiting !== undefined) {\n result.rateLimiting = { ...rateLimiting }\n }\n if (truncated !== undefined) {\n result.truncated = truncated\n }\n if (paginationContract !== undefined) {\n result.paginationContract = structuredClone(paginationContract)\n }\n return result\n }\n\n constructor(model: ApiModel, state?: Partial<ExposedEntitySchema>) {\n super()\n this.api = model\n const init = ExposedEntity.createSchema(state)\n this.kind = init.kind\n this.key = init.key\n this.entity = init.entity\n this.hasCollection = init.hasCollection\n this.collectionPath = init.collectionPath\n this.resourcePath = init.resourcePath\n this.isRoot = init.isRoot\n this.parent = init.parent\n this.exposeOptions = init.exposeOptions\n this.actions = init.actions ? init.actions.map((a) => restoreAction(this, a)) : []\n this.accessRule = init.accessRule ? init.accessRule.map((ar) => restoreAccessRule(this, ar)) : []\n if (init.rateLimiting) {\n this.rateLimiting = new RateLimitingConfiguration(init.rateLimiting)\n }\n this.truncated = init.truncated\n if (init.paginationContract) {\n this.paginationContract = structuredClone(init.paginationContract)\n }\n this.#initializing = false\n }\n\n notifyChange() {\n if (this.#notifying || this.#initializing) {\n return\n }\n this.#notifying = true\n queueMicrotask(() => {\n this.#notifying = false\n const event = new Event('change')\n this.dispatchEvent(event)\n this.api.notifyChange()\n })\n }\n\n toJSON(): ExposedEntitySchema {\n const result: ExposedEntitySchema = {\n kind: this.kind,\n key: this.key,\n entity: { ...this.entity },\n resourcePath: this.resourcePath,\n actions: this.actions.map((a) => a.toJSON()),\n hasCollection: this.hasCollection,\n }\n if (this.collectionPath !== undefined) {\n result.collectionPath = this.collectionPath\n }\n if (this.isRoot !== undefined) {\n result.isRoot = this.isRoot\n }\n if (this.parent !== undefined) {\n result.parent = { ...this.parent }\n }\n if (this.exposeOptions !== undefined) {\n result.exposeOptions = { ...this.exposeOptions }\n }\n if (Array.isArray(this.accessRule) && this.accessRule.length > 0) {\n result.accessRule = this.accessRule.map((ar) => ar.toJSON())\n }\n if (this.rateLimiting !== undefined) {\n result.rateLimiting = this.rateLimiting.toJSON()\n }\n if (this.truncated !== undefined) {\n result.truncated = this.truncated\n }\n if (this.paginationContract) {\n result.paginationContract = structuredClone(toRaw(this, this.paginationContract))\n }\n return result\n }\n\n /**\n * Sets a new collection path for this exposed entity.\n *\n * It:\n * - updates the collectionPath property\n * - updates the absoluteCollectionPath property accordingly\n * - updates the resourcePath accordingly.\n * @param path The new path to set.\n */\n setCollectionPath(path: string) {\n if (!this.hasCollection) {\n throw new Exception(`Cannot set collection path on an exposure that does not have a collection`, {\n code: 'E_PATH_MISSING',\n help: 'The exposed entity you are trying to set a collection path for does not have a collection.',\n })\n }\n const cleaned = ensureLeadingSlash(path)\n // Ensure exactly one non-empty segment\n const segments = cleaned.split('/').filter(Boolean)\n if (segments.length !== 1) {\n throw new Exception(`Collection path must contain exactly one segment. Received: \"${path}\"`, {\n code: 'E_PATH_SEGMENT_SIZE',\n help: 'The set path must have a single path segment (e.g., `/products`)',\n })\n }\n const normalizedCollection = `/${segments[0]}`\n\n // Check for collision if this is a root entity\n if (this.isRoot) {\n const collision = this.api.findCollectionPathCollision(normalizedCollection, this.key)\n if (collision) {\n throw new Exception(`Collection path \"${normalizedCollection}\" is already in use by another root entity.`, {\n code: 'E_PATH_INUSE',\n help: 'The set path is already in use by another root entity.',\n })\n }\n }\n\n // Preserve current parameter name if present, otherwise default to semantic param name\n let param = ''\n if (this.resourcePath && this.resourcePath !== '/') {\n const curSegments = this.resourcePath.split('/').filter(Boolean)\n const maybeParam = curSegments[1]\n if (maybeParam && /^\\{[A-Za-z_][A-Za-z0-9_]*\\}$/.test(maybeParam)) {\n param = maybeParam\n }\n }\n\n if (!param) {\n const entityObj = this.api.domain?.findEntity(this.entity.key, this.entity.domain)\n if (!entityObj || !entityObj.info.name) {\n // Never fall back to a default like '{id}' here. Silent param generation failures must throw\n // to prevent runtime/OAS collisions.\n throw new Exception(\n 'Cannot generate a semantic parameter name because the associated entity or its name is missing.',\n {\n code: 'E_ENTITY_NOT_FOUND',\n help: 'Ensure the exposed entity points to a valid domain entity with a defined name.',\n }\n )\n }\n param = `{${paramNameFor(entityObj.info.name)}}`\n }\n const nextResource = `${normalizedCollection}/${param}`\n this.#validateParameterCollisions(nextResource)\n this.collectionPath = normalizedCollection\n this.resourcePath = nextResource\n // rely on ApiModel.exposes deep observation to notify on property sets\n }\n\n /**\n * Sets a new resource path for this exposed entity.\n *\n * Rules:\n * - Must start with '/'.\n * - If this exposure has a collection, the path must be exactly the collection path plus a single\n * parameter segment (e.g. `/products/{productId}`) and only the parameter name may vary.\n * - If this exposure does NOT have a collection, the path can be any two segments (e.g. `/profile/{id}` or `/a/b`).\n */\n setResourcePath(path: string) {\n const cleaned = ensureLeadingSlash(path)\n const segments = cleaned.split('/').filter(Boolean)\n\n if (this.hasCollection) {\n if (!this.collectionPath) {\n // Why do we throw this error? We should just create it from the resource path...\n throw new Exception('Cannot set resource path: missing collection path for this exposure', {\n code: 'E_PATH_MISSING',\n help: 'Set the collection path on the exposed entity first.',\n })\n }\n const colSegments = this.collectionPath.split('/').filter(Boolean)\n if (colSegments.length !== 1) {\n throw new Exception(`Invalid stored collection path \"${this.collectionPath}\"`, {\n code: 'E_PATH_SEGMENT_SIZE',\n help: 'The set collection path must have a single path segment (e.g., `/products`)',\n })\n }\n if (segments.length !== 2) {\n throw new Exception(\n `Resource path must be exactly two segments (collection + parameter). Received: \"${cleaned}\"`,\n {\n code: 'E_PATH_SEGMENT_SIZE',\n help: 'The set resource path must have exactly two segments (collection + parameter).',\n }\n )\n }\n const [s1, s2] = segments\n if (s1 !== colSegments[0]) {\n throw new Exception(\n `Resource path must start with the collection segment \"${colSegments[0]}\". Received: \"${s1}\"`,\n {\n code: 'E_PATH_MISMATCH',\n help: 'Set the resource path to the same value as the collection path + the parameter value.',\n }\n )\n }\n // s2 must be a parameter segment {name}\n if (!/^\\{[A-Za-z_][A-Za-z0-9_]*\\}$/.test(s2)) {\n throw new Exception(`The second segment must be a parameter in braces, e.g. {id}. Received: \"${s2}\"`, {\n code: 'E_PARAMETER_INVALID',\n help: 'Use the braces to surround the parameter name, e.g., {productId}.',\n })\n }\n if (this.resourcePath !== cleaned) {\n this.#validateParameterCollisions(`/${s1}/${s2}`)\n this.resourcePath = `/${s1}/${s2}`\n }\n return\n }\n\n // No collection: allow exactly one segment\n if (segments.length !== 1) {\n throw new Exception(\n `Resource path must contain exactly one segment when no collection is present. Received: \"${cleaned}\"`,\n {\n code: 'E_PATH_SEGMENT_SIZE',\n help: 'The set resource path must have exactly one segment.',\n }\n )\n }\n // Check for collision if this is a root entity (singleton case)\n if (this.isRoot) {\n const collision = this.api.findResourcePathCollision(cleaned, this.key)\n if (collision) {\n throw new Exception(`Resource path \"${cleaned}\" is already in use by another root entity.`, {\n code: 'E_PATH_INUSE',\n help: 'The set path is already in use by another root entity.',\n })\n }\n }\n\n if (this.resourcePath !== cleaned) {\n this.#validateParameterCollisions(`/${segments[0]}`)\n this.resourcePath = `/${segments[0]}`\n }\n }\n\n #checkDuplicatesInPaths(paths: string[]) {\n const absolute = paths.join('/')\n const params = [...absolute.matchAll(/\\{([^}]+)\\}/g)].map((m) => m[1])\n const seen = new Set<string>()\n for (const p of params) {\n if (seen.has(p)) {\n throw new Exception(`Duplicate path parameter \"{${p}}\" detected in branch hierarchy.`, {\n code: 'E_PATH_PARAM_COLLISION',\n help: 'Change the parameter name in either this resource or its ancestor to ensure unique parameter names.',\n })\n }\n seen.add(p)\n }\n }\n\n #validateDescendantCollisions(parentKey: string, ancestorPaths: string[]) {\n for (const exposure of this.api.exposes.values()) {\n if (exposure.parent?.key === parentKey) {\n const currentPaths = [...ancestorPaths, exposure.resourcePath]\n this.#checkDuplicatesInPaths(currentPaths)\n this.#validateDescendantCollisions(exposure.key, currentPaths)\n }\n }\n }\n\n #validateParameterCollisions(tempResourcePath: string) {\n const paths: string[] = [tempResourcePath]\n let parentKey = this.parent?.key\n while (parentKey) {\n const parent = this.api.exposes.get(parentKey)\n if (!parent) break\n paths.unshift(parent.resourcePath)\n parentKey = parent.parent?.key\n }\n\n this.#checkDuplicatesInPaths(paths)\n this.#validateDescendantCollisions(this.key, paths)\n }\n\n /**\n * Computes the absolute path for this exposure's resource endpoint by\n * walking up the exposure tree using `parent.key` until reaching a root exposure.\n * The absolute path is composed by concatenating each ancestor's resource path\n * with this exposure's resource path.\n */\n getAbsoluteResourcePath(): string {\n let absolute = ensureLeadingSlash(this.resourcePath)\n // Traverse parents, always joining with the parent's resource path\n let parentKey = this.parent?.key\n while (parentKey) {\n const parent = this.api.exposes.get(parentKey)\n if (!parent) break\n const parentResource = ensureLeadingSlash(parent.resourcePath)\n absolute = joinPaths(parentResource, absolute)\n parentKey = parent.parent?.key\n }\n return absolute\n }\n\n /**\n * Computes the absolute path for this exposure's collection endpoint (if any)\n * by walking up the exposure tree using `parent.key` until reaching a root exposure.\n * The absolute path is composed by concatenating each ancestor's resource path\n * with this exposure's collection path.\n * Returns undefined if this exposure has no collection.\n */\n getAbsoluteCollectionPath(): string | undefined {\n if (!this.hasCollection || !this.collectionPath) return undefined\n let absolute = ensureLeadingSlash(this.collectionPath)\n // Traverse parents, always joining with the parent's resource path\n let parentKey = this.parent?.key\n while (parentKey) {\n const parent = this.api.exposes.get(parentKey)\n if (!parent) break\n const parentResource = ensureLeadingSlash(parent.resourcePath)\n absolute = joinPaths(parentResource, absolute)\n parentKey = parent.parent?.key\n }\n return absolute\n }\n\n /**\n * Returns all access rules for this exposure, including the ones from all the parents up to the API.\n */\n getAllRules(): AccessRule[] {\n const rules: AccessRule[] = []\n this.api.accessRule.forEach((rule) => rules.push(rule))\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n let current: ExposedEntity | undefined = this\n while (current) {\n if (current.accessRule) {\n rules.push(...current.accessRule)\n }\n current = current.parent ? this.api.exposes.get(current.parent.key) : undefined\n }\n return rules\n }\n\n /**\n * Returns all rate limiters for this exposure, including the ones from all the parents up to the API.\n */\n getAllRateLimiters(): RateLimitingConfiguration[] {\n const rateLimiters: RateLimitingConfiguration[] = []\n if (this.api.rateLimiting) {\n rateLimiters.push(this.api.rateLimiting)\n }\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n let current: ExposedEntity | undefined = this\n while (current) {\n if (current.rateLimiting) {\n rateLimiters.push(current.rateLimiting)\n }\n current = current.parent ? this.api.exposes.get(current.parent.key) : undefined\n }\n return rateLimiters\n }\n\n /**\n * Returns all rate limiter rules for this exposure, including the ones from all the parents up to the API.\n * Similar to the getAllRules() method, but it flattens the rate limiters into a single list of rules.\n */\n getAllRateLimiterRules(): RateLimitRule[] {\n const rules: RateLimitRule[] = []\n if (this.api.rateLimiting) {\n rules.push(...this.api.rateLimiting.rules)\n }\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n let current: ExposedEntity | undefined = this\n while (current) {\n if (current.rateLimiting) {\n rules.push(...current.rateLimiting.rules)\n }\n current = current.parent ? this.api.exposes.get(current.parent.key) : undefined\n }\n return rules\n }\n\n /**\n * Adds an action to the exposure.\n * @param schema The schema of the action to add.\n * @returns The added action.\n */\n addAction(schema: ApiActionSchema): Action {\n if (this.actions.some((action) => action.kind === schema.kind)) {\n throw new Exception(`Action of kind \"${schema.kind}\" already exists for this exposure`, {\n code: 'E_ACTION_USED',\n help: \"There's no need to add an API action again.\",\n })\n }\n const action = restoreAction(this, schema)\n this.actions.push(action)\n return action\n }\n\n /**\n * @deprecated Use {@link addActionFromKind()} instead.\n */\n addCrudAction(actionKind: ActionKind): Action {\n return this.addActionFromKind(actionKind)\n }\n\n /**\n * Adds an action of a given kind to the exposure.\n *\n * @param actionKind The kind of the action to add.\n * @returns The added action.\n */\n addActionFromKind(actionKind: ActionKind): Action {\n if (this.actions.some((action) => action.kind === actionKind)) {\n throw new Exception(`Action of kind \"${actionKind}\" already exists for this exposure`, {\n code: 'E_ACTION_USED',\n help: \"There's no need to add an API action again.\",\n })\n }\n const action = createActionFromKind(this, actionKind)\n this.actions.push(action)\n return action\n }\n\n /**\n * Scans for the indexed and search properties in the `DomainEntity`\n * and recreates the `paginationContract` with all indexed/searched fields.\n *\n * Note, this is a destructive action designed as a helper function when creating\n * an exposed entity to fill up default values. Should not be used if the user\n * didn't request that.\n */\n createPaginationContract(): void {\n const entity = this.api.domain?.findEntity(this.entity.key, this.entity.domain)\n if (!entity) {\n throw new Exception(`Entity \"${this.entity.key}\" not found\"`, {\n code: 'E_ENTITY_NOT_FOUND',\n help: 'The set entity does not exist.',\n })\n }\n if (!this.paginationContract) {\n this.paginationContract = {\n filterableFields: [],\n searchableFields: [],\n sortableFields: [],\n }\n } else {\n this.paginationContract.filterableFields = []\n this.paginationContract.searchableFields = []\n this.paginationContract.sortableFields = []\n }\n for (const prop of entity.properties) {\n // indexed properties allow sorting and filtering in the List action.\n if (prop.index) {\n this.paginationContract.filterableFields.push(prop.key)\n this.paginationContract.sortableFields.push(prop.key)\n }\n // search properties allow full-text search in the Search action.\n if (prop.search) {\n this.paginationContract.searchableFields.push(prop.key)\n }\n }\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"RuntimeApiModel.d.ts","sourceRoot":"","sources":["../../../src/modeling/RuntimeApiModel.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"RuntimeApiModel.d.ts","sourceRoot":"","sources":["../../../src/modeling/RuntimeApiModel.ts"],"names":[],"mappings":"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"}
@@ -88,9 +88,13 @@ export class RuntimeApiModel extends ApiModel {
88
88
  }
89
89
  constructor(schema, domainSchema) {
90
90
  super(schema, domainSchema);
91
- if (schema.routingMap) {
92
- this.#initializeRouter(schema.routingMap);
91
+ if (!schema.routingMap) {
92
+ throw new Exception('The runtime API model must have a routing map.', {
93
+ code: 'E_MISSING_ROUTING_MAP',
94
+ help: 'Ensure that the routingMap property is defined when creating a RuntimeApiModel.',
95
+ });
93
96
  }
97
+ this.#initializeRouter(schema.routingMap);
94
98
  this.#cacheEntitiesAndProperties();
95
99
  this.#precomputeAccessRules();
96
100
  this.#precomputeSessionProperties();
@@ -1 +1 @@
1
- {"version":3,"file":"RuntimeApiModel.js","sourceRoot":"","sources":["../../../src/modeling/RuntimeApiModel.ts"],"names":[],"mappings":"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","sourcesContent":["import { match, parse, exec, type RouteToken } from '@poppinss/matchit'\nimport { ApiModel, type ApiModelSchema } from './ApiModel.js'\nimport type { DataDomainSchema } from './DataDomain.js'\nimport type { ActionKind } from './actions/index.js'\nimport type { ExposedEntity } from './ExposedEntity.js'\nimport type { Action } from './actions/Action.js'\nimport type { DomainEntity } from './DomainEntity.js'\nimport type { DomainProperty } from './DomainProperty.js'\nimport type { DomainAssociation } from './DomainAssociation.js'\nimport { SemanticType } from './Semantics.js'\nimport { AccessRule, AccessRuleExecutionPhase } from './rules/AccessRule.js'\nimport { Exception } from '../exceptions/exception.js'\n\n/**\n * Identifies a specific exposed entity and its action kind.\n */\nexport interface RouteLookup {\n exposedEntityKey: string\n actionKind: ActionKind\n}\n\n/**\n * A routing definition mapping a path to an action lookup.\n */\nexport interface RouteDefinition {\n path: string\n lookup: RouteLookup\n}\n\n/**\n * A map of HTTP methods to their route definitions.\n */\nexport type RoutingMap = Record<string, RouteDefinition[]>\n\n/**\n * Schema for an API Model optimized for runtime routing.\n */\nexport interface RuntimeApiModelSchema extends ApiModelSchema {\n routingMap: RoutingMap\n}\n\nexport interface RuntimeResolvedAction {\n exposure: ExposedEntity\n entity: DomainEntity\n action: Action\n params: Record<string, string>\n}\n\nexport type RuleEvaluator = (rule: AccessRule) => Promise<boolean | undefined> | boolean | undefined\n\nexport interface PhaseRules {\n permissionRules: AccessRule[]\n mandatoryRules: AccessRule[]\n}\n\nexport interface ActionRulesCache {\n preFetch: PhaseRules\n fetch: PhaseRules\n postFetch: PhaseRules\n}\n\n/**\n * An optimized API Model subclass designed for fast runtime lookups.\n * It pre-compiles the RoutingMap into a radix tree for O(log N) or faster endpoint resolution.\n */\nexport class RuntimeApiModel extends ApiModel {\n /**\n * The parsed radix tree for fast routing.\n * Method -> ParsedRoutes\n */\n #routes = new Map<string, RouteToken[][]>()\n\n /**\n * Quick map from matchit parsed route format to our RouteDefinition for returning results\n */\n #definitions = new WeakMap<RouteToken[], RouteDefinition>()\n\n /**\n * Cached references to commonly used entities for fast runtime lookup.\n */\n cachedEntities: {\n user?: DomainEntity\n } = {}\n\n /**\n * Cached references to commonly used properties for fast runtime lookup.\n */\n cachedProperties: {\n username?: DomainProperty\n password?: DomainProperty\n role?: DomainProperty\n } = {}\n\n /**\n * Cached access rules for each action to avoid runtime computation overhead.\n */\n #actionRulesCache = new WeakMap<Action, ActionRulesCache>()\n\n /**\n * Cached session properties for fast runtime lookup.\n */\n readonly #sessionProperties = new Map<string, DomainProperty>()\n\n /**\n * Returns a readonly map of session properties.\n * Note, it creates a copy of the cached map to prevent modification of the internal state.\n */\n public get sessionProperties(): ReadonlyMap<string, DomainProperty> {\n return new Map(this.#sessionProperties)\n }\n\n /**\n * Cached properties that have at least one semantic, grouped by their entity.\n */\n readonly #semanticPropertiesCache = new Map<DomainEntity, DomainProperty[]>()\n\n /**\n * Cached properties that have at least one semantic, grouped by their entity and then by SemanticType.\n */\n readonly #propertiesBySemanticCache = new Map<DomainEntity, Map<SemanticType, DomainProperty[]>>()\n\n /**\n * Cached associations that have at least one semantic, grouped by their entity.\n */\n readonly #semanticAssociationsCache = new Map<DomainEntity, DomainAssociation[]>()\n\n /**\n * Cached associations that have at least one semantic, grouped by their entity and then by SemanticType.\n */\n readonly #associationsBySemanticCache = new Map<DomainEntity, Map<SemanticType, DomainAssociation[]>>()\n\n /**\n * Returns a readonly map of properties with semantics.\n * Note, it creates a copy of the cached map to prevent modification of the internal state.\n */\n public get semanticPropertiesCache(): ReadonlyMap<DomainEntity, DomainProperty[]> {\n return new Map(this.#semanticPropertiesCache)\n }\n\n /**\n * Returns properties for a specific entity that have a specific semantic type.\n * Provides O(1) lookup using the precomputed cache.\n */\n public getPropertiesBySemantic(entity: DomainEntity, semanticType: SemanticType): DomainProperty[] {\n const semanticMap = this.#propertiesBySemanticCache.get(entity)\n return semanticMap?.get(semanticType) || []\n }\n\n /**\n * Returns a readonly map of associations with semantics.\n * Note, it creates a copy of the cached map to prevent modification of the internal state.\n */\n public get semanticAssociationsCache(): ReadonlyMap<DomainEntity, DomainAssociation[]> {\n return new Map(this.#semanticAssociationsCache)\n }\n\n /**\n * Returns associations for a specific entity that have a specific semantic type.\n * Provides O(1) lookup using the precomputed cache.\n */\n public getAssociationsBySemantic(entity: DomainEntity, semanticType: SemanticType): DomainAssociation[] {\n const semanticMap = this.#associationsBySemanticCache.get(entity)\n return semanticMap?.get(semanticType) || []\n }\n\n constructor(schema: RuntimeApiModelSchema, domainSchema: DataDomainSchema) {\n super(schema, domainSchema)\n\n if (schema.routingMap) {\n this.#initializeRouter(schema.routingMap)\n }\n\n this.#cacheEntitiesAndProperties()\n this.#precomputeAccessRules()\n this.#precomputeSessionProperties()\n this.#precomputeSemanticProperties()\n }\n\n #precomputeSessionProperties(): void {\n if (!this.session || !this.domain) {\n return\n }\n for (const prop of this.session.properties) {\n const domainProperty = this.domain.findProperty(prop.key, prop.domain)\n if (!domainProperty) {\n throw new Exception(`Session property ${prop.key} not found in domain`)\n }\n this.#sessionProperties.set(prop.key, domainProperty)\n }\n }\n\n #precomputeSemanticProperties(): void {\n if (!this.domain) {\n return\n }\n\n const processEntity = (entity: DomainEntity) => {\n if (this.#semanticPropertiesCache.has(entity)) {\n return\n }\n\n const propertiesWithSemantics: DomainProperty[] = []\n const semanticPropsMap = new Map<SemanticType, DomainProperty[]>()\n\n for (const prop of entity.withInheritedProperties()) {\n if (Array.isArray(prop.semantics) && prop.semantics.length > 0) {\n propertiesWithSemantics.push(prop)\n\n for (const semantic of prop.semantics) {\n let propsForSemantic = semanticPropsMap.get(semantic.id)\n if (!propsForSemantic) {\n propsForSemantic = []\n semanticPropsMap.set(semantic.id, propsForSemantic)\n }\n propsForSemantic.push(prop)\n }\n }\n }\n\n if (propertiesWithSemantics.length > 0) {\n this.#semanticPropertiesCache.set(entity, propertiesWithSemantics)\n this.#propertiesBySemanticCache.set(entity, semanticPropsMap)\n }\n\n const associationsWithSemantics: DomainAssociation[] = []\n const semanticAssocMap = new Map<SemanticType, DomainAssociation[]>()\n\n for (const assoc of entity.withInheritedAssociations()) {\n if (Array.isArray(assoc.semantics) && assoc.semantics.length > 0) {\n associationsWithSemantics.push(assoc)\n\n for (const semantic of assoc.semantics) {\n let assocForSemantic = semanticAssocMap.get(semantic.id)\n if (!assocForSemantic) {\n assocForSemantic = []\n semanticAssocMap.set(semantic.id, assocForSemantic)\n }\n assocForSemantic.push(assoc)\n }\n }\n }\n\n if (associationsWithSemantics.length > 0) {\n this.#semanticAssociationsCache.set(entity, associationsWithSemantics)\n this.#associationsBySemanticCache.set(entity, semanticAssocMap)\n }\n }\n\n for (const entity of this.domain.listEntities()) {\n processEntity(entity)\n }\n\n for (const entity of this.domain.listAllForeignEntities()) {\n processEntity(entity)\n }\n }\n\n #precomputeAccessRules(): void {\n for (const entity of this.exposes.values()) {\n for (const action of entity.actions) {\n this.#actionRulesCache.set(action, this.#computeEffectiveRules(action, entity))\n }\n }\n }\n\n #computeEffectiveRules(action: Action, entity: ExposedEntity): ActionRulesCache {\n const hierarchy: AccessRule[][] = []\n\n if (action.accessRule && action.accessRule.length > 0) {\n hierarchy.push(action.accessRule)\n }\n\n let currentEntity: ExposedEntity | undefined = entity\n while (currentEntity) {\n if (currentEntity.accessRule && currentEntity.accessRule.length > 0) {\n hierarchy.push(currentEntity.accessRule)\n }\n currentEntity = currentEntity.parent ? this.exposes.get(currentEntity.parent.key) : undefined\n }\n\n if (this.accessRule && this.accessRule.length > 0) {\n hierarchy.push(this.accessRule)\n }\n\n const result: ActionRulesCache = {\n preFetch: {\n permissionRules: [],\n mandatoryRules: [],\n },\n fetch: {\n permissionRules: [],\n mandatoryRules: [],\n },\n postFetch: {\n permissionRules: [],\n mandatoryRules: [],\n },\n }\n\n const seenTypes = new Set<string>()\n\n for (const rulesLevel of hierarchy) {\n const typesInThisLevel = new Set<string>()\n for (const rule of rulesLevel) {\n const phase = rule.metadata[action.kind as keyof typeof rule.metadata]\n\n // If the rule does not specify an execution phase for this action kind, it is not evaluated\n if (!phase) {\n continue\n }\n\n // Shadowing: If a rule of the same type was defined closer to the action, ignore this one.\n if (seenTypes.has(rule.type)) {\n continue\n }\n typesInThisLevel.add(rule.type)\n\n let bucket\n if (phase === AccessRuleExecutionPhase.POST_FETCH) {\n bucket = result.postFetch\n } else if (phase === AccessRuleExecutionPhase.FETCH) {\n bucket = result.fetch\n } else {\n bucket = result.preFetch\n }\n\n if (rule.mandatory) {\n bucket.mandatoryRules.push(rule)\n } else {\n bucket.permissionRules.push(rule)\n }\n }\n for (const type of typesInThisLevel) {\n seenTypes.add(type)\n }\n }\n\n return result\n }\n\n #cacheEntitiesAndProperties(): void {\n if (!this.user || !this.domain) {\n return\n }\n\n const userEntity = this.domain.findEntity(this.user.key, this.user.domain)\n if (!userEntity) {\n return\n }\n\n this.cachedEntities.user = userEntity\n\n for (const prop of userEntity.withInheritedProperties()) {\n if (prop.hasSemantic(SemanticType.Username)) {\n this.cachedProperties.username = prop\n }\n if (prop.hasSemantic(SemanticType.Password)) {\n this.cachedProperties.password = prop\n }\n if (prop.hasSemantic(SemanticType.UserRole)) {\n this.cachedProperties.role = prop\n }\n }\n }\n\n #initializeRouter(routingMap: RoutingMap): void {\n for (const [method, definitions] of Object.entries(routingMap)) {\n const parsedRoutes = []\n for (const def of definitions) {\n // matchit's parse() transforms a route string into an object representation.\n // It expects `:param` syntax, while our API models use OpenAPI `{param}` syntax.\n const matchitPath = def.path.replace(/\\{([^}]+)\\}/g, ':$1')\n const parsed = parse(matchitPath)\n this.#definitions.set(parsed, def)\n parsedRoutes.push(parsed)\n }\n this.#routes.set(method.toUpperCase(), parsedRoutes)\n }\n }\n\n /**\n * Looks up the corresponding exposed entity and action for a given request.\n *\n * @param method The HTTP method (e.g., 'GET', 'POST').\n * @param path The request path (e.g., '/users/123').\n * @returns An object with the entity, action, and extracted path parameters if a match is found.\n */\n lookupAction(method: string, path: string): RuntimeResolvedAction | undefined {\n const parsedRoutes = this.#routes.get(method.toUpperCase())\n if (!parsedRoutes) {\n return undefined\n }\n\n // `match` returns the matching parsed route (which is an array of segments), or empty array if no match\n const matchedRoute = match(path, parsedRoutes)\n if (!matchedRoute || matchedRoute.length === 0) {\n return undefined\n }\n\n const def = this.#definitions.get(matchedRoute)\n if (!def) {\n return undefined\n }\n\n const params = exec(path, matchedRoute)\n\n const exposure = this.exposes.get(def.lookup.exposedEntityKey)\n if (!exposure) {\n throw new Exception('Missing exposure ' + def.lookup.exposedEntityKey, { code: 'API_MODEL_ERROR', status: 500 })\n }\n\n const action = exposure.actions.find((a) => a.kind === def.lookup.actionKind)\n if (!action) {\n throw new Exception('Missing action ' + def.lookup.actionKind, { code: 'API_MODEL_ERROR', status: 500 })\n }\n\n const entity = this.domain?.findEntity(exposure.entity.key, exposure.entity.domain)\n if (!entity) {\n throw new Exception('Missing entity ' + exposure.entity.key, { code: 'API_MODEL_ERROR', status: 500 })\n }\n\n return {\n exposure,\n entity,\n action,\n params,\n }\n }\n\n /**\n * Retrieves the precomputed and shadowed effective rules for a given action.\n */\n getEffectiveRules(action: RuntimeResolvedAction): ActionRulesCache {\n let cachedRules = this.#actionRulesCache.get(action.action)\n if (!cachedRules) {\n cachedRules = this.#computeEffectiveRules(action.action, action.exposure)\n this.#actionRulesCache.set(action.action, cachedRules)\n }\n return cachedRules\n }\n\n override toJSON(): RuntimeApiModelSchema {\n const base = super.toJSON() as RuntimeApiModelSchema\n\n const routingMap: RoutingMap = {}\n for (const [method, parsedRoutes] of this.#routes.entries()) {\n routingMap[method] = parsedRoutes.map((pr) => this.#definitions.get(pr) as RouteDefinition)\n }\n\n return {\n ...base,\n routingMap,\n }\n }\n}\n"]}
1
+ {"version":3,"file":"RuntimeApiModel.js","sourceRoot":"","sources":["../../../src/modeling/RuntimeApiModel.ts"],"names":[],"mappings":"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","sourcesContent":["import { match, parse, exec, type RouteToken } from '@poppinss/matchit'\nimport { ApiModel, type ApiModelSchema } from './ApiModel.js'\nimport type { DataDomainSchema } from './DataDomain.js'\nimport type { ActionKind } from './actions/index.js'\nimport type { ExposedEntity } from './ExposedEntity.js'\nimport type { Action } from './actions/Action.js'\nimport type { DomainEntity } from './DomainEntity.js'\nimport type { DomainProperty } from './DomainProperty.js'\nimport type { DomainAssociation } from './DomainAssociation.js'\nimport { SemanticType } from './Semantics.js'\nimport { AccessRule, AccessRuleExecutionPhase } from './rules/AccessRule.js'\nimport { Exception } from '../exceptions/exception.js'\n\n/**\n * Identifies a specific exposed entity and its action kind.\n */\nexport interface RouteLookup {\n exposedEntityKey: string\n actionKind: ActionKind\n}\n\n/**\n * A routing definition mapping a path to an action lookup.\n */\nexport interface RouteDefinition {\n path: string\n lookup: RouteLookup\n}\n\n/**\n * A map of HTTP methods to their route definitions.\n */\nexport type RoutingMap = Record<string, RouteDefinition[]>\n\n/**\n * Schema for an API Model optimized for runtime routing.\n */\nexport interface RuntimeApiModelSchema extends ApiModelSchema {\n routingMap: RoutingMap\n}\n\nexport interface RuntimeResolvedAction {\n exposure: ExposedEntity\n entity: DomainEntity\n action: Action\n params: Record<string, string>\n}\n\nexport type RuleEvaluator = (rule: AccessRule) => Promise<boolean | undefined> | boolean | undefined\n\nexport interface PhaseRules {\n permissionRules: AccessRule[]\n mandatoryRules: AccessRule[]\n}\n\nexport interface ActionRulesCache {\n preFetch: PhaseRules\n fetch: PhaseRules\n postFetch: PhaseRules\n}\n\n/**\n * An optimized API Model subclass designed for fast runtime lookups.\n * It pre-compiles the RoutingMap into a radix tree for O(log N) or faster endpoint resolution.\n */\nexport class RuntimeApiModel extends ApiModel {\n /**\n * The parsed radix tree for fast routing.\n * Method -> ParsedRoutes\n */\n #routes = new Map<string, RouteToken[][]>()\n\n /**\n * Quick map from matchit parsed route format to our RouteDefinition for returning results\n */\n #definitions = new WeakMap<RouteToken[], RouteDefinition>()\n\n /**\n * Cached references to commonly used entities for fast runtime lookup.\n */\n cachedEntities: {\n user?: DomainEntity\n } = {}\n\n /**\n * Cached references to commonly used properties for fast runtime lookup.\n */\n cachedProperties: {\n username?: DomainProperty\n password?: DomainProperty\n role?: DomainProperty\n } = {}\n\n /**\n * Cached access rules for each action to avoid runtime computation overhead.\n */\n #actionRulesCache = new WeakMap<Action, ActionRulesCache>()\n\n /**\n * Cached session properties for fast runtime lookup.\n */\n readonly #sessionProperties = new Map<string, DomainProperty>()\n\n /**\n * Returns a readonly map of session properties.\n * Note, it creates a copy of the cached map to prevent modification of the internal state.\n */\n public get sessionProperties(): ReadonlyMap<string, DomainProperty> {\n return new Map(this.#sessionProperties)\n }\n\n /**\n * Cached properties that have at least one semantic, grouped by their entity.\n */\n readonly #semanticPropertiesCache = new Map<DomainEntity, DomainProperty[]>()\n\n /**\n * Cached properties that have at least one semantic, grouped by their entity and then by SemanticType.\n */\n readonly #propertiesBySemanticCache = new Map<DomainEntity, Map<SemanticType, DomainProperty[]>>()\n\n /**\n * Cached associations that have at least one semantic, grouped by their entity.\n */\n readonly #semanticAssociationsCache = new Map<DomainEntity, DomainAssociation[]>()\n\n /**\n * Cached associations that have at least one semantic, grouped by their entity and then by SemanticType.\n */\n readonly #associationsBySemanticCache = new Map<DomainEntity, Map<SemanticType, DomainAssociation[]>>()\n\n /**\n * Returns a readonly map of properties with semantics.\n * Note, it creates a copy of the cached map to prevent modification of the internal state.\n */\n public get semanticPropertiesCache(): ReadonlyMap<DomainEntity, DomainProperty[]> {\n return new Map(this.#semanticPropertiesCache)\n }\n\n /**\n * Returns properties for a specific entity that have a specific semantic type.\n * Provides O(1) lookup using the precomputed cache.\n */\n public getPropertiesBySemantic(entity: DomainEntity, semanticType: SemanticType): DomainProperty[] {\n const semanticMap = this.#propertiesBySemanticCache.get(entity)\n return semanticMap?.get(semanticType) || []\n }\n\n /**\n * Returns a readonly map of associations with semantics.\n * Note, it creates a copy of the cached map to prevent modification of the internal state.\n */\n public get semanticAssociationsCache(): ReadonlyMap<DomainEntity, DomainAssociation[]> {\n return new Map(this.#semanticAssociationsCache)\n }\n\n /**\n * Returns associations for a specific entity that have a specific semantic type.\n * Provides O(1) lookup using the precomputed cache.\n */\n public getAssociationsBySemantic(entity: DomainEntity, semanticType: SemanticType): DomainAssociation[] {\n const semanticMap = this.#associationsBySemanticCache.get(entity)\n return semanticMap?.get(semanticType) || []\n }\n\n constructor(schema: RuntimeApiModelSchema, domainSchema: DataDomainSchema) {\n super(schema, domainSchema)\n\n if (!schema.routingMap) {\n throw new Exception('The runtime API model must have a routing map.', {\n code: 'E_MISSING_ROUTING_MAP',\n help: 'Ensure that the routingMap property is defined when creating a RuntimeApiModel.',\n })\n }\n\n this.#initializeRouter(schema.routingMap)\n\n this.#cacheEntitiesAndProperties()\n this.#precomputeAccessRules()\n this.#precomputeSessionProperties()\n this.#precomputeSemanticProperties()\n }\n\n #precomputeSessionProperties(): void {\n if (!this.session || !this.domain) {\n return\n }\n for (const prop of this.session.properties) {\n const domainProperty = this.domain.findProperty(prop.key, prop.domain)\n if (!domainProperty) {\n throw new Exception(`Session property ${prop.key} not found in domain`)\n }\n this.#sessionProperties.set(prop.key, domainProperty)\n }\n }\n\n #precomputeSemanticProperties(): void {\n if (!this.domain) {\n return\n }\n\n const processEntity = (entity: DomainEntity) => {\n if (this.#semanticPropertiesCache.has(entity)) {\n return\n }\n\n const propertiesWithSemantics: DomainProperty[] = []\n const semanticPropsMap = new Map<SemanticType, DomainProperty[]>()\n\n for (const prop of entity.withInheritedProperties()) {\n if (Array.isArray(prop.semantics) && prop.semantics.length > 0) {\n propertiesWithSemantics.push(prop)\n\n for (const semantic of prop.semantics) {\n let propsForSemantic = semanticPropsMap.get(semantic.id)\n if (!propsForSemantic) {\n propsForSemantic = []\n semanticPropsMap.set(semantic.id, propsForSemantic)\n }\n propsForSemantic.push(prop)\n }\n }\n }\n\n if (propertiesWithSemantics.length > 0) {\n this.#semanticPropertiesCache.set(entity, propertiesWithSemantics)\n this.#propertiesBySemanticCache.set(entity, semanticPropsMap)\n }\n\n const associationsWithSemantics: DomainAssociation[] = []\n const semanticAssocMap = new Map<SemanticType, DomainAssociation[]>()\n\n for (const assoc of entity.withInheritedAssociations()) {\n if (Array.isArray(assoc.semantics) && assoc.semantics.length > 0) {\n associationsWithSemantics.push(assoc)\n\n for (const semantic of assoc.semantics) {\n let assocForSemantic = semanticAssocMap.get(semantic.id)\n if (!assocForSemantic) {\n assocForSemantic = []\n semanticAssocMap.set(semantic.id, assocForSemantic)\n }\n assocForSemantic.push(assoc)\n }\n }\n }\n\n if (associationsWithSemantics.length > 0) {\n this.#semanticAssociationsCache.set(entity, associationsWithSemantics)\n this.#associationsBySemanticCache.set(entity, semanticAssocMap)\n }\n }\n\n for (const entity of this.domain.listEntities()) {\n processEntity(entity)\n }\n\n for (const entity of this.domain.listAllForeignEntities()) {\n processEntity(entity)\n }\n }\n\n #precomputeAccessRules(): void {\n for (const entity of this.exposes.values()) {\n for (const action of entity.actions) {\n this.#actionRulesCache.set(action, this.#computeEffectiveRules(action, entity))\n }\n }\n }\n\n #computeEffectiveRules(action: Action, entity: ExposedEntity): ActionRulesCache {\n const hierarchy: AccessRule[][] = []\n\n if (action.accessRule && action.accessRule.length > 0) {\n hierarchy.push(action.accessRule)\n }\n\n let currentEntity: ExposedEntity | undefined = entity\n while (currentEntity) {\n if (currentEntity.accessRule && currentEntity.accessRule.length > 0) {\n hierarchy.push(currentEntity.accessRule)\n }\n currentEntity = currentEntity.parent ? this.exposes.get(currentEntity.parent.key) : undefined\n }\n\n if (this.accessRule && this.accessRule.length > 0) {\n hierarchy.push(this.accessRule)\n }\n\n const result: ActionRulesCache = {\n preFetch: {\n permissionRules: [],\n mandatoryRules: [],\n },\n fetch: {\n permissionRules: [],\n mandatoryRules: [],\n },\n postFetch: {\n permissionRules: [],\n mandatoryRules: [],\n },\n }\n\n const seenTypes = new Set<string>()\n\n for (const rulesLevel of hierarchy) {\n const typesInThisLevel = new Set<string>()\n for (const rule of rulesLevel) {\n const phase = rule.metadata[action.kind as keyof typeof rule.metadata]\n\n // If the rule does not specify an execution phase for this action kind, it is not evaluated\n if (!phase) {\n continue\n }\n\n // Shadowing: If a rule of the same type was defined closer to the action, ignore this one.\n if (seenTypes.has(rule.type)) {\n continue\n }\n typesInThisLevel.add(rule.type)\n\n let bucket\n if (phase === AccessRuleExecutionPhase.POST_FETCH) {\n bucket = result.postFetch\n } else if (phase === AccessRuleExecutionPhase.FETCH) {\n bucket = result.fetch\n } else {\n bucket = result.preFetch\n }\n\n if (rule.mandatory) {\n bucket.mandatoryRules.push(rule)\n } else {\n bucket.permissionRules.push(rule)\n }\n }\n for (const type of typesInThisLevel) {\n seenTypes.add(type)\n }\n }\n\n return result\n }\n\n #cacheEntitiesAndProperties(): void {\n if (!this.user || !this.domain) {\n return\n }\n\n const userEntity = this.domain.findEntity(this.user.key, this.user.domain)\n if (!userEntity) {\n return\n }\n\n this.cachedEntities.user = userEntity\n\n for (const prop of userEntity.withInheritedProperties()) {\n if (prop.hasSemantic(SemanticType.Username)) {\n this.cachedProperties.username = prop\n }\n if (prop.hasSemantic(SemanticType.Password)) {\n this.cachedProperties.password = prop\n }\n if (prop.hasSemantic(SemanticType.UserRole)) {\n this.cachedProperties.role = prop\n }\n }\n }\n\n #initializeRouter(routingMap: RoutingMap): void {\n for (const [method, definitions] of Object.entries(routingMap)) {\n const parsedRoutes = []\n for (const def of definitions) {\n // matchit's parse() transforms a route string into an object representation.\n // It expects `:param` syntax, while our API models use OpenAPI `{param}` syntax.\n const matchitPath = def.path.replace(/\\{([^}]+)\\}/g, ':$1')\n const parsed = parse(matchitPath)\n this.#definitions.set(parsed, def)\n parsedRoutes.push(parsed)\n }\n this.#routes.set(method.toUpperCase(), parsedRoutes)\n }\n }\n\n /**\n * Looks up the corresponding exposed entity and action for a given request.\n *\n * @param method The HTTP method (e.g., 'GET', 'POST').\n * @param path The request path (e.g., '/users/123').\n * @returns An object with the entity, action, and extracted path parameters if a match is found.\n */\n lookupAction(method: string, path: string): RuntimeResolvedAction | undefined {\n const parsedRoutes = this.#routes.get(method.toUpperCase())\n if (!parsedRoutes) {\n return undefined\n }\n\n // `match` returns the matching parsed route (which is an array of segments), or empty array if no match\n const matchedRoute = match(path, parsedRoutes)\n if (!matchedRoute || matchedRoute.length === 0) {\n return undefined\n }\n\n const def = this.#definitions.get(matchedRoute)\n if (!def) {\n return undefined\n }\n\n const params = exec(path, matchedRoute)\n\n const exposure = this.exposes.get(def.lookup.exposedEntityKey)\n if (!exposure) {\n throw new Exception('Missing exposure ' + def.lookup.exposedEntityKey, { code: 'API_MODEL_ERROR', status: 500 })\n }\n\n const action = exposure.actions.find((a) => a.kind === def.lookup.actionKind)\n if (!action) {\n throw new Exception('Missing action ' + def.lookup.actionKind, { code: 'API_MODEL_ERROR', status: 500 })\n }\n\n const entity = this.domain?.findEntity(exposure.entity.key, exposure.entity.domain)\n if (!entity) {\n throw new Exception('Missing entity ' + exposure.entity.key, { code: 'API_MODEL_ERROR', status: 500 })\n }\n\n return {\n exposure,\n entity,\n action,\n params,\n }\n }\n\n /**\n * Retrieves the precomputed and shadowed effective rules for a given action.\n */\n getEffectiveRules(action: RuntimeResolvedAction): ActionRulesCache {\n let cachedRules = this.#actionRulesCache.get(action.action)\n if (!cachedRules) {\n cachedRules = this.#computeEffectiveRules(action.action, action.exposure)\n this.#actionRulesCache.set(action.action, cachedRules)\n }\n return cachedRules\n }\n\n override toJSON(): RuntimeApiModelSchema {\n const base = super.toJSON() as RuntimeApiModelSchema\n\n const routingMap: RoutingMap = {}\n for (const [method, parsedRoutes] of this.#routes.entries()) {\n routingMap[method] = parsedRoutes.map((pr) => this.#definitions.get(pr) as RouteDefinition)\n }\n\n return {\n ...base,\n routingMap,\n }\n }\n}\n"]}
@@ -0,0 +1,15 @@
1
+ import { ApiModel, type ApiModelSchema } from '../ApiModel.js';
2
+ import { type RuntimeApiModelSchema } from '../RuntimeApiModel.js';
3
+ /**
4
+ * A class that takes the API model and generates a runtime-optimized API model.
5
+ *
6
+ * Note, the API model must be already validated before passing it to this generator.
7
+ * This class doesn't perform any validation, but it will throw an exception if the API model is invalid.
8
+ */
9
+ export declare class RuntimeModelGenerator {
10
+ #private;
11
+ constructor(input: ApiModel | ApiModelSchema);
12
+ generate(): Promise<RuntimeApiModelSchema>;
13
+ private addRoute;
14
+ }
15
+ //# sourceMappingURL=RuntimeModelGenerator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RuntimeModelGenerator.d.ts","sourceRoot":"","sources":["../../../../src/modeling/generators/RuntimeModelGenerator.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,KAAK,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAC9D,OAAO,EAAwB,KAAK,qBAAqB,EAAE,MAAM,uBAAuB,CAAA;AAExF;;;;;GAKG;AACH,qBAAa,qBAAqB;;gBAKpB,KAAK,EAAE,QAAQ,GAAG,cAAc;IAU/B,QAAQ,IAAI,OAAO,CAAC,qBAAqB,CAAC;IA2CvD,OAAO,CAAC,QAAQ;CAUjB"}
@@ -0,0 +1,78 @@
1
+ import { ApiModel } from '../ApiModel.js';
2
+ /**
3
+ * A class that takes the API model and generates a runtime-optimized API model.
4
+ *
5
+ * Note, the API model must be already validated before passing it to this generator.
6
+ * This class doesn't perform any validation, but it will throw an exception if the API model is invalid.
7
+ */
8
+ export class RuntimeModelGenerator {
9
+ #apiModel;
10
+ #apiSchema;
11
+ #routingMap = {};
12
+ constructor(input) {
13
+ if (input instanceof ApiModel) {
14
+ this.#apiModel = input;
15
+ this.#apiSchema = input.toJSON();
16
+ }
17
+ else {
18
+ this.#apiModel = new ApiModel(input);
19
+ this.#apiSchema = input;
20
+ }
21
+ }
22
+ async generate() {
23
+ if (!this.#apiModel) {
24
+ throw new Error('API model is not defined');
25
+ }
26
+ for (const expose of this.#apiModel.exposes.values()) {
27
+ const colPath = expose.getAbsoluteCollectionPath();
28
+ const resPath = expose.getAbsoluteResourcePath();
29
+ for (const action of expose.actions) {
30
+ switch (action.kind) {
31
+ case 'list':
32
+ if (colPath)
33
+ this.addRoute('GET', colPath, expose.key, action.kind);
34
+ break;
35
+ case 'create':
36
+ if (colPath)
37
+ this.addRoute('POST', colPath, expose.key, action.kind);
38
+ break;
39
+ case 'search':
40
+ if (colPath)
41
+ this.addRoute('POST', `${colPath}/search`, expose.key, action.kind);
42
+ break;
43
+ case 'read':
44
+ if (resPath)
45
+ this.addRoute('GET', resPath, expose.key, action.kind);
46
+ break;
47
+ case 'update':
48
+ if (resPath) {
49
+ const updateAction = action;
50
+ for (const method of updateAction.allowedMethods) {
51
+ this.addRoute(method, resPath, expose.key, action.kind);
52
+ }
53
+ }
54
+ break;
55
+ case 'delete':
56
+ if (resPath)
57
+ this.addRoute('DELETE', resPath, expose.key, action.kind);
58
+ break;
59
+ }
60
+ }
61
+ }
62
+ return {
63
+ ...this.#apiSchema,
64
+ routingMap: this.#routingMap,
65
+ };
66
+ }
67
+ addRoute(method, path, exposedEntityKey, actionKind) {
68
+ const upperMethod = method.toUpperCase();
69
+ if (!this.#routingMap[upperMethod]) {
70
+ this.#routingMap[upperMethod] = [];
71
+ }
72
+ this.#routingMap[upperMethod].push({
73
+ path,
74
+ lookup: { exposedEntityKey, actionKind },
75
+ });
76
+ }
77
+ }
78
+ //# sourceMappingURL=RuntimeModelGenerator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RuntimeModelGenerator.js","sourceRoot":"","sources":["../../../../src/modeling/generators/RuntimeModelGenerator.ts"],"names":[],"mappings":"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","sourcesContent":["import { type ActionKind, type UpdateAction } from '../actions/index.js'\nimport { ApiModel, type ApiModelSchema } from '../ApiModel.js'\nimport { type RouteDefinition, type RuntimeApiModelSchema } from '../RuntimeApiModel.js'\n\n/**\n * A class that takes the API model and generates a runtime-optimized API model.\n *\n * Note, the API model must be already validated before passing it to this generator.\n * This class doesn't perform any validation, but it will throw an exception if the API model is invalid.\n */\nexport class RuntimeModelGenerator {\n #apiModel: ApiModel\n #apiSchema: ApiModelSchema\n #routingMap: Record<string, RouteDefinition[]> = {}\n\n constructor(input: ApiModel | ApiModelSchema) {\n if (input instanceof ApiModel) {\n this.#apiModel = input\n this.#apiSchema = input.toJSON()\n } else {\n this.#apiModel = new ApiModel(input)\n this.#apiSchema = input\n }\n }\n\n public async generate(): Promise<RuntimeApiModelSchema> {\n if (!this.#apiModel) {\n throw new Error('API model is not defined')\n }\n\n for (const expose of this.#apiModel.exposes.values()) {\n const colPath = expose.getAbsoluteCollectionPath()\n const resPath = expose.getAbsoluteResourcePath()\n for (const action of expose.actions) {\n switch (action.kind) {\n case 'list':\n if (colPath) this.addRoute('GET', colPath, expose.key, action.kind)\n break\n case 'create':\n if (colPath) this.addRoute('POST', colPath, expose.key, action.kind)\n break\n case 'search':\n if (colPath) this.addRoute('POST', `${colPath}/search`, expose.key, action.kind)\n break\n case 'read':\n if (resPath) this.addRoute('GET', resPath, expose.key, action.kind)\n break\n case 'update':\n if (resPath) {\n const updateAction = action as UpdateAction\n for (const method of updateAction.allowedMethods) {\n this.addRoute(method, resPath, expose.key, action.kind)\n }\n }\n break\n case 'delete':\n if (resPath) this.addRoute('DELETE', resPath, expose.key, action.kind)\n break\n }\n }\n }\n\n return {\n ...this.#apiSchema,\n routingMap: this.#routingMap,\n }\n }\n\n private addRoute(method: string, path: string, exposedEntityKey: string, actionKind: ActionKind): void {\n const upperMethod = method.toUpperCase()\n if (!this.#routingMap[upperMethod]) {\n this.#routingMap[upperMethod] = []\n }\n this.#routingMap[upperMethod].push({\n path,\n lookup: { exposedEntityKey, actionKind },\n })\n }\n}\n"]}
@@ -1,4 +1,9 @@
1
- export declare function paramNameFor(entityKeyLocal: string): string;
1
+ /**
2
+ * Generates a semantic parameter name for an entity.
3
+ * It converts snake_case, kebab-case, or PascalCase to camelCase and appends 'Id'.
4
+ * @param entityName The entity name (e.g. from entity.info.name)
5
+ */
6
+ export declare function paramNameFor(entityName: string): string;
2
7
  /**
3
8
  * Ensures the path starts with a single leading slash and has no trailing slash (except root '/')
4
9
  * @param path The path fragment to normalize
@@ -1 +1 @@
1
- {"version":3,"file":"endpointHelpers.d.ts","sourceRoot":"","sources":["../../../../src/modeling/helpers/endpointHelpers.ts"],"names":[],"mappings":"AAAA,wBAAgB,YAAY,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAI3D;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKvD;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAI7D"}
1
+ {"version":3,"file":"endpointHelpers.d.ts","sourceRoot":"","sources":["../../../../src/modeling/helpers/endpointHelpers.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CA4CvD;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKvD;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAI7D"}