@api-client/core 0.19.24 → 0.19.26
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/index.d.ts +3 -1
- package/build/src/index.d.ts.map +1 -1
- package/build/src/index.js +3 -1
- package/build/src/index.js.map +1 -1
- package/build/src/mocking/ModelingMock.d.ts +2 -0
- package/build/src/mocking/ModelingMock.d.ts.map +1 -1
- package/build/src/mocking/ModelingMock.js +2 -0
- package/build/src/mocking/ModelingMock.js.map +1 -1
- package/build/src/mocking/lib/Deployment.d.ts +16 -0
- package/build/src/mocking/lib/Deployment.d.ts.map +1 -0
- package/build/src/mocking/lib/Deployment.js +76 -0
- package/build/src/mocking/lib/Deployment.js.map +1 -0
- package/build/src/modeling/Bindings.d.ts +4 -0
- package/build/src/modeling/Bindings.d.ts.map +1 -1
- package/build/src/modeling/Bindings.js.map +1 -1
- package/build/src/modeling/DataFormat.d.ts +1 -1
- package/build/src/modeling/DataFormat.d.ts.map +1 -1
- package/build/src/modeling/DataFormat.js +2 -0
- package/build/src/modeling/DataFormat.js.map +1 -1
- package/build/src/modeling/DomainAssociation.d.ts +7 -0
- package/build/src/modeling/DomainAssociation.d.ts.map +1 -1
- package/build/src/modeling/DomainAssociation.js +10 -0
- package/build/src/modeling/DomainAssociation.js.map +1 -1
- package/build/src/modeling/DomainEntity.d.ts +9 -1
- package/build/src/modeling/DomainEntity.d.ts.map +1 -1
- package/build/src/modeling/DomainEntity.js +26 -1
- package/build/src/modeling/DomainEntity.js.map +1 -1
- package/build/src/modeling/ExposedEntity.d.ts +12 -1
- package/build/src/modeling/ExposedEntity.d.ts.map +1 -1
- package/build/src/modeling/ExposedEntity.js +24 -1
- package/build/src/modeling/ExposedEntity.js.map +1 -1
- package/build/src/modeling/RuntimeApiModel.d.ts +52 -0
- package/build/src/modeling/RuntimeApiModel.d.ts.map +1 -0
- package/build/src/modeling/RuntimeApiModel.js +85 -0
- package/build/src/modeling/RuntimeApiModel.js.map +1 -0
- package/build/src/modeling/actions/index.d.ts +10 -0
- package/build/src/modeling/actions/index.d.ts.map +1 -1
- package/build/src/modeling/actions/index.js +30 -0
- package/build/src/modeling/actions/index.js.map +1 -1
- package/build/src/modeling/index.d.ts.map +1 -1
- package/build/src/modeling/index.js +1 -0
- package/build/src/modeling/index.js.map +1 -1
- package/build/src/modeling/types.d.ts +25 -1
- 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/src/models/store/Deployment.d.ts +53 -16
- package/build/src/models/store/Deployment.d.ts.map +1 -1
- package/build/src/models/store/Deployment.js +92 -34
- package/build/src/models/store/Deployment.js.map +1 -1
- package/build/src/sdk/DataCatalogSdk.d.ts.map +1 -1
- package/build/src/sdk/DataCatalogSdk.js +22 -179
- package/build/src/sdk/DataCatalogSdk.js.map +1 -1
- package/build/src/sdk/DeploymentsSdk.d.ts +48 -0
- package/build/src/sdk/DeploymentsSdk.d.ts.map +1 -0
- package/build/src/sdk/DeploymentsSdk.js +94 -0
- package/build/src/sdk/DeploymentsSdk.js.map +1 -0
- package/build/src/sdk/RouteBuilder.d.ts +2 -0
- package/build/src/sdk/RouteBuilder.d.ts.map +1 -1
- package/build/src/sdk/RouteBuilder.js +6 -0
- package/build/src/sdk/RouteBuilder.js.map +1 -1
- package/build/src/sdk/Sdk.d.ts +2 -0
- package/build/src/sdk/Sdk.d.ts.map +1 -1
- package/build/src/sdk/Sdk.js +2 -0
- package/build/src/sdk/Sdk.js.map +1 -1
- package/build/src/sdk/SdkBase.d.ts +19 -1
- package/build/src/sdk/SdkBase.d.ts.map +1 -1
- package/build/src/sdk/SdkBase.js +31 -1
- package/build/src/sdk/SdkBase.js.map +1 -1
- package/build/src/sdk/SdkMock.d.ts +9 -0
- package/build/src/sdk/SdkMock.d.ts.map +1 -1
- package/build/src/sdk/SdkMock.js +73 -0
- package/build/src/sdk/SdkMock.js.map +1 -1
- package/build/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -1
- package/src/matchit.d.ts +19 -0
- package/src/mocking/ModelingMock.ts +2 -0
- package/src/mocking/lib/Deployment.ts +88 -0
- package/src/modeling/Bindings.ts +4 -0
- package/src/modeling/DataFormat.ts +4 -0
- package/src/modeling/DomainAssociation.ts +11 -0
- package/src/modeling/DomainEntity.ts +30 -1
- package/src/modeling/ExposedEntity.ts +26 -1
- package/src/modeling/RuntimeApiModel.ts +137 -0
- package/src/modeling/types.ts +26 -1
- package/src/models/kinds.ts +1 -0
- package/src/models/store/Deployment.ts +122 -45
- package/src/sdk/DataCatalogSdk.ts +22 -176
- package/src/sdk/DeploymentsSdk.ts +123 -0
- package/src/sdk/RouteBuilder.ts +8 -0
- package/src/sdk/Sdk.ts +3 -0
- package/src/sdk/SdkBase.ts +35 -3
- package/src/sdk/SdkMock.ts +103 -0
- package/tests/unit/modeling/RuntimeApiModel.spec.ts +122 -0
- package/tests/unit/modeling/actions/index.spec.ts +113 -0
- package/tests/unit/modeling/domain_asociation.spec.ts +28 -0
- package/tests/unit/modeling/domain_entity_parents.spec.ts +49 -0
- package/tests/unit/modeling/exposed_entity_actions.spec.ts +47 -0
- package/tests/unit/models/store/Deployment.spec.ts +108 -44
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.19.
|
|
4
|
+
"version": "0.19.26",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"exports": {
|
|
7
7
|
"./browser.js": {
|
|
@@ -92,6 +92,7 @@
|
|
|
92
92
|
"@pawel-up/csv": "^0.2.0",
|
|
93
93
|
"@pawel-up/data-mock": "^0.4.0",
|
|
94
94
|
"@pawel-up/jexl": "^4.0.1",
|
|
95
|
+
"@poppinss/matchit": "^3.2.0",
|
|
95
96
|
"@xmldom/xmldom": "^0.9.9",
|
|
96
97
|
"chalk": "^5.4.1",
|
|
97
98
|
"console-table-printer": "^2.11.2",
|
package/src/matchit.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
declare module '@poppinss/matchit' {
|
|
2
|
+
export interface Matcher {
|
|
3
|
+
match?: RegExp
|
|
4
|
+
cast?: (value: string) => unknown
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface RouteToken {
|
|
8
|
+
old: string
|
|
9
|
+
type: 0 | 1 | 2 | 3
|
|
10
|
+
val: string
|
|
11
|
+
end: string
|
|
12
|
+
matcher?: RegExp
|
|
13
|
+
cast?: (value: string) => unknown
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function parse(route: string, matchers?: Record<string, Matcher>): RouteToken[]
|
|
17
|
+
export function match(url: string, routes: RouteToken[][]): RouteToken[]
|
|
18
|
+
export function exec(url: string, tokens: RouteToken[], shouldDecodeParam?: boolean): Record<string, string>
|
|
19
|
+
}
|
|
@@ -9,6 +9,7 @@ import { Patch } from './lib/Patch.js'
|
|
|
9
9
|
import { DataCatalog } from './lib/DataCatalog.js'
|
|
10
10
|
import { Permission } from './lib/Permission.js'
|
|
11
11
|
import { Ai } from './lib/Ai.js'
|
|
12
|
+
import { Deployment } from './lib/Deployment.js'
|
|
12
13
|
|
|
13
14
|
export class ModelingMock {
|
|
14
15
|
faker: Faker = faker
|
|
@@ -22,4 +23,5 @@ export class ModelingMock {
|
|
|
22
23
|
dataCatalog = new DataCatalog()
|
|
23
24
|
permission = new Permission()
|
|
24
25
|
ai = new Ai()
|
|
26
|
+
deployments = new Deployment()
|
|
25
27
|
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { faker } from '@faker-js/faker'
|
|
2
|
+
import { nanoid } from '../../nanoid.js'
|
|
3
|
+
import { DeploymentEnvironment, DeploymentKind, DeploymentStatus } from '../../models/store/Deployment.js'
|
|
4
|
+
import type { DeploymentSchema } from '../../models/store/Deployment.js'
|
|
5
|
+
|
|
6
|
+
const deploymentEnvironments: DeploymentEnvironment[] = [
|
|
7
|
+
DeploymentEnvironment.PROD,
|
|
8
|
+
DeploymentEnvironment.STAGING,
|
|
9
|
+
DeploymentEnvironment.DEV,
|
|
10
|
+
] as const
|
|
11
|
+
|
|
12
|
+
export class Deployment {
|
|
13
|
+
/**
|
|
14
|
+
* Generates a random deployment object.
|
|
15
|
+
* @param init Optional values to be present in the object.
|
|
16
|
+
* @returns Random deployment object.
|
|
17
|
+
*/
|
|
18
|
+
deployment(init: Partial<DeploymentSchema> = {}): DeploymentSchema {
|
|
19
|
+
const env = init.env ?? faker.helpers.arrayElement(deploymentEnvironments)
|
|
20
|
+
let version: string | undefined
|
|
21
|
+
if (init.version !== undefined) {
|
|
22
|
+
version = init.version
|
|
23
|
+
} else if (env === DeploymentEnvironment.PROD) {
|
|
24
|
+
version = `v${faker.number.int({ min: 1, max: 5 })}`
|
|
25
|
+
} else {
|
|
26
|
+
version = undefined
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const {
|
|
30
|
+
key = nanoid(),
|
|
31
|
+
orgId = nanoid(),
|
|
32
|
+
apiId = nanoid(),
|
|
33
|
+
orgSlug = faker.internet.domainWord(),
|
|
34
|
+
apiSlug = faker.internet.domainWord(),
|
|
35
|
+
modelVersion = faker.system.semver(),
|
|
36
|
+
status = faker.helpers.arrayElement([
|
|
37
|
+
DeploymentStatus.Pending,
|
|
38
|
+
DeploymentStatus.Active,
|
|
39
|
+
DeploymentStatus.Inactive,
|
|
40
|
+
DeploymentStatus.Failed,
|
|
41
|
+
] as const),
|
|
42
|
+
createdAt = faker.date.past().getTime(),
|
|
43
|
+
updatedAt = faker.date.recent().getTime(),
|
|
44
|
+
} = init
|
|
45
|
+
|
|
46
|
+
const result: DeploymentSchema = {
|
|
47
|
+
kind: DeploymentKind,
|
|
48
|
+
key,
|
|
49
|
+
orgId,
|
|
50
|
+
apiId,
|
|
51
|
+
orgSlug,
|
|
52
|
+
apiSlug,
|
|
53
|
+
env,
|
|
54
|
+
modelVersion,
|
|
55
|
+
status,
|
|
56
|
+
createdAt,
|
|
57
|
+
updatedAt,
|
|
58
|
+
}
|
|
59
|
+
if (version !== undefined && version !== '') {
|
|
60
|
+
result.version = version
|
|
61
|
+
}
|
|
62
|
+
if (status === DeploymentStatus.Active) {
|
|
63
|
+
result.baseUri = init.baseUri ?? faker.internet.url()
|
|
64
|
+
result.portalUri = init.portalUri ?? faker.internet.url()
|
|
65
|
+
} else {
|
|
66
|
+
if (init.baseUri !== undefined) {
|
|
67
|
+
result.baseUri = init.baseUri
|
|
68
|
+
}
|
|
69
|
+
if (init.portalUri !== undefined) {
|
|
70
|
+
result.portalUri = init.portalUri
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return result
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Generates a list of random deployment objects.
|
|
78
|
+
* @param size Number of deployments to generate. Default is 25.
|
|
79
|
+
* @returns List of random deployments
|
|
80
|
+
*/
|
|
81
|
+
deployments(size = 25, init?: Partial<DeploymentSchema>): DeploymentSchema[] {
|
|
82
|
+
const result: DeploymentSchema[] = []
|
|
83
|
+
for (let i = 0; i < size; i++) {
|
|
84
|
+
result.push(this.deployment(init))
|
|
85
|
+
}
|
|
86
|
+
return result
|
|
87
|
+
}
|
|
88
|
+
}
|
package/src/modeling/Bindings.ts
CHANGED
|
@@ -147,6 +147,10 @@ export interface AssociationWebBindings {
|
|
|
147
147
|
* Whether the association is hidden in the schema (not a part of it).
|
|
148
148
|
*/
|
|
149
149
|
hidden?: boolean
|
|
150
|
+
/**
|
|
151
|
+
* When set it overrides the `name` of the property.
|
|
152
|
+
*/
|
|
153
|
+
name?: string
|
|
150
154
|
}
|
|
151
155
|
|
|
152
156
|
export type AssociationBindings = AssociationWebBindings
|
|
@@ -51,6 +51,8 @@ export type DomainPropertyAttribute =
|
|
|
51
51
|
| 'multiple'
|
|
52
52
|
| 'primary'
|
|
53
53
|
| 'index'
|
|
54
|
+
| 'unique'
|
|
55
|
+
| 'search'
|
|
54
56
|
| 'readOnly'
|
|
55
57
|
| 'writeOnly'
|
|
56
58
|
| 'deprecated'
|
|
@@ -60,6 +62,8 @@ export const DomainPropertyAttributes: DomainPropertyAttribute[] = [
|
|
|
60
62
|
'multiple',
|
|
61
63
|
'primary',
|
|
62
64
|
'index',
|
|
65
|
+
'unique',
|
|
66
|
+
'search',
|
|
63
67
|
'readOnly',
|
|
64
68
|
'writeOnly',
|
|
65
69
|
'deprecated',
|
|
@@ -394,6 +394,17 @@ export class DomainAssociation extends DomainElement {
|
|
|
394
394
|
return object.schema as AssociationWebBindings
|
|
395
395
|
}
|
|
396
396
|
|
|
397
|
+
/**
|
|
398
|
+
* Reads the web binding definition, if any.
|
|
399
|
+
* Useful for reading binding data without mutating the model when the binding
|
|
400
|
+
* is missing (unlike `getWebBinding()` which creates the binding when missing).
|
|
401
|
+
* @returns The web binding definition, if any
|
|
402
|
+
*/
|
|
403
|
+
readWebBinding(): AssociationWebBindings | undefined {
|
|
404
|
+
const object = this.bindings.find((i) => i.type === 'web') as AssociationBinding | undefined
|
|
405
|
+
return object?.schema as AssociationWebBindings | undefined
|
|
406
|
+
}
|
|
407
|
+
|
|
397
408
|
/**
|
|
398
409
|
* Returns the schema value of the binding, if any was
|
|
399
410
|
* created.
|
|
@@ -374,7 +374,7 @@ export class DomainEntity extends DomainElement {
|
|
|
374
374
|
}
|
|
375
375
|
|
|
376
376
|
/**
|
|
377
|
-
* Lists all parent entities of this entity.
|
|
377
|
+
* Lists all parent entities of this entity (only the first level).
|
|
378
378
|
*
|
|
379
379
|
* @returns A generator that yields each parent `DomainEntity`.
|
|
380
380
|
* @example
|
|
@@ -397,6 +397,35 @@ export class DomainEntity extends DomainElement {
|
|
|
397
397
|
}
|
|
398
398
|
}
|
|
399
399
|
|
|
400
|
+
/**
|
|
401
|
+
* Lists all parent entities recursively.
|
|
402
|
+
*
|
|
403
|
+
* @param direction The direction of the traversal. 'up' (default) lists from immediate parents up to the oldest.
|
|
404
|
+
* 'down' lists from the oldest parents down to the immediate parents.
|
|
405
|
+
* @returns An array of parent `DomainEntity` instances, ordered according to the requested traversal direction.
|
|
406
|
+
*/
|
|
407
|
+
listAllParents(direction: 'up' | 'down' = 'up'): DomainEntity[] {
|
|
408
|
+
const visited = new Set<string>()
|
|
409
|
+
const parents: DomainEntity[] = []
|
|
410
|
+
const queue: DomainEntity[] = [...this.listParents()]
|
|
411
|
+
|
|
412
|
+
let index = 0
|
|
413
|
+
while (index < queue.length) {
|
|
414
|
+
const parent = queue[index++]
|
|
415
|
+
if (!visited.has(parent.key)) {
|
|
416
|
+
visited.add(parent.key)
|
|
417
|
+
parents.push(parent)
|
|
418
|
+
queue.push(...parent.listParents())
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
if (direction === 'down') {
|
|
423
|
+
parents.reverse()
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
return parents
|
|
427
|
+
}
|
|
428
|
+
|
|
400
429
|
/**
|
|
401
430
|
* Adds a parent to this entity.
|
|
402
431
|
*
|
|
@@ -3,7 +3,7 @@ import { Exception } from '../exceptions/exception.js'
|
|
|
3
3
|
import { ExposedEntityKind } from '../models/kinds.js'
|
|
4
4
|
import { nanoid } from '../nanoid.js'
|
|
5
5
|
import { Action } from './actions/Action.js'
|
|
6
|
-
import { type ApiActionSchema, restoreAction } from './actions/index.js'
|
|
6
|
+
import { ActionKind, type ApiActionSchema, createActionFromKind, restoreAction } from './actions/index.js'
|
|
7
7
|
import type { ApiModel } from './ApiModel.js'
|
|
8
8
|
import { ensureLeadingSlash, joinPaths } from './helpers/endpointHelpers.js'
|
|
9
9
|
import { AccessRule } from './rules/AccessRule.js'
|
|
@@ -518,6 +518,31 @@ export class ExposedEntity extends EventTarget {
|
|
|
518
518
|
return action
|
|
519
519
|
}
|
|
520
520
|
|
|
521
|
+
/**
|
|
522
|
+
* @deprecated Use {@link addActionFromKind()} instead.
|
|
523
|
+
*/
|
|
524
|
+
addCrudAction(actionKind: ActionKind): Action {
|
|
525
|
+
return this.addActionFromKind(actionKind)
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
/**
|
|
529
|
+
* Adds an action of a given kind to the exposure.
|
|
530
|
+
*
|
|
531
|
+
* @param actionKind The kind of the action to add.
|
|
532
|
+
* @returns The added action.
|
|
533
|
+
*/
|
|
534
|
+
addActionFromKind(actionKind: ActionKind): Action {
|
|
535
|
+
if (this.actions.some((action) => action.kind === actionKind)) {
|
|
536
|
+
throw new Exception(`Action of kind "${actionKind}" already exists for this exposure`, {
|
|
537
|
+
code: 'E_ACTION_USED',
|
|
538
|
+
help: "There's no need to add an API action again.",
|
|
539
|
+
})
|
|
540
|
+
}
|
|
541
|
+
const action = createActionFromKind(this, actionKind)
|
|
542
|
+
this.actions.push(action)
|
|
543
|
+
return action
|
|
544
|
+
}
|
|
545
|
+
|
|
521
546
|
/**
|
|
522
547
|
* Scans for the indexed and search properties in the `DomainEntity`
|
|
523
548
|
* and recreates the `paginationContract` with all indexed/searched fields.
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { match, parse, exec, type RouteToken } from '@poppinss/matchit'
|
|
2
|
+
import { ApiModel, type ApiModelSchema } from './ApiModel.js'
|
|
3
|
+
import type { DataDomainSchema } from './DataDomain.js'
|
|
4
|
+
import type { ActionKind } from './actions/index.js'
|
|
5
|
+
import type { ExposedEntity } from './ExposedEntity.js'
|
|
6
|
+
import type { Action } from './actions/Action.js'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Identifies a specific exposed entity and its action kind.
|
|
10
|
+
*/
|
|
11
|
+
export interface RouteLookup {
|
|
12
|
+
exposedEntityKey: string
|
|
13
|
+
actionKind: ActionKind
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* A routing definition mapping a path to an action lookup.
|
|
18
|
+
*/
|
|
19
|
+
export interface RouteDefinition {
|
|
20
|
+
path: string
|
|
21
|
+
lookup: RouteLookup
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* A map of HTTP methods to their route definitions.
|
|
26
|
+
*/
|
|
27
|
+
export type RoutingMap = Record<string, RouteDefinition[]>
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Schema for an API Model optimized for runtime routing.
|
|
31
|
+
*/
|
|
32
|
+
export interface RuntimeApiModelSchema extends ApiModelSchema {
|
|
33
|
+
routingMap: RoutingMap
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface RuntimeResolvedAction {
|
|
37
|
+
entity: ExposedEntity
|
|
38
|
+
action: Action
|
|
39
|
+
params: Record<string, string>
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* An optimized API Model subclass designed for fast runtime lookups.
|
|
44
|
+
* It pre-compiles the RoutingMap into a radix tree for O(log N) or faster endpoint resolution.
|
|
45
|
+
*/
|
|
46
|
+
export class RuntimeApiModel extends ApiModel {
|
|
47
|
+
/**
|
|
48
|
+
* The parsed radix tree for fast routing.
|
|
49
|
+
* Method -> ParsedRoutes
|
|
50
|
+
*/
|
|
51
|
+
#routes = new Map<string, RouteToken[][]>()
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Quick map from matchit parsed route format to our RouteDefinition for returning results
|
|
55
|
+
*/
|
|
56
|
+
#definitions = new WeakMap<RouteToken[], RouteDefinition>()
|
|
57
|
+
|
|
58
|
+
constructor(schema: RuntimeApiModelSchema, domainSchema: DataDomainSchema) {
|
|
59
|
+
super(schema, domainSchema)
|
|
60
|
+
|
|
61
|
+
if (schema.routingMap) {
|
|
62
|
+
this.#initializeRouter(schema.routingMap)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
#initializeRouter(routingMap: RoutingMap) {
|
|
67
|
+
for (const [method, definitions] of Object.entries(routingMap)) {
|
|
68
|
+
const parsedRoutes = []
|
|
69
|
+
for (const def of definitions) {
|
|
70
|
+
// matchit's parse() transforms a route string into an object representation.
|
|
71
|
+
// It expects `:param` syntax, while our API models use OpenAPI `{param}` syntax.
|
|
72
|
+
const matchitPath = def.path.replace(/\{([^}]+)\}/g, ':$1')
|
|
73
|
+
const parsed = parse(matchitPath)
|
|
74
|
+
this.#definitions.set(parsed, def)
|
|
75
|
+
parsedRoutes.push(parsed)
|
|
76
|
+
}
|
|
77
|
+
this.#routes.set(method.toUpperCase(), parsedRoutes)
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Looks up the corresponding exposed entity and action for a given request.
|
|
83
|
+
*
|
|
84
|
+
* @param method The HTTP method (e.g., 'GET', 'POST').
|
|
85
|
+
* @param path The request path (e.g., '/users/123').
|
|
86
|
+
* @returns An object with the entity, action, and extracted path parameters if a match is found.
|
|
87
|
+
*/
|
|
88
|
+
lookupAction(method: string, path: string): RuntimeResolvedAction | undefined {
|
|
89
|
+
const parsedRoutes = this.#routes.get(method.toUpperCase())
|
|
90
|
+
if (!parsedRoutes) {
|
|
91
|
+
return undefined
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// `match` returns the matching parsed route (which is an array of segments), or empty array if no match
|
|
95
|
+
const matchedRoute = match(path, parsedRoutes)
|
|
96
|
+
if (!matchedRoute || matchedRoute.length === 0) {
|
|
97
|
+
return undefined
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const def = this.#definitions.get(matchedRoute)
|
|
101
|
+
if (!def) {
|
|
102
|
+
return undefined
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const params = exec(path, matchedRoute)
|
|
106
|
+
|
|
107
|
+
const entity = this.exposes.get(def.lookup.exposedEntityKey)
|
|
108
|
+
if (!entity) {
|
|
109
|
+
return undefined
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const action = entity.actions.find((a) => a.kind === def.lookup.actionKind)
|
|
113
|
+
if (!action) {
|
|
114
|
+
return undefined
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return {
|
|
118
|
+
entity,
|
|
119
|
+
action,
|
|
120
|
+
params,
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
override toJSON(): RuntimeApiModelSchema {
|
|
125
|
+
const base = super.toJSON() as RuntimeApiModelSchema
|
|
126
|
+
|
|
127
|
+
const routingMap: RoutingMap = {}
|
|
128
|
+
for (const [method, parsedRoutes] of this.#routes.entries()) {
|
|
129
|
+
routingMap[method] = parsedRoutes.map((pr) => this.#definitions.get(pr) as RouteDefinition)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return {
|
|
133
|
+
...base,
|
|
134
|
+
routingMap,
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
package/src/modeling/types.ts
CHANGED
|
@@ -86,6 +86,31 @@ export interface AssociationTarget {
|
|
|
86
86
|
domain?: string
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
+
/**
|
|
90
|
+
* The list of functions supported for string properties.
|
|
91
|
+
*/
|
|
92
|
+
export type StringFunctions = 'random' | 'uuid-v4'
|
|
93
|
+
/**
|
|
94
|
+
* The list of functions supported for number properties.
|
|
95
|
+
*/
|
|
96
|
+
export type NumberFunctions = 'incremental'
|
|
97
|
+
/**
|
|
98
|
+
* The list of functions supported for date properties.
|
|
99
|
+
*/
|
|
100
|
+
export type DateFunctions = 'now'
|
|
101
|
+
/**
|
|
102
|
+
* The list of functions supported for datetime properties.
|
|
103
|
+
*/
|
|
104
|
+
export type DateTimeFunctions = 'now'
|
|
105
|
+
/**
|
|
106
|
+
* The list of functions supported for time properties.
|
|
107
|
+
*/
|
|
108
|
+
export type TimeFunctions = 'now'
|
|
109
|
+
/**
|
|
110
|
+
* The list of all functions that can be used as default values for properties.
|
|
111
|
+
*/
|
|
112
|
+
export type FunctionValue = StringFunctions | NumberFunctions | DateFunctions | DateTimeFunctions | TimeFunctions
|
|
113
|
+
|
|
89
114
|
/**
|
|
90
115
|
* Describes the default value set on a property schema.
|
|
91
116
|
*/
|
|
@@ -101,7 +126,7 @@ export interface SchemaDefaultValue {
|
|
|
101
126
|
* The actual value type depends on the `type`.
|
|
102
127
|
* It is always a string and it has to be casted to the property's data type.
|
|
103
128
|
*/
|
|
104
|
-
value: string
|
|
129
|
+
value: string | FunctionValue
|
|
105
130
|
}
|
|
106
131
|
|
|
107
132
|
/**
|
package/src/models/kinds.ts
CHANGED
|
@@ -20,6 +20,7 @@ export const DataCatalogKind = 'Core#DataCatalog'
|
|
|
20
20
|
export const DataCatalogVersionKind = 'Core#DataCatalogVersion'
|
|
21
21
|
export const OrganizationKind = 'Core#Organization'
|
|
22
22
|
export const InvitationKind = 'Core#Invitation'
|
|
23
|
+
export const DeploymentKind = 'Core#Deployment'
|
|
23
24
|
export const ApiModelKind = 'Core#ApiModel'
|
|
24
25
|
export const ExposedEntityKind = 'Core#ExposedEntity'
|
|
25
26
|
export const ApiFileKind = 'Core#ApiFile'
|