@jskit-ai/agent-docs 0.1.106 → 0.1.108
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.
|
@@ -1336,8 +1336,8 @@ If the filter contract should be shared with server code, promote it into a CRUD
|
|
|
1336
1336
|
|
|
1337
1337
|
- create `packages/contacts/src/shared/contactListFilters.js`
|
|
1338
1338
|
- create `packages/contacts/src/server/contactListFilterContract.js` with `createCrudListFilterContract(...)`
|
|
1339
|
-
- update `packages/contacts/src/server/registerRoutes.js` so
|
|
1340
|
-
- update `packages/contacts/src/server/actions.js` so
|
|
1339
|
+
- update `packages/contacts/src/server/registerRoutes.js` so `createCrudJsonApiRouteContracts(...)` receives `listFilterQueryValidator: contactListFilterContract.queryValidator`
|
|
1340
|
+
- update `packages/contacts/src/server/actions.js` so `createStandardCrudListQueryValidators(...)` receives the same `listFilterQueryValidator`
|
|
1341
1341
|
- update the provider's `createJsonRestResourceScopeOptions(...)` call so it merges `searchSchema: contactListFilterContract.jsonRestSearchSchema`
|
|
1342
1342
|
- update `packages/contacts/src/server/repository.js` so the list query path passes `contactListFilterContract.toJsonRestQuery(query)` into `buildJsonRestQueryParams(...)`
|
|
1343
1343
|
|
|
@@ -1466,21 +1466,49 @@ That one contract gives the server:
|
|
|
1466
1466
|
- `toJsonRestQuery(query)` for repository query normalization
|
|
1467
1467
|
- `applyQuery(...)` when a non-JSON REST repository still needs direct Knex filtering
|
|
1468
1468
|
|
|
1469
|
-
Wire the contract into route and action
|
|
1469
|
+
Wire the contract independently into the standard route and action query
|
|
1470
|
+
groups:
|
|
1470
1471
|
|
|
1471
1472
|
```js
|
|
1472
|
-
const
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
contactListFilterContract.queryValidator
|
|
1477
|
-
lookupIncludeQueryValidator
|
|
1478
|
-
], {
|
|
1479
|
-
mode: "patch"
|
|
1473
|
+
const {
|
|
1474
|
+
listRouteContract
|
|
1475
|
+
} = createCrudJsonApiRouteContracts({
|
|
1476
|
+
resource,
|
|
1477
|
+
listFilterQueryValidator: contactListFilterContract.queryValidator
|
|
1480
1478
|
});
|
|
1481
1479
|
```
|
|
1482
1480
|
|
|
1483
|
-
|
|
1481
|
+
```js
|
|
1482
|
+
input: composeSchemaDefinitions([
|
|
1483
|
+
workspaceSlugParamsValidator,
|
|
1484
|
+
...createStandardCrudListQueryValidators({
|
|
1485
|
+
resource,
|
|
1486
|
+
listFilterQueryValidator: contactListFilterContract.queryValidator
|
|
1487
|
+
})
|
|
1488
|
+
])
|
|
1489
|
+
```
|
|
1490
|
+
|
|
1491
|
+
This does not couple route and action layers together. Each layer still owns
|
|
1492
|
+
its validator; both consume the same explicit standard group so pagination,
|
|
1493
|
+
search, parent filters, includes, typed sparse fieldsets, and structured
|
|
1494
|
+
filters cannot drift.
|
|
1495
|
+
|
|
1496
|
+
If `resource.contract.listFilters.queryValidator` already owns the filter
|
|
1497
|
+
validator, call `createStandardCrudListQueryValidators({ resource })` instead.
|
|
1498
|
+
Append a validator after the standard group only for genuinely additional,
|
|
1499
|
+
non-filter query input. Never provide the same filter validator through both
|
|
1500
|
+
paths.
|
|
1501
|
+
|
|
1502
|
+
Do not manually reconstruct the standard list group from its individual
|
|
1503
|
+
validators. Standard view actions likewise compose:
|
|
1504
|
+
|
|
1505
|
+
```js
|
|
1506
|
+
input: composeSchemaDefinitions([
|
|
1507
|
+
workspaceSlugParamsValidator,
|
|
1508
|
+
recordIdParamsValidator,
|
|
1509
|
+
...createStandardCrudViewQueryValidators()
|
|
1510
|
+
])
|
|
1511
|
+
```
|
|
1484
1512
|
|
|
1485
1513
|
Merge the JSON REST search schema when the provider registers the resource:
|
|
1486
1514
|
|
|
@@ -1532,6 +1560,13 @@ Choose the invalid-value contract deliberately:
|
|
|
1532
1560
|
- Keep client-only filters in the generated page-local `listFilters.js`. Move definitions into a CRUD package only when server code or another page needs to share them.
|
|
1533
1561
|
- Keep the filter keys identical all the way through: definition key, query param key, and repository meaning.
|
|
1534
1562
|
- Prefer `createCrudListFilterContract(...)` for server-backed structured filters so route/action validators, JSON REST search schema, and repository query normalization stay derived from one shared definition.
|
|
1563
|
+
- Compose standard list and view query validators with
|
|
1564
|
+
`createStandardCrudListQueryValidators(...)` and
|
|
1565
|
+
`createStandardCrudViewQueryValidators()` rather than repeating the
|
|
1566
|
+
individual standard validators.
|
|
1567
|
+
- Pass a server-backed structured-filter validator through
|
|
1568
|
+
`listFilterQueryValidator`; append validators separately only for
|
|
1569
|
+
additional non-filter query input.
|
|
1535
1570
|
- Use `type: "presence"` for null/not-null filters such as assigned vs unassigned storage. Do not model those as custom enums plus `applyQuery(...)` overrides unless the SQL semantics are genuinely different from `whereNotNull(...)` / `whereNull(...)`.
|
|
1536
1571
|
- Use `createCrudListFilters(...)` directly only for non-JSON REST repository code that needs direct Knex filtering without JSON REST registration.
|
|
1537
1572
|
- Use `q` for free-text and explicit query params for structured filters.
|
|
@@ -424,6 +424,22 @@ The same rule applies after later server scaffolds such as `addresses` and `comm
|
|
|
424
424
|
|
|
425
425
|
For standard CRUDs, that file is intentionally compact. It uses `defineCrudResource(...)` from `@jskit-ai/resource-crud-core`, authors the canonical `schema` / `searchSchema` / `defaultSort` / `autofilter` shape once, and lets JSKIT derive the standard CRUD operation contracts from it.
|
|
426
426
|
|
|
427
|
+
The generated server action validators are compact for the same reason.
|
|
428
|
+
Standard list actions compose
|
|
429
|
+
`createStandardCrudListQueryValidators({ resource })`; standard view actions
|
|
430
|
+
compose `createStandardCrudViewQueryValidators()`. Do not expand those groups
|
|
431
|
+
back into individual pagination, search, parent-filter, include, or
|
|
432
|
+
sparse-field validators.
|
|
433
|
+
|
|
434
|
+
When a CRUD adds a server-backed structured-filter contract, pass its
|
|
435
|
+
`queryValidator` through the list group's dedicated
|
|
436
|
+
`listFilterQueryValidator` option. If
|
|
437
|
+
`resource.contract.listFilters.queryValidator` already owns it, `{ resource }`
|
|
438
|
+
is sufficient. A validator belongs after the standard group only when it is
|
|
439
|
+
genuinely additional, non-filter query input. This keeps route and action
|
|
440
|
+
validation independent while preventing the two boundaries from drifting as
|
|
441
|
+
the standard query contract evolves.
|
|
442
|
+
|
|
427
443
|
### Step 3: scaffold the UI
|
|
428
444
|
|
|
429
445
|
Once the resource file exists, generate the UI route tree:
|
package/package.json
CHANGED
package/patterns/filters.md
CHANGED
|
@@ -60,19 +60,58 @@ Server-side pattern, only when implementing real backend filter semantics:
|
|
|
60
60
|
1. Put reusable filter definitions in the CRUD package if server code or multiple pages need the same contract.
|
|
61
61
|
Example path: `packages/<crud>/src/shared/<crud>ListFilters.js`
|
|
62
62
|
2. Build a server contract from that module with `createCrudListFilterContract(...)`.
|
|
63
|
-
3.
|
|
63
|
+
3. Pass the contract's `queryValidator` through the dedicated
|
|
64
|
+
`listFilterQueryValidator` option of the standard CRUD list validator group
|
|
65
|
+
at both the route and action boundaries.
|
|
64
66
|
4. Pass the contract's `jsonRestSearchSchema` into `createJsonRestResourceScopeOptions(..., { searchSchema })`.
|
|
65
67
|
5. Call `contract.toJsonRestQuery(query)` before `buildJsonRestQueryParams(...)` in the JSON REST repository path.
|
|
66
68
|
|
|
67
69
|
Exact file checklist:
|
|
68
70
|
- create `packages/<crud>/src/shared/<crud>ListFilters.js`
|
|
69
71
|
- create `packages/<crud>/src/server/<crud>ListFilterContract.js` with `createCrudListFilterContract(...)`
|
|
70
|
-
- update `packages/<crud>/src/server/registerRoutes.js`
|
|
72
|
+
- update `packages/<crud>/src/server/registerRoutes.js` so
|
|
73
|
+
`createCrudJsonApiRouteContracts(...)` receives
|
|
74
|
+
`listFilterQueryValidator: listFilterContract.queryValidator`
|
|
75
|
+
- update `packages/<crud>/src/server/actions.js` so
|
|
76
|
+
`createStandardCrudListQueryValidators(...)` receives the same
|
|
77
|
+
`listFilterQueryValidator`
|
|
71
78
|
- update the provider's `createJsonRestResourceScopeOptions(...)` call so `searchSchema: listFilterContract.jsonRestSearchSchema` is merged into the internal JSON REST resource
|
|
72
79
|
- update `packages/<crud>/src/server/repository.js` so list queries pass `listFilterContract.toJsonRestQuery(query)` into `buildJsonRestQueryParams(...)`
|
|
73
80
|
- update the generated page-local `listFilters.js` first; only edit `index.vue` if a specialist lookup label/runtime integration is needed
|
|
74
81
|
- for lookup-backed filters, wire `useCrudListFilterLookups(...)` beside the existing generated filter runtime instead of replacing `CrudListFilterSurface`
|
|
75
82
|
|
|
83
|
+
Standard route and action query composition:
|
|
84
|
+
|
|
85
|
+
```js
|
|
86
|
+
const {
|
|
87
|
+
listRouteContract
|
|
88
|
+
} = createCrudJsonApiRouteContracts({
|
|
89
|
+
resource,
|
|
90
|
+
listFilterQueryValidator: recordsListFilterContract.queryValidator
|
|
91
|
+
});
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
```js
|
|
95
|
+
input: composeSchemaDefinitions([
|
|
96
|
+
workspaceSlugParamsValidator,
|
|
97
|
+
...createStandardCrudListQueryValidators({
|
|
98
|
+
resource,
|
|
99
|
+
listFilterQueryValidator: recordsListFilterContract.queryValidator
|
|
100
|
+
})
|
|
101
|
+
])
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
If `resource.contract.listFilters.queryValidator` already owns the filter
|
|
105
|
+
validator, pass only `{ resource }`. Append a validator after the standard
|
|
106
|
+
group only for genuinely additional, non-filter query input. Never supply the
|
|
107
|
+
same filter validator through both paths.
|
|
108
|
+
|
|
109
|
+
Do not reconstruct the standard list group from individual pagination,
|
|
110
|
+
search, parent-filter, include, or sparse-field validators. The group keeps
|
|
111
|
+
the independently validated route and action layers aligned as standard query
|
|
112
|
+
features evolve. Standard view actions use
|
|
113
|
+
`createStandardCrudViewQueryValidators()` for the same reason.
|
|
114
|
+
|
|
76
115
|
Validation mode is part of the contract:
|
|
77
116
|
- `createCrudListFilterContract(...)` defaults to `invalidValues: "reject"` for a strict server boundary
|
|
78
117
|
- set `invalidValues` explicitly when a package is choosing a non-default validation posture
|
|
@@ -111,6 +150,8 @@ Avoid:
|
|
|
111
150
|
- local filter composables that duplicate the same keys the server already knows about
|
|
112
151
|
- a custom validator shape that does not match the page state
|
|
113
152
|
- hand-rolled route/action validators or repository filters that duplicate `createCrudListFilterContract(...)`
|
|
153
|
+
- manually rebuilding the standard CRUD list/view validator groups from individual validators
|
|
154
|
+
- appending a list-filter validator after `createStandardCrudListQueryValidators(...)` when it belongs in the dedicated `listFilterQueryValidator` option
|
|
114
155
|
- hand-rolled preset apply/reset/active-state helpers when `useCrudListFilters(..., { presets })`, `applyPreset(...)`, and `matchesPreset(...)` fit
|
|
115
156
|
- per-screen `useList()` wrappers for lookup-backed filters when `useCrudListFilterLookups(...)` fits
|
|
116
157
|
- editing generated `.vue` files just to add basic filter controls; use the page-local `listFilters.js` seam first
|
|
@@ -139,6 +180,10 @@ Preset contract notes:
|
|
|
139
180
|
Review checks:
|
|
140
181
|
- one filter definition source of truth: generated page-local `listFilters.js` for client-only filters, or a shared CRUD-package module when server code imports the same definitions
|
|
141
182
|
- server validator, JSON REST search schema, and repository query projection derived from that source through `createCrudListFilterContract(...)`
|
|
183
|
+
- route and action boundaries independently compose
|
|
184
|
+
`createStandardCrudListQueryValidators(...)`, using the dedicated
|
|
185
|
+
`listFilterQueryValidator` option when the resource does not already own it
|
|
186
|
+
- standard view actions compose `createStandardCrudViewQueryValidators()`
|
|
142
187
|
- client query params/chips/reset logic derived from that source
|
|
143
188
|
- initial route/default resolution completes before the first list request
|
|
144
189
|
- lookup-backed filters use the shared lookup helper, not a page-local mini-framework
|
|
@@ -128,26 +128,40 @@ Keep `applyFilter` focused on query semantics:
|
|
|
128
128
|
- do not put permission checks there
|
|
129
129
|
- do not turn it into a second service layer
|
|
130
130
|
|
|
131
|
-
Add
|
|
131
|
+
Add public query validation when:
|
|
132
132
|
- the filter key is public and may arrive from HTTP query params
|
|
133
133
|
- the page/UI needs a stable, validated query contract
|
|
134
134
|
- malformed values should either be rejected or deliberately discarded
|
|
135
135
|
|
|
136
|
-
|
|
136
|
+
For standard CRUD routes and actions, pass the structured-filter validator
|
|
137
|
+
through the standard group's dedicated option:
|
|
137
138
|
|
|
138
139
|
```js
|
|
139
140
|
input: composeSchemaDefinitions([
|
|
140
141
|
workspaceSlugParamsValidator,
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
142
|
+
...createStandardCrudListQueryValidators({
|
|
143
|
+
resource,
|
|
144
|
+
listFilterQueryValidator: vetsListFilterContract.queryValidator
|
|
145
|
+
})
|
|
144
146
|
])
|
|
145
147
|
```
|
|
146
148
|
|
|
147
149
|
That means:
|
|
148
|
-
- `q
|
|
150
|
+
- pagination, `q`, parent filters, includes, sparse fieldsets, and the
|
|
151
|
+
structured filter keys remain one standard group
|
|
149
152
|
- the repository may still add internal-only keys later
|
|
150
153
|
|
|
154
|
+
Use the same `listFilterQueryValidator` option with
|
|
155
|
+
`createCrudJsonApiRouteContracts(...)` at the route boundary. The layers
|
|
156
|
+
remain independently validated; they share a small standard validator group
|
|
157
|
+
rather than duplicating its current members.
|
|
158
|
+
|
|
159
|
+
If `resource.contract.listFilters.queryValidator` already owns the filter
|
|
160
|
+
validator, call `createStandardCrudListQueryValidators({ resource })`.
|
|
161
|
+
Append validators separately only for genuinely additional, non-filter query
|
|
162
|
+
input. Standard view actions use
|
|
163
|
+
`createStandardCrudViewQueryValidators()`.
|
|
164
|
+
|
|
151
165
|
For structured list filters, prefer the generated contract shape:
|
|
152
166
|
|
|
153
167
|
```js
|
|
@@ -229,5 +243,5 @@ function buildScopedQuery(query = {}, context = null) {
|
|
|
229
243
|
- Same key, same field, simple behavior: `search: true`
|
|
230
244
|
- Public alias or multi-field search: `searchSchema`
|
|
231
245
|
- Complex SQL semantics: `searchSchema` + `applyFilter`
|
|
232
|
-
- Public HTTP query key: add
|
|
246
|
+
- Public HTTP query key: add it through the standard route/action query group
|
|
233
247
|
- Internal-only repository key: inject it in `repository.js`, skip the public validator
|