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

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 (108) hide show
  1. package/CHANGELOG.md +338 -0
  2. package/README.md +100 -3
  3. package/dist/adapters/adapter-model.d.ts +8 -0
  4. package/dist/adapters/adapter.interface.d.ts +6 -2
  5. package/dist/compiler/contract-compiler-diagnostic.d.ts +6 -0
  6. package/dist/compiler/contract.compiler.js +67 -0
  7. package/dist/config/config.resolver.d.ts +3 -0
  8. package/dist/config/config.resolver.js +1 -0
  9. package/dist/config/config.validator.js +6 -0
  10. package/dist/config/define-fields.d.ts +10 -3
  11. package/dist/config/framework-config.d.ts +4 -1
  12. package/dist/config/framework-fields-config.d.ts +6 -0
  13. package/dist/contracts/client-contract-structure.validator.d.ts +21 -1
  14. package/dist/contracts/client-contract-structure.validator.js +99 -2
  15. package/dist/contracts/contract-canonicalizer.js +32 -0
  16. package/dist/contracts/contract.d.ts +7 -0
  17. package/dist/contracts/field.d.ts +10 -0
  18. package/dist/contracts/json-shape.d.ts +65 -0
  19. package/dist/contracts/json-shape.js +1 -0
  20. package/dist/contracts/reference-write-limit.d.ts +7 -0
  21. package/dist/contracts/reference-write-limit.js +1 -0
  22. package/dist/contracts/scalar-value-type.d.ts +12 -1
  23. package/dist/framework/contract-view.d.ts +126 -21
  24. package/dist/framework/framework.d.ts +5 -3
  25. package/dist/framework/framework.factory.js +56 -13
  26. package/dist/index.d.ts +8 -40
  27. package/dist/index.js +0 -20
  28. package/dist/internal.d.ts +35 -0
  29. package/dist/internal.js +16 -0
  30. package/dist/json/avz.d.ts +96 -0
  31. package/dist/json/avz.js +212 -0
  32. package/dist/json/index.d.ts +6 -0
  33. package/dist/json/index.js +1 -0
  34. package/dist/json/json-shape.registry.d.ts +22 -0
  35. package/dist/json/json-shape.registry.js +16 -0
  36. package/dist/json/zod-issue.translator.d.ts +51 -0
  37. package/dist/json/zod-issue.translator.js +142 -0
  38. package/dist/operations/operation-arguments.d.ts +151 -101
  39. package/dist/operations/operation-identity.d.ts +2 -0
  40. package/dist/operations/operation-identity.js +3 -0
  41. package/dist/operations/operation-validator-core.d.ts +1 -1
  42. package/dist/operations/operation-validator-core.js +28 -10
  43. package/dist/operations/operation-validator.d.ts +20 -5
  44. package/dist/operations/operation-validator.js +26 -10
  45. package/dist/operations/projection-scope.resolver.d.ts +1 -1
  46. package/dist/operations/structural-limits.walker.d.ts +19 -0
  47. package/dist/operations/structural-limits.walker.js +344 -0
  48. package/dist/protocol/absent-route.responder.d.ts +2 -1
  49. package/dist/protocol/absent-route.responder.js +32 -6
  50. package/dist/protocol/http-request.decoder.d.ts +6 -0
  51. package/dist/protocol/http-request.decoder.js +11 -3
  52. package/dist/protocol/protocol.binder.d.ts +4 -2
  53. package/dist/protocol/protocol.binder.js +3 -1
  54. package/dist/protocol/protocol.handler.d.ts +6 -2
  55. package/dist/protocol/protocol.handler.js +14 -4
  56. package/dist/protocol/unmounted-route.error.d.ts +19 -0
  57. package/dist/protocol/unmounted-route.error.js +10 -0
  58. package/dist/runtime/caller-data.copier.d.ts +59 -0
  59. package/dist/runtime/caller-data.copier.js +470 -0
  60. package/dist/runtime/caller-data.door.d.ts +56 -0
  61. package/dist/runtime/caller-data.door.js +65 -0
  62. package/dist/runtime/computed-read-runtime.js +3 -10
  63. package/dist/runtime/computed-value.error.d.ts +13 -0
  64. package/dist/runtime/computed-value.error.js +9 -0
  65. package/dist/runtime/create-requirement.d.ts +43 -7
  66. package/dist/runtime/create-requirement.js +89 -9
  67. package/dist/runtime/diagnostics-reporter.d.ts +20 -4
  68. package/dist/runtime/diagnostics-reporter.js +11 -4
  69. package/dist/runtime/error-boundary.d.ts +8 -0
  70. package/dist/runtime/error-boundary.js +65 -35
  71. package/dist/runtime/field-behavior.d.ts +2 -2
  72. package/dist/runtime/framework-error.d.ts +12 -0
  73. package/dist/runtime/misuse-reporter.d.ts +32 -0
  74. package/dist/runtime/misuse-reporter.js +19 -0
  75. package/dist/runtime/mutation-planner.js +13 -11
  76. package/dist/runtime/operation-request.d.ts +4 -11
  77. package/dist/runtime/operation-runtime.d.ts +14 -7
  78. package/dist/runtime/operation-runtime.js +37 -18
  79. package/dist/runtime/outcome-mapper.js +12 -2
  80. package/dist/runtime/output-validator.d.ts +10 -0
  81. package/dist/runtime/output-validator.js +11 -0
  82. package/dist/runtime/owned-execution.registry.d.ts +13 -0
  83. package/dist/runtime/owned-execution.registry.js +7 -0
  84. package/dist/runtime/pipeline.d.ts +19 -7
  85. package/dist/runtime/referential-action.d.ts +7 -0
  86. package/dist/runtime/request-envelope.validator.d.ts +5 -0
  87. package/dist/runtime/request-envelope.validator.js +118 -0
  88. package/dist/runtime/scalar-runtime.d.ts +30 -2
  89. package/dist/runtime/scalar-runtime.js +162 -79
  90. package/dist/transactions/transaction-plan-assembler.d.ts +5 -1
  91. package/dist/transactions/transaction-plan-assembler.js +74 -75
  92. package/dist/transactions/transaction-plan-validator.d.ts +30 -7
  93. package/dist/transactions/transaction-plan-validator.js +204 -153
  94. package/dist/transactions/transaction-reference-collector.d.ts +30 -0
  95. package/dist/transactions/transaction-reference-collector.js +204 -0
  96. package/dist/transactions/transaction-reference-resolver.js +10 -5
  97. package/dist/transactions/transaction-reference-validator.js +24 -17
  98. package/dist/transactions/transaction-reference.d.ts +23 -51
  99. package/dist/transactions/transaction-request.d.ts +3 -3
  100. package/dist/transactions/transaction-response.d.ts +6 -1
  101. package/dist/transactions/transaction-response.js +24 -1
  102. package/dist/transactions/transaction-runtime.d.ts +4 -2
  103. package/dist/transactions/transaction-runtime.js +4 -3
  104. package/package.json +17 -3
  105. package/dist/operations/operation-boolean-nodes.d.ts +0 -11
  106. package/dist/operations/operation-boolean-nodes.js +0 -283
  107. package/dist/operations/operation-nesting.d.ts +0 -8
  108. package/dist/operations/operation-nesting.js +0 -307
@@ -1,283 +0,0 @@
1
- import { lookupField, lookupResource } from "../contracts/contract-lookup.js";
2
- import { advertisedDirectives, holdsAt, } from "../contracts/field.js";
3
- import { NESTED_PROJECTION_SCOPE, resolveProjectionScope, } from "./projection-scope.resolver.js";
4
- function isRecord(value) {
5
- return typeof value === "object" && value !== null && !Array.isArray(value);
6
- }
7
- function booleanNodeIssue(contract, path) {
8
- return {
9
- path,
10
- code: "V1015",
11
- message: `Boolean/filter node count exceeds maxBooleanNodes (${contract.limits.maxBooleanNodes}).`,
12
- };
13
- }
14
- function countNode(state, path) {
15
- state.count += 1;
16
- return state.count > state.contract.limits.maxBooleanNodes
17
- ? booleanNodeIssue(state.contract, path)
18
- : undefined;
19
- }
20
- function walkWhere(state, resourceName, value, path) {
21
- if (!isRecord(value)) {
22
- return undefined;
23
- }
24
- const resource = lookupResource(state.contract, resourceName);
25
- if (resource === undefined) {
26
- return undefined;
27
- }
28
- for (const [key, child] of Object.entries(value)) {
29
- const exceeded = countNode(state, [...path, key]);
30
- if (exceeded !== undefined) {
31
- return exceeded;
32
- }
33
- if (key === "AND" || key === "OR") {
34
- if (!Array.isArray(child)) {
35
- continue;
36
- }
37
- for (let index = 0; index < child.length; index += 1) {
38
- const issue = walkWhere(state, resourceName, child[index], [
39
- ...path,
40
- key,
41
- index,
42
- ]);
43
- if (issue !== undefined) {
44
- return issue;
45
- }
46
- }
47
- continue;
48
- }
49
- if (key === "NOT") {
50
- const issue = walkWhere(state, resourceName, child, [...path, key]);
51
- if (issue !== undefined) {
52
- return issue;
53
- }
54
- continue;
55
- }
56
- const field = lookupField(resource, key);
57
- if (field?.kind !== "relation") {
58
- continue;
59
- }
60
- if (field.cardinality === "one") {
61
- if (child === null || !isRecord(child)) {
62
- continue;
63
- }
64
- const issue = walkWhere(state, field.target, child, [...path, key]);
65
- if (issue !== undefined) {
66
- return issue;
67
- }
68
- continue;
69
- }
70
- if (!isRecord(child)) {
71
- continue;
72
- }
73
- for (const relationOperator of ["some", "every", "none"]) {
74
- if (!(relationOperator in child)) {
75
- continue;
76
- }
77
- const issue = walkWhere(state, field.target, child[relationOperator], [
78
- ...path,
79
- key,
80
- relationOperator,
81
- ]);
82
- if (issue !== undefined) {
83
- return issue;
84
- }
85
- }
86
- }
87
- return undefined;
88
- }
89
- function projectionRelation(contract, resourceName, entry, mode, scope) {
90
- if (Object.keys(entry).length !== 1) {
91
- return undefined;
92
- }
93
- const name = Object.keys(entry)[0];
94
- const field = lookupField(lookupResource(contract, resourceName), name);
95
- if (field?.kind !== "relation") {
96
- return undefined;
97
- }
98
- if (mode === "select" && !holdsAt(field.capabilities.select, scope)) {
99
- return undefined;
100
- }
101
- if (mode === "include" && !holdsAt(field.capabilities.include, scope)) {
102
- return undefined;
103
- }
104
- return { name, edge: field, value: entry[name] };
105
- }
106
- function walkProjection(state, resourceName, value, mode, scope, path) {
107
- if (!Array.isArray(value)) {
108
- return undefined;
109
- }
110
- for (let index = 0; index < value.length; index += 1) {
111
- const entry = value[index];
112
- if (!isRecord(entry)) {
113
- continue;
114
- }
115
- const relation = projectionRelation(state.contract, resourceName, entry, mode, scope);
116
- if (relation === undefined || !isRecord(relation.value)) {
117
- continue;
118
- }
119
- const relationPath = [...path, index, relation.name];
120
- if ("where" in relation.value &&
121
- relation.edge.capabilities.filter?.includes("nested") === true) {
122
- const issue = walkWhere(state, relation.edge.target, relation.value.where, [...relationPath, "where"]);
123
- if (issue !== undefined) {
124
- return issue;
125
- }
126
- }
127
- for (const nestedMode of ["select", "include"]) {
128
- if (!(nestedMode in relation.value)) {
129
- continue;
130
- }
131
- const issue = walkProjection(state, relation.edge.target, relation.value[nestedMode], nestedMode, NESTED_PROJECTION_SCOPE, [...relationPath, nestedMode]);
132
- if (issue !== undefined) {
133
- return issue;
134
- }
135
- }
136
- }
137
- return undefined;
138
- }
139
- function relationEntries(value) {
140
- return Array.isArray(value) ? value : [value];
141
- }
142
- function walkMutationData(state, resourceName, value, stage, path) {
143
- if (!isRecord(value)) {
144
- return undefined;
145
- }
146
- const resource = lookupResource(state.contract, resourceName);
147
- if (resource === undefined) {
148
- return undefined;
149
- }
150
- for (const [fieldName, fieldValue] of Object.entries(value)) {
151
- const edge = lookupField(resource, fieldName);
152
- if (edge?.kind !== "relation" || !isRecord(fieldValue)) {
153
- continue;
154
- }
155
- const supported = advertisedDirectives(edge.capabilities[stage]);
156
- for (const [directive, directiveValue] of Object.entries(fieldValue)) {
157
- if (supported?.includes(directive) !== true) {
158
- continue;
159
- }
160
- const entries = relationEntries(directiveValue);
161
- for (let index = 0; index < entries.length; index += 1) {
162
- const entry = entries[index];
163
- const indexPath = Array.isArray(directiveValue) ? [index] : [];
164
- const directivePath = [...path, fieldName, directive, ...indexPath];
165
- if (directive === "$create") {
166
- const issue = walkMutationData(state, edge.target, entry, "create", directivePath);
167
- if (issue !== undefined) {
168
- return issue;
169
- }
170
- continue;
171
- }
172
- if (!isRecord(entry)) {
173
- continue;
174
- }
175
- if (directive === "$connectOrCreate" && "create" in entry) {
176
- const issue = walkMutationData(state, edge.target, entry.create, "create", [...directivePath, "create"]);
177
- if (issue !== undefined) {
178
- return issue;
179
- }
180
- continue;
181
- }
182
- if (directive === "$update") {
183
- if ("where" in entry) {
184
- const issue = walkWhere(state, edge.target, entry.where, [
185
- ...directivePath,
186
- "where",
187
- ]);
188
- if (issue !== undefined) {
189
- return issue;
190
- }
191
- }
192
- if ("data" in entry) {
193
- const issue = walkMutationData(state, edge.target, entry.data, "update", [...directivePath, "data"]);
194
- if (issue !== undefined) {
195
- return issue;
196
- }
197
- }
198
- continue;
199
- }
200
- if (directive === "$delete" && "where" in entry) {
201
- const issue = walkWhere(state, edge.target, entry.where, [
202
- ...directivePath,
203
- "where",
204
- ]);
205
- if (issue !== undefined) {
206
- return issue;
207
- }
208
- continue;
209
- }
210
- if (directive === "$upsert") {
211
- for (const branch of ["create", "update"]) {
212
- if (!(branch in entry)) {
213
- continue;
214
- }
215
- const issue = walkMutationData(state, edge.target, entry[branch], branch, [...directivePath, branch]);
216
- if (issue !== undefined) {
217
- return issue;
218
- }
219
- }
220
- }
221
- }
222
- }
223
- }
224
- return undefined;
225
- }
226
- function isUniqueOperation(request) {
227
- return (request.variant === "unique" &&
228
- (request.family === "find" ||
229
- request.family === "update" ||
230
- request.family === "delete" ||
231
- request.family === "upsert"));
232
- }
233
- export function findOperationBooleanNodeIssue(contract, request, args) {
234
- const state = { contract, count: 0 };
235
- const projectionScope = resolveProjectionScope(lookupResource(contract, request.resource), request);
236
- if ("where" in args && !isUniqueOperation(request)) {
237
- const issue = walkWhere(state, request.resource, args.where, [
238
- "arguments",
239
- "where",
240
- ]);
241
- if (issue !== undefined) {
242
- return issue;
243
- }
244
- }
245
- for (const mode of ["select", "include"]) {
246
- if (!(mode in args)) {
247
- continue;
248
- }
249
- const issue = walkProjection(state, request.resource, args[mode], mode, projectionScope, ["arguments", mode]);
250
- if (issue !== undefined) {
251
- return issue;
252
- }
253
- }
254
- if (request.family === "create" && "data" in args) {
255
- const entries = Array.isArray(args.data) ? args.data : [args.data];
256
- for (let index = 0; index < entries.length; index += 1) {
257
- const issue = walkMutationData(state, request.resource, entries[index], "create", Array.isArray(args.data)
258
- ? ["arguments", "data", index]
259
- : ["arguments", "data"]);
260
- if (issue !== undefined) {
261
- return issue;
262
- }
263
- }
264
- }
265
- if (request.family === "update" && "data" in args) {
266
- const issue = walkMutationData(state, request.resource, args.data, "update", ["arguments", "data"]);
267
- if (issue !== undefined) {
268
- return issue;
269
- }
270
- }
271
- if (request.family === "upsert") {
272
- for (const branch of ["create", "update"]) {
273
- if (!(branch in args)) {
274
- continue;
275
- }
276
- const issue = walkMutationData(state, request.resource, args[branch], branch, ["arguments", branch]);
277
- if (issue !== undefined) {
278
- return issue;
279
- }
280
- }
281
- }
282
- return undefined;
283
- }
@@ -1,8 +0,0 @@
1
- import type { Contract } from "../contracts/contract.js";
2
- import type { ValidationIssue } from "./validation-code.js";
3
- /**
4
- * Enforces the Contract's semantic nesting limit across where, projection,
5
- * orderBy, mutation data, and relation traversal before deeper argument
6
- * validation.
7
- */
8
- export declare function findOperationNestingIssue(contract: Contract, resourceName: string, args: Readonly<Record<string, unknown>>): ValidationIssue | undefined;
@@ -1,307 +0,0 @@
1
- import { lookupField, lookupResource } from "../contracts/contract-lookup.js";
2
- function isRecord(value) {
3
- return typeof value === "object" && value !== null && !Array.isArray(value);
4
- }
5
- function nestingIssue(context) {
6
- return {
7
- path: context.rootPath,
8
- code: "V1013",
9
- message: `Request nesting exceeds maxNestingDepth (${context.limit}).`,
10
- };
11
- }
12
- function checkDepth(context, depth) {
13
- return depth > context.limit ? nestingIssue(context) : undefined;
14
- }
15
- function createContext(contract, rootPath) {
16
- return {
17
- contract,
18
- limit: contract.limits.maxNestingDepth,
19
- rootPath,
20
- };
21
- }
22
- function relationEntries(value) {
23
- return Array.isArray(value) ? value : [value];
24
- }
25
- function walkWhere(context, resourceName, value, depth, path) {
26
- const exceeded = checkDepth(context, depth);
27
- if (exceeded !== undefined || !isRecord(value)) {
28
- return exceeded;
29
- }
30
- const resource = lookupResource(context.contract, resourceName);
31
- if (resource === undefined) {
32
- return undefined;
33
- }
34
- for (const [key, child] of Object.entries(value)) {
35
- if (key === "AND" || key === "OR") {
36
- if (!Array.isArray(child)) {
37
- continue;
38
- }
39
- for (let index = 0; index < child.length; index += 1) {
40
- const issue = walkWhere(context, resourceName, child[index], depth + 1, [...path, key, index]);
41
- if (issue !== undefined) {
42
- return issue;
43
- }
44
- }
45
- continue;
46
- }
47
- if (key === "NOT") {
48
- const issue = walkWhere(context, resourceName, child, depth + 1, [
49
- ...path,
50
- key,
51
- ]);
52
- if (issue !== undefined) {
53
- return issue;
54
- }
55
- continue;
56
- }
57
- const field = lookupField(resource, key);
58
- if (field?.kind !== "relation") {
59
- continue;
60
- }
61
- if (field.cardinality === "one") {
62
- const issue = walkWhere(context, field.target, child, depth + 1, [
63
- ...path,
64
- key,
65
- ]);
66
- if (issue !== undefined) {
67
- return issue;
68
- }
69
- continue;
70
- }
71
- if (!isRecord(child)) {
72
- continue;
73
- }
74
- for (const relationOperator of ["some", "every", "none"]) {
75
- if (!(relationOperator in child)) {
76
- continue;
77
- }
78
- const issue = walkWhere(context, field.target, child[relationOperator], depth + 1, [...path, key, relationOperator]);
79
- if (issue !== undefined) {
80
- return issue;
81
- }
82
- }
83
- }
84
- return undefined;
85
- }
86
- function walkOrderBy(context, resourceName, value, depth, path) {
87
- const entries = Array.isArray(value) ? value : [value];
88
- const resource = lookupResource(context.contract, resourceName);
89
- if (resource === undefined) {
90
- return undefined;
91
- }
92
- for (let index = 0; index < entries.length; index += 1) {
93
- const entry = entries[index];
94
- if (!isRecord(entry)) {
95
- continue;
96
- }
97
- const entryPath = Array.isArray(value) ? [...path, index] : path;
98
- for (const [fieldName, child] of Object.entries(entry)) {
99
- const field = lookupField(resource, fieldName);
100
- if (field?.kind !== "relation" || field.cardinality === "many") {
101
- continue;
102
- }
103
- const relationDepth = depth + 1;
104
- const exceeded = checkDepth(context, relationDepth);
105
- if (exceeded !== undefined) {
106
- return exceeded;
107
- }
108
- const issue = walkOrderBy(context, field.target, child, relationDepth, [
109
- ...entryPath,
110
- fieldName,
111
- ]);
112
- if (issue !== undefined) {
113
- return issue;
114
- }
115
- }
116
- }
117
- return undefined;
118
- }
119
- function walkProjection(context, resourceName, value, depth, path) {
120
- if (!Array.isArray(value)) {
121
- return undefined;
122
- }
123
- const resource = lookupResource(context.contract, resourceName);
124
- if (resource === undefined) {
125
- return undefined;
126
- }
127
- for (let index = 0; index < value.length; index += 1) {
128
- const entry = value[index];
129
- if (!isRecord(entry) || Object.keys(entry).length !== 1) {
130
- continue;
131
- }
132
- const relationName = Object.keys(entry)[0];
133
- const edge = lookupField(resource, relationName);
134
- if (edge?.kind !== "relation") {
135
- continue;
136
- }
137
- const relationPath = [...path, index, relationName];
138
- const relationDepth = depth + 1;
139
- const exceeded = checkDepth(context, relationDepth);
140
- if (exceeded !== undefined) {
141
- return exceeded;
142
- }
143
- const projection = entry[relationName];
144
- if (!isRecord(projection)) {
145
- continue;
146
- }
147
- if ("where" in projection) {
148
- const issue = walkWhere(context, edge.target, projection.where, relationDepth, [...relationPath, "where"]);
149
- if (issue !== undefined) {
150
- return issue;
151
- }
152
- }
153
- if ("orderBy" in projection) {
154
- const issue = walkOrderBy(context, edge.target, projection.orderBy, relationDepth, [...relationPath, "orderBy"]);
155
- if (issue !== undefined) {
156
- return issue;
157
- }
158
- }
159
- for (const mode of ["select", "include"]) {
160
- if (!(mode in projection)) {
161
- continue;
162
- }
163
- const issue = walkProjection(context, edge.target, projection[mode], relationDepth, [...relationPath, mode]);
164
- if (issue !== undefined) {
165
- return issue;
166
- }
167
- }
168
- }
169
- return undefined;
170
- }
171
- function nestedMutationPayloads(directive, value) {
172
- const values = relationEntries(value);
173
- const payloads = [];
174
- for (let index = 0; index < values.length; index += 1) {
175
- const entry = values[index];
176
- const indexPath = Array.isArray(value) ? [index] : [];
177
- if (directive === "$create") {
178
- payloads.push({ data: entry, suffix: indexPath });
179
- continue;
180
- }
181
- if (!isRecord(entry)) {
182
- continue;
183
- }
184
- if (directive === "$connectOrCreate" && "create" in entry) {
185
- payloads.push({ data: entry.create, suffix: [...indexPath, "create"] });
186
- continue;
187
- }
188
- if (directive === "$update" && "data" in entry) {
189
- payloads.push({ data: entry.data, suffix: [...indexPath, "data"] });
190
- continue;
191
- }
192
- if (directive === "$upsert") {
193
- if ("create" in entry) {
194
- payloads.push({ data: entry.create, suffix: [...indexPath, "create"] });
195
- }
196
- if ("update" in entry) {
197
- payloads.push({ data: entry.update, suffix: [...indexPath, "update"] });
198
- }
199
- }
200
- }
201
- return payloads;
202
- }
203
- function walkMutationDirectiveWheres(context, resourceName, directive, value, depth, path) {
204
- if (directive !== "$update" && directive !== "$delete") {
205
- return undefined;
206
- }
207
- const entries = relationEntries(value);
208
- for (let index = 0; index < entries.length; index += 1) {
209
- const entry = entries[index];
210
- if (!isRecord(entry) || !("where" in entry)) {
211
- continue;
212
- }
213
- const indexPath = Array.isArray(value) ? [index] : [];
214
- const issue = walkWhere(context, resourceName, entry.where, depth, [
215
- ...path,
216
- ...indexPath,
217
- "where",
218
- ]);
219
- if (issue !== undefined) {
220
- return issue;
221
- }
222
- }
223
- return undefined;
224
- }
225
- function walkMutationData(context, resourceName, value, depth, path) {
226
- const exceeded = checkDepth(context, depth);
227
- if (exceeded !== undefined || !isRecord(value)) {
228
- return exceeded;
229
- }
230
- const resource = lookupResource(context.contract, resourceName);
231
- if (resource === undefined) {
232
- return undefined;
233
- }
234
- for (const [fieldName, fieldValue] of Object.entries(value)) {
235
- const edge = lookupField(resource, fieldName);
236
- if (edge?.kind !== "relation" || !isRecord(fieldValue)) {
237
- continue;
238
- }
239
- for (const [directive, directiveValue] of Object.entries(fieldValue)) {
240
- const relationDepth = depth + 1;
241
- const relationPath = [...path, fieldName, directive];
242
- const relationExceeded = checkDepth(context, relationDepth);
243
- if (relationExceeded !== undefined) {
244
- return relationExceeded;
245
- }
246
- const whereIssue = walkMutationDirectiveWheres(context, edge.target, directive, directiveValue, relationDepth, relationPath);
247
- if (whereIssue !== undefined) {
248
- return whereIssue;
249
- }
250
- for (const payload of nestedMutationPayloads(directive, directiveValue)) {
251
- const issue = walkMutationData(context, edge.target, payload.data, relationDepth, [...relationPath, ...payload.suffix]);
252
- if (issue !== undefined) {
253
- return issue;
254
- }
255
- }
256
- }
257
- }
258
- return undefined;
259
- }
260
- export function findOperationNestingIssue(contract, resourceName, args) {
261
- if ("where" in args) {
262
- const rootPath = ["arguments", "where"];
263
- const issue = walkWhere(createContext(contract, rootPath), resourceName, args.where, 1, rootPath);
264
- if (issue !== undefined) {
265
- return issue;
266
- }
267
- }
268
- if ("orderBy" in args) {
269
- const rootPath = ["arguments", "orderBy"];
270
- const issue = walkOrderBy(createContext(contract, rootPath), resourceName, args.orderBy, 0, rootPath);
271
- if (issue !== undefined) {
272
- return issue;
273
- }
274
- }
275
- for (const mode of ["select", "include"]) {
276
- if (!(mode in args)) {
277
- continue;
278
- }
279
- const rootPath = ["arguments", mode];
280
- const issue = walkProjection(createContext(contract, rootPath), resourceName, args[mode], 0, rootPath);
281
- if (issue !== undefined) {
282
- return issue;
283
- }
284
- }
285
- if ("data" in args) {
286
- const rootPath = ["arguments", "data"];
287
- const context = createContext(contract, rootPath);
288
- const dataEntries = Array.isArray(args.data) ? args.data : [args.data];
289
- for (let index = 0; index < dataEntries.length; index += 1) {
290
- const issue = walkMutationData(context, resourceName, dataEntries[index], 0, Array.isArray(args.data) ? [...rootPath, index] : rootPath);
291
- if (issue !== undefined) {
292
- return issue;
293
- }
294
- }
295
- }
296
- for (const branch of ["create", "update"]) {
297
- if (!(branch in args)) {
298
- continue;
299
- }
300
- const rootPath = ["arguments", branch];
301
- const issue = walkMutationData(createContext(contract, rootPath), resourceName, args[branch], 0, rootPath);
302
- if (issue !== undefined) {
303
- return issue;
304
- }
305
- }
306
- return undefined;
307
- }