@api-client/core 0.19.22 → 0.19.24
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 +3 -0
- package/build/src/browser.d.ts.map +1 -1
- package/build/src/browser.js +2 -0
- package/build/src/browser.js.map +1 -1
- package/build/src/index.d.ts +3 -0
- package/build/src/index.d.ts.map +1 -1
- package/build/src/index.js +2 -0
- package/build/src/index.js.map +1 -1
- package/build/src/modeling/ApiModel.d.ts.map +1 -1
- package/build/src/modeling/ApiModel.js +37 -13
- package/build/src/modeling/ApiModel.js.map +1 -1
- package/build/src/modeling/ExposedEntity.d.ts.map +1 -1
- package/build/src/modeling/ExposedEntity.js +54 -15
- package/build/src/modeling/ExposedEntity.js.map +1 -1
- package/build/src/modeling/actions/Action.js +2 -2
- package/build/src/modeling/actions/Action.js.map +1 -1
- package/build/src/modeling/rules/AccessRule.d.ts +5 -1
- package/build/src/modeling/rules/AccessRule.d.ts.map +1 -1
- package/build/src/modeling/rules/AccessRule.js +4 -1
- package/build/src/modeling/rules/AccessRule.js.map +1 -1
- package/build/src/modeling/rules/AllowAuthenticated.d.ts +4 -1
- package/build/src/modeling/rules/AllowAuthenticated.d.ts.map +1 -1
- package/build/src/modeling/rules/AllowAuthenticated.js +2 -2
- package/build/src/modeling/rules/AllowAuthenticated.js.map +1 -1
- package/build/src/modeling/rules/AllowPublic.d.ts +4 -1
- package/build/src/modeling/rules/AllowPublic.d.ts.map +1 -1
- package/build/src/modeling/rules/AllowPublic.js +2 -2
- package/build/src/modeling/rules/AllowPublic.js.map +1 -1
- package/build/src/modeling/rules/MatchEmailDomain.d.ts +4 -1
- package/build/src/modeling/rules/MatchEmailDomain.d.ts.map +1 -1
- package/build/src/modeling/rules/MatchEmailDomain.js +2 -2
- package/build/src/modeling/rules/MatchEmailDomain.js.map +1 -1
- package/build/src/modeling/rules/MatchResourceOwner.d.ts +4 -1
- package/build/src/modeling/rules/MatchResourceOwner.d.ts.map +1 -1
- package/build/src/modeling/rules/MatchResourceOwner.js +2 -2
- package/build/src/modeling/rules/MatchResourceOwner.js.map +1 -1
- package/build/src/modeling/rules/MatchUserProperty.d.ts +4 -1
- package/build/src/modeling/rules/MatchUserProperty.d.ts.map +1 -1
- package/build/src/modeling/rules/MatchUserProperty.js +2 -2
- package/build/src/modeling/rules/MatchUserProperty.js.map +1 -1
- package/build/src/modeling/rules/MatchUserRole.d.ts +4 -1
- package/build/src/modeling/rules/MatchUserRole.d.ts.map +1 -1
- package/build/src/modeling/rules/MatchUserRole.js +2 -2
- package/build/src/modeling/rules/MatchUserRole.js.map +1 -1
- package/build/src/modeling/rules/index.d.ts +4 -1
- package/build/src/modeling/rules/index.d.ts.map +1 -1
- package/build/src/modeling/rules/index.js +7 -7
- package/build/src/modeling/rules/index.js.map +1 -1
- package/build/src/models/store/CustomDomain.d.ts +50 -0
- package/build/src/models/store/CustomDomain.d.ts.map +1 -0
- package/build/src/models/store/CustomDomain.js +79 -0
- package/build/src/models/store/CustomDomain.js.map +1 -0
- package/build/src/models/store/Deployment.d.ts +81 -0
- package/build/src/models/store/Deployment.d.ts.map +1 -0
- package/build/src/models/store/Deployment.js +124 -0
- package/build/src/models/store/Deployment.js.map +1 -0
- package/build/src/models/store/DeploymentCustomDomain.d.ts +52 -0
- package/build/src/models/store/DeploymentCustomDomain.d.ts.map +1 -0
- package/build/src/models/store/DeploymentCustomDomain.js +84 -0
- package/build/src/models/store/DeploymentCustomDomain.js.map +1 -0
- package/build/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/modeling/ApiModel.ts +37 -13
- package/src/modeling/ExposedEntity.ts +62 -16
- package/src/modeling/actions/Action.ts +2 -2
- package/src/modeling/rules/AccessRule.ts +8 -1
- package/src/modeling/rules/AllowAuthenticated.ts +5 -2
- package/src/modeling/rules/AllowPublic.ts +5 -2
- package/src/modeling/rules/MatchEmailDomain.ts +5 -2
- package/src/modeling/rules/MatchResourceOwner.ts +5 -2
- package/src/modeling/rules/MatchUserProperty.ts +5 -2
- package/src/modeling/rules/MatchUserRole.ts +5 -2
- package/src/models/store/CustomDomain.ts +119 -0
- package/src/models/store/Deployment.ts +173 -0
- package/src/models/store/DeploymentCustomDomain.ts +120 -0
- package/tests/unit/modeling/actions/Action.spec.ts +13 -10
- package/tests/unit/modeling/actions/CreateAction.spec.ts +7 -6
- package/tests/unit/modeling/actions/DeleteAction.spec.ts +7 -6
- package/tests/unit/modeling/actions/ListAction.spec.ts +5 -4
- package/tests/unit/modeling/actions/ReadAction.spec.ts +9 -8
- package/tests/unit/modeling/actions/SearchAction.spec.ts +5 -4
- package/tests/unit/modeling/actions/UpdateAction.spec.ts +7 -6
- package/tests/unit/modeling/actions/helpers.ts +7 -0
- package/tests/unit/modeling/api_model.spec.ts +3 -1
- package/tests/unit/modeling/api_model_expose_entity.spec.ts +5 -17
- package/tests/unit/modeling/exposed_entity.spec.ts +6 -2
- package/tests/unit/modeling/exposed_entity_actions.spec.ts +0 -4
- package/tests/unit/modeling/rules/AccessRule.spec.ts +6 -5
- package/tests/unit/modeling/rules/AllowAuthenticated.spec.ts +4 -3
- package/tests/unit/modeling/rules/AllowPublic.spec.ts +4 -3
- package/tests/unit/modeling/rules/MatchEmailDomain.spec.ts +6 -5
- package/tests/unit/modeling/rules/MatchResourceOwner.spec.ts +7 -6
- package/tests/unit/modeling/rules/MatchUserProperty.spec.ts +6 -5
- package/tests/unit/modeling/rules/MatchUserRole.spec.ts +6 -5
- package/tests/unit/modeling/rules/restoring_rules.spec.ts +19 -21
- package/tests/unit/models/store/CustomDomain.spec.ts +111 -0
- package/tests/unit/models/store/Deployment.spec.ts +134 -0
- package/tests/unit/models/store/DeploymentCustomDomain.spec.ts +122 -0
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import type { FieldValidationMessage } from '../../exceptions/validation_error.js'
|
|
2
|
+
import { nanoid } from '../../nanoid.js'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Status of the deployment
|
|
6
|
+
*/
|
|
7
|
+
export enum DeploymentStatus {
|
|
8
|
+
/**
|
|
9
|
+
* Deployment is pending
|
|
10
|
+
*/
|
|
11
|
+
Pending = 0,
|
|
12
|
+
/**
|
|
13
|
+
* Deployment is active
|
|
14
|
+
*/
|
|
15
|
+
Active = 1,
|
|
16
|
+
/**
|
|
17
|
+
* Deployment is inactive
|
|
18
|
+
*/
|
|
19
|
+
Inactive = 2,
|
|
20
|
+
/**
|
|
21
|
+
* Deployment has failed
|
|
22
|
+
*/
|
|
23
|
+
Failed = 3,
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface DeploymentSchema {
|
|
27
|
+
/**
|
|
28
|
+
* Primary key (nanoid)
|
|
29
|
+
*/
|
|
30
|
+
id: string
|
|
31
|
+
/**
|
|
32
|
+
* ID of the organization
|
|
33
|
+
*/
|
|
34
|
+
orgId: string
|
|
35
|
+
/**
|
|
36
|
+
* The file ID representing the API
|
|
37
|
+
*/
|
|
38
|
+
apiId: string
|
|
39
|
+
/**
|
|
40
|
+
* The version of the deployment (e.g., 'v1', 'v2')
|
|
41
|
+
*/
|
|
42
|
+
deploymentVersion: string
|
|
43
|
+
/**
|
|
44
|
+
* The semantic version of the deployed API model (e.g., '1.0.1')
|
|
45
|
+
*/
|
|
46
|
+
apiModelVersion: string
|
|
47
|
+
/**
|
|
48
|
+
* Status of the deployment
|
|
49
|
+
*/
|
|
50
|
+
status: DeploymentStatus
|
|
51
|
+
/**
|
|
52
|
+
* Optional custom path for staging (e.g., '/dev')
|
|
53
|
+
*/
|
|
54
|
+
stagingPath?: string
|
|
55
|
+
/**
|
|
56
|
+
* Reference to the optimized model in MongoDB
|
|
57
|
+
*/
|
|
58
|
+
mongoModelId?: string
|
|
59
|
+
/**
|
|
60
|
+
* Timestamp of creation
|
|
61
|
+
*/
|
|
62
|
+
createdAt: number
|
|
63
|
+
/**
|
|
64
|
+
* Timestamp of last update
|
|
65
|
+
*/
|
|
66
|
+
updatedAt: number
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export class Deployment implements DeploymentSchema {
|
|
70
|
+
id: string
|
|
71
|
+
orgId: string
|
|
72
|
+
apiId: string
|
|
73
|
+
deploymentVersion: string
|
|
74
|
+
apiModelVersion: string
|
|
75
|
+
status: DeploymentStatus
|
|
76
|
+
stagingPath?: string
|
|
77
|
+
mongoModelId?: string
|
|
78
|
+
createdAt: number
|
|
79
|
+
updatedAt: number
|
|
80
|
+
|
|
81
|
+
static createSchema(input: Partial<DeploymentSchema> = {}): DeploymentSchema {
|
|
82
|
+
const id = input.id ?? nanoid()
|
|
83
|
+
const result: DeploymentSchema = {
|
|
84
|
+
id,
|
|
85
|
+
orgId: input.orgId || '',
|
|
86
|
+
apiId: input.apiId || '',
|
|
87
|
+
deploymentVersion: input.deploymentVersion || 'v0',
|
|
88
|
+
apiModelVersion: input.apiModelVersion || '0.0.0',
|
|
89
|
+
status: input.status ?? DeploymentStatus.Pending,
|
|
90
|
+
createdAt: input.createdAt ?? Date.now(),
|
|
91
|
+
updatedAt: input.updatedAt ?? Date.now(),
|
|
92
|
+
}
|
|
93
|
+
if (input.stagingPath) {
|
|
94
|
+
result.stagingPath = input.stagingPath
|
|
95
|
+
}
|
|
96
|
+
if (input.mongoModelId) {
|
|
97
|
+
result.mongoModelId = input.mongoModelId
|
|
98
|
+
}
|
|
99
|
+
return result
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
constructor(state?: Partial<DeploymentSchema>) {
|
|
103
|
+
const init = Deployment.createSchema(state)
|
|
104
|
+
this.id = init.id
|
|
105
|
+
this.orgId = init.orgId
|
|
106
|
+
this.apiId = init.apiId
|
|
107
|
+
this.deploymentVersion = init.deploymentVersion
|
|
108
|
+
this.apiModelVersion = init.apiModelVersion
|
|
109
|
+
this.status = init.status
|
|
110
|
+
if (init.stagingPath) {
|
|
111
|
+
this.stagingPath = init.stagingPath
|
|
112
|
+
}
|
|
113
|
+
if (init.mongoModelId) {
|
|
114
|
+
this.mongoModelId = init.mongoModelId
|
|
115
|
+
}
|
|
116
|
+
this.createdAt = init.createdAt
|
|
117
|
+
this.updatedAt = init.updatedAt
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
toJSON(): DeploymentSchema {
|
|
121
|
+
const result: DeploymentSchema = {
|
|
122
|
+
id: this.id,
|
|
123
|
+
orgId: this.orgId,
|
|
124
|
+
apiId: this.apiId,
|
|
125
|
+
deploymentVersion: this.deploymentVersion,
|
|
126
|
+
apiModelVersion: this.apiModelVersion,
|
|
127
|
+
status: this.status,
|
|
128
|
+
createdAt: this.createdAt,
|
|
129
|
+
updatedAt: this.updatedAt,
|
|
130
|
+
}
|
|
131
|
+
if (this.stagingPath) {
|
|
132
|
+
result.stagingPath = this.stagingPath
|
|
133
|
+
}
|
|
134
|
+
if (this.mongoModelId) {
|
|
135
|
+
result.mongoModelId = this.mongoModelId
|
|
136
|
+
}
|
|
137
|
+
return result
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
validate(): FieldValidationMessage[] {
|
|
141
|
+
const result: FieldValidationMessage[] = []
|
|
142
|
+
|
|
143
|
+
if (this.orgId === '') {
|
|
144
|
+
result.push({
|
|
145
|
+
field: 'orgId',
|
|
146
|
+
message: 'Org ID must not be empty',
|
|
147
|
+
rule: 'notEmpty',
|
|
148
|
+
})
|
|
149
|
+
}
|
|
150
|
+
if (this.apiId === '') {
|
|
151
|
+
result.push({
|
|
152
|
+
field: 'apiId',
|
|
153
|
+
message: 'API ID must not be empty',
|
|
154
|
+
rule: 'notEmpty',
|
|
155
|
+
})
|
|
156
|
+
}
|
|
157
|
+
if (this.deploymentVersion === '') {
|
|
158
|
+
result.push({
|
|
159
|
+
field: 'deploymentVersion',
|
|
160
|
+
message: 'Deployment version must not be empty',
|
|
161
|
+
rule: 'notEmpty',
|
|
162
|
+
})
|
|
163
|
+
}
|
|
164
|
+
if (this.apiModelVersion === '') {
|
|
165
|
+
result.push({
|
|
166
|
+
field: 'apiModelVersion',
|
|
167
|
+
message: 'API model version must not be empty',
|
|
168
|
+
rule: 'notEmpty',
|
|
169
|
+
})
|
|
170
|
+
}
|
|
171
|
+
return result
|
|
172
|
+
}
|
|
173
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import type { FieldValidationMessage } from '../../exceptions/validation_error.js'
|
|
2
|
+
import { nanoid } from '../../nanoid.js'
|
|
3
|
+
|
|
4
|
+
export enum SslStatus {
|
|
5
|
+
Initializing = 0,
|
|
6
|
+
PendingDns = 1,
|
|
7
|
+
Issuing = 2,
|
|
8
|
+
Active = 3,
|
|
9
|
+
Error = 4,
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface DeploymentCustomDomainSchema {
|
|
13
|
+
/**
|
|
14
|
+
* Primary key (nanoid)
|
|
15
|
+
*/
|
|
16
|
+
id: string
|
|
17
|
+
/**
|
|
18
|
+
* ID of the deployment
|
|
19
|
+
*/
|
|
20
|
+
deploymentId: string
|
|
21
|
+
/**
|
|
22
|
+
* ID of the custom domain
|
|
23
|
+
*/
|
|
24
|
+
customDomainId: string
|
|
25
|
+
/**
|
|
26
|
+
* The base path for the deployment
|
|
27
|
+
*/
|
|
28
|
+
basePath: string
|
|
29
|
+
/**
|
|
30
|
+
* Status of the SSL certificate
|
|
31
|
+
*/
|
|
32
|
+
sslStatus: SslStatus
|
|
33
|
+
/**
|
|
34
|
+
* Timestamp of creation
|
|
35
|
+
*/
|
|
36
|
+
createdAt: number
|
|
37
|
+
/**
|
|
38
|
+
* Timestamp of last update
|
|
39
|
+
*/
|
|
40
|
+
updatedAt: number
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export class DeploymentCustomDomainModel implements DeploymentCustomDomainSchema {
|
|
44
|
+
id: string
|
|
45
|
+
deploymentId: string
|
|
46
|
+
customDomainId: string
|
|
47
|
+
basePath: string
|
|
48
|
+
sslStatus: SslStatus
|
|
49
|
+
createdAt: number
|
|
50
|
+
updatedAt: number
|
|
51
|
+
|
|
52
|
+
static createSchema(input: Partial<DeploymentCustomDomainSchema> = {}): DeploymentCustomDomainSchema {
|
|
53
|
+
const id = input.id ?? nanoid()
|
|
54
|
+
return {
|
|
55
|
+
id,
|
|
56
|
+
deploymentId: input.deploymentId || '',
|
|
57
|
+
customDomainId: input.customDomainId || '',
|
|
58
|
+
basePath: input.basePath ?? '/',
|
|
59
|
+
sslStatus: input.sslStatus ?? SslStatus.PendingDns,
|
|
60
|
+
createdAt: input.createdAt ?? Date.now(),
|
|
61
|
+
updatedAt: input.updatedAt ?? Date.now(),
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
constructor(state?: Partial<DeploymentCustomDomainSchema>) {
|
|
66
|
+
const init = DeploymentCustomDomainModel.createSchema(state)
|
|
67
|
+
this.id = init.id
|
|
68
|
+
this.deploymentId = init.deploymentId
|
|
69
|
+
this.customDomainId = init.customDomainId
|
|
70
|
+
this.basePath = init.basePath
|
|
71
|
+
this.sslStatus = init.sslStatus
|
|
72
|
+
this.createdAt = init.createdAt
|
|
73
|
+
this.updatedAt = init.updatedAt
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
toJSON(): DeploymentCustomDomainSchema {
|
|
77
|
+
return {
|
|
78
|
+
id: this.id,
|
|
79
|
+
deploymentId: this.deploymentId,
|
|
80
|
+
customDomainId: this.customDomainId,
|
|
81
|
+
basePath: this.basePath,
|
|
82
|
+
sslStatus: this.sslStatus,
|
|
83
|
+
createdAt: this.createdAt,
|
|
84
|
+
updatedAt: this.updatedAt,
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
validate(): FieldValidationMessage[] {
|
|
89
|
+
const result: FieldValidationMessage[] = []
|
|
90
|
+
|
|
91
|
+
if (this.basePath === '') {
|
|
92
|
+
result.push({
|
|
93
|
+
field: 'basePath',
|
|
94
|
+
message: 'Base path must not be empty',
|
|
95
|
+
rule: 'notEmpty',
|
|
96
|
+
})
|
|
97
|
+
} else if (!this.basePath.startsWith('/')) {
|
|
98
|
+
result.push({
|
|
99
|
+
field: 'basePath',
|
|
100
|
+
message: 'Base path must start with a slash',
|
|
101
|
+
rule: 'startsWithSlash',
|
|
102
|
+
})
|
|
103
|
+
}
|
|
104
|
+
if (!this.deploymentId) {
|
|
105
|
+
result.push({
|
|
106
|
+
field: 'deploymentId',
|
|
107
|
+
message: 'Deployment ID must not be empty',
|
|
108
|
+
rule: 'notEmpty',
|
|
109
|
+
})
|
|
110
|
+
}
|
|
111
|
+
if (!this.customDomainId) {
|
|
112
|
+
result.push({
|
|
113
|
+
field: 'customDomainId',
|
|
114
|
+
message: 'Custom domain ID must not be empty',
|
|
115
|
+
rule: 'notEmpty',
|
|
116
|
+
})
|
|
117
|
+
}
|
|
118
|
+
return result
|
|
119
|
+
}
|
|
120
|
+
}
|
|
@@ -2,10 +2,11 @@ import { test } from '@japa/runner'
|
|
|
2
2
|
import { Action, AccessRule, RateLimitingConfiguration } from '../../../../src/modeling/index.js'
|
|
3
3
|
import { type ActionSchema } from '../../../../src/modeling/actions/Action.js'
|
|
4
4
|
import { type ExposedEntity } from '../../../../src/modeling/ExposedEntity.js'
|
|
5
|
+
import { mockExposedEntity } from './helpers.js'
|
|
5
6
|
|
|
6
7
|
test.group('Action', () => {
|
|
7
8
|
test('initializes with default values', ({ assert }) => {
|
|
8
|
-
const action = new Action(
|
|
9
|
+
const action = new Action(mockExposedEntity())
|
|
9
10
|
assert.equal(action.kind, '')
|
|
10
11
|
assert.deepEqual(action.accessRule, [])
|
|
11
12
|
assert.isUndefined(action.rateLimiting)
|
|
@@ -17,7 +18,7 @@ test.group('Action', () => {
|
|
|
17
18
|
accessRule: [{ type: 'allowPublic' }],
|
|
18
19
|
rateLimiting: { rules: [] },
|
|
19
20
|
}
|
|
20
|
-
const action = new Action(
|
|
21
|
+
const action = new Action(mockExposedEntity(), schema)
|
|
21
22
|
assert.equal(action.kind, 'read')
|
|
22
23
|
assert.lengthOf(action.accessRule, 1)
|
|
23
24
|
assert.instanceOf(action.accessRule[0], AccessRule)
|
|
@@ -26,7 +27,7 @@ test.group('Action', () => {
|
|
|
26
27
|
}).tags(['@modeling', '@action'])
|
|
27
28
|
|
|
28
29
|
test('serializes to JSON', ({ assert }) => {
|
|
29
|
-
const action = new Action(
|
|
30
|
+
const action = new Action(mockExposedEntity(), {
|
|
30
31
|
kind: 'write',
|
|
31
32
|
accessRule: [{ type: 'allowPublic' }],
|
|
32
33
|
rateLimiting: { rules: [] },
|
|
@@ -39,7 +40,7 @@ test.group('Action', () => {
|
|
|
39
40
|
}).tags(['@modeling', '@action'])
|
|
40
41
|
|
|
41
42
|
test('notifies change when kind changes', async ({ assert }) => {
|
|
42
|
-
const action = new Action(
|
|
43
|
+
const action = new Action(mockExposedEntity(), { kind: 'read' })
|
|
43
44
|
let notified = false
|
|
44
45
|
action.addEventListener('change', () => {
|
|
45
46
|
notified = true
|
|
@@ -53,19 +54,19 @@ test.group('Action', () => {
|
|
|
53
54
|
}).tags(['@modeling', '@action', '@observed'])
|
|
54
55
|
|
|
55
56
|
test('notifies change when accessRule array is replaced', async ({ assert }) => {
|
|
56
|
-
const action = new Action(
|
|
57
|
+
const action = new Action(mockExposedEntity())
|
|
57
58
|
let notified = false
|
|
58
59
|
action.addEventListener('change', () => {
|
|
59
60
|
notified = true
|
|
60
61
|
})
|
|
61
62
|
|
|
62
|
-
action.accessRule = [new AccessRule({ type: 'allowPublic' })]
|
|
63
|
+
action.accessRule = [new AccessRule(mockExposedEntity(), { type: 'allowPublic' })]
|
|
63
64
|
await Promise.resolve()
|
|
64
65
|
assert.isTrue(notified)
|
|
65
66
|
}).tags(['@modeling', '@action', '@observed'])
|
|
66
67
|
|
|
67
68
|
test('notifies change when rateLimiting is replaced', async ({ assert }) => {
|
|
68
|
-
const action = new Action(
|
|
69
|
+
const action = new Action(mockExposedEntity())
|
|
69
70
|
let notified = false
|
|
70
71
|
action.addEventListener('change', () => {
|
|
71
72
|
notified = true
|
|
@@ -78,7 +79,7 @@ test.group('Action', () => {
|
|
|
78
79
|
|
|
79
80
|
test('constructor copies accessRule array (immutability)', ({ assert }) => {
|
|
80
81
|
const rules = [{ type: 'allowPublic' }]
|
|
81
|
-
const action = new Action(
|
|
82
|
+
const action = new Action(mockExposedEntity(), { kind: 'read', accessRule: rules })
|
|
82
83
|
|
|
83
84
|
// Modify original array
|
|
84
85
|
rules.push({ type: 'other' })
|
|
@@ -89,7 +90,7 @@ test.group('Action', () => {
|
|
|
89
90
|
}).tags(['@modeling', '@action', '@immutability'])
|
|
90
91
|
|
|
91
92
|
test('toJSON returns safe copy', ({ assert }) => {
|
|
92
|
-
const action = new Action(
|
|
93
|
+
const action = new Action(mockExposedEntity(), {
|
|
93
94
|
kind: 'read',
|
|
94
95
|
accessRule: [{ type: 'allowPublic' }],
|
|
95
96
|
rateLimiting: { rules: [] },
|
|
@@ -110,7 +111,8 @@ test.group('Action', () => {
|
|
|
110
111
|
|
|
111
112
|
test('getAllRules() aggregates rules from action and parent', ({ assert }) => {
|
|
112
113
|
const parent = {
|
|
113
|
-
getAllRules: () => [new AccessRule({ type: 'allowPublic' })],
|
|
114
|
+
getAllRules: () => [new AccessRule(mockExposedEntity(), { type: 'allowPublic' })],
|
|
115
|
+
notifyChange: () => {},
|
|
114
116
|
} as unknown as ExposedEntity
|
|
115
117
|
|
|
116
118
|
const action = new Action(parent, {
|
|
@@ -127,6 +129,7 @@ test.group('Action', () => {
|
|
|
127
129
|
const parentLimiter = new RateLimitingConfiguration({ rules: [{ rate: 10, interval: 'second' }] })
|
|
128
130
|
const parent = {
|
|
129
131
|
getAllRateLimiters: () => [parentLimiter],
|
|
132
|
+
notifyChange: () => {},
|
|
130
133
|
} as unknown as ExposedEntity
|
|
131
134
|
|
|
132
135
|
const action = new Action(parent, {
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { test } from '@japa/runner'
|
|
2
2
|
import { CreateAction } from '../../../../src/modeling/actions/CreateAction.js'
|
|
3
3
|
import { AccessRule } from '../../../../src/modeling/rules/index.js'
|
|
4
|
+
import { mockExposedEntity } from './helpers.js'
|
|
4
5
|
|
|
5
6
|
test.group('CreateAction', () => {
|
|
6
7
|
test('initializes with default values', ({ assert }) => {
|
|
7
|
-
const action = new CreateAction(
|
|
8
|
+
const action = new CreateAction(mockExposedEntity())
|
|
8
9
|
assert.equal(action.kind, 'create')
|
|
9
10
|
assert.isEmpty(action.accessRule) // Inherited from Action
|
|
10
11
|
}).tags(['@modeling', '@action', '@create-action'])
|
|
11
12
|
|
|
12
13
|
test('initializes with inherited values', ({ assert }) => {
|
|
13
|
-
const action = new CreateAction(
|
|
14
|
+
const action = new CreateAction(mockExposedEntity(), {
|
|
14
15
|
accessRule: [{ type: 'allowPublic' }],
|
|
15
16
|
})
|
|
16
17
|
|
|
@@ -22,7 +23,7 @@ test.group('CreateAction', () => {
|
|
|
22
23
|
test('constructor copies arrays (immutability)', ({ assert }) => {
|
|
23
24
|
const rules = [{ type: 'allowPublic' }]
|
|
24
25
|
|
|
25
|
-
const action = new CreateAction(
|
|
26
|
+
const action = new CreateAction(mockExposedEntity(), {
|
|
26
27
|
accessRule: rules,
|
|
27
28
|
})
|
|
28
29
|
|
|
@@ -35,7 +36,7 @@ test.group('CreateAction', () => {
|
|
|
35
36
|
}).tags(['@modeling', '@action', '@create-action', '@immutability'])
|
|
36
37
|
|
|
37
38
|
test('toJSON returns valid schema', ({ assert }) => {
|
|
38
|
-
const action = new CreateAction(
|
|
39
|
+
const action = new CreateAction(mockExposedEntity(), {
|
|
39
40
|
accessRule: [{ type: 'allowPublic' }],
|
|
40
41
|
})
|
|
41
42
|
|
|
@@ -51,14 +52,14 @@ test.group('CreateAction', () => {
|
|
|
51
52
|
}).tags(['@modeling', '@action', '@create-action', '@serialization'])
|
|
52
53
|
|
|
53
54
|
test('notifies change when inherited property changes', async ({ assert }) => {
|
|
54
|
-
const action = new CreateAction(
|
|
55
|
+
const action = new CreateAction(mockExposedEntity())
|
|
55
56
|
let notified = false
|
|
56
57
|
action.addEventListener('change', () => {
|
|
57
58
|
notified = true
|
|
58
59
|
})
|
|
59
60
|
|
|
60
61
|
// Modify inherited property
|
|
61
|
-
action.accessRule = [new AccessRule({ type: 'allowPublic' })]
|
|
62
|
+
action.accessRule = [new AccessRule(mockExposedEntity(), { type: 'allowPublic' })]
|
|
62
63
|
await Promise.resolve()
|
|
63
64
|
assert.isTrue(notified)
|
|
64
65
|
}).tags(['@modeling', '@action', '@create-action', '@observed'])
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { test } from '@japa/runner'
|
|
2
2
|
import { DeleteAction } from '../../../../src/modeling/actions/DeleteAction.js'
|
|
3
|
+
import { mockExposedEntity } from './helpers.js'
|
|
3
4
|
|
|
4
5
|
test.group('DeleteAction', () => {
|
|
5
6
|
test('initializes with default values', ({ assert }) => {
|
|
6
|
-
const action = new DeleteAction(
|
|
7
|
+
const action = new DeleteAction(mockExposedEntity())
|
|
7
8
|
assert.equal(action.kind, 'delete')
|
|
8
9
|
assert.equal(action.strategy, 'soft')
|
|
9
10
|
assert.equal(action.retentionPeriod, 30)
|
|
@@ -11,7 +12,7 @@ test.group('DeleteAction', () => {
|
|
|
11
12
|
}).tags(['@modeling', '@action', '@delete-action'])
|
|
12
13
|
|
|
13
14
|
test('initializes with provided values', ({ assert }) => {
|
|
14
|
-
const action = new DeleteAction(
|
|
15
|
+
const action = new DeleteAction(mockExposedEntity(), {
|
|
15
16
|
strategy: 'hard',
|
|
16
17
|
retentionPeriod: 0,
|
|
17
18
|
accessRule: [{ type: 'allowPublic' }],
|
|
@@ -27,7 +28,7 @@ test.group('DeleteAction', () => {
|
|
|
27
28
|
test('constructor copies arrays (immutability)', ({ assert }) => {
|
|
28
29
|
const rules = [{ type: 'allowPublic' }]
|
|
29
30
|
|
|
30
|
-
const action = new DeleteAction(
|
|
31
|
+
const action = new DeleteAction(mockExposedEntity(), {
|
|
31
32
|
accessRule: rules,
|
|
32
33
|
})
|
|
33
34
|
|
|
@@ -40,7 +41,7 @@ test.group('DeleteAction', () => {
|
|
|
40
41
|
}).tags(['@modeling', '@action', '@delete-action', '@immutability'])
|
|
41
42
|
|
|
42
43
|
test('toJSON returns valid schema', ({ assert }) => {
|
|
43
|
-
const action = new DeleteAction(
|
|
44
|
+
const action = new DeleteAction(mockExposedEntity(), {
|
|
44
45
|
strategy: 'hard',
|
|
45
46
|
retentionPeriod: 0,
|
|
46
47
|
})
|
|
@@ -53,7 +54,7 @@ test.group('DeleteAction', () => {
|
|
|
53
54
|
}).tags(['@modeling', '@action', '@delete-action', '@serialization'])
|
|
54
55
|
|
|
55
56
|
test('notifies change when strategy changes', async ({ assert }) => {
|
|
56
|
-
const action = new DeleteAction(
|
|
57
|
+
const action = new DeleteAction(mockExposedEntity())
|
|
57
58
|
let notified = false
|
|
58
59
|
action.addEventListener('change', () => {
|
|
59
60
|
notified = true
|
|
@@ -65,7 +66,7 @@ test.group('DeleteAction', () => {
|
|
|
65
66
|
}).tags(['@modeling', '@action', '@delete-action', '@observed'])
|
|
66
67
|
|
|
67
68
|
test('notifies change when retentionPeriod changes', async ({ assert }) => {
|
|
68
|
-
const action = new DeleteAction(
|
|
69
|
+
const action = new DeleteAction(mockExposedEntity())
|
|
69
70
|
let notified = false
|
|
70
71
|
action.addEventListener('change', () => {
|
|
71
72
|
notified = true
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { test } from '@japa/runner'
|
|
2
2
|
import { ListAction } from '../../../../src/modeling/actions/ListAction.js'
|
|
3
|
+
import { mockExposedEntity } from './helpers.js'
|
|
3
4
|
|
|
4
5
|
test.group('ListAction', () => {
|
|
5
6
|
test('initializes with default values', ({ assert }) => {
|
|
6
|
-
const action = new ListAction(
|
|
7
|
+
const action = new ListAction(mockExposedEntity())
|
|
7
8
|
assert.equal(action.kind, 'list')
|
|
8
9
|
assert.isUndefined(action.cacheTtl)
|
|
9
10
|
assert.isEmpty(action.accessRule) // Inherited from Action
|
|
@@ -12,7 +13,7 @@ test.group('ListAction', () => {
|
|
|
12
13
|
test('initializes with provided values', ({ assert }) => {
|
|
13
14
|
const cacheTtl = 100
|
|
14
15
|
|
|
15
|
-
const action = new ListAction(
|
|
16
|
+
const action = new ListAction(mockExposedEntity(), {
|
|
16
17
|
cacheTtl,
|
|
17
18
|
})
|
|
18
19
|
|
|
@@ -20,7 +21,7 @@ test.group('ListAction', () => {
|
|
|
20
21
|
}).tags(['@modeling', '@action', '@list-action'])
|
|
21
22
|
|
|
22
23
|
test('toJSON returns safe copy', ({ assert }) => {
|
|
23
|
-
const action = new ListAction(
|
|
24
|
+
const action = new ListAction(mockExposedEntity(), {
|
|
24
25
|
cacheTtl: 100,
|
|
25
26
|
})
|
|
26
27
|
|
|
@@ -33,7 +34,7 @@ test.group('ListAction', () => {
|
|
|
33
34
|
}).tags(['@modeling', '@action', '@list-action', '@immutability'])
|
|
34
35
|
|
|
35
36
|
test('notifies change when cacheTtl changes', async ({ assert }) => {
|
|
36
|
-
const action = new ListAction(
|
|
37
|
+
const action = new ListAction(mockExposedEntity())
|
|
37
38
|
let notified = false
|
|
38
39
|
action.addEventListener('change', () => {
|
|
39
40
|
notified = true
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { test } from '@japa/runner'
|
|
2
2
|
import { ReadAction } from '../../../../src/modeling/actions/ReadAction.js'
|
|
3
3
|
import { AccessRule } from '../../../../src/modeling/rules/index.js'
|
|
4
|
+
import { mockExposedEntity } from './helpers.js'
|
|
4
5
|
|
|
5
6
|
test.group('ReadAction', () => {
|
|
6
7
|
test('initializes with default values', ({ assert }) => {
|
|
7
|
-
const action = new ReadAction(
|
|
8
|
+
const action = new ReadAction(mockExposedEntity())
|
|
8
9
|
assert.equal(action.kind, 'read')
|
|
9
10
|
assert.isEmpty(action.accessRule) // Inherited from Action
|
|
10
11
|
}).tags(['@modeling', '@action', '@read-action'])
|
|
11
12
|
|
|
12
13
|
test('initializes with inherited values', ({ assert }) => {
|
|
13
|
-
const action = new ReadAction(
|
|
14
|
+
const action = new ReadAction(mockExposedEntity(), {
|
|
14
15
|
accessRule: [{ type: 'allowPublic' }],
|
|
15
16
|
})
|
|
16
17
|
|
|
@@ -22,7 +23,7 @@ test.group('ReadAction', () => {
|
|
|
22
23
|
test('constructor copies arrays (immutability)', ({ assert }) => {
|
|
23
24
|
const rules = [{ type: 'allowPublic' }]
|
|
24
25
|
|
|
25
|
-
const action = new ReadAction(
|
|
26
|
+
const action = new ReadAction(mockExposedEntity(), {
|
|
26
27
|
accessRule: rules,
|
|
27
28
|
})
|
|
28
29
|
|
|
@@ -35,7 +36,7 @@ test.group('ReadAction', () => {
|
|
|
35
36
|
}).tags(['@modeling', '@action', '@read-action', '@immutability'])
|
|
36
37
|
|
|
37
38
|
test('toJSON returns valid schema', ({ assert }) => {
|
|
38
|
-
const action = new ReadAction(
|
|
39
|
+
const action = new ReadAction(mockExposedEntity(), {
|
|
39
40
|
accessRule: [{ type: 'allowPublic' }],
|
|
40
41
|
})
|
|
41
42
|
|
|
@@ -51,26 +52,26 @@ test.group('ReadAction', () => {
|
|
|
51
52
|
}).tags(['@modeling', '@action', '@read-action', '@serialization'])
|
|
52
53
|
|
|
53
54
|
test('notifies change when inherited property changes', async ({ assert }) => {
|
|
54
|
-
const action = new ReadAction(
|
|
55
|
+
const action = new ReadAction(mockExposedEntity())
|
|
55
56
|
let notified = false
|
|
56
57
|
action.addEventListener('change', () => {
|
|
57
58
|
notified = true
|
|
58
59
|
})
|
|
59
60
|
|
|
60
61
|
// Modify inherited property
|
|
61
|
-
action.accessRule = [new AccessRule({ type: 'allowPublic' })]
|
|
62
|
+
action.accessRule = [new AccessRule(mockExposedEntity(), { type: 'allowPublic' })]
|
|
62
63
|
await Promise.resolve()
|
|
63
64
|
assert.isTrue(notified)
|
|
64
65
|
}).tags(['@modeling', '@action', '@read-action', '@observed'])
|
|
65
66
|
|
|
66
67
|
test('notifies change when accessRule value change', async ({ assert }) => {
|
|
67
|
-
const action = new ReadAction(
|
|
68
|
+
const action = new ReadAction(mockExposedEntity())
|
|
68
69
|
let notified = false
|
|
69
70
|
action.addEventListener('change', () => {
|
|
70
71
|
notified = true
|
|
71
72
|
})
|
|
72
73
|
|
|
73
|
-
action.accessRule.push(new AccessRule({ type: 'allowPublic' }))
|
|
74
|
+
action.accessRule.push(new AccessRule(mockExposedEntity(), { type: 'allowPublic' }))
|
|
74
75
|
await Promise.resolve()
|
|
75
76
|
assert.isTrue(notified)
|
|
76
77
|
}).tags(['@modeling', '@action', '@read-action', '@observed'])
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { test } from '@japa/runner'
|
|
2
2
|
import { SearchAction } from '../../../../src/modeling/actions/SearchAction.js'
|
|
3
|
+
import { mockExposedEntity } from './helpers.js'
|
|
3
4
|
|
|
4
5
|
test.group('SearchAction', () => {
|
|
5
6
|
test('initializes with default values', ({ assert }) => {
|
|
6
|
-
const action = new SearchAction(
|
|
7
|
+
const action = new SearchAction(mockExposedEntity())
|
|
7
8
|
assert.equal(action.kind, 'search')
|
|
8
9
|
assert.isUndefined(action.maxAstDepth)
|
|
9
10
|
assert.isEmpty(action.accessRule)
|
|
@@ -11,7 +12,7 @@ test.group('SearchAction', () => {
|
|
|
11
12
|
|
|
12
13
|
test('initializes with provided values', ({ assert }) => {
|
|
13
14
|
const maxAstDepth = 10
|
|
14
|
-
const action = new SearchAction(
|
|
15
|
+
const action = new SearchAction(mockExposedEntity(), {
|
|
15
16
|
maxAstDepth,
|
|
16
17
|
})
|
|
17
18
|
|
|
@@ -20,7 +21,7 @@ test.group('SearchAction', () => {
|
|
|
20
21
|
}).tags(['@modeling', '@action', '@search-action'])
|
|
21
22
|
|
|
22
23
|
test('toJSON returns valid schema', ({ assert }) => {
|
|
23
|
-
const action = new SearchAction(
|
|
24
|
+
const action = new SearchAction(mockExposedEntity(), {
|
|
24
25
|
maxAstDepth: 10,
|
|
25
26
|
})
|
|
26
27
|
|
|
@@ -34,7 +35,7 @@ test.group('SearchAction', () => {
|
|
|
34
35
|
}).tags(['@modeling', '@action', '@search-action', '@serialization', '@immutability'])
|
|
35
36
|
|
|
36
37
|
test('notifies change when maxAstDepth changes', async ({ assert }) => {
|
|
37
|
-
const action = new SearchAction(
|
|
38
|
+
const action = new SearchAction(mockExposedEntity())
|
|
38
39
|
let notified = false
|
|
39
40
|
action.addEventListener('change', () => {
|
|
40
41
|
notified = true
|