@api-client/core 0.14.2 → 0.14.3

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 (59) hide show
  1. package/build/src/index.d.ts +1 -0
  2. package/build/src/index.d.ts.map +1 -1
  3. package/build/src/index.js +1 -0
  4. package/build/src/index.js.map +1 -1
  5. package/build/src/modeling/ApiFile.d.ts +23 -0
  6. package/build/src/modeling/ApiFile.d.ts.map +1 -0
  7. package/build/src/modeling/ApiFile.js +44 -0
  8. package/build/src/modeling/ApiFile.js.map +1 -0
  9. package/build/src/modeling/ApiModel.d.ts +159 -0
  10. package/build/src/modeling/ApiModel.d.ts.map +1 -0
  11. package/build/src/modeling/ApiModel.js +237 -0
  12. package/build/src/modeling/ApiModel.js.map +1 -0
  13. package/build/src/modeling/DataDomain.d.ts +1 -1
  14. package/build/src/modeling/DataDomain.d.ts.map +1 -1
  15. package/build/src/modeling/DataDomain.js +1 -3
  16. package/build/src/modeling/DataDomain.js.map +1 -1
  17. package/build/src/modeling/DomainEntity.js +1 -1
  18. package/build/src/modeling/DomainEntity.js.map +1 -1
  19. package/build/src/modeling/DomainFile.d.ts +1 -2
  20. package/build/src/modeling/DomainFile.d.ts.map +1 -1
  21. package/build/src/modeling/DomainFile.js +3 -41
  22. package/build/src/modeling/DomainFile.js.map +1 -1
  23. package/build/src/modeling/Semantics.d.ts +55 -8
  24. package/build/src/modeling/Semantics.d.ts.map +1 -1
  25. package/build/src/modeling/Semantics.js +62 -8
  26. package/build/src/modeling/Semantics.js.map +1 -1
  27. package/build/src/modeling/amf/ShapeGenerator.d.ts.map +1 -1
  28. package/build/src/modeling/amf/ShapeGenerator.js.map +1 -1
  29. package/build/src/modeling/types.d.ts +491 -0
  30. package/build/src/modeling/types.d.ts.map +1 -1
  31. package/build/src/modeling/types.js.map +1 -1
  32. package/build/src/models/kinds.d.ts +2 -0
  33. package/build/src/models/kinds.d.ts.map +1 -1
  34. package/build/src/models/kinds.js +2 -0
  35. package/build/src/models/kinds.js.map +1 -1
  36. package/build/src/models/store/File.d.ts +19 -2
  37. package/build/src/models/store/File.d.ts.map +1 -1
  38. package/build/src/models/store/File.js +100 -13
  39. package/build/src/models/store/File.js.map +1 -1
  40. package/build/tsconfig.tsbuildinfo +1 -1
  41. package/data/models/example-generator-api.json +19 -19
  42. package/package.json +2 -3
  43. package/src/modeling/ApiFile.ts +53 -0
  44. package/src/modeling/ApiModel.ts +327 -0
  45. package/src/modeling/DataDomain.ts +1 -1
  46. package/src/modeling/DomainEntity.ts +1 -1
  47. package/src/modeling/DomainFile.ts +3 -40
  48. package/src/modeling/Semantics.ts +63 -8
  49. package/src/modeling/amf/ShapeGenerator.ts +1 -1
  50. package/src/modeling/types.ts +545 -0
  51. package/src/models/kinds.ts +2 -0
  52. package/src/models/store/File.ts +100 -13
  53. package/tests/unit/modeling/api_model.spec.ts +291 -0
  54. package/tests/unit/modeling/domain_entity.spec.ts +15 -15
  55. package/tests/unit/modeling/domain_file.spec.ts +1 -11
  56. package/tests/unit/modeling/domain_model_entities.spec.ts +2 -2
  57. package/tests/unit/modeling/semantics.spec.ts +8 -11
  58. package/tests/unit/models/File/constructor.spec.ts +3 -2
  59. package/tests/unit/models/File/shortcutTo.spec.ts +1 -1
@@ -42071,13 +42071,13 @@
42071
42071
  "@id": "#197"
42072
42072
  },
42073
42073
  {
42074
- "@id": "#200"
42074
+ "@id": "#206"
42075
42075
  },
42076
42076
  {
42077
- "@id": "#203"
42077
+ "@id": "#200"
42078
42078
  },
42079
42079
  {
42080
- "@id": "#206"
42080
+ "@id": "#203"
42081
42081
  },
42082
42082
  {
42083
42083
  "@id": "#209"
@@ -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": "#216"
42820
- },
42821
- {
42822
- "@id": "#219"
42823
42823
  }
42824
42824
  ],
42825
42825
  "doc:root": false,
@@ -43499,7 +43499,7 @@
43499
43499
  "doc:ExternalDomainElement",
43500
43500
  "doc:DomainElement"
43501
43501
  ],
43502
- "doc:raw": "class: '3'\ndescription: '150 - 300'\nnumberOfFte: 5500\nnumberOfEmployees: 5232\n",
43502
+ "doc:raw": "code: 'J'\ndescription: 'Information and communication'\n",
43503
43503
  "core:mediaType": "application/yaml",
43504
43504
  "sourcemaps:sources": [
43505
43505
  {
@@ -43520,7 +43520,7 @@
43520
43520
  "doc:ExternalDomainElement",
43521
43521
  "doc:DomainElement"
43522
43522
  ],
43523
- "doc:raw": "code: 'J'\ndescription: 'Information and communication'\n",
43523
+ "doc:raw": "code: '7487'\ndescription: 'Financial and insurance activities'\ntype: \"PRIMARY\"\nclassificationCode: 'BE_NACEBEL2008'\nactivityGroupCode: 'ABCDE'\n",
43524
43524
  "core:mediaType": "application/yaml",
43525
43525
  "sourcemaps:sources": [
43526
43526
  {
@@ -43541,7 +43541,7 @@
43541
43541
  "doc:ExternalDomainElement",
43542
43542
  "doc:DomainElement"
43543
43543
  ],
43544
- "doc:raw": "code: '7487'\ndescription: 'Financial and insurance activities'\ntype: \"PRIMARY\"\nclassificationCode: 'BE_NACEBEL2008'\nactivityGroupCode: 'ABCDE'\n",
43544
+ "doc:raw": "class: '3'\ndescription: '150 - 300'\nnumberOfFte: 5500\nnumberOfEmployees: 5232\n",
43545
43545
  "core:mediaType": "application/yaml",
43546
43546
  "sourcemaps:sources": [
43547
43547
  {
@@ -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": "type: 'GENERAL'\ncountryDialCode : '+32'\nareaCode : '21'\nsubscriberNumber: '12.87.00'\nformatted: '+32-(0)21 302099'\n",
44256
+ "doc:raw": "-\n type: 'GENERAL'\n value: 'info@company.be'\n-\n type: 'IT_DEPT'\n value: 'it-service@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": "-\n type: 'GENERAL'\n value: 'info@company.be'\n-\n type: 'IT_DEPT'\n value: 'it-service@company.be'\n",
44277
+ "doc:raw": "type: \"GENERAL\"\nvalue: \"www.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
  {
@@ -44771,17 +44771,17 @@
44771
44771
  {
44772
44772
  "@id": "#202/source-map/lexical/element_0",
44773
44773
  "sourcemaps:element": "amf://id#202",
44774
- "sourcemaps:value": "[(1,0)-(5,0)]"
44774
+ "sourcemaps:value": "[(1,0)-(3,0)]"
44775
44775
  },
44776
44776
  {
44777
44777
  "@id": "#205/source-map/lexical/element_0",
44778
44778
  "sourcemaps:element": "amf://id#205",
44779
- "sourcemaps:value": "[(1,0)-(3,0)]"
44779
+ "sourcemaps:value": "[(1,0)-(6,0)]"
44780
44780
  },
44781
44781
  {
44782
44782
  "@id": "#208/source-map/lexical/element_0",
44783
44783
  "sourcemaps:element": "amf://id#208",
44784
- "sourcemaps:value": "[(1,0)-(6,0)]"
44784
+ "sourcemaps:value": "[(1,0)-(5,0)]"
44785
44785
  },
44786
44786
  {
44787
44787
  "@id": "#223/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)-(6,0)]"
45124
+ "sourcemaps:value": "[(1,0)-(7,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)-(7,0)]"
45129
+ "sourcemaps:value": "[(1,0)-(3,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.2",
4
+ "version": "0.14.3",
5
5
  "license": "Apache-2.0",
6
6
  "exports": {
7
7
  "./browser.js": {
@@ -135,7 +135,7 @@
135
135
  "oauth2-mock-server": "^8.0.0",
136
136
  "playwright": "^1.50.1",
137
137
  "prettier": "^3.5.1",
138
- "sinon": "^20.0.0",
138
+ "sinon": "^21.0.0",
139
139
  "ts-lit-plugin": "^2.0.2",
140
140
  "ts-node-maintained": "^10.9.5",
141
141
  "typescript": "^5.5.2",
@@ -157,7 +157,6 @@
157
157
  "test:coverage": "wireit",
158
158
  "test:node": "node --import ts-node-maintained/register/esm --enable-source-maps bin/test.ts",
159
159
  "test:node:coverage": "c8 --reporter lcov --reporter text node --import ts-node-maintained/register/esm --enable-source-maps bin/test.ts",
160
- "test:node:watch": "node --import ts-node-maintained/register/esm --enable-source-maps bin/test.ts --watch",
161
160
  "build:api-models": "node data/model.js",
162
161
  "copy:assets": "cp -f ./oauth-popup.html ./build/oauth-popup.html",
163
162
  "start": "echo \"Use the npm run dev instead\"",
@@ -0,0 +1,53 @@
1
+ import { File, type IFile } from '../models/store/File.js'
2
+ import { ApiFileKind } from '../models/kinds.js'
3
+ import { ApiModel, ApiModelSchema } from './ApiModel.js'
4
+
5
+ export interface IApiFile extends IFile {
6
+ kind: typeof ApiFileKind
7
+ }
8
+
9
+ /**
10
+ * Used by the store. A file definition for the ApiModel.
11
+ */
12
+ export class ApiFile extends File {
13
+ override kind = ApiFileKind
14
+
15
+ static override fromName(name: string): ApiFile {
16
+ return super.fromName(name, ApiFileKind) as ApiFile
17
+ }
18
+
19
+ /**
20
+ * Creates the file definition for a DomainNamespace contents.
21
+ *
22
+ * @param input The data namespace instance or schema.
23
+ */
24
+ static fromApiModel(input: ApiModel | ApiModelSchema): ApiFile {
25
+ let final: ApiModelSchema
26
+ if (typeof (input as ApiModel).toJSON === 'function') {
27
+ final = (input as ApiModel).toJSON()
28
+ } else {
29
+ final = input as ApiModelSchema
30
+ }
31
+ return new ApiFile({ key: final.key, info: final.info })
32
+ }
33
+
34
+ constructor(state: Partial<IApiFile> = {}) {
35
+ super({ ...state, kind: ApiFileKind })
36
+ }
37
+
38
+ static isApiFile(input: unknown): boolean {
39
+ const typed = input as IApiFile
40
+ if (!input || typed.kind !== ApiFileKind) {
41
+ return false
42
+ }
43
+ return true
44
+ }
45
+
46
+ override toJSON(): IApiFile {
47
+ const result: IApiFile = {
48
+ ...super.toJSON(),
49
+ kind: ApiFileKind,
50
+ }
51
+ return result
52
+ }
53
+ }
@@ -0,0 +1,327 @@
1
+ import { nanoid } from '../nanoid.js'
2
+ import { ApiModelKind } from '../models/kinds.js'
3
+ import { type IThing, Thing } from '../models/Thing.js'
4
+ import type {
5
+ AccessRule,
6
+ AuthenticationConfiguration,
7
+ AuthorizationConfiguration,
8
+ ExposedEntity,
9
+ ForeignDomainDependency,
10
+ RateLimitingConfiguration,
11
+ SessionConfiguration,
12
+ } from './types.js'
13
+ import { DataDomain, type DataDomainSchema } from './DataDomain.js'
14
+
15
+ export interface ApiModelSchema {
16
+ /**
17
+ * The data domain kind recognizable by the ecosystem.
18
+ */
19
+ kind: typeof ApiModelKind
20
+ /**
21
+ * The unique key of the data domain schema.
22
+ * This is a stable identifier that does not change across versions.
23
+ */
24
+ key: string
25
+ /**
26
+ * Contains the name, display name, description, and the version of the data domain schema.
27
+ */
28
+ info: IThing
29
+
30
+ /**
31
+ * The designated Data Entity that represents a "User".
32
+ * This entity must be marked with the "User" semantic in the Data Modeler.
33
+ *
34
+ * This property is required to publish the API.
35
+ */
36
+ userKey?: string
37
+
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
+ /**
45
+ * Configuration for how users prove their identity.
46
+ * The API model is invalid if this is not set.
47
+ */
48
+ authentication?: AuthenticationConfiguration
49
+
50
+ /**
51
+ * Configuration for what authenticated users are allowed to do.
52
+ * The API model is invalid if this is not set.
53
+ */
54
+ authorization?: AuthorizationConfiguration
55
+
56
+ /**
57
+ * Configuration for the transport and payload of the user session.
58
+ * The API model is invalid if this is not set.
59
+ */
60
+ session?: SessionConfiguration
61
+ /**
62
+ * The specific subset of Data Entities to be exposed by this API.
63
+ * These are the entities that are included in the data domain schema.
64
+ */
65
+ exposes: ExposedEntity[]
66
+
67
+ /**
68
+ * Optional array of access rules that define the access control policies
69
+ * for the API. These rules are used to enforce security and permissions
70
+ * on the exposed entities.
71
+ *
72
+ * These rules apply to all exposed entities and actions. An API action
73
+ * can declare its own access rules, which will override these.
74
+ */
75
+ accessRule?: AccessRule[]
76
+ /**
77
+ * Optional configuration for API-wide rate limiting and throttling.
78
+ * Defines rules to protect the API from overuse.
79
+ */
80
+ rateLimiting?: RateLimitingConfiguration
81
+ }
82
+
83
+ export class ApiModel extends EventTarget {
84
+ /**
85
+ * The data domain kind recognizable by the ecosystem.
86
+ */
87
+ kind: typeof ApiModelKind
88
+ /**
89
+ * The unique key of the data domain schema.
90
+ * This is a stable identifier that does not change across versions.
91
+ */
92
+ key: string
93
+
94
+ /**
95
+ * The description of the domain property.
96
+ */
97
+ info: Thing
98
+ /**
99
+ * The designated Data Entity that represents a "User".
100
+ * This entity must be marked with the "User" semantic in the Data Modeler.
101
+ *
102
+ * This property is required to publish the API.
103
+ */
104
+ userKey?: string
105
+
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
+ /**
113
+ * Configuration for how users prove their identity.
114
+ * The API model is invalid if this is not set.
115
+ */
116
+ authentication?: AuthenticationConfiguration
117
+
118
+ /**
119
+ * Configuration for what authenticated users are allowed to do.
120
+ * The API model is invalid if this is not set.
121
+ */
122
+ authorization?: AuthorizationConfiguration
123
+
124
+ /**
125
+ * Configuration for the transport and payload of the user session.
126
+ * The API model is invalid if this is not set.
127
+ */
128
+ session?: SessionConfiguration
129
+ /**
130
+ * The specific subset of Data Entities to be exposed by this API.
131
+ * These are the entities that are included in the data domain schema.
132
+ */
133
+ exposes: ExposedEntity[]
134
+ /**
135
+ * Optional array of access rules that define the access control policies
136
+ * for the API. These rules are used to enforce security and permissions
137
+ * on the exposed entities.
138
+ *
139
+ * These rules apply to all exposed entities and actions. An API action
140
+ * can declare its own access rules, which will override these.
141
+ */
142
+ accessRule?: AccessRule[]
143
+ /**
144
+ * Optional configuration for API-wide rate limiting and throttling.
145
+ * Defines rules to protect the API from overuse.
146
+ */
147
+ rateLimiting?: RateLimitingConfiguration
148
+
149
+ /**
150
+ * When the initializing flag is set to true,
151
+ * the domain is not notified of changes.
152
+ */
153
+ #initializing = true
154
+
155
+ /**
156
+ * When the notifying flag is set to true,
157
+ * the domain is pending a notification.
158
+ * No other notifications will be sent until
159
+ * the current notification is sent.
160
+ */
161
+ #notifying = false
162
+
163
+ /**
164
+ * A reference to the published data domain.
165
+ */
166
+ dataDomain?: DataDomain
167
+
168
+ static createSchema(input: Partial<ApiModelSchema> = {}): ApiModelSchema {
169
+ const { key = nanoid(), exposes = [] } = input
170
+ const info = Thing.fromJSON(input.info, { name: 'Unnamed API' }).toJSON()
171
+ const result: ApiModelSchema = {
172
+ kind: ApiModelKind,
173
+ key,
174
+ info,
175
+ exposes,
176
+ }
177
+ if (input.userKey) {
178
+ result.userKey = input.userKey
179
+ }
180
+ if (input.domain) {
181
+ result.domain = input.domain
182
+ }
183
+ if (input.authentication) {
184
+ result.authentication = input.authentication
185
+ }
186
+ if (input.authorization) {
187
+ result.authorization = input.authorization
188
+ }
189
+ if (input.session) {
190
+ result.session = input.session
191
+ }
192
+ if (input.accessRule) {
193
+ result.accessRule = input.accessRule
194
+ }
195
+ if (input.rateLimiting) {
196
+ result.rateLimiting = input.rateLimiting
197
+ }
198
+ return result
199
+ }
200
+
201
+ constructor(state?: Partial<ApiModelSchema>, domain?: DataDomainSchema) {
202
+ super()
203
+ const init = ApiModel.createSchema(state)
204
+ this.kind = init.kind
205
+ this.key = init.key
206
+ this.info = new Thing(init.info)
207
+ this.userKey = init.userKey
208
+ if (init.domain) {
209
+ this.domain = structuredClone(init.domain)
210
+ }
211
+ if (init.authentication) {
212
+ this.authentication = structuredClone(init.authentication)
213
+ }
214
+ if (init.authorization) {
215
+ this.authorization = structuredClone(init.authorization)
216
+ }
217
+ if (init.session) {
218
+ this.session = structuredClone(init.session)
219
+ }
220
+ if (Array.isArray(init.exposes)) {
221
+ this.exposes = structuredClone(init.exposes)
222
+ } else {
223
+ this.exposes = []
224
+ }
225
+ if (init.accessRule) {
226
+ this.accessRule = structuredClone(init.accessRule)
227
+ }
228
+ if (init.rateLimiting) {
229
+ this.rateLimiting = structuredClone(init.rateLimiting)
230
+ }
231
+ if (domain) {
232
+ this.dataDomain = new DataDomain(domain)
233
+ }
234
+ this.#initializing = false
235
+ this.info.addEventListener('change', () => {
236
+ this.notifyChange()
237
+ })
238
+ }
239
+
240
+ toJSON(): ApiModelSchema {
241
+ const result: ApiModelSchema = {
242
+ kind: this.kind,
243
+ key: this.key,
244
+ info: this.info.toJSON(),
245
+ exposes: structuredClone(this.exposes),
246
+ }
247
+ if (this.userKey) {
248
+ result.userKey = this.userKey
249
+ }
250
+ if (this.domain) {
251
+ result.domain = structuredClone(this.domain)
252
+ }
253
+ if (this.authentication) {
254
+ result.authentication = structuredClone(this.authentication)
255
+ }
256
+ if (this.authorization) {
257
+ result.authorization = structuredClone(this.authorization)
258
+ }
259
+ if (this.session) {
260
+ result.session = structuredClone(this.session)
261
+ }
262
+ if (this.accessRule) {
263
+ result.accessRule = structuredClone(this.accessRule)
264
+ }
265
+ if (this.rateLimiting) {
266
+ result.rateLimiting = structuredClone(this.rateLimiting)
267
+ }
268
+ return result
269
+ }
270
+
271
+ /**
272
+ * This function is used internally by all domain elements to notify that something has changed.
273
+ * Since we want to notify listeners after the operation commits, we use microtask
274
+ * to ensure that the event is dispatched after the current operation.
275
+ */
276
+ notifyChange() {
277
+ if (this.#notifying || this.#initializing) {
278
+ return
279
+ }
280
+ this.#notifying = true
281
+ queueMicrotask(() => {
282
+ this.#notifying = false
283
+ const event = new Event('change')
284
+ this.dispatchEvent(event)
285
+ })
286
+ }
287
+
288
+ /**
289
+ * Exposes a new entity in the API model.
290
+ * If the entity already exists, it returns the existing one.
291
+ * @param entityKey The key of the entity to expose.
292
+ * @returns The exposed entity.
293
+ */
294
+ exposeEntity(entityKey: string): ExposedEntity {
295
+ const existing = this.exposes.find((e) => e.key === entityKey)
296
+ if (existing) {
297
+ return existing
298
+ }
299
+ const newEntity: ExposedEntity = {
300
+ key: entityKey,
301
+ actions: [],
302
+ }
303
+ this.exposes.push(newEntity)
304
+ this.notifyChange()
305
+ return newEntity
306
+ }
307
+
308
+ /**
309
+ * Removes an entity from the API model.
310
+ * @param entityKey The key of the entity to remove.
311
+ */
312
+ removeEntity(entityKey: string): void {
313
+ const index = this.exposes.findIndex((e) => e.key === entityKey)
314
+ if (index !== -1) {
315
+ this.exposes.splice(index, 1)
316
+ this.notifyChange()
317
+ }
318
+ }
319
+ /**
320
+ * Returns the exposed entity by its key.
321
+ * @param entityKey The key of the entity to find.
322
+ * @returns The exposed entity or undefined if not found.
323
+ */
324
+ getExposedEntity(entityKey: string): ExposedEntity | undefined {
325
+ return this.exposes.find((e) => e.key === entityKey)
326
+ }
327
+ }
@@ -134,7 +134,7 @@ export class DataDomain extends EventTarget {
134
134
  /**
135
135
  * The description of the domain property.
136
136
  */
137
- accessor info: Thing
137
+ info: Thing
138
138
 
139
139
  /**
140
140
  * When the initializing flag is set to true,
@@ -165,7 +165,7 @@ export class DomainEntity extends DomainElement {
165
165
  */
166
166
  static createSchema(input: Partial<DomainEntitySchema> = {}): DomainEntitySchema {
167
167
  const { key = nanoid(), tags, semantics, fields, deprecated } = input
168
- const info = Thing.fromJSON(input.info, { name: 'New entity' }).toJSON()
168
+ const info = Thing.fromJSON(input.info, { name: 'new_entity' }).toJSON()
169
169
  const result: DomainEntitySchema = {
170
170
  kind: DomainEntityKind,
171
171
  key,
@@ -1,6 +1,4 @@
1
- import { nanoid } from '../nanoid.js'
2
1
  import { File, type IFile } from '../models/store/File.js'
3
- import { Thing } from '../models/Thing.js'
4
2
  import type { DataDomain, DataDomainSchema } from './DataDomain.js'
5
3
  import { DomainFileKind } from '../models/kinds.js'
6
4
 
@@ -30,46 +28,11 @@ export class DomainFile extends File {
30
28
  } else {
31
29
  final = input as DataDomainSchema
32
30
  }
33
- const init: IDomainFile = {
34
- kind: DomainFileKind,
35
- key: final.key,
36
- info: { ...final.info },
37
- lastModified: { user: '', time: 0, byMe: false },
38
- parents: [],
39
- permissionIds: [],
40
- permissions: [],
41
- }
42
- return new DomainFile(init)
31
+ return new DomainFile({ key: final.key, info: final.info })
43
32
  }
44
33
 
45
- constructor(input?: string | IDomainFile) {
46
- super()
47
- let init: IDomainFile
48
- if (typeof input === 'string') {
49
- init = JSON.parse(input)
50
- } else if (typeof input === 'object') {
51
- init = input
52
- } else {
53
- init = {
54
- kind: DomainFileKind,
55
- key: nanoid(),
56
- info: Thing.fromName('').toJSON(),
57
- parents: [],
58
- permissionIds: [],
59
- permissions: [],
60
- lastModified: { user: '', time: 0, byMe: false },
61
- }
62
- }
63
- this.new(init)
64
- }
65
-
66
- override new(init: IDomainFile): this {
67
- if (!DomainFile.isDomainFile(init)) {
68
- throw new Error(`Not a data file.`)
69
- }
70
- super.new(init)
71
- this.kind = DomainFileKind
72
- return this
34
+ constructor(state: Partial<IDomainFile> = {}) {
35
+ super({ ...state, kind: DomainFileKind })
73
36
  }
74
37
 
75
38
  static isDomainFile(input: unknown): boolean {