@api-client/core 0.18.1 → 0.18.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.
- 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 -1
- package/build/src/index.d.ts.map +1 -1
- package/build/src/index.js.map +1 -1
- package/build/src/modeling/ApiModel.d.ts +60 -6
- package/build/src/modeling/ApiModel.d.ts.map +1 -1
- package/build/src/modeling/ApiModel.js +347 -277
- package/build/src/modeling/ApiModel.js.map +1 -1
- package/build/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/modeling/ApiModel.ts +96 -11
- package/tests/unit/modeling/api_model.spec.ts +38 -9
package/package.json
CHANGED
package/src/modeling/ApiModel.ts
CHANGED
|
@@ -3,6 +3,7 @@ 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
|
+
AssociationTarget,
|
|
6
7
|
AuthenticationConfiguration,
|
|
7
8
|
AuthorizationConfiguration,
|
|
8
9
|
ExposedEntity,
|
|
@@ -12,7 +13,40 @@ import type {
|
|
|
12
13
|
UsernamePasswordConfiguration,
|
|
13
14
|
} from './types.js'
|
|
14
15
|
import { DataDomain } from './DataDomain.js'
|
|
15
|
-
import { DependentModel, type
|
|
16
|
+
import { DependentModel, type DependentModelSchema, type DomainDependency } from './DependentModel.js'
|
|
17
|
+
import { observed, toRaw } from './observed.js'
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Contact information for the exposed API.
|
|
21
|
+
*/
|
|
22
|
+
export interface ApiContact {
|
|
23
|
+
/**
|
|
24
|
+
* The identifying name of the contact person/organization.
|
|
25
|
+
*/
|
|
26
|
+
name?: string
|
|
27
|
+
/**
|
|
28
|
+
* The URL pointing to the contact information. MUST be in the format of a URL.
|
|
29
|
+
*/
|
|
30
|
+
url?: string
|
|
31
|
+
/**
|
|
32
|
+
* The email address of the contact person/organization. MUST be in the format of an email address.
|
|
33
|
+
*/
|
|
34
|
+
email?: string
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* License information for the exposed API.
|
|
39
|
+
*/
|
|
40
|
+
export interface ApiLicense {
|
|
41
|
+
/**
|
|
42
|
+
* The license name used for the API. It is recommended to be an SPDX license identifier.
|
|
43
|
+
*/
|
|
44
|
+
name: string
|
|
45
|
+
/**
|
|
46
|
+
* A URL to the license used for the API. MUST be in the format of a URL.
|
|
47
|
+
*/
|
|
48
|
+
url?: string
|
|
49
|
+
}
|
|
16
50
|
|
|
17
51
|
export interface ApiModelSchema extends DependentModelSchema {
|
|
18
52
|
/**
|
|
@@ -31,11 +65,11 @@ export interface ApiModelSchema extends DependentModelSchema {
|
|
|
31
65
|
|
|
32
66
|
/**
|
|
33
67
|
* The designated Data Entity that represents a "User".
|
|
34
|
-
* This entity
|
|
68
|
+
* This entity should be marked with the "User" semantic in the Data Modeler.
|
|
35
69
|
*
|
|
36
70
|
* This property is required to publish the API.
|
|
37
71
|
*/
|
|
38
|
-
|
|
72
|
+
user?: AssociationTarget
|
|
39
73
|
|
|
40
74
|
/**
|
|
41
75
|
* Configuration for how users prove their identity.
|
|
@@ -74,6 +108,18 @@ export interface ApiModelSchema extends DependentModelSchema {
|
|
|
74
108
|
* Defines rules to protect the API from overuse.
|
|
75
109
|
*/
|
|
76
110
|
rateLimiting?: RateLimitingConfiguration
|
|
111
|
+
/**
|
|
112
|
+
* A URL to the Terms of Service for the API.
|
|
113
|
+
*/
|
|
114
|
+
termsOfService?: string
|
|
115
|
+
/**
|
|
116
|
+
* The contact information for the exposed API.
|
|
117
|
+
*/
|
|
118
|
+
contact?: ApiContact
|
|
119
|
+
/**
|
|
120
|
+
* The license information for the API.
|
|
121
|
+
*/
|
|
122
|
+
license?: ApiLicense
|
|
77
123
|
}
|
|
78
124
|
|
|
79
125
|
export class ApiModel extends DependentModel {
|
|
@@ -97,7 +143,7 @@ export class ApiModel extends DependentModel {
|
|
|
97
143
|
*
|
|
98
144
|
* This property is required to publish the API.
|
|
99
145
|
*/
|
|
100
|
-
|
|
146
|
+
user?: AssociationTarget
|
|
101
147
|
|
|
102
148
|
/**
|
|
103
149
|
* Configuration for how users prove their identity.
|
|
@@ -135,6 +181,18 @@ export class ApiModel extends DependentModel {
|
|
|
135
181
|
* Defines rules to protect the API from overuse.
|
|
136
182
|
*/
|
|
137
183
|
rateLimiting?: RateLimitingConfiguration
|
|
184
|
+
/**
|
|
185
|
+
* A URL to the Terms of Service for the API.
|
|
186
|
+
*/
|
|
187
|
+
@observed() accessor termsOfService: string | undefined
|
|
188
|
+
/**
|
|
189
|
+
* The contact information for the exposed API.
|
|
190
|
+
*/
|
|
191
|
+
@observed({ deep: true }) accessor contact: ApiContact | undefined
|
|
192
|
+
/**
|
|
193
|
+
* The license information for the API.
|
|
194
|
+
*/
|
|
195
|
+
@observed({ deep: true }) accessor license: ApiLicense | undefined
|
|
138
196
|
|
|
139
197
|
/**
|
|
140
198
|
* When the initializing flag is set to true,
|
|
@@ -175,8 +233,8 @@ export class ApiModel extends DependentModel {
|
|
|
175
233
|
info,
|
|
176
234
|
exposes,
|
|
177
235
|
}
|
|
178
|
-
if (input.
|
|
179
|
-
result.
|
|
236
|
+
if (input.user) {
|
|
237
|
+
result.user = { ...input.user }
|
|
180
238
|
}
|
|
181
239
|
if (input.dependencyList) {
|
|
182
240
|
result.dependencyList = structuredClone(input.dependencyList)
|
|
@@ -196,6 +254,15 @@ export class ApiModel extends DependentModel {
|
|
|
196
254
|
if (input.rateLimiting) {
|
|
197
255
|
result.rateLimiting = input.rateLimiting
|
|
198
256
|
}
|
|
257
|
+
if (input.termsOfService) {
|
|
258
|
+
result.termsOfService = input.termsOfService
|
|
259
|
+
}
|
|
260
|
+
if (input.contact) {
|
|
261
|
+
result.contact = structuredClone(input.contact)
|
|
262
|
+
}
|
|
263
|
+
if (input.license) {
|
|
264
|
+
result.license = structuredClone(input.license)
|
|
265
|
+
}
|
|
199
266
|
return result
|
|
200
267
|
}
|
|
201
268
|
|
|
@@ -213,7 +280,7 @@ export class ApiModel extends DependentModel {
|
|
|
213
280
|
this.kind = init.kind
|
|
214
281
|
this.key = init.key
|
|
215
282
|
this.info = new Thing(init.info)
|
|
216
|
-
this.
|
|
283
|
+
this.user = init.user
|
|
217
284
|
if (init.authentication) {
|
|
218
285
|
this.authentication = structuredClone(init.authentication)
|
|
219
286
|
}
|
|
@@ -234,6 +301,15 @@ export class ApiModel extends DependentModel {
|
|
|
234
301
|
if (init.rateLimiting) {
|
|
235
302
|
this.rateLimiting = structuredClone(init.rateLimiting)
|
|
236
303
|
}
|
|
304
|
+
if (init.termsOfService) {
|
|
305
|
+
this.termsOfService = init.termsOfService
|
|
306
|
+
}
|
|
307
|
+
if (init.contact) {
|
|
308
|
+
this.contact = init.contact
|
|
309
|
+
}
|
|
310
|
+
if (init.license) {
|
|
311
|
+
this.license = init.license
|
|
312
|
+
}
|
|
237
313
|
this.#initializing = false
|
|
238
314
|
this.info.addEventListener('change', () => {
|
|
239
315
|
this.notifyChange()
|
|
@@ -247,8 +323,8 @@ export class ApiModel extends DependentModel {
|
|
|
247
323
|
info: this.info.toJSON(),
|
|
248
324
|
exposes: structuredClone(this.exposes),
|
|
249
325
|
}
|
|
250
|
-
if (this.
|
|
251
|
-
result.
|
|
326
|
+
if (this.user) {
|
|
327
|
+
result.user = { ...this.user }
|
|
252
328
|
}
|
|
253
329
|
if (this.dependencyList.length > 0) {
|
|
254
330
|
result.dependencyList = structuredClone(this.dependencyList)
|
|
@@ -268,6 +344,15 @@ export class ApiModel extends DependentModel {
|
|
|
268
344
|
if (this.rateLimiting) {
|
|
269
345
|
result.rateLimiting = structuredClone(this.rateLimiting)
|
|
270
346
|
}
|
|
347
|
+
if (this.termsOfService) {
|
|
348
|
+
result.termsOfService = this.termsOfService
|
|
349
|
+
}
|
|
350
|
+
if (this.contact) {
|
|
351
|
+
result.contact = structuredClone(toRaw(this, this.contact))
|
|
352
|
+
}
|
|
353
|
+
if (this.license) {
|
|
354
|
+
result.license = structuredClone(toRaw(this, this.license))
|
|
355
|
+
}
|
|
271
356
|
return result
|
|
272
357
|
}
|
|
273
358
|
|
|
@@ -330,14 +415,14 @@ export class ApiModel extends DependentModel {
|
|
|
330
415
|
|
|
331
416
|
/**
|
|
332
417
|
* Clears the API model for a new entity change.
|
|
333
|
-
* This method resets the dependencies, exposes,
|
|
418
|
+
* This method resets the dependencies, exposes, user,
|
|
334
419
|
* authentication, authorization, and session properties.
|
|
335
420
|
*/
|
|
336
421
|
cleanForEntityChange(): void {
|
|
337
422
|
this.dependencies.clear()
|
|
338
423
|
this.dependencyList = []
|
|
339
424
|
this.exposes = []
|
|
340
|
-
this.
|
|
425
|
+
this.user = undefined
|
|
341
426
|
if (this.session) {
|
|
342
427
|
this.session.properties = []
|
|
343
428
|
}
|
|
@@ -6,6 +6,8 @@ import {
|
|
|
6
6
|
type RolesBasedAccessControl,
|
|
7
7
|
type ApiModelSchema,
|
|
8
8
|
type ExposedEntity,
|
|
9
|
+
type ApiContact,
|
|
10
|
+
type ApiLicense,
|
|
9
11
|
} from '../../../src/index.js'
|
|
10
12
|
|
|
11
13
|
test.group('ApiModel.createSchema()', (g) => {
|
|
@@ -19,13 +21,16 @@ test.group('ApiModel.createSchema()', (g) => {
|
|
|
19
21
|
assert.isNotEmpty(schema.key)
|
|
20
22
|
assert.deepInclude(schema.info, { name: 'Unnamed API' })
|
|
21
23
|
assert.deepEqual(schema.exposes, [])
|
|
22
|
-
assert.isUndefined(schema.
|
|
24
|
+
assert.isUndefined(schema.user)
|
|
23
25
|
assert.isUndefined(schema.dependencyList)
|
|
24
26
|
assert.isUndefined(schema.authentication)
|
|
25
27
|
assert.isUndefined(schema.authorization)
|
|
26
28
|
assert.isUndefined(schema.session)
|
|
27
29
|
assert.isUndefined(schema.accessRule)
|
|
28
30
|
assert.isUndefined(schema.rateLimiting)
|
|
31
|
+
assert.isUndefined(schema.termsOfService)
|
|
32
|
+
assert.isUndefined(schema.contact)
|
|
33
|
+
assert.isUndefined(schema.license)
|
|
29
34
|
})
|
|
30
35
|
|
|
31
36
|
test('creates a schema with provided values', ({ assert }) => {
|
|
@@ -33,13 +38,16 @@ test.group('ApiModel.createSchema()', (g) => {
|
|
|
33
38
|
key: 'test-api',
|
|
34
39
|
info: { name: 'Test API', description: 'A test API' },
|
|
35
40
|
exposes: [{ key: 'entity1', actions: [] }],
|
|
36
|
-
|
|
41
|
+
user: { key: 'user-entity' },
|
|
37
42
|
dependencyList: [{ key: 'domain1', version: '1.0.0' }],
|
|
38
43
|
authentication: { strategy: 'UsernamePassword' },
|
|
39
44
|
authorization: { strategy: 'RBAC', roleKey: 'role' } as RolesBasedAccessControl,
|
|
40
45
|
session: { secret: 'secret', properties: ['email'] },
|
|
41
46
|
accessRule: [{ type: 'public' }],
|
|
42
47
|
rateLimiting: { rules: [] },
|
|
48
|
+
termsOfService: 'https://example.com/terms',
|
|
49
|
+
contact: { name: 'John Doe', email: 'john.doe@example.com' } as ApiContact,
|
|
50
|
+
license: { name: 'MIT', url: 'https://opensource.org/licenses/MIT' } as ApiLicense,
|
|
43
51
|
}
|
|
44
52
|
const schema = ApiModel.createSchema(input)
|
|
45
53
|
|
|
@@ -47,13 +55,16 @@ test.group('ApiModel.createSchema()', (g) => {
|
|
|
47
55
|
assert.equal(schema.key, 'test-api')
|
|
48
56
|
assert.deepInclude(schema.info, { name: 'Test API', description: 'A test API' })
|
|
49
57
|
assert.deepEqual(schema.exposes, [{ key: 'entity1', actions: [] }])
|
|
50
|
-
assert.
|
|
58
|
+
assert.deepEqual(schema.user, { key: 'user-entity' })
|
|
51
59
|
assert.deepEqual(schema.dependencyList, [{ key: 'domain1', version: '1.0.0' }])
|
|
52
60
|
assert.deepEqual(schema.authentication, { strategy: 'UsernamePassword' })
|
|
53
61
|
assert.deepEqual(schema.authorization, { strategy: 'RBAC', roleKey: 'role' })
|
|
54
62
|
assert.deepEqual(schema.session, { secret: 'secret', properties: ['email'] })
|
|
55
63
|
assert.deepEqual(schema.accessRule, [{ type: 'public' }])
|
|
56
64
|
assert.deepEqual(schema.rateLimiting, { rules: [] })
|
|
65
|
+
assert.equal(schema.termsOfService, 'https://example.com/terms')
|
|
66
|
+
assert.deepEqual(schema.contact, { name: 'John Doe', email: 'john.doe@example.com' })
|
|
67
|
+
assert.deepEqual(schema.license, { name: 'MIT', url: 'https://opensource.org/licenses/MIT' })
|
|
57
68
|
})
|
|
58
69
|
|
|
59
70
|
test('creates a schema with partial info', ({ assert }) => {
|
|
@@ -79,12 +90,15 @@ test.group('ApiModel.constructor()', (g) => {
|
|
|
79
90
|
assert.isNotEmpty(model.key)
|
|
80
91
|
assert.equal(model.info.name, 'Unnamed API')
|
|
81
92
|
assert.deepEqual(model.exposes, [])
|
|
82
|
-
assert.isUndefined(model.
|
|
93
|
+
assert.isUndefined(model.user)
|
|
83
94
|
assert.isUndefined(model.authentication)
|
|
84
95
|
assert.isUndefined(model.authorization)
|
|
85
96
|
assert.isUndefined(model.session)
|
|
86
97
|
assert.isUndefined(model.accessRule)
|
|
87
98
|
assert.isUndefined(model.rateLimiting)
|
|
99
|
+
assert.isUndefined(model.termsOfService)
|
|
100
|
+
assert.isUndefined(model.contact)
|
|
101
|
+
assert.isUndefined(model.license)
|
|
88
102
|
assert.deepEqual(model.dependencyList, [])
|
|
89
103
|
})
|
|
90
104
|
|
|
@@ -94,26 +108,32 @@ test.group('ApiModel.constructor()', (g) => {
|
|
|
94
108
|
key: 'test-api',
|
|
95
109
|
info: { name: 'Test API', description: 'A test API' },
|
|
96
110
|
exposes: [{ key: 'entity1', actions: [] }],
|
|
97
|
-
|
|
111
|
+
user: { key: 'user-entity' },
|
|
98
112
|
dependencyList: [{ key: 'domain1', version: '1.0.0' }],
|
|
99
113
|
authentication: { strategy: 'UsernamePassword' },
|
|
100
114
|
authorization: { strategy: 'RBAC', roleKey: 'role' } as RolesBasedAccessControl,
|
|
101
115
|
session: { secret: 'secret', properties: ['email'] },
|
|
102
116
|
accessRule: [{ type: 'public' }],
|
|
103
117
|
rateLimiting: { rules: [] },
|
|
118
|
+
termsOfService: 'https://example.com/terms',
|
|
119
|
+
contact: { name: 'John Doe', email: 'john.doe@example.com' },
|
|
120
|
+
license: { name: 'MIT', url: 'https://opensource.org/licenses/MIT' },
|
|
104
121
|
}
|
|
105
122
|
const model = new ApiModel(schema)
|
|
106
123
|
|
|
107
124
|
assert.equal(model.key, 'test-api')
|
|
108
125
|
assert.equal(model.info.name, 'Test API')
|
|
109
126
|
assert.deepEqual(model.exposes, [{ key: 'entity1', actions: [] }])
|
|
110
|
-
assert.
|
|
127
|
+
assert.deepEqual(model.user, { key: 'user-entity' })
|
|
111
128
|
assert.deepEqual(model.dependencyList, [{ key: 'domain1', version: '1.0.0' }])
|
|
112
129
|
assert.deepEqual(model.authentication, { strategy: 'UsernamePassword' })
|
|
113
130
|
assert.deepEqual(model.authorization, { strategy: 'RBAC', roleKey: 'role' })
|
|
114
131
|
assert.deepEqual(model.session, { secret: 'secret', properties: ['email'] })
|
|
115
132
|
assert.deepEqual(model.accessRule, [{ type: 'public' }])
|
|
116
133
|
assert.deepEqual(model.rateLimiting, { rules: [] })
|
|
134
|
+
assert.equal(model.termsOfService, 'https://example.com/terms')
|
|
135
|
+
assert.deepEqual(model.contact, { name: 'John Doe', email: 'john.doe@example.com' })
|
|
136
|
+
assert.deepEqual(model.license, { name: 'MIT', url: 'https://opensource.org/licenses/MIT' })
|
|
117
137
|
})
|
|
118
138
|
|
|
119
139
|
test('creates an instance with a DataDomain', ({ assert }) => {
|
|
@@ -152,13 +172,16 @@ test.group('ApiModel.toJSON()', (g) => {
|
|
|
152
172
|
assert.equal(json.key, model.key)
|
|
153
173
|
assert.deepInclude(json.info, { name: 'Unnamed API' })
|
|
154
174
|
assert.deepEqual(json.exposes, [])
|
|
155
|
-
assert.isUndefined(json.
|
|
175
|
+
assert.isUndefined(json.user)
|
|
156
176
|
assert.isUndefined(json.dependencyList)
|
|
157
177
|
assert.isUndefined(json.authentication)
|
|
158
178
|
assert.isUndefined(json.authorization)
|
|
159
179
|
assert.isUndefined(json.session)
|
|
160
180
|
assert.isUndefined(json.accessRule)
|
|
161
181
|
assert.isUndefined(json.rateLimiting)
|
|
182
|
+
assert.isUndefined(json.termsOfService)
|
|
183
|
+
assert.isUndefined(json.contact)
|
|
184
|
+
assert.isUndefined(json.license)
|
|
162
185
|
})
|
|
163
186
|
|
|
164
187
|
test('serializes all provided values', ({ assert }) => {
|
|
@@ -167,13 +190,16 @@ test.group('ApiModel.toJSON()', (g) => {
|
|
|
167
190
|
key: 'test-api',
|
|
168
191
|
info: { name: 'Test API', description: 'A test API' },
|
|
169
192
|
exposes: [{ key: 'entity1', actions: [] }],
|
|
170
|
-
|
|
193
|
+
user: { key: 'user-entity' },
|
|
171
194
|
dependencyList: [{ key: 'domain1', version: '1.0.0' }],
|
|
172
195
|
authentication: { strategy: 'UsernamePassword' },
|
|
173
196
|
authorization: { strategy: 'RBAC', roleKey: 'role' } as RolesBasedAccessControl,
|
|
174
197
|
session: { secret: 'secret', properties: ['email'] },
|
|
175
198
|
accessRule: [{ type: 'public' }],
|
|
176
199
|
rateLimiting: { rules: [] },
|
|
200
|
+
termsOfService: 'https://example.com/terms',
|
|
201
|
+
contact: { name: 'John Doe', email: 'john.doe@example.com' },
|
|
202
|
+
license: { name: 'MIT', url: 'https://opensource.org/licenses/MIT' },
|
|
177
203
|
}
|
|
178
204
|
const model = new ApiModel(schema)
|
|
179
205
|
const json = model.toJSON()
|
|
@@ -181,13 +207,16 @@ test.group('ApiModel.toJSON()', (g) => {
|
|
|
181
207
|
assert.equal(json.key, 'test-api')
|
|
182
208
|
assert.deepInclude(json.info, { name: 'Test API', description: 'A test API' })
|
|
183
209
|
assert.deepEqual(json.exposes, [{ key: 'entity1', actions: [] }])
|
|
184
|
-
assert.
|
|
210
|
+
assert.deepEqual(json.user, { key: 'user-entity' })
|
|
185
211
|
assert.deepEqual(json.dependencyList, [{ key: 'domain1', version: '1.0.0' }])
|
|
186
212
|
assert.deepEqual(json.authentication, { strategy: 'UsernamePassword' })
|
|
187
213
|
assert.deepEqual(json.authorization, { strategy: 'RBAC', roleKey: 'role' })
|
|
188
214
|
assert.deepEqual(json.session, { secret: 'secret', properties: ['email'] })
|
|
189
215
|
assert.deepEqual(json.accessRule, [{ type: 'public' }])
|
|
190
216
|
assert.deepEqual(json.rateLimiting, { rules: [] })
|
|
217
|
+
assert.equal(json.termsOfService, 'https://example.com/terms')
|
|
218
|
+
assert.deepEqual(json.contact, { name: 'John Doe', email: 'john.doe@example.com' })
|
|
219
|
+
assert.deepEqual(json.license, { name: 'MIT', url: 'https://opensource.org/licenses/MIT' })
|
|
191
220
|
})
|
|
192
221
|
})
|
|
193
222
|
|