@api-client/core 0.18.31 → 0.18.33
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.
- package/build/src/browser.d.ts +1 -0
- package/build/src/browser.d.ts.map +1 -1
- package/build/src/browser.js +1 -0
- package/build/src/browser.js.map +1 -1
- package/build/src/index.d.ts +1 -0
- package/build/src/index.d.ts.map +1 -1
- package/build/src/index.js +1 -0
- package/build/src/index.js.map +1 -1
- package/build/src/modeling/ApiModel.d.ts +4 -3
- package/build/src/modeling/ApiModel.d.ts.map +1 -1
- package/build/src/modeling/ApiModel.js +25 -22
- package/build/src/modeling/ApiModel.js.map +1 -1
- package/build/src/modeling/ExposedEntity.d.ts +124 -0
- package/build/src/modeling/ExposedEntity.d.ts.map +1 -0
- package/build/src/modeling/ExposedEntity.js +364 -0
- package/build/src/modeling/ExposedEntity.js.map +1 -0
- package/build/src/modeling/helpers/endpointHelpers.d.ts +11 -0
- package/build/src/modeling/helpers/endpointHelpers.d.ts.map +1 -1
- package/build/src/modeling/helpers/endpointHelpers.js +21 -0
- package/build/src/modeling/helpers/endpointHelpers.js.map +1 -1
- package/build/src/modeling/types.d.ts +12 -15
- package/build/src/modeling/types.d.ts.map +1 -1
- package/build/src/modeling/types.js.map +1 -1
- package/build/src/models/kinds.d.ts +1 -0
- package/build/src/models/kinds.d.ts.map +1 -1
- package/build/src/models/kinds.js +1 -0
- package/build/src/models/kinds.js.map +1 -1
- package/build/tsconfig.tsbuildinfo +1 -1
- package/data/models/example-generator-api.json +6 -6
- package/package.json +1 -1
- package/src/modeling/ApiModel.ts +22 -26
- package/src/modeling/ExposedEntity.ts +358 -0
- package/src/modeling/helpers/endpointHelpers.ts +22 -0
- package/src/modeling/types.ts +12 -16
- package/src/models/kinds.ts +1 -0
- package/tests/unit/modeling/api_model.spec.ts +49 -10
- package/tests/unit/modeling/api_model_expose_entity.spec.ts +2 -4
- package/tests/unit/modeling/api_model_remove_entity.spec.ts +1 -2
- package/tests/unit/modeling/exposed_entity.spec.ts +155 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ApiModel.js","sourceRoot":"","sources":["../../../src/modeling/ApiModel.ts"],"names":[],"mappings":"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","sourcesContent":["import { nanoid } from '../nanoid.js'\nimport { ApiModelKind, DataDomainKind } from '../models/kinds.js'\nimport { type IThing, Thing } from '../models/Thing.js'\nimport type {\n AccessRule,\n AssociationTarget,\n AuthenticationConfiguration,\n AuthorizationConfiguration,\n ExposedEntity,\n RateLimitingConfiguration,\n RolesBasedAccessControl,\n SessionConfiguration,\n UsernamePasswordConfiguration,\n ExposeOptions,\n} from './types.js'\nimport { DataDomain } from './DataDomain.js'\nimport { DependentModel, type DependentModelSchema, type DomainDependency } from './DependentModel.js'\nimport { observed, toRaw } from '../decorators/observed.js'\nimport pluralize from '@jarrodek/pluralize'\nimport { createDomainKey } from './helpers/keying.js'\n\n/**\n * Contact information for the exposed API.\n */\nexport interface ApiContact {\n /**\n * The identifying name of the contact person/organization.\n */\n name?: string\n /**\n * The URL pointing to the contact information. MUST be in the format of a URL.\n */\n url?: string\n /**\n * The email address of the contact person/organization. MUST be in the format of an email address.\n */\n email?: string\n}\n\n/**\n * License information for the exposed API.\n */\nexport interface ApiLicense {\n /**\n * The license name used for the API. It is recommended to be an SPDX license identifier.\n */\n name: string\n /**\n * A URL to the license used for the API. MUST be in the format of a URL.\n */\n url?: string\n}\n\nexport interface ApiModelSchema extends DependentModelSchema {\n /**\n * The data domain kind recognizable by the ecosystem.\n */\n kind: typeof ApiModelKind\n /**\n * The unique key of the API model schema.\n * This is a stable identifier that does not change across versions.\n */\n key: string\n /**\n * Contains the name, display name, description, and the version of the API model schema.\n */\n info: IThing\n\n /**\n * The designated Data Entity that represents a \"User\".\n * This entity should be marked with the \"User\" semantic in the Data Modeler.\n *\n * This property is required to publish the API.\n */\n user?: AssociationTarget\n\n /**\n * Configuration for how users prove their identity.\n * The API model is invalid if this is not set.\n */\n authentication?: AuthenticationConfiguration\n\n /**\n * Configuration for what authenticated users are allowed to do.\n * The API model is invalid if this is not set.\n */\n authorization?: AuthorizationConfiguration\n\n /**\n * Configuration for the transport and payload of the user session.\n * The API model is invalid if this is not set.\n */\n session?: SessionConfiguration\n /**\n * The specific subset of Data Entities to be exposed by this API.\n * These are the entities that are included in the data domain schema.\n */\n exposes: ExposedEntity[]\n\n /**\n * Optional array of access rules that define the access control policies\n * for the API. These rules are used to enforce security and permissions\n * on the exposed entities.\n *\n * These rules apply to all exposed entities and actions. An API action\n * can declare its own access rules, which will override these.\n */\n accessRule?: AccessRule[]\n /**\n * Optional configuration for API-wide rate limiting and throttling.\n * Defines rules to protect the API from overuse.\n */\n rateLimiting?: RateLimitingConfiguration\n /**\n * A URL to the Terms of Service for the API.\n */\n termsOfService?: string\n /**\n * The contact information for the exposed API.\n */\n contact?: ApiContact\n /**\n * The license information for the API.\n */\n license?: ApiLicense\n}\n\nexport class ApiModel extends DependentModel {\n /**\n * The data domain kind recognizable by the ecosystem.\n */\n kind: typeof ApiModelKind\n /**\n * The unique key of the data domain schema.\n * This is a stable identifier that does not change across versions.\n */\n key: string\n\n /**\n * The description of the domain property.\n */\n info: Thing\n /**\n * The designated Data Entity that represents a \"User\".\n * This entity must be marked with the \"User\" semantic in the Data Modeler.\n *\n * This property is required to publish the API.\n */\n user?: AssociationTarget\n\n /**\n * Configuration for how users prove their identity.\n * The API model is invalid if this is not set.\n */\n authentication?: AuthenticationConfiguration\n\n /**\n * Configuration for what authenticated users are allowed to do.\n * The API model is invalid if this is not set.\n */\n authorization?: AuthorizationConfiguration\n\n /**\n * Configuration for the transport and payload of the user session.\n * The API model is invalid if this is not set.\n */\n session?: SessionConfiguration\n /**\n * The specific subset of Data Entities to be exposed by this API.\n * These are the entities that are included in the data domain schema.\n */\n exposes: ExposedEntity[]\n /**\n * Optional array of access rules that define the access control policies\n * for the API. These rules are used to enforce security and permissions\n * on the exposed entities.\n *\n * These rules apply to all exposed entities and actions. An API action\n * can declare its own access rules, which will override these.\n */\n accessRule?: AccessRule[]\n /**\n * Optional configuration for API-wide rate limiting and throttling.\n * Defines rules to protect the API from overuse.\n */\n rateLimiting?: RateLimitingConfiguration\n /**\n * A URL to the Terms of Service for the API.\n */\n @observed() accessor termsOfService: string | undefined\n /**\n * The contact information for the exposed API.\n */\n @observed({ deep: true }) accessor contact: ApiContact | undefined\n /**\n * The license information for the API.\n */\n @observed({ deep: true }) accessor license: ApiLicense | undefined\n\n /**\n * When the initializing flag is set to true,\n * the domain is not notified of changes.\n */\n #initializing = true\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 /**\n * A convenience getter that returns the DataDomain associated with this API model.\n * Since the API model can have only one DataDomain,\n * this getter returns the first dependency in the list.\n *\n * The parent interface `DependentModel` allows for multiple dependencies,\n * to unify the dependency management across different models.\n */\n get domain(): DataDomain | undefined {\n if (this.dependencyList.length === 0) {\n return undefined\n }\n const domain = this.dependencyList[0]\n return this.dependencies.get(domain.key)\n }\n\n static createSchema(input: Partial<ApiModelSchema> = {}): ApiModelSchema {\n const { key = nanoid(), exposes = [] } = input\n const info = Thing.fromJSON(input.info, { name: 'Unnamed API' }).toJSON()\n const result: ApiModelSchema = {\n kind: ApiModelKind,\n key,\n info,\n exposes,\n }\n if (input.user) {\n result.user = { ...input.user }\n }\n if (input.dependencyList) {\n result.dependencyList = structuredClone(input.dependencyList)\n }\n if (input.authentication) {\n result.authentication = input.authentication\n }\n if (input.authorization) {\n result.authorization = input.authorization\n }\n if (input.session) {\n result.session = input.session\n }\n if (input.accessRule) {\n result.accessRule = input.accessRule\n }\n if (input.rateLimiting) {\n result.rateLimiting = input.rateLimiting\n }\n if (input.termsOfService) {\n result.termsOfService = input.termsOfService\n }\n if (input.contact) {\n result.contact = structuredClone(input.contact)\n }\n if (input.license) {\n result.license = structuredClone(input.license)\n }\n return result\n }\n\n constructor(state?: Partial<ApiModelSchema>, domain?: DomainDependency) {\n const init = ApiModel.createSchema(state)\n const instances: DataDomain[] = []\n if (domain instanceof DataDomain) {\n instances.push(domain)\n } else if (typeof domain === 'object' && domain.kind === DataDomainKind) {\n instances.push(new DataDomain(domain))\n } else if (domain) {\n throw new Error(`Invalid domain provided. Expected a DataDomain instance or schema.`)\n }\n super(init.dependencyList, instances)\n this.kind = init.kind\n this.key = init.key\n this.info = new Thing(init.info)\n this.user = init.user\n if (init.authentication) {\n this.authentication = structuredClone(init.authentication)\n }\n if (init.authorization) {\n this.authorization = structuredClone(init.authorization)\n }\n if (init.session) {\n this.session = structuredClone(init.session)\n }\n if (Array.isArray(init.exposes)) {\n this.exposes = structuredClone(init.exposes)\n } else {\n this.exposes = []\n }\n if (init.accessRule) {\n this.accessRule = structuredClone(init.accessRule)\n }\n if (init.rateLimiting) {\n this.rateLimiting = structuredClone(init.rateLimiting)\n }\n if (init.termsOfService) {\n this.termsOfService = init.termsOfService\n }\n if (init.contact) {\n this.contact = init.contact\n }\n if (init.license) {\n this.license = init.license\n }\n this.#initializing = false\n this.info.addEventListener('change', () => {\n this.notifyChange()\n })\n }\n\n toJSON(): ApiModelSchema {\n const result: ApiModelSchema = {\n kind: this.kind,\n key: this.key,\n info: this.info.toJSON(),\n exposes: structuredClone(this.exposes),\n }\n if (this.user) {\n result.user = { ...this.user }\n }\n if (this.dependencyList.length > 0) {\n result.dependencyList = structuredClone(this.dependencyList)\n }\n if (this.authentication) {\n result.authentication = structuredClone(this.authentication)\n }\n if (this.authorization) {\n result.authorization = structuredClone(this.authorization)\n }\n if (this.session) {\n result.session = structuredClone(this.session)\n }\n if (this.accessRule) {\n result.accessRule = structuredClone(this.accessRule)\n }\n if (this.rateLimiting) {\n result.rateLimiting = structuredClone(this.rateLimiting)\n }\n if (this.termsOfService) {\n result.termsOfService = this.termsOfService\n }\n if (this.contact) {\n result.contact = structuredClone(toRaw(this, this.contact))\n }\n if (this.license) {\n result.license = structuredClone(toRaw(this, this.license))\n }\n return result\n }\n\n /**\n * This function is used internally by all domain elements to notify that something has changed.\n * Since we want to notify listeners after the operation commits, we use microtask\n * to ensure that the event is dispatched after the current operation.\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 })\n }\n\n /**\n * Exposes a new entity in the API model.\n * If the entity already exists, it returns the existing one.\n * @param entity The entity key and domain to expose.\n * @returns The exposed entity.\n */\n exposeEntity(entity: AssociationTarget, options?: ExposeOptions): ExposedEntity {\n const domain = this.domain\n if (!domain) {\n throw new Error(`No domain attached to API model`)\n }\n // checks whether the entity is already exposed as a root exposure.\n const existing = this.exposes.find(\n (e) => e.isRoot && e.entity.key === entity.key && e.entity.domain === entity.domain\n )\n if (existing) {\n // quietly return the existing exposure\n // TBD: should we throw an error here?\n return existing\n }\n const domainEntity = domain.findEntity(entity.key, entity.domain)\n if (!domainEntity) {\n throw new Error(`Entity not found in domain: ${entity.key}`)\n }\n const name = domainEntity.info.name || ''\n const segment = pluralize(name.toLocaleLowerCase())\n const relativeCollectionPath = `/${segment}`\n const relativeResourcePath = `/${segment}/{id}`\n const absoluteCollectionPath = relativeCollectionPath\n const absoluteResourcePath = relativeResourcePath\n const newEntity: ExposedEntity = {\n key: nanoid(),\n entity: { ...entity },\n actions: [],\n isRoot: true,\n relativeCollectionPath,\n relativeResourcePath,\n absoluteCollectionPath,\n absoluteResourcePath,\n }\n if (options) {\n newEntity.exposeOptions = { ...options }\n }\n this.exposes.push(newEntity)\n\n // Follow associations if requested\n if (options?.followAssociations) {\n if (options?.maxDepth === undefined || options.maxDepth > 0) {\n this.followEntityAssociations(newEntity, options)\n }\n }\n this.notifyChange()\n return newEntity\n }\n\n /**\n * Follows associations for a newly exposed entity if configured to do so.\n * This creates nested exposures based on the entity's associations.\n *\n * @param parentExposure The root exposure to follow associations from\n * @param options The expose options containing follow configuration\n */\n private followEntityAssociations(parentExposure: ExposedEntity, options: ExposeOptions): void {\n const domain = this.domain\n if (!domain) {\n return\n }\n const maxDepth = options.maxDepth ?? 6\n const visited = new Set<string>()\n // Add parent entity's key to the visited set so we won't skip it when traversing\n // associations.\n visited.add(createDomainKey(parentExposure.entity))\n\n const follow = (currentEntity: AssociationTarget, parentKey: string, depth: number) => {\n // Find the domain entity\n const domainEntity = domain.findEntity(currentEntity.key, currentEntity.domain)\n if (!domainEntity) return\n\n // Iterate through associations\n for (const association of domainEntity.listAssociations()) {\n for (const target of association.targets) {\n // Skip self-referencing associations\n if (target.key === currentEntity.key && target.domain === currentEntity.domain) {\n continue\n }\n\n // Create unique identifier for circular detection\n const visitKey = createDomainKey(target)\n if (visited.has(visitKey)) {\n continue // Skip circular references\n }\n visited.add(visitKey)\n\n // Check if this nested exposure already exists\n const existingNested = this.exposes.find(\n (e) =>\n !e.isRoot &&\n e.entity.key === target.key &&\n e.entity.domain === target.domain &&\n e.parent?.key === parentKey\n )\n\n if (existingNested) {\n continue // Already exposed under this parent\n }\n\n // Find the target domain entity for path generation\n const targetDomainEntity = domain.findEntity(target.key, target.domain)\n if (!targetDomainEntity) continue\n\n const name = association.info.name || ''\n const parentExposure = this.exposes.find((e) => e.key === parentKey)\n const parentAbsResource = parentExposure?.absoluteResourcePath || ''\n const segment = pluralize(name.toLocaleLowerCase())\n const isCollection = association.multiple !== false\n const relativeCollectionPath = isCollection ? `/${segment}` : undefined\n const relativeResourcePath = isCollection ? `/${segment}/{id}` : `/${segment}`\n const absoluteCollectionPath = isCollection ? `${parentAbsResource}${relativeCollectionPath}` : undefined\n const absoluteResourcePath = `${parentAbsResource}${relativeResourcePath}`\n // Create nested exposure\n const nestedExposure: ExposedEntity = {\n key: nanoid(),\n entity: { ...target },\n actions: [],\n isRoot: false,\n relativeCollectionPath,\n relativeResourcePath,\n absoluteCollectionPath,\n absoluteResourcePath,\n parent: {\n key: parentKey,\n association: {\n key: association.key,\n domain: currentEntity.domain,\n },\n depth: depth + 1,\n },\n }\n\n this.exposes.push(nestedExposure)\n if (depth + 1 >= maxDepth) {\n nestedExposure.truncated = true\n } else {\n // Recursively follow associations\n follow(target, nestedExposure.key, depth + 1)\n }\n }\n }\n }\n\n // Start following from the root exposure\n follow(parentExposure.entity, parentExposure.key, 0)\n }\n\n /**\n * Removes an exposed entity from the API model.\n * @param entity The entity to remove.\n */\n removeEntity(entity: AssociationTarget): void {\n const current = this.exposes.find((e) => e.entity.key === entity.key && e.entity.domain === entity.domain)\n if (!current) {\n return\n }\n this.removeWithChildren(current.key)\n this.notifyChange()\n }\n\n private removeWithChildren(key: string): void {\n const index = this.exposes.findIndex((e) => e.key === key)\n if (index < 0) {\n return\n }\n // Remove the parent itself\n this.exposes.splice(index, 1)\n // Remove all children recursively\n const removeChildren = (parentKey: string) => {\n // Find all exposures whose parent.key matches parentKey\n const children = this.exposes.filter((e) => e.parent?.key === parentKey)\n for (const child of children) {\n removeChildren(child.key)\n const childIndex = this.exposes.findIndex((e) => e.key === child.key)\n if (childIndex >= 0) {\n this.exposes.splice(childIndex, 1)\n }\n }\n }\n // Then also remove children\n removeChildren(key)\n this.notifyChange()\n }\n\n /**\n * Returns the exposed entity by its key.\n * @param entityKey The key of the entity to find.\n * @returns The exposed entity or undefined if not found.\n */\n getExposedEntity(entity: AssociationTarget): ExposedEntity | undefined {\n return this.exposes.find((e) => e.entity.key === entity.key && e.entity.domain === entity.domain)\n }\n\n /**\n * Clears the API model for a new entity change.\n * This method resets the dependencies, exposes, user,\n * authentication, authorization, and session properties.\n */\n cleanForEntityChange(): void {\n this.dependencies.clear()\n this.dependencyList = []\n this.exposes = []\n this.user = undefined\n if (this.session) {\n this.session.properties = []\n }\n if (this.authentication && this.authentication.strategy === 'UsernamePassword') {\n const typed = this.authentication as UsernamePasswordConfiguration\n typed.passwordKey = undefined\n }\n if (this.authorization && this.authorization.strategy == 'RBAC') {\n const typed = this.authorization as RolesBasedAccessControl\n typed.roleKey = ''\n }\n }\n\n /**\n * Attaches a DataDomain to this API model.\n * This method clears any existing dependencies and sets the new domain.\n *\n * @param domain The DataDomain to attach to this API model.\n * @throws Error if the domain does not have a version set in its info.\n */\n attachDataDomain(domain: DataDomain): void {\n if (!domain.info.version) {\n throw new Error(`Cannot attach DataDomain without a version. Please set the version in the domain info.`)\n }\n this.cleanForEntityChange()\n this.dependencies.set(domain.key, domain)\n this.dependencyList = [{ key: domain.key, version: domain.info.version }]\n this.notifyChange()\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ApiModel.js","sourceRoot":"","sources":["../../../src/modeling/ApiModel.ts"],"names":[],"mappings":"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","sourcesContent":["import { nanoid } from '../nanoid.js'\nimport { ApiModelKind, DataDomainKind, ExposedEntityKind } from '../models/kinds.js'\nimport { type IThing, Thing } from '../models/Thing.js'\nimport type {\n AccessRule,\n AssociationTarget,\n AuthenticationConfiguration,\n AuthorizationConfiguration,\n ExposedEntitySchema,\n RateLimitingConfiguration,\n RolesBasedAccessControl,\n SessionConfiguration,\n UsernamePasswordConfiguration,\n ExposeOptions,\n} from './types.js'\nimport { DataDomain } from './DataDomain.js'\nimport { DependentModel, type DependentModelSchema, type DomainDependency } from './DependentModel.js'\nimport { observed, toRaw } from '../decorators/observed.js'\nimport pluralize from '@jarrodek/pluralize'\nimport { createDomainKey } from './helpers/keying.js'\nimport { ExposedEntity } from './ExposedEntity.js'\n\n/**\n * Contact information for the exposed API.\n */\nexport interface ApiContact {\n /**\n * The identifying name of the contact person/organization.\n */\n name?: string\n /**\n * The URL pointing to the contact information. MUST be in the format of a URL.\n */\n url?: string\n /**\n * The email address of the contact person/organization. MUST be in the format of an email address.\n */\n email?: string\n}\n\n/**\n * License information for the exposed API.\n */\nexport interface ApiLicense {\n /**\n * The license name used for the API. It is recommended to be an SPDX license identifier.\n */\n name: string\n /**\n * A URL to the license used for the API. MUST be in the format of a URL.\n */\n url?: string\n}\n\nexport interface ApiModelSchema extends DependentModelSchema {\n /**\n * The data domain kind recognizable by the ecosystem.\n */\n kind: typeof ApiModelKind\n /**\n * The unique key of the API model schema.\n * This is a stable identifier that does not change across versions.\n */\n key: string\n /**\n * Contains the name, display name, description, and the version of the API model schema.\n */\n info: IThing\n\n /**\n * The designated Data Entity that represents a \"User\".\n * This entity should be marked with the \"User\" semantic in the Data Modeler.\n *\n * This property is required to publish the API.\n */\n user?: AssociationTarget\n\n /**\n * Configuration for how users prove their identity.\n * The API model is invalid if this is not set.\n */\n authentication?: AuthenticationConfiguration\n\n /**\n * Configuration for what authenticated users are allowed to do.\n * The API model is invalid if this is not set.\n */\n authorization?: AuthorizationConfiguration\n\n /**\n * Configuration for the transport and payload of the user session.\n * The API model is invalid if this is not set.\n */\n session?: SessionConfiguration\n /**\n * The specific subset of Data Entities to be exposed by this API.\n * These are the entities that are included in the data domain schema.\n */\n exposes: ExposedEntitySchema[]\n\n /**\n * Optional array of access rules that define the access control policies\n * for the API. These rules are used to enforce security and permissions\n * on the exposed entities.\n *\n * These rules apply to all exposed entities and actions. An API action\n * can declare its own access rules, which will override these.\n */\n accessRule?: AccessRule[]\n /**\n * Optional configuration for API-wide rate limiting and throttling.\n * Defines rules to protect the API from overuse.\n */\n rateLimiting?: RateLimitingConfiguration\n /**\n * A URL to the Terms of Service for the API.\n */\n termsOfService?: string\n /**\n * The contact information for the exposed API.\n */\n contact?: ApiContact\n /**\n * The license information for the API.\n */\n license?: ApiLicense\n}\n\nexport class ApiModel extends DependentModel {\n /**\n * The data domain kind recognizable by the ecosystem.\n */\n kind: typeof ApiModelKind\n /**\n * The unique key of the data domain schema.\n * This is a stable identifier that does not change across versions.\n */\n key: string\n\n /**\n * The description of the domain property.\n */\n info: Thing\n /**\n * The designated Data Entity that represents a \"User\".\n * This entity must be marked with the \"User\" semantic in the Data Modeler.\n *\n * This property is required to publish the API.\n */\n user?: AssociationTarget\n\n /**\n * Configuration for how users prove their identity.\n * The API model is invalid if this is not set.\n */\n authentication?: AuthenticationConfiguration\n\n /**\n * Configuration for what authenticated users are allowed to do.\n * The API model is invalid if this is not set.\n */\n authorization?: AuthorizationConfiguration\n\n /**\n * Configuration for the transport and payload of the user session.\n * The API model is invalid if this is not set.\n */\n session?: SessionConfiguration\n /**\n * The specific subset of Data Entities to be exposed by this API.\n * These are the entities that are included in the data domain schema.\n */\n @observed({ deep: true }) accessor exposes: ExposedEntity[]\n /**\n * Optional array of access rules that define the access control policies\n * for the API. These rules are used to enforce security and permissions\n * on the exposed entities.\n *\n * These rules apply to all exposed entities and actions. An API action\n * can declare its own access rules, which will override these.\n */\n accessRule?: AccessRule[]\n /**\n * Optional configuration for API-wide rate limiting and throttling.\n * Defines rules to protect the API from overuse.\n */\n rateLimiting?: RateLimitingConfiguration\n /**\n * A URL to the Terms of Service for the API.\n */\n @observed() accessor termsOfService: string | undefined\n /**\n * The contact information for the exposed API.\n */\n @observed({ deep: true }) accessor contact: ApiContact | undefined\n /**\n * The license information for the API.\n */\n @observed({ deep: true }) accessor license: ApiLicense | undefined\n\n /**\n * When the initializing flag is set to true,\n * the domain is not notified of changes.\n */\n #initializing = true\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 /**\n * A convenience getter that returns the DataDomain associated with this API model.\n * Since the API model can have only one DataDomain,\n * this getter returns the first dependency in the list.\n *\n * The parent interface `DependentModel` allows for multiple dependencies,\n * to unify the dependency management across different models.\n */\n get domain(): DataDomain | undefined {\n if (this.dependencyList.length === 0) {\n return undefined\n }\n const domain = this.dependencyList[0]\n return this.dependencies.get(domain.key)\n }\n\n static createSchema(input: Partial<ApiModelSchema> = {}): ApiModelSchema {\n const { key = nanoid(), exposes = [] } = input\n const info = Thing.fromJSON(input.info, { name: 'Unnamed API' }).toJSON()\n const result: ApiModelSchema = {\n kind: ApiModelKind,\n key,\n info,\n exposes,\n }\n if (input.user) {\n result.user = { ...input.user }\n }\n if (input.dependencyList) {\n result.dependencyList = structuredClone(input.dependencyList)\n }\n if (input.authentication) {\n result.authentication = input.authentication\n }\n if (input.authorization) {\n result.authorization = input.authorization\n }\n if (input.session) {\n result.session = input.session\n }\n if (input.accessRule) {\n result.accessRule = input.accessRule\n }\n if (input.rateLimiting) {\n result.rateLimiting = input.rateLimiting\n }\n if (input.termsOfService) {\n result.termsOfService = input.termsOfService\n }\n if (input.contact) {\n result.contact = structuredClone(input.contact)\n }\n if (input.license) {\n result.license = structuredClone(input.license)\n }\n return result\n }\n\n constructor(state?: Partial<ApiModelSchema>, domain?: DomainDependency) {\n const init = ApiModel.createSchema(state)\n const instances: DataDomain[] = []\n if (domain instanceof DataDomain) {\n instances.push(domain)\n } else if (typeof domain === 'object' && domain.kind === DataDomainKind) {\n instances.push(new DataDomain(domain))\n } else if (domain) {\n throw new Error(`Invalid domain provided. Expected a DataDomain instance or schema.`)\n }\n super(init.dependencyList, instances)\n this.kind = init.kind\n this.key = init.key\n this.info = new Thing(init.info)\n this.user = init.user\n if (init.authentication) {\n this.authentication = structuredClone(init.authentication)\n }\n if (init.authorization) {\n this.authorization = structuredClone(init.authorization)\n }\n if (init.session) {\n this.session = structuredClone(init.session)\n }\n if (Array.isArray(init.exposes)) {\n this.exposes = init.exposes.map((e) => new ExposedEntity(this, e))\n } else {\n this.exposes = []\n }\n if (init.accessRule) {\n this.accessRule = structuredClone(init.accessRule)\n }\n if (init.rateLimiting) {\n this.rateLimiting = structuredClone(init.rateLimiting)\n }\n if (init.termsOfService) {\n this.termsOfService = init.termsOfService\n }\n if (init.contact) {\n this.contact = init.contact\n }\n if (init.license) {\n this.license = init.license\n }\n this.#initializing = false\n this.info.addEventListener('change', () => {\n this.notifyChange()\n })\n }\n\n toJSON(): ApiModelSchema {\n const result: ApiModelSchema = {\n kind: this.kind,\n key: this.key,\n info: this.info.toJSON(),\n exposes: this.exposes.map((e) => e.toJSON()),\n }\n if (this.user) {\n result.user = { ...this.user }\n }\n if (this.dependencyList.length > 0) {\n result.dependencyList = structuredClone(this.dependencyList)\n }\n if (this.authentication) {\n result.authentication = structuredClone(this.authentication)\n }\n if (this.authorization) {\n result.authorization = structuredClone(this.authorization)\n }\n if (this.session) {\n result.session = structuredClone(this.session)\n }\n if (this.accessRule) {\n result.accessRule = structuredClone(this.accessRule)\n }\n if (this.rateLimiting) {\n result.rateLimiting = structuredClone(this.rateLimiting)\n }\n if (this.termsOfService) {\n result.termsOfService = this.termsOfService\n }\n if (this.contact) {\n result.contact = structuredClone(toRaw(this, this.contact))\n }\n if (this.license) {\n result.license = structuredClone(toRaw(this, this.license))\n }\n return result\n }\n\n /**\n * This function is used internally by all domain elements to notify that something has changed.\n * Since we want to notify listeners after the operation commits, we use microtask\n * to ensure that the event is dispatched after the current operation.\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 })\n }\n\n /**\n * Exposes a new entity in the API model.\n * If the entity already exists, it returns the existing one.\n * @param entity The entity key and domain to expose.\n * @returns The exposed entity.\n */\n exposeEntity(entity: AssociationTarget, options?: ExposeOptions): ExposedEntity {\n const domain = this.domain\n if (!domain) {\n throw new Error(`No domain attached to API model`)\n }\n // checks whether the entity is already exposed as a root exposure.\n const existing = this.exposes.find(\n (e) => e.isRoot && e.entity.key === entity.key && e.entity.domain === entity.domain\n )\n if (existing) {\n // quietly return the existing exposure\n // TBD: should we throw an error here?\n return existing\n }\n const domainEntity = domain.findEntity(entity.key, entity.domain)\n if (!domainEntity) {\n throw new Error(`Entity not found in domain: ${entity.key}`)\n }\n const name = domainEntity.info.name || ''\n const segment = pluralize(name.toLocaleLowerCase())\n const relativeCollectionPath = `/${segment}`\n const relativeResourcePath = `/${segment}/{id}`\n const newEntity: ExposedEntitySchema = {\n kind: ExposedEntityKind,\n key: nanoid(),\n entity: { ...entity },\n actions: [],\n isRoot: true,\n collectionPath: relativeCollectionPath,\n resourcePath: relativeResourcePath,\n hasCollection: true,\n }\n if (options) {\n newEntity.exposeOptions = { ...options }\n }\n const created = new ExposedEntity(this, newEntity)\n this.exposes.push(created)\n\n // Follow associations if requested\n if (options?.followAssociations) {\n if (options?.maxDepth === undefined || options.maxDepth > 0) {\n this.followEntityAssociations(newEntity, options)\n }\n }\n this.notifyChange()\n return created\n }\n\n /**\n * Follows associations for a newly exposed entity if configured to do so.\n * This creates nested exposures based on the entity's associations.\n *\n * @param parentExposure The root exposure to follow associations from\n * @param options The expose options containing follow configuration\n */\n private followEntityAssociations(parentExposure: ExposedEntitySchema, options: ExposeOptions): void {\n const domain = this.domain\n if (!domain) {\n return\n }\n const maxDepth = options.maxDepth ?? 6\n const visited = new Set<string>()\n // Add parent entity's key to the visited set so we won't skip it when traversing\n // associations.\n visited.add(createDomainKey(parentExposure.entity))\n\n const follow = (currentEntity: AssociationTarget, parentKey: string, depth: number) => {\n // Find the domain entity\n const domainEntity = domain.findEntity(currentEntity.key, currentEntity.domain)\n if (!domainEntity) return\n\n // Iterate through associations\n for (const association of domainEntity.listAssociations()) {\n for (const target of association.targets) {\n // Skip self-referencing associations\n if (target.key === currentEntity.key && target.domain === currentEntity.domain) {\n continue\n }\n\n // Create unique identifier for circular detection\n const visitKey = createDomainKey(target)\n if (visited.has(visitKey)) {\n continue // Skip circular references\n }\n visited.add(visitKey)\n\n // Check if this nested exposure already exists\n const existingNested = this.exposes.find(\n (e) =>\n !e.isRoot &&\n e.entity.key === target.key &&\n e.entity.domain === target.domain &&\n e.parent?.key === parentKey\n )\n\n if (existingNested) {\n continue // Already exposed under this parent\n }\n\n // Find the target domain entity for path generation\n const targetDomainEntity = domain.findEntity(target.key, target.domain)\n if (!targetDomainEntity) continue\n\n const name = association.info.name || ''\n const segment = pluralize(name.toLocaleLowerCase())\n const isCollection = association.multiple !== false\n const relativeCollectionPath = isCollection ? `/${segment}` : undefined\n const relativeResourcePath = isCollection ? `/${segment}/{id}` : `/${segment}`\n // Create nested exposure\n const nestedExposure: ExposedEntitySchema = {\n kind: ExposedEntityKind,\n key: nanoid(),\n entity: { ...target },\n actions: [],\n isRoot: false,\n collectionPath: relativeCollectionPath,\n resourcePath: relativeResourcePath,\n hasCollection: isCollection,\n parent: {\n key: parentKey,\n association: {\n key: association.key,\n domain: currentEntity.domain,\n },\n depth: depth + 1,\n },\n }\n\n this.exposes.push(new ExposedEntity(this, nestedExposure))\n if (depth + 1 >= maxDepth) {\n nestedExposure.truncated = true\n } else {\n // Recursively follow associations\n follow(target, nestedExposure.key, depth + 1)\n }\n }\n }\n }\n\n // Start following from the root exposure\n follow(parentExposure.entity, parentExposure.key, 0)\n }\n\n /**\n * Removes an exposed entity from the API model.\n * @param entity The entity to remove.\n */\n removeEntity(entity: AssociationTarget): void {\n const current = this.exposes.find((e) => e.entity.key === entity.key && e.entity.domain === entity.domain)\n if (!current) {\n return\n }\n this.removeWithChildren(current.key)\n this.notifyChange()\n }\n\n private removeWithChildren(key: string): void {\n const index = this.exposes.findIndex((e) => e.key === key)\n if (index < 0) {\n return\n }\n // Remove the parent itself\n this.exposes.splice(index, 1)\n // Remove all children recursively\n const removeChildren = (parentKey: string) => {\n // Find all exposures whose parent.key matches parentKey\n const children = this.exposes.filter((e) => e.parent?.key === parentKey)\n for (const child of children) {\n removeChildren(child.key)\n const childIndex = this.exposes.findIndex((e) => e.key === child.key)\n if (childIndex >= 0) {\n this.exposes.splice(childIndex, 1)\n }\n }\n }\n // Then also remove children\n removeChildren(key)\n this.notifyChange()\n }\n\n /**\n * Returns the exposed entity by its key.\n * @param entityKey The key of the entity to find.\n * @returns The exposed entity or undefined if not found.\n */\n getExposedEntity(entity: AssociationTarget): ExposedEntity | undefined {\n return this.exposes.find((e) => e.entity.key === entity.key && e.entity.domain === entity.domain)\n }\n\n /**\n * Clears the API model for a new entity change.\n * This method resets the dependencies, exposes, user,\n * authentication, authorization, and session properties.\n */\n cleanForEntityChange(): void {\n this.dependencies.clear()\n this.dependencyList = []\n this.exposes = []\n this.user = undefined\n if (this.session) {\n this.session.properties = []\n }\n if (this.authentication && this.authentication.strategy === 'UsernamePassword') {\n const typed = this.authentication as UsernamePasswordConfiguration\n typed.passwordKey = undefined\n }\n if (this.authorization && this.authorization.strategy == 'RBAC') {\n const typed = this.authorization as RolesBasedAccessControl\n typed.roleKey = ''\n }\n }\n\n /**\n * Attaches a DataDomain to this API model.\n * This method clears any existing dependencies and sets the new domain.\n *\n * @param domain The DataDomain to attach to this API model.\n * @throws Error if the domain does not have a version set in its info.\n */\n attachDataDomain(domain: DataDomain): void {\n if (!domain.info.version) {\n throw new Error(`Cannot attach DataDomain without a version. Please set the version in the domain info.`)\n }\n this.cleanForEntityChange()\n this.dependencies.set(domain.key, domain)\n this.dependencyList = [{ key: domain.key, version: domain.info.version }]\n this.notifyChange()\n }\n}\n"]}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { ExposedEntityKind } from '../models/kinds.js';
|
|
2
|
+
import type { ApiModel } from './ApiModel.js';
|
|
3
|
+
import type { AccessRule, ApiAction, AssociationTarget, ExposeOptions, ExposeParentRef, RateLimitingConfiguration, ExposedEntitySchema } from './types.js';
|
|
4
|
+
/**
|
|
5
|
+
* A class that specializes in representing an exposed Data Entity within an API Model.
|
|
6
|
+
*
|
|
7
|
+
* @fires change - Emitted when the exposed entity has changed.
|
|
8
|
+
*/
|
|
9
|
+
export declare class ExposedEntity extends EventTarget {
|
|
10
|
+
#private;
|
|
11
|
+
/**
|
|
12
|
+
* The exposed entity kind recognizable by the ecosystem.
|
|
13
|
+
*/
|
|
14
|
+
kind: typeof ExposedEntityKind;
|
|
15
|
+
/**
|
|
16
|
+
* The unique key of the exposed entity.
|
|
17
|
+
* This is a stable identifier that does not change across versions.
|
|
18
|
+
*/
|
|
19
|
+
key: string;
|
|
20
|
+
/**
|
|
21
|
+
* A pointer to a Data Entity from the Data Domain.
|
|
22
|
+
*/
|
|
23
|
+
accessor entity: AssociationTarget;
|
|
24
|
+
/**
|
|
25
|
+
* Indicates whether this exposure has a collection endpoint.
|
|
26
|
+
* A collection endpoint is optional for nested exposures where the association is 1:1
|
|
27
|
+
* and the schema is embedded directly under the parent resource.
|
|
28
|
+
*
|
|
29
|
+
* Note that this property is not observed for changes as it is immutable after creation.
|
|
30
|
+
*/
|
|
31
|
+
hasCollection: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Path to the collection endpoint for this exposure.
|
|
34
|
+
* Starts with '/'. Not set for 1:1 nested exposures where collection does not exist.
|
|
35
|
+
*/
|
|
36
|
+
accessor collectionPath: string | undefined;
|
|
37
|
+
/**
|
|
38
|
+
* Path to the resource endpoint for this exposure.
|
|
39
|
+
* Starts with '/'. For 1:1 nested exposures the resource path typically does not include an id segment.
|
|
40
|
+
*/
|
|
41
|
+
accessor resourcePath: string;
|
|
42
|
+
/**
|
|
43
|
+
* Whether this exposure is a root exposure (top-level collection).
|
|
44
|
+
* If this is set then the `parent` reference must be populated.
|
|
45
|
+
*
|
|
46
|
+
* Note that this property is not observed for changes as it is immutable after creation.
|
|
47
|
+
*/
|
|
48
|
+
isRoot?: boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Parent reference when this exposure was created via following an association.
|
|
51
|
+
*
|
|
52
|
+
* Note that this property is not observed for changes as it is immutable after creation.
|
|
53
|
+
*/
|
|
54
|
+
parent?: ExposeParentRef;
|
|
55
|
+
/**
|
|
56
|
+
* Expose-time config used to create this exposure (persisted for auditing/UI).
|
|
57
|
+
* This is only populated for the root exposure. All children exposures inherit this config.
|
|
58
|
+
*
|
|
59
|
+
* Note that this property is not observed for changes as it is immutable after creation.
|
|
60
|
+
*/
|
|
61
|
+
exposeOptions?: ExposeOptions;
|
|
62
|
+
/**
|
|
63
|
+
* The list of enabled API actions for this exposure (List/Read/Create/etc.)
|
|
64
|
+
*/
|
|
65
|
+
accessor actions: ApiAction[];
|
|
66
|
+
/**
|
|
67
|
+
* Optional array of access rules that define the access control policies for this exposure.
|
|
68
|
+
*/
|
|
69
|
+
accessor accessRule: AccessRule[] | undefined;
|
|
70
|
+
/**
|
|
71
|
+
* Optional configuration for rate limiting for this exposure.
|
|
72
|
+
*/
|
|
73
|
+
accessor rateLimiting: RateLimitingConfiguration | undefined;
|
|
74
|
+
/**
|
|
75
|
+
* When true, generation for this exposure hit configured limits
|
|
76
|
+
*
|
|
77
|
+
* Note that this property is not observed for changes as it is immutable after creation.
|
|
78
|
+
*/
|
|
79
|
+
truncated?: boolean;
|
|
80
|
+
/**
|
|
81
|
+
* A reference to the parent API Model instance.
|
|
82
|
+
*/
|
|
83
|
+
api: ApiModel;
|
|
84
|
+
static createSchema(input?: Partial<ExposedEntitySchema>): ExposedEntitySchema;
|
|
85
|
+
constructor(model: ApiModel, state?: Partial<ExposedEntitySchema>);
|
|
86
|
+
notifyChange(): void;
|
|
87
|
+
toJSON(): ExposedEntitySchema;
|
|
88
|
+
/**
|
|
89
|
+
* Sets a new collection path for this exposed entity.
|
|
90
|
+
*
|
|
91
|
+
* It:
|
|
92
|
+
* - updates the collectionPath property
|
|
93
|
+
* - updates the absoluteCollectionPath property accordingly
|
|
94
|
+
* - updates the resourcePath accordingly.
|
|
95
|
+
* @param path The new path to set.
|
|
96
|
+
*/
|
|
97
|
+
setCollectionPath(path: string): void;
|
|
98
|
+
/**
|
|
99
|
+
* Sets a new resource path for this exposed entity.
|
|
100
|
+
*
|
|
101
|
+
* Rules:
|
|
102
|
+
* - Must start with '/'.
|
|
103
|
+
* - If this exposure has a collection, the path must be exactly the collection path plus a single
|
|
104
|
+
* parameter segment (e.g. `/products/{productId}`) and only the parameter name may vary.
|
|
105
|
+
* - If this exposure does NOT have a collection, the path can be any two segments (e.g. `/profile/{id}` or `/a/b`).
|
|
106
|
+
*/
|
|
107
|
+
setResourcePath(path: string): void;
|
|
108
|
+
/**
|
|
109
|
+
* Computes the absolute path for this exposure's resource endpoint by
|
|
110
|
+
* walking up the exposure tree using `parent.key` until reaching a root exposure.
|
|
111
|
+
* The absolute path is composed by concatenating each ancestor's resource path
|
|
112
|
+
* with this exposure's resource path.
|
|
113
|
+
*/
|
|
114
|
+
getAbsoluteResourcePath(): string;
|
|
115
|
+
/**
|
|
116
|
+
* Computes the absolute path for this exposure's collection endpoint (if any)
|
|
117
|
+
* by walking up the exposure tree using `parent.key` until reaching a root exposure.
|
|
118
|
+
* The absolute path is composed by concatenating each ancestor's resource path
|
|
119
|
+
* with this exposure's collection path.
|
|
120
|
+
* Returns undefined if this exposure has no collection.
|
|
121
|
+
*/
|
|
122
|
+
getAbsoluteCollectionPath(): string | undefined;
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=ExposedEntity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExposedEntity.d.ts","sourceRoot":"","sources":["../../../src/modeling/ExposedEntity.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAEtD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAE7C,OAAO,KAAK,EACV,UAAU,EACV,SAAS,EACT,iBAAiB,EACjB,aAAa,EACb,eAAe,EACf,yBAAyB,EACzB,mBAAmB,EACpB,MAAM,YAAY,CAAA;AAEnB;;;;GAIG;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;IACuB,QAAQ,CAAC,OAAO,EAAE,SAAS,EAAE,CAAA;IAEvD;;OAEG;IACuB,QAAQ,CAAC,UAAU,EAAE,UAAU,EAAE,GAAG,SAAS,CAAA;IAEvE;;OAEG;IACuB,QAAQ,CAAC,YAAY,EAAE,yBAAyB,GAAG,SAAS,CAAA;IAEtF;;;;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;gBA+CtE,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC;IAoBjE,YAAY;IAYZ,MAAM,IAAI,mBAAmB;IAiC7B;;;;;;;;OAQG;IACH,iBAAiB,CAAC,IAAI,EAAE,MAAM;IA0B9B;;;;;;;;OAQG;IACH,eAAe,CAAC,IAAI,EAAE,MAAM;IAwC5B;;;;;OAKG;IACH,uBAAuB,IAAI,MAAM;IAcjC;;;;;;OAMG;IACH,yBAAyB,IAAI,MAAM,GAAG,SAAS;CAchD"}
|
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
import { __esDecorate, __runInitializers } from "tslib";
|
|
2
|
+
import { observed } from '../decorators/observed.js';
|
|
3
|
+
import { ExposedEntityKind } from '../models/kinds.js';
|
|
4
|
+
import { nanoid } from '../nanoid.js';
|
|
5
|
+
import { ensureLeadingSlash, joinPaths } from './helpers/endpointHelpers.js';
|
|
6
|
+
/**
|
|
7
|
+
* A class that specializes in representing an exposed Data Entity within an API Model.
|
|
8
|
+
*
|
|
9
|
+
* @fires change - Emitted when the exposed entity has changed.
|
|
10
|
+
*/
|
|
11
|
+
let ExposedEntity = (() => {
|
|
12
|
+
let _classSuper = EventTarget;
|
|
13
|
+
let _entity_decorators;
|
|
14
|
+
let _entity_initializers = [];
|
|
15
|
+
let _entity_extraInitializers = [];
|
|
16
|
+
let _collectionPath_decorators;
|
|
17
|
+
let _collectionPath_initializers = [];
|
|
18
|
+
let _collectionPath_extraInitializers = [];
|
|
19
|
+
let _resourcePath_decorators;
|
|
20
|
+
let _resourcePath_initializers = [];
|
|
21
|
+
let _resourcePath_extraInitializers = [];
|
|
22
|
+
let _actions_decorators;
|
|
23
|
+
let _actions_initializers = [];
|
|
24
|
+
let _actions_extraInitializers = [];
|
|
25
|
+
let _accessRule_decorators;
|
|
26
|
+
let _accessRule_initializers = [];
|
|
27
|
+
let _accessRule_extraInitializers = [];
|
|
28
|
+
let _rateLimiting_decorators;
|
|
29
|
+
let _rateLimiting_initializers = [];
|
|
30
|
+
let _rateLimiting_extraInitializers = [];
|
|
31
|
+
return class ExposedEntity extends _classSuper {
|
|
32
|
+
static {
|
|
33
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
34
|
+
_entity_decorators = [observed()];
|
|
35
|
+
_collectionPath_decorators = [observed()];
|
|
36
|
+
_resourcePath_decorators = [observed()];
|
|
37
|
+
_actions_decorators = [observed({ deep: true })];
|
|
38
|
+
_accessRule_decorators = [observed({ deep: true })];
|
|
39
|
+
_rateLimiting_decorators = [observed({ deep: true })];
|
|
40
|
+
__esDecorate(this, null, _entity_decorators, { kind: "accessor", name: "entity", static: false, private: false, access: { has: obj => "entity" in obj, get: obj => obj.entity, set: (obj, value) => { obj.entity = value; } }, metadata: _metadata }, _entity_initializers, _entity_extraInitializers);
|
|
41
|
+
__esDecorate(this, null, _collectionPath_decorators, { kind: "accessor", name: "collectionPath", static: false, private: false, access: { has: obj => "collectionPath" in obj, get: obj => obj.collectionPath, set: (obj, value) => { obj.collectionPath = value; } }, metadata: _metadata }, _collectionPath_initializers, _collectionPath_extraInitializers);
|
|
42
|
+
__esDecorate(this, null, _resourcePath_decorators, { kind: "accessor", name: "resourcePath", static: false, private: false, access: { has: obj => "resourcePath" in obj, get: obj => obj.resourcePath, set: (obj, value) => { obj.resourcePath = value; } }, metadata: _metadata }, _resourcePath_initializers, _resourcePath_extraInitializers);
|
|
43
|
+
__esDecorate(this, null, _actions_decorators, { kind: "accessor", name: "actions", static: false, private: false, access: { has: obj => "actions" in obj, get: obj => obj.actions, set: (obj, value) => { obj.actions = value; } }, metadata: _metadata }, _actions_initializers, _actions_extraInitializers);
|
|
44
|
+
__esDecorate(this, null, _accessRule_decorators, { kind: "accessor", name: "accessRule", static: false, private: false, access: { has: obj => "accessRule" in obj, get: obj => obj.accessRule, set: (obj, value) => { obj.accessRule = value; } }, metadata: _metadata }, _accessRule_initializers, _accessRule_extraInitializers);
|
|
45
|
+
__esDecorate(this, null, _rateLimiting_decorators, { kind: "accessor", name: "rateLimiting", static: false, private: false, access: { has: obj => "rateLimiting" in obj, get: obj => obj.rateLimiting, set: (obj, value) => { obj.rateLimiting = value; } }, metadata: _metadata }, _rateLimiting_initializers, _rateLimiting_extraInitializers);
|
|
46
|
+
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* The exposed entity kind recognizable by the ecosystem.
|
|
50
|
+
*/
|
|
51
|
+
kind;
|
|
52
|
+
/**
|
|
53
|
+
* The unique key of the exposed entity.
|
|
54
|
+
* This is a stable identifier that does not change across versions.
|
|
55
|
+
*/
|
|
56
|
+
key;
|
|
57
|
+
#entity_accessor_storage = __runInitializers(this, _entity_initializers, void 0);
|
|
58
|
+
/**
|
|
59
|
+
* A pointer to a Data Entity from the Data Domain.
|
|
60
|
+
*/
|
|
61
|
+
get entity() { return this.#entity_accessor_storage; }
|
|
62
|
+
set entity(value) { this.#entity_accessor_storage = value; }
|
|
63
|
+
/**
|
|
64
|
+
* Indicates whether this exposure has a collection endpoint.
|
|
65
|
+
* A collection endpoint is optional for nested exposures where the association is 1:1
|
|
66
|
+
* and the schema is embedded directly under the parent resource.
|
|
67
|
+
*
|
|
68
|
+
* Note that this property is not observed for changes as it is immutable after creation.
|
|
69
|
+
*/
|
|
70
|
+
hasCollection = __runInitializers(this, _entity_extraInitializers);
|
|
71
|
+
#collectionPath_accessor_storage = __runInitializers(this, _collectionPath_initializers, void 0);
|
|
72
|
+
/**
|
|
73
|
+
* Path to the collection endpoint for this exposure.
|
|
74
|
+
* Starts with '/'. Not set for 1:1 nested exposures where collection does not exist.
|
|
75
|
+
*/
|
|
76
|
+
get collectionPath() { return this.#collectionPath_accessor_storage; }
|
|
77
|
+
set collectionPath(value) { this.#collectionPath_accessor_storage = value; }
|
|
78
|
+
#resourcePath_accessor_storage = (__runInitializers(this, _collectionPath_extraInitializers), __runInitializers(this, _resourcePath_initializers, void 0));
|
|
79
|
+
/**
|
|
80
|
+
* Path to the resource endpoint for this exposure.
|
|
81
|
+
* Starts with '/'. For 1:1 nested exposures the resource path typically does not include an id segment.
|
|
82
|
+
*/
|
|
83
|
+
get resourcePath() { return this.#resourcePath_accessor_storage; }
|
|
84
|
+
set resourcePath(value) { this.#resourcePath_accessor_storage = value; }
|
|
85
|
+
/**
|
|
86
|
+
* Whether this exposure is a root exposure (top-level collection).
|
|
87
|
+
* If this is set then the `parent` reference must be populated.
|
|
88
|
+
*
|
|
89
|
+
* Note that this property is not observed for changes as it is immutable after creation.
|
|
90
|
+
*/
|
|
91
|
+
isRoot = __runInitializers(this, _resourcePath_extraInitializers);
|
|
92
|
+
/**
|
|
93
|
+
* Parent reference when this exposure was created via following an association.
|
|
94
|
+
*
|
|
95
|
+
* Note that this property is not observed for changes as it is immutable after creation.
|
|
96
|
+
*/
|
|
97
|
+
parent;
|
|
98
|
+
/**
|
|
99
|
+
* Expose-time config used to create this exposure (persisted for auditing/UI).
|
|
100
|
+
* This is only populated for the root exposure. All children exposures inherit this config.
|
|
101
|
+
*
|
|
102
|
+
* Note that this property is not observed for changes as it is immutable after creation.
|
|
103
|
+
*/
|
|
104
|
+
exposeOptions;
|
|
105
|
+
#actions_accessor_storage = __runInitializers(this, _actions_initializers, void 0);
|
|
106
|
+
/**
|
|
107
|
+
* The list of enabled API actions for this exposure (List/Read/Create/etc.)
|
|
108
|
+
*/
|
|
109
|
+
get actions() { return this.#actions_accessor_storage; }
|
|
110
|
+
set actions(value) { this.#actions_accessor_storage = value; }
|
|
111
|
+
#accessRule_accessor_storage = (__runInitializers(this, _actions_extraInitializers), __runInitializers(this, _accessRule_initializers, void 0));
|
|
112
|
+
/**
|
|
113
|
+
* Optional array of access rules that define the access control policies for this exposure.
|
|
114
|
+
*/
|
|
115
|
+
get accessRule() { return this.#accessRule_accessor_storage; }
|
|
116
|
+
set accessRule(value) { this.#accessRule_accessor_storage = value; }
|
|
117
|
+
#rateLimiting_accessor_storage = (__runInitializers(this, _accessRule_extraInitializers), __runInitializers(this, _rateLimiting_initializers, void 0));
|
|
118
|
+
/**
|
|
119
|
+
* Optional configuration for rate limiting for this exposure.
|
|
120
|
+
*/
|
|
121
|
+
get rateLimiting() { return this.#rateLimiting_accessor_storage; }
|
|
122
|
+
set rateLimiting(value) { this.#rateLimiting_accessor_storage = value; }
|
|
123
|
+
/**
|
|
124
|
+
* When true, generation for this exposure hit configured limits
|
|
125
|
+
*
|
|
126
|
+
* Note that this property is not observed for changes as it is immutable after creation.
|
|
127
|
+
*/
|
|
128
|
+
truncated = __runInitializers(this, _rateLimiting_extraInitializers);
|
|
129
|
+
/**
|
|
130
|
+
* When the notifying flag is set to true,
|
|
131
|
+
* the domain is pending a notification.
|
|
132
|
+
* No other notifications will be sent until
|
|
133
|
+
* the current notification is sent.
|
|
134
|
+
*/
|
|
135
|
+
#notifying = false;
|
|
136
|
+
/**
|
|
137
|
+
* When the initializing flag is set to true,
|
|
138
|
+
* the domain is not notified of changes.
|
|
139
|
+
*/
|
|
140
|
+
#initializing = true;
|
|
141
|
+
/**
|
|
142
|
+
* A reference to the parent API Model instance.
|
|
143
|
+
*/
|
|
144
|
+
api;
|
|
145
|
+
static createSchema(input = {}) {
|
|
146
|
+
const { key = nanoid(), entity = { key: '' }, collectionPath, resourcePath = '/', hasCollection = true, isRoot, parent, exposeOptions, actions = [], accessRule, rateLimiting, truncated, } = input;
|
|
147
|
+
const result = {
|
|
148
|
+
kind: ExposedEntityKind,
|
|
149
|
+
key,
|
|
150
|
+
entity: { ...entity },
|
|
151
|
+
hasCollection,
|
|
152
|
+
resourcePath,
|
|
153
|
+
actions: actions.map((a) => ({ ...a })),
|
|
154
|
+
};
|
|
155
|
+
if (collectionPath !== undefined) {
|
|
156
|
+
result.collectionPath = collectionPath;
|
|
157
|
+
}
|
|
158
|
+
if (isRoot !== undefined) {
|
|
159
|
+
result.isRoot = isRoot;
|
|
160
|
+
}
|
|
161
|
+
if (parent !== undefined) {
|
|
162
|
+
result.parent = { ...parent };
|
|
163
|
+
}
|
|
164
|
+
if (exposeOptions !== undefined) {
|
|
165
|
+
result.exposeOptions = { ...exposeOptions };
|
|
166
|
+
}
|
|
167
|
+
if (accessRule !== undefined) {
|
|
168
|
+
result.accessRule = accessRule.map((ar) => ({ ...ar }));
|
|
169
|
+
}
|
|
170
|
+
if (rateLimiting !== undefined) {
|
|
171
|
+
result.rateLimiting = { ...rateLimiting };
|
|
172
|
+
}
|
|
173
|
+
if (truncated !== undefined) {
|
|
174
|
+
result.truncated = truncated;
|
|
175
|
+
}
|
|
176
|
+
return result;
|
|
177
|
+
}
|
|
178
|
+
constructor(model, state) {
|
|
179
|
+
super();
|
|
180
|
+
this.api = model;
|
|
181
|
+
const init = ExposedEntity.createSchema(state);
|
|
182
|
+
this.kind = init.kind;
|
|
183
|
+
this.key = init.key;
|
|
184
|
+
this.entity = init.entity;
|
|
185
|
+
this.hasCollection = init.hasCollection;
|
|
186
|
+
this.collectionPath = init.collectionPath;
|
|
187
|
+
this.resourcePath = init.resourcePath;
|
|
188
|
+
this.isRoot = init.isRoot;
|
|
189
|
+
this.parent = init.parent;
|
|
190
|
+
this.exposeOptions = init.exposeOptions;
|
|
191
|
+
this.actions = init.actions;
|
|
192
|
+
this.accessRule = init.accessRule;
|
|
193
|
+
this.rateLimiting = init.rateLimiting;
|
|
194
|
+
this.truncated = init.truncated;
|
|
195
|
+
this.#initializing = false;
|
|
196
|
+
}
|
|
197
|
+
notifyChange() {
|
|
198
|
+
if (this.#notifying || this.#initializing) {
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
this.#notifying = true;
|
|
202
|
+
queueMicrotask(() => {
|
|
203
|
+
this.#notifying = false;
|
|
204
|
+
const event = new Event('change');
|
|
205
|
+
this.dispatchEvent(event);
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
toJSON() {
|
|
209
|
+
const result = {
|
|
210
|
+
kind: this.kind,
|
|
211
|
+
key: this.key,
|
|
212
|
+
entity: { ...this.entity },
|
|
213
|
+
resourcePath: this.resourcePath,
|
|
214
|
+
actions: this.actions.map((a) => ({ ...a })),
|
|
215
|
+
hasCollection: this.hasCollection,
|
|
216
|
+
};
|
|
217
|
+
if (this.collectionPath !== undefined) {
|
|
218
|
+
result.collectionPath = this.collectionPath;
|
|
219
|
+
}
|
|
220
|
+
if (this.isRoot !== undefined) {
|
|
221
|
+
result.isRoot = this.isRoot;
|
|
222
|
+
}
|
|
223
|
+
if (this.parent !== undefined) {
|
|
224
|
+
result.parent = { ...this.parent };
|
|
225
|
+
}
|
|
226
|
+
if (this.exposeOptions !== undefined) {
|
|
227
|
+
result.exposeOptions = { ...this.exposeOptions };
|
|
228
|
+
}
|
|
229
|
+
if (this.accessRule !== undefined) {
|
|
230
|
+
result.accessRule = this.accessRule.map((ar) => ({ ...ar }));
|
|
231
|
+
}
|
|
232
|
+
if (this.rateLimiting !== undefined) {
|
|
233
|
+
result.rateLimiting = { ...this.rateLimiting };
|
|
234
|
+
}
|
|
235
|
+
if (this.truncated !== undefined) {
|
|
236
|
+
result.truncated = this.truncated;
|
|
237
|
+
}
|
|
238
|
+
return result;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Sets a new collection path for this exposed entity.
|
|
242
|
+
*
|
|
243
|
+
* It:
|
|
244
|
+
* - updates the collectionPath property
|
|
245
|
+
* - updates the absoluteCollectionPath property accordingly
|
|
246
|
+
* - updates the resourcePath accordingly.
|
|
247
|
+
* @param path The new path to set.
|
|
248
|
+
*/
|
|
249
|
+
setCollectionPath(path) {
|
|
250
|
+
if (!this.hasCollection) {
|
|
251
|
+
throw new Error(`Cannot set collection path on an exposure that does not have a collection`);
|
|
252
|
+
}
|
|
253
|
+
const cleaned = ensureLeadingSlash(path);
|
|
254
|
+
// Ensure exactly one non-empty segment
|
|
255
|
+
const segments = cleaned.split('/').filter(Boolean);
|
|
256
|
+
if (segments.length !== 1) {
|
|
257
|
+
throw new Error(`Collection path must contain exactly one segment. Received: "${path}"`);
|
|
258
|
+
}
|
|
259
|
+
const normalizedCollection = `/${segments[0]}`;
|
|
260
|
+
// Preserve current parameter name if present, otherwise default to {id}
|
|
261
|
+
let param = '{id}';
|
|
262
|
+
if (this.resourcePath) {
|
|
263
|
+
const curSegments = this.resourcePath.split('/').filter(Boolean);
|
|
264
|
+
const maybeParam = curSegments[1];
|
|
265
|
+
if (maybeParam && /^\{[A-Za-z_][A-Za-z0-9_]*\}$/.test(maybeParam)) {
|
|
266
|
+
param = maybeParam;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
const nextResource = `${normalizedCollection}/${param}`;
|
|
270
|
+
this.collectionPath = normalizedCollection;
|
|
271
|
+
this.resourcePath = nextResource;
|
|
272
|
+
// rely on ApiModel.exposes deep observation to notify on property sets
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Sets a new resource path for this exposed entity.
|
|
276
|
+
*
|
|
277
|
+
* Rules:
|
|
278
|
+
* - Must start with '/'.
|
|
279
|
+
* - If this exposure has a collection, the path must be exactly the collection path plus a single
|
|
280
|
+
* parameter segment (e.g. `/products/{productId}`) and only the parameter name may vary.
|
|
281
|
+
* - If this exposure does NOT have a collection, the path can be any two segments (e.g. `/profile/{id}` or `/a/b`).
|
|
282
|
+
*/
|
|
283
|
+
setResourcePath(path) {
|
|
284
|
+
const cleaned = ensureLeadingSlash(path);
|
|
285
|
+
const segments = cleaned.split('/').filter(Boolean);
|
|
286
|
+
if (this.hasCollection) {
|
|
287
|
+
if (!this.collectionPath) {
|
|
288
|
+
throw new Error('Cannot set resource path: missing collection path for this exposure');
|
|
289
|
+
}
|
|
290
|
+
const colSegments = this.collectionPath.split('/').filter(Boolean);
|
|
291
|
+
if (colSegments.length !== 1) {
|
|
292
|
+
throw new Error(`Invalid stored collection path "${this.collectionPath}"`);
|
|
293
|
+
}
|
|
294
|
+
if (segments.length !== 2) {
|
|
295
|
+
throw new Error(`Resource path must be exactly two segments (collection + parameter). Received: "${cleaned}"`);
|
|
296
|
+
}
|
|
297
|
+
const [s1, s2] = segments;
|
|
298
|
+
if (s1 !== colSegments[0]) {
|
|
299
|
+
throw new Error(`Resource path must start with the collection segment "${colSegments[0]}". Received: "${s1}"`);
|
|
300
|
+
}
|
|
301
|
+
// s2 must be a parameter segment {name}
|
|
302
|
+
if (!/^\{[A-Za-z_][A-Za-z0-9_]*\}$/.test(s2)) {
|
|
303
|
+
throw new Error(`The second segment must be a parameter in braces, e.g. {id}. Received: "${s2}"`);
|
|
304
|
+
}
|
|
305
|
+
if (this.resourcePath !== cleaned) {
|
|
306
|
+
this.resourcePath = `/${s1}/${s2}`;
|
|
307
|
+
}
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
// No collection: allow any two segments
|
|
311
|
+
if (segments.length !== 2) {
|
|
312
|
+
throw new Error(`Resource path must contain exactly two segments when no collection is present. Received: "${cleaned}"`);
|
|
313
|
+
}
|
|
314
|
+
if (this.resourcePath !== cleaned) {
|
|
315
|
+
this.resourcePath = `/${segments[0]}/${segments[1]}`;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Computes the absolute path for this exposure's resource endpoint by
|
|
320
|
+
* walking up the exposure tree using `parent.key` until reaching a root exposure.
|
|
321
|
+
* The absolute path is composed by concatenating each ancestor's resource path
|
|
322
|
+
* with this exposure's resource path.
|
|
323
|
+
*/
|
|
324
|
+
getAbsoluteResourcePath() {
|
|
325
|
+
let absolute = ensureLeadingSlash(this.resourcePath);
|
|
326
|
+
// Traverse parents, always joining with the parent's resource path
|
|
327
|
+
let parentKey = this.parent?.key;
|
|
328
|
+
while (parentKey) {
|
|
329
|
+
const parent = this.api.exposes.find((e) => e.key === parentKey);
|
|
330
|
+
if (!parent)
|
|
331
|
+
break;
|
|
332
|
+
const parentResource = ensureLeadingSlash(parent.resourcePath);
|
|
333
|
+
absolute = joinPaths(parentResource, absolute);
|
|
334
|
+
parentKey = parent.parent?.key;
|
|
335
|
+
}
|
|
336
|
+
return absolute;
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Computes the absolute path for this exposure's collection endpoint (if any)
|
|
340
|
+
* by walking up the exposure tree using `parent.key` until reaching a root exposure.
|
|
341
|
+
* The absolute path is composed by concatenating each ancestor's resource path
|
|
342
|
+
* with this exposure's collection path.
|
|
343
|
+
* Returns undefined if this exposure has no collection.
|
|
344
|
+
*/
|
|
345
|
+
getAbsoluteCollectionPath() {
|
|
346
|
+
if (!this.hasCollection || !this.collectionPath)
|
|
347
|
+
return undefined;
|
|
348
|
+
let absolute = ensureLeadingSlash(this.collectionPath);
|
|
349
|
+
// Traverse parents, always joining with the parent's resource path
|
|
350
|
+
let parentKey = this.parent?.key;
|
|
351
|
+
while (parentKey) {
|
|
352
|
+
const parent = this.api.exposes.find((e) => e.key === parentKey);
|
|
353
|
+
if (!parent)
|
|
354
|
+
break;
|
|
355
|
+
const parentResource = ensureLeadingSlash(parent.resourcePath);
|
|
356
|
+
absolute = joinPaths(parentResource, absolute);
|
|
357
|
+
parentKey = parent.parent?.key;
|
|
358
|
+
}
|
|
359
|
+
return absolute;
|
|
360
|
+
}
|
|
361
|
+
};
|
|
362
|
+
})();
|
|
363
|
+
export { ExposedEntity };
|
|
364
|
+
//# sourceMappingURL=ExposedEntity.js.map
|