@opensaas/stack-core 0.30.0 → 0.31.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 (127) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +412 -0
  3. package/dist/access/access-filter.d.ts.map +1 -1
  4. package/dist/access/access-filter.js +14 -1
  5. package/dist/access/access-filter.js.map +1 -1
  6. package/dist/access/access-filter.test.js +50 -0
  7. package/dist/access/access-filter.test.js.map +1 -1
  8. package/dist/access/field-access.js +6 -6
  9. package/dist/access/field-access.js.map +1 -1
  10. package/dist/access/multi-column-read-write.test.js +46 -12
  11. package/dist/access/multi-column-read-write.test.js.map +1 -1
  12. package/dist/access/relationship-count.d.ts +60 -0
  13. package/dist/access/relationship-count.d.ts.map +1 -0
  14. package/dist/access/relationship-count.js +233 -0
  15. package/dist/access/relationship-count.js.map +1 -0
  16. package/dist/access/relationship-count.test.d.ts +2 -0
  17. package/dist/access/relationship-count.test.d.ts.map +1 -0
  18. package/dist/access/relationship-count.test.js +185 -0
  19. package/dist/access/relationship-count.test.js.map +1 -0
  20. package/dist/access/relationship-label-filter.d.ts +45 -0
  21. package/dist/access/relationship-label-filter.d.ts.map +1 -0
  22. package/dist/access/relationship-label-filter.js +93 -0
  23. package/dist/access/relationship-label-filter.js.map +1 -0
  24. package/dist/access/relationship-label-filter.test.d.ts +2 -0
  25. package/dist/access/relationship-label-filter.test.d.ts.map +1 -0
  26. package/dist/access/relationship-label-filter.test.js +126 -0
  27. package/dist/access/relationship-label-filter.test.js.map +1 -0
  28. package/dist/config/index.d.ts +1 -1
  29. package/dist/config/index.d.ts.map +1 -1
  30. package/dist/config/nav-count.d.ts +34 -0
  31. package/dist/config/nav-count.d.ts.map +1 -0
  32. package/dist/config/nav-count.js +71 -0
  33. package/dist/config/nav-count.js.map +1 -0
  34. package/dist/config/types.d.ts +305 -4
  35. package/dist/config/types.d.ts.map +1 -1
  36. package/dist/context/hook-pipeline.d.ts.map +1 -1
  37. package/dist/context/hook-pipeline.js +11 -1
  38. package/dist/context/hook-pipeline.js.map +1 -1
  39. package/dist/context/index.d.ts +28 -0
  40. package/dist/context/index.d.ts.map +1 -1
  41. package/dist/context/index.js +205 -0
  42. package/dist/context/index.js.map +1 -1
  43. package/dist/context/nested-operations.d.ts.map +1 -1
  44. package/dist/context/nested-operations.js +7 -1
  45. package/dist/context/nested-operations.js.map +1 -1
  46. package/dist/extend.d.ts +1 -0
  47. package/dist/extend.d.ts.map +1 -1
  48. package/dist/fields/index.d.ts +1 -1
  49. package/dist/fields/index.d.ts.map +1 -1
  50. package/dist/fields/index.js +166 -0
  51. package/dist/fields/index.js.map +1 -1
  52. package/dist/filter/collect.d.ts +32 -0
  53. package/dist/filter/collect.d.ts.map +1 -0
  54. package/dist/filter/collect.js +60 -0
  55. package/dist/filter/collect.js.map +1 -0
  56. package/dist/filter/filter.test.d.ts +2 -0
  57. package/dist/filter/filter.test.d.ts.map +1 -0
  58. package/dist/filter/filter.test.js +348 -0
  59. package/dist/filter/filter.test.js.map +1 -0
  60. package/dist/filter/index.d.ts +7 -0
  61. package/dist/filter/index.d.ts.map +1 -0
  62. package/dist/filter/index.js +16 -0
  63. package/dist/filter/index.js.map +1 -0
  64. package/dist/filter/map.d.ts +18 -0
  65. package/dist/filter/map.d.ts.map +1 -0
  66. package/dist/filter/map.js +60 -0
  67. package/dist/filter/map.js.map +1 -0
  68. package/dist/filter/parse.d.ts +33 -0
  69. package/dist/filter/parse.d.ts.map +1 -0
  70. package/dist/filter/parse.js +103 -0
  71. package/dist/filter/parse.js.map +1 -0
  72. package/dist/filter/serialize.d.ts +25 -0
  73. package/dist/filter/serialize.d.ts.map +1 -0
  74. package/dist/filter/serialize.js +68 -0
  75. package/dist/filter/serialize.js.map +1 -0
  76. package/dist/filter/serialize.test.d.ts +2 -0
  77. package/dist/filter/serialize.test.d.ts.map +1 -0
  78. package/dist/filter/serialize.test.js +83 -0
  79. package/dist/filter/serialize.test.js.map +1 -0
  80. package/dist/filter/types.d.ts +122 -0
  81. package/dist/filter/types.d.ts.map +1 -0
  82. package/dist/filter/types.js +24 -0
  83. package/dist/filter/types.js.map +1 -0
  84. package/dist/hooks/index.d.ts +30 -0
  85. package/dist/hooks/index.d.ts.map +1 -1
  86. package/dist/hooks/index.js +79 -59
  87. package/dist/hooks/index.js.map +1 -1
  88. package/dist/index.d.ts +6 -1
  89. package/dist/index.d.ts.map +1 -1
  90. package/dist/index.js +19 -0
  91. package/dist/index.js.map +1 -1
  92. package/dist/internal.d.ts +1 -0
  93. package/dist/internal.d.ts.map +1 -1
  94. package/dist/internal.js +4 -0
  95. package/dist/internal.js.map +1 -1
  96. package/package.json +1 -1
  97. package/src/access/access-filter.test.ts +79 -0
  98. package/src/access/access-filter.ts +15 -4
  99. package/src/access/field-access.ts +6 -6
  100. package/src/access/multi-column-read-write.test.ts +68 -19
  101. package/src/access/relationship-count.test.ts +269 -0
  102. package/src/access/relationship-count.ts +311 -0
  103. package/src/access/relationship-label-filter.test.ts +177 -0
  104. package/src/access/relationship-label-filter.ts +140 -0
  105. package/src/config/index.ts +6 -0
  106. package/src/config/nav-count.ts +85 -0
  107. package/src/config/types.ts +319 -1
  108. package/src/context/hook-pipeline.ts +19 -0
  109. package/src/context/index.ts +285 -3
  110. package/src/context/nested-operations.ts +22 -0
  111. package/src/extend.ts +9 -0
  112. package/src/fields/index.ts +168 -0
  113. package/src/filter/collect.ts +72 -0
  114. package/src/filter/filter.test.ts +400 -0
  115. package/src/filter/index.ts +25 -0
  116. package/src/filter/map.ts +68 -0
  117. package/src/filter/parse.ts +106 -0
  118. package/src/filter/serialize.test.ts +115 -0
  119. package/src/filter/serialize.ts +75 -0
  120. package/src/filter/types.ts +120 -0
  121. package/src/hooks/index.ts +87 -57
  122. package/src/index.ts +54 -0
  123. package/src/internal.ts +5 -0
  124. package/tests/context.test.ts +690 -0
  125. package/tests/multi-column-validation-ordering.test.ts +305 -0
  126. package/tests/nav-count.test.ts +189 -0
  127. package/tsconfig.tsbuildinfo +1 -1
@@ -1,12 +1,19 @@
1
1
  import { describe, it, expect } from 'vitest';
2
2
  import { filterReadableFields } from './field-visibility.js';
3
- import { executeFieldResolveInputHooks } from '../hooks/index.js';
3
+ import { executeFieldResolveInputHooks, splitMultiColumnFields } from '../hooks/index.js';
4
4
  /**
5
5
  * Generic core wiring for multi-column fields (the contract storage
6
6
  * image()/file() use in Keystone-parity mode — see ADR-0006). These tests are
7
7
  * field-agnostic: they assert that ANY field implementing
8
8
  * getColumnNames/assembleColumns/splitColumns is assembled on read (raw columns
9
9
  * stripped) and split on write.
10
+ *
11
+ * The write side is split across two phases (#789): `executeFieldResolveInputHooks`
12
+ * (Phase 1.5) resolves the field's value under its LOGICAL key only — no split —
13
+ * so that validation (Phase 2-3, not exercised by these field-agnostic unit
14
+ * tests; see the Hook Pipeline / Write Pipeline test suites) runs against the
15
+ * logical value first. `splitMultiColumnFields` (Phase 4) then replaces the
16
+ * logical key with its physical per-part columns, AFTER validation has passed.
10
17
  */
11
18
  // A minimal multi-column field: two physical columns `m_url` and `m_size`
12
19
  // assembled into `{ url, size }` and split back. Optionally carries field-level
@@ -77,24 +84,51 @@ describe('multi-column read assembly (filterReadableFields)', () => {
77
84
  expect('media' in result).toBe(false);
78
85
  });
79
86
  });
80
- describe('multi-column write split (executeFieldResolveInputHooks)', () => {
87
+ describe('multi-column resolveInput (executeFieldResolveInputHooks) does NOT split (#789)', () => {
81
88
  const fields = { media: multiColumnField() };
82
- it('splits the logical value into per-part columns and removes the logical key', async () => {
89
+ it('resolves the field under its LOGICAL key and leaves it unsplit', async () => {
83
90
  const inputData = { media: { url: 'https://x/y.jpg', size: 99 } };
84
91
  const result = await executeFieldResolveInputHooks(inputData, { ...inputData }, fields, 'create', makeContext(), 'Post');
92
+ // Still under the logical key — no split, no per-part columns yet.
93
+ expect(result).toEqual({ media: { url: 'https://x/y.jpg', size: 99 } });
94
+ expect('m_url' in result).toBe(false);
95
+ expect('m_size' in result).toBe(false);
96
+ });
97
+ it('passes an unrecognised value through unsplit, under the logical key', async () => {
98
+ // The field's own resolveInput fallback (see fixture: "unknown → return as
99
+ // is and let validation catch it") must be able to hand this value to
100
+ // validation BEFORE any split happens.
101
+ const inputData = { media: 'not-a-valid-shape' };
102
+ const result = await executeFieldResolveInputHooks(inputData, { ...inputData }, fields, 'update', makeContext(), 'Post');
103
+ expect(result).toEqual({ media: 'not-a-valid-shape' });
104
+ });
105
+ it('does not touch the field when it is absent from the write', async () => {
106
+ const inputData = { title: 'no media in payload' };
107
+ const result = await executeFieldResolveInputHooks(inputData, { ...inputData },
108
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- inline field configs
109
+ { ...fields, title: { type: 'text' } }, 'update', makeContext(), 'Post');
110
+ expect(result).toEqual({ title: 'no media in payload' });
111
+ expect('media' in result).toBe(false);
112
+ });
113
+ });
114
+ describe('multi-column write split (splitMultiColumnFields, AFTER validation — #789)', () => {
115
+ const fields = { media: multiColumnField() };
116
+ it('splits the logical value into per-part columns and removes the logical key', async () => {
117
+ const inputData = { media: { url: 'https://x/y.jpg', size: 99 } };
118
+ const result = await splitMultiColumnFields(inputData, { ...inputData }, fields, 'create', makeContext());
85
119
  expect(result).toEqual({ m_url: 'https://x/y.jpg', m_size: 99 });
86
120
  expect('media' in result).toBe(false);
87
121
  });
88
122
  it('splitting null clears all per-part columns', async () => {
89
123
  const inputData = { media: null };
90
- const result = await executeFieldResolveInputHooks(inputData, { ...inputData }, fields, 'update', makeContext(), 'Post');
124
+ const result = await splitMultiColumnFields(inputData, { ...inputData }, fields, 'update', makeContext());
91
125
  expect(result).toEqual({ m_url: null, m_size: null });
92
126
  });
93
127
  it('does not touch the columns when the logical field is absent from the write', async () => {
94
128
  const inputData = { title: 'no media in payload' };
95
- const result = await executeFieldResolveInputHooks(inputData, { ...inputData },
129
+ const result = await splitMultiColumnFields(inputData, { ...inputData },
96
130
  // eslint-disable-next-line @typescript-eslint/no-explicit-any -- inline field configs
97
- { ...fields, title: { type: 'text' } }, 'update', makeContext(), 'Post');
131
+ { ...fields, title: { type: 'text' } }, 'update', makeContext());
98
132
  expect(result).toEqual({ title: 'no media in payload' });
99
133
  expect('m_url' in result).toBe(false);
100
134
  });
@@ -103,7 +137,7 @@ describe('multi-column write split respects field-level write access', () => {
103
137
  it('does NOT write any per-part columns when update access is denied', async () => {
104
138
  const fields = { media: multiColumnField({ update: () => false }) };
105
139
  const inputData = { media: { url: 'https://x/y.jpg', size: 99 } };
106
- const result = await executeFieldResolveInputHooks(inputData, { ...inputData }, fields, 'update', makeContext(), 'Post');
140
+ const result = await splitMultiColumnFields(inputData, { ...inputData }, fields, 'update', makeContext());
107
141
  // The logical key is dropped (it is not a real column) AND none of its
108
142
  // per-part columns are written — identical to how filterWritableFields
109
143
  // drops a denied single-column field.
@@ -115,14 +149,14 @@ describe('multi-column write split respects field-level write access', () => {
115
149
  it('does NOT write any per-part columns when create access is denied', async () => {
116
150
  const fields = { media: multiColumnField({ create: () => false }) };
117
151
  const inputData = { media: { url: 'https://x/y.jpg', size: 99 } };
118
- const result = await executeFieldResolveInputHooks(inputData, { ...inputData }, fields, 'create', makeContext(), 'Post');
152
+ const result = await splitMultiColumnFields(inputData, { ...inputData }, fields, 'create', makeContext());
119
153
  expect(result).toEqual({});
120
154
  expect('m_url' in result).toBe(false);
121
155
  });
122
156
  it('still splits/writes the columns when write access is granted', async () => {
123
157
  const fields = { media: multiColumnField({ update: () => true, create: () => true }) };
124
158
  const inputData = { media: { url: 'https://x/y.jpg', size: 99 } };
125
- const result = await executeFieldResolveInputHooks(inputData, { ...inputData }, fields, 'update', makeContext(), 'Post');
159
+ const result = await splitMultiColumnFields(inputData, { ...inputData }, fields, 'update', makeContext());
126
160
  expect(result).toEqual({ m_url: 'https://x/y.jpg', m_size: 99 });
127
161
  expect('media' in result).toBe(false);
128
162
  });
@@ -130,19 +164,19 @@ describe('multi-column write split respects field-level write access', () => {
130
164
  // A field that denies `update` must still be writable on `create`.
131
165
  const fields = { media: multiColumnField({ update: () => false }) };
132
166
  const inputData = { media: { url: 'https://x/y.jpg', size: 99 } };
133
- const result = await executeFieldResolveInputHooks(inputData, { ...inputData }, fields, 'create', makeContext(), 'Post');
167
+ const result = await splitMultiColumnFields(inputData, { ...inputData }, fields, 'create', makeContext());
134
168
  expect(result).toEqual({ m_url: 'https://x/y.jpg', m_size: 99 });
135
169
  });
136
170
  it('sudo bypasses the field-access gate and still splits', async () => {
137
171
  const fields = { media: multiColumnField({ update: () => false }) };
138
172
  const inputData = { media: { url: 'https://x/y.jpg', size: 99 } };
139
- const result = await executeFieldResolveInputHooks(inputData, { ...inputData }, fields, 'update', makeContext({ isSudo: true }), 'Post');
173
+ const result = await splitMultiColumnFields(inputData, { ...inputData }, fields, 'update', makeContext({ isSudo: true }));
140
174
  expect(result).toEqual({ m_url: 'https://x/y.jpg', m_size: 99 });
141
175
  });
142
176
  it('a multi-column field WITHOUT field-level access splits exactly as before', async () => {
143
177
  const fields = { media: multiColumnField() };
144
178
  const inputData = { media: { url: 'https://x/y.jpg', size: 99 } };
145
- const result = await executeFieldResolveInputHooks(inputData, { ...inputData }, fields, 'update', makeContext(), 'Post');
179
+ const result = await splitMultiColumnFields(inputData, { ...inputData }, fields, 'update', makeContext());
146
180
  expect(result).toEqual({ m_url: 'https://x/y.jpg', m_size: 99 });
147
181
  });
148
182
  });
@@ -1 +1 @@
1
- {"version":3,"file":"multi-column-read-write.test.js","sourceRoot":"","sources":["../../src/access/multi-column-read-write.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"multi-column-read-write.test.js","sourceRoot":"","sources":["../../src/access/multi-column-read-write.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ import type { Session, AccessContext } from './types.js';
2
+ import type { OpenSaasConfig, ListConfig, FieldConfig } from '../config/types.js';
3
+ /**
4
+ * Access-scoped to-many relationship counts for the admin list view (issue
5
+ * #732).
6
+ *
7
+ * A to-many relationship column shows the count of the related rows the session
8
+ * may see — fetched in the SAME query as the row via Prisma's filtered
9
+ * `_count` (`_count: { select: { orders: { where: <access filter> } } }`), so no
10
+ * per-row query is issued and the count can never include rows the session
11
+ * cannot read. This module is the single place the related list's
12
+ * operation-level `query` access is folded into that `_count`, mirroring how
13
+ * `buildIncludeWithAccessControl` folds it into relation includes.
14
+ *
15
+ * It also resolves the count Filter spec's markers: Prisma cannot compare a
16
+ * relation count in a `where`, so a to-many relationship's Filter spec emits a
17
+ * {@link RELATIONSHIP_COUNT_FILTER_KEY} marker that
18
+ * {@link resolveRelationshipCountFilters} turns into an access-scoped
19
+ * `{ id: { in } }` before the query runs — never leaking counts of related rows
20
+ * the session cannot see.
21
+ */
22
+ type CountArgs = {
23
+ session: Session | null;
24
+ context: AccessContext;
25
+ };
26
+ /**
27
+ * Whether a field is a to-many relationship — the only field kind that carries a
28
+ * relationship count (a to-one relationship has at most one related row).
29
+ */
30
+ export declare function isToManyRelationshipField(field: FieldConfig | undefined): boolean;
31
+ /**
32
+ * Build the object to place at `include._count.select` for a list's to-many
33
+ * relationships, with each related list's `query` access folded into the
34
+ * per-relation `where` so the returned counts are access-scoped. A relationship
35
+ * whose related list is fully denied is omitted (its count renders as 0). Returns
36
+ * `undefined` when the list has no countable to-many relationships.
37
+ */
38
+ export declare function buildRelationshipCountSelect(listConfig: ListConfig<any>, args: CountArgs, config: OpenSaasConfig): Promise<Record<string, unknown> | undefined>;
39
+ /**
40
+ * Merge a filter-member's non-resolved sibling conditions with a resolved
41
+ * access-scoped fragment (e.g. a count marker's `{ id: { in } }`, or a to-one
42
+ * label filter's access-scoped `is`). With no siblings (the guaranteed case
43
+ * today) this is just the resolved fragment. When a sibling shares a key with
44
+ * the resolved fragment — a contrived case that cannot arise under the current
45
+ * one-condition-per-member invariant — both are ANDed so neither condition is
46
+ * silently lost. Shared by both relationship resolvers in this module and in
47
+ * `relationship-label-filter.ts`.
48
+ */
49
+ export declare function mergeResolvedMember(siblings: Record<string, unknown>, resolved: Record<string, unknown>): Record<string, unknown>;
50
+ /**
51
+ * Replace any to-many relationship count-filter markers in a filter `where` with
52
+ * access-scoped `{ id: { in } }` fragments. Markers only ever appear as
53
+ * top-level AND members (the pure filter engine pushes each field condition into
54
+ * the top-level AND, and never nests a marker inside the free-text OR), so this
55
+ * walks only the top level. Returns the `where` unchanged when it contains no
56
+ * markers, so lists without count filters pay nothing.
57
+ */
58
+ export declare function resolveRelationshipCountFilters(where: Record<string, unknown> | undefined, listConfig: ListConfig<any>, listKey: string, args: CountArgs, config: OpenSaasConfig): Promise<Record<string, unknown> | undefined>;
59
+ export {};
60
+ //# sourceMappingURL=relationship-count.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relationship-count.d.ts","sourceRoot":"","sources":["../../src/access/relationship-count.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,aAAa,EAAgB,MAAM,YAAY,CAAA;AACtE,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAMjF;;;;;;;;;;;;;;;;;;GAkBG;AAEH,KAAK,SAAS,GAAG;IACf,OAAO,EAAE,OAAO,GAAG,IAAI,CAAA;IACvB,OAAO,EAAE,aAAa,CAAA;CACvB,CAAA;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,WAAW,GAAG,SAAS,GAAG,OAAO,CASjF;AAkCD;;;;;;GAMG;AACH,wBAAsB,4BAA4B,CAEhD,UAAU,EAAE,UAAU,CAAC,GAAG,CAAC,EAC3B,IAAI,EAAE,SAAS,EACf,MAAM,EAAE,cAAc,GACrB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC,CAQ9C;AA0HD;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAIzB;AAED;;;;;;;GAOG;AACH,wBAAsB,+BAA+B,CACnD,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAE1C,UAAU,EAAE,UAAU,CAAC,GAAG,CAAC,EAC3B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,SAAS,EACf,MAAM,EAAE,cAAc,GACrB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC,CAuD9C"}
@@ -0,0 +1,233 @@
1
+ import { RELATIONSHIP_COUNT_FILTER_KEY } from '../filter/types.js';
2
+ import { checkAccess, getRelatedListConfig } from './engine.js';
3
+ import { getDbKey } from '../lib/case-utils.js';
4
+ /**
5
+ * Whether a field is a to-many relationship — the only field kind that carries a
6
+ * relationship count (a to-one relationship has at most one related row).
7
+ */
8
+ export function isToManyRelationshipField(field) {
9
+ return (field?.type === 'relationship' &&
10
+ 'many' in field &&
11
+ field.many === true &&
12
+ 'ref' in field &&
13
+ typeof field.ref === 'string' &&
14
+ field.ref.length > 0);
15
+ }
16
+ /**
17
+ * Resolve the related list's operation-level `query` access for one to-many
18
+ * relationship into the entry its `_count` select needs. Returns `null` when the
19
+ * field is not a resolvable to-many relationship.
20
+ */
21
+ async function relationshipCountAccessEntry(field, args, config) {
22
+ if (!field || !isToManyRelationshipField(field) || !('ref' in field)) {
23
+ return null;
24
+ }
25
+ const ref = field.ref;
26
+ if (typeof ref !== 'string')
27
+ return null;
28
+ const related = getRelatedListConfig(ref, config);
29
+ if (!related)
30
+ return null;
31
+ const queryAccess = related.listConfig.access?.operation?.query;
32
+ const result = await checkAccess(queryAccess, { session: args.session, context: args.context });
33
+ if (result === false)
34
+ return { kind: 'denied' };
35
+ if (typeof result === 'object')
36
+ return { kind: 'scoped', where: result };
37
+ return { kind: 'all' };
38
+ }
39
+ /**
40
+ * Build the object to place at `include._count.select` for a list's to-many
41
+ * relationships, with each related list's `query` access folded into the
42
+ * per-relation `where` so the returned counts are access-scoped. A relationship
43
+ * whose related list is fully denied is omitted (its count renders as 0). Returns
44
+ * `undefined` when the list has no countable to-many relationships.
45
+ */
46
+ export async function buildRelationshipCountSelect(
47
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- ListConfig must accept any TypeInfo
48
+ listConfig, args, config) {
49
+ const select = {};
50
+ for (const [fieldName, field] of Object.entries(listConfig.fields)) {
51
+ const entry = await relationshipCountAccessEntry(field, args, config);
52
+ if (entry === null || entry.kind === 'denied')
53
+ continue;
54
+ select[fieldName] = entry.kind === 'scoped' ? { where: entry.where } : true;
55
+ }
56
+ return Object.keys(select).length > 0 ? select : undefined;
57
+ }
58
+ /** Read a to-many relationship's count off a fetched row's `_count` payload. */
59
+ function readRelationshipCount(row, fieldName) {
60
+ const counts = row._count;
61
+ if (counts && typeof counts === 'object') {
62
+ const value = counts[fieldName];
63
+ if (typeof value === 'number')
64
+ return value;
65
+ }
66
+ return 0;
67
+ }
68
+ /** Whether a count satisfies a Filter operator/value comparison. */
69
+ function matchesCount(count, operator, value) {
70
+ switch (operator) {
71
+ case 'eq':
72
+ return count === value;
73
+ case 'gt':
74
+ return count > value;
75
+ case 'gte':
76
+ return count >= value;
77
+ case 'lt':
78
+ return count < value;
79
+ case 'lte':
80
+ return count <= value;
81
+ }
82
+ }
83
+ function asCountDelegate(value) {
84
+ if (value && typeof value === 'object' && 'findMany' in value) {
85
+ const candidate = value;
86
+ if (typeof candidate.findMany === 'function') {
87
+ return value;
88
+ }
89
+ }
90
+ return null;
91
+ }
92
+ /** Extract the `RelationshipCountFilterMarker` from a condition value, if present. */
93
+ function readCountMarker(value) {
94
+ if (!value || typeof value !== 'object')
95
+ return null;
96
+ const marker = value[RELATIONSHIP_COUNT_FILTER_KEY];
97
+ if (!marker || typeof marker !== 'object')
98
+ return null;
99
+ const { operator, value: n } = marker;
100
+ if ((operator === 'eq' ||
101
+ operator === 'gt' ||
102
+ operator === 'gte' ||
103
+ operator === 'lt' ||
104
+ operator === 'lte') &&
105
+ typeof n === 'number') {
106
+ return { operator, value: n };
107
+ }
108
+ return null;
109
+ }
110
+ /**
111
+ * Resolve one to-many relationship count-filter marker into a Prisma `where`
112
+ * fragment constraining the parent by id. Runs a single access-scoped read
113
+ * through the SECURED context — never a raw/unscoped query and never a per-row
114
+ * query — computing the access-visible count per parent and keeping the ids
115
+ * whose count satisfies the comparison. A fully-denied related list makes every
116
+ * count 0, resolved without any query.
117
+ */
118
+ async function resolveOneCountFilter(
119
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- ListConfig must accept any TypeInfo
120
+ listConfig, listKey, fieldName, marker, args, config) {
121
+ const field = listConfig.fields[fieldName];
122
+ const entry = await relationshipCountAccessEntry(field, args, config);
123
+ // Not resolvable (shouldn't happen for a marker the spec emitted) → no-op.
124
+ if (entry === null)
125
+ return {};
126
+ // Related list fully denied → every parent's access-visible count is 0.
127
+ if (entry.kind === 'denied') {
128
+ return matchesCount(0, marker.operator, marker.value) ? {} : { id: { in: [] } };
129
+ }
130
+ const delegate = asCountDelegate(args.context.db[getDbKey(listKey)]);
131
+ if (!delegate)
132
+ return {};
133
+ const countSelect = entry.kind === 'scoped' ? { where: entry.where } : true;
134
+ // This over-fetches the parent's scalar columns — it reads only `id` + `_count`
135
+ // per row yet materialises every scalar. It is left un-narrowed on purpose: the
136
+ // secured `context.db` `findMany` does NOT honour Prisma `select` (it
137
+ // warns-and-ignores it and returns the full access-filtered record — see
138
+ // `warnIfSelectIgnored` in context/index.ts and the "Narrowing Reads" note in
139
+ // packages/core/CLAUDE.md). The only supported narrowing is `include`/fragment
140
+ // `query`, neither of which can drop scalar columns. So adding
141
+ // `select: { id: true, _count: {...} }` here would be a silent no-op that also
142
+ // trips the ignore-warning, not a real projection. The count stays access-scoped
143
+ // via the filtered `_count` include below regardless; trimming the projection
144
+ // would first require the read pipeline to honour `select`.
145
+ const rows = await delegate.findMany({
146
+ include: { _count: { select: { [fieldName]: countSelect } } },
147
+ });
148
+ const matchingIds = [];
149
+ if (Array.isArray(rows)) {
150
+ for (const row of rows) {
151
+ if (!row || typeof row !== 'object')
152
+ continue;
153
+ const record = row;
154
+ if (matchesCount(readRelationshipCount(record, fieldName), marker.operator, marker.value)) {
155
+ matchingIds.push(String(record.id));
156
+ }
157
+ }
158
+ }
159
+ return { id: { in: matchingIds } };
160
+ }
161
+ /**
162
+ * Merge a filter-member's non-resolved sibling conditions with a resolved
163
+ * access-scoped fragment (e.g. a count marker's `{ id: { in } }`, or a to-one
164
+ * label filter's access-scoped `is`). With no siblings (the guaranteed case
165
+ * today) this is just the resolved fragment. When a sibling shares a key with
166
+ * the resolved fragment — a contrived case that cannot arise under the current
167
+ * one-condition-per-member invariant — both are ANDed so neither condition is
168
+ * silently lost. Shared by both relationship resolvers in this module and in
169
+ * `relationship-label-filter.ts`.
170
+ */
171
+ export function mergeResolvedMember(siblings, resolved) {
172
+ if (Object.keys(siblings).length === 0)
173
+ return resolved;
174
+ const collides = Object.keys(resolved).some((key) => key in siblings);
175
+ return collides ? { AND: [siblings, resolved] } : { ...siblings, ...resolved };
176
+ }
177
+ /**
178
+ * Replace any to-many relationship count-filter markers in a filter `where` with
179
+ * access-scoped `{ id: { in } }` fragments. Markers only ever appear as
180
+ * top-level AND members (the pure filter engine pushes each field condition into
181
+ * the top-level AND, and never nests a marker inside the free-text OR), so this
182
+ * walks only the top level. Returns the `where` unchanged when it contains no
183
+ * markers, so lists without count filters pay nothing.
184
+ */
185
+ export async function resolveRelationshipCountFilters(where,
186
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- ListConfig must accept any TypeInfo
187
+ listConfig, listKey, args, config) {
188
+ if (!where)
189
+ return where;
190
+ const andValue = where.AND;
191
+ const members = Array.isArray(andValue)
192
+ ? andValue
193
+ : [where];
194
+ const findMarker = (member) => {
195
+ for (const key of Object.keys(member)) {
196
+ if (!isToManyRelationshipField(listConfig.fields[key]))
197
+ continue;
198
+ const marker = readCountMarker(member[key]);
199
+ if (marker)
200
+ return { field: key, marker };
201
+ }
202
+ return null;
203
+ };
204
+ if (!members.some((member) => findMarker(member) !== null)) {
205
+ return where;
206
+ }
207
+ const resolvedMembers = [];
208
+ for (const member of members) {
209
+ const found = findMarker(member);
210
+ if (!found) {
211
+ resolvedMembers.push(member);
212
+ continue;
213
+ }
214
+ const resolved = await resolveOneCountFilter(listConfig, listKey, found.field, found.marker, args, config);
215
+ // Preserve any sibling conditions co-present on this member rather than
216
+ // replacing it wholesale with the resolved `{ id: { in } }`. The filter engine
217
+ // currently guarantees each AND-member (and the no-AND single object) carries
218
+ // exactly one field condition, so `siblings` is empty today and this equals the
219
+ // previous wholesale replacement — but if a future engine change ever merged
220
+ // multiple conditions into one member, spreading keeps the marker's siblings
221
+ // from being silently dropped.
222
+ const siblings = { ...member };
223
+ delete siblings[found.field];
224
+ resolvedMembers.push(mergeResolvedMember(siblings, resolved));
225
+ }
226
+ // Drop no-op members (a fully-denied related list where 0 satisfies the
227
+ // comparison resolves to `{}` — matches everything, so it need not be ANDed).
228
+ const effective = resolvedMembers.filter((member) => Object.keys(member).length > 0);
229
+ if (effective.length === 0)
230
+ return undefined;
231
+ return effective.length === 1 ? effective[0] : { AND: effective };
232
+ }
233
+ //# sourceMappingURL=relationship-count.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relationship-count.js","sourceRoot":"","sources":["../../src/access/relationship-count.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=relationship-count.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relationship-count.test.d.ts","sourceRoot":"","sources":["../../src/access/relationship-count.test.ts"],"names":[],"mappings":""}