@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,7 +1,46 @@
1
- export function paramNameFor(entityKeyLocal) {
2
- const parts = entityKeyLocal.split(':');
3
- const key = parts[parts.length - 1];
4
- return `${key}Id`;
1
+ import { Exception } from '../../exceptions/exception.js';
2
+ /**
3
+ * Generates a semantic parameter name for an entity.
4
+ * It converts snake_case, kebab-case, or PascalCase to camelCase and appends 'Id'.
5
+ * @param entityName The entity name (e.g. from entity.info.name)
6
+ */
7
+ export function paramNameFor(entityName) {
8
+ if (!entityName) {
9
+ throw new Exception('Cannot generate parameter name from an empty string.', {
10
+ code: 'E_INVALID_PARAM_NAME',
11
+ help: 'The entity name used for path parameter generation is empty.',
12
+ });
13
+ }
14
+ // Add a space between lowercase and uppercase letters to handle camelCase/PascalCase
15
+ let withSpaces = entityName.replace(/([a-z])([A-Z])/g, '$1 $2');
16
+ // Also split consecutive uppercase letters if followed by a lowercase (e.g. XMLHttp -> XML Http)
17
+ withSpaces = withSpaces.replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2');
18
+ // Replace all non-alphanumeric characters with spaces
19
+ const cleanStr = withSpaces.replace(/[^a-zA-Z0-9]/g, ' ');
20
+ // Split by spaces and filter out empty strings
21
+ const words = cleanStr.split(/\s+/).filter(Boolean);
22
+ if (words.length === 0) {
23
+ throw new Exception(`Cannot generate a valid parameter name from "${entityName}".`, {
24
+ code: 'E_INVALID_PARAM_NAME',
25
+ help: 'The entity name must contain alphanumeric characters to generate a path parameter.',
26
+ });
27
+ }
28
+ // CamelCase: lower first word, Capitalize subsequent words
29
+ const camelCased = words
30
+ .map((word, index) => {
31
+ const lower = word.toLowerCase();
32
+ if (index === 0) {
33
+ return lower;
34
+ }
35
+ return lower.charAt(0).toUpperCase() + lower.slice(1);
36
+ })
37
+ .join('');
38
+ // Ensure it starts with a letter or underscore
39
+ let param = camelCased;
40
+ if (/^[0-9]/.test(param)) {
41
+ param = '_' + param;
42
+ }
43
+ return `${param}Id`;
5
44
  }
6
45
  /**
7
46
  * Ensures the path starts with a single leading slash and has no trailing slash (except root '/')
@@ -1 +1 @@
1
- {"version":3,"file":"endpointHelpers.js","sourceRoot":"","sources":["../../../../src/modeling/helpers/endpointHelpers.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,YAAY,CAAC,cAAsB;IACjD,MAAM,KAAK,GAAG,cAAc,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IACvC,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;IACnC,OAAO,GAAG,GAAG,IAAI,CAAA;AACnB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAA;IAC3B,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,OAAO,EAAE,CAAA;IACnE,IAAI,SAAS,KAAK,GAAG;QAAE,OAAO,GAAG,CAAA;IACjC,OAAO,SAAS,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;AACtC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,SAAS,CAAC,IAAY,EAAE,KAAa;IACnD,MAAM,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IACvD,MAAM,CAAC,GAAG,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,EAAE,CAAA;IACrD,OAAO,GAAG,CAAC,GAAG,CAAC,EAAE,CAAA;AACnB,CAAC","sourcesContent":["export function paramNameFor(entityKeyLocal: string): string {\n const parts = entityKeyLocal.split(':')\n const key = parts[parts.length - 1]\n return `${key}Id`\n}\n\n/**\n * Ensures the path starts with a single leading slash and has no trailing slash (except root '/')\n * @param path The path fragment to normalize\n */\nexport function ensureLeadingSlash(path: string): string {\n const trimmed = path.trim()\n const withSlash = trimmed.startsWith('/') ? trimmed : `/${trimmed}`\n if (withSlash === '/') return '/'\n return withSlash.replace(/\\/+$/, '')\n}\n\n/**\n * Joins two absolute-like fragments ensuring single slashes between segments\n * @param left The left path fragment\n * @param right The right path fragment\n */\nexport function joinPaths(left: string, right: string): string {\n const l = left.endsWith('/') ? left.slice(0, -1) : left\n const r = right.startsWith('/') ? right : `/${right}`\n return `${l}${r}`\n}\n"]}
1
+ {"version":3,"file":"endpointHelpers.js","sourceRoot":"","sources":["../../../../src/modeling/helpers/endpointHelpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAA;AAEzD;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,UAAkB;IAC7C,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,IAAI,SAAS,CAAC,sDAAsD,EAAE;YAC1E,IAAI,EAAE,sBAAsB;YAC5B,IAAI,EAAE,8DAA8D;SACrE,CAAC,CAAA;IACJ,CAAC;IAED,qFAAqF;IACrF,IAAI,UAAU,GAAG,UAAU,CAAC,OAAO,CAAC,iBAAiB,EAAE,OAAO,CAAC,CAAA;IAC/D,iGAAiG;IACjG,UAAU,GAAG,UAAU,CAAC,OAAO,CAAC,uBAAuB,EAAE,OAAO,CAAC,CAAA;IAEjE,sDAAsD;IACtD,MAAM,QAAQ,GAAG,UAAU,CAAC,OAAO,CAAC,eAAe,EAAE,GAAG,CAAC,CAAA;IAEzD,+CAA+C;IAC/C,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;IAEnD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,SAAS,CAAC,gDAAgD,UAAU,IAAI,EAAE;YAClF,IAAI,EAAE,sBAAsB;YAC5B,IAAI,EAAE,oFAAoF;SAC3F,CAAC,CAAA;IACJ,CAAC;IAED,2DAA2D;IAC3D,MAAM,UAAU,GAAG,KAAK;SACrB,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;QACnB,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAA;QAChC,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;YAChB,OAAO,KAAK,CAAA;QACd,CAAC;QACD,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;IACvD,CAAC,CAAC;SACD,IAAI,CAAC,EAAE,CAAC,CAAA;IAEX,+CAA+C;IAC/C,IAAI,KAAK,GAAG,UAAU,CAAA;IACtB,IAAI,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,KAAK,GAAG,GAAG,GAAG,KAAK,CAAA;IACrB,CAAC;IAED,OAAO,GAAG,KAAK,IAAI,CAAA;AACrB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAA;IAC3B,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,OAAO,EAAE,CAAA;IACnE,IAAI,SAAS,KAAK,GAAG;QAAE,OAAO,GAAG,CAAA;IACjC,OAAO,SAAS,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;AACtC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,SAAS,CAAC,IAAY,EAAE,KAAa;IACnD,MAAM,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IACvD,MAAM,CAAC,GAAG,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,EAAE,CAAA;IACrD,OAAO,GAAG,CAAC,GAAG,CAAC,EAAE,CAAA;AACnB,CAAC","sourcesContent":["import { Exception } from '../../exceptions/exception.js'\n\n/**\n * Generates a semantic parameter name for an entity.\n * It converts snake_case, kebab-case, or PascalCase to camelCase and appends 'Id'.\n * @param entityName The entity name (e.g. from entity.info.name)\n */\nexport function paramNameFor(entityName: string): string {\n if (!entityName) {\n throw new Exception('Cannot generate parameter name from an empty string.', {\n code: 'E_INVALID_PARAM_NAME',\n help: 'The entity name used for path parameter generation is empty.',\n })\n }\n\n // Add a space between lowercase and uppercase letters to handle camelCase/PascalCase\n let withSpaces = entityName.replace(/([a-z])([A-Z])/g, '$1 $2')\n // Also split consecutive uppercase letters if followed by a lowercase (e.g. XMLHttp -> XML Http)\n withSpaces = withSpaces.replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')\n\n // Replace all non-alphanumeric characters with spaces\n const cleanStr = withSpaces.replace(/[^a-zA-Z0-9]/g, ' ')\n\n // Split by spaces and filter out empty strings\n const words = cleanStr.split(/\\s+/).filter(Boolean)\n\n if (words.length === 0) {\n throw new Exception(`Cannot generate a valid parameter name from \"${entityName}\".`, {\n code: 'E_INVALID_PARAM_NAME',\n help: 'The entity name must contain alphanumeric characters to generate a path parameter.',\n })\n }\n\n // CamelCase: lower first word, Capitalize subsequent words\n const camelCased = words\n .map((word, index) => {\n const lower = word.toLowerCase()\n if (index === 0) {\n return lower\n }\n return lower.charAt(0).toUpperCase() + lower.slice(1)\n })\n .join('')\n\n // Ensure it starts with a letter or underscore\n let param = camelCased\n if (/^[0-9]/.test(param)) {\n param = '_' + param\n }\n\n return `${param}Id`\n}\n\n/**\n * Ensures the path starts with a single leading slash and has no trailing slash (except root '/')\n * @param path The path fragment to normalize\n */\nexport function ensureLeadingSlash(path: string): string {\n const trimmed = path.trim()\n const withSlash = trimmed.startsWith('/') ? trimmed : `/${trimmed}`\n if (withSlash === '/') return '/'\n return withSlash.replace(/\\/+$/, '')\n}\n\n/**\n * Joins two absolute-like fragments ensuring single slashes between segments\n * @param left The left path fragment\n * @param right The right path fragment\n */\nexport function joinPaths(left: string, right: string): string {\n const l = left.endsWith('/') ? left.slice(0, -1) : left\n const r = right.startsWith('/') ? right : `/${right}`\n return `${l}${r}`\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"api_model_rules.d.ts","sourceRoot":"","sources":["../../../../src/modeling/validation/api_model_rules.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAC9C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACxD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAKlD,OAAO,KAAK,EAAE,sBAAsB,EAA6B,MAAM,aAAa,CAAA;AAcpF;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,QAAQ,GAAG,sBAAsB,EAAE,CAiD9E;AAED,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,QAAQ,GAAG,sBAAsB,EAAE,CA+BpF;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,QAAQ,GAAG,sBAAsB,EAAE,CAyKlF;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,QAAQ,GAAG,sBAAsB,EAAE,CAuElF;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,QAAQ,GAAG,sBAAsB,EAAE,CA+C/E;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,GAAG,sBAAsB,EAAE,CAuDnH;AAED,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,aAAa,EAAE,QAAQ,EAAE,QAAQ,GAAG,sBAAsB,EAAE,CAoO3G"}
1
+ {"version":3,"file":"api_model_rules.d.ts","sourceRoot":"","sources":["../../../../src/modeling/validation/api_model_rules.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAC9C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACxD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAKlD,OAAO,KAAK,EAAE,sBAAsB,EAA6B,MAAM,aAAa,CAAA;AAcpF;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,QAAQ,GAAG,sBAAsB,EAAE,CAiD9E;AAED,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,QAAQ,GAAG,sBAAsB,EAAE,CA+BpF;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,QAAQ,GAAG,sBAAsB,EAAE,CAyKlF;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,QAAQ,GAAG,sBAAsB,EAAE,CAuElF;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,QAAQ,GAAG,sBAAsB,EAAE,CA+C/E;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,GAAG,sBAAsB,EAAE,CAuDnH;AAED,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,aAAa,EAAE,QAAQ,EAAE,QAAQ,GAAG,sBAAsB,EAAE,CAuP3G"}
@@ -548,6 +548,23 @@ export function validateExposedEntity(exposure, apiModel) {
548
548
  }
549
549
  }
550
550
  }
551
+ // Branch Path Parameter Collision
552
+ const absoluteResourcePath = exposure.getAbsoluteResourcePath();
553
+ if (absoluteResourcePath) {
554
+ const params = [...absoluteResourcePath.matchAll(/\{([^}]+)\}/g)].map((m) => m[1]);
555
+ const uniqueParams = new Set(params);
556
+ if (uniqueParams.size !== params.length) {
557
+ const duplicates = params.filter((item, index) => params.indexOf(item) !== index);
558
+ const duplicateParam = duplicates[0];
559
+ issues.push({
560
+ code: createCode('EXPOSURE', 'DUPLICATE_PATH_PARAMETER'),
561
+ message: `[${entityName}]: The path parameter "{${duplicateParam}}" is duplicated in the resource path hierarchy.`,
562
+ suggestion: 'Change the parameter name in either this resource or its ancestor to ensure unique parameter names.',
563
+ severity: 'error',
564
+ context: { ...context, property: 'resourcePath' },
565
+ });
566
+ }
567
+ }
551
568
  // Minimum Actions
552
569
  if (!exposure.actions || exposure.actions.length === 0) {
553
570
  issues.push({
@@ -1 +1 @@
1
- {"version":3,"file":"api_model_rules.js","sourceRoot":"","sources":["../../../../src/modeling/validation/api_model_rules.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ApiModel } from '../ApiModel.js'\nimport type { ExposedEntity } from '../ExposedEntity.js'\nimport type { Action } from '../actions/Action.js'\nimport { ListAction } from '../actions/ListAction.js'\nimport { DeleteAction } from '../actions/DeleteAction.js'\nimport { UpdateAction } from '../actions/UpdateAction.js'\nimport { SearchAction } from '../actions/SearchAction.js'\nimport type { ApiModelValidationItem, ApiModelValidationContext } from '../types.js'\nimport { ApiModelKind, ExposedEntityKind } from '../../models/kinds.js'\nimport { SemanticType } from '../Semantics.js'\nimport { DomainProperty } from '../DomainProperty.js'\n\n/**\n * Creates a unique validation code.\n * @param entity The entity type (e.g., 'API', 'EXPOSURE', 'ACTION')\n * @param issue The issue identifier (e.g., 'MISSING_NAME')\n */\nfunction createCode(entity: string, issue: string): string {\n return `${entity}_${issue}`\n}\n\n/**\n * Validates the core properties and metadata of an ApiModel.\n */\nexport function validateApiModelInfo(model: ApiModel): ApiModelValidationItem[] {\n const issues: ApiModelValidationItem[] = []\n const context: ApiModelValidationContext = {\n apiModelKey: model.key,\n kind: ApiModelKind,\n key: model.key,\n }\n\n if (model.kind !== ApiModelKind) {\n issues.push({\n code: createCode('API', 'INVALID_KIND'),\n message: 'The API model type is incorrect.',\n suggestion: 'Set the model type to \"ApiModel\".',\n severity: 'error',\n context: { ...context, property: 'kind' },\n })\n }\n\n if (!model.key || typeof model.key !== 'string' || model.key.trim() === '') {\n issues.push({\n code: createCode('API', 'MISSING_KEY'),\n message: 'The API model is missing a unique identifier.',\n suggestion: 'Provide a valid name to use as a unique identifier.',\n severity: 'error',\n context: { ...context, property: 'key' },\n })\n }\n\n if (!model.info || !model.info.name || model.info.name.trim() === '') {\n issues.push({\n code: createCode('API', 'MISSING_NAME'),\n message: 'The API model has no defined name.',\n suggestion: 'Provide a descriptive name for your API.',\n severity: 'error',\n context: { ...context, property: 'info.name' },\n })\n }\n\n if (!model.info || !model.info.description || model.info.description.trim() === '') {\n issues.push({\n code: createCode('API', 'MISSING_DESCRIPTION'),\n message: 'Adding a description helps others understand your API.',\n suggestion: 'Add a description to clarify the purpose of this API.',\n severity: 'warning',\n context: { ...context, property: 'info.description' },\n })\n }\n\n return issues\n}\n\nexport function validateApiModelDependency(model: ApiModel): ApiModelValidationItem[] {\n const issues: ApiModelValidationItem[] = []\n const context: ApiModelValidationContext = {\n apiModelKey: model.key,\n kind: ApiModelKind,\n key: model.key,\n }\n\n const domain = model.domain\n if (!domain) {\n issues.push({\n code: createCode('API', 'MISSING_DOMAIN'),\n message: 'No Data Domain is attached to the API.',\n suggestion: 'Select a Data Domain from the settings to power your API.',\n severity: 'error',\n context,\n })\n return issues // Can't validate version if it doesn't exist\n }\n\n if (!domain.info || !domain.info.version) {\n issues.push({\n code: createCode('API', 'MISSING_DOMAIN_VERSION'),\n message: 'The selected Data Domain is missing a version number.',\n suggestion: 'Specify a version for the attached Data Domain.',\n severity: 'error',\n context,\n })\n }\n\n return issues\n}\n\nexport function validateApiModelSecurity(model: ApiModel): ApiModelValidationItem[] {\n const issues: ApiModelValidationItem[] = []\n const context: ApiModelValidationContext = {\n apiModelKey: model.key,\n kind: ApiModelKind,\n key: model.key,\n }\n\n // Resolve User target\n const userEntity = model.domain && model.user ? model.domain.findEntity(model.user.key, model.user.domain) : undefined\n\n // Authentication\n if (!model.authentication) {\n issues.push({\n code: createCode('API', 'MISSING_AUTHENTICATION'),\n message: 'The API is missing authentication settings.',\n suggestion: 'Go to the security settings and configure how users authenticate.',\n severity: 'error',\n context: { ...context, property: 'authentication' },\n })\n } else if (model.authentication.strategy === 'UsernamePassword') {\n if (userEntity) {\n let passwordProp: DomainProperty | undefined\n for (const prop of userEntity.properties) {\n if (prop.hasSemantic(SemanticType.Password)) {\n passwordProp = prop\n break\n }\n }\n if (!passwordProp) {\n issues.push({\n code: createCode('API', 'MISSING_PASSWORD_SEMANTIC'),\n message: 'The selected user model requires a property with the Password data semantic for authentication.',\n suggestion: 'Go to the Data Modeler and add the \"Password\" semantic to the password property.',\n severity: 'error',\n context: { ...context, property: 'user' },\n })\n }\n\n let usernameProp: DomainProperty | undefined\n for (const prop of userEntity.properties) {\n if (prop.hasSemantic(SemanticType.Username)) {\n usernameProp = prop\n break\n }\n }\n if (!usernameProp) {\n issues.push({\n code: createCode('API', 'MISSING_USERNAME_SEMANTIC'),\n message: 'Username & Password authentication requires a field with the Username data semantic.',\n suggestion: 'Go to the Data Modeler and add the \"Username\" semantic to the property used for login.',\n severity: 'error',\n context: { ...context, property: 'user' },\n })\n }\n }\n }\n\n // Authorization\n if (!model.authorization) {\n issues.push({\n code: createCode('API', 'MISSING_AUTHORIZATION'),\n message: 'The API is missing authorization settings.',\n suggestion: 'Go to the security settings and configure how to handle user permissions.',\n severity: 'error',\n context: { ...context, property: 'authorization' },\n })\n } else if (model.authorization.strategy === 'RBAC') {\n if (userEntity) {\n let roleProp: DomainProperty | undefined\n for (const prop of userEntity.properties) {\n if (prop.hasSemantic(SemanticType.UserRole)) {\n roleProp = prop\n break\n }\n }\n if (!roleProp) {\n issues.push({\n code: createCode('API', 'MISSING_ROLE_SEMANTIC'),\n message: 'Role-based access control requires a property with the User Role data semantic on the user model.',\n suggestion: 'Go to the Data Modeler and add the \"User Role\" semantic to the property used for roles.',\n severity: 'error',\n context: { ...context, property: 'user' },\n })\n }\n }\n }\n\n // Session\n if (!model.session) {\n issues.push({\n code: createCode('API', 'MISSING_SESSION'),\n message: 'The API is missing session configuration.',\n suggestion: 'Configure how user sessions will be handled.',\n severity: 'error',\n context: { ...context, property: 'session' },\n })\n } else {\n if (!model.session.secret) {\n issues.push({\n code: createCode('API', 'MISSING_SESSION_SECRET'),\n message: 'A secure encryption key is required for sessions.',\n suggestion: 'Provide a strong security key in the session settings.',\n severity: 'error',\n context: { ...context, property: 'session.secret' },\n })\n }\n\n if (!model.session.properties || model.session.properties.length === 0) {\n issues.push({\n code: createCode('API', 'MISSING_SESSION_PROPERTIES'),\n message: 'The session token needs to include at least one piece of user information, like an ID.',\n suggestion: 'Select fields that should be stored securely inside the session payload.',\n severity: 'error',\n context: { ...context, property: 'session.properties' },\n })\n } else if (model.authorization && model.authorization.strategy === 'RBAC') {\n if (userEntity) {\n let roleProp: DomainProperty | undefined\n for (const prop of userEntity.properties) {\n if (prop.hasSemantic(SemanticType.UserRole)) {\n roleProp = prop\n break\n }\n }\n if (roleProp && !model.session.properties.find((p) => p.key === roleProp?.key)) {\n issues.push({\n code: createCode('API', 'MISSING_RBAC_SESSION_PROPERTY'),\n message: 'The user role must be included in the session data for permissions to work.',\n suggestion: 'Make sure your selected role property is checked in the session settings.',\n severity: 'error',\n context: { ...context, property: 'session.properties' },\n })\n }\n }\n }\n\n const { cookie, jwt } = model.session\n if ((!cookie || !cookie.enabled) && (!jwt || !jwt.enabled)) {\n issues.push({\n code: createCode('API', 'MISSING_SESSION_TRANSPORT'),\n message: 'No delivery method for sessions (like cookies or tokens) is enabled.',\n suggestion: 'Enable at least one session delivery mechanism in the security settings.',\n severity: 'error',\n context: { ...context, property: 'session' },\n })\n }\n }\n\n // User Target\n if (!model.user) {\n issues.push({\n code: createCode('API', 'MISSING_USER_ENTITY'),\n message: 'You need to specify what kind of object represents your users.',\n suggestion: 'Select a model from your domain that stores your user accounts.',\n severity: 'error',\n context: { ...context, property: 'user' },\n })\n } else if (model.domain && !model.domain.findEntity(model.user.key, model.user.domain)) {\n issues.push({\n code: createCode('API', 'INVALID_USER_ENTITY'),\n message: 'The selected user model no longer exists in your data domain.',\n suggestion: 'Please navigate to security settings and select a valid user model.',\n severity: 'error',\n context: { ...context, property: 'user' },\n })\n }\n\n return issues\n}\n\nexport function validateApiModelMetadata(model: ApiModel): ApiModelValidationItem[] {\n const issues: ApiModelValidationItem[] = []\n const context: ApiModelValidationContext = {\n apiModelKey: model.key,\n kind: ApiModelKind,\n key: model.key,\n }\n\n const urlRegex = /^https?:\\/\\//i\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/\n\n if (model.contact) {\n if (model.contact.email && !emailRegex.test(model.contact.email)) {\n issues.push({\n code: createCode('API', 'INVALID_CONTACT_EMAIL'),\n message: 'The contact email address looks invalid.',\n suggestion: 'Please double check the email address formatting.',\n severity: 'error',\n context: { ...context, property: 'contact.email' },\n })\n }\n if (model.contact.url && !urlRegex.test(model.contact.url)) {\n issues.push({\n code: createCode('API', 'INVALID_CONTACT_URL'),\n message: 'The contact link looks invalid.',\n suggestion: 'Provide a working link, starting with http:// or https://.',\n severity: 'error',\n context: { ...context, property: 'contact.url' },\n })\n }\n } else {\n issues.push({\n code: createCode('API', 'MISSING_CONTACT'),\n message: 'A contact email or link is highly recommended for API consumers.',\n suggestion: 'Add an email or help desk link in the metadata tab.',\n severity: 'info',\n context: { ...context, property: 'contact' },\n })\n }\n\n if (model.license) {\n if (model.license.url && !urlRegex.test(model.license.url)) {\n issues.push({\n code: createCode('API', 'INVALID_LICENSE_URL'),\n message: 'The license link looks invalid.',\n suggestion: 'Provide a working link, starting with http:// or https://.',\n severity: 'error',\n context: { ...context, property: 'license.url' },\n })\n }\n } else {\n issues.push({\n code: createCode('API', 'MISSING_LICENSE'),\n message: 'Adding a license to your API helps users understand its usage rights.',\n suggestion: 'Add the name and a link to your API license terms.',\n severity: 'info',\n context: { ...context, property: 'license' },\n })\n }\n\n if (!model.termsOfService) {\n issues.push({\n code: createCode('API', 'MISSING_TOS'),\n message: 'Terms of Service help legal compliance.',\n suggestion: 'Add a link to the terms of your API service.',\n severity: 'info',\n context: { ...context, property: 'termsOfService' },\n })\n }\n\n return issues\n}\n\nexport function validateApiPagination(model: ApiModel): ApiModelValidationItem[] {\n const issues: ApiModelValidationItem[] = []\n const context: ApiModelValidationContext = {\n apiModelKey: model.key,\n kind: ApiModelKind,\n key: model.key,\n }\n // We only need pagination when the API contains at least one List or Search action\n let validate = false\n for (const exposure of model.exposes.values()) {\n if (exposure.actions.some((action) => ListAction.isListAction(action) || SearchAction.isSearchAction(action))) {\n validate = true\n break\n }\n }\n if (!validate) {\n return issues\n }\n if (!model.pagination || !model.pagination.kind) {\n issues.push({\n code: createCode('API', 'MISSING_PAGINATION'),\n message: 'The API must have a defined pagination strategy when it exposes List or Search actions.',\n suggestion: 'Configure how results are loaded (e.g. by page or by a continuous cursor).',\n severity: 'error',\n context: { ...context, property: 'pagination' },\n })\n } else {\n if (model.pagination.defaultLimit === undefined) {\n issues.push({\n code: createCode('API', 'MISSING_PAGINATION_DEFAULT_LIMIT'),\n message: \"The API doesn't have a defined default page limit when it exposes List or Search actions.\",\n suggestion: 'Set a default page limit for the pagination otherwise the API will use its default limit.',\n severity: 'info',\n context: { ...context, property: 'pagination.defaultLimit' },\n })\n }\n if (model.pagination.maxLimit === undefined) {\n issues.push({\n code: createCode('API', 'MISSING_PAGINATION_MAX_LIMIT'),\n message: \"The API doesn't have a defined page size max limit when it exposes List or Search actions.\",\n suggestion: 'Set a max page size limit for the pagination otherwise the API will use its default max limit.',\n severity: 'info',\n context: { ...context, property: 'pagination.maxLimit' },\n })\n }\n }\n return issues\n}\n\nexport function validateAction(action: Action, parent: ExposedEntity, apiModelKey: string): ApiModelValidationItem[] {\n const issues: ApiModelValidationItem[] = []\n const context: ApiModelValidationContext = {\n apiModelKey,\n kind: 'Action',\n key: action.kind, // Actions lack nanoids, kind represents its type\n parentExposedEntityKey: parent.key,\n }\n\n if (DeleteAction.isDeleteAction(action)) {\n if (!action.strategy) {\n issues.push({\n code: createCode('ACTION', 'DELETE_MISSING_STRATEGY'),\n message: 'A Delete action must know if you want to completely erase the record, or just hide it.',\n suggestion: 'Configure the deletion type (permanent or soft).',\n severity: 'error',\n context: { ...context, property: 'strategy' },\n })\n } else if (action.strategy === 'hard') {\n issues.push({\n code: createCode('ACTION', 'DELETE_HARD_WARNING'),\n message: 'Permanent delete is active. There will be no way to restore deleted data.',\n suggestion: 'Consider switching to \"soft delete\" if users might need to undo mistakes.',\n severity: 'info',\n context: { ...context, property: 'strategy' },\n })\n }\n }\n\n if (UpdateAction.isUpdateAction(action)) {\n if (!action.allowedMethods || action.allowedMethods.length === 0) {\n issues.push({\n code: createCode('ACTION', 'UPDATE_MISSING_METHODS'),\n message:\n 'An Update action must define how the data is sent (PUT replaces everything; PATCH applies partial changes).',\n suggestion: 'Select at least one allowed HTTP method.',\n severity: 'error',\n context: { ...context, property: 'allowedMethods' },\n })\n }\n }\n\n const allRateLimiters = action.getAllRateLimiters()\n const oneHasRules = allRateLimiters.some((i) => i.rules.length)\n if (!oneHasRules) {\n issues.push({\n code: createCode('ACTION', 'MISSING_RATE_LIMITS'),\n message: 'It is best practice to configure a rate limit so your API is not overwhelmed.',\n suggestion: 'Set a reasonable maximum request speed for this operation.',\n severity: 'warning',\n context,\n })\n }\n\n return issues\n}\n\nexport function validateExposedEntity(exposure: ExposedEntity, apiModel: ApiModel): ApiModelValidationItem[] {\n const issues: ApiModelValidationItem[] = []\n const context: ApiModelValidationContext = {\n apiModelKey: apiModel.key,\n kind: ExposedEntityKind,\n key: exposure.key,\n }\n\n const entity = exposure.entity ? apiModel.domain?.findEntity(exposure.entity.key, exposure.entity.domain) : undefined\n const entityName = entity?.info.getLabel() || entity?.key || 'unknown'\n\n // Valid Entity Reference\n if (!exposure.entity || !exposure.entity.key) {\n issues.push({\n code: createCode('EXPOSURE', 'MISSING_ENTITY_REF'),\n message: 'This exposed endpoint does not point to a specific data model.',\n suggestion: 'Select which database entity this endpoint should serve.',\n severity: 'error',\n context: { ...context, property: 'entity' },\n })\n } else if (!entity) {\n issues.push({\n code: createCode('EXPOSURE', 'INVALID_ENTITY_REF'),\n message: 'This endpoint points to a data model that no longer exists.',\n suggestion: 'Select a new valid database model or delete this endpoint.',\n severity: 'error',\n context: { ...context, property: 'entity' },\n })\n }\n\n // Path Integrity\n if (exposure.hasCollection) {\n if (!exposure.collectionPath) {\n issues.push({\n code: createCode('EXPOSURE', 'MISSING_COLLECTION_PATH'),\n message: `[${entityName}]: When an endpoint exposes a collection, it must define what its base URL path is.`,\n suggestion: 'Add a path (e.g., \"/items\").',\n severity: 'error',\n context: { ...context, property: 'collectionPath' },\n })\n } else {\n const parts = exposure.collectionPath.split('/').filter(Boolean)\n if (parts.length !== 1 || !exposure.collectionPath.startsWith('/')) {\n issues.push({\n code: createCode('EXPOSURE', 'INVALID_COLLECTION_PATH'),\n message: `[${entityName}]: The collection URL should start with \"/\" and have no extra slashes.`,\n suggestion: `Ensure the path looks like exactly \"/${parts[0] || 'subresource'}\".`,\n severity: 'error',\n context: { ...context, property: 'collectionPath' },\n })\n }\n }\n\n if (!exposure.resourcePath) {\n issues.push({\n code: createCode('EXPOSURE', 'MISSING_RESOURCE_PATH'),\n message: `[${entityName}]: You need an identifier to locate single items.`,\n suggestion: 'Specify the identification parameter format, like \"{id}\".',\n severity: 'error',\n context: { ...context, property: 'resourcePath' },\n })\n } else if (exposure.collectionPath) {\n const colRegex = new RegExp(`^${exposure.collectionPath}/\\\\{[a-zA-Z0-9_]+\\\\}$`)\n if (!colRegex.test(exposure.resourcePath)) {\n issues.push({\n code: createCode('EXPOSURE', 'INVALID_RESOURCE_PATH_FORMAT'),\n message: `[${entityName}]: The single item route should match exactly your collection path plus one identifier variable.`,\n suggestion: `Make sure the item path is formatted exactly like \"${exposure.collectionPath}/{id}\".`,\n severity: 'error',\n context: { ...context, property: 'resourcePath' },\n })\n }\n }\n } else {\n if (!exposure.resourcePath) {\n issues.push({\n code: createCode('EXPOSURE', 'MISSING_RESOURCE_PATH'),\n message: `[${entityName}]: Exposed entity representing a single item must declare their URL route.`,\n suggestion: 'Set the URL path (such as \"/profile\").',\n severity: 'error',\n context: { ...context, property: 'resourcePath' },\n })\n } else {\n const parts = exposure.resourcePath.split('/').filter(Boolean)\n if (parts.length !== 1 || !exposure.resourcePath.startsWith('/')) {\n issues.push({\n code: createCode('EXPOSURE', 'INVALID_RESOURCE_PATH_FORMAT'),\n message: `[${entityName}]: The URL route ${exposure.resourcePath} must only contain one exact part or level.`,\n suggestion: 'Simplify the endpoint URL to a single segment.',\n severity: 'error',\n context: { ...context, property: 'resourcePath' },\n })\n }\n }\n }\n\n // Path Collisions\n if (exposure.isRoot) {\n if (exposure.collectionPath) {\n const collectionCollision = apiModel.findCollectionPathCollision(exposure.collectionPath, exposure.key)\n if (collectionCollision) {\n issues.push({\n code: createCode('EXPOSURE', 'ROOT_COLLECTION_COLLISION'),\n message: `[${entityName}]: The route \"${exposure.collectionPath}\" is already used by another view.`,\n suggestion: 'Give this resource a different path to avoid conflicts.',\n severity: 'error',\n context: { ...context, property: 'collectionPath' },\n })\n }\n }\n\n if (exposure.resourcePath) {\n const resourceCollision = apiModel.findResourcePathCollision(exposure.resourcePath, exposure.key)\n if (resourceCollision) {\n issues.push({\n code: createCode('EXPOSURE', 'ROOT_RESOURCE_COLLISION'),\n message: `[${entityName}]: The route \"${exposure.resourcePath}\" is already used by another one.`,\n suggestion: 'Give this single-item resource a different path to avoid conflicts.',\n severity: 'error',\n context: { ...context, property: 'resourcePath' },\n })\n }\n }\n }\n\n // Minimum Actions\n if (!exposure.actions || exposure.actions.length === 0) {\n issues.push({\n code: createCode('EXPOSURE', 'MISSING_ACTIONS'),\n message: `[${entityName}]: This exposed entity does not let users do anything.`,\n suggestion: 'Enable at least one operation like Create, Read, or Update.',\n severity: 'error',\n context: { ...context, property: 'actions' },\n })\n } else {\n let hasSearch = false\n let hasList = false\n for (const action of exposure.actions) {\n issues.push(...validateAction(action, exposure, apiModel.key))\n\n if (SearchAction.isSearchAction(action)) hasSearch = true\n if (ListAction.isListAction(action)) hasList = true\n\n // Check inheritance of access rules\n // For a rule to exist, it might be on the action, the exposure, any parent, or the apiModel.\n let hasAuth = false\n if (action.accessRule && action.accessRule.length > 0) hasAuth = true\n if (!hasAuth && exposure.accessRule && exposure.accessRule.length > 0) hasAuth = true\n\n let curr = exposure.parent?.key\n while (curr && !hasAuth) {\n const p = apiModel.exposes.get(curr)\n if (p && p.accessRule && p.accessRule.length > 0) {\n hasAuth = true\n break\n }\n curr = p?.parent?.key\n }\n\n if (!hasAuth && apiModel.accessRule && apiModel.accessRule.length > 0) hasAuth = true\n\n if (!hasAuth) {\n issues.push({\n code: createCode('ACTION', 'MISSING_ACCESS_RULES'),\n message: `[${entityName}]: The ${action.kind} action has no security rules attached, making it entirely inaccessible or open.`,\n suggestion: 'Allow specific user roles to access this operation.',\n severity: 'error',\n // using action.kind as the key context equivalent\n context: { ...context, kind: 'Action', key: action.kind, parentExposedEntityKey: exposure.key },\n })\n }\n }\n\n if (hasList || hasSearch) {\n const contract = exposure.paginationContract\n if (!contract) {\n issues.push({\n code: createCode('EXPOSURE', 'MISSING_PAGINATION_CONTRACT'),\n message: `[${entityName}]: The List or Search action needs a pagination contract.`,\n suggestion: 'Add a pagination contract to the exposed entity.',\n severity: 'error',\n context,\n })\n } else {\n if (hasList) {\n if (!contract.filterableFields || contract.filterableFields.length === 0) {\n issues.push({\n code: createCode('EXPOSURE', 'LIST_MISSING_FILTERS'),\n message: `[${entityName}]: Listing all elements without filters could be overwhelming for large tables.`,\n suggestion: 'Select a few important fields to allow filtering.',\n severity: 'warning',\n context,\n })\n }\n if (!contract.sortableFields || contract.sortableFields.length === 0) {\n issues.push({\n code: createCode('EXPOSURE', 'LIST_MISSING_SORTING'),\n message: `[${entityName}]: Listing all elements without sorting could be overwhelming for large tables.`,\n suggestion: 'Select a few important fields to allow sorting.',\n severity: 'warning',\n context,\n })\n }\n }\n if (hasSearch) {\n // Search and technically be used for filtering.\n const all: string[] = []\n if (Array.isArray(contract.searchableFields)) {\n all.push(...contract.searchableFields)\n }\n if (Array.isArray(contract.filterableFields)) {\n all.push(...contract.filterableFields)\n }\n if (!all.length) {\n issues.push({\n code: createCode('EXPOSURE', 'SEARCH_MISSING_FIELDS'),\n message: `[${entityName}]: Search action needs to know which text fields to look in.`,\n suggestion: 'Select a few important fields to allow searching or full-text search.',\n severity: 'warning',\n context,\n })\n }\n }\n }\n }\n }\n\n return issues\n}\n"]}
1
+ {"version":3,"file":"api_model_rules.js","sourceRoot":"","sources":["../../../../src/modeling/validation/api_model_rules.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ApiModel } from '../ApiModel.js'\nimport type { ExposedEntity } from '../ExposedEntity.js'\nimport type { Action } from '../actions/Action.js'\nimport { ListAction } from '../actions/ListAction.js'\nimport { DeleteAction } from '../actions/DeleteAction.js'\nimport { UpdateAction } from '../actions/UpdateAction.js'\nimport { SearchAction } from '../actions/SearchAction.js'\nimport type { ApiModelValidationItem, ApiModelValidationContext } from '../types.js'\nimport { ApiModelKind, ExposedEntityKind } from '../../models/kinds.js'\nimport { SemanticType } from '../Semantics.js'\nimport { DomainProperty } from '../DomainProperty.js'\n\n/**\n * Creates a unique validation code.\n * @param entity The entity type (e.g., 'API', 'EXPOSURE', 'ACTION')\n * @param issue The issue identifier (e.g., 'MISSING_NAME')\n */\nfunction createCode(entity: string, issue: string): string {\n return `${entity}_${issue}`\n}\n\n/**\n * Validates the core properties and metadata of an ApiModel.\n */\nexport function validateApiModelInfo(model: ApiModel): ApiModelValidationItem[] {\n const issues: ApiModelValidationItem[] = []\n const context: ApiModelValidationContext = {\n apiModelKey: model.key,\n kind: ApiModelKind,\n key: model.key,\n }\n\n if (model.kind !== ApiModelKind) {\n issues.push({\n code: createCode('API', 'INVALID_KIND'),\n message: 'The API model type is incorrect.',\n suggestion: 'Set the model type to \"ApiModel\".',\n severity: 'error',\n context: { ...context, property: 'kind' },\n })\n }\n\n if (!model.key || typeof model.key !== 'string' || model.key.trim() === '') {\n issues.push({\n code: createCode('API', 'MISSING_KEY'),\n message: 'The API model is missing a unique identifier.',\n suggestion: 'Provide a valid name to use as a unique identifier.',\n severity: 'error',\n context: { ...context, property: 'key' },\n })\n }\n\n if (!model.info || !model.info.name || model.info.name.trim() === '') {\n issues.push({\n code: createCode('API', 'MISSING_NAME'),\n message: 'The API model has no defined name.',\n suggestion: 'Provide a descriptive name for your API.',\n severity: 'error',\n context: { ...context, property: 'info.name' },\n })\n }\n\n if (!model.info || !model.info.description || model.info.description.trim() === '') {\n issues.push({\n code: createCode('API', 'MISSING_DESCRIPTION'),\n message: 'Adding a description helps others understand your API.',\n suggestion: 'Add a description to clarify the purpose of this API.',\n severity: 'warning',\n context: { ...context, property: 'info.description' },\n })\n }\n\n return issues\n}\n\nexport function validateApiModelDependency(model: ApiModel): ApiModelValidationItem[] {\n const issues: ApiModelValidationItem[] = []\n const context: ApiModelValidationContext = {\n apiModelKey: model.key,\n kind: ApiModelKind,\n key: model.key,\n }\n\n const domain = model.domain\n if (!domain) {\n issues.push({\n code: createCode('API', 'MISSING_DOMAIN'),\n message: 'No Data Domain is attached to the API.',\n suggestion: 'Select a Data Domain from the settings to power your API.',\n severity: 'error',\n context,\n })\n return issues // Can't validate version if it doesn't exist\n }\n\n if (!domain.info || !domain.info.version) {\n issues.push({\n code: createCode('API', 'MISSING_DOMAIN_VERSION'),\n message: 'The selected Data Domain is missing a version number.',\n suggestion: 'Specify a version for the attached Data Domain.',\n severity: 'error',\n context,\n })\n }\n\n return issues\n}\n\nexport function validateApiModelSecurity(model: ApiModel): ApiModelValidationItem[] {\n const issues: ApiModelValidationItem[] = []\n const context: ApiModelValidationContext = {\n apiModelKey: model.key,\n kind: ApiModelKind,\n key: model.key,\n }\n\n // Resolve User target\n const userEntity = model.domain && model.user ? model.domain.findEntity(model.user.key, model.user.domain) : undefined\n\n // Authentication\n if (!model.authentication) {\n issues.push({\n code: createCode('API', 'MISSING_AUTHENTICATION'),\n message: 'The API is missing authentication settings.',\n suggestion: 'Go to the security settings and configure how users authenticate.',\n severity: 'error',\n context: { ...context, property: 'authentication' },\n })\n } else if (model.authentication.strategy === 'UsernamePassword') {\n if (userEntity) {\n let passwordProp: DomainProperty | undefined\n for (const prop of userEntity.properties) {\n if (prop.hasSemantic(SemanticType.Password)) {\n passwordProp = prop\n break\n }\n }\n if (!passwordProp) {\n issues.push({\n code: createCode('API', 'MISSING_PASSWORD_SEMANTIC'),\n message: 'The selected user model requires a property with the Password data semantic for authentication.',\n suggestion: 'Go to the Data Modeler and add the \"Password\" semantic to the password property.',\n severity: 'error',\n context: { ...context, property: 'user' },\n })\n }\n\n let usernameProp: DomainProperty | undefined\n for (const prop of userEntity.properties) {\n if (prop.hasSemantic(SemanticType.Username)) {\n usernameProp = prop\n break\n }\n }\n if (!usernameProp) {\n issues.push({\n code: createCode('API', 'MISSING_USERNAME_SEMANTIC'),\n message: 'Username & Password authentication requires a field with the Username data semantic.',\n suggestion: 'Go to the Data Modeler and add the \"Username\" semantic to the property used for login.',\n severity: 'error',\n context: { ...context, property: 'user' },\n })\n }\n }\n }\n\n // Authorization\n if (!model.authorization) {\n issues.push({\n code: createCode('API', 'MISSING_AUTHORIZATION'),\n message: 'The API is missing authorization settings.',\n suggestion: 'Go to the security settings and configure how to handle user permissions.',\n severity: 'error',\n context: { ...context, property: 'authorization' },\n })\n } else if (model.authorization.strategy === 'RBAC') {\n if (userEntity) {\n let roleProp: DomainProperty | undefined\n for (const prop of userEntity.properties) {\n if (prop.hasSemantic(SemanticType.UserRole)) {\n roleProp = prop\n break\n }\n }\n if (!roleProp) {\n issues.push({\n code: createCode('API', 'MISSING_ROLE_SEMANTIC'),\n message: 'Role-based access control requires a property with the User Role data semantic on the user model.',\n suggestion: 'Go to the Data Modeler and add the \"User Role\" semantic to the property used for roles.',\n severity: 'error',\n context: { ...context, property: 'user' },\n })\n }\n }\n }\n\n // Session\n if (!model.session) {\n issues.push({\n code: createCode('API', 'MISSING_SESSION'),\n message: 'The API is missing session configuration.',\n suggestion: 'Configure how user sessions will be handled.',\n severity: 'error',\n context: { ...context, property: 'session' },\n })\n } else {\n if (!model.session.secret) {\n issues.push({\n code: createCode('API', 'MISSING_SESSION_SECRET'),\n message: 'A secure encryption key is required for sessions.',\n suggestion: 'Provide a strong security key in the session settings.',\n severity: 'error',\n context: { ...context, property: 'session.secret' },\n })\n }\n\n if (!model.session.properties || model.session.properties.length === 0) {\n issues.push({\n code: createCode('API', 'MISSING_SESSION_PROPERTIES'),\n message: 'The session token needs to include at least one piece of user information, like an ID.',\n suggestion: 'Select fields that should be stored securely inside the session payload.',\n severity: 'error',\n context: { ...context, property: 'session.properties' },\n })\n } else if (model.authorization && model.authorization.strategy === 'RBAC') {\n if (userEntity) {\n let roleProp: DomainProperty | undefined\n for (const prop of userEntity.properties) {\n if (prop.hasSemantic(SemanticType.UserRole)) {\n roleProp = prop\n break\n }\n }\n if (roleProp && !model.session.properties.find((p) => p.key === roleProp?.key)) {\n issues.push({\n code: createCode('API', 'MISSING_RBAC_SESSION_PROPERTY'),\n message: 'The user role must be included in the session data for permissions to work.',\n suggestion: 'Make sure your selected role property is checked in the session settings.',\n severity: 'error',\n context: { ...context, property: 'session.properties' },\n })\n }\n }\n }\n\n const { cookie, jwt } = model.session\n if ((!cookie || !cookie.enabled) && (!jwt || !jwt.enabled)) {\n issues.push({\n code: createCode('API', 'MISSING_SESSION_TRANSPORT'),\n message: 'No delivery method for sessions (like cookies or tokens) is enabled.',\n suggestion: 'Enable at least one session delivery mechanism in the security settings.',\n severity: 'error',\n context: { ...context, property: 'session' },\n })\n }\n }\n\n // User Target\n if (!model.user) {\n issues.push({\n code: createCode('API', 'MISSING_USER_ENTITY'),\n message: 'You need to specify what kind of object represents your users.',\n suggestion: 'Select a model from your domain that stores your user accounts.',\n severity: 'error',\n context: { ...context, property: 'user' },\n })\n } else if (model.domain && !model.domain.findEntity(model.user.key, model.user.domain)) {\n issues.push({\n code: createCode('API', 'INVALID_USER_ENTITY'),\n message: 'The selected user model no longer exists in your data domain.',\n suggestion: 'Please navigate to security settings and select a valid user model.',\n severity: 'error',\n context: { ...context, property: 'user' },\n })\n }\n\n return issues\n}\n\nexport function validateApiModelMetadata(model: ApiModel): ApiModelValidationItem[] {\n const issues: ApiModelValidationItem[] = []\n const context: ApiModelValidationContext = {\n apiModelKey: model.key,\n kind: ApiModelKind,\n key: model.key,\n }\n\n const urlRegex = /^https?:\\/\\//i\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/\n\n if (model.contact) {\n if (model.contact.email && !emailRegex.test(model.contact.email)) {\n issues.push({\n code: createCode('API', 'INVALID_CONTACT_EMAIL'),\n message: 'The contact email address looks invalid.',\n suggestion: 'Please double check the email address formatting.',\n severity: 'error',\n context: { ...context, property: 'contact.email' },\n })\n }\n if (model.contact.url && !urlRegex.test(model.contact.url)) {\n issues.push({\n code: createCode('API', 'INVALID_CONTACT_URL'),\n message: 'The contact link looks invalid.',\n suggestion: 'Provide a working link, starting with http:// or https://.',\n severity: 'error',\n context: { ...context, property: 'contact.url' },\n })\n }\n } else {\n issues.push({\n code: createCode('API', 'MISSING_CONTACT'),\n message: 'A contact email or link is highly recommended for API consumers.',\n suggestion: 'Add an email or help desk link in the metadata tab.',\n severity: 'info',\n context: { ...context, property: 'contact' },\n })\n }\n\n if (model.license) {\n if (model.license.url && !urlRegex.test(model.license.url)) {\n issues.push({\n code: createCode('API', 'INVALID_LICENSE_URL'),\n message: 'The license link looks invalid.',\n suggestion: 'Provide a working link, starting with http:// or https://.',\n severity: 'error',\n context: { ...context, property: 'license.url' },\n })\n }\n } else {\n issues.push({\n code: createCode('API', 'MISSING_LICENSE'),\n message: 'Adding a license to your API helps users understand its usage rights.',\n suggestion: 'Add the name and a link to your API license terms.',\n severity: 'info',\n context: { ...context, property: 'license' },\n })\n }\n\n if (!model.termsOfService) {\n issues.push({\n code: createCode('API', 'MISSING_TOS'),\n message: 'Terms of Service help legal compliance.',\n suggestion: 'Add a link to the terms of your API service.',\n severity: 'info',\n context: { ...context, property: 'termsOfService' },\n })\n }\n\n return issues\n}\n\nexport function validateApiPagination(model: ApiModel): ApiModelValidationItem[] {\n const issues: ApiModelValidationItem[] = []\n const context: ApiModelValidationContext = {\n apiModelKey: model.key,\n kind: ApiModelKind,\n key: model.key,\n }\n // We only need pagination when the API contains at least one List or Search action\n let validate = false\n for (const exposure of model.exposes.values()) {\n if (exposure.actions.some((action) => ListAction.isListAction(action) || SearchAction.isSearchAction(action))) {\n validate = true\n break\n }\n }\n if (!validate) {\n return issues\n }\n if (!model.pagination || !model.pagination.kind) {\n issues.push({\n code: createCode('API', 'MISSING_PAGINATION'),\n message: 'The API must have a defined pagination strategy when it exposes List or Search actions.',\n suggestion: 'Configure how results are loaded (e.g. by page or by a continuous cursor).',\n severity: 'error',\n context: { ...context, property: 'pagination' },\n })\n } else {\n if (model.pagination.defaultLimit === undefined) {\n issues.push({\n code: createCode('API', 'MISSING_PAGINATION_DEFAULT_LIMIT'),\n message: \"The API doesn't have a defined default page limit when it exposes List or Search actions.\",\n suggestion: 'Set a default page limit for the pagination otherwise the API will use its default limit.',\n severity: 'info',\n context: { ...context, property: 'pagination.defaultLimit' },\n })\n }\n if (model.pagination.maxLimit === undefined) {\n issues.push({\n code: createCode('API', 'MISSING_PAGINATION_MAX_LIMIT'),\n message: \"The API doesn't have a defined page size max limit when it exposes List or Search actions.\",\n suggestion: 'Set a max page size limit for the pagination otherwise the API will use its default max limit.',\n severity: 'info',\n context: { ...context, property: 'pagination.maxLimit' },\n })\n }\n }\n return issues\n}\n\nexport function validateAction(action: Action, parent: ExposedEntity, apiModelKey: string): ApiModelValidationItem[] {\n const issues: ApiModelValidationItem[] = []\n const context: ApiModelValidationContext = {\n apiModelKey,\n kind: 'Action',\n key: action.kind, // Actions lack nanoids, kind represents its type\n parentExposedEntityKey: parent.key,\n }\n\n if (DeleteAction.isDeleteAction(action)) {\n if (!action.strategy) {\n issues.push({\n code: createCode('ACTION', 'DELETE_MISSING_STRATEGY'),\n message: 'A Delete action must know if you want to completely erase the record, or just hide it.',\n suggestion: 'Configure the deletion type (permanent or soft).',\n severity: 'error',\n context: { ...context, property: 'strategy' },\n })\n } else if (action.strategy === 'hard') {\n issues.push({\n code: createCode('ACTION', 'DELETE_HARD_WARNING'),\n message: 'Permanent delete is active. There will be no way to restore deleted data.',\n suggestion: 'Consider switching to \"soft delete\" if users might need to undo mistakes.',\n severity: 'info',\n context: { ...context, property: 'strategy' },\n })\n }\n }\n\n if (UpdateAction.isUpdateAction(action)) {\n if (!action.allowedMethods || action.allowedMethods.length === 0) {\n issues.push({\n code: createCode('ACTION', 'UPDATE_MISSING_METHODS'),\n message:\n 'An Update action must define how the data is sent (PUT replaces everything; PATCH applies partial changes).',\n suggestion: 'Select at least one allowed HTTP method.',\n severity: 'error',\n context: { ...context, property: 'allowedMethods' },\n })\n }\n }\n\n const allRateLimiters = action.getAllRateLimiters()\n const oneHasRules = allRateLimiters.some((i) => i.rules.length)\n if (!oneHasRules) {\n issues.push({\n code: createCode('ACTION', 'MISSING_RATE_LIMITS'),\n message: 'It is best practice to configure a rate limit so your API is not overwhelmed.',\n suggestion: 'Set a reasonable maximum request speed for this operation.',\n severity: 'warning',\n context,\n })\n }\n\n return issues\n}\n\nexport function validateExposedEntity(exposure: ExposedEntity, apiModel: ApiModel): ApiModelValidationItem[] {\n const issues: ApiModelValidationItem[] = []\n const context: ApiModelValidationContext = {\n apiModelKey: apiModel.key,\n kind: ExposedEntityKind,\n key: exposure.key,\n }\n\n const entity = exposure.entity ? apiModel.domain?.findEntity(exposure.entity.key, exposure.entity.domain) : undefined\n const entityName = entity?.info.getLabel() || entity?.key || 'unknown'\n\n // Valid Entity Reference\n if (!exposure.entity || !exposure.entity.key) {\n issues.push({\n code: createCode('EXPOSURE', 'MISSING_ENTITY_REF'),\n message: 'This exposed endpoint does not point to a specific data model.',\n suggestion: 'Select which database entity this endpoint should serve.',\n severity: 'error',\n context: { ...context, property: 'entity' },\n })\n } else if (!entity) {\n issues.push({\n code: createCode('EXPOSURE', 'INVALID_ENTITY_REF'),\n message: 'This endpoint points to a data model that no longer exists.',\n suggestion: 'Select a new valid database model or delete this endpoint.',\n severity: 'error',\n context: { ...context, property: 'entity' },\n })\n }\n\n // Path Integrity\n if (exposure.hasCollection) {\n if (!exposure.collectionPath) {\n issues.push({\n code: createCode('EXPOSURE', 'MISSING_COLLECTION_PATH'),\n message: `[${entityName}]: When an endpoint exposes a collection, it must define what its base URL path is.`,\n suggestion: 'Add a path (e.g., \"/items\").',\n severity: 'error',\n context: { ...context, property: 'collectionPath' },\n })\n } else {\n const parts = exposure.collectionPath.split('/').filter(Boolean)\n if (parts.length !== 1 || !exposure.collectionPath.startsWith('/')) {\n issues.push({\n code: createCode('EXPOSURE', 'INVALID_COLLECTION_PATH'),\n message: `[${entityName}]: The collection URL should start with \"/\" and have no extra slashes.`,\n suggestion: `Ensure the path looks like exactly \"/${parts[0] || 'subresource'}\".`,\n severity: 'error',\n context: { ...context, property: 'collectionPath' },\n })\n }\n }\n\n if (!exposure.resourcePath) {\n issues.push({\n code: createCode('EXPOSURE', 'MISSING_RESOURCE_PATH'),\n message: `[${entityName}]: You need an identifier to locate single items.`,\n suggestion: 'Specify the identification parameter format, like \"{id}\".',\n severity: 'error',\n context: { ...context, property: 'resourcePath' },\n })\n } else if (exposure.collectionPath) {\n const colRegex = new RegExp(`^${exposure.collectionPath}/\\\\{[a-zA-Z0-9_]+\\\\}$`)\n if (!colRegex.test(exposure.resourcePath)) {\n issues.push({\n code: createCode('EXPOSURE', 'INVALID_RESOURCE_PATH_FORMAT'),\n message: `[${entityName}]: The single item route should match exactly your collection path plus one identifier variable.`,\n suggestion: `Make sure the item path is formatted exactly like \"${exposure.collectionPath}/{id}\".`,\n severity: 'error',\n context: { ...context, property: 'resourcePath' },\n })\n }\n }\n } else {\n if (!exposure.resourcePath) {\n issues.push({\n code: createCode('EXPOSURE', 'MISSING_RESOURCE_PATH'),\n message: `[${entityName}]: Exposed entity representing a single item must declare their URL route.`,\n suggestion: 'Set the URL path (such as \"/profile\").',\n severity: 'error',\n context: { ...context, property: 'resourcePath' },\n })\n } else {\n const parts = exposure.resourcePath.split('/').filter(Boolean)\n if (parts.length !== 1 || !exposure.resourcePath.startsWith('/')) {\n issues.push({\n code: createCode('EXPOSURE', 'INVALID_RESOURCE_PATH_FORMAT'),\n message: `[${entityName}]: The URL route ${exposure.resourcePath} must only contain one exact part or level.`,\n suggestion: 'Simplify the endpoint URL to a single segment.',\n severity: 'error',\n context: { ...context, property: 'resourcePath' },\n })\n }\n }\n }\n\n // Path Collisions\n if (exposure.isRoot) {\n if (exposure.collectionPath) {\n const collectionCollision = apiModel.findCollectionPathCollision(exposure.collectionPath, exposure.key)\n if (collectionCollision) {\n issues.push({\n code: createCode('EXPOSURE', 'ROOT_COLLECTION_COLLISION'),\n message: `[${entityName}]: The route \"${exposure.collectionPath}\" is already used by another view.`,\n suggestion: 'Give this resource a different path to avoid conflicts.',\n severity: 'error',\n context: { ...context, property: 'collectionPath' },\n })\n }\n }\n\n if (exposure.resourcePath) {\n const resourceCollision = apiModel.findResourcePathCollision(exposure.resourcePath, exposure.key)\n if (resourceCollision) {\n issues.push({\n code: createCode('EXPOSURE', 'ROOT_RESOURCE_COLLISION'),\n message: `[${entityName}]: The route \"${exposure.resourcePath}\" is already used by another one.`,\n suggestion: 'Give this single-item resource a different path to avoid conflicts.',\n severity: 'error',\n context: { ...context, property: 'resourcePath' },\n })\n }\n }\n }\n\n // Branch Path Parameter Collision\n const absoluteResourcePath = exposure.getAbsoluteResourcePath()\n if (absoluteResourcePath) {\n const params = [...absoluteResourcePath.matchAll(/\\{([^}]+)\\}/g)].map((m) => m[1])\n const uniqueParams = new Set(params)\n if (uniqueParams.size !== params.length) {\n const duplicates = params.filter((item, index) => params.indexOf(item) !== index)\n const duplicateParam = duplicates[0]\n issues.push({\n code: createCode('EXPOSURE', 'DUPLICATE_PATH_PARAMETER'),\n message: `[${entityName}]: The path parameter \"{${duplicateParam}}\" is duplicated in the resource path hierarchy.`,\n suggestion:\n 'Change the parameter name in either this resource or its ancestor to ensure unique parameter names.',\n severity: 'error',\n context: { ...context, property: 'resourcePath' },\n })\n }\n }\n\n // Minimum Actions\n if (!exposure.actions || exposure.actions.length === 0) {\n issues.push({\n code: createCode('EXPOSURE', 'MISSING_ACTIONS'),\n message: `[${entityName}]: This exposed entity does not let users do anything.`,\n suggestion: 'Enable at least one operation like Create, Read, or Update.',\n severity: 'error',\n context: { ...context, property: 'actions' },\n })\n } else {\n let hasSearch = false\n let hasList = false\n for (const action of exposure.actions) {\n issues.push(...validateAction(action, exposure, apiModel.key))\n\n if (SearchAction.isSearchAction(action)) hasSearch = true\n if (ListAction.isListAction(action)) hasList = true\n\n // Check inheritance of access rules\n // For a rule to exist, it might be on the action, the exposure, any parent, or the apiModel.\n let hasAuth = false\n if (action.accessRule && action.accessRule.length > 0) hasAuth = true\n if (!hasAuth && exposure.accessRule && exposure.accessRule.length > 0) hasAuth = true\n\n let curr = exposure.parent?.key\n while (curr && !hasAuth) {\n const p = apiModel.exposes.get(curr)\n if (p && p.accessRule && p.accessRule.length > 0) {\n hasAuth = true\n break\n }\n curr = p?.parent?.key\n }\n\n if (!hasAuth && apiModel.accessRule && apiModel.accessRule.length > 0) hasAuth = true\n\n if (!hasAuth) {\n issues.push({\n code: createCode('ACTION', 'MISSING_ACCESS_RULES'),\n message: `[${entityName}]: The ${action.kind} action has no security rules attached, making it entirely inaccessible or open.`,\n suggestion: 'Allow specific user roles to access this operation.',\n severity: 'error',\n // using action.kind as the key context equivalent\n context: { ...context, kind: 'Action', key: action.kind, parentExposedEntityKey: exposure.key },\n })\n }\n }\n\n if (hasList || hasSearch) {\n const contract = exposure.paginationContract\n if (!contract) {\n issues.push({\n code: createCode('EXPOSURE', 'MISSING_PAGINATION_CONTRACT'),\n message: `[${entityName}]: The List or Search action needs a pagination contract.`,\n suggestion: 'Add a pagination contract to the exposed entity.',\n severity: 'error',\n context,\n })\n } else {\n if (hasList) {\n if (!contract.filterableFields || contract.filterableFields.length === 0) {\n issues.push({\n code: createCode('EXPOSURE', 'LIST_MISSING_FILTERS'),\n message: `[${entityName}]: Listing all elements without filters could be overwhelming for large tables.`,\n suggestion: 'Select a few important fields to allow filtering.',\n severity: 'warning',\n context,\n })\n }\n if (!contract.sortableFields || contract.sortableFields.length === 0) {\n issues.push({\n code: createCode('EXPOSURE', 'LIST_MISSING_SORTING'),\n message: `[${entityName}]: Listing all elements without sorting could be overwhelming for large tables.`,\n suggestion: 'Select a few important fields to allow sorting.',\n severity: 'warning',\n context,\n })\n }\n }\n if (hasSearch) {\n // Search and technically be used for filtering.\n const all: string[] = []\n if (Array.isArray(contract.searchableFields)) {\n all.push(...contract.searchableFields)\n }\n if (Array.isArray(contract.filterableFields)) {\n all.push(...contract.filterableFields)\n }\n if (!all.length) {\n issues.push({\n code: createCode('EXPOSURE', 'SEARCH_MISSING_FIELDS'),\n message: `[${entityName}]: Search action needs to know which text fields to look in.`,\n suggestion: 'Select a few important fields to allow searching or full-text search.',\n severity: 'warning',\n context,\n })\n }\n }\n }\n }\n }\n\n return issues\n}\n"]}