@api-client/core 0.14.6 → 0.14.8

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 (31) hide show
  1. package/build/src/amf/ApiSchemaValues.js.map +1 -1
  2. package/build/src/modeling/ApiModel.d.ts +27 -17
  3. package/build/src/modeling/ApiModel.d.ts.map +1 -1
  4. package/build/src/modeling/ApiModel.js +69 -20
  5. package/build/src/modeling/ApiModel.js.map +1 -1
  6. package/build/src/modeling/DataDomain.d.ts +34 -20
  7. package/build/src/modeling/DataDomain.d.ts.map +1 -1
  8. package/build/src/modeling/DataDomain.js +64 -24
  9. package/build/src/modeling/DataDomain.js.map +1 -1
  10. package/build/src/modeling/DependentModel.d.ts +26 -0
  11. package/build/src/modeling/DependentModel.d.ts.map +1 -0
  12. package/build/src/modeling/DependentModel.js +23 -0
  13. package/build/src/modeling/DependentModel.js.map +1 -0
  14. package/build/src/modeling/types.d.ts +2 -0
  15. package/build/src/modeling/types.d.ts.map +1 -1
  16. package/build/src/modeling/types.js.map +1 -1
  17. package/build/src/models/store/Backend.d.ts +0 -168
  18. package/build/src/models/store/Backend.d.ts.map +1 -1
  19. package/build/src/models/store/Backend.js +1 -12
  20. package/build/src/models/store/Backend.js.map +1 -1
  21. package/build/tsconfig.tsbuildinfo +1 -1
  22. package/data/models/example-generator-api.json +16 -16
  23. package/package.json +1 -1
  24. package/src/amf/ApiSchemaValues.ts +1 -1
  25. package/src/modeling/ApiModel.ts +74 -31
  26. package/src/modeling/DataDomain.ts +65 -35
  27. package/src/modeling/DependentModel.ts +36 -0
  28. package/src/modeling/types.ts +2 -0
  29. package/src/models/store/Backend.ts +0 -176
  30. package/tests/unit/modeling/api_model.spec.ts +17 -15
  31. package/tests/unit/modeling/data_domain_foreign.spec.ts +172 -39
@@ -42062,10 +42062,10 @@
42062
42062
  "@id": "#209"
42063
42063
  },
42064
42064
  {
42065
- "@id": "#191"
42065
+ "@id": "#194"
42066
42066
  },
42067
42067
  {
42068
- "@id": "#194"
42068
+ "@id": "#191"
42069
42069
  },
42070
42070
  {
42071
42071
  "@id": "#197"
@@ -42810,6 +42810,9 @@
42810
42810
  "@id": "#219"
42811
42811
  },
42812
42812
  {
42813
+ "@id": "#219"
42814
+ },
42815
+ {
42813
42816
  "@id": "#210"
42814
42817
  },
42815
42818
  {
@@ -42817,9 +42820,6 @@
42817
42820
  },
42818
42821
  {
42819
42822
  "@id": "#213"
42820
- },
42821
- {
42822
- "@id": "#219"
42823
42823
  }
42824
42824
  ],
42825
42825
  "doc:root": false,
@@ -43436,7 +43436,7 @@
43436
43436
  "doc:ExternalDomainElement",
43437
43437
  "doc:DomainElement"
43438
43438
  ],
43439
- "doc:raw": "countryCode: \"BE\"\ngraydonEnterpriseId: 1057155523\nregistrationId: \"0422319093\"\nvatNumber: \"BE0422319093\"\ngraydonCompanyId: \"0422319093\"\nisBranchOffice: false\n",
43439
+ "doc:raw": "addressType: 'REGISTERED-OFFICE-ADDRESS'\nstreetName: 'UITBREIDINGSTRAAT'\nhouseNumber: '84'\nhouseNumberAddition: '/1'\npostalCode: '2600'\ncity: 'BERCHEM (ANTWERPEN)'\ncountry: 'Belgium'\ncountryCode: 'BE'\nfullFormatedAddress: \"UITBREIDINGSTRAAT 84 /1, 2600 BERCHEM (ANTWERPEN), BELIUM\"\n",
43440
43440
  "core:mediaType": "application/yaml",
43441
43441
  "sourcemaps:sources": [
43442
43442
  {
@@ -43457,7 +43457,7 @@
43457
43457
  "doc:ExternalDomainElement",
43458
43458
  "doc:DomainElement"
43459
43459
  ],
43460
- "doc:raw": "addressType: 'REGISTERED-OFFICE-ADDRESS'\nstreetName: 'UITBREIDINGSTRAAT'\nhouseNumber: '84'\nhouseNumberAddition: '/1'\npostalCode: '2600'\ncity: 'BERCHEM (ANTWERPEN)'\ncountry: 'Belgium'\ncountryCode: 'BE'\nfullFormatedAddress: \"UITBREIDINGSTRAAT 84 /1, 2600 BERCHEM (ANTWERPEN), BELIUM\"\n",
43460
+ "doc:raw": "countryCode: \"BE\"\ngraydonEnterpriseId: 1057155523\nregistrationId: \"0422319093\"\nvatNumber: \"BE0422319093\"\ngraydonCompanyId: \"0422319093\"\nisBranchOffice: false\n",
43461
43461
  "core:mediaType": "application/yaml",
43462
43462
  "sourcemaps:sources": [
43463
43463
  {
@@ -44232,7 +44232,7 @@
44232
44232
  "doc:ExternalDomainElement",
44233
44233
  "doc:DomainElement"
44234
44234
  ],
44235
- "doc:raw": "type: 'GENERAL'\ncountryDialCode : '+32'\nareaCode : '22'\nsubscriberNumber: '12.87.00'\nformatted: '+32-(0)22 000000'\n",
44235
+ "doc:raw": "type: 'GENERAL'\ncountryDialCode : '+32'\nareaCode : '21'\nsubscriberNumber: '12.87.00'\nformatted: '+32-(0)21 302099'\n",
44236
44236
  "core:mediaType": "application/yaml",
44237
44237
  "sourcemaps:sources": [
44238
44238
  {
@@ -44253,7 +44253,7 @@
44253
44253
  "doc:ExternalDomainElement",
44254
44254
  "doc:DomainElement"
44255
44255
  ],
44256
- "doc:raw": "-\n type: 'GENERAL'\n value: 'info@company.be'\n-\n type: 'IT_DEPT'\n value: 'it-service@company.be'\n",
44256
+ "doc:raw": "type: \"GENERAL\"\nvalue: \"www.company.be\"\n",
44257
44257
  "core:mediaType": "application/yaml",
44258
44258
  "sourcemaps:sources": [
44259
44259
  {
@@ -44274,7 +44274,7 @@
44274
44274
  "doc:ExternalDomainElement",
44275
44275
  "doc:DomainElement"
44276
44276
  ],
44277
- "doc:raw": "type: 'GENERAL'\ncountryDialCode : '+32'\nareaCode : '21'\nsubscriberNumber: '12.87.00'\nformatted: '+32-(0)21 302099'\n",
44277
+ "doc:raw": "-\n type: 'GENERAL'\n value: 'info@company.be'\n-\n type: 'IT_DEPT'\n value: 'it-service@company.be'\n",
44278
44278
  "core:mediaType": "application/yaml",
44279
44279
  "sourcemaps:sources": [
44280
44280
  {
@@ -44295,7 +44295,7 @@
44295
44295
  "doc:ExternalDomainElement",
44296
44296
  "doc:DomainElement"
44297
44297
  ],
44298
- "doc:raw": "type: \"GENERAL\"\nvalue: \"www.company.be\"\n",
44298
+ "doc:raw": "type: 'GENERAL'\ncountryDialCode : '+32'\nareaCode : '22'\nsubscriberNumber: '12.87.00'\nformatted: '+32-(0)22 000000'\n",
44299
44299
  "core:mediaType": "application/yaml",
44300
44300
  "sourcemaps:sources": [
44301
44301
  {
@@ -44756,12 +44756,12 @@
44756
44756
  {
44757
44757
  "@id": "#193/source-map/lexical/element_0",
44758
44758
  "sourcemaps:element": "amf://id#193",
44759
- "sourcemaps:value": "[(1,0)-(7,0)]"
44759
+ "sourcemaps:value": "[(1,0)-(10,0)]"
44760
44760
  },
44761
44761
  {
44762
44762
  "@id": "#196/source-map/lexical/element_0",
44763
44763
  "sourcemaps:element": "amf://id#196",
44764
- "sourcemaps:value": "[(1,0)-(10,0)]"
44764
+ "sourcemaps:value": "[(1,0)-(7,0)]"
44765
44765
  },
44766
44766
  {
44767
44767
  "@id": "#199/source-map/lexical/element_0",
@@ -45121,17 +45121,17 @@
45121
45121
  {
45122
45122
  "@id": "#215/source-map/lexical/element_0",
45123
45123
  "sourcemaps:element": "amf://id#215",
45124
- "sourcemaps:value": "[(1,0)-(7,0)]"
45124
+ "sourcemaps:value": "[(1,0)-(3,0)]"
45125
45125
  },
45126
45126
  {
45127
45127
  "@id": "#218/source-map/lexical/element_0",
45128
45128
  "sourcemaps:element": "amf://id#218",
45129
- "sourcemaps:value": "[(1,0)-(6,0)]"
45129
+ "sourcemaps:value": "[(1,0)-(7,0)]"
45130
45130
  },
45131
45131
  {
45132
45132
  "@id": "#221/source-map/lexical/element_0",
45133
45133
  "sourcemaps:element": "amf://id#221",
45134
- "sourcemaps:value": "[(1,0)-(3,0)]"
45134
+ "sourcemaps:value": "[(1,0)-(6,0)]"
45135
45135
  },
45136
45136
  {
45137
45137
  "@id": "#338/source-map/synthesized-field/element_1",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@api-client/core",
3
3
  "description": "The API Client's core client library. Works in NodeJS and in a ES enabled browser.",
4
- "version": "0.14.6",
4
+ "version": "0.14.8",
5
5
  "license": "Apache-2.0",
6
6
  "exports": {
7
7
  "./browser.js": {
@@ -15,7 +15,7 @@ import {
15
15
  IApiScalarShape,
16
16
  IShapeUnion,
17
17
  } from './definitions/Shapes.js'
18
- import { ILoremWordInit, ITypeHashInit, ITypeNumberInit } from '@pawel-up/data-mock/types.js'
18
+ import type { ILoremWordInit, ITypeHashInit, ITypeNumberInit } from '@pawel-up/data-mock/types.js'
19
19
 
20
20
  export interface IApiSchemaReadOptions {
21
21
  /**
@@ -1,18 +1,20 @@
1
1
  import { nanoid } from '../nanoid.js'
2
- import { ApiModelKind } from '../models/kinds.js'
2
+ import { ApiModelKind, DataDomainKind } from '../models/kinds.js'
3
3
  import { type IThing, Thing } from '../models/Thing.js'
4
4
  import type {
5
5
  AccessRule,
6
6
  AuthenticationConfiguration,
7
7
  AuthorizationConfiguration,
8
8
  ExposedEntity,
9
- ForeignDomainDependency,
10
9
  RateLimitingConfiguration,
10
+ RolesBasedAccessControl,
11
11
  SessionConfiguration,
12
+ UsernamePasswordConfiguration,
12
13
  } from './types.js'
13
- import { DataDomain, type DataDomainSchema } from './DataDomain.js'
14
+ import { DataDomain } from './DataDomain.js'
15
+ import { DependentModel, type DomainDependency, type DependentModelSchema } from './DependentModel.js'
14
16
 
15
- export interface ApiModelSchema {
17
+ export interface ApiModelSchema extends DependentModelSchema {
16
18
  /**
17
19
  * The data domain kind recognizable by the ecosystem.
18
20
  */
@@ -35,12 +37,6 @@ export interface ApiModelSchema {
35
37
  */
36
38
  userKey?: string
37
39
 
38
- /**
39
- * Reference to the stable, version-controlled data definition from the
40
- * Data Catalog. When not set, the model cannot be published.
41
- */
42
- domain?: ForeignDomainDependency
43
-
44
40
  /**
45
41
  * Configuration for how users prove their identity.
46
42
  * The API model is invalid if this is not set.
@@ -80,7 +76,7 @@ export interface ApiModelSchema {
80
76
  rateLimiting?: RateLimitingConfiguration
81
77
  }
82
78
 
83
- export class ApiModel extends EventTarget {
79
+ export class ApiModel extends DependentModel {
84
80
  /**
85
81
  * The data domain kind recognizable by the ecosystem.
86
82
  */
@@ -103,12 +99,6 @@ export class ApiModel extends EventTarget {
103
99
  */
104
100
  userKey?: string
105
101
 
106
- /**
107
- * Reference to the stable, version-controlled data definition from the
108
- * Data Catalog. When not set, the model cannot be published.
109
- */
110
- domain?: ForeignDomainDependency
111
-
112
102
  /**
113
103
  * Configuration for how users prove their identity.
114
104
  * The API model is invalid if this is not set.
@@ -161,9 +151,20 @@ export class ApiModel extends EventTarget {
161
151
  #notifying = false
162
152
 
163
153
  /**
164
- * A reference to the published data domain.
154
+ * A convenience getter that returns the DataDomain associated with this API model.
155
+ * Since the API model can have only one DataDomain,
156
+ * this getter returns the first dependency in the list.
157
+ *
158
+ * The parent interface `DependentModel` allows for multiple dependencies,
159
+ * to unify the dependency management across different models.
165
160
  */
166
- dataDomain?: DataDomain
161
+ get domain(): DataDomain | undefined {
162
+ if (this.dependencyList.length === 0) {
163
+ return undefined
164
+ }
165
+ const domain = this.dependencyList[0]
166
+ return this.dependencies.get(domain.key)
167
+ }
167
168
 
168
169
  static createSchema(input: Partial<ApiModelSchema> = {}): ApiModelSchema {
169
170
  const { key = nanoid(), exposes = [] } = input
@@ -177,8 +178,8 @@ export class ApiModel extends EventTarget {
177
178
  if (input.userKey) {
178
179
  result.userKey = input.userKey
179
180
  }
180
- if (input.domain) {
181
- result.domain = input.domain
181
+ if (input.dependencyList) {
182
+ result.dependencyList = structuredClone(input.dependencyList)
182
183
  }
183
184
  if (input.authentication) {
184
185
  result.authentication = input.authentication
@@ -198,16 +199,21 @@ export class ApiModel extends EventTarget {
198
199
  return result
199
200
  }
200
201
 
201
- constructor(state?: Partial<ApiModelSchema>, domain?: DataDomainSchema) {
202
- super()
202
+ constructor(state?: Partial<ApiModelSchema>, domain?: DomainDependency) {
203
203
  const init = ApiModel.createSchema(state)
204
+ const instances: DataDomain[] = []
205
+ if (domain instanceof DataDomain) {
206
+ instances.push(domain)
207
+ } else if (typeof domain === 'object' && domain.kind === DataDomainKind) {
208
+ instances.push(new DataDomain(domain))
209
+ } else if (domain) {
210
+ throw new Error(`Invalid domain provided. Expected a DataDomain instance or schema.`)
211
+ }
212
+ super(init.dependencyList, instances)
204
213
  this.kind = init.kind
205
214
  this.key = init.key
206
215
  this.info = new Thing(init.info)
207
216
  this.userKey = init.userKey
208
- if (init.domain) {
209
- this.domain = structuredClone(init.domain)
210
- }
211
217
  if (init.authentication) {
212
218
  this.authentication = structuredClone(init.authentication)
213
219
  }
@@ -228,9 +234,6 @@ export class ApiModel extends EventTarget {
228
234
  if (init.rateLimiting) {
229
235
  this.rateLimiting = structuredClone(init.rateLimiting)
230
236
  }
231
- if (domain) {
232
- this.dataDomain = new DataDomain(domain)
233
- }
234
237
  this.#initializing = false
235
238
  this.info.addEventListener('change', () => {
236
239
  this.notifyChange()
@@ -247,8 +250,8 @@ export class ApiModel extends EventTarget {
247
250
  if (this.userKey) {
248
251
  result.userKey = this.userKey
249
252
  }
250
- if (this.domain) {
251
- result.domain = structuredClone(this.domain)
253
+ if (this.dependencyList.length > 0) {
254
+ result.dependencyList = structuredClone(this.dependencyList)
252
255
  }
253
256
  if (this.authentication) {
254
257
  result.authentication = structuredClone(this.authentication)
@@ -324,4 +327,44 @@ export class ApiModel extends EventTarget {
324
327
  getExposedEntity(entityKey: string): ExposedEntity | undefined {
325
328
  return this.exposes.find((e) => e.key === entityKey)
326
329
  }
330
+
331
+ /**
332
+ * Clears the API model for a new entity change.
333
+ * This method resets the dependencies, exposes, userKey,
334
+ * authentication, authorization, and session properties.
335
+ */
336
+ cleanForEntityChange(): void {
337
+ this.dependencies.clear()
338
+ this.dependencyList = []
339
+ this.exposes = []
340
+ this.userKey = undefined
341
+ if (this.session) {
342
+ this.session.properties = []
343
+ }
344
+ if (this.authentication && this.authentication.strategy === 'UsernamePassword') {
345
+ const typed = this.authentication as UsernamePasswordConfiguration
346
+ typed.passwordKey = undefined
347
+ }
348
+ if (this.authorization && this.authorization.strategy == 'RBAC') {
349
+ const typed = this.authorization as RolesBasedAccessControl
350
+ typed.roleKey = ''
351
+ }
352
+ }
353
+
354
+ /**
355
+ * Attaches a DataDomain to this API model.
356
+ * This method clears any existing dependencies and sets the new domain.
357
+ *
358
+ * @param domain The DataDomain to attach to this API model.
359
+ * @throws Error if the domain does not have a version set in its info.
360
+ */
361
+ attachDataDomain(domain: DataDomain): void {
362
+ if (!domain.info.version) {
363
+ throw new Error(`Cannot attach DataDomain without a version. Please set the version in the domain info.`)
364
+ }
365
+ this.cleanForEntityChange()
366
+ this.dependencies.set(domain.key, domain)
367
+ this.dependencyList = [{ key: domain.key, version: domain.info.version }]
368
+ this.notifyChange()
369
+ }
327
370
  }
@@ -8,13 +8,7 @@ import {
8
8
  DomainNamespaceKind,
9
9
  DomainPropertyKind,
10
10
  } from '../models/kinds.js'
11
- import type {
12
- AssociationAddOptions,
13
- DomainGraphEdge,
14
- DomainGraphNodeType,
15
- ForeignDomainDependency,
16
- SerializedGraph,
17
- } from './types.js'
11
+ import type { AssociationAddOptions, DomainGraphEdge, DomainGraphNodeType, SerializedGraph } from './types.js'
18
12
  import { type DomainNamespaceSchema, DomainNamespace, type NamespaceOrderedItem } from './DomainNamespace.js'
19
13
  import { type DomainModelSchema, DomainModel } from './DomainModel.js'
20
14
  import { type DomainEntitySchema, DomainEntity } from './DomainEntity.js'
@@ -23,13 +17,13 @@ import { DomainProperty, DomainPropertySchema } from './DomainProperty.js'
23
17
  import { type IThing, Thing } from '../models/Thing.js'
24
18
  import { removeGraphNode } from './GraphUtils.js'
25
19
  import { serialize, deserialize, mergeGraph, removeForeignGraph } from './DomainSerialization.js'
20
+ import { DependentModel, type DependentModelSchema, type DomainDependency } from './DependentModel.js'
26
21
 
27
- export interface DataDomainSchema {
22
+ export interface DataDomainSchema extends DependentModelSchema {
28
23
  info: IThing
29
24
  kind: typeof DataDomainKind
30
25
  key: string
31
26
  graph?: SerializedGraph
32
- dependencyList?: ForeignDomainDependency[]
33
27
  /**
34
28
  * The ordered list of fields (namespace and models) in the schema.
35
29
  * These only keep references to define the order of these properties
@@ -104,7 +98,7 @@ export interface DataDomainSchema {
104
98
  * @todo: Implement a mechanism to move an entity to a new
105
99
  * parent model.
106
100
  */
107
- export class DataDomain extends EventTarget {
101
+ export class DataDomain extends DependentModel {
108
102
  /**
109
103
  * The kind of the domain element.
110
104
  */
@@ -119,18 +113,6 @@ export class DataDomain extends EventTarget {
119
113
  */
120
114
  graph: Graph<unknown, DomainGraphNodeType, DomainGraphEdge>
121
115
 
122
- /**
123
- * A map of foreign data domains.
124
- * Key: The unique identifier of the foreign domain.
125
- * Value: The foreign DataDomain instance.
126
- */
127
- dependencies: Map<string, DataDomain> = new Map<string, DataDomain>()
128
-
129
- /**
130
- * The list of foreign domain dependencies.
131
- */
132
- dependencyList: ForeignDomainDependency[] = []
133
-
134
116
  /**
135
117
  * The description of the domain property.
136
118
  */
@@ -196,13 +178,24 @@ export class DataDomain extends EventTarget {
196
178
  * @param state The previously serialized state of the graph.
197
179
  * @param dependencies An array of foreign data domains to register with this domain.
198
180
  */
199
- constructor(state?: Partial<DataDomainSchema>, dependencies?: DataDomain[]) {
200
- super()
181
+ constructor(state?: Partial<DataDomainSchema>, dependencies: DomainDependency[] = []) {
201
182
  const init = DataDomain.createSchema(state)
183
+ const instances: DataDomain[] = []
184
+ for (const dep of dependencies) {
185
+ if (dep instanceof DataDomain) {
186
+ instances.push(dep)
187
+ } else if (typeof dep === 'object' && dep.kind === DataDomainKind && dep.key) {
188
+ const domain = new DataDomain(dep)
189
+ instances.push(domain)
190
+ } else {
191
+ throw new Error(`Invalid foreign domain dependency: ${dep}`)
192
+ }
193
+ }
194
+ super(init.dependencyList, instances)
202
195
  this.kind = init.kind
203
196
  this.key = init.key
204
197
  this.info = new Thing(init.info)
205
- this.graph = deserialize(this, init.graph, dependencies)
198
+ this.graph = deserialize(this, init.graph, instances)
206
199
  if (Array.isArray(init.fields)) {
207
200
  this.fields = [...init.fields]
208
201
  } else {
@@ -438,10 +431,41 @@ export class DataDomain extends EventTarget {
438
431
  }
439
432
  }
440
433
 
434
+ /**
435
+ * Builds a reference key for a domain object.
436
+ *
437
+ * If the namespace is provided and it is different from the domain key,
438
+ * it will return the key in the format `namespace:key`. The foreign namespace
439
+ * must be registered in the domain's dependencies otherwise an error will be thrown.
440
+ *
441
+ * @param key The key of the namespace or model.
442
+ * @param namespace The namespace to search in. When different from the domain key, it looks for a foreign namespace.
443
+ * @returns The reference key in the format `namespace:key` or just `key` if no namespace is provided.
444
+ * @throws Error When the foreign domain is not found.
445
+ * @example
446
+ * ```typescript
447
+ * const refKey = dataDomain.buildReferenceKey('userModel', 'domainKey');
448
+ * ```
449
+ */
450
+ buildReferenceKey(key: string, namespace?: string): string {
451
+ if (namespace && namespace !== this.key) {
452
+ if (typeof namespace !== 'string' || namespace.length === 0) {
453
+ throw new Error(`Invalid namespace key. Expected a string, got ${typeof namespace}`)
454
+ }
455
+ const foreignDomain = this.dependencies.get(namespace)
456
+ if (!foreignDomain) {
457
+ throw new Error(`Foreign domain ${namespace} not found`)
458
+ }
459
+ return `${namespace}:${key}`
460
+ }
461
+ return key
462
+ }
463
+
441
464
  /**
442
465
  * Finds a namespace by its key.
443
466
  *
444
467
  * @param key The key of the namespace to find.
468
+ * @param namespace The namespace to search in. When different from the domain key, it looks for a foreign namespace.
445
469
  * @returns The namespace instance or undefined if not
446
470
  * found.
447
471
  * @example
@@ -452,8 +476,8 @@ export class DataDomain extends EventTarget {
452
476
  * }
453
477
  * ```
454
478
  */
455
- findNamespace(key: string): DomainNamespace | undefined {
456
- const result = this.graph.node(key) as DomainNamespace | undefined
479
+ findNamespace(key: string, namespace?: string): DomainNamespace | undefined {
480
+ const result = this.graph.node(this.buildReferenceKey(key, namespace)) as DomainNamespace | undefined
457
481
  if (result && result.kind === DomainNamespaceKind) {
458
482
  return result
459
483
  }
@@ -696,6 +720,7 @@ export class DataDomain extends EventTarget {
696
720
  * Finds a data model by its key.
697
721
  *
698
722
  * @param key The key of the data model to find.
723
+ * @param namespace The namespace to search in. When different from the domain key, it looks for a foreign entity.
699
724
  * @returns The data model instance or undefined if not
700
725
  * found.
701
726
  * @example
@@ -706,8 +731,8 @@ export class DataDomain extends EventTarget {
706
731
  * }
707
732
  * ```
708
733
  */
709
- findModel(key: string): DomainModel | undefined {
710
- const value = this.graph.node(key) as DomainModel | undefined
734
+ findModel(key: string, namespace?: string): DomainModel | undefined {
735
+ const value = this.graph.node(this.buildReferenceKey(key, namespace)) as DomainModel | undefined
711
736
  if (value && value.kind === DomainModelKind) {
712
737
  return value
713
738
  }
@@ -884,6 +909,7 @@ export class DataDomain extends EventTarget {
884
909
  * Finds an entity by its key.
885
910
  *
886
911
  * @param key The key of the entity to find.
912
+ * @param namespace The namespace to search in. When different from the domain key, it looks for a foreign entity.
887
913
  * @returns The entity instance or undefined if not found.
888
914
  * @example
889
915
  * ```typescript
@@ -893,8 +919,8 @@ export class DataDomain extends EventTarget {
893
919
  * }
894
920
  * ```
895
921
  */
896
- findEntity(key: string): DomainEntity | undefined {
897
- const node = this.graph.node(key) as DomainEntity | undefined
922
+ findEntity(key: string, namespace?: string): DomainEntity | undefined {
923
+ const node = this.graph.node(this.buildReferenceKey(key, namespace)) as DomainEntity | undefined
898
924
  if (node && node.kind === DomainEntityKind) {
899
925
  return node
900
926
  }
@@ -1012,6 +1038,7 @@ export class DataDomain extends EventTarget {
1012
1038
  * Finds an association by its key.
1013
1039
  *
1014
1040
  * @param key The key of the association to find.
1041
+ * @param namespace The namespace to search in. When different from the domain key, it looks for a foreign association
1015
1042
  * @returns The association instance or undefined if not
1016
1043
  * found.
1017
1044
  * @example
@@ -1022,8 +1049,8 @@ export class DataDomain extends EventTarget {
1022
1049
  * }
1023
1050
  * ```
1024
1051
  */
1025
- findAssociation(key: string): DomainAssociation | undefined {
1026
- const node = this.graph.node(key) as DomainAssociation | undefined
1052
+ findAssociation(key: string, namespace?: string): DomainAssociation | undefined {
1053
+ const node = this.graph.node(this.buildReferenceKey(key, namespace)) as DomainAssociation | undefined
1027
1054
  if (node && node.kind === DomainAssociationKind) {
1028
1055
  return node
1029
1056
  }
@@ -1097,6 +1124,7 @@ export class DataDomain extends EventTarget {
1097
1124
  * Finds a property by its key.
1098
1125
  *
1099
1126
  * @param key The key of the property to find.
1127
+ * @param namespace The namespace to search in. When different from the domain key, it looks for a foreign property
1100
1128
  * @returns The property instance or undefined if not
1101
1129
  * found.
1102
1130
  * @example
@@ -1107,8 +1135,8 @@ export class DataDomain extends EventTarget {
1107
1135
  * }
1108
1136
  * ```
1109
1137
  */
1110
- findProperty(key: string): DomainProperty | undefined {
1111
- const node = this.graph.node(key) as DomainProperty | undefined
1138
+ findProperty(key: string, namespace?: string): DomainProperty | undefined {
1139
+ const node = this.graph.node(this.buildReferenceKey(key, namespace)) as DomainProperty | undefined
1112
1140
  if (node && node.kind === DomainPropertyKind) {
1113
1141
  return node
1114
1142
  }
@@ -1182,6 +1210,8 @@ export class DataDomain extends EventTarget {
1182
1210
  * console.log(foreignUser.key);
1183
1211
  * }
1184
1212
  * ```
1213
+ * @deprecated Use `findEntity` with the `namespace` parameter instead.
1214
+ * This method is kept for backward compatibility but will be removed in the future.
1185
1215
  */
1186
1216
  findForeignEntity(entityKey: string, domainKey: string): DomainEntity | undefined {
1187
1217
  const foreignDomain = this.dependencies.get(domainKey)
@@ -0,0 +1,36 @@
1
+ import type { DataDomain, DataDomainSchema } from './DataDomain.js'
2
+ import type { ForeignDomainDependency } from './types.js'
3
+
4
+ export type DomainDependency = DataDomain | DataDomainSchema
5
+
6
+ export interface DependentModelSchema {
7
+ /**
8
+ * A list of foreign domain dependencies.
9
+ */
10
+ dependencyList?: ForeignDomainDependency[]
11
+ }
12
+
13
+ /**
14
+ * A base model that has dependencies on foreign data domains.
15
+ */
16
+ export class DependentModel extends EventTarget {
17
+ /**
18
+ * A map of foreign data domains.
19
+ * Key: The unique identifier of the foreign domain.
20
+ * Value: The foreign DataDomain instance.
21
+ */
22
+ dependencies: Map<string, DataDomain> = new Map<string, DataDomain>()
23
+
24
+ /**
25
+ * The list of foreign domain dependencies.
26
+ */
27
+ dependencyList: ForeignDomainDependency[] = []
28
+
29
+ constructor(items: ForeignDomainDependency[] = [], instances: DataDomain[] = []) {
30
+ super()
31
+ this.dependencyList = [...items]
32
+ for (const dep of instances) {
33
+ this.dependencies.set(dep.key, dep)
34
+ }
35
+ }
36
+ }
@@ -337,6 +337,8 @@ export interface SessionConfiguration {
337
337
  /**
338
338
  * The properties from the `User` entity to be encoded into the session payload (JWT/cookie).
339
339
  * These properties become available in the `request.auth` object at runtime.
340
+ *
341
+ * In practice, these are the ids of the properties in the `User` entity.
340
342
  */
341
343
  properties: string[]
342
344
  /**