@api-client/core 0.19.24 → 0.19.25

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 (102) hide show
  1. package/build/src/index.d.ts +3 -1
  2. package/build/src/index.d.ts.map +1 -1
  3. package/build/src/index.js +3 -1
  4. package/build/src/index.js.map +1 -1
  5. package/build/src/mocking/ModelingMock.d.ts +2 -0
  6. package/build/src/mocking/ModelingMock.d.ts.map +1 -1
  7. package/build/src/mocking/ModelingMock.js +2 -0
  8. package/build/src/mocking/ModelingMock.js.map +1 -1
  9. package/build/src/mocking/lib/Deployment.d.ts +16 -0
  10. package/build/src/mocking/lib/Deployment.d.ts.map +1 -0
  11. package/build/src/mocking/lib/Deployment.js +76 -0
  12. package/build/src/mocking/lib/Deployment.js.map +1 -0
  13. package/build/src/modeling/Bindings.d.ts +4 -0
  14. package/build/src/modeling/Bindings.d.ts.map +1 -1
  15. package/build/src/modeling/Bindings.js.map +1 -1
  16. package/build/src/modeling/DataFormat.d.ts +1 -1
  17. package/build/src/modeling/DataFormat.d.ts.map +1 -1
  18. package/build/src/modeling/DataFormat.js +2 -0
  19. package/build/src/modeling/DataFormat.js.map +1 -1
  20. package/build/src/modeling/DomainAssociation.d.ts +7 -0
  21. package/build/src/modeling/DomainAssociation.d.ts.map +1 -1
  22. package/build/src/modeling/DomainAssociation.js +10 -0
  23. package/build/src/modeling/DomainAssociation.js.map +1 -1
  24. package/build/src/modeling/DomainEntity.d.ts +9 -1
  25. package/build/src/modeling/DomainEntity.d.ts.map +1 -1
  26. package/build/src/modeling/DomainEntity.js +26 -1
  27. package/build/src/modeling/DomainEntity.js.map +1 -1
  28. package/build/src/modeling/ExposedEntity.d.ts +12 -1
  29. package/build/src/modeling/ExposedEntity.d.ts.map +1 -1
  30. package/build/src/modeling/ExposedEntity.js +24 -1
  31. package/build/src/modeling/ExposedEntity.js.map +1 -1
  32. package/build/src/modeling/RuntimeApiModel.d.ts +52 -0
  33. package/build/src/modeling/RuntimeApiModel.d.ts.map +1 -0
  34. package/build/src/modeling/RuntimeApiModel.js +85 -0
  35. package/build/src/modeling/RuntimeApiModel.js.map +1 -0
  36. package/build/src/modeling/actions/index.d.ts +10 -0
  37. package/build/src/modeling/actions/index.d.ts.map +1 -1
  38. package/build/src/modeling/actions/index.js +30 -0
  39. package/build/src/modeling/actions/index.js.map +1 -1
  40. package/build/src/modeling/index.d.ts.map +1 -1
  41. package/build/src/modeling/index.js +1 -0
  42. package/build/src/modeling/index.js.map +1 -1
  43. package/build/src/modeling/types.d.ts +25 -1
  44. package/build/src/modeling/types.d.ts.map +1 -1
  45. package/build/src/modeling/types.js.map +1 -1
  46. package/build/src/models/kinds.d.ts +1 -0
  47. package/build/src/models/kinds.d.ts.map +1 -1
  48. package/build/src/models/kinds.js +1 -0
  49. package/build/src/models/kinds.js.map +1 -1
  50. package/build/src/models/store/Deployment.d.ts +53 -16
  51. package/build/src/models/store/Deployment.d.ts.map +1 -1
  52. package/build/src/models/store/Deployment.js +92 -34
  53. package/build/src/models/store/Deployment.js.map +1 -1
  54. package/build/src/sdk/DataCatalogSdk.d.ts.map +1 -1
  55. package/build/src/sdk/DataCatalogSdk.js +22 -179
  56. package/build/src/sdk/DataCatalogSdk.js.map +1 -1
  57. package/build/src/sdk/DeploymentsSdk.d.ts +48 -0
  58. package/build/src/sdk/DeploymentsSdk.d.ts.map +1 -0
  59. package/build/src/sdk/DeploymentsSdk.js +94 -0
  60. package/build/src/sdk/DeploymentsSdk.js.map +1 -0
  61. package/build/src/sdk/RouteBuilder.d.ts +2 -0
  62. package/build/src/sdk/RouteBuilder.d.ts.map +1 -1
  63. package/build/src/sdk/RouteBuilder.js +6 -0
  64. package/build/src/sdk/RouteBuilder.js.map +1 -1
  65. package/build/src/sdk/Sdk.d.ts +2 -0
  66. package/build/src/sdk/Sdk.d.ts.map +1 -1
  67. package/build/src/sdk/Sdk.js +2 -0
  68. package/build/src/sdk/Sdk.js.map +1 -1
  69. package/build/src/sdk/SdkBase.d.ts +19 -1
  70. package/build/src/sdk/SdkBase.d.ts.map +1 -1
  71. package/build/src/sdk/SdkBase.js +31 -1
  72. package/build/src/sdk/SdkBase.js.map +1 -1
  73. package/build/src/sdk/SdkMock.d.ts +9 -0
  74. package/build/src/sdk/SdkMock.d.ts.map +1 -1
  75. package/build/src/sdk/SdkMock.js +73 -0
  76. package/build/src/sdk/SdkMock.js.map +1 -1
  77. package/build/tsconfig.tsbuildinfo +1 -1
  78. package/package.json +2 -1
  79. package/src/matchit.d.ts +19 -0
  80. package/src/mocking/ModelingMock.ts +2 -0
  81. package/src/mocking/lib/Deployment.ts +88 -0
  82. package/src/modeling/Bindings.ts +4 -0
  83. package/src/modeling/DataFormat.ts +4 -0
  84. package/src/modeling/DomainAssociation.ts +11 -0
  85. package/src/modeling/DomainEntity.ts +30 -1
  86. package/src/modeling/ExposedEntity.ts +26 -1
  87. package/src/modeling/RuntimeApiModel.ts +137 -0
  88. package/src/modeling/types.ts +26 -1
  89. package/src/models/kinds.ts +1 -0
  90. package/src/models/store/Deployment.ts +122 -45
  91. package/src/sdk/DataCatalogSdk.ts +22 -176
  92. package/src/sdk/DeploymentsSdk.ts +123 -0
  93. package/src/sdk/RouteBuilder.ts +8 -0
  94. package/src/sdk/Sdk.ts +3 -0
  95. package/src/sdk/SdkBase.ts +35 -3
  96. package/src/sdk/SdkMock.ts +103 -0
  97. package/tests/unit/modeling/RuntimeApiModel.spec.ts +122 -0
  98. package/tests/unit/modeling/actions/index.spec.ts +113 -0
  99. package/tests/unit/modeling/domain_asociation.spec.ts +28 -0
  100. package/tests/unit/modeling/domain_entity_parents.spec.ts +49 -0
  101. package/tests/unit/modeling/exposed_entity_actions.spec.ts +47 -0
  102. 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.24",
4
+ "version": "0.19.25",
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",
@@ -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
+ }
@@ -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
+ }
@@ -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
  /**
@@ -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'