@opensaas/stack-core 0.29.0 → 0.31.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 (133) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +443 -0
  3. package/CLAUDE.md +4 -4
  4. package/dist/access/access-filter.d.ts.map +1 -1
  5. package/dist/access/access-filter.js +14 -1
  6. package/dist/access/access-filter.js.map +1 -1
  7. package/dist/access/access-filter.test.js +50 -0
  8. package/dist/access/access-filter.test.js.map +1 -1
  9. package/dist/access/field-access.js +6 -6
  10. package/dist/access/field-access.js.map +1 -1
  11. package/dist/access/multi-column-read-write.test.js +46 -12
  12. package/dist/access/multi-column-read-write.test.js.map +1 -1
  13. package/dist/access/relationship-count.d.ts +60 -0
  14. package/dist/access/relationship-count.d.ts.map +1 -0
  15. package/dist/access/relationship-count.js +233 -0
  16. package/dist/access/relationship-count.js.map +1 -0
  17. package/dist/access/relationship-count.test.d.ts +2 -0
  18. package/dist/access/relationship-count.test.d.ts.map +1 -0
  19. package/dist/access/relationship-count.test.js +185 -0
  20. package/dist/access/relationship-count.test.js.map +1 -0
  21. package/dist/access/relationship-label-filter.d.ts +45 -0
  22. package/dist/access/relationship-label-filter.d.ts.map +1 -0
  23. package/dist/access/relationship-label-filter.js +93 -0
  24. package/dist/access/relationship-label-filter.js.map +1 -0
  25. package/dist/access/relationship-label-filter.test.d.ts +2 -0
  26. package/dist/access/relationship-label-filter.test.d.ts.map +1 -0
  27. package/dist/access/relationship-label-filter.test.js +126 -0
  28. package/dist/access/relationship-label-filter.test.js.map +1 -0
  29. package/dist/config/index.d.ts +1 -1
  30. package/dist/config/index.d.ts.map +1 -1
  31. package/dist/config/nav-count.d.ts +34 -0
  32. package/dist/config/nav-count.d.ts.map +1 -0
  33. package/dist/config/nav-count.js +71 -0
  34. package/dist/config/nav-count.js.map +1 -0
  35. package/dist/config/types.d.ts +305 -4
  36. package/dist/config/types.d.ts.map +1 -1
  37. package/dist/context/hook-pipeline.d.ts.map +1 -1
  38. package/dist/context/hook-pipeline.js +11 -1
  39. package/dist/context/hook-pipeline.js.map +1 -1
  40. package/dist/context/index.d.ts +28 -0
  41. package/dist/context/index.d.ts.map +1 -1
  42. package/dist/context/index.js +206 -1
  43. package/dist/context/index.js.map +1 -1
  44. package/dist/context/nested-operations.d.ts.map +1 -1
  45. package/dist/context/nested-operations.js +7 -1
  46. package/dist/context/nested-operations.js.map +1 -1
  47. package/dist/extend.d.ts +1 -0
  48. package/dist/extend.d.ts.map +1 -1
  49. package/dist/fields/index.d.ts +1 -1
  50. package/dist/fields/index.d.ts.map +1 -1
  51. package/dist/fields/index.js +166 -0
  52. package/dist/fields/index.js.map +1 -1
  53. package/dist/filter/collect.d.ts +32 -0
  54. package/dist/filter/collect.d.ts.map +1 -0
  55. package/dist/filter/collect.js +60 -0
  56. package/dist/filter/collect.js.map +1 -0
  57. package/dist/filter/filter.test.d.ts +2 -0
  58. package/dist/filter/filter.test.d.ts.map +1 -0
  59. package/dist/filter/filter.test.js +348 -0
  60. package/dist/filter/filter.test.js.map +1 -0
  61. package/dist/filter/index.d.ts +7 -0
  62. package/dist/filter/index.d.ts.map +1 -0
  63. package/dist/filter/index.js +16 -0
  64. package/dist/filter/index.js.map +1 -0
  65. package/dist/filter/map.d.ts +18 -0
  66. package/dist/filter/map.d.ts.map +1 -0
  67. package/dist/filter/map.js +60 -0
  68. package/dist/filter/map.js.map +1 -0
  69. package/dist/filter/parse.d.ts +33 -0
  70. package/dist/filter/parse.d.ts.map +1 -0
  71. package/dist/filter/parse.js +103 -0
  72. package/dist/filter/parse.js.map +1 -0
  73. package/dist/filter/serialize.d.ts +25 -0
  74. package/dist/filter/serialize.d.ts.map +1 -0
  75. package/dist/filter/serialize.js +68 -0
  76. package/dist/filter/serialize.js.map +1 -0
  77. package/dist/filter/serialize.test.d.ts +2 -0
  78. package/dist/filter/serialize.test.d.ts.map +1 -0
  79. package/dist/filter/serialize.test.js +83 -0
  80. package/dist/filter/serialize.test.js.map +1 -0
  81. package/dist/filter/types.d.ts +122 -0
  82. package/dist/filter/types.d.ts.map +1 -0
  83. package/dist/filter/types.js +24 -0
  84. package/dist/filter/types.js.map +1 -0
  85. package/dist/hooks/index.d.ts +30 -0
  86. package/dist/hooks/index.d.ts.map +1 -1
  87. package/dist/hooks/index.js +79 -59
  88. package/dist/hooks/index.js.map +1 -1
  89. package/dist/index.d.ts +6 -1
  90. package/dist/index.d.ts.map +1 -1
  91. package/dist/index.js +19 -0
  92. package/dist/index.js.map +1 -1
  93. package/dist/internal.d.ts +1 -0
  94. package/dist/internal.d.ts.map +1 -1
  95. package/dist/internal.js +4 -0
  96. package/dist/internal.js.map +1 -1
  97. package/dist/mcp/handler.d.ts +11 -3
  98. package/dist/mcp/handler.d.ts.map +1 -1
  99. package/dist/mcp/handler.js +96 -20
  100. package/dist/mcp/handler.js.map +1 -1
  101. package/package.json +1 -1
  102. package/src/access/access-filter.test.ts +79 -0
  103. package/src/access/access-filter.ts +15 -4
  104. package/src/access/field-access.ts +6 -6
  105. package/src/access/multi-column-read-write.test.ts +68 -19
  106. package/src/access/relationship-count.test.ts +269 -0
  107. package/src/access/relationship-count.ts +311 -0
  108. package/src/access/relationship-label-filter.test.ts +177 -0
  109. package/src/access/relationship-label-filter.ts +140 -0
  110. package/src/config/index.ts +6 -0
  111. package/src/config/nav-count.ts +85 -0
  112. package/src/config/types.ts +319 -1
  113. package/src/context/hook-pipeline.ts +19 -0
  114. package/src/context/index.ts +286 -4
  115. package/src/context/nested-operations.ts +22 -0
  116. package/src/extend.ts +9 -0
  117. package/src/fields/index.ts +168 -0
  118. package/src/filter/collect.ts +72 -0
  119. package/src/filter/filter.test.ts +400 -0
  120. package/src/filter/index.ts +25 -0
  121. package/src/filter/map.ts +68 -0
  122. package/src/filter/parse.ts +106 -0
  123. package/src/filter/serialize.test.ts +115 -0
  124. package/src/filter/serialize.ts +75 -0
  125. package/src/filter/types.ts +120 -0
  126. package/src/hooks/index.ts +87 -57
  127. package/src/index.ts +54 -0
  128. package/src/internal.ts +5 -0
  129. package/src/mcp/handler.ts +118 -28
  130. package/tests/context.test.ts +690 -0
  131. package/tests/multi-column-validation-ordering.test.ts +305 -0
  132. package/tests/nav-count.test.ts +189 -0
  133. package/tsconfig.tsbuildinfo +1 -1
@@ -1,4 +1,4 @@
1
1
 
2
- > @opensaas/stack-core@0.29.0 build /home/runner/work/stack/stack/packages/core
2
+ > @opensaas/stack-core@0.31.0 build /home/runner/work/stack/stack/packages/core
3
3
  > tsc
4
4
 
package/CHANGELOG.md CHANGED
@@ -1,5 +1,448 @@
1
1
  # @opensaas/stack-core
2
2
 
3
+ ## 0.31.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#750](https://github.com/OpenSaasAU/stack/pull/750) [`047487a`](https://github.com/OpenSaasAU/stack/commit/047487adf502f10f7f6774ff52c38c70d465f533) Thanks [@borisno2](https://github.com/borisno2)! - Add a `bulkDelete` server action for list-level bulk deletion
8
+
9
+ `context.serverAction` now accepts `{ listKey, action: 'bulkDelete', ids }`. It
10
+ deletes each id row-by-row through the secured context, honouring Silent failure
11
+ (a denied or missing row returns `null` and is not counted; one row's error does
12
+ not abort the rest), and returns `{ deleted, total }`.
13
+
14
+ The result is deliberately a count shape rather than the single-op `{ success }`
15
+ shape, so a UI `serverAction` wrapper that redirects on a single-item success
16
+ (the item-form pattern) does not hijack a list-level bulk operation.
17
+
18
+ ```ts
19
+ const result = await context.serverAction({
20
+ listKey: 'Post',
21
+ action: 'bulkDelete',
22
+ ids: ['a', 'b', 'c'],
23
+ })
24
+ // result: { deleted: 2, total: 3 } // one row was denied/missing
25
+ ```
26
+
27
+ - [#755](https://github.com/OpenSaasAU/stack/pull/755) [`9cd06dd`](https://github.com/OpenSaasAU/stack/commit/9cd06dddb45512966affc3a6b3455e97595c0de2) Thanks [@list({](https://github.com/list({)! - Admin chrome polish: opt-in nav counts and avatar label cells ([#735](https://github.com/OpenSaasAU/stack/issues/735))
28
+
29
+ Two per-list opt-ins for the admin UI, both off by default.
30
+
31
+ **Nav counts** — set `ui.navCount: true` on a list to show an access-scoped
32
+ record count next to its nav item. The count is fetched through the secured
33
+ context, so it only ever reflects what the current session may see; no count
34
+ query runs for lists that don't opt in, and a list whose query access is
35
+ statically denied renders no count rather than a misleading zero.
36
+
37
+ ```typescript
38
+ lists: {
39
+ Post: list({
40
+ fields: {
41
+ /* ... */
42
+ },
43
+ ui: { navCount: true },
44
+ }),
45
+ }
46
+ ```
47
+
48
+ **Avatar label cells** — set `ui.avatar: true` to render a list's label column
49
+ with a deterministic initials bubble ahead of the emphasized Item label. The
50
+ initials and colour derive from the row; the palette is Theme-token-derived (no
51
+ raw hex). A per-field cell override (`ui.cell`) on the label field still wins.
52
+
53
+ ```typescript
54
+ lists: {
55
+
56
+ fields: {
57
+ /* ... */
58
+ },
59
+ ui: { avatar: true },
60
+ }),
61
+ }
62
+ ```
63
+
64
+ New exports:
65
+
66
+ - `@opensaas/stack-core`: `resolveNavCounts`, `isListQueryStaticallyDenied`
67
+ - `@opensaas/stack-ui`: `Avatar` primitive, `AvatarLabelCell`, and the
68
+ `getInitials`, `getAvatarTone`, `AVATAR_TONES` helpers. New Slots:
69
+ `avatar`, `cell-avatar-label`, `nav-count`.
70
+
71
+ - [#759](https://github.com/OpenSaasAU/stack/pull/759) [`b190813`](https://github.com/OpenSaasAU/stack/commit/b190813a4531bd01b3206845b2c531099e0a204a) Thanks [@borisno2](https://github.com/borisno2)! - Add custom Bulk actions from list config (admin list view)
72
+
73
+ A list can now declare list-specific Bulk actions under `ui.listView.bulkActions`. Each action's button renders in the list view's selection bar (in declaration order) alongside the built-in Delete. The action's server-side `handler` receives the selected ids and the secured context, so all its work runs through access control and hooks — a denied row is a Silent failure absorbed into the outcome, never leaked.
74
+
75
+ ```typescript
76
+ Post: list({
77
+ fields: { title: text(), status: select({ options: [/* ... */] }) },
78
+ ui: {
79
+ listView: {
80
+ bulkActions: [
81
+ {
82
+ key: 'publish',
83
+ label: 'Publish',
84
+ // Optional: `variant`, `destructive` (confirm first),
85
+ // `hasAccess` (server-side visibility gate).
86
+ handler: async ({ ids, context }) => {
87
+ let n = 0
88
+ for (const id of ids) {
89
+ const updated = await context.db.post.update({
90
+ where: { id },
91
+ data: { status: 'published' },
92
+ })
93
+ if (updated) n++
94
+ }
95
+ return { message: `Published ${n} of ${ids.length}` }
96
+ },
97
+ },
98
+ ],
99
+ },
100
+ },
101
+ })
102
+ ```
103
+
104
+ Only serialisable metadata (`key`/`label`/`variant`/`destructive`) crosses to the client; the `handler`/`hasAccess` functions stay on the server. Clicking the button sends the `key` and selected ids back through the generic server action, which looks the handler up and runs it with a freshly-rebuilt secured context. Selection is enabled for a list that has custom actions even when Delete is denied. CSV export is documented as a recipe using this surface rather than shipping as a built-in.
105
+
106
+ - [#754](https://github.com/OpenSaasAU/stack/pull/754) [`f67cd79`](https://github.com/OpenSaasAU/stack/commit/f67cd798724712a90d7ada8f28202d3d6371693f) Thanks [@borisno2](https://github.com/borisno2)! - Add the Filter builder input UI for the admin list view ([#731](https://github.com/OpenSaasAU/stack/issues/731))
107
+
108
+ The admin list view now ships a `FilterBuilder` that constructs the `?search=`
109
+ filter query the filter engine already consumes (ADR-0017) — a free-text search
110
+ box plus structured field / operator / value rows. Available fields, operators,
111
+ and value suggestions are derived entirely from each field's self-contained
112
+ `getFilterSpec` (via the serializable `collectFilterSuggestions` metadata), so
113
+ there is no field-type `switch` and no functions cross the server/client
114
+ boundary. Applied filters flow through the same secured `context.db`, so
115
+ filtering can only ever narrow what a session may see.
116
+
117
+ `@opensaas/stack-core` gains `serializeFilterQuery(tokens)` — the exact inverse
118
+ of `parseFilterQuery` — so the builder produces the grammar the engine parses
119
+ with the quoting and operator-prefix rules kept next to the parser.
120
+
121
+ The `FilterBuilder` is composable (exported from `@opensaas/stack-ui` and
122
+ `@opensaas/stack-ui/standalone`) with theme-token styling and `data-slot` parts
123
+ for extension:
124
+
125
+ ```tsx
126
+ import { FilterBuilder } from '@opensaas/stack-ui/standalone'
127
+ import { collectFilterSuggestions } from '@opensaas/stack-core'
128
+
129
+ // Server component: collect serializable suggestion metadata for the list.
130
+ const suggestions = collectFilterSuggestions(listConfig, 'Post', config)
131
+
132
+ // Client: build and apply a `?search=` query.
133
+ <FilterBuilder
134
+ suggestions={suggestions}
135
+ defaultValue={search}
136
+ onApply={(query) => router.push(`/admin/post?search=${encodeURIComponent(query)}`)}
137
+ />
138
+ ```
139
+
140
+ The list view wires this in automatically; existing `?search=` URLs keep
141
+ working unchanged.
142
+
143
+ - [#746](https://github.com/OpenSaasAU/stack/pull/746) [`dcb10e2`](https://github.com/OpenSaasAU/stack/commit/dcb10e27c28a8a8f9a5e625f550ac5c750436eb6) Thanks [@borisno2](https://github.com/borisno2)! - Add the admin UI filter engine: a Filter spec field-builder contract and URL-driven server-side list filtering (ADR-0017).
144
+
145
+ Fields now declare their filtering capability through a new optional `getFilterSpec` method — a peer of `getPrismaType`/`getTypeScriptType` on the field-builder contract. It reports the operators a field supports, a pure token→condition mapper, and serializable suggestion metadata. Core field types implement it (text contains + free text, integer/decimal/timestamp/calendarDay comparisons, select/checkbox equality against enumerated values, relationship by label lookup). A field without a spec — `password`, `json`, `virtual`, or any third-party field that hasn't adopted one — is simply not filterable, so the addition degrades gracefully everywhere.
146
+
147
+ The admin list view now parses the URL filter query (the list's `search` param) through the engine and merges the result into the access-controlled query via the secured context, so filtering runs server-side and can only ever narrow — never widen — what a session may see. This replaces the previous hard-coded `type === 'text'` search; free-text behavior is now driven by each text field's Filter spec.
148
+
149
+ Grammar (ADR-0017): implicit-AND tokens, quoted multi-word values, `>`/`>=`/`<`/`<=` comparisons on numeric/date fields, and bare words as free text. Unknown syntax degrades to free text, never errors.
150
+
151
+ Multi-word free-text UX shift (intentional, per ADR-0017): bare words now combine with AND, so `hello world` requires each word to match separately (not the literal substring `hello world`). To match a contiguous phrase, quote it: `"hello world"`. A pasted URL such as `http://x` is treated as a single free-text token and searched verbatim — the `http:` prefix is not parsed as a field.
152
+
153
+ New exports from `@opensaas/stack-core`:
154
+
155
+ ```typescript
156
+ import {
157
+ parseFilterQuery, // (query) => FilterToken[] — pure
158
+ buildFilterWhere, // (tokens, specs) => where — pure
159
+ collectFilterSpecs, // (listConfig, listKey, config) => specs
160
+ buildListFilterWhere, // (query, listConfig, listKey, config) => where
161
+ collectFilterSuggestions, // serializable autocomplete metadata
162
+ } from '@opensaas/stack-core'
163
+
164
+ // e.g. "status:Published views:>10 author:\"Ada Lovelace\" beta"
165
+ const where = buildListFilterWhere(query, listConfig, listKey, config)
166
+ const rows = await context.db.post.findMany({ where }) // ANDed with the access filter
167
+ ```
168
+
169
+ Third-party field authors can implement `FilterSpec` (exported from `@opensaas/stack-core/extend`) to make their field filterable.
170
+
171
+ - [#760](https://github.com/OpenSaasAU/stack/pull/760) [`f8b6f02`](https://github.com/OpenSaasAU/stack/commit/f8b6f02c18322d0d04a7c3cc82e579d0ba9a2da9) Thanks [@borisno2](https://github.com/borisno2)! - Add inline cell editing to admin Relationship tables
172
+
173
+ Cells in a to-many Relationship table on the item view are now editable in place.
174
+ Click a cell to edit it, commit with Enter or blur, cancel with Escape. Each
175
+ commit is a single-field update on the **related** row through the secured
176
+ context, so the related list's own operation- and field-level update access plus
177
+ its hooks/validation apply — never the parent's. The update is optimistic and
178
+ reverts, with a visible reason, on a Silent failure (access denied / row gone) or
179
+ a validation error (inline field errors surface too). Committed values re-render
180
+ through the Cell registry, so select cells stay coloured badges.
181
+
182
+ A field the session cannot write — or a table whose related-list update access is
183
+ statically denied — renders read-only with no edit affordance; row-level
184
+ (filter-scoped) denials surface at commit as a revert. Non-editable cells keep
185
+ click-to-navigate; main list tables are unchanged (this is Relationship-table
186
+ only).
187
+
188
+ - `@opensaas/stack-core`: the generic server action gains a distinct
189
+ `updateRelated` result shape (`{ updated, error?, fieldErrors? }`), and
190
+ `checkFieldAccess` is exposed on `@opensaas/stack-core/internal` so the UI can
191
+ decide the edit affordance without a parallel field-access evaluator.
192
+ - `@opensaas/stack-ui`: `RelationshipTableClient` accepts `editableColumns`; the
193
+ editable cell reuses the field-component registry for its editor and the Cell
194
+ registry for its display (new Slots: `relationship-table-cell-display`,
195
+ `relationship-table-cell-editor`, `relationship-table-cell-edit-trigger`,
196
+ `relationship-table-cell-error`).
197
+
198
+ - [#757](https://github.com/OpenSaasAU/stack/pull/757) [`c05701e`](https://github.com/OpenSaasAU/stack/commit/c05701e523815b8f411a6d39e57bbb9317dc2a9d) Thanks [@borisno2](https://github.com/borisno2)! - Add a pre-linked create drawer to read-only Relationship tables (issue [#738](https://github.com/OpenSaasAU/stack/issues/738))
199
+
200
+ The item view's read-only Relationship tables now offer a "+ Add" control that
201
+ opens a drawer hosting the related list's create form, with the back-reference to
202
+ the current record preset and hidden. On submit the new row is created through
203
+ the secured context already linked to the parent, then the drawer closes and the
204
+ table refreshes.
205
+
206
+ Create-and-link semantics (ADR-0018): the create runs on the RELATED list, so
207
+ the related list's own `create` access control, hooks, and field-level access
208
+ apply — never the parent's. The back-reference is set on the server from the
209
+ field/parent id (never trusted from the client payload). The "+ Add" is shown
210
+ only when a back-reference exists to preset the link and the related list's
211
+ `create` access is not statically denied; a filter/function-scoped denial
212
+ surfaces at commit time as a generic error (no denied-vs-absent leak).
213
+
214
+ New generic server action (`@opensaas/stack-core`):
215
+
216
+ ```ts
217
+ await context.serverAction({
218
+ listKey: 'Post', // the RELATED list
219
+ action: 'createRelated',
220
+ data: { title: 'Hello', slug: 'hello' },
221
+ field: 'author', // the back-reference field on Post
222
+ parentId: user.id, // the record being edited
223
+ })
224
+ // → { created: true, id } | { created: false, error?, fieldErrors? }
225
+ ```
226
+
227
+ The drawer (`RelationshipCreateDrawer` from `@opensaas/stack-ui`) mounts on the
228
+ existing `relationship-table-toolbar` seam and reuses the shared item-form engine
229
+ and field-component registry, so the related list's full validation and required
230
+ fields are enforced even when a required field is not one of the table's columns.
231
+
232
+ - [#756](https://github.com/OpenSaasAU/stack/pull/756) [`8199238`](https://github.com/OpenSaasAU/stack/commit/81992382290f356071955f16efd14f7771045a16) Thanks [@list({](https://github.com/list({)! - Add relationship-table row removal to the admin item view (ADR-0018)
233
+
234
+ Each read-only Relationship table row now has a ✕ removal control. By default it
235
+ **disconnects** the related row from the current record (non-destructive — the
236
+ row survives and still appears on its own list), gated on the related list's
237
+ update access. A per-relationship opt-in truly deletes the related row (behind a
238
+ confirmation, gated on the related list's delete access), or hides the control
239
+ entirely. Where the schema makes disconnect impossible (a required foreign key on
240
+ the related side) the control is hidden unless delete is opted in. Removals run
241
+ through the secured context, so an access-denied removal is a Silent failure: the
242
+ row stays with a visible reason.
243
+
244
+ Configure per relationship via `ui.itemView.removeAction`:
245
+
246
+ ```typescript
247
+
248
+ fields: {
249
+ // Default: ✕ disconnects the post (it still exists).
250
+ posts: relationship({ ref: 'Post.author', many: true }),
251
+ // Opt in to destructive delete (confirmed).
252
+ notes: relationship({
253
+ ref: 'Note.owner',
254
+ many: true,
255
+ ui: { itemView: { removeAction: 'delete' } }, // 'disconnect' (default) | 'delete' | 'none'
256
+ }),
257
+ },
258
+ })
259
+ ```
260
+
261
+ `@opensaas/stack-core` adds a `removeRelated` server action (distinct
262
+ `{ removed }` result shape, like `bulkDelete`, so a redirect-on-success wrapper
263
+ never hijacks an in-place removal) and the `RelationshipItemViewConfig.removeAction`
264
+ option.
265
+
266
+ - [#745](https://github.com/OpenSaasAU/stack/pull/745) [`4d99e91`](https://github.com/OpenSaasAU/stack/commit/4d99e910b61c6196564a7248abf3d32b1d6be883) Thanks [@borisno2](https://github.com/borisno2)! - Add a Cell registry with default cells for core field types
267
+
268
+ List tables now render every value through a **Cell** resolved by a
269
+ cell-component registry that mirrors the form-field registry's priority chain:
270
+ per-field override → custom type registry → field-type registry → plain-text
271
+ fallback. Each core field type ships a default Cell — text (plain), integer
272
+ (tabular figures), select (coloured Badge), timestamp (formatted date), checkbox
273
+ (mark), and to-one relationship (Item label link). Unknown/third-party types
274
+ without a registered Cell fall back to plain text.
275
+
276
+ Select options gain optional, additive per-option UI metadata mapping a value to
277
+ a badge variant. Existing options keep working unchanged; unmapped options render
278
+ the neutral badge.
279
+
280
+ ```typescript
281
+ // opensaas.config.ts — colour a status value in list-table cells
282
+ status: select({
283
+ options: [
284
+ { label: 'Draft', value: 'draft', ui: { variant: 'secondary' } },
285
+ { label: 'Published', value: 'published', ui: { variant: 'success' } },
286
+ ],
287
+ })
288
+ ```
289
+
290
+ Register a Cell for a custom/third-party field exactly as you register its form
291
+ component, or override a single field's Cell:
292
+
293
+ ```typescript
294
+ 'use client'
295
+ import { registerCellComponent } from '@opensaas/stack-ui'
296
+ registerCellComponent('myField', MyCell)
297
+
298
+ // or per-field override (highest priority)
299
+ price: integer({ ui: { cell: CurrencyCell } })
300
+ ```
301
+
302
+ - [#751](https://github.com/OpenSaasAU/stack/pull/751) [`20459b5`](https://github.com/OpenSaasAU/stack/commit/20459b5a7f8b2578342509442d36017cfa2f08f6) Thanks [@list({](https://github.com/list({)! - Derive the admin item view from the list shape, with read-only Relationship tables and a totals footer ([#734](https://github.com/OpenSaasAU/stack/issues/734))
303
+
304
+ A record's edit page now derives its layout from the list's shape. Scalar and
305
+ to-one fields stay in a details card (whole-form Save/Cancel, unchanged), and
306
+ each to-many relationship renders as a read-only **Relationship table**: one
307
+ to-many relationship gives a two-column split, none gives a single centered
308
+ card, several stack. Table columns default to the related list's own column
309
+ curation minus the back-reference to the parent, cells come from the cell
310
+ registry, and a totals footer always shows the row count plus sums for any
311
+ explicitly-configured numeric columns (each formatted by that column's Cell).
312
+ Rows are fetched through the secured context, so only access-visible data shows.
313
+ Rows are read-only here — a row click navigates to the related record.
314
+
315
+ `@opensaas/stack-core` gains additive item-view config (no breaking changes):
316
+
317
+ ```typescript
318
+ lists: {
319
+
320
+ fields: {
321
+ posts: relationship({
322
+ ref: 'Post.author',
323
+ many: true,
324
+ ui: {
325
+ itemView: {
326
+ // Override the Relationship table's columns…
327
+ columns: ['title', 'status', 'viewCount'],
328
+ // …and sum numeric columns in the totals footer.
329
+ sum: ['viewCount'],
330
+ // Or demote it back to the compact picker in the details card:
331
+ // displayMode: 'picker',
332
+ },
333
+ },
334
+ }),
335
+ },
336
+ // Reorder the Relationship-table sections:
337
+ ui: { itemView: { order: ['posts'] } },
338
+ }),
339
+ }
340
+ ```
341
+
342
+ New `@opensaas/stack-ui` exports: `RelationshipTable`, `RelationshipTableClient`,
343
+ and the pure `deriveItemViewLayout` helper (with `ItemViewLayout`,
344
+ `ItemViewArrangement`, `RelationshipTableSection`). The Relationship table ships
345
+ named Slots (`relationship-table`, `relationship-table-toolbar`,
346
+ `relationship-table-row`, `relationship-table-cell`, `relationship-table-footer`)
347
+ as extension seams for the follow-up inline-edit, create-drawer, and row-removal
348
+ work.
349
+
350
+ - [#774](https://github.com/OpenSaasAU/stack/pull/774) [`62a1612`](https://github.com/OpenSaasAU/stack/commit/62a16127c7b6610a35fb239911eff3486de585be) Thanks [@borisno2](https://github.com/borisno2)! - Bound the admin item-view Relationship tables with a `take` and a "showing N of M" footer
351
+
352
+ The read-only Relationship tables on a record's edit page (issue [#734](https://github.com/OpenSaasAU/stack/issues/734)) previously
353
+ fetched every related row unbounded. They now fetch a bounded page of related rows
354
+ and surface the full access-scoped total in the footer.
355
+
356
+ - **Bounded fetch:** each to-many Relationship table fetches at most a default cap
357
+ of related rows (`DEFAULT_ITEM_VIEW_TAKE`, 10), overridable per relationship via
358
+ `ui.itemView.take`. Rows are still fetched through the secured context, so only
359
+ access-visible rows come back.
360
+ - **"Showing N of M" footer:** the totals footer now reads `Showing N of M rows`,
361
+ where N is the rendered (bounded) count and M is the full access-scoped total,
362
+ fetched via a filtered `_count` that folds the related list's own `query` access
363
+ in (mirroring the list view's count columns). A fully-denied related list reads
364
+ `Showing 0 of 0` and never leaks a true total. The row count is always shown,
365
+ including the zero-column footer path.
366
+
367
+ ```typescript
368
+ sessions: relationship({
369
+ ref: 'Session.user',
370
+ many: true,
371
+ // Cap this table at 5 rows; the footer still shows the full access-scoped total.
372
+ ui: { itemView: { take: 5 } },
373
+ })
374
+ ```
375
+
376
+ Core: `mergeIncludeWithAccessControl` now preserves a caller-supplied `take` on a
377
+ to-many relation include (it only narrows the fetch, never widening past the access
378
+ `where`), so the secured `findUnique`/`findMany` include can bound related-row reads.
379
+
380
+ - [#764](https://github.com/OpenSaasAU/stack/pull/764) [`c210319`](https://github.com/OpenSaasAU/stack/commit/c210319c3b25ff74d832d3c2ec5d3253d5d8b832) Thanks [@list({](https://github.com/list({)! - Admin list view: to-many relationship columns render an access-visible count, sort by relation count, and filter by numeric count comparisons (issue [#732](https://github.com/OpenSaasAU/stack/issues/732)). Virtual fields render via their Cell but are excluded from sorting and filtering.
381
+
382
+ A to-many relationship used as a list column now shows the count of the related rows the session may see — fetched in the SAME query via a filtered Prisma `_count`, with the related list's `query` access folded into the count's `where`, so it never counts rows the session cannot read and issues no per-row query. Clicking the column header sorts by relation `_count`, and its Filter spec offers numeric comparisons on the count (`posts:>5`) in the filter builder and in shared URLs.
383
+
384
+ Because Prisma cannot compare a relation count in a `where`, a to-many relationship's Filter spec emits a structured count marker that is resolved to an access-scoped `{ id: { in } }` before the query runs, through the secured context.
385
+
386
+ New `@opensaas/stack-core` exports: `buildRelationshipCountSelect`, `resolveRelationshipCountFilters`, `isToManyRelationshipField`, and `RELATIONSHIP_COUNT_FILTER_KEY` (with the `RelationshipCountFilterMarker` type).
387
+
388
+ ```ts
389
+ // A to-many relationship column now shows an access-scoped count and is
390
+ // sortable / filterable by that count — zero config:
391
+
392
+ fields: {
393
+ name: text(),
394
+ posts: relationship({ ref: 'Post.author', many: true }),
395
+ },
396
+ })
397
+ // List view: the `posts` column renders the count; its header sorts by count;
398
+ // `posts:>5` filters by count in the builder and in a shared URL.
399
+ ```
400
+
401
+ ### Patch Changes
402
+
403
+ - [#773](https://github.com/OpenSaasAU/stack/pull/773) [`5a60291`](https://github.com/OpenSaasAU/stack/commit/5a602916f30535604b590b875c363f21930a109f) Thanks [@borisno2](https://github.com/borisno2)! - Harden `createRelated` server action: reject malformed calls that supply only one of `field`/`parentId`, and validate that the back-reference names a relationship field before injecting the parent connect.
404
+
405
+ - [#775](https://github.com/OpenSaasAU/stack/pull/775) [`2fcb582`](https://github.com/OpenSaasAU/stack/commit/2fcb5820bc00d9d432265d1ba01404097e296e8e) Thanks [@borisno2](https://github.com/borisno2)! - Return a generic "Action failed" message (and log the real error server-side) when a custom bulk-action handler throws an unexpected non-Prisma error, instead of surfacing its internal message to the client
406
+
407
+ - [#771](https://github.com/OpenSaasAU/stack/pull/771) [`85c7fc3`](https://github.com/OpenSaasAU/stack/commit/85c7fc3b3a0090a986cafa0e46b1798f237264da) Thanks [@borisno2](https://github.com/borisno2)! - Harden relationship count-filter resolution: preserve any sibling conditions co-present in a `_countFilter` marker's AND-member instead of replacing it wholesale, and document why the secured count read intentionally keeps its full projection (`context.db` does not honour `select`).
408
+
409
+ - [#780](https://github.com/OpenSaasAU/stack/pull/780) [`55d55e0`](https://github.com/OpenSaasAU/stack/commit/55d55e0a1ed9521b6e31283524d9194a9420059a) Thanks [@borisno2](https://github.com/borisno2)! - Fix a to-one relationship filter token (e.g. `author:Ada`) leaking related-list data by ANDing the related list's `query` access filter into the nested condition instead of running it unscoped.
410
+
411
+ - [#794](https://github.com/OpenSaasAU/stack/pull/794) [`96e1067`](https://github.com/OpenSaasAU/stack/commit/96e1067661c7ebc8e23896086fec7428e475dd03) Thanks [@borisno2](https://github.com/borisno2)! - Fix multi-column fields (e.g. storage `image()`/`file()` in Keystone-parity mode) writing an unrecognised value silently instead of failing validation. The column split now runs after `validateFieldRules`, not before, at the top-level and nested write paths.
412
+
413
+ ## 0.30.0
414
+
415
+ ### Minor Changes
416
+
417
+ - [#744](https://github.com/OpenSaasAU/stack/pull/744) [`5e135ef`](https://github.com/OpenSaasAU/stack/commit/5e135ef635dd7cd97ab106f46fbf808250aa079e) Thanks [@borisno2](https://github.com/borisno2)! - MCP runtime: serve plugin-registered tools, support Zod input schemas, and pass custom session fields through to access control
418
+
419
+ - Tools registered by plugins via `registerMcpTool` (e.g. the RAG plugin's `semantic_search_*` tools) are now listed by `tools/list` and callable via `tools/call` — previously they were stored but never served.
420
+ - Custom tool `inputSchema` may now be a Zod schema or a plain JSON Schema object. Zod schemas are converted to JSON Schema for `tools/list` and validated on `tools/call` (invalid input returns a JSON-RPC `-32602` error):
421
+
422
+ ```typescript
423
+ mcp: {
424
+ customTools: [
425
+ {
426
+ name: 'publish_post',
427
+ description: 'Publish a draft post',
428
+ inputSchema: z.object({ id: z.string() }),
429
+ handler: async ({ input, context }) => {
430
+ return context.db.post.update({
431
+ where: { id: input.id },
432
+ data: { status: 'published' },
433
+ })
434
+ },
435
+ },
436
+ ]
437
+ }
438
+ ```
439
+
440
+ - MCP sessions now pass custom fields through to access control. Transport fields (`accessToken`, `expiresAt`, `scopes`) are stripped; everything else — `userId` plus any fields your session provider attaches (email, role, ...) — reaches `context.session`, so session-based access rules behave consistently over MCP.
441
+
442
+ ### Patch Changes
443
+
444
+ - [#741](https://github.com/OpenSaasAU/stack/pull/741) [`afa865f`](https://github.com/OpenSaasAU/stack/commit/afa865f62ed7968b494a87e0621cf71bacd36f39) Thanks [@borisno2](https://github.com/borisno2)! - Update documentation links to the restructured docs site URLs (Diátaxis layout)
445
+
3
446
  ## 0.29.0
4
447
 
5
448
  ### Minor Changes
package/CLAUDE.md CHANGED
@@ -273,10 +273,10 @@ const context = createContext<typeof prisma>(config, prisma, session)
273
273
  ### With MCP (Model Context Protocol)
274
274
 
275
275
  - Core provides auth-agnostic MCP runtime via `@opensaas/stack-core/mcp`
276
- - MCP handler reads config to generate tools
277
- - Uses context for all operations (access control enforced)
278
- - Zod schemas from fields validate tool inputs
279
- - Auth adapters (like `@opensaas/stack-auth/mcp`) provide session integration
276
+ - MCP handler reads config to derive tools at request time (CRUD per list, list `mcp.customTools`, plugin-registered tools)
277
+ - Uses context for all operations (access control enforced); writes are validated by the normal `context.db` pipeline (field Zod schemas, hooks, access control)
278
+ - Custom tools may declare a Zod `inputSchema` validated on `tools/call`, converted to JSON Schema for `tools/list` — or a plain JSON Schema object
279
+ - Auth adapters (like `@opensaas/stack-auth/mcp`) provide session integration; custom session fields pass through to access control
280
280
 
281
281
  ### With Third-Party Field Packages
282
282
 
@@ -1 +1 @@
1
- {"version":3,"file":"access-filter.d.ts","sourceRoot":"","sources":["../../src/access/access-filter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AACtE,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAGrE;;;;;;;;;;;;;;GAcG;AAEH;;;GAGG;AACH,wBAAsB,6BAA6B,CACjD,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACzC,IAAI,EAAE;IACJ,OAAO,EAAE,OAAO,GAAG,IAAI,CAAA;IACvB,OAAO,EAAE,aAAa,CAAA;CACvB,EACD,MAAM,EAAE,cAAc,EACtB,KAAK,GAAE,MAAU,EAIjB,YAAY,GAAE,SAAS,MAAM,EAAO;YAeI,YAAY;cAAY,MAAM,CAAC,MAAM,2BAAe;gBAiE7F;AAiDD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,wBAAgB,6BAA6B,CAC3C,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACtC,uBAAuB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAC5D,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACzC,MAAM,EAAE,cAAc,GACrB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAgEzB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAC5C,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACzC,MAAM,EAAE,cAAc,GACrB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAgCrC"}
1
+ {"version":3,"file":"access-filter.d.ts","sourceRoot":"","sources":["../../src/access/access-filter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AACtE,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAGrE;;;;;;;;;;;;;;GAcG;AAEH;;;GAGG;AACH,wBAAsB,6BAA6B,CACjD,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACzC,IAAI,EAAE;IACJ,OAAO,EAAE,OAAO,GAAG,IAAI,CAAA;IACvB,OAAO,EAAE,aAAa,CAAA;CACvB,EACD,MAAM,EAAE,cAAc,EACtB,KAAK,GAAE,MAAU,EAIjB,YAAY,GAAE,SAAS,MAAM,EAAO;YAeI,YAAY;cAAY,MAAM,CAAC,MAAM,2BAAe;gBAiE7F;AAyDD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,wBAAgB,6BAA6B,CAC3C,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACtC,uBAAuB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAC5D,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACzC,MAAM,EAAE,cAAc,GACrB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAmEzB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAC5C,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACzC,MAAM,EAAE,cAAc,GACrB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAgCrC"}
@@ -87,17 +87,26 @@ visitedLists = []) {
87
87
  * Narrow an unknown include value to the structured object form (vs bare `true`
88
88
  * or any other primitive). Caller-supplied includes arrive untyped at the
89
89
  * runtime boundary, so we validate the shape here rather than casting.
90
+ *
91
+ * A numeric `take` on a to-many relation include (a caller-supplied row bound,
92
+ * issue #752) is carried through: it only ever NARROWS the fetched rows and can
93
+ * never widen past the access `where`, so preserving it is access-neutral. The
94
+ * access-controlled include never sets `take` itself — it originates solely
95
+ * from the caller — so `mergeIncludeWithAccessControl` re-attaches it below.
90
96
  */
91
97
  function asEntryObject(value) {
92
98
  if (value && typeof value === 'object') {
93
99
  const obj = value;
94
100
  const where = obj.where;
95
101
  const include = obj.include;
102
+ const take = obj.take;
96
103
  const entry = {};
97
104
  if (where && typeof where === 'object')
98
105
  entry.where = where;
99
106
  if (include && typeof include === 'object')
100
107
  entry.include = include;
108
+ if (typeof take === 'number')
109
+ entry.take = take;
101
110
  return entry;
102
111
  }
103
112
  return null;
@@ -199,7 +208,11 @@ export function mergeIncludeWithAccessControl(callerInclude, accessControlledInc
199
208
  entry.where = mergedWhere;
200
209
  if (mergedNested && Object.keys(mergedNested).length > 0)
201
210
  entry.include = mergedNested;
202
- // A bare-`true` relation with no access filter and no nested include stays `true`.
211
+ // Preserve a caller-supplied row bound on the relation (issue #752). It only
212
+ // narrows, never widens, so it rides on top of the access `where`/include.
213
+ if (callerEntry?.take !== undefined)
214
+ entry.take = callerEntry.take;
215
+ // A bare-`true` relation with no access filter, nested include, or row bound stays `true`.
203
216
  merged[relationName] = Object.keys(entry).length > 0 ? entry : true;
204
217
  }
205
218
  return merged;
@@ -1 +1 @@
1
- {"version":3,"file":"access-filter.js","sourceRoot":"","sources":["../../src/access/access-filter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"access-filter.js","sourceRoot":"","sources":["../../src/access/access-filter.ts"],"names":[],"mappings":"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"}
@@ -113,4 +113,54 @@ describe('mergeIncludeWithAccessControl — bare-true leaf on a cyclic graph', (
113
113
  expect(includeDepth(merged)).toBeLessThanOrEqual(3);
114
114
  });
115
115
  });
116
+ /**
117
+ * A caller-supplied `take` on a to-many relation include must survive the
118
+ * access-controlled merge (issue #752). It only narrows the fetched rows and can
119
+ * never widen past the access `where`, so the merge re-attaches it on top of the
120
+ * per-relation access filter — powering the item view's bounded relationship
121
+ * tables without dropping row-level access.
122
+ */
123
+ describe('mergeIncludeWithAccessControl — caller take on a to-many relation (issue #752)', () => {
124
+ // A one-list config whose `posts` to-many is query-scoped by an access filter.
125
+ function scopedConfig() {
126
+ return {
127
+ db: { provider: 'sqlite', url: 'file:./dev.db' },
128
+ lists: {
129
+ User: {
130
+ fields: { name: { type: 'text' }, posts: rel('Post.author', true) },
131
+ access: { operation: { query: () => true } },
132
+ },
133
+ Post: {
134
+ fields: { title: { type: 'text' }, author: rel('User.posts') },
135
+ // Scoped read access → the merge must fold this into the relation include.
136
+ access: { operation: { query: () => ({ published: { equals: true } }) } },
137
+ },
138
+ },
139
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- minimal config for unit test
140
+ };
141
+ }
142
+ it('preserves the take and AND-combines it with the access where', async () => {
143
+ const config = scopedConfig();
144
+ 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);
146
+ // The bound rides on top of the access filter — neither is dropped. The
147
+ // access-controlled include also auto-nests Post's `author` back-relation.
148
+ expect(merged).toEqual({
149
+ posts: {
150
+ where: { published: { equals: true } },
151
+ include: { author: true },
152
+ take: 10,
153
+ },
154
+ });
155
+ });
156
+ it('drops a take for a relation whose query access is denied', async () => {
157
+ const config = scopedConfig();
158
+ // Deny Post reads entirely.
159
+ config.lists.Post.access = { operation: { query: () => false } };
160
+ 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);
162
+ // A denied relation is dropped wholesale — the take cannot resurrect it.
163
+ expect(merged).toEqual({});
164
+ });
165
+ });
116
166
  //# 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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"}