@aventara/core 0.1.0-pilot.4 → 1.0.0-rc.1

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 (255) hide show
  1. package/CHANGELOG.md +1478 -0
  2. package/README.md +275 -11
  3. package/dist/adapters/adapter-discovery-diagnostic.d.ts +4 -4
  4. package/dist/adapters/adapter-field.d.ts +11 -11
  5. package/dist/adapters/adapter-identifier.d.ts +6 -6
  6. package/dist/adapters/adapter-model.d.ts +17 -9
  7. package/dist/adapters/adapter-operation-executor.interface.d.ts +4 -4
  8. package/dist/adapters/adapter-operation.d.ts +3 -3
  9. package/dist/adapters/adapter-resource.d.ts +18 -9
  10. package/dist/adapters/adapter-sql-statement.d.ts +19 -0
  11. package/dist/adapters/adapter-transaction-executor.interface.d.ts +19 -0
  12. package/dist/adapters/adapter.interface.d.ts +49 -25
  13. package/dist/avz/avz-check.factory.d.ts +83 -0
  14. package/dist/avz/avz-check.factory.js +116 -0
  15. package/dist/avz/avz-check.registry.d.ts +35 -0
  16. package/dist/avz/avz-check.registry.js +9 -0
  17. package/dist/avz/avz.d.ts +203 -0
  18. package/dist/avz/avz.js +354 -0
  19. package/dist/avz/index.d.ts +7 -0
  20. package/dist/avz/index.js +1 -0
  21. package/dist/avz/json-shape.registry.d.ts +22 -0
  22. package/dist/avz/json-shape.registry.js +16 -0
  23. package/dist/avz/zod-issue.translator.d.ts +57 -0
  24. package/dist/avz/zod-issue.translator.js +149 -0
  25. package/dist/compiler/contract-compiler-diagnostic.d.ts +37 -5
  26. package/dist/compiler/contract.compiler.d.ts +18 -18
  27. package/dist/compiler/contract.compiler.js +595 -421
  28. package/dist/compiler/create-requirements.projector.d.ts +49 -0
  29. package/dist/compiler/create-requirements.projector.js +423 -0
  30. package/dist/compiler/field-validator.compiler.d.ts +47 -0
  31. package/dist/compiler/field-validator.compiler.js +238 -0
  32. package/dist/config/any-framework-config.d.ts +19 -12
  33. package/dist/config/config-diagnostic.d.ts +11 -4
  34. package/dist/config/config-layer.d.ts +15 -6
  35. package/dist/config/config.resolver.d.ts +75 -29
  36. package/dist/config/config.resolver.js +109 -44
  37. package/dist/config/config.validator.d.ts +7 -7
  38. package/dist/config/config.validator.js +586 -71
  39. package/dist/config/define-resource.d.ts +57 -0
  40. package/dist/config/define-resource.js +14 -0
  41. package/dist/config/effective-fields.d.ts +19 -23
  42. package/dist/config/entrypoint.normalizer.d.ts +1 -1
  43. package/dist/config/exact-framework-config.d.ts +280 -0
  44. package/dist/config/field-compute.resolver.d.ts +19 -0
  45. package/dist/config/field-compute.resolver.js +115 -0
  46. package/dist/config/field-pipeline-config.d.ts +47 -0
  47. package/dist/config/forced-operation.validator.d.ts +10 -0
  48. package/dist/config/forced-operation.validator.js +66 -0
  49. package/dist/config/framework-config.d.ts +111 -37
  50. package/dist/config/framework-exemptions-config.d.ts +91 -0
  51. package/dist/config/framework-exemptions-config.js +1 -0
  52. package/dist/config/framework-field-definition.d.ts +78 -0
  53. package/dist/config/framework-field-definition.js +28 -0
  54. package/dist/config/framework-resources-config.d.ts +116 -0
  55. package/dist/config/framework-resources-config.js +1 -0
  56. package/dist/config/pipeline-config.d.ts +56 -20
  57. package/dist/config/pipeline-tree.resolver.d.ts +79 -0
  58. package/dist/config/pipeline-tree.resolver.js +220 -0
  59. package/dist/config/stage-type.eraser.d.ts +65 -0
  60. package/dist/config/stage-type.eraser.js +1 -0
  61. package/dist/contracts/capability.d.ts +11 -11
  62. package/dist/contracts/client-contract-structure.validator.d.ts +344 -29
  63. package/dist/contracts/client-contract-structure.validator.js +248 -7
  64. package/dist/contracts/contract-canonicalizer.d.ts +19 -3
  65. package/dist/contracts/contract-canonicalizer.js +172 -27
  66. package/dist/contracts/contract-hash.d.ts +12 -7
  67. package/dist/contracts/contract-hash.js +3 -2
  68. package/dist/contracts/contract-limits.d.ts +4 -1
  69. package/dist/contracts/contract-limits.js +1 -0
  70. package/dist/contracts/contract-lookup.d.ts +5 -5
  71. package/dist/contracts/contract-protocol.d.ts +4 -4
  72. package/dist/contracts/contract.d.ts +31 -16
  73. package/dist/contracts/create-requirements.d.ts +35 -0
  74. package/dist/contracts/create-requirements.js +1 -0
  75. package/dist/contracts/enum-definition.d.ts +1 -1
  76. package/dist/contracts/field-check.d.ts +101 -0
  77. package/dist/contracts/field-check.js +1 -0
  78. package/dist/contracts/field.d.ts +61 -41
  79. package/dist/contracts/identifier.d.ts +4 -4
  80. package/dist/contracts/json-shape.d.ts +76 -0
  81. package/dist/contracts/json-shape.js +1 -0
  82. package/dist/contracts/lifecycle-trait.d.ts +2 -2
  83. package/dist/contracts/reference-write-limit.d.ts +7 -0
  84. package/dist/contracts/reference-write-limit.js +1 -0
  85. package/dist/contracts/resource-operations.d.ts +28 -28
  86. package/dist/contracts/resource.d.ts +15 -9
  87. package/dist/contracts/scalar-value-type.d.ts +25 -14
  88. package/dist/contracts/scalar.d.ts +3 -3
  89. package/dist/contracts/transaction-capability.d.ts +1 -1
  90. package/dist/contracts/wire-scalar-format.d.ts +4 -4
  91. package/dist/framework/contract-view.d.ts +234 -63
  92. package/dist/framework/framework-construction.error.d.ts +10 -10
  93. package/dist/framework/framework-construction.error.js +2 -2
  94. package/dist/framework/framework.d.ts +50 -24
  95. package/dist/framework/framework.factory.d.ts +8 -6
  96. package/dist/framework/framework.factory.js +95 -32
  97. package/dist/framework/operation-facade.d.ts +123 -52
  98. package/dist/framework/operation-facade.js +9 -1
  99. package/dist/index.d.ts +55 -82
  100. package/dist/index.js +6 -26
  101. package/dist/internal.d.ts +40 -0
  102. package/dist/internal.js +18 -0
  103. package/dist/operations/operation-arguments.d.ts +316 -201
  104. package/dist/operations/operation-call.d.ts +27 -28
  105. package/dist/operations/operation-identity.d.ts +12 -10
  106. package/dist/operations/operation-identity.js +3 -0
  107. package/dist/operations/operation-result.d.ts +21 -21
  108. package/dist/operations/operation-validator-core.d.ts +6 -6
  109. package/dist/operations/operation-validator-core.js +41 -12
  110. package/dist/operations/operation-validator.d.ts +24 -9
  111. package/dist/operations/operation-validator.js +26 -10
  112. package/dist/operations/projection-scope.resolver.d.ts +7 -7
  113. package/dist/operations/structural-limits.walker.d.ts +19 -0
  114. package/dist/operations/structural-limits.walker.js +489 -0
  115. package/dist/operations/validation-code.d.ts +11 -6
  116. package/dist/operations/validation-code.js +4 -0
  117. package/dist/operations/write-scope.resolver.d.ts +6 -6
  118. package/dist/protocol/absent-route.responder.d.ts +13 -11
  119. package/dist/protocol/absent-route.responder.js +42 -16
  120. package/dist/protocol/contract-document.responder.d.ts +3 -3
  121. package/dist/protocol/contract-document.responder.js +2 -2
  122. package/dist/protocol/http-request.decoder.d.ts +23 -13
  123. package/dist/protocol/http-request.decoder.js +19 -11
  124. package/dist/protocol/http-request.reader.d.ts +3 -3
  125. package/dist/protocol/http-response.encoder.d.ts +4 -4
  126. package/dist/protocol/http-response.encoder.js +94 -55
  127. package/dist/protocol/http-status.table.d.ts +2 -2
  128. package/dist/protocol/operation-response.guard.d.ts +2 -2
  129. package/dist/protocol/protocol-surface.d.ts +4 -4
  130. package/dist/protocol/protocol.binder.d.ts +52 -27
  131. package/dist/protocol/protocol.binder.js +14 -9
  132. package/dist/protocol/protocol.handler.d.ts +28 -15
  133. package/dist/protocol/protocol.handler.js +55 -10
  134. package/dist/protocol/unmounted-route.error.d.ts +19 -0
  135. package/dist/protocol/unmounted-route.error.js +10 -0
  136. package/dist/runtime/caller-data.copier.d.ts +59 -0
  137. package/dist/runtime/caller-data.copier.js +470 -0
  138. package/dist/runtime/caller-data.door.d.ts +56 -0
  139. package/dist/runtime/caller-data.door.js +67 -0
  140. package/dist/runtime/computed-read-runtime.d.ts +7 -6
  141. package/dist/runtime/computed-read-runtime.js +61 -55
  142. package/dist/runtime/computed-value.error.d.ts +13 -0
  143. package/dist/runtime/computed-value.error.js +9 -0
  144. package/dist/runtime/context-executor.runtime.d.ts +59 -0
  145. package/dist/runtime/context-executor.runtime.js +275 -0
  146. package/dist/runtime/create-requirement.d.ts +22 -57
  147. package/dist/runtime/create-requirement.js +140 -37
  148. package/dist/runtime/decimal.d.ts +2 -2
  149. package/dist/runtime/decimal.js +1 -1
  150. package/dist/runtime/diagnostics-reporter.d.ts +64 -22
  151. package/dist/runtime/diagnostics-reporter.js +35 -4
  152. package/dist/runtime/error-boundary.d.ts +73 -8
  153. package/dist/runtime/error-boundary.js +104 -48
  154. package/dist/runtime/execution-options.d.ts +10 -2
  155. package/dist/runtime/field-check.evaluator.d.ts +29 -0
  156. package/dist/runtime/field-check.evaluator.js +521 -0
  157. package/dist/runtime/field-compute.d.ts +64 -0
  158. package/dist/runtime/field-compute.js +1 -0
  159. package/dist/runtime/field-stage.plan.d.ts +15 -0
  160. package/dist/runtime/field-stage.plan.js +27 -0
  161. package/dist/runtime/field-stage.runtime.d.ts +35 -0
  162. package/dist/runtime/field-stage.runtime.js +143 -0
  163. package/dist/runtime/field-validator.runtime.d.ts +11 -0
  164. package/dist/runtime/field-validator.runtime.js +87 -0
  165. package/dist/runtime/framework-error-class.table.d.ts +33 -0
  166. package/dist/runtime/framework-error-class.table.js +25 -0
  167. package/dist/runtime/framework-error.d.ts +79 -7
  168. package/dist/runtime/framework-error.factory.d.ts +4 -0
  169. package/dist/runtime/framework-error.factory.js +15 -0
  170. package/dist/runtime/framework-error.js +23 -2
  171. package/dist/runtime/interceptor-next.error.d.ts +5 -0
  172. package/dist/runtime/interceptor-next.error.js +6 -0
  173. package/dist/runtime/json-value.d.ts +3 -3
  174. package/dist/runtime/level-lifecycle.runtime.d.ts +25 -0
  175. package/dist/runtime/level-lifecycle.runtime.js +42 -0
  176. package/dist/runtime/misuse-reporter.d.ts +32 -0
  177. package/dist/runtime/misuse-reporter.js +19 -0
  178. package/dist/runtime/mutation-planner.d.ts +19 -10
  179. package/dist/runtime/mutation-planner.js +62 -36
  180. package/dist/runtime/nested-write.walker.d.ts +32 -0
  181. package/dist/runtime/nested-write.walker.js +73 -0
  182. package/dist/runtime/operation-request.d.ts +35 -15
  183. package/dist/runtime/operation-response.d.ts +17 -17
  184. package/dist/runtime/operation-runtime.d.ts +125 -30
  185. package/dist/runtime/operation-runtime.js +423 -83
  186. package/dist/runtime/outcome-mapper.d.ts +16 -5
  187. package/dist/runtime/outcome-mapper.js +35 -8
  188. package/dist/runtime/output-validator.d.ts +16 -6
  189. package/dist/runtime/output-validator.js +12 -1
  190. package/dist/runtime/owned-execution.registry.d.ts +13 -0
  191. package/dist/runtime/owned-execution.registry.js +7 -0
  192. package/dist/runtime/pipe-output.validator.d.ts +33 -18
  193. package/dist/runtime/pipe-output.validator.js +12 -12
  194. package/dist/runtime/pipeline.d.ts +202 -28
  195. package/dist/runtime/readonly-value.d.ts +32 -0
  196. package/dist/runtime/readonly-value.js +141 -0
  197. package/dist/runtime/referential-action.d.ts +7 -0
  198. package/dist/runtime/request-envelope.validator.d.ts +5 -0
  199. package/dist/runtime/request-envelope.validator.js +123 -0
  200. package/dist/runtime/request-id.d.ts +1 -1
  201. package/dist/runtime/request-state.d.ts +14 -0
  202. package/dist/runtime/request-state.js +1 -0
  203. package/dist/runtime/request-state.resolver.d.ts +12 -0
  204. package/dist/runtime/request-state.resolver.js +20 -0
  205. package/dist/runtime/scalar-runtime.d.ts +56 -13
  206. package/dist/runtime/scalar-runtime.js +167 -86
  207. package/dist/transactions/deferred-operation.d.ts +35 -20
  208. package/dist/transactions/operation-arguments-encoder.d.ts +3 -3
  209. package/dist/transactions/operation-arguments-encoder.js +2 -2
  210. package/dist/transactions/sql-statement.d.ts +77 -0
  211. package/dist/transactions/sql-statement.js +47 -0
  212. package/dist/transactions/sql-statement.validator.d.ts +44 -0
  213. package/dist/transactions/sql-statement.validator.js +134 -0
  214. package/dist/transactions/transaction-envelope.d.ts +4 -4
  215. package/dist/transactions/transaction-integrity-error.d.ts +6 -6
  216. package/dist/transactions/transaction-integrity-error.js +5 -2
  217. package/dist/transactions/transaction-plan-assembler.d.ts +23 -9
  218. package/dist/transactions/transaction-plan-assembler.js +195 -82
  219. package/dist/transactions/transaction-plan-validator.d.ts +53 -21
  220. package/dist/transactions/transaction-plan-validator.js +246 -163
  221. package/dist/transactions/transaction-reference-collector.d.ts +30 -0
  222. package/dist/transactions/transaction-reference-collector.js +204 -0
  223. package/dist/transactions/transaction-reference-resolver.d.ts +19 -2
  224. package/dist/transactions/transaction-reference-resolver.js +27 -10
  225. package/dist/transactions/transaction-reference-validator.d.ts +34 -4
  226. package/dist/transactions/transaction-reference-validator.js +82 -43
  227. package/dist/transactions/transaction-reference.d.ts +30 -58
  228. package/dist/transactions/transaction-request.d.ts +20 -7
  229. package/dist/transactions/transaction-response.d.ts +12 -7
  230. package/dist/transactions/transaction-response.js +24 -1
  231. package/dist/transactions/transaction-runtime.d.ts +11 -8
  232. package/dist/transactions/transaction-runtime.js +167 -50
  233. package/dist/transactions/transaction-settlement.runtime.d.ts +51 -0
  234. package/dist/transactions/transaction-settlement.runtime.js +120 -0
  235. package/dist/transactions/transaction-slot-path-error.d.ts +4 -4
  236. package/dist/transactions/transaction-slot-path-error.js +2 -2
  237. package/dist/transactions/transaction-slot-writer.js +2 -2
  238. package/dist/transactions/transaction-stage.runtime.d.ts +81 -0
  239. package/dist/transactions/transaction-stage.runtime.js +123 -0
  240. package/package.json +18 -3
  241. package/src/runtime/field-check.evaluator.ts +720 -0
  242. package/dist/config/define-fields.d.ts +0 -35
  243. package/dist/config/define-fields.js +0 -3
  244. package/dist/config/framework-behaviors-config.d.ts +0 -30
  245. package/dist/config/framework-fields-config.d.ts +0 -36
  246. package/dist/config/framework-restrictions-config.d.ts +0 -142
  247. package/dist/operations/operation-boolean-nodes.d.ts +0 -11
  248. package/dist/operations/operation-boolean-nodes.js +0 -283
  249. package/dist/operations/operation-nesting.d.ts +0 -8
  250. package/dist/operations/operation-nesting.js +0 -307
  251. package/dist/runtime/field-behavior.d.ts +0 -48
  252. /package/dist/{config/framework-behaviors-config.js → adapters/adapter-sql-statement.js} +0 -0
  253. /package/dist/{config/framework-fields-config.js → adapters/adapter-transaction-executor.interface.js} +0 -0
  254. /package/dist/config/{framework-restrictions-config.js → exact-framework-config.js} +0 -0
  255. /package/dist/{runtime/field-behavior.js → config/field-pipeline-config.js} +0 -0
@@ -1,7 +1,8 @@
1
- import { lookupField, lookupResource } from "../contracts/contract-lookup.js";
1
+ import { shapeOfField } from "../avz/json-shape.registry.js";
2
+ import { lookupField, lookupOwn, lookupResource, } from "../contracts/contract-lookup.js";
2
3
  import { decodeBase64, WIRE_SCALAR_PATTERNS, } from "../contracts/wire-scalar-format.js";
3
- import { routeTransactionReferenceCandidate } from "../transactions/transaction-reference.js";
4
- import { Decimal } from "./decimal.js";
4
+ import { routeTransactionReferenceCandidate, } from "../transactions/transaction-reference.js";
5
+ import { AvDecimal } from "./decimal.js";
5
6
  const INT_MIN = -(2 ** 31);
6
7
  const INT_MAX = 2 ** 31 - 1;
7
8
  const BIGINT_MIN = -(2n ** 63n);
@@ -26,8 +27,9 @@ function typeIssue(path, expected) {
26
27
  function formatIssue(path, expected) {
27
28
  return issue("V1003", path, `Value must use ${expected}.`);
28
29
  }
30
+ let writeInPlace = false;
29
31
  function cloneRecord(value) {
30
- return { ...value };
32
+ return writeInPlace ? value : { ...value };
31
33
  }
32
34
  function materializeJsonPath(root, link) {
33
35
  const segments = [];
@@ -37,7 +39,7 @@ function materializeJsonPath(root, link) {
37
39
  segments.reverse();
38
40
  return [...root, ...segments];
39
41
  }
40
- function normalizeJsonValue(value, path, seen) {
42
+ export function normalizeJsonValue(value, path, seen) {
41
43
  const issues = [];
42
44
  let root;
43
45
  const stack = [
@@ -125,7 +127,7 @@ function normalizeJsonValue(value, path, seen) {
125
127
  }
126
128
  return issues.length > 0 ? { ok: false, issues } : { ok: true, value: root };
127
129
  }
128
- function normalizeScalarAtom(contract, field, value, scope, path, allowNull) {
130
+ function normalizeScalarAtom(contract, field, value, origin, path, allowNull) {
129
131
  if (value === null) {
130
132
  return allowNull
131
133
  ? { ok: true, value: null }
@@ -195,7 +197,7 @@ function normalizeScalarAtom(contract, field, value, scope, path, allowNull) {
195
197
  }
196
198
  break;
197
199
  case "bigint":
198
- if (scope === "application") {
200
+ if (origin === "application") {
199
201
  normalized =
200
202
  typeof value === "bigint"
201
203
  ? { ok: true, value }
@@ -228,9 +230,9 @@ function normalizeScalarAtom(contract, field, value, scope, path, allowNull) {
228
230
  }
229
231
  break;
230
232
  case "decimal":
231
- if (scope === "application") {
233
+ if (origin === "application") {
232
234
  normalized =
233
- value instanceof Decimal
235
+ value instanceof AvDecimal
234
236
  ? { ok: true, value }
235
237
  : { ok: false, issues: [typeIssue(path, "an Aventara Decimal")] };
236
238
  }
@@ -242,7 +244,7 @@ function normalizeScalarAtom(contract, field, value, scope, path, allowNull) {
242
244
  }
243
245
  else {
244
246
  try {
245
- normalized = { ok: true, value: new Decimal(value) };
247
+ normalized = { ok: true, value: new AvDecimal(value) };
246
248
  }
247
249
  catch {
248
250
  normalized = {
@@ -253,7 +255,7 @@ function normalizeScalarAtom(contract, field, value, scope, path, allowNull) {
253
255
  }
254
256
  break;
255
257
  case "datetime":
256
- if (scope === "application") {
258
+ if (origin === "application") {
257
259
  if (!(value instanceof Date)) {
258
260
  normalized = { ok: false, issues: [typeIssue(path, "a Date")] };
259
261
  }
@@ -289,7 +291,7 @@ function normalizeScalarAtom(contract, field, value, scope, path, allowNull) {
289
291
  }
290
292
  break;
291
293
  case "bytes":
292
- if (scope === "application") {
294
+ if (origin === "application") {
293
295
  normalized =
294
296
  value instanceof Uint8Array
295
297
  ? { ok: true, value }
@@ -334,7 +336,7 @@ function normalizeScalarAtom(contract, field, value, scope, path, allowNull) {
334
336
  }
335
337
  return normalized;
336
338
  }
337
- export function normalizeScalarFieldValue(contract, field, value, scope, path) {
339
+ export function normalizeScalarFieldValue(contract, field, value, origin, path) {
338
340
  if (value === null) {
339
341
  return field.nullable
340
342
  ? { ok: true, value: null }
@@ -347,7 +349,7 @@ export function normalizeScalarFieldValue(contract, field, value, scope, path) {
347
349
  const normalized = [];
348
350
  const issues = [];
349
351
  value.forEach((entry, index) => {
350
- const result = normalizeScalarAtom(contract, field, entry, scope === "runtime" ? "application" : scope, [...path, index], false);
352
+ const result = normalizeScalarAtom(contract, field, entry, origin === "runtime" ? "application" : origin, [...path, index], false);
351
353
  if (result.ok) {
352
354
  normalized.push(result.value);
353
355
  }
@@ -359,7 +361,39 @@ export function normalizeScalarFieldValue(contract, field, value, scope, path) {
359
361
  ? { ok: false, issues }
360
362
  : { ok: true, value: normalized };
361
363
  }
362
- return normalizeScalarAtom(contract, field, value, scope === "runtime" ? "application" : scope, path, field.nullable);
364
+ return normalizeScalarAtom(contract, field, value, origin === "runtime" ? "application" : origin, path, field.nullable);
365
+ }
366
+ export function jsonShapeIssues(field, value, path, position = "value") {
367
+ if (field.json === undefined || value === null || value === undefined) {
368
+ return [];
369
+ }
370
+ const shape = shapeOfField(field);
371
+ if (shape === undefined) {
372
+ throw new Error("a shaped Json field reached validation with no shape bound to it");
373
+ }
374
+ const at = (entry, entryPath) => shape.validate(entry).map((found) => ({
375
+ ...found,
376
+ path: [...entryPath, ...(found.path ?? [])],
377
+ }));
378
+ return field.list && position === "value" && Array.isArray(value)
379
+ ? value.flatMap((entry, index) => at(entry, [...path, index]))
380
+ : at(value, path);
381
+ }
382
+ function normalizeWrittenValue(contract, field, value, origin, path, issues) {
383
+ const result = normalizeScalarFieldValue(contract, field, value, origin, path);
384
+ if (!result.ok) {
385
+ issues.push(...result.issues);
386
+ return undefined;
387
+ }
388
+ return result.value;
389
+ }
390
+ function normalizeWrittenElement(contract, field, value, origin, path, issues) {
391
+ const result = normalizeListElement(contract, field, value, origin, path);
392
+ if (!result.ok) {
393
+ issues.push(...result.issues);
394
+ return undefined;
395
+ }
396
+ return result.value;
363
397
  }
364
398
  const SCALAR_ATOM_COPIERS = {
365
399
  string: (value) => value,
@@ -390,8 +424,8 @@ export function copyScalarFieldValue(field, value) {
390
424
  }
391
425
  return items;
392
426
  }
393
- function normalizeListElement(contract, field, value, scope, path) {
394
- return normalizeScalarAtom(contract, field, value, scope, path, false);
427
+ function normalizeListElement(contract, field, value, origin, path) {
428
+ return normalizeScalarAtom(contract, field, value, origin, path, false);
395
429
  }
396
430
  function mergeResult(result, issues) {
397
431
  if (result.ok) {
@@ -400,9 +434,41 @@ function mergeResult(result, issues) {
400
434
  issues.push(...result.issues);
401
435
  return undefined;
402
436
  }
403
- function normalizeScalarFilter(contract, field, value, scope, path, issues) {
437
+ export const REFERENCE_OPERANDS = Object.freeze({
438
+ equals: "value",
439
+ not: "value",
440
+ lt: "nonNullValue",
441
+ lte: "nonNullValue",
442
+ gt: "nonNullValue",
443
+ gte: "nonNullValue",
444
+ contains: "nonNullValue",
445
+ startsWith: "nonNullValue",
446
+ endsWith: "nonNullValue",
447
+ has: "entry",
448
+ in: "entries",
449
+ notIn: "entries",
450
+ hasEvery: "entries",
451
+ hasSome: "entries",
452
+ });
453
+ export function referenceOperandShape(operator) {
454
+ return lookupOwn(REFERENCE_OPERANDS, operator);
455
+ }
456
+ function acceptsNullOperand(operator) {
457
+ return NULL_OPERAND_OPERATORS.has(operator);
458
+ }
459
+ const NULL_OPERAND_OPERATORS = new Set([
460
+ "equals",
461
+ "not",
462
+ "arrayContains",
463
+ "arrayStartsWith",
464
+ "arrayEndsWith",
465
+ ]);
466
+ function normalizeScalarFilter(contract, field, value, origin, path, issues, references = false) {
467
+ if (isKeptReference(references, value)) {
468
+ return value;
469
+ }
404
470
  if (!isPlainRecord(value)) {
405
- return mergeResult(normalizeScalarFieldValue(contract, field, value, scope, path), issues);
471
+ return mergeResult(normalizeScalarFieldValue(contract, field, value, origin, path), issues);
406
472
  }
407
473
  const keys = Object.keys(value);
408
474
  if (keys.length === 0 || !keys.some((key) => key in value)) {
@@ -411,11 +477,19 @@ function normalizeScalarFilter(contract, field, value, scope, path, issues) {
411
477
  const normalized = cloneRecord(value);
412
478
  for (const [operator, operand] of Object.entries(value)) {
413
479
  const operandPath = [...path, operator];
480
+ if (operand === null && !acceptsNullOperand(operator)) {
481
+ issues.push(typeIssue(operandPath, "non-null"));
482
+ continue;
483
+ }
414
484
  if (operator === "mode" || operator === "isEmpty" || operator === "path") {
415
485
  continue;
416
486
  }
487
+ if (referenceOperandShape(operator) !== undefined &&
488
+ isKeptReference(references, operand)) {
489
+ continue;
490
+ }
417
491
  if (operator === "not" && isPlainRecord(operand)) {
418
- normalized[operator] = normalizeScalarFilter(contract, field, operand, scope, operandPath, issues);
492
+ normalized[operator] = normalizeScalarFilter(contract, field, operand, origin, operandPath, issues, references);
419
493
  continue;
420
494
  }
421
495
  if (operator === "in" || operator === "notIn") {
@@ -423,14 +497,14 @@ function normalizeScalarFilter(contract, field, value, scope, path, issues) {
423
497
  issues.push(typeIssue(operandPath, "an array"));
424
498
  continue;
425
499
  }
426
- normalized[operator] = operand.map((entry, index) => mergeResult(normalizeListElement(contract, field, entry, scope, [
500
+ normalized[operator] = operand.map((entry, index) => mergeResult(normalizeListElement(contract, field, entry, origin, [
427
501
  ...operandPath,
428
502
  index,
429
503
  ]), issues));
430
504
  continue;
431
505
  }
432
506
  if (operator === "has") {
433
- normalized[operator] = mergeResult(normalizeListElement(contract, field, operand, scope, operandPath), issues);
507
+ normalized[operator] = mergeResult(normalizeListElement(contract, field, operand, origin, operandPath), issues);
434
508
  continue;
435
509
  }
436
510
  if (operator === "hasEvery" || operator === "hasSome") {
@@ -438,7 +512,7 @@ function normalizeScalarFilter(contract, field, value, scope, path, issues) {
438
512
  issues.push(typeIssue(operandPath, "an array"));
439
513
  continue;
440
514
  }
441
- normalized[operator] = operand.map((entry, index) => mergeResult(normalizeListElement(contract, field, entry, scope, [
515
+ normalized[operator] = operand.map((entry, index) => mergeResult(normalizeListElement(contract, field, entry, origin, [
442
516
  ...operandPath,
443
517
  index,
444
518
  ]), issues));
@@ -451,11 +525,11 @@ function normalizeScalarFilter(contract, field, value, scope, path, issues) {
451
525
  normalized[operator] = mergeResult(jsonResult, issues);
452
526
  continue;
453
527
  }
454
- normalized[operator] = mergeResult(normalizeScalarFieldValue(contract, field, operand, scope, operandPath), issues);
528
+ normalized[operator] = mergeResult(normalizeScalarFieldValue(contract, field, operand, origin, operandPath), issues);
455
529
  }
456
530
  return normalized;
457
531
  }
458
- function normalizeWhere(contract, resourceName, where, scope, path, issues) {
532
+ function normalizeWhere(contract, resourceName, where, origin, path, issues, references = false) {
459
533
  if (!isPlainRecord(where)) {
460
534
  return where;
461
535
  }
@@ -467,28 +541,28 @@ function normalizeWhere(contract, resourceName, where, scope, path, issues) {
467
541
  for (const [key, value] of Object.entries(where)) {
468
542
  if (key === "AND" || key === "OR") {
469
543
  if (Array.isArray(value)) {
470
- normalized[key] = value.map((entry, index) => normalizeWhere(contract, resourceName, entry, scope, [...path, key, index], issues));
544
+ normalized[key] = value.map((entry, index) => normalizeWhere(contract, resourceName, entry, origin, [...path, key, index], issues, references));
471
545
  }
472
546
  continue;
473
547
  }
474
548
  if (key === "NOT") {
475
- normalized[key] = normalizeWhere(contract, resourceName, value, scope, [...path, key], issues);
549
+ normalized[key] = normalizeWhere(contract, resourceName, value, origin, [...path, key], issues, references);
476
550
  continue;
477
551
  }
478
552
  const field = lookupField(resource, key);
479
553
  if (field?.kind === "scalar") {
480
- normalized[key] = normalizeScalarFilter(contract, field, value, scope, [...path, key], issues);
554
+ normalized[key] = normalizeScalarFilter(contract, field, value, origin, [...path, key], issues, references);
481
555
  continue;
482
556
  }
483
557
  if (field?.kind === "relation" && isPlainRecord(value)) {
484
558
  if (field.cardinality === "one") {
485
- normalized[key] = normalizeWhere(contract, field.target, value, scope, [...path, key], issues);
559
+ normalized[key] = normalizeWhere(contract, field.target, value, origin, [...path, key], issues, references);
486
560
  }
487
561
  else {
488
562
  const relationValue = cloneRecord(value);
489
563
  for (const relationOperator of ["some", "every", "none"]) {
490
564
  if (relationOperator in value) {
491
- relationValue[relationOperator] = normalizeWhere(contract, field.target, value[relationOperator], scope, [...path, key, relationOperator], issues);
565
+ relationValue[relationOperator] = normalizeWhere(contract, field.target, value[relationOperator], origin, [...path, key, relationOperator], issues, references);
492
566
  }
493
567
  }
494
568
  normalized[key] = relationValue;
@@ -497,7 +571,10 @@ function normalizeWhere(contract, resourceName, where, scope, path, issues) {
497
571
  }
498
572
  return normalized;
499
573
  }
500
- function normalizeUniqueSelector(contract, resourceName, selector, scope, path, issues) {
574
+ function isKeptReference(references, value) {
575
+ return (references && routeTransactionReferenceCandidate(value).kind !== "ordinary");
576
+ }
577
+ function normalizeUniqueSelector(contract, resourceName, selector, origin, path, issues, references = false) {
501
578
  if (!isPlainRecord(selector)) {
502
579
  return selector;
503
580
  }
@@ -508,8 +585,8 @@ function normalizeUniqueSelector(contract, resourceName, selector, scope, path,
508
585
  const normalized = cloneRecord(selector);
509
586
  for (const [fieldName, value] of Object.entries(selector)) {
510
587
  const field = lookupField(resource, fieldName);
511
- if (field?.kind === "scalar") {
512
- normalized[fieldName] = mergeResult(normalizeScalarFieldValue(contract, field, value, scope, [
588
+ if (field?.kind === "scalar" && !isKeptReference(references, value)) {
589
+ normalized[fieldName] = mergeResult(normalizeScalarFieldValue(contract, field, value, origin, [
513
590
  ...path,
514
591
  fieldName,
515
592
  ]), issues);
@@ -517,28 +594,28 @@ function normalizeUniqueSelector(contract, resourceName, selector, scope, path,
517
594
  }
518
595
  return normalized;
519
596
  }
520
- function normalizeCursor(contract, resourceName, cursor, scope, path, issues) {
521
- return normalizeUniqueSelector(contract, resourceName, cursor, scope, path, issues);
597
+ function normalizeCursor(contract, resourceName, cursor, origin, path, issues, references = false) {
598
+ return normalizeUniqueSelector(contract, resourceName, cursor, origin, path, issues, references);
522
599
  }
523
- function normalizeRelationProjection(contract, edge, value, scope, path, issues) {
600
+ function normalizeRelationProjection(contract, edge, value, origin, path, issues) {
524
601
  if (!isPlainRecord(value)) {
525
602
  return value;
526
603
  }
527
604
  const normalized = cloneRecord(value);
528
605
  if ("where" in value) {
529
- normalized.where = normalizeWhere(contract, edge.target, value.where, scope, [...path, "where"], issues);
606
+ normalized.where = normalizeWhere(contract, edge.target, value.where, origin, [...path, "where"], issues);
530
607
  }
531
608
  if ("cursor" in value) {
532
- normalized.cursor = normalizeCursor(contract, edge.target, value.cursor, scope, [...path, "cursor"], issues);
609
+ normalized.cursor = normalizeCursor(contract, edge.target, value.cursor, origin, [...path, "cursor"], issues);
533
610
  }
534
611
  for (const mode of ["select", "include"]) {
535
612
  if (mode in value) {
536
- normalized[mode] = normalizeProjection(contract, edge.target, value[mode], scope, [...path, mode], issues);
613
+ normalized[mode] = normalizeProjection(contract, edge.target, value[mode], origin, [...path, mode], issues);
537
614
  }
538
615
  }
539
616
  return normalized;
540
617
  }
541
- function normalizeProjection(contract, resourceName, projection, scope, path, issues) {
618
+ function normalizeProjection(contract, resourceName, projection, origin, path, issues) {
542
619
  if (!Array.isArray(projection)) {
543
620
  return projection;
544
621
  }
@@ -559,23 +636,20 @@ function normalizeProjection(contract, resourceName, projection, scope, path, is
559
636
  return entry;
560
637
  }
561
638
  return {
562
- [relationName]: normalizeRelationProjection(contract, edge, entry[relationName], scope, [...path, index, relationName], issues),
639
+ [relationName]: normalizeRelationProjection(contract, edge, entry[relationName], origin, [...path, index, relationName], issues),
563
640
  };
564
641
  });
565
642
  }
566
- function normalizeScalarMutation(contract, field, value, scope, path, issues, transactionReferences = false) {
567
- if (transactionReferences) {
568
- const route = routeTransactionReferenceCandidate(value);
569
- if (route.kind !== "ordinary") {
570
- return value;
571
- }
643
+ function normalizeScalarMutation(contract, field, value, origin, path, issues, transactionReferences = false) {
644
+ if (isKeptReference(transactionReferences, value)) {
645
+ return value;
572
646
  }
573
647
  if (!isPlainRecord(value)) {
574
- return mergeResult(normalizeScalarFieldValue(contract, field, value, scope, path), issues);
648
+ return normalizeWrittenValue(contract, field, value, origin, path, issues);
575
649
  }
576
650
  const directiveKeys = Object.keys(value).filter((key) => key.startsWith("$"));
577
651
  if (directiveKeys.length === 0) {
578
- return mergeResult(normalizeScalarFieldValue(contract, field, value, scope, path), issues);
652
+ return normalizeWrittenValue(contract, field, value, origin, path, issues);
579
653
  }
580
654
  const normalized = cloneRecord(value);
581
655
  for (const [directive, operand] of Object.entries(value)) {
@@ -585,35 +659,32 @@ function normalizeScalarMutation(contract, field, value, scope, path, issues, tr
585
659
  }
586
660
  if (directive === "$push" && field.list) {
587
661
  if (Array.isArray(operand)) {
588
- normalized[directive] = operand.map((entry, index) => mergeResult(normalizeListElement(contract, field, entry, scope, [
589
- ...operandPath,
590
- index,
591
- ]), issues));
662
+ normalized[directive] = operand.map((entry, index) => normalizeWrittenElement(contract, field, entry, origin, [...operandPath, index], issues));
592
663
  }
593
664
  else {
594
- normalized[directive] = mergeResult(normalizeListElement(contract, field, operand, scope, operandPath), issues);
665
+ normalized[directive] = normalizeWrittenElement(contract, field, operand, origin, operandPath, issues);
595
666
  }
596
667
  continue;
597
668
  }
598
- normalized[directive] = mergeResult(normalizeListElement(contract, field, operand, scope, operandPath), issues);
669
+ normalized[directive] = mergeResult(normalizeListElement(contract, field, operand, origin, operandPath), issues);
599
670
  }
600
671
  return normalized;
601
672
  }
602
- function normalizeRelationMutation(contract, edge, value, scope, path, issues) {
673
+ function normalizeRelationMutation(contract, edge, value, origin, path, issues, references = false) {
603
674
  if (!isPlainRecord(value)) {
604
675
  return value;
605
676
  }
606
677
  const normalized = cloneRecord(value);
607
678
  for (const [directive, operand] of Object.entries(value)) {
608
679
  const directivePath = [...path, directive];
609
- const entries = edge.cardinality === "many" && Array.isArray(operand)
610
- ? operand
611
- : [operand];
680
+ const listed = edge.cardinality === "many" && Array.isArray(operand);
681
+ const entries = listed ? operand : [operand];
682
+ const entryPath = (index) => listed ? [...directivePath, index] : directivePath;
612
683
  if (directive === "$create") {
613
684
  normalized[directive] =
614
685
  edge.cardinality === "many" && Array.isArray(operand)
615
- ? entries.map((entry, index) => normalizeMutationData(contract, edge.target, entry, scope, [...directivePath, index], issues))
616
- : normalizeMutationData(contract, edge.target, operand, scope, directivePath, issues);
686
+ ? entries.map((entry, index) => normalizeMutationData(contract, edge.target, entry, origin, [...directivePath, index], issues, references))
687
+ : normalizeMutationData(contract, edge.target, operand, origin, directivePath, issues, references);
617
688
  continue;
618
689
  }
619
690
  if (directive === "$connect" || directive === "$set") {
@@ -621,8 +692,8 @@ function normalizeRelationMutation(contract, edge, value, scope, path, issues) {
621
692
  continue;
622
693
  }
623
694
  normalized[directive] = Array.isArray(operand)
624
- ? operand.map((entry, index) => normalizeUniqueSelector(contract, edge.target, entry, scope, [...directivePath, index], issues))
625
- : normalizeUniqueSelector(contract, edge.target, operand, scope, directivePath, issues);
695
+ ? operand.map((entry, index) => normalizeUniqueSelector(contract, edge.target, entry, origin, [...directivePath, index], issues, references))
696
+ : normalizeUniqueSelector(contract, edge.target, operand, origin, directivePath, issues, references);
626
697
  continue;
627
698
  }
628
699
  if (directive === "$disconnect") {
@@ -630,8 +701,8 @@ function normalizeRelationMutation(contract, edge, value, scope, path, issues) {
630
701
  continue;
631
702
  }
632
703
  normalized[directive] = Array.isArray(operand)
633
- ? operand.map((entry, index) => normalizeUniqueSelector(contract, edge.target, entry, scope, [...directivePath, index], issues))
634
- : normalizeUniqueSelector(contract, edge.target, operand, scope, directivePath, issues);
704
+ ? operand.map((entry, index) => normalizeUniqueSelector(contract, edge.target, entry, origin, [...directivePath, index], issues, references))
705
+ : normalizeUniqueSelector(contract, edge.target, operand, origin, directivePath, issues, references);
635
706
  continue;
636
707
  }
637
708
  if (directive === "$connectOrCreate") {
@@ -641,8 +712,8 @@ function normalizeRelationMutation(contract, edge, value, scope, path, issues) {
641
712
  }
642
713
  return {
643
714
  ...entry,
644
- where: normalizeUniqueSelector(contract, edge.target, entry.where, scope, [...directivePath, index, "where"], issues),
645
- create: normalizeMutationData(contract, edge.target, entry.create, scope, [...directivePath, index, "create"], issues),
715
+ where: normalizeUniqueSelector(contract, edge.target, entry.where, origin, [...entryPath(index), "where"], issues, references),
716
+ create: normalizeMutationData(contract, edge.target, entry.create, origin, [...entryPath(index), "create"], issues, references),
646
717
  };
647
718
  });
648
719
  normalized[directive] =
@@ -660,10 +731,10 @@ function normalizeRelationMutation(contract, edge, value, scope, path, issues) {
660
731
  ...entry,
661
732
  ...(entry.where !== undefined
662
733
  ? {
663
- where: normalizeWhere(contract, edge.target, entry.where, scope, [...directivePath, index, "where"], issues),
734
+ where: normalizeWhere(contract, edge.target, entry.where, origin, [...entryPath(index), "where"], issues, references),
664
735
  }
665
736
  : {}),
666
- data: normalizeMutationData(contract, edge.target, entry.data, scope, [...directivePath, index, "data"], issues),
737
+ data: normalizeMutationData(contract, edge.target, entry.data, origin, [...entryPath(index), "data"], issues, references),
667
738
  };
668
739
  });
669
740
  normalized[directive] =
@@ -679,7 +750,7 @@ function normalizeRelationMutation(contract, edge, value, scope, path, issues) {
679
750
  }
680
751
  return {
681
752
  ...entry,
682
- where: normalizeWhere(contract, edge.target, entry.where, scope, [...directivePath, index, "where"], issues),
753
+ where: normalizeWhere(contract, edge.target, entry.where, origin, [...entryPath(index), "where"], issues, references),
683
754
  };
684
755
  });
685
756
  normalized[directive] =
@@ -697,11 +768,11 @@ function normalizeRelationMutation(contract, edge, value, scope, path, issues) {
697
768
  ...entry,
698
769
  ...(entry.where !== undefined
699
770
  ? {
700
- where: normalizeUniqueSelector(contract, edge.target, entry.where, scope, [...directivePath, index, "where"], issues),
771
+ where: normalizeUniqueSelector(contract, edge.target, entry.where, origin, [...entryPath(index), "where"], issues, references),
701
772
  }
702
773
  : {}),
703
- create: normalizeMutationData(contract, edge.target, entry.create, scope, [...directivePath, index, "create"], issues),
704
- update: normalizeMutationData(contract, edge.target, entry.update, scope, [...directivePath, index, "update"], issues),
774
+ create: normalizeMutationData(contract, edge.target, entry.create, origin, [...entryPath(index), "create"], issues, references),
775
+ update: normalizeMutationData(contract, edge.target, entry.update, origin, [...entryPath(index), "update"], issues, references),
705
776
  };
706
777
  });
707
778
  normalized[directive] =
@@ -712,7 +783,7 @@ function normalizeRelationMutation(contract, edge, value, scope, path, issues) {
712
783
  }
713
784
  return normalized;
714
785
  }
715
- function normalizeMutationData(contract, resourceName, data, scope, path, issues, transactionReferences = false) {
786
+ function normalizeMutationData(contract, resourceName, data, origin, path, issues, transactionReferences = false) {
716
787
  if (!isPlainRecord(data)) {
717
788
  return data;
718
789
  }
@@ -724,10 +795,10 @@ function normalizeMutationData(contract, resourceName, data, scope, path, issues
724
795
  for (const [fieldName, value] of Object.entries(data)) {
725
796
  const field = lookupField(resource, fieldName);
726
797
  if (field?.kind === "scalar") {
727
- normalized[fieldName] = normalizeScalarMutation(contract, field, value, scope, [...path, fieldName], issues, transactionReferences);
798
+ normalized[fieldName] = normalizeScalarMutation(contract, field, value, origin, [...path, fieldName], issues, transactionReferences);
728
799
  }
729
800
  else if (field?.kind === "relation") {
730
- normalized[fieldName] = normalizeRelationMutation(contract, field, value, scope, [...path, fieldName], issues);
801
+ normalized[fieldName] = normalizeRelationMutation(contract, field, value, origin, [...path, fieldName], issues, transactionReferences);
731
802
  }
732
803
  }
733
804
  return normalized;
@@ -739,36 +810,46 @@ function isUniqueOperation(request) {
739
810
  request.family === "delete" ||
740
811
  request.family === "upsert"));
741
812
  }
742
- export function normalizeOperationScalarValues(contract, request, scope, options) {
813
+ export function normalizeOperationScalarValues(contract, request, origin, options, write = "copy") {
814
+ const previous = writeInPlace;
815
+ writeInPlace = write === "in-place";
816
+ try {
817
+ return normalizeArguments(contract, request, origin, options);
818
+ }
819
+ finally {
820
+ writeInPlace = previous;
821
+ }
822
+ }
823
+ function normalizeArguments(contract, request, origin, options) {
743
824
  const issues = [];
744
825
  const args = cloneRecord(request.arguments);
745
826
  if ("where" in args) {
746
827
  args.where = isUniqueOperation(request)
747
- ? normalizeUniqueSelector(contract, request.resource, args.where, scope, ["arguments", "where"], issues)
748
- : normalizeWhere(contract, request.resource, args.where, scope, ["arguments", "where"], issues);
828
+ ? normalizeUniqueSelector(contract, request.resource, args.where, origin, ["arguments", "where"], issues, options?.transactionReferences === true)
829
+ : normalizeWhere(contract, request.resource, args.where, origin, ["arguments", "where"], issues, options?.transactionReferences === true);
749
830
  }
750
831
  if ("cursor" in args) {
751
- args.cursor = normalizeCursor(contract, request.resource, args.cursor, scope, ["arguments", "cursor"], issues);
832
+ args.cursor = normalizeCursor(contract, request.resource, args.cursor, origin, ["arguments", "cursor"], issues, options?.transactionReferences === true);
752
833
  }
753
834
  for (const mode of ["select", "include"]) {
754
835
  if (mode in args) {
755
- args[mode] = normalizeProjection(contract, request.resource, args[mode], scope, ["arguments", mode], issues);
836
+ args[mode] = normalizeProjection(contract, request.resource, args[mode], origin, ["arguments", mode], issues);
756
837
  }
757
838
  }
758
839
  if (request.family === "create" && "data" in args) {
759
840
  args.data = Array.isArray(args.data)
760
- ? args.data.map((entry, index) => normalizeMutationData(contract, request.resource, entry, scope, ["arguments", "data", index], issues, options?.transactionReferences === true))
761
- : normalizeMutationData(contract, request.resource, args.data, scope, ["arguments", "data"], issues, options?.transactionReferences === true);
841
+ ? args.data.map((entry, index) => normalizeMutationData(contract, request.resource, entry, origin, ["arguments", "data", index], issues, options?.transactionReferences === true))
842
+ : normalizeMutationData(contract, request.resource, args.data, origin, ["arguments", "data"], issues, options?.transactionReferences === true);
762
843
  }
763
844
  if (request.family === "update" && "data" in args) {
764
- args.data = normalizeMutationData(contract, request.resource, args.data, scope, ["arguments", "data"], issues, options?.transactionReferences === true);
845
+ args.data = normalizeMutationData(contract, request.resource, args.data, origin, ["arguments", "data"], issues, options?.transactionReferences === true);
765
846
  }
766
847
  if (request.family === "upsert") {
767
848
  if ("create" in args) {
768
- args.create = normalizeMutationData(contract, request.resource, args.create, scope, ["arguments", "create"], issues, options?.transactionReferences === true);
849
+ args.create = normalizeMutationData(contract, request.resource, args.create, origin, ["arguments", "create"], issues, options?.transactionReferences === true);
769
850
  }
770
851
  if ("update" in args) {
771
- args.update = normalizeMutationData(contract, request.resource, args.update, scope, ["arguments", "update"], issues, options?.transactionReferences === true);
852
+ args.update = normalizeMutationData(contract, request.resource, args.update, origin, ["arguments", "update"], issues, options?.transactionReferences === true);
772
853
  }
773
854
  }
774
855
  return issues.length > 0