@api-client/core 0.19.22 → 0.19.23

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 (72) hide show
  1. package/build/src/modeling/ApiModel.d.ts.map +1 -1
  2. package/build/src/modeling/ApiModel.js +37 -13
  3. package/build/src/modeling/ApiModel.js.map +1 -1
  4. package/build/src/modeling/ExposedEntity.d.ts.map +1 -1
  5. package/build/src/modeling/ExposedEntity.js +54 -15
  6. package/build/src/modeling/ExposedEntity.js.map +1 -1
  7. package/build/src/modeling/actions/Action.js +2 -2
  8. package/build/src/modeling/actions/Action.js.map +1 -1
  9. package/build/src/modeling/rules/AccessRule.d.ts +5 -1
  10. package/build/src/modeling/rules/AccessRule.d.ts.map +1 -1
  11. package/build/src/modeling/rules/AccessRule.js +4 -1
  12. package/build/src/modeling/rules/AccessRule.js.map +1 -1
  13. package/build/src/modeling/rules/AllowAuthenticated.d.ts +4 -1
  14. package/build/src/modeling/rules/AllowAuthenticated.d.ts.map +1 -1
  15. package/build/src/modeling/rules/AllowAuthenticated.js +2 -2
  16. package/build/src/modeling/rules/AllowAuthenticated.js.map +1 -1
  17. package/build/src/modeling/rules/AllowPublic.d.ts +4 -1
  18. package/build/src/modeling/rules/AllowPublic.d.ts.map +1 -1
  19. package/build/src/modeling/rules/AllowPublic.js +2 -2
  20. package/build/src/modeling/rules/AllowPublic.js.map +1 -1
  21. package/build/src/modeling/rules/MatchEmailDomain.d.ts +4 -1
  22. package/build/src/modeling/rules/MatchEmailDomain.d.ts.map +1 -1
  23. package/build/src/modeling/rules/MatchEmailDomain.js +2 -2
  24. package/build/src/modeling/rules/MatchEmailDomain.js.map +1 -1
  25. package/build/src/modeling/rules/MatchResourceOwner.d.ts +4 -1
  26. package/build/src/modeling/rules/MatchResourceOwner.d.ts.map +1 -1
  27. package/build/src/modeling/rules/MatchResourceOwner.js +2 -2
  28. package/build/src/modeling/rules/MatchResourceOwner.js.map +1 -1
  29. package/build/src/modeling/rules/MatchUserProperty.d.ts +4 -1
  30. package/build/src/modeling/rules/MatchUserProperty.d.ts.map +1 -1
  31. package/build/src/modeling/rules/MatchUserProperty.js +2 -2
  32. package/build/src/modeling/rules/MatchUserProperty.js.map +1 -1
  33. package/build/src/modeling/rules/MatchUserRole.d.ts +4 -1
  34. package/build/src/modeling/rules/MatchUserRole.d.ts.map +1 -1
  35. package/build/src/modeling/rules/MatchUserRole.js +2 -2
  36. package/build/src/modeling/rules/MatchUserRole.js.map +1 -1
  37. package/build/src/modeling/rules/index.d.ts +4 -1
  38. package/build/src/modeling/rules/index.d.ts.map +1 -1
  39. package/build/src/modeling/rules/index.js +7 -7
  40. package/build/src/modeling/rules/index.js.map +1 -1
  41. package/build/tsconfig.tsbuildinfo +1 -1
  42. package/package.json +1 -1
  43. package/src/modeling/ApiModel.ts +37 -13
  44. package/src/modeling/ExposedEntity.ts +62 -16
  45. package/src/modeling/actions/Action.ts +2 -2
  46. package/src/modeling/rules/AccessRule.ts +8 -1
  47. package/src/modeling/rules/AllowAuthenticated.ts +5 -2
  48. package/src/modeling/rules/AllowPublic.ts +5 -2
  49. package/src/modeling/rules/MatchEmailDomain.ts +5 -2
  50. package/src/modeling/rules/MatchResourceOwner.ts +5 -2
  51. package/src/modeling/rules/MatchUserProperty.ts +5 -2
  52. package/src/modeling/rules/MatchUserRole.ts +5 -2
  53. package/tests/unit/modeling/actions/Action.spec.ts +13 -10
  54. package/tests/unit/modeling/actions/CreateAction.spec.ts +7 -6
  55. package/tests/unit/modeling/actions/DeleteAction.spec.ts +7 -6
  56. package/tests/unit/modeling/actions/ListAction.spec.ts +5 -4
  57. package/tests/unit/modeling/actions/ReadAction.spec.ts +9 -8
  58. package/tests/unit/modeling/actions/SearchAction.spec.ts +5 -4
  59. package/tests/unit/modeling/actions/UpdateAction.spec.ts +7 -6
  60. package/tests/unit/modeling/actions/helpers.ts +7 -0
  61. package/tests/unit/modeling/api_model.spec.ts +3 -1
  62. package/tests/unit/modeling/api_model_expose_entity.spec.ts +5 -17
  63. package/tests/unit/modeling/exposed_entity.spec.ts +6 -2
  64. package/tests/unit/modeling/exposed_entity_actions.spec.ts +0 -4
  65. package/tests/unit/modeling/rules/AccessRule.spec.ts +6 -5
  66. package/tests/unit/modeling/rules/AllowAuthenticated.spec.ts +4 -3
  67. package/tests/unit/modeling/rules/AllowPublic.spec.ts +4 -3
  68. package/tests/unit/modeling/rules/MatchEmailDomain.spec.ts +6 -5
  69. package/tests/unit/modeling/rules/MatchResourceOwner.spec.ts +7 -6
  70. package/tests/unit/modeling/rules/MatchUserProperty.spec.ts +6 -5
  71. package/tests/unit/modeling/rules/MatchUserRole.spec.ts +6 -5
  72. package/tests/unit/modeling/rules/restoring_rules.spec.ts +19 -21
@@ -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({} as any)
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({} as any, {
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({} as any, {
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({} as any, {
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({} as any)
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({} as any)
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({} as any)
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({} as any, {
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({} as any, {
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({} as any)
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({} as any)
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({} as any, {
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({} as any, {
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({} as any, {
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({} as any)
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({} as any)
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({} as any)
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({} as any, {
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({} as any, {
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({} as any)
38
+ const action = new SearchAction(mockExposedEntity())
38
39
  let notified = false
39
40
  action.addEventListener('change', () => {
40
41
  notified = true
@@ -1,9 +1,10 @@
1
1
  import { test } from '@japa/runner'
2
2
  import { UpdateAction } from '../../../../src/modeling/actions/UpdateAction.js'
3
+ import { mockExposedEntity } from './helpers.js'
3
4
 
4
5
  test.group('UpdateAction', () => {
5
6
  test('initializes with default values', ({ assert }) => {
6
- const action = new UpdateAction({} as any)
7
+ const action = new UpdateAction(mockExposedEntity())
7
8
  assert.equal(action.kind, 'update')
8
9
  assert.deepEqual(action.allowedMethods, ['PATCH'])
9
10
  assert.isEmpty(action.accessRule)
@@ -11,7 +12,7 @@ test.group('UpdateAction', () => {
11
12
 
12
13
  test('initializes with provided values', ({ assert }) => {
13
14
  const methods: ('PUT' | 'PATCH')[] = ['PUT', 'PATCH']
14
- const action = new UpdateAction({} as any, {
15
+ const action = new UpdateAction(mockExposedEntity(), {
15
16
  allowedMethods: methods,
16
17
  })
17
18
 
@@ -22,7 +23,7 @@ test.group('UpdateAction', () => {
22
23
  test('constructor copies arrays (immutability)', ({ assert }) => {
23
24
  const methods: ('PUT' | 'PATCH')[] = ['PUT']
24
25
 
25
- const action = new UpdateAction({} as any, {
26
+ const action = new UpdateAction(mockExposedEntity(), {
26
27
  allowedMethods: methods,
27
28
  })
28
29
 
@@ -33,7 +34,7 @@ test.group('UpdateAction', () => {
33
34
  }).tags(['@modeling', '@action', '@update-action', '@immutability'])
34
35
 
35
36
  test('toJSON returns valid schema', ({ assert }) => {
36
- const action = new UpdateAction({} as any, {
37
+ const action = new UpdateAction(mockExposedEntity(), {
37
38
  allowedMethods: ['PUT'],
38
39
  })
39
40
 
@@ -48,7 +49,7 @@ test.group('UpdateAction', () => {
48
49
  }).tags(['@modeling', '@action', '@update-action', '@serialization', '@immutability'])
49
50
 
50
51
  test('notifies change when allowedMethods changes', async ({ assert }) => {
51
- const action = new UpdateAction({} as any)
52
+ const action = new UpdateAction(mockExposedEntity())
52
53
  let notified = false
53
54
  action.addEventListener('change', () => {
54
55
  notified = true
@@ -60,7 +61,7 @@ test.group('UpdateAction', () => {
60
61
  }).tags(['@modeling', '@action', '@update-action', '@observed'])
61
62
 
62
63
  test('notifies change when allowedMethods value change', async ({ assert }) => {
63
- const action = new UpdateAction({} as any)
64
+ const action = new UpdateAction(mockExposedEntity())
64
65
  let notified = false
65
66
  action.addEventListener('change', () => {
66
67
  notified = true
@@ -0,0 +1,7 @@
1
+ import { type ExposedEntity } from '../../../../src/modeling/ExposedEntity.js'
2
+
3
+ export function mockExposedEntity(): ExposedEntity {
4
+ return {
5
+ notifyChange: () => {},
6
+ } as unknown as ExposedEntity
7
+ }
@@ -152,7 +152,7 @@ test.group('ApiModel.constructor()', () => {
152
152
  assert.deepEqual(model.authentication, { strategy: 'UsernamePassword' })
153
153
  assert.deepEqual(model.authorization, { strategy: 'RBAC', roleKey: 'role' })
154
154
  assert.deepEqual(model.session, { secret: 'secret', properties: ['email'] })
155
- assert.deepEqual(model.accessRule, [new AllowPublicAccessRule()])
155
+ assert.deepEqual(model.accessRule, [new AllowPublicAccessRule(model)])
156
156
  assert.deepEqual(model.rateLimiting, new RateLimitingConfiguration())
157
157
  assert.equal(model.termsOfService, 'https://example.com/terms')
158
158
  assert.deepEqual(model.contact, { name: 'John Doe', email: 'john.doe@example.com' })
@@ -223,6 +223,8 @@ test.group('ApiModel.constructor()', () => {
223
223
  })
224
224
 
225
225
  Array.from(model.exposes.values())[0]!.actions[0]!.kind = 'write'
226
+ // there are two microtasks on the notification path.
227
+ await Promise.resolve()
226
228
  await Promise.resolve()
227
229
  assert.isTrue(notified)
228
230
  }).tags(['@modeling', '@api', '@observed'])
@@ -35,20 +35,6 @@ test.group('ApiModel.exposeEntity()', () => {
35
35
  assert.deepEqual(exposedEntity.actions, [])
36
36
  }).tags(['@modeling', '@api'])
37
37
 
38
- test('returns an existing entity if already exposed', ({ assert }) => {
39
- const domain = new DataDomain()
40
- domain.info.version = '1.0.0'
41
- const dm = domain.addModel()
42
- const e1 = dm.addEntity()
43
- const model = new ApiModel()
44
- model.attachDataDomain(domain)
45
- const initialExposedEntity = model.exposeEntity({ key: e1.key })
46
- const retrievedExposedEntity = model.exposeEntity({ key: e1.key })
47
-
48
- assert.deepEqual(retrievedExposedEntity.toJSON(), initialExposedEntity.toJSON())
49
- assert.equal(model.exposes.size, 1)
50
- }).tags(['@modeling', '@api'])
51
-
52
38
  test('notifies change when a new entity is exposed', async ({ assert }) => {
53
39
  const domain = new DataDomain()
54
40
  domain.info.version = '1.0.0'
@@ -65,7 +51,7 @@ test.group('ApiModel.exposeEntity()', () => {
65
51
  assert.isTrue(notified)
66
52
  }).tags(['@modeling', '@api'])
67
53
 
68
- test('does not notify change if entity already exposed', async ({ assert }) => {
54
+ test('throws if entity already exposed', async ({ assert }) => {
69
55
  const domain = new DataDomain()
70
56
  domain.info.version = '1.0.0'
71
57
  const dm = domain.addModel()
@@ -78,9 +64,11 @@ test.group('ApiModel.exposeEntity()', () => {
78
64
  model.addEventListener('change', () => {
79
65
  notified = true
80
66
  })
81
- model.exposeEntity({ key: e1.key }) // Second exposure
67
+ await assert.rejects(async () => {
68
+ model.exposeEntity({ key: e1.key }) // Second exposure
69
+ }, `Entity ${e1.key} is already exposed.`)
82
70
  await Promise.resolve() // Allow microtask to run
83
- assert.isFalse(notified)
71
+ assert.isFalse(notified, 'should not notify change if entity already exposed')
84
72
  }).tags(['@modeling', '@api'])
85
73
 
86
74
  test('exposes nested entities through associations', ({ assert }) => {
@@ -127,7 +127,9 @@ test.group('ExposedEntity', () => {
127
127
 
128
128
  const ex = Array.from(model.exposes.values())[0]
129
129
  ex.setCollectionPath('items')
130
- await Promise.resolve() // allow ApiModel.notifyChange microtask to run
130
+ // there are two microtasks on the notification path.
131
+ await Promise.resolve()
132
+ await Promise.resolve()
131
133
  assert.isAtLeast(notified, 1)
132
134
  }).tags(['@modeling', '@exposed-entity', '@observed'])
133
135
 
@@ -154,6 +156,8 @@ test.group('ExposedEntity', () => {
154
156
 
155
157
  const ex = Array.from(model.exposes.values())[0]
156
158
  ex.setResourcePath('/products/{productId}')
159
+ // there are two microtasks on the notification path.
160
+ await Promise.resolve()
157
161
  await Promise.resolve()
158
162
  assert.isAtLeast(notified, 1)
159
163
  }).tags(['@modeling', '@exposed-entity', '@observed'])
@@ -304,7 +308,7 @@ test.group('ExposedEntity', () => {
304
308
 
305
309
  test('getAllRules() aggregates rules from entity, parent, and API', ({ assert }) => {
306
310
  const model = new ApiModel()
307
- model.accessRule = [new AccessRule({ type: 'allowPublic' })]
311
+ model.accessRule = [new AccessRule(model, { type: 'allowPublic' })]
308
312
 
309
313
  const rootEx = new ExposedEntity(model, {
310
314
  key: 'root',
@@ -33,9 +33,6 @@ test.group('ExposedEntity::actions', (group) => {
33
33
  test('restores a list acton', ({ assert }) => {
34
34
  const action: ListActionSchema = {
35
35
  kind: 'list',
36
- pagination: { kind: '' },
37
- sortableFields: [],
38
- filterableFields: [],
39
36
  }
40
37
  const model = new ApiModel(
41
38
  {
@@ -177,7 +174,6 @@ test.group('ExposedEntity::actions', (group) => {
177
174
  test('restores a search acton', ({ assert }) => {
178
175
  const action: SearchActionSchema = {
179
176
  kind: 'search',
180
- fields: [],
181
177
  }
182
178
  const model = new ApiModel(
183
179
  {
@@ -1,26 +1,27 @@
1
1
  import { test } from '@japa/runner'
2
2
  import { AccessRule, type AccessRuleSchema } from '../../../../src/modeling/index.js'
3
+ import { mockExposedEntity } from '../actions/helpers.js'
3
4
 
4
5
  test.group('AccessRule', () => {
5
6
  test('initializes with default values', ({ assert }) => {
6
- const rule = new AccessRule()
7
+ const rule = new AccessRule(mockExposedEntity())
7
8
  assert.equal(rule.type, '')
8
9
  }).tags(['@modeling', '@access-rule'])
9
10
 
10
11
  test('initializes with provided values', ({ assert }) => {
11
12
  const schema: AccessRuleSchema = { type: 'public' }
12
- const rule = new AccessRule(schema)
13
+ const rule = new AccessRule(mockExposedEntity(), schema)
13
14
  assert.equal(rule.type, 'public')
14
15
  }).tags(['@modeling', '@access-rule'])
15
16
 
16
17
  test('serializes to JSON', ({ assert }) => {
17
- const rule = new AccessRule({ type: 'authenticated' })
18
+ const rule = new AccessRule(mockExposedEntity(), { type: 'authenticated' })
18
19
  const json = rule.toJSON()
19
20
  assert.deepEqual(json, { type: 'authenticated' })
20
21
  }).tags(['@modeling', '@access-rule'])
21
22
 
22
23
  test('notifies change', async ({ assert }) => {
23
- const rule = new AccessRule({ type: 'public' })
24
+ const rule = new AccessRule(mockExposedEntity(), { type: 'public' })
24
25
  let notified = false
25
26
  rule.addEventListener('change', () => {
26
27
  notified = true
@@ -31,7 +32,7 @@ test.group('AccessRule', () => {
31
32
  }).tags(['@modeling', '@access-rule'])
32
33
 
33
34
  test('toJSON returns safe copy (immutability)', ({ assert }) => {
34
- const rule = new AccessRule({ type: 'public' })
35
+ const rule = new AccessRule(mockExposedEntity(), { type: 'public' })
35
36
  const json = rule.toJSON()
36
37
 
37
38
  // Modify JSON (simulate runtime mutation)
@@ -1,21 +1,22 @@
1
1
  import { test } from '@japa/runner'
2
2
  import { AllowAuthenticatedAccessRule } from '../../../../src/modeling/rules/AllowAuthenticated.js'
3
+ import { mockExposedEntity } from '../actions/helpers.js'
3
4
 
4
5
  test.group('AllowAuthenticatedAccessRule', () => {
5
6
  test('initializes with correct type', ({ assert }) => {
6
- const rule = new AllowAuthenticatedAccessRule()
7
+ const rule = new AllowAuthenticatedAccessRule(mockExposedEntity())
7
8
  assert.equal(rule.type, 'allowAuthenticated')
8
9
  }).tags(['@modeling', '@rule', '@allow-authenticated'])
9
10
 
10
11
  test('toJSON returns valid schema', ({ assert }) => {
11
- const rule = new AllowAuthenticatedAccessRule()
12
+ const rule = new AllowAuthenticatedAccessRule(mockExposedEntity())
12
13
  const json = rule.toJSON()
13
14
 
14
15
  assert.equal(json.type, 'allowAuthenticated')
15
16
  }).tags(['@modeling', '@rule', '@allow-authenticated', '@serialization'])
16
17
 
17
18
  test('notifies change', async ({ assert }) => {
18
- const rule = new AllowAuthenticatedAccessRule()
19
+ const rule = new AllowAuthenticatedAccessRule(mockExposedEntity())
19
20
  let notified = false
20
21
  rule.addEventListener('change', () => {
21
22
  notified = true
@@ -1,21 +1,22 @@
1
1
  import { test } from '@japa/runner'
2
2
  import { AllowPublicAccessRule } from '../../../../src/modeling/rules/AllowPublic.js'
3
+ import { mockExposedEntity } from '../actions/helpers.js'
3
4
 
4
5
  test.group('AllowPublicAccessRule', () => {
5
6
  test('initializes with correct type', ({ assert }) => {
6
- const rule = new AllowPublicAccessRule()
7
+ const rule = new AllowPublicAccessRule(mockExposedEntity())
7
8
  assert.equal(rule.type, 'allowPublic')
8
9
  }).tags(['@modeling', '@rule', '@allow-public'])
9
10
 
10
11
  test('toJSON returns valid schema', ({ assert }) => {
11
- const rule = new AllowPublicAccessRule()
12
+ const rule = new AllowPublicAccessRule(mockExposedEntity())
12
13
  const json = rule.toJSON()
13
14
 
14
15
  assert.equal(json.type, 'allowPublic')
15
16
  }).tags(['@modeling', '@rule', '@allow-public', '@serialization'])
16
17
 
17
18
  test('notifies change', async ({ assert }) => {
18
- const rule = new AllowPublicAccessRule()
19
+ const rule = new AllowPublicAccessRule(mockExposedEntity())
19
20
  let notified = false
20
21
  rule.addEventListener('change', () => {
21
22
  notified = true
@@ -1,16 +1,17 @@
1
1
  import { test } from '@japa/runner'
2
2
  import { MatchEmailDomainAccessRule } from '../../../../src/modeling/rules/MatchEmailDomain.js'
3
+ import { mockExposedEntity } from '../actions/helpers.js'
3
4
 
4
5
  test.group('MatchEmailDomainAccessRule', () => {
5
6
  test('initializes with default values', ({ assert }) => {
6
- const rule = new MatchEmailDomainAccessRule()
7
+ const rule = new MatchEmailDomainAccessRule(mockExposedEntity())
7
8
  assert.equal(rule.type, 'matchEmailDomain')
8
9
  assert.deepEqual(rule.domains, [])
9
10
  }).tags(['@modeling', '@rule', '@match-email-domain'])
10
11
 
11
12
  test('initializes with provided values', ({ assert }) => {
12
13
  const domains = ['example.com', 'test.org']
13
- const rule = new MatchEmailDomainAccessRule({ domains })
14
+ const rule = new MatchEmailDomainAccessRule(mockExposedEntity(), { domains })
14
15
 
15
16
  assert.equal(rule.type, 'matchEmailDomain')
16
17
  assert.deepEqual(rule.domains, domains)
@@ -18,7 +19,7 @@ test.group('MatchEmailDomainAccessRule', () => {
18
19
 
19
20
  test('constructor copies arrays (immutability)', ({ assert }) => {
20
21
  const domains = ['example.com']
21
- const rule = new MatchEmailDomainAccessRule({ domains })
22
+ const rule = new MatchEmailDomainAccessRule(mockExposedEntity(), { domains })
22
23
 
23
24
  // Modify original source
24
25
  domains.push('hacker.com')
@@ -27,7 +28,7 @@ test.group('MatchEmailDomainAccessRule', () => {
27
28
  }).tags(['@modeling', '@rule', '@match-email-domain', '@immutability'])
28
29
 
29
30
  test('toJSON returns valid schema', ({ assert }) => {
30
- const rule = new MatchEmailDomainAccessRule({ domains: ['example.com'] })
31
+ const rule = new MatchEmailDomainAccessRule(mockExposedEntity(), { domains: ['example.com'] })
31
32
  const json = rule.toJSON()
32
33
 
33
34
  // Modify JSON
@@ -39,7 +40,7 @@ test.group('MatchEmailDomainAccessRule', () => {
39
40
  }).tags(['@modeling', '@rule', '@match-email-domain', '@serialization', '@immutability'])
40
41
 
41
42
  test('notifies change when domains changes', async ({ assert }) => {
42
- const rule = new MatchEmailDomainAccessRule()
43
+ const rule = new MatchEmailDomainAccessRule(mockExposedEntity())
43
44
  let notified = false
44
45
  rule.addEventListener('change', () => {
45
46
  notified = true
@@ -1,16 +1,17 @@
1
1
  import { test } from '@japa/runner'
2
2
  import { MatchResourceOwnerAccessRule } from '../../../../src/modeling/rules/MatchResourceOwner.js'
3
+ import { mockExposedEntity } from '../actions/helpers.js'
3
4
 
4
5
  test.group('MatchResourceOwnerAccessRule', () => {
5
6
  test('initializes with default values', ({ assert }) => {
6
- const rule = new MatchResourceOwnerAccessRule()
7
+ const rule = new MatchResourceOwnerAccessRule(mockExposedEntity())
7
8
  assert.equal(rule.type, 'matchResourceOwner')
8
9
  assert.isUndefined(rule.property)
9
10
  assert.equal(rule.target, 'property')
10
11
  }).tags(['@modeling', '@rule', '@match-resource-owner'])
11
12
 
12
13
  test('initializes with provided values', ({ assert }) => {
13
- const rule = new MatchResourceOwnerAccessRule({ property: 'creatorId' })
14
+ const rule = new MatchResourceOwnerAccessRule(mockExposedEntity(), { property: 'creatorId' })
14
15
 
15
16
  assert.equal(rule.type, 'matchResourceOwner')
16
17
  assert.equal(rule.property, 'creatorId')
@@ -18,7 +19,7 @@ test.group('MatchResourceOwnerAccessRule', () => {
18
19
  }).tags(['@modeling', '@rule', '@match-resource-owner'])
19
20
 
20
21
  test('initializes with target user-entity', ({ assert }) => {
21
- const rule = new MatchResourceOwnerAccessRule({ target: 'user-entity' })
22
+ const rule = new MatchResourceOwnerAccessRule(mockExposedEntity(), { target: 'user-entity' })
22
23
 
23
24
  assert.equal(rule.type, 'matchResourceOwner')
24
25
  assert.isUndefined(rule.property)
@@ -26,7 +27,7 @@ test.group('MatchResourceOwnerAccessRule', () => {
26
27
  }).tags(['@modeling', '@rule', '@match-resource-owner'])
27
28
 
28
29
  test('toJSON returns valid schema', ({ assert }) => {
29
- const rule = new MatchResourceOwnerAccessRule({ property: 'creatorId' })
30
+ const rule = new MatchResourceOwnerAccessRule(mockExposedEntity(), { property: 'creatorId' })
30
31
  const json = rule.toJSON()
31
32
 
32
33
  assert.equal(json.type, 'matchResourceOwner')
@@ -35,7 +36,7 @@ test.group('MatchResourceOwnerAccessRule', () => {
35
36
  }).tags(['@modeling', '@rule', '@match-resource-owner', '@serialization'])
36
37
 
37
38
  test('toJSON omits property when undefined', ({ assert }) => {
38
- const rule = new MatchResourceOwnerAccessRule({ target: 'user-entity' })
39
+ const rule = new MatchResourceOwnerAccessRule(mockExposedEntity(), { target: 'user-entity' })
39
40
  const json = rule.toJSON()
40
41
 
41
42
  assert.equal(json.type, 'matchResourceOwner')
@@ -44,7 +45,7 @@ test.group('MatchResourceOwnerAccessRule', () => {
44
45
  }).tags(['@modeling', '@rule', '@match-resource-owner', '@serialization'])
45
46
 
46
47
  test('notifies change when property changes', async ({ assert }) => {
47
- const rule = new MatchResourceOwnerAccessRule()
48
+ const rule = new MatchResourceOwnerAccessRule(mockExposedEntity())
48
49
  let notified = false
49
50
  rule.addEventListener('change', () => {
50
51
  notified = true
@@ -1,16 +1,17 @@
1
1
  import { test } from '@japa/runner'
2
2
  import { MatchUserPropertyAccessRule } from '../../../../src/modeling/rules/MatchUserProperty.js'
3
+ import { mockExposedEntity } from '../actions/helpers.js'
3
4
 
4
5
  test.group('MatchUserPropertyAccessRule', () => {
5
6
  test('initializes with default values', ({ assert }) => {
6
- const rule = new MatchUserPropertyAccessRule()
7
+ const rule = new MatchUserPropertyAccessRule(mockExposedEntity())
7
8
  assert.equal(rule.type, 'matchUserProperty')
8
9
  assert.equal(rule.property, '')
9
10
  assert.equal(rule.value, '')
10
11
  }).tags(['@modeling', '@rule', '@match-user-property'])
11
12
 
12
13
  test('initializes with provided values', ({ assert }) => {
13
- const rule = new MatchUserPropertyAccessRule({
14
+ const rule = new MatchUserPropertyAccessRule(mockExposedEntity(), {
14
15
  property: 'department',
15
16
  value: 'engineering',
16
17
  })
@@ -21,7 +22,7 @@ test.group('MatchUserPropertyAccessRule', () => {
21
22
  }).tags(['@modeling', '@rule', '@match-user-property'])
22
23
 
23
24
  test('toJSON returns valid schema', ({ assert }) => {
24
- const rule = new MatchUserPropertyAccessRule({
25
+ const rule = new MatchUserPropertyAccessRule(mockExposedEntity(), {
25
26
  property: 'department',
26
27
  value: 'engineering',
27
28
  })
@@ -33,7 +34,7 @@ test.group('MatchUserPropertyAccessRule', () => {
33
34
  }).tags(['@modeling', '@rule', '@match-user-property', '@serialization'])
34
35
 
35
36
  test('notifies change when property changes', async ({ assert }) => {
36
- const rule = new MatchUserPropertyAccessRule()
37
+ const rule = new MatchUserPropertyAccessRule(mockExposedEntity())
37
38
  let notified = false
38
39
  rule.addEventListener('change', () => {
39
40
  notified = true
@@ -45,7 +46,7 @@ test.group('MatchUserPropertyAccessRule', () => {
45
46
  }).tags(['@modeling', '@rule', '@match-user-property', '@observed'])
46
47
 
47
48
  test('notifies change when value changes', async ({ assert }) => {
48
- const rule = new MatchUserPropertyAccessRule()
49
+ const rule = new MatchUserPropertyAccessRule(mockExposedEntity())
49
50
  let notified = false
50
51
  rule.addEventListener('change', () => {
51
52
  notified = true