@opensaas/stack-core 0.32.0 → 0.34.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.
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +61 -0
- package/dist/access/access-filter.d.ts +76 -20
- package/dist/access/access-filter.d.ts.map +1 -1
- package/dist/access/access-filter.js +102 -70
- package/dist/access/access-filter.js.map +1 -1
- package/dist/access/access-filter.test.js +175 -10
- package/dist/access/access-filter.test.js.map +1 -1
- package/dist/access/depth-limits.d.ts +26 -0
- package/dist/access/depth-limits.d.ts.map +1 -0
- package/dist/access/depth-limits.js +26 -0
- package/dist/access/depth-limits.js.map +1 -0
- package/dist/access/errors.d.ts +43 -0
- package/dist/access/errors.d.ts.map +1 -0
- package/dist/access/errors.js +55 -0
- package/dist/access/errors.js.map +1 -0
- package/dist/access/field-visibility.d.ts.map +1 -1
- package/dist/access/field-visibility.js +82 -20
- package/dist/access/field-visibility.js.map +1 -1
- package/dist/access/index.d.ts +4 -1
- package/dist/access/index.d.ts.map +1 -1
- package/dist/access/index.js +5 -1
- package/dist/access/index.js.map +1 -1
- package/dist/access/multi-column-read-write.test.js +1 -1
- package/dist/access/multi-column-read-write.test.js.map +1 -1
- package/dist/access/relationship-count.test.js +1 -1
- package/dist/access/relationship-count.test.js.map +1 -1
- package/dist/access/relationship-label-filter.test.js +1 -1
- package/dist/access/relationship-label-filter.test.js.map +1 -1
- package/dist/access/types.d.ts +15 -7
- package/dist/access/types.d.ts.map +1 -1
- package/dist/context/index.d.ts.map +1 -1
- package/dist/context/index.js +15 -9
- package/dist/context/index.js.map +1 -1
- package/dist/context/nested-operations.d.ts +1 -1
- package/dist/context/nested-operations.d.ts.map +1 -1
- package/dist/context/nested-operations.js +1 -5
- package/dist/context/nested-operations.js.map +1 -1
- package/dist/context/transaction-boundary.d.ts.map +1 -1
- package/dist/context/transaction-boundary.js +43 -6
- package/dist/context/transaction-boundary.js.map +1 -1
- package/dist/context/write-pipeline.d.ts.map +1 -1
- package/dist/context/write-pipeline.js +5 -4
- package/dist/context/write-pipeline.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/access/access-filter.test.ts +258 -7
- package/src/access/access-filter.ts +146 -72
- package/src/access/depth-limits.ts +26 -0
- package/src/access/errors.ts +62 -0
- package/src/access/field-visibility.ts +97 -21
- package/src/access/index.ts +6 -0
- package/src/access/multi-column-read-write.test.ts +1 -1
- package/src/access/relationship-count.test.ts +1 -1
- package/src/access/relationship-label-filter.test.ts +1 -1
- package/src/access/types.ts +12 -5
- package/src/context/index.ts +15 -6
- package/src/context/nested-operations.ts +0 -7
- package/src/context/transaction-boundary.ts +48 -7
- package/src/context/write-pipeline.ts +5 -4
- package/src/index.ts +11 -0
- package/tests/access-relationships.test.ts +78 -64
- package/tests/context.test.ts +106 -24
- package/tests/default-value-create.test.ts +1 -1
- package/tests/hook-pipeline.test.ts +1 -1
- package/tests/nav-count.test.ts +2 -2
- package/tests/resolve-chain.test.ts +394 -0
- package/tests/transaction-boundary-hooks.test.ts +246 -1
- package/tests/write-pipeline.test.ts +1 -1
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { buildIncludeWithAccessControl, mergeIncludeWithAccessControl } from './access-filter.js';
|
|
2
|
+
import { buildIncludeWithAccessControl, mergeIncludeWithAccessControl, toPrismaInclude, } from './access-filter.js';
|
|
3
|
+
import { AccessScopeDepthExceededError } from './errors.js';
|
|
4
|
+
import { READ_INCLUDE_MAX_DEPTH } from './depth-limits.js';
|
|
3
5
|
/**
|
|
4
6
|
* Regression coverage for the cyclic readable-relationship auto-include.
|
|
5
7
|
*
|
|
@@ -37,11 +39,15 @@ function cyclicConfig() {
|
|
|
37
39
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- minimal config for unit test
|
|
38
40
|
};
|
|
39
41
|
}
|
|
40
|
-
function makeContext() {
|
|
42
|
+
function makeContext(resolveOutputDepth = 0) {
|
|
43
|
+
const chain = Array.from({ length: resolveOutputDepth }, (_, i) => ({
|
|
44
|
+
listKey: 'TestHook',
|
|
45
|
+
fieldKey: `hook${i}`,
|
|
46
|
+
}));
|
|
41
47
|
return {
|
|
42
48
|
session: null,
|
|
43
49
|
_isSudo: false,
|
|
44
|
-
|
|
50
|
+
_resolveOutputChain: chain,
|
|
45
51
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- minimal context for unit test
|
|
46
52
|
};
|
|
47
53
|
}
|
|
@@ -64,10 +70,60 @@ function includeDepth(include) {
|
|
|
64
70
|
}
|
|
65
71
|
return max;
|
|
66
72
|
}
|
|
73
|
+
// A straight-line chain of `count` lists, each with a scalar field and a
|
|
74
|
+
// single relationship to the next list: L0 → L1 → … → L(count-1). Every list
|
|
75
|
+
// past the root is query-scoped with a filter unique to it, so a test can
|
|
76
|
+
// assert the merged tree actually carries the right `where` at a given hop
|
|
77
|
+
// (not just that it happens not to throw).
|
|
78
|
+
function chainConfig(count) {
|
|
79
|
+
const lists = {};
|
|
80
|
+
for (let i = 0; i < count; i++) {
|
|
81
|
+
const listName = `L${i}`;
|
|
82
|
+
const fields = { name: { type: 'text' } };
|
|
83
|
+
if (i < count - 1) {
|
|
84
|
+
fields.next = rel(`L${i + 1}.prev`);
|
|
85
|
+
}
|
|
86
|
+
if (i > 0) {
|
|
87
|
+
fields.prev = rel(`L${i - 1}.next`);
|
|
88
|
+
}
|
|
89
|
+
const filter = { ownerId: { equals: listName } };
|
|
90
|
+
lists[listName] = {
|
|
91
|
+
fields,
|
|
92
|
+
access: { operation: { query: i === 0 ? () => true : () => filter } },
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
db: { provider: 'sqlite', url: 'file:./dev.db' },
|
|
97
|
+
lists,
|
|
98
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- minimal config for unit test
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
// A caller `include` value selecting `next` `hops` more times beyond the
|
|
102
|
+
// point at which this value is attached, ending in a bare `true` leaf. E.g.
|
|
103
|
+
// `nestedInclude(0) === true` (stop here); `{ next: nestedInclude(2) }` at the
|
|
104
|
+
// top level names 3 hops total (the outer `next` plus 2 more).
|
|
105
|
+
function nestedInclude(hops) {
|
|
106
|
+
if (hops <= 0)
|
|
107
|
+
return true;
|
|
108
|
+
return { include: { next: nestedInclude(hops - 1) } };
|
|
109
|
+
}
|
|
110
|
+
// Read the `where` at the end of a chain of nested `next` includes (used to
|
|
111
|
+
// assert row-scoping survived down to a specific hop).
|
|
112
|
+
function whereAtHop(merged, hops) {
|
|
113
|
+
let current = merged;
|
|
114
|
+
for (let i = 0; i < hops; i++) {
|
|
115
|
+
const entry = current?.next;
|
|
116
|
+
if (i === hops - 1)
|
|
117
|
+
return entry?.where;
|
|
118
|
+
current = entry?.include;
|
|
119
|
+
}
|
|
120
|
+
return undefined;
|
|
121
|
+
}
|
|
67
122
|
describe('buildIncludeWithAccessControl — cyclic graph', () => {
|
|
68
123
|
it('stops re-descending a relationship cycle instead of walking to MAX_DEPTH', async () => {
|
|
69
124
|
const config = cyclicConfig();
|
|
70
|
-
const
|
|
125
|
+
const result = await buildIncludeWithAccessControl(config.lists.A.fields, { session: null, context: makeContext() }, config, 0, ['A']);
|
|
126
|
+
const include = toPrismaInclude(result);
|
|
71
127
|
// A → B → C, then C.a closes the cycle back to A → flat (no further nesting).
|
|
72
128
|
expect(include).toEqual({
|
|
73
129
|
b: { include: { c: { include: { a: true } } } },
|
|
@@ -79,7 +135,7 @@ describe('buildIncludeWithAccessControl — cyclic graph', () => {
|
|
|
79
135
|
it('flattens a self-referential relationship to a single level', async () => {
|
|
80
136
|
const allowQuery = () => true;
|
|
81
137
|
const config = {
|
|
82
|
-
db: { provider: 'sqlite'
|
|
138
|
+
db: { provider: 'sqlite' },
|
|
83
139
|
lists: {
|
|
84
140
|
Category: {
|
|
85
141
|
fields: {
|
|
@@ -92,7 +148,8 @@ describe('buildIncludeWithAccessControl — cyclic graph', () => {
|
|
|
92
148
|
},
|
|
93
149
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- minimal config for unit test
|
|
94
150
|
};
|
|
95
|
-
const
|
|
151
|
+
const result = await buildIncludeWithAccessControl(config.lists.Category.fields, { session: null, context: makeContext() }, config, 0, ['Category']);
|
|
152
|
+
const include = toPrismaInclude(result);
|
|
96
153
|
// Both self-references come back flat — no infinite parent/children descent.
|
|
97
154
|
expect(include).toEqual({ parent: true, children: true });
|
|
98
155
|
expect(includeDepth(include)).toBe(1);
|
|
@@ -105,7 +162,7 @@ describe('mergeIncludeWithAccessControl — bare-true leaf on a cyclic graph', (
|
|
|
105
162
|
// Caller asks for A → b with a bare-`true` leaf. The merge must keep the
|
|
106
163
|
// access-controlled (cycle-bounded) nested include rather than re-expanding
|
|
107
164
|
// the leaf into an unbounded auto-include.
|
|
108
|
-
const merged = mergeIncludeWithAccessControl({ b: true }, accessControlledInclude, config.lists.A.fields, config);
|
|
165
|
+
const merged = mergeIncludeWithAccessControl({ b: true }, accessControlledInclude, config.lists.A.fields, config, 'A');
|
|
109
166
|
expect(merged).toEqual({
|
|
110
167
|
b: { include: { c: { include: { a: true } } } },
|
|
111
168
|
});
|
|
@@ -124,7 +181,7 @@ describe('mergeIncludeWithAccessControl — caller take on a to-many relation (i
|
|
|
124
181
|
// A one-list config whose `posts` to-many is query-scoped by an access filter.
|
|
125
182
|
function scopedConfig() {
|
|
126
183
|
return {
|
|
127
|
-
db: { provider: 'sqlite'
|
|
184
|
+
db: { provider: 'sqlite' },
|
|
128
185
|
lists: {
|
|
129
186
|
User: {
|
|
130
187
|
fields: { name: { type: 'text' }, posts: rel('Post.author', true) },
|
|
@@ -142,7 +199,7 @@ describe('mergeIncludeWithAccessControl — caller take on a to-many relation (i
|
|
|
142
199
|
it('preserves the take and AND-combines it with the access where', async () => {
|
|
143
200
|
const config = scopedConfig();
|
|
144
201
|
const accessControlledInclude = await buildIncludeWithAccessControl(config.lists.User.fields, { session: null, context: makeContext() }, config, 0, ['User']);
|
|
145
|
-
const merged = mergeIncludeWithAccessControl({ posts: { take: 10 } }, accessControlledInclude, config.lists.User.fields, config);
|
|
202
|
+
const merged = mergeIncludeWithAccessControl({ posts: { take: 10 } }, accessControlledInclude, config.lists.User.fields, config, 'User');
|
|
146
203
|
// The bound rides on top of the access filter — neither is dropped. The
|
|
147
204
|
// access-controlled include also auto-nests Post's `author` back-relation.
|
|
148
205
|
expect(merged).toEqual({
|
|
@@ -158,9 +215,117 @@ describe('mergeIncludeWithAccessControl — caller take on a to-many relation (i
|
|
|
158
215
|
// Deny Post reads entirely.
|
|
159
216
|
config.lists.Post.access = { operation: { query: () => false } };
|
|
160
217
|
const accessControlledInclude = await buildIncludeWithAccessControl(config.lists.User.fields, { session: null, context: makeContext() }, config, 0, ['User']);
|
|
161
|
-
const merged = mergeIncludeWithAccessControl({ posts: { take: 10 } }, accessControlledInclude, config.lists.User.fields, config);
|
|
218
|
+
const merged = mergeIncludeWithAccessControl({ posts: { take: 10 } }, accessControlledInclude, config.lists.User.fields, config, 'User');
|
|
162
219
|
// A denied relation is dropped wholesale — the take cannot resurrect it.
|
|
163
220
|
expect(merged).toEqual({});
|
|
164
221
|
});
|
|
165
222
|
});
|
|
223
|
+
/**
|
|
224
|
+
* Regression coverage for issue #830: the read pipeline used to FAIL OPEN past
|
|
225
|
+
* `READ_INCLUDE_MAX_DEPTH` — a caller-supplied `include` nested deeper than the
|
|
226
|
+
* engine could scope was passed through unscoped rather than denied. These
|
|
227
|
+
* tests pin the exact boundary the fix introduces (ADR-0022): a caller include
|
|
228
|
+
* one level past the cap throws, the same include one level shallower still
|
|
229
|
+
* works, and an unrequested auto-include past the cap stays silent.
|
|
230
|
+
*/
|
|
231
|
+
describe('mergeIncludeWithAccessControl — fail-closed at the read-include depth cap (#830)', () => {
|
|
232
|
+
// A relation `hops` hops from the root sits AT the cap boundary (correctly
|
|
233
|
+
// where-scoped, matching the triage report's "F" list); one hop further is
|
|
234
|
+
// the first one the engine cannot scope ("G"). With
|
|
235
|
+
// READ_INCLUDE_MAX_DEPTH = 5 that boundary is hop 5 / hop 6.
|
|
236
|
+
const HOPS_AT_CAP = READ_INCLUDE_MAX_DEPTH;
|
|
237
|
+
it('throws AccessScopeDepthExceededError when the caller include reaches past the cap', async () => {
|
|
238
|
+
// L0 → L1 → … → L6 (one more list than HOPS_AT_CAP + 1) so a caller
|
|
239
|
+
// include can walk `next` one hop past the boundary.
|
|
240
|
+
const chainLength = HOPS_AT_CAP + 2;
|
|
241
|
+
const config = chainConfig(chainLength);
|
|
242
|
+
const accessControlledInclude = await buildIncludeWithAccessControl(config.lists.L0.fields, { session: null, context: makeContext() }, config, 0, ['L0']);
|
|
243
|
+
// Outer `next` (hop 1) + nestedInclude(HOPS_AT_CAP) (HOPS_AT_CAP more) = HOPS_AT_CAP + 1 hops.
|
|
244
|
+
const callerInclude = { next: nestedInclude(HOPS_AT_CAP) };
|
|
245
|
+
expect(() => mergeIncludeWithAccessControl(callerInclude, accessControlledInclude, config.lists.L0.fields, config, 'L0')).toThrow(AccessScopeDepthExceededError);
|
|
246
|
+
});
|
|
247
|
+
it('still row-scopes a caller include one level shallower than the cap', async () => {
|
|
248
|
+
const chainLength = HOPS_AT_CAP + 1;
|
|
249
|
+
const config = chainConfig(chainLength);
|
|
250
|
+
const accessControlledInclude = await buildIncludeWithAccessControl(config.lists.L0.fields, { session: null, context: makeContext() }, config, 0, ['L0']);
|
|
251
|
+
// Outer `next` (hop 1) + nestedInclude(HOPS_AT_CAP - 1) = HOPS_AT_CAP hops total — right at the boundary.
|
|
252
|
+
const callerInclude = { next: nestedInclude(HOPS_AT_CAP - 1) };
|
|
253
|
+
// Must NOT throw — this depth is within what the engine can scope.
|
|
254
|
+
const merged = mergeIncludeWithAccessControl(callerInclude, accessControlledInclude, config.lists.L0.fields, config, 'L0');
|
|
255
|
+
expect(includeDepth(merged)).toBe(HOPS_AT_CAP);
|
|
256
|
+
// The last list in the chain (at the boundary) is genuinely row-scoped —
|
|
257
|
+
// not just present without a throw.
|
|
258
|
+
expect(whereAtHop(merged, HOPS_AT_CAP)).toEqual({ ownerId: { equals: `L${HOPS_AT_CAP}` } });
|
|
259
|
+
});
|
|
260
|
+
it('does not throw for an ordinary read with no caller include, even on a deep schema', async () => {
|
|
261
|
+
// No caller include at all — the auto-include just stops at the cap
|
|
262
|
+
// silently. This must never throw; only an EXPLICIT caller selection past
|
|
263
|
+
// the cap is a denial.
|
|
264
|
+
const chainLength = HOPS_AT_CAP + 3;
|
|
265
|
+
const config = chainConfig(chainLength);
|
|
266
|
+
const result = await buildIncludeWithAccessControl(config.lists.L0.fields, { session: null, context: makeContext() }, config, 0, ['L0']);
|
|
267
|
+
expect(() => toPrismaInclude(result)).not.toThrow();
|
|
268
|
+
const include = toPrismaInclude(result);
|
|
269
|
+
expect(includeDepth(include)).toBeLessThanOrEqual(HOPS_AT_CAP);
|
|
270
|
+
});
|
|
271
|
+
it('a list with no relationships still passes the caller include through unchanged', async () => {
|
|
272
|
+
const config = {
|
|
273
|
+
db: { provider: 'sqlite' },
|
|
274
|
+
lists: {
|
|
275
|
+
Leaf: {
|
|
276
|
+
fields: { name: { type: 'text' } },
|
|
277
|
+
access: { operation: { query: () => true } },
|
|
278
|
+
},
|
|
279
|
+
},
|
|
280
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- minimal config for unit test
|
|
281
|
+
};
|
|
282
|
+
const accessControlledInclude = await buildIncludeWithAccessControl(config.lists.Leaf.fields, { session: null, context: makeContext() }, config, 0, ['Leaf']);
|
|
283
|
+
expect(accessControlledInclude).toEqual({ kind: 'nothing-to-scope' });
|
|
284
|
+
// An arbitrary (non-declared-relationship) key passed through unchanged —
|
|
285
|
+
// access control does not govern keys it doesn't recognize as relationships.
|
|
286
|
+
const merged = mergeIncludeWithAccessControl({ someUnrelatedKey: true }, accessControlledInclude, config.lists.Leaf.fields, config, 'Leaf');
|
|
287
|
+
expect(merged).toEqual({ someUnrelatedKey: true });
|
|
288
|
+
});
|
|
289
|
+
});
|
|
290
|
+
/**
|
|
291
|
+
* Regression coverage for the resolveOutput/virtual-field trigger of #830: a
|
|
292
|
+
* read issued from inside a resolveOutput hook used to lose relation row
|
|
293
|
+
* scoping ENTIRELY (whole-object passthrough) rather than scoping the
|
|
294
|
+
* immediate relation and simply not auto-expanding further. The loop guard
|
|
295
|
+
* that motivated the original passthrough (hooks making DB queries that
|
|
296
|
+
* include relationships back to the same entity) must still hold.
|
|
297
|
+
*/
|
|
298
|
+
describe('buildIncludeWithAccessControl — inside a resolveOutput context', () => {
|
|
299
|
+
it('scopes the immediate relation with its access where but does not auto-expand nested relations', async () => {
|
|
300
|
+
const config = chainConfig(4); // L0 → L1 → L2 → L3
|
|
301
|
+
config.lists.L1.access = { operation: { query: () => ({ tenantId: { equals: 'mine' } }) } };
|
|
302
|
+
const result = await buildIncludeWithAccessControl(config.lists.L0.fields, { session: null, context: makeContext(1) }, // depth > 0 → inside resolveOutput
|
|
303
|
+
config, 0, ['L0']);
|
|
304
|
+
expect(result.kind).toBe('scoped');
|
|
305
|
+
const include = toPrismaInclude(result);
|
|
306
|
+
// L1's own access `where` is applied...
|
|
307
|
+
expect(include).toEqual({ next: { where: { tenantId: { equals: 'mine' } } } });
|
|
308
|
+
// ...but L1's own nested relations (`next` → L2) are NOT auto-included.
|
|
309
|
+
expect(includeDepth(include)).toBe(1);
|
|
310
|
+
});
|
|
311
|
+
it('terminates on a self-referential relationship instead of looping', async () => {
|
|
312
|
+
const config = {
|
|
313
|
+
db: { provider: 'sqlite' },
|
|
314
|
+
lists: {
|
|
315
|
+
Category: {
|
|
316
|
+
fields: {
|
|
317
|
+
name: { type: 'text' },
|
|
318
|
+
parent: rel('Category.children'),
|
|
319
|
+
children: rel('Category.parent', true),
|
|
320
|
+
},
|
|
321
|
+
access: { operation: { query: () => true } },
|
|
322
|
+
},
|
|
323
|
+
},
|
|
324
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- minimal config for unit test
|
|
325
|
+
};
|
|
326
|
+
const result = await buildIncludeWithAccessControl(config.lists.Category.fields, { session: null, context: makeContext(1) }, config, 0, ['Category']);
|
|
327
|
+
const include = toPrismaInclude(result);
|
|
328
|
+
expect(include).toEqual({ parent: true, children: true });
|
|
329
|
+
});
|
|
330
|
+
});
|
|
166
331
|
//# sourceMappingURL=access-filter.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"access-filter.test.js","sourceRoot":"","sources":["../../src/access/access-filter.test.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"access-filter.test.js","sourceRoot":"","sources":["../../src/access/access-filter.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Maximum nesting depth of relation `include`s that the Access Filter
|
|
3
|
+
* (`buildIncludeWithAccessControl`) will auto-scope on a read.
|
|
4
|
+
*
|
|
5
|
+
* Security implication: this is an access-control boundary, not just a cost
|
|
6
|
+
* bound. Past this depth the engine cannot compute a row/field scope for a
|
|
7
|
+
* relation, so a caller-supplied `include` naming a relation at or beyond it
|
|
8
|
+
* must be treated as a denial (see `AccessScopeDepthExceededError`) rather
|
|
9
|
+
* than passed through unscoped — see ADR-0022 and issue #830.
|
|
10
|
+
*/
|
|
11
|
+
export declare const READ_INCLUDE_MAX_DEPTH = 5;
|
|
12
|
+
/**
|
|
13
|
+
* Maximum length of the resolve chain — the ordered sequence of `resolveOutput`
|
|
14
|
+
* hooks a read has entered, each entry extended by a hook that issues its own
|
|
15
|
+
* read (see `_resolveOutputChain` on `AccessContext`).
|
|
16
|
+
*
|
|
17
|
+
* This is a COST limit, not an access-control boundary: an acyclic chain
|
|
18
|
+
* genuinely can exceed it and still be correct (e.g. a virtual `Order.total`
|
|
19
|
+
* reading a virtual `LineItem.subtotal` reading further virtuals), so
|
|
20
|
+
* exceeding it omits the field and emits a single `console.warn` rather than
|
|
21
|
+
* throwing. Termination itself is guaranteed by the separate cycle guard,
|
|
22
|
+
* which refuses to re-enter a `(list, field)` pair already on the chain
|
|
23
|
+
* regardless of this cap. See ADR-0023.
|
|
24
|
+
*/
|
|
25
|
+
export declare const RESOLVE_CHAIN_MAX_LENGTH = 5;
|
|
26
|
+
//# sourceMappingURL=depth-limits.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"depth-limits.d.ts","sourceRoot":"","sources":["../../src/access/depth-limits.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,eAAO,MAAM,sBAAsB,IAAI,CAAA;AAEvC;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,wBAAwB,IAAI,CAAA"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Maximum nesting depth of relation `include`s that the Access Filter
|
|
3
|
+
* (`buildIncludeWithAccessControl`) will auto-scope on a read.
|
|
4
|
+
*
|
|
5
|
+
* Security implication: this is an access-control boundary, not just a cost
|
|
6
|
+
* bound. Past this depth the engine cannot compute a row/field scope for a
|
|
7
|
+
* relation, so a caller-supplied `include` naming a relation at or beyond it
|
|
8
|
+
* must be treated as a denial (see `AccessScopeDepthExceededError`) rather
|
|
9
|
+
* than passed through unscoped — see ADR-0022 and issue #830.
|
|
10
|
+
*/
|
|
11
|
+
export const READ_INCLUDE_MAX_DEPTH = 5;
|
|
12
|
+
/**
|
|
13
|
+
* Maximum length of the resolve chain — the ordered sequence of `resolveOutput`
|
|
14
|
+
* hooks a read has entered, each entry extended by a hook that issues its own
|
|
15
|
+
* read (see `_resolveOutputChain` on `AccessContext`).
|
|
16
|
+
*
|
|
17
|
+
* This is a COST limit, not an access-control boundary: an acyclic chain
|
|
18
|
+
* genuinely can exceed it and still be correct (e.g. a virtual `Order.total`
|
|
19
|
+
* reading a virtual `LineItem.subtotal` reading further virtuals), so
|
|
20
|
+
* exceeding it omits the field and emits a single `console.warn` rather than
|
|
21
|
+
* throwing. Termination itself is guaranteed by the separate cycle guard,
|
|
22
|
+
* which refuses to re-enter a `(list, field)` pair already on the chain
|
|
23
|
+
* regardless of this cap. See ADR-0023.
|
|
24
|
+
*/
|
|
25
|
+
export const RESOLVE_CHAIN_MAX_LENGTH = 5;
|
|
26
|
+
//# sourceMappingURL=depth-limits.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"depth-limits.js","sourceRoot":"","sources":["../../src/access/depth-limits.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAA;AAEvC;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAA"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thrown when a caller-supplied `include` names a relation nested deeper than
|
|
3
|
+
* the Access Filter can scope (see `READ_INCLUDE_MAX_DEPTH`). Deliberately
|
|
4
|
+
* distinct from `ValidationError`: this is not bad user input, it is the
|
|
5
|
+
* engine refusing to return data it cannot prove is row/field scoped. Code
|
|
6
|
+
* that catches `ValidationError` to report form errors must not silently
|
|
7
|
+
* swallow this.
|
|
8
|
+
*
|
|
9
|
+
* Only an explicit caller selection past the depth cap triggers this — the
|
|
10
|
+
* auto-include silently stopping at the cap (no caller `include` involved)
|
|
11
|
+
* never throws. See ADR-0022 and issue #830.
|
|
12
|
+
*/
|
|
13
|
+
export declare class AccessScopeDepthExceededError extends Error {
|
|
14
|
+
listKey: string;
|
|
15
|
+
fieldKey: string;
|
|
16
|
+
depth: number;
|
|
17
|
+
constructor(listKey: string, fieldKey: string, depth: number);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Thrown when a `resolveOutput` hook re-enters a `(list, field)` pair already
|
|
21
|
+
* on its own resolve chain — a hook whose own read (directly or transitively)
|
|
22
|
+
* comes back around to itself. Deliberately distinct from `ValidationError`
|
|
23
|
+
* (same reasoning as `AccessScopeDepthExceededError`): this is not bad user
|
|
24
|
+
* input, it is the engine refusing to run a hook chain that cannot terminate.
|
|
25
|
+
*
|
|
26
|
+
* This is a loud failure, not a Silent one, on purpose: a repeated pair never
|
|
27
|
+
* terminated before this guard existed, so no working application can depend
|
|
28
|
+
* on the old (hanging) behaviour, and staying silent here would return
|
|
29
|
+
* `undefined` for a field with nothing in the logs to explain why. Contrast
|
|
30
|
+
* with exceeding `RESOLVE_CHAIN_MAX_LENGTH`, which can happen on a chain that
|
|
31
|
+
* would otherwise terminate correctly and therefore only warns. See ADR-0023.
|
|
32
|
+
*/
|
|
33
|
+
export declare class ResolveOutputCycleError extends Error {
|
|
34
|
+
chain: readonly {
|
|
35
|
+
listKey: string;
|
|
36
|
+
fieldKey: string;
|
|
37
|
+
}[];
|
|
38
|
+
constructor(chain: readonly {
|
|
39
|
+
listKey: string;
|
|
40
|
+
fieldKey: string;
|
|
41
|
+
}[]);
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/access/errors.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AACH,qBAAa,6BAA8B,SAAQ,KAAK;IAC/C,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IAEpB,YAAY,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAW3D;CACF;AAED;;;;;;;;;;;;;GAaG;AACH,qBAAa,uBAAwB,SAAQ,KAAK;IACzC,KAAK,EAAE,SAAS;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IAE9D,YAAY,KAAK,EAAE,SAAS;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,EAAE,EAUlE;CACF"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { READ_INCLUDE_MAX_DEPTH } from './depth-limits.js';
|
|
2
|
+
/**
|
|
3
|
+
* Thrown when a caller-supplied `include` names a relation nested deeper than
|
|
4
|
+
* the Access Filter can scope (see `READ_INCLUDE_MAX_DEPTH`). Deliberately
|
|
5
|
+
* distinct from `ValidationError`: this is not bad user input, it is the
|
|
6
|
+
* engine refusing to return data it cannot prove is row/field scoped. Code
|
|
7
|
+
* that catches `ValidationError` to report form errors must not silently
|
|
8
|
+
* swallow this.
|
|
9
|
+
*
|
|
10
|
+
* Only an explicit caller selection past the depth cap triggers this — the
|
|
11
|
+
* auto-include silently stopping at the cap (no caller `include` involved)
|
|
12
|
+
* never throws. See ADR-0022 and issue #830.
|
|
13
|
+
*/
|
|
14
|
+
export class AccessScopeDepthExceededError extends Error {
|
|
15
|
+
listKey;
|
|
16
|
+
fieldKey;
|
|
17
|
+
depth;
|
|
18
|
+
constructor(listKey, fieldKey, depth) {
|
|
19
|
+
super(`Cannot compute an access scope for "${listKey}.${fieldKey}" at include depth ${depth}: ` +
|
|
20
|
+
`this exceeds the Access Filter's maximum read-include depth (${READ_INCLUDE_MAX_DEPTH}). ` +
|
|
21
|
+
`A caller-supplied include this deep cannot be row- and field-scoped, so the read is denied ` +
|
|
22
|
+
`rather than returned unscoped. Restructure the query to fetch this relation separately.`);
|
|
23
|
+
this.name = 'AccessScopeDepthExceededError';
|
|
24
|
+
this.listKey = listKey;
|
|
25
|
+
this.fieldKey = fieldKey;
|
|
26
|
+
this.depth = depth;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Thrown when a `resolveOutput` hook re-enters a `(list, field)` pair already
|
|
31
|
+
* on its own resolve chain — a hook whose own read (directly or transitively)
|
|
32
|
+
* comes back around to itself. Deliberately distinct from `ValidationError`
|
|
33
|
+
* (same reasoning as `AccessScopeDepthExceededError`): this is not bad user
|
|
34
|
+
* input, it is the engine refusing to run a hook chain that cannot terminate.
|
|
35
|
+
*
|
|
36
|
+
* This is a loud failure, not a Silent one, on purpose: a repeated pair never
|
|
37
|
+
* terminated before this guard existed, so no working application can depend
|
|
38
|
+
* on the old (hanging) behaviour, and staying silent here would return
|
|
39
|
+
* `undefined` for a field with nothing in the logs to explain why. Contrast
|
|
40
|
+
* with exceeding `RESOLVE_CHAIN_MAX_LENGTH`, which can happen on a chain that
|
|
41
|
+
* would otherwise terminate correctly and therefore only warns. See ADR-0023.
|
|
42
|
+
*/
|
|
43
|
+
export class ResolveOutputCycleError extends Error {
|
|
44
|
+
chain;
|
|
45
|
+
constructor(chain) {
|
|
46
|
+
const path = chain.map((link) => `${link.listKey}.${link.fieldKey}`).join(' → ');
|
|
47
|
+
super(`resolveOutput cycle detected: ${path}. A hook that re-enters a (list, field) pair ` +
|
|
48
|
+
`already on its own resolve chain cannot terminate, so the read is refused rather than ` +
|
|
49
|
+
`left to recurse until the process runs out of memory. Restructure the hooks so the read ` +
|
|
50
|
+
`does not loop back into itself.`);
|
|
51
|
+
this.name = 'ResolveOutputCycleError';
|
|
52
|
+
this.chain = chain;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/access/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAA;AAE1D;;;;;;;;;;;GAWG;AACH,MAAM,OAAO,6BAA8B,SAAQ,KAAK;IAC/C,OAAO,CAAQ;IACf,QAAQ,CAAQ;IAChB,KAAK,CAAQ;IAEpB,YAAY,OAAe,EAAE,QAAgB,EAAE,KAAa;QAC1D,KAAK,CACH,uCAAuC,OAAO,IAAI,QAAQ,sBAAsB,KAAK,IAAI;YACvF,gEAAgE,sBAAsB,KAAK;YAC3F,6FAA6F;YAC7F,yFAAyF,CAC5F,CAAA;QACD,IAAI,CAAC,IAAI,GAAG,+BAA+B,CAAA;QAC3C,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;QACtB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAA;QACxB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAA;IACpB,CAAC;CACF;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,OAAO,uBAAwB,SAAQ,KAAK;IACzC,KAAK,CAAkD;IAE9D,YAAY,KAAuD;QACjE,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QAChF,KAAK,CACH,iCAAiC,IAAI,+CAA+C;YAClF,wFAAwF;YACxF,0FAA0F;YAC1F,iCAAiC,CACpC,CAAA;QACD,IAAI,CAAC,IAAI,GAAG,yBAAyB,CAAA;QACrC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAA;IACpB,CAAC;CACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"field-visibility.d.ts","sourceRoot":"","sources":["../../src/access/field-visibility.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;
|
|
1
|
+
{"version":3,"file":"field-visibility.d.ts","sourceRoot":"","sources":["../../src/access/field-visibility.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAwKrE;;;GAGG;AACH,wBAAsB,oBAAoB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC1E,IAAI,EAAE,CAAC,EACP,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACzC,IAAI,EAAE;IACJ,OAAO,EAAE,OAAO,GAAG,IAAI,CAAA;IACvB,OAAO,EAAE,aAAa,GAAG;QAAE,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,CAAA;CAC/C,EACD,MAAM,CAAC,EAAE,cAAc,EACvB,KAAK,GAAE,MAAU,EACjB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAiKrB"}
|
|
@@ -1,5 +1,47 @@
|
|
|
1
1
|
import { getRelatedListConfig } from './engine.js';
|
|
2
2
|
import { checkFieldAccess } from './field-access.js';
|
|
3
|
+
import { RESOLVE_CHAIN_MAX_LENGTH } from './depth-limits.js';
|
|
4
|
+
import { ResolveOutputCycleError } from './errors.js';
|
|
5
|
+
// NOTE: `context/index.ts` imports `filterReadableFields` from this module
|
|
6
|
+
// (via the `access/index.ts` barrel) — this is an intentional cyclic
|
|
7
|
+
// dependency, the same shape and for the same reason as the one documented in
|
|
8
|
+
// `context/write-pipeline.ts`. `buildDbDelegate` is only INVOKED when a
|
|
9
|
+
// `resolveOutput` hook actually runs (never during module evaluation), so by
|
|
10
|
+
// the time it runs the export is fully initialised.
|
|
11
|
+
import { buildDbDelegate } from '../context/index.js';
|
|
12
|
+
/**
|
|
13
|
+
* Derive the context passed to a single `resolveOutput` hook invocation: a
|
|
14
|
+
* NEW context object whose `_resolveOutputChain` extends the caller's chain
|
|
15
|
+
* with this hook's own `(list, field)` link. The chain is never mutated in
|
|
16
|
+
* place — this is what lets concurrent hook invocations (e.g. sibling rows in
|
|
17
|
+
* a to-many relation, filtered via `Promise.all`) each see their own chain
|
|
18
|
+
* rather than racing on one shared value (ADR-0023).
|
|
19
|
+
*
|
|
20
|
+
* A plain `{ ...context, _resolveOutputChain }` spread is not enough on its
|
|
21
|
+
* own: `context.db`'s operations capture their `context` at construction
|
|
22
|
+
* (see `populateDbDelegate`), so a hook that calls `context.db.x.findMany(…)`
|
|
23
|
+
* would otherwise reach the ORIGINAL closures — bound to the ORIGINAL
|
|
24
|
+
* context — and its read would silently fall back to the un-extended chain,
|
|
25
|
+
* defeating the cycle guard entirely. Rebuilding `db` via `buildDbDelegate`
|
|
26
|
+
* against the derived context is what makes a hook-issued read's own nested
|
|
27
|
+
* hooks actually observe the extended chain.
|
|
28
|
+
*
|
|
29
|
+
* `config` is required to rebuild `db`; callers that cannot supply one (e.g. a
|
|
30
|
+
* narrow unit test exercising field access in isolation) still get a correct
|
|
31
|
+
* chain for THIS hook's own cycle/cap check, but a read that hook issues
|
|
32
|
+
* would not carry the chain any further — those callers are not exercising
|
|
33
|
+
* the read pipeline, so there is nothing for it to reach.
|
|
34
|
+
*/
|
|
35
|
+
function deriveResolveOutputContext(context, link, config) {
|
|
36
|
+
const derived = {
|
|
37
|
+
...context,
|
|
38
|
+
_resolveOutputChain: [...context._resolveOutputChain, link],
|
|
39
|
+
};
|
|
40
|
+
if (config) {
|
|
41
|
+
derived.db = buildDbDelegate(config, context.prisma, derived);
|
|
42
|
+
}
|
|
43
|
+
return derived;
|
|
44
|
+
}
|
|
3
45
|
/**
|
|
4
46
|
* The core Field Visibility step for a single field: check read access and, if
|
|
5
47
|
* granted, produce the output value by running any `resolveOutput` hook.
|
|
@@ -15,7 +57,7 @@ import { checkFieldAccess } from './field-access.js';
|
|
|
15
57
|
* see the already-filtered output so they can read sibling fields).
|
|
16
58
|
*/
|
|
17
59
|
async function resolveReadableFieldValue(params) {
|
|
18
|
-
const { fieldConfig, fieldName, value, accessItem, hookItem, listKey, args } = params;
|
|
60
|
+
const { fieldConfig, fieldName, value, accessItem, hookItem, listKey, args, config } = params;
|
|
19
61
|
// Check field access (checkFieldAccess already handles sudo mode)
|
|
20
62
|
const canRead = await checkFieldAccess(fieldConfig?.access, 'read', {
|
|
21
63
|
...args,
|
|
@@ -29,24 +71,35 @@ async function resolveReadableFieldValue(params) {
|
|
|
29
71
|
// Cast to runtime type for generic execution
|
|
30
72
|
// At runtime, the hook will receive the correct value type for the field
|
|
31
73
|
const hook = fieldConfig.hooks.resolveOutput;
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
fieldName,
|
|
41
|
-
listKey,
|
|
42
|
-
item: hookItem,
|
|
43
|
-
context: args.context,
|
|
44
|
-
}));
|
|
45
|
-
return { readable: true, value: resolved };
|
|
74
|
+
const link = { listKey, fieldKey: fieldName };
|
|
75
|
+
const chain = args.context._resolveOutputChain;
|
|
76
|
+
// Cycle guard: a hook that would re-enter a (list, field) pair already on
|
|
77
|
+
// its own chain cannot terminate — refuse loudly rather than recurse
|
|
78
|
+
// until the process runs out of memory (issue #844, ADR-0023).
|
|
79
|
+
const alreadyOnChain = chain.some((entry) => entry.listKey === link.listKey && entry.fieldKey === link.fieldKey);
|
|
80
|
+
if (alreadyOnChain) {
|
|
81
|
+
throw new ResolveOutputCycleError([...chain, link]);
|
|
46
82
|
}
|
|
47
|
-
|
|
48
|
-
|
|
83
|
+
// Cost cap: a chain this long is refused only as a cost limit, never a
|
|
84
|
+
// correctness one — an acyclic chain that works today can legitimately
|
|
85
|
+
// reach this. Omit the field and warn instead of throwing.
|
|
86
|
+
if (chain.length >= RESOLVE_CHAIN_MAX_LENGTH) {
|
|
87
|
+
const path = [...chain, link].map((entry) => `${entry.listKey}.${entry.fieldKey}`).join(' → ');
|
|
88
|
+
console.warn(`resolveOutput: omitting "${listKey}.${fieldName}" — its resolve chain exceeded ` +
|
|
89
|
+
`RESOLVE_CHAIN_MAX_LENGTH (${RESOLVE_CHAIN_MAX_LENGTH}): ${path}. This is a cost limit, ` +
|
|
90
|
+
`not an access denial.`);
|
|
91
|
+
return { readable: false };
|
|
49
92
|
}
|
|
93
|
+
// Use Promise.resolve() to handle both sync and async hooks
|
|
94
|
+
const resolved = await Promise.resolve(hook({
|
|
95
|
+
value,
|
|
96
|
+
operation: 'query',
|
|
97
|
+
fieldName,
|
|
98
|
+
listKey,
|
|
99
|
+
item: hookItem,
|
|
100
|
+
context: deriveResolveOutputContext(args.context, link, config),
|
|
101
|
+
}));
|
|
102
|
+
return { readable: true, value: resolved };
|
|
50
103
|
}
|
|
51
104
|
return { readable: true, value };
|
|
52
105
|
}
|
|
@@ -56,7 +109,6 @@ async function resolveReadableFieldValue(params) {
|
|
|
56
109
|
*/
|
|
57
110
|
export async function filterReadableFields(item, fieldConfigs, args, config, depth = 0, listKey) {
|
|
58
111
|
const filtered = {};
|
|
59
|
-
const MAX_DEPTH = 5; // Prevent infinite recursion
|
|
60
112
|
// Multi-column fields (e.g. storage image()/file() in Keystone-parity mode)
|
|
61
113
|
// back several physical columns rather than one. Before the per-field pass,
|
|
62
114
|
// assemble each such field's logical value from its raw columns and remove the
|
|
@@ -91,13 +143,21 @@ export async function filterReadableFields(item, fieldConfigs, args, config, dep
|
|
|
91
143
|
// Handle relationship fields - recursively filter fields within related items
|
|
92
144
|
// Note: Access control filtering is now done at database level via buildIncludeWithAccessControl
|
|
93
145
|
// This only handles field-level access (hiding sensitive fields)
|
|
146
|
+
//
|
|
147
|
+
// Deliberately uncapped: the row/relation scoping in access-filter.ts bounds
|
|
148
|
+
// what gets FETCHED (a caller include past its depth cap is now a denial,
|
|
149
|
+
// not a passthrough — see ADR-0022), so by the time a result reaches this
|
|
150
|
+
// function it is already a finite, acyclic tree whose depth was decided at
|
|
151
|
+
// the pre-query phase. Capping recursion again here independently of that
|
|
152
|
+
// cap used to let a relation be scoped correctly at the DB level while
|
|
153
|
+
// still returning with unfiltered fields past this function's own,
|
|
154
|
+
// separately-tracked limit (issue #830).
|
|
94
155
|
if (config &&
|
|
95
156
|
fieldConfig?.type === 'relationship' &&
|
|
96
157
|
'ref' in fieldConfig &&
|
|
97
158
|
fieldConfig.ref &&
|
|
98
159
|
value !== null &&
|
|
99
|
-
value !== undefined
|
|
100
|
-
depth < MAX_DEPTH) {
|
|
160
|
+
value !== undefined) {
|
|
101
161
|
// Gate the relationship on read access before recursing.
|
|
102
162
|
const canRead = await checkFieldAccess(fieldConfig?.access, 'read', {
|
|
103
163
|
...args,
|
|
@@ -135,6 +195,7 @@ export async function filterReadableFields(item, fieldConfigs, args, config, dep
|
|
|
135
195
|
hookItem: workingItem,
|
|
136
196
|
listKey,
|
|
137
197
|
args,
|
|
198
|
+
config,
|
|
138
199
|
});
|
|
139
200
|
if (result.readable) {
|
|
140
201
|
filtered[fieldName] = result.value;
|
|
@@ -168,6 +229,7 @@ export async function filterReadableFields(item, fieldConfigs, args, config, dep
|
|
|
168
229
|
hookItem: filtered,
|
|
169
230
|
listKey,
|
|
170
231
|
args,
|
|
232
|
+
config,
|
|
171
233
|
});
|
|
172
234
|
if (result.readable) {
|
|
173
235
|
filtered[fieldName] = result.value;
|