@api-client/core 0.19.19 → 0.19.21

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 (130) hide show
  1. package/build/src/authorization/Utils.js +3 -3
  2. package/build/src/authorization/Utils.js.map +1 -1
  3. package/build/src/modeling/ApiModel.d.ts +16 -5
  4. package/build/src/modeling/ApiModel.d.ts.map +1 -1
  5. package/build/src/modeling/ApiModel.js +17 -2
  6. package/build/src/modeling/ApiModel.js.map +1 -1
  7. package/build/src/modeling/ApiValidation.d.ts.map +1 -1
  8. package/build/src/modeling/ApiValidation.js +2 -1
  9. package/build/src/modeling/ApiValidation.js.map +1 -1
  10. package/build/src/modeling/DomainProperty.d.ts +12 -0
  11. package/build/src/modeling/DomainProperty.d.ts.map +1 -1
  12. package/build/src/modeling/DomainProperty.js +23 -28
  13. package/build/src/modeling/DomainProperty.js.map +1 -1
  14. package/build/src/modeling/DomainSerialization.js +1 -1
  15. package/build/src/modeling/DomainSerialization.js.map +1 -1
  16. package/build/src/modeling/ExposedEntity.d.ts +15 -1
  17. package/build/src/modeling/ExposedEntity.d.ts.map +1 -1
  18. package/build/src/modeling/ExposedEntity.js +42 -4
  19. package/build/src/modeling/ExposedEntity.js.map +1 -1
  20. package/build/src/modeling/actions/Action.d.ts.map +1 -1
  21. package/build/src/modeling/actions/Action.js +1 -0
  22. package/build/src/modeling/actions/Action.js.map +1 -1
  23. package/build/src/modeling/actions/ListAction.d.ts +3 -17
  24. package/build/src/modeling/actions/ListAction.d.ts.map +1 -1
  25. package/build/src/modeling/actions/ListAction.js +18 -38
  26. package/build/src/modeling/actions/ListAction.js.map +1 -1
  27. package/build/src/modeling/actions/SearchAction.d.ts +4 -4
  28. package/build/src/modeling/actions/SearchAction.d.ts.map +1 -1
  29. package/build/src/modeling/actions/SearchAction.js +16 -13
  30. package/build/src/modeling/actions/SearchAction.js.map +1 -1
  31. package/build/src/modeling/generators/oas_312/OasGenerator.d.ts +32 -0
  32. package/build/src/modeling/generators/oas_312/OasGenerator.d.ts.map +1 -0
  33. package/build/src/modeling/generators/oas_312/OasGenerator.js +1452 -0
  34. package/build/src/modeling/generators/oas_312/OasGenerator.js.map +1 -0
  35. package/build/src/modeling/generators/oas_312/OasSchemaGenerator.d.ts +27 -0
  36. package/build/src/modeling/generators/oas_312/OasSchemaGenerator.d.ts.map +1 -0
  37. package/build/src/modeling/generators/oas_312/OasSchemaGenerator.js +295 -0
  38. package/build/src/modeling/generators/oas_312/OasSchemaGenerator.js.map +1 -0
  39. package/build/src/modeling/generators/oas_312/types.d.ts +1010 -0
  40. package/build/src/modeling/generators/oas_312/types.d.ts.map +1 -0
  41. package/build/src/modeling/generators/oas_312/types.js +2 -0
  42. package/build/src/modeling/generators/oas_312/types.js.map +1 -0
  43. package/build/src/modeling/generators/oas_320/OasGenerator.d.ts +16 -0
  44. package/build/src/modeling/generators/oas_320/OasGenerator.d.ts.map +1 -0
  45. package/build/src/modeling/generators/oas_320/OasGenerator.js +306 -0
  46. package/build/src/modeling/generators/oas_320/OasGenerator.js.map +1 -0
  47. package/build/src/modeling/generators/oas_320/OasSchemaGenerator.d.ts +25 -0
  48. package/build/src/modeling/generators/oas_320/OasSchemaGenerator.d.ts.map +1 -0
  49. package/build/src/modeling/generators/oas_320/OasSchemaGenerator.js +237 -0
  50. package/build/src/modeling/generators/oas_320/OasSchemaGenerator.js.map +1 -0
  51. package/build/src/modeling/generators/oas_320/types.d.ts +1219 -0
  52. package/build/src/modeling/generators/oas_320/types.d.ts.map +1 -0
  53. package/build/src/modeling/generators/oas_320/types.js +2 -0
  54. package/build/src/modeling/generators/oas_320/types.js.map +1 -0
  55. package/build/src/modeling/helpers/Intelisense.d.ts +1 -1
  56. package/build/src/modeling/helpers/Intelisense.d.ts.map +1 -1
  57. package/build/src/modeling/helpers/Intelisense.js +4 -2
  58. package/build/src/modeling/helpers/Intelisense.js.map +1 -1
  59. package/build/src/modeling/types.d.ts +50 -13
  60. package/build/src/modeling/types.d.ts.map +1 -1
  61. package/build/src/modeling/types.js.map +1 -1
  62. package/build/src/modeling/validation/api_model_rules.d.ts +1 -0
  63. package/build/src/modeling/validation/api_model_rules.d.ts.map +1 -1
  64. package/build/src/modeling/validation/api_model_rules.js +105 -29
  65. package/build/src/modeling/validation/api_model_rules.js.map +1 -1
  66. package/build/src/models/ProjectRequest.d.ts.map +1 -1
  67. package/build/src/models/ProjectRequest.js +0 -4
  68. package/build/src/models/ProjectRequest.js.map +1 -1
  69. package/build/src/models/transformers/ArcDexieTransformer.d.ts.map +1 -1
  70. package/build/src/models/transformers/ArcDexieTransformer.js +0 -4
  71. package/build/src/models/transformers/ArcDexieTransformer.js.map +1 -1
  72. package/build/src/models/transformers/ImportUtils.js +1 -1
  73. package/build/src/models/transformers/ImportUtils.js.map +1 -1
  74. package/build/src/models/transformers/PostmanBackupTransformer.d.ts.map +1 -1
  75. package/build/src/models/transformers/PostmanBackupTransformer.js +0 -4
  76. package/build/src/models/transformers/PostmanBackupTransformer.js.map +1 -1
  77. package/build/src/runtime/constants.d.ts +7 -0
  78. package/build/src/runtime/constants.d.ts.map +1 -0
  79. package/build/src/runtime/constants.js +8 -0
  80. package/build/src/runtime/constants.js.map +1 -0
  81. package/build/src/runtime/http-engine/ntlm/Des.d.ts.map +1 -1
  82. package/build/src/runtime/http-engine/ntlm/Des.js +1 -0
  83. package/build/src/runtime/http-engine/ntlm/Des.js.map +1 -1
  84. package/build/src/runtime/variables/EvalFunctions.d.ts.map +1 -1
  85. package/build/src/runtime/variables/EvalFunctions.js +0 -1
  86. package/build/src/runtime/variables/EvalFunctions.js.map +1 -1
  87. package/build/tsconfig.tsbuildinfo +1 -1
  88. package/eslint.config.js +6 -0
  89. package/package.json +3 -1
  90. package/src/authorization/Utils.ts +3 -3
  91. package/src/modeling/ApiModel.ts +23 -8
  92. package/src/modeling/ApiValidation.ts +2 -0
  93. package/src/modeling/DomainProperty.ts +22 -18
  94. package/src/modeling/DomainSerialization.ts +1 -1
  95. package/src/modeling/ExposedEntity.ts +44 -4
  96. package/src/modeling/actions/Action.ts +1 -0
  97. package/src/modeling/actions/ListAction.ts +12 -30
  98. package/src/modeling/actions/SearchAction.ts +11 -8
  99. package/src/modeling/generators/oas_312/OasGenerator.ts +1685 -0
  100. package/src/modeling/generators/oas_312/OasSchemaGenerator.ts +322 -0
  101. package/src/modeling/generators/oas_312/types.ts +1052 -0
  102. package/src/modeling/generators/oas_320/OasGenerator.ts +359 -0
  103. package/src/modeling/generators/oas_320/OasSchemaGenerator.ts +255 -0
  104. package/src/modeling/generators/oas_320/types.ts +1259 -0
  105. package/src/modeling/helpers/Intelisense.ts +4 -2
  106. package/src/modeling/types.ts +55 -22
  107. package/src/modeling/validation/api_model_rules.ts +103 -32
  108. package/src/models/ProjectRequest.ts +0 -4
  109. package/src/models/transformers/ArcDexieTransformer.ts +0 -4
  110. package/src/models/transformers/ImportUtils.ts +1 -1
  111. package/src/models/transformers/PostmanBackupTransformer.ts +0 -5
  112. package/src/runtime/constants.ts +9 -0
  113. package/src/runtime/http-engine/ntlm/Des.ts +1 -0
  114. package/src/runtime/variables/EvalFunctions.ts +0 -1
  115. package/tests/test-utils.ts +6 -2
  116. package/tests/unit/decorators/observed.spec.ts +8 -24
  117. package/tests/unit/decorators/observed_recursive.spec.ts +0 -1
  118. package/tests/unit/events/EventsTestHelpers.ts +0 -1
  119. package/tests/unit/events/events_polyfills.ts +0 -1
  120. package/tests/unit/legacy-transformers/DataTestHelper.ts +0 -2
  121. package/tests/unit/legacy-transformers/LegacyExportProcessor.spec.ts +0 -1
  122. package/tests/unit/modeling/actions/ListAction.spec.ts +9 -69
  123. package/tests/unit/modeling/actions/SearchAction.spec.ts +9 -35
  124. package/tests/unit/modeling/api_model.spec.ts +28 -0
  125. package/tests/unit/modeling/definitions/sku.spec.ts +0 -2
  126. package/tests/unit/modeling/domain_property.spec.ts +20 -1
  127. package/tests/unit/modeling/exposed_entity.spec.ts +71 -0
  128. package/tests/unit/modeling/generators/OasGenerator.spec.ts +302 -0
  129. package/tests/unit/modeling/helpers/intellisense.spec.ts +1 -1
  130. package/tests/unit/modeling/validation/api_model_rules.spec.ts +113 -15
@@ -1,105 +1,45 @@
1
1
  import { test } from '@japa/runner'
2
2
  import { ListAction } from '../../../../src/modeling/actions/ListAction.js'
3
- import { PaginationStrategy } from '../../../../src/modeling/types.js'
4
3
 
5
4
  test.group('ListAction', () => {
6
5
  test('initializes with default values', ({ assert }) => {
7
6
  const action = new ListAction({} as any)
8
7
  assert.equal(action.kind, 'list')
9
- assert.deepEqual(action.pagination, { kind: 'offset' })
10
- assert.deepEqual(action.filterableFields, [])
11
- assert.deepEqual(action.sortableFields, [])
8
+ assert.isUndefined(action.cacheTtl)
12
9
  assert.isEmpty(action.accessRule) // Inherited from Action
13
10
  }).tags(['@modeling', '@action', '@list-action'])
14
11
 
15
12
  test('initializes with provided values', ({ assert }) => {
16
- const pagination: PaginationStrategy = { kind: 'cursor' }
17
- const filterableFields = ['name', 'status']
18
- const sortableFields = ['createdAt']
13
+ const cacheTtl = 100
19
14
 
20
15
  const action = new ListAction({} as any, {
21
- pagination,
22
- filterableFields,
23
- sortableFields,
16
+ cacheTtl,
24
17
  })
25
18
 
26
- assert.deepEqual(action.pagination, pagination)
27
- assert.deepEqual(action.filterableFields, filterableFields)
28
- assert.deepEqual(action.sortableFields, sortableFields)
19
+ assert.equal(action.cacheTtl, cacheTtl)
29
20
  }).tags(['@modeling', '@action', '@list-action'])
30
21
 
31
- test('constructor copies arrays and objects (immutability)', ({ assert }) => {
32
- const pagination: PaginationStrategy = { kind: 'offset' }
33
- const filterableFields = ['name']
34
- const sortableFields = ['name']
35
-
36
- const action = new ListAction({} as any, {
37
- pagination,
38
- filterableFields,
39
- sortableFields,
40
- })
41
-
42
- // Modify original sources
43
- pagination.kind = 'cursor'
44
- filterableFields.push('age')
45
- sortableFields.push('age')
46
-
47
- assert.deepEqual(action.pagination, { kind: 'offset' })
48
- assert.deepEqual(action.filterableFields, ['name'])
49
- assert.deepEqual(action.sortableFields, ['name'])
50
- }).tags(['@modeling', '@action', '@list-action', '@immutability'])
51
-
52
22
  test('toJSON returns safe copy', ({ assert }) => {
53
23
  const action = new ListAction({} as any, {
54
- pagination: { kind: 'offset' },
55
- filterableFields: ['name'],
56
- sortableFields: ['name'],
24
+ cacheTtl: 100,
57
25
  })
58
26
 
59
27
  const json = action.toJSON()
60
28
 
61
29
  // Modify JSON
62
- json.pagination.kind = 'cursor'
63
- json.filterableFields.push('new')
64
- json.sortableFields.push('new')
30
+ json.cacheTtl = 200
65
31
 
66
- assert.deepEqual(action.pagination, { kind: 'offset' })
67
- assert.deepEqual(action.filterableFields, ['name'])
68
- assert.deepEqual(action.sortableFields, ['name'])
32
+ assert.equal(action.cacheTtl, 100)
69
33
  }).tags(['@modeling', '@action', '@list-action', '@immutability'])
70
34
 
71
- test('notifies change when pagination changes', async ({ assert }) => {
72
- const action = new ListAction({} as any)
73
- let notified = false
74
- action.addEventListener('change', () => {
75
- notified = true
76
- })
77
-
78
- action.pagination = { kind: 'cursor' }
79
- await Promise.resolve()
80
- assert.isTrue(notified)
81
- }).tags(['@modeling', '@action', '@list-action', '@observed'])
82
-
83
- test('notifies change when filterableFields changes', async ({ assert }) => {
84
- const action = new ListAction({} as any)
85
- let notified = false
86
- action.addEventListener('change', () => {
87
- notified = true
88
- })
89
-
90
- action.filterableFields = ['name']
91
- await Promise.resolve()
92
- assert.isTrue(notified)
93
- }).tags(['@modeling', '@action', '@list-action', '@observed'])
94
-
95
- test('notifies change when sortableFields changes', async ({ assert }) => {
35
+ test('notifies change when cacheTtl changes', async ({ assert }) => {
96
36
  const action = new ListAction({} as any)
97
37
  let notified = false
98
38
  action.addEventListener('change', () => {
99
39
  notified = true
100
40
  })
101
41
 
102
- action.sortableFields = ['name']
42
+ action.cacheTtl = 100
103
43
  await Promise.resolve()
104
44
  assert.isTrue(notified)
105
45
  }).tags(['@modeling', '@action', '@list-action', '@observed'])
@@ -5,68 +5,42 @@ test.group('SearchAction', () => {
5
5
  test('initializes with default values', ({ assert }) => {
6
6
  const action = new SearchAction({} as any)
7
7
  assert.equal(action.kind, 'search')
8
- assert.deepEqual(action.fields, [])
8
+ assert.isUndefined(action.maxAstDepth)
9
9
  assert.isEmpty(action.accessRule)
10
10
  }).tags(['@modeling', '@action', '@search-action'])
11
11
 
12
12
  test('initializes with provided values', ({ assert }) => {
13
- const fields = ['name', 'description']
13
+ const maxAstDepth = 10
14
14
  const action = new SearchAction({} as any, {
15
- fields,
15
+ maxAstDepth,
16
16
  })
17
17
 
18
18
  assert.equal(action.kind, 'search')
19
- assert.deepEqual(action.fields, fields)
19
+ assert.equal(action.maxAstDepth, maxAstDepth)
20
20
  }).tags(['@modeling', '@action', '@search-action'])
21
21
 
22
- test('constructor copies arrays (immutability)', ({ assert }) => {
23
- const fields = ['name']
24
-
25
- const action = new SearchAction({} as any, {
26
- fields,
27
- })
28
-
29
- // Modify original source
30
- fields.push('age')
31
-
32
- assert.deepEqual(action.fields, ['name'])
33
- }).tags(['@modeling', '@action', '@search-action', '@immutability'])
34
-
35
22
  test('toJSON returns valid schema', ({ assert }) => {
36
23
  const action = new SearchAction({} as any, {
37
- fields: ['name'],
24
+ maxAstDepth: 10,
38
25
  })
39
26
 
40
27
  const json = action.toJSON()
41
28
 
42
29
  // Modify JSON
43
- json.fields.push('new')
30
+ json.maxAstDepth = 20
44
31
 
45
32
  assert.equal(json.kind, 'search')
46
- assert.lengthOf(action.fields, 1) // Ensure immutability
47
- assert.equal(action.fields[0], 'name')
33
+ assert.equal(action.maxAstDepth, 10)
48
34
  }).tags(['@modeling', '@action', '@search-action', '@serialization', '@immutability'])
49
35
 
50
- test('notifies change when fields changes', async ({ assert }) => {
51
- const action = new SearchAction({} as any)
52
- let notified = false
53
- action.addEventListener('change', () => {
54
- notified = true
55
- })
56
-
57
- action.fields = ['name']
58
- await Promise.resolve()
59
- assert.isTrue(notified)
60
- }).tags(['@modeling', '@action', '@search-action', '@observed'])
61
-
62
- test('notifies change when fields value change', async ({ assert }) => {
36
+ test('notifies change when maxAstDepth changes', async ({ assert }) => {
63
37
  const action = new SearchAction({} as any)
64
38
  let notified = false
65
39
  action.addEventListener('change', () => {
66
40
  notified = true
67
41
  })
68
42
 
69
- action.fields.push('name')
43
+ action.maxAstDepth = 10
70
44
  await Promise.resolve()
71
45
  assert.isTrue(notified)
72
46
  }).tags(['@modeling', '@action', '@search-action', '@observed'])
@@ -33,6 +33,7 @@ test.group('ApiModel.createSchema()', () => {
33
33
  assert.isUndefined(schema.termsOfService)
34
34
  assert.isUndefined(schema.contact)
35
35
  assert.isUndefined(schema.license)
36
+ assert.deepEqual(schema.pagination, { kind: 'cursor' })
36
37
  }).tags(['@modeling', '@api', '@schema'])
37
38
 
38
39
  test('creates a schema with provided values', ({ assert }) => {
@@ -59,6 +60,7 @@ test.group('ApiModel.createSchema()', () => {
59
60
  termsOfService: 'https://example.com/terms',
60
61
  contact: { name: 'John Doe', email: 'john.doe@example.com' } as ApiContact,
61
62
  license: { name: 'MIT', url: 'https://opensource.org/licenses/MIT' } as ApiLicense,
63
+ pagination: { kind: 'offset', defaultLimit: 10 },
62
64
  }
63
65
  const schema = ApiModel.createSchema(input)
64
66
 
@@ -77,6 +79,7 @@ test.group('ApiModel.createSchema()', () => {
77
79
  assert.equal(schema.termsOfService, 'https://example.com/terms')
78
80
  assert.deepEqual(schema.contact, { name: 'John Doe', email: 'john.doe@example.com' })
79
81
  assert.deepEqual(schema.license, { name: 'MIT', url: 'https://opensource.org/licenses/MIT' })
82
+ assert.deepEqual(schema.pagination, { kind: 'offset', defaultLimit: 10 })
80
83
  }).tags(['@modeling', '@api', '@schema'])
81
84
 
82
85
  test('creates a schema with partial info', ({ assert }) => {
@@ -108,6 +111,7 @@ test.group('ApiModel.constructor()', () => {
108
111
  assert.isUndefined(model.contact)
109
112
  assert.isUndefined(model.license)
110
113
  assert.deepEqual(model.dependencyList, [])
114
+ assert.deepEqual(model.pagination, { kind: 'cursor' })
111
115
  }).tags(['@modeling', '@api', '@creation'])
112
116
 
113
117
  test('creates an instance with provided schema values', ({ assert }) => {
@@ -135,6 +139,7 @@ test.group('ApiModel.constructor()', () => {
135
139
  termsOfService: 'https://example.com/terms',
136
140
  contact: { name: 'John Doe', email: 'john.doe@example.com' },
137
141
  license: { name: 'MIT', url: 'https://opensource.org/licenses/MIT' },
142
+ pagination: { kind: 'offset', maxLimit: 50 },
138
143
  }
139
144
  const model = new ApiModel(schema)
140
145
 
@@ -152,6 +157,7 @@ test.group('ApiModel.constructor()', () => {
152
157
  assert.equal(model.termsOfService, 'https://example.com/terms')
153
158
  assert.deepEqual(model.contact, { name: 'John Doe', email: 'john.doe@example.com' })
154
159
  assert.deepEqual(model.license, { name: 'MIT', url: 'https://opensource.org/licenses/MIT' })
160
+ assert.deepEqual(model.pagination, { kind: 'offset', maxLimit: 50 })
155
161
  }).tags(['@modeling', '@api', '@creation'])
156
162
 
157
163
  test('creates an instance with a DataDomain', ({ assert }) => {
@@ -220,6 +226,25 @@ test.group('ApiModel.constructor()', () => {
220
226
  await Promise.resolve()
221
227
  assert.isTrue(notified)
222
228
  }).tags(['@modeling', '@api', '@observed'])
229
+
230
+ test('notifies change when pagination changes', async ({ assert }) => {
231
+ const model = new ApiModel()
232
+ let notified = false
233
+ model.addEventListener('change', () => {
234
+ notified = true
235
+ })
236
+
237
+ // Test mutability notifications
238
+ model.pagination.defaultLimit = 100
239
+ await Promise.resolve()
240
+ assert.isTrue(notified)
241
+ notified = false
242
+
243
+ // Test object reassignment
244
+ model.pagination = { kind: 'offset', maxLimit: 50 }
245
+ await Promise.resolve()
246
+ assert.isTrue(notified)
247
+ }).tags(['@modeling', '@api', '@observed'])
223
248
  })
224
249
 
225
250
  test.group('ApiModel.toJSON()', () => {
@@ -241,6 +266,7 @@ test.group('ApiModel.toJSON()', () => {
241
266
  assert.isUndefined(json.termsOfService)
242
267
  assert.isUndefined(json.contact)
243
268
  assert.isUndefined(json.license)
269
+ assert.deepEqual(json.pagination, { kind: 'cursor' })
244
270
  }).tags(['@modeling', '@api', '@serialization'])
245
271
 
246
272
  test('serializes all provided values', ({ assert }) => {
@@ -268,6 +294,7 @@ test.group('ApiModel.toJSON()', () => {
268
294
  termsOfService: 'https://example.com/terms',
269
295
  contact: { name: 'John Doe', email: 'john.doe@example.com' },
270
296
  license: { name: 'MIT', url: 'https://opensource.org/licenses/MIT' },
297
+ pagination: { kind: 'cursor', defaultLimit: 25 },
271
298
  }
272
299
  const model = new ApiModel(schema)
273
300
  const json = model.toJSON()
@@ -286,6 +313,7 @@ test.group('ApiModel.toJSON()', () => {
286
313
  assert.equal(json.termsOfService, 'https://example.com/terms')
287
314
  assert.deepEqual(json.contact, { name: 'John Doe', email: 'john.doe@example.com' })
288
315
  assert.deepEqual(json.license, { name: 'MIT', url: 'https://opensource.org/licenses/MIT' })
316
+ assert.deepEqual(json.pagination, { kind: 'cursor', defaultLimit: 25 })
289
317
  }).tags(['@modeling', '@api', '@serialization'])
290
318
 
291
319
  test('actions are immutable', ({ assert }) => {
@@ -130,9 +130,7 @@ test.group('SKU Value Validation', () => {
130
130
 
131
131
  test('should reject empty or null values', ({ assert }) => {
132
132
  assert.include(validateSKUValue(''), 'SKU value must be a non-empty string')
133
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
134
133
  assert.include(validateSKUValue(null as any), 'SKU value must be a non-empty string')
135
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
136
134
  assert.include(validateSKUValue(undefined as any), 'SKU value must be a non-empty string')
137
135
  })
138
136
 
@@ -13,6 +13,7 @@ test.group('DomainProperty.createSchema()', () => {
13
13
  assert.isUndefined(schema.multiple)
14
14
  assert.isUndefined(schema.required)
15
15
  assert.isUndefined(schema.index)
16
+ assert.isUndefined(schema.search)
16
17
  assert.isUndefined(schema.primary)
17
18
  assert.isUndefined(schema.readOnly)
18
19
  assert.isUndefined(schema.writeOnly)
@@ -31,6 +32,7 @@ test.group('DomainProperty.createSchema()', () => {
31
32
  multiple: true,
32
33
  primary: true,
33
34
  index: true,
35
+ search: true,
34
36
  readOnly: true,
35
37
  writeOnly: true,
36
38
  deprecated: true,
@@ -48,6 +50,7 @@ test.group('DomainProperty.createSchema()', () => {
48
50
  assert.isTrue(schema.multiple)
49
51
  assert.isTrue(schema.primary)
50
52
  assert.isTrue(schema.index)
53
+ assert.isTrue(schema.search)
51
54
  assert.isTrue(schema.readOnly)
52
55
  assert.isTrue(schema.writeOnly)
53
56
  assert.isTrue(schema.deprecated)
@@ -83,6 +86,7 @@ test.group('DomainProperty.createSchema()', () => {
83
86
  multiple: undefined,
84
87
  required: undefined,
85
88
  index: undefined,
89
+ search: undefined,
86
90
  primary: undefined,
87
91
  readOnly: undefined,
88
92
  writeOnly: undefined,
@@ -100,6 +104,7 @@ test.group('DomainProperty.createSchema()', () => {
100
104
  assert.isUndefined(schema.multiple)
101
105
  assert.isUndefined(schema.required)
102
106
  assert.isUndefined(schema.index)
107
+ assert.isUndefined(schema.search)
103
108
  assert.isUndefined(schema.primary)
104
109
  assert.isUndefined(schema.readOnly)
105
110
  assert.isUndefined(schema.writeOnly)
@@ -119,6 +124,8 @@ test.group('DomainProperty.createSchema()', () => {
119
124
  // @ts-expect-error Testing null values
120
125
  index: null,
121
126
  // @ts-expect-error Testing null values
127
+ search: null,
128
+ // @ts-expect-error Testing null values
122
129
  primary: null,
123
130
  // @ts-expect-error Testing null values
124
131
  readOnly: null,
@@ -138,6 +145,7 @@ test.group('DomainProperty.createSchema()', () => {
138
145
  assert.isUndefined(schema.multiple)
139
146
  assert.isUndefined(schema.required)
140
147
  assert.isUndefined(schema.index)
148
+ assert.isUndefined(schema.search)
141
149
  assert.isUndefined(schema.primary)
142
150
  assert.isUndefined(schema.readOnly)
143
151
  assert.isUndefined(schema.writeOnly)
@@ -165,6 +173,7 @@ test.group('DomainProperty.createSchema()', () => {
165
173
  multiple: false,
166
174
  primary: false,
167
175
  index: false,
176
+ search: false,
168
177
  readOnly: false,
169
178
  writeOnly: false,
170
179
  deprecated: false,
@@ -173,6 +182,7 @@ test.group('DomainProperty.createSchema()', () => {
173
182
  assert.isFalse(schema.multiple)
174
183
  assert.isFalse(schema.primary)
175
184
  assert.isFalse(schema.index)
185
+ assert.isFalse(schema.search)
176
186
  assert.isFalse(schema.readOnly)
177
187
  assert.isFalse(schema.writeOnly)
178
188
  assert.isFalse(schema.deprecated)
@@ -238,6 +248,7 @@ test.group('DomainProperty.constructor()', () => {
238
248
  assert.isUndefined(property.multiple)
239
249
  assert.isUndefined(property.required)
240
250
  assert.isUndefined(property.index)
251
+ assert.isUndefined(property.search)
241
252
  assert.isUndefined(property.primary)
242
253
  assert.isUndefined(property.readOnly)
243
254
  assert.isUndefined(property.writeOnly)
@@ -260,6 +271,7 @@ test.group('DomainProperty.constructor()', () => {
260
271
  multiple: true,
261
272
  primary: true,
262
273
  index: true,
274
+ search: true,
263
275
  readOnly: true,
264
276
  writeOnly: true,
265
277
  deprecated: true,
@@ -278,6 +290,7 @@ test.group('DomainProperty.constructor()', () => {
278
290
  assert.isTrue(property.multiple)
279
291
  assert.isTrue(property.primary)
280
292
  assert.isTrue(property.index)
293
+ assert.isTrue(property.search)
281
294
  assert.isTrue(property.readOnly)
282
295
  assert.isTrue(property.writeOnly)
283
296
  assert.isTrue(property.deprecated)
@@ -400,6 +413,7 @@ test.group('DomainProperty.toJSON()', () => {
400
413
  assert.isUndefined(json.multiple)
401
414
  assert.isUndefined(json.required)
402
415
  assert.isUndefined(json.index)
416
+ assert.isUndefined(json.search)
403
417
  assert.isUndefined(json.primary)
404
418
  assert.isUndefined(json.readOnly)
405
419
  assert.isUndefined(json.writeOnly)
@@ -420,6 +434,7 @@ test.group('DomainProperty.toJSON()', () => {
420
434
  multiple: true,
421
435
  primary: true,
422
436
  index: true,
437
+ search: true,
423
438
  readOnly: true,
424
439
  writeOnly: true,
425
440
  deprecated: true,
@@ -439,6 +454,7 @@ test.group('DomainProperty.toJSON()', () => {
439
454
  assert.isTrue(json.multiple)
440
455
  assert.isTrue(json.primary)
441
456
  assert.isTrue(json.index)
457
+ assert.isTrue(json.search)
442
458
  assert.isTrue(json.readOnly)
443
459
  assert.isTrue(json.writeOnly)
444
460
  assert.isTrue(json.deprecated)
@@ -470,6 +486,7 @@ test.group('DomainProperty.toJSON()', () => {
470
486
  required: undefined,
471
487
  multiple: undefined,
472
488
  index: undefined,
489
+ search: undefined,
473
490
  primary: undefined,
474
491
  readOnly: undefined,
475
492
  writeOnly: undefined,
@@ -484,6 +501,7 @@ test.group('DomainProperty.toJSON()', () => {
484
501
  assert.isUndefined(json.required)
485
502
  assert.isUndefined(json.multiple)
486
503
  assert.isUndefined(json.index)
504
+ assert.isUndefined(json.search)
487
505
  assert.isUndefined(json.primary)
488
506
  assert.isUndefined(json.readOnly)
489
507
  assert.isUndefined(json.writeOnly)
@@ -1296,7 +1314,6 @@ test.group('DomainProperty.toExample()', () => {
1296
1314
 
1297
1315
  // Mock the toApiShape method to return a shape without range
1298
1316
  const originalToApiShape = property.toApiShape
1299
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1300
1317
  property.toApiShape = () => ({ range: undefined }) as any
1301
1318
 
1302
1319
  const result = property.toExample('application/json')
@@ -1545,6 +1562,7 @@ test.group('DomainProperty.duplicate()', () => {
1545
1562
  required: true,
1546
1563
  multiple: true,
1547
1564
  index: true,
1565
+ search: true,
1548
1566
  readOnly: true,
1549
1567
  writeOnly: false,
1550
1568
  deprecated: true,
@@ -1562,6 +1580,7 @@ test.group('DomainProperty.duplicate()', () => {
1562
1580
  assert.equal(duplicate.required, true)
1563
1581
  assert.equal(duplicate.multiple, true)
1564
1582
  assert.equal(duplicate.index, true)
1583
+ assert.equal(duplicate.search, true)
1565
1584
  assert.equal(duplicate.readOnly, true)
1566
1585
  assert.equal(duplicate.writeOnly, false)
1567
1586
  assert.equal(duplicate.deprecated, true)
@@ -231,6 +231,77 @@ test.group('ExposedEntity', () => {
231
231
  assert.equal(ex.accessRule![0].type, 'allowPublic')
232
232
  }).tags(['@modeling', '@exposed-entity', '@immutability'])
233
233
 
234
+ test('initializes with paginationContract', ({ assert }) => {
235
+ const model = new ApiModel()
236
+ const contract = {
237
+ searchableFields: ['name'],
238
+ filterableFields: ['status'],
239
+ sortableFields: ['createdAt'],
240
+ }
241
+ const ex = new ExposedEntity(model, {
242
+ paginationContract: contract,
243
+ })
244
+
245
+ assert.deepEqual(ex.paginationContract, contract)
246
+ }).tags(['@modeling', '@exposed-entity'])
247
+
248
+ test('toJSON serializes paginationContract safely', ({ assert }) => {
249
+ const model = new ApiModel()
250
+ const ex = new ExposedEntity(model, {
251
+ paginationContract: { sortableFields: ['name'], filterableFields: [], searchableFields: [] },
252
+ })
253
+
254
+ const json = ex.toJSON()
255
+ assert.deepEqual(json.paginationContract, { sortableFields: ['name'], filterableFields: [], searchableFields: [] })
256
+
257
+ // Modify json to ensure immutability
258
+ json.paginationContract!.sortableFields.push('modified')
259
+ assert.lengthOf(ex.paginationContract!.sortableFields, 1)
260
+ }).tags(['@modeling', '@exposed-entity', '@serialization', '@immutability'])
261
+
262
+ test('constructor deep copies paginationContract (immutability)', ({ assert }) => {
263
+ const model = new ApiModel()
264
+ const contract = {
265
+ searchableFields: ['name'],
266
+ filterableFields: [],
267
+ sortableFields: [],
268
+ }
269
+ const ex = new ExposedEntity(model, {
270
+ paginationContract: contract,
271
+ })
272
+
273
+ contract.searchableFields.push('age')
274
+ assert.lengthOf(ex.paginationContract!.searchableFields, 1)
275
+ }).tags(['@modeling', '@exposed-entity', '@immutability'])
276
+
277
+ test('notifies change when paginationContract changes', async ({ assert }) => {
278
+ const model = new ApiModel()
279
+ const ex = new ExposedEntity(model, {})
280
+ let notified = false
281
+ ex.addEventListener('change', () => {
282
+ notified = true
283
+ })
284
+
285
+ ex.paginationContract = { sortableFields: [], filterableFields: [], searchableFields: [] }
286
+ await Promise.resolve()
287
+ assert.isTrue(notified)
288
+ }).tags(['@modeling', '@exposed-entity', '@observed'])
289
+
290
+ test('notifies change when paginationContract property mutates', async ({ assert }) => {
291
+ const model = new ApiModel()
292
+ const ex = new ExposedEntity(model, {
293
+ paginationContract: { sortableFields: [], filterableFields: [], searchableFields: [] },
294
+ })
295
+ let notified = false
296
+ ex.addEventListener('change', () => {
297
+ notified = true
298
+ })
299
+
300
+ ex.paginationContract!.sortableFields.push('name')
301
+ await Promise.resolve()
302
+ assert.isTrue(notified)
303
+ }).tags(['@modeling', '@exposed-entity', '@observed'])
304
+
234
305
  test('getAllRules() aggregates rules from entity, parent, and API', ({ assert }) => {
235
306
  const model = new ApiModel()
236
307
  model.accessRule = [new AccessRule({ type: 'allowPublic' })]