@jskit-ai/agent-docs 0.1.101 → 0.1.103
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/guide/agent/app-setup/database-layer.md +56 -0
- package/guide/agent/generators/crud-generators.md +44 -0
- package/package.json +1 -1
- package/patterns/client-requests.md +8 -0
- package/patterns/crud-scaffolding.md +35 -0
- package/patterns/filters.md +24 -0
- package/reference/autogen/KERNEL_MAP.md +7 -0
- package/reference/autogen/packages/crud-core.md +1 -0
- package/reference/autogen/packages/http-runtime.md +7 -4
- package/reference/autogen/packages/json-rest-api-core.md +4 -0
- package/reference/autogen/packages/kernel.md +7 -0
- package/reference/autogen/packages/users-web.md +15 -11
- package/reference/autogen/tooling/jskit-cli.md +13 -0
|
@@ -96,6 +96,16 @@ The app has two different migration-related layers:
|
|
|
96
96
|
|
|
97
97
|
Those are **not** the same step.
|
|
98
98
|
|
|
99
|
+
There is also an important ownership distinction:
|
|
100
|
+
|
|
101
|
+
- a CRUD generator owns the installed baseline migration for the table it
|
|
102
|
+
scaffolds
|
|
103
|
+
- the table's app-local package owns later additive schema evolution
|
|
104
|
+
|
|
105
|
+
Never modify or replace a generator-owned baseline migration. Later schema
|
|
106
|
+
evolution must use a new immutable, package-owned additive migration in the
|
|
107
|
+
table's app-local package, declared through `install-migration`.
|
|
108
|
+
|
|
99
109
|
The npm scripts hide the easy-to-miss first step for normal use. `npm run db:migrate` and `npm run db:migrate:status` run `npm run db:migrations:sync` first, then run Knex. That means package upgrades can add new JSKIT-managed migration files before Knex checks what is pending.
|
|
100
110
|
|
|
101
111
|
### `jskit migrations ...` writes managed migration files
|
|
@@ -157,6 +167,52 @@ So:
|
|
|
157
167
|
- sometimes you need only `npm run db:migrate`
|
|
158
168
|
- sometimes, after repair or re-materialization work, you need **both**
|
|
159
169
|
|
|
170
|
+
### Authoring a later app-owned schema change
|
|
171
|
+
|
|
172
|
+
When an existing CRUD-owned table needs a new column, constraint, index, or
|
|
173
|
+
other compatible evolution, keep the generated baseline unchanged. Ask JSKIT
|
|
174
|
+
to create a new migration source in the app-local package that owns the table:
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
npx jskit create migration \
|
|
178
|
+
--package @local/workflow-record-report-values \
|
|
179
|
+
--id extend-report-value-field-types
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
This command:
|
|
183
|
+
|
|
184
|
+
1. verifies that the owner is an installed app-local package
|
|
185
|
+
2. rejects duplicate or unsafe migration ids
|
|
186
|
+
3. creates an editable template under the package's
|
|
187
|
+
`templates/migrations/` directory
|
|
188
|
+
4. adds the matching `install-migration` mutation to the package descriptor
|
|
189
|
+
5. leaves the migration unmaterialized so its implementation can still be
|
|
190
|
+
completed
|
|
191
|
+
|
|
192
|
+
Implement and test the template first. It intentionally fails if someone tries
|
|
193
|
+
to apply the untouched scaffold. Then materialize and apply it:
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
npx jskit migrations package @local/workflow-record-report-values
|
|
197
|
+
npm run db:migrate
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
The materialized migration and its lock record are managed artifacts. Once
|
|
201
|
+
installed, the migration id and content are immutable. Any later correction
|
|
202
|
+
must use another additive migration with a new id.
|
|
203
|
+
|
|
204
|
+
SQL inside the source-controlled migration is supported when Knex does not
|
|
205
|
+
express the required schema operation directly. Ad-hoc SQL applied only to a
|
|
206
|
+
development or live database is not a migration and must not be used: it
|
|
207
|
+
creates schema drift, breaks fresh reconstruction, and leaves deployment
|
|
208
|
+
history incomplete.
|
|
209
|
+
|
|
210
|
+
Before completion, exercise the complete migration chain against a fresh
|
|
211
|
+
disposable database as well as the intended upgrade path. A down migration
|
|
212
|
+
must refuse safely when narrowing the schema would invalidate existing data;
|
|
213
|
+
it must never delete or silently transform valuable rows merely to make a
|
|
214
|
+
rollback pass.
|
|
215
|
+
|
|
160
216
|
### Shared database helpers
|
|
161
217
|
|
|
162
218
|
The database layer also gives later server code a shared helper surface:
|
|
@@ -286,6 +286,25 @@ The exact fields will vary by app. What matters for the generator is:
|
|
|
286
286
|
- the column names are stable enough to become part of your app's resource contract
|
|
287
287
|
- if you are using `crud-server-generator`, do **not** hand-write a separate CRUD migration for this table; the server generator installs the CRUD migration scaffold itself
|
|
288
288
|
|
|
289
|
+
That last rule governs the generated baseline, not every future schema change.
|
|
290
|
+
Never modify or replace a generator-owned baseline migration after it has been
|
|
291
|
+
installed. Later schema evolution must use a new immutable, package-owned
|
|
292
|
+
additive migration in the table's app-local package, declared through
|
|
293
|
+
`install-migration`.
|
|
294
|
+
|
|
295
|
+
Create that source and descriptor mutation together with:
|
|
296
|
+
|
|
297
|
+
```bash
|
|
298
|
+
npx jskit create migration \
|
|
299
|
+
--package @local/contacts \
|
|
300
|
+
--id add-contact-status
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
Implement the generated template before running
|
|
304
|
+
`npx jskit migrations package @local/contacts`. SQL or Knex schema operations
|
|
305
|
+
inside the source-controlled migration are supported. Running ad-hoc SQL
|
|
306
|
+
against only one database is not, because it creates schema drift.
|
|
307
|
+
|
|
289
308
|
In this table, `workspace_id` is the important ownership clue. That is why the next step uses:
|
|
290
309
|
|
|
291
310
|
```bash
|
|
@@ -425,6 +444,31 @@ That creates the baseline CRUD route tree:
|
|
|
425
444
|
- `w/[workspaceSlug]/admin/contacts/[contactId]/edit.vue`
|
|
426
445
|
- shared `_components` files under the same route root
|
|
427
446
|
|
|
447
|
+
Generated list, view, and lookup reads use the resource contract as their
|
|
448
|
+
response authority. They return every field declared for output by default,
|
|
449
|
+
including the target resource's declared output when a lookup relation is
|
|
450
|
+
hydrated; generated pages do not repeat those fields in a second page-owned
|
|
451
|
+
allowlist. Adding an output field or lookup to the resource therefore does not
|
|
452
|
+
require regenerating endpoint projections.
|
|
453
|
+
|
|
454
|
+
Put exceptional large fields in the resource-owned default response blacklist,
|
|
455
|
+
`resource.contract.response.defaultExclude`:
|
|
456
|
+
|
|
457
|
+
```js
|
|
458
|
+
contract: {
|
|
459
|
+
response: {
|
|
460
|
+
defaultExclude: ["rawPayload", "largeAuditJson"]
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
Each included resource applies its own blacklist. A default-excluded field is
|
|
466
|
+
still part of the public output contract and can be requested through an
|
|
467
|
+
explicit typed JSON:API `fields[type]` fieldset. Use that sparse-field override
|
|
468
|
+
only for a specialised caller; do not add one to ordinary generated pages or
|
|
469
|
+
build a page-local query-string adapter. Fields that must never be exposed do
|
|
470
|
+
not belong in the output schema at all.
|
|
471
|
+
|
|
428
472
|
This is the most important mental model in the whole chapter:
|
|
429
473
|
|
|
430
474
|
- `crud-server-generator` creates the reusable CRUD contract and server package
|
package/package.json
CHANGED
|
@@ -49,6 +49,7 @@ Generated screen wrapper extension rules:
|
|
|
49
49
|
- Use `useCrudListScreen({ readEnabled })` for permission-gated generated list reads instead of splitting the page or replacing the shared list screen.
|
|
50
50
|
- Use `useCrudListScreen({ requestQueryParams })` for list includes or other endpoint query params instead of putting query strings in `apiSuffix`.
|
|
51
51
|
- Use `useCrudViewScreen({ requestQueryParams })` for detail includes instead of putting query strings in `apiUrlTemplate`.
|
|
52
|
+
- Use `requestFieldsets` only when a specialised caller intentionally needs a typed JSON:API sparse fieldset. Ordinary generated reads use the complete resource output contract.
|
|
52
53
|
- Use `readEnabled` and `queryKeyFactory` on `useCrudViewScreen()` when the detail read needs the same gating or cache identity control as `useCrudView()`.
|
|
53
54
|
- Use `CrudViewScreen` slots (`before-fields`, `fields`, `after-fields`, `supporting-content`) for page-specific domain sections while keeping shared load/error/retry chrome.
|
|
54
55
|
- Use `listRowActions` with `defineCrudListRowActions(...)` for row-level commands in `CrudListScreen`.
|
|
@@ -72,6 +73,11 @@ Why this is the standard JSKIT shape:
|
|
|
72
73
|
- `usersWebHttpClient` already handles credentials and CSRF behavior.
|
|
73
74
|
- `useEndpointResource()` is the shared endpoint primitive for loading, saving, and standard load/save error handling. Higher-level runtimes add UI feedback and field-error handling on top.
|
|
74
75
|
- Use `requestQueryParams` for endpoint query strings on list, view, and add/edit runtimes.
|
|
76
|
+
- Generated CRUD and lookup reads use all resource-defined output fields by default. Hydrated relationships use the target resource's output contract. Generated pages and lookup controls do not repeat those definitions as request fieldsets.
|
|
77
|
+
- Put exceptional large fields in `resource.contract.response.defaultExclude`. The target resource owns that default even when it is included by another resource.
|
|
78
|
+
- `requestFieldsets` remains an explicit specialised override and accepts the canonical typed shape, for example `{ jobs: ["id", "status"], contacts: ["id", "displayName"] }`. It participates in both the request and the query cache key.
|
|
79
|
+
- Sparse fieldsets are a serialization boundary, not an authorization mechanism. Server resources reject unknown fields, never serialize hidden fields, and preserve the fields needed internally for relationship linkage.
|
|
80
|
+
- Fields that must never be exposed do not belong in the resource output schema.
|
|
75
81
|
- Keep `apiUrlTemplate` path-only. Do not put `?include=...` or other query strings in URL templates.
|
|
76
82
|
- If an app needs route-aware API URL rewriting, configure the users-web client once with `configureUsersWebHttpClient({ resolveRequestUrl })` before mounting the app. Do not replace `fetchImpl` just to rewrite paths.
|
|
77
83
|
- `resolveRequestUrl` belongs at the HTTP client boundary. It runs after JSKIT encodes query params and before browser `fetch`, so reads, commands, request recovery metadata, JSON:API transport, credentials, and CSRF behavior stay on the standard path.
|
|
@@ -96,6 +102,8 @@ Avoid:
|
|
|
96
102
|
- manually concatenating scoped route params into API URLs
|
|
97
103
|
- using a lower-level seam when a higher-level routed CRUD or command runtime already fits
|
|
98
104
|
- smuggling query params into `apiUrlTemplate`
|
|
105
|
+
- hand-building `fields[type]` parameters or page-local sparse-response adapters
|
|
106
|
+
- repeating resource output fields as page-owned request allowlists
|
|
99
107
|
- replacing `CrudListScreen` or `CrudViewScreen` only to add read gating, row actions, synthetic display rows, includes, or domain detail sections
|
|
100
108
|
- reporting routine resource load errors through hand-written global snackbar/banner calls
|
|
101
109
|
- calling `useShellRequestRecoveryRuntime().report(...)` from normal panels just to recover an HTTP read
|
|
@@ -51,6 +51,9 @@ Rules:
|
|
|
51
51
|
- If the table should already be CRUD-owned but should not expose public CRUD HTTP routes yet, scaffold it with `jskit generate crud-server-generator scaffold ... --internal` instead of dropping to direct knex or a hand-built pseudo-repository.
|
|
52
52
|
- Create the real table directly in the database before scaffolding. `crud-server-generator` reads the live table shape.
|
|
53
53
|
- If `crud-server-generator` is going to own the CRUD, do not hand-write a separate CRUD migration for that table. The generator installs and manages the CRUD migration scaffold itself.
|
|
54
|
+
- Never modify or replace a generator-owned baseline migration after it has
|
|
55
|
+
been installed. Later schema evolution must use a new immutable,
|
|
56
|
+
package-owned additive migration declared through `install-migration`.
|
|
54
57
|
- Keep generated table creation in `migrations/` and generated foreign keys in
|
|
55
58
|
`migrations/constraints/`. The database runtime deliberately runs those
|
|
56
59
|
phases in that order so valid mutual foreign keys rebuild cleanly without
|
|
@@ -72,6 +75,38 @@ Rules:
|
|
|
72
75
|
- Structured filters should use shared filter definitions and collapse to compact filter controls/sheets when they outgrow simple search. Do not stack dense desktop filter bars on phone widths.
|
|
73
76
|
- Use `--navigation-role` for CRUD list placement intent. Main resources can stay `primary`; nested/detail/workflow CRUD routes should usually be `secondary`, `workflow`, or `none`.
|
|
74
77
|
|
|
78
|
+
## Baseline generation versus later schema evolution
|
|
79
|
+
|
|
80
|
+
The initial CRUD scaffold and a later schema change are different operations:
|
|
81
|
+
|
|
82
|
+
- The server generator owns the baseline migration that recreates the table
|
|
83
|
+
from zero. Do not edit, replace, or regenerate that installed baseline to
|
|
84
|
+
express a later change.
|
|
85
|
+
- The table's app-local package owns later schema evolution. Create each change
|
|
86
|
+
as a new immutable additive migration:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
npx jskit create migration \
|
|
90
|
+
--package @local/workflow-record-report-values \
|
|
91
|
+
--id extend-report-value-field-types
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
- The authoring command creates an editable migration template and adds its
|
|
95
|
+
`install-migration` mutation to the owning package descriptor in one
|
|
96
|
+
operation. Implement and test the template before materializing it.
|
|
97
|
+
- Materialize the completed source with
|
|
98
|
+
`npx jskit migrations package <package-id>`, then apply it with
|
|
99
|
+
`npm run db:migrate`.
|
|
100
|
+
- SQL or Knex schema operations inside that source-controlled migration are
|
|
101
|
+
supported. Ad-hoc SQL applied only to one database is not: it creates schema
|
|
102
|
+
drift and leaves fresh installations incorrect.
|
|
103
|
+
- Installed migration ids and content are immutable. A correction to an
|
|
104
|
+
installed migration is another additive migration with a new id.
|
|
105
|
+
|
|
106
|
+
A package-owned additive migration is not the prohibited "separate CRUD
|
|
107
|
+
migration." The prohibition applies to competing with or modifying the
|
|
108
|
+
generator-owned baseline.
|
|
109
|
+
|
|
75
110
|
Meaning of `--internal`:
|
|
76
111
|
|
|
77
112
|
- it keeps the generated repository, service, actions, provider, resource, and CRUD migration ownership chain
|
package/patterns/filters.md
CHANGED
|
@@ -13,6 +13,7 @@ Ask first:
|
|
|
13
13
|
- which fields are filterable
|
|
14
14
|
- whether each filter is a flag, enum, multi-enum, date/date-range, number-range, record id, or lookup-backed record id
|
|
15
15
|
- whether filters must sync to the route query
|
|
16
|
+
- whether a filter needs a default before the first request
|
|
16
17
|
- whether the screen needs chips and clear/reset behavior
|
|
17
18
|
- whether lookup filters need remote autocomplete search
|
|
18
19
|
- whether there are presets such as "Today", "Last 7 Days", or "Only Archived"
|
|
@@ -25,6 +26,27 @@ Default JSKIT client pattern:
|
|
|
25
26
|
5. The AI/app author is responsible for ensuring the server accepts and applies the query params declared in `listFilters.js`.
|
|
26
27
|
6. For lookup-backed filters, use `useCrudListFilterLookups(...)` when the page needs remote options or readable chip labels.
|
|
27
28
|
|
|
29
|
+
Initial-value contract:
|
|
30
|
+
- declare a pre-query default with `defaultValue` in the filter definition
|
|
31
|
+
- a valid route-query value wins over `defaultValue`
|
|
32
|
+
- when the initial route has no value, `defaultValue` is applied before list reading is enabled
|
|
33
|
+
- an invalid initial route value falls back to `defaultValue`
|
|
34
|
+
- clearing a filter after initialization produces the empty value; it does not reapply the default
|
|
35
|
+
- route back/forward navigation rehydrates the same filter state without an early unfiltered request
|
|
36
|
+
|
|
37
|
+
```js
|
|
38
|
+
const listFilters = defineCrudListFilters({
|
|
39
|
+
currentness: {
|
|
40
|
+
type: "enum",
|
|
41
|
+
defaultValue: "active",
|
|
42
|
+
options: [
|
|
43
|
+
{ value: "active", label: "Active" },
|
|
44
|
+
{ value: "archived", label: "Archived" }
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
```
|
|
49
|
+
|
|
28
50
|
Generated client shape:
|
|
29
51
|
- `src/pages/<surface>/<resource>/listFilters.js`
|
|
30
52
|
- `const listFilters = defineCrudListFilters({ ... })`
|
|
@@ -94,6 +116,7 @@ Avoid:
|
|
|
94
116
|
- editing generated `.vue` files just to add basic filter controls; use the page-local `listFilters.js` seam first
|
|
95
117
|
- overloading `q` with structured filter meaning
|
|
96
118
|
- inline filter-definition objects passed into `useCrudListFilters(...)`, `createCrudListFilters(...)`, or `createCrudListFilterContract(...)`; keep definitions in a named module
|
|
119
|
+
- assigning a default to `filterRuntime.values` after `useCrudListScreen(...)` has started; that changes the query after construction and can issue a second initial request
|
|
97
120
|
|
|
98
121
|
Good shape:
|
|
99
122
|
- `src/pages/home/customers/listFilters.js`
|
|
@@ -117,5 +140,6 @@ Review checks:
|
|
|
117
140
|
- 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
|
|
118
141
|
- server validator, JSON REST search schema, and repository query projection derived from that source through `createCrudListFilterContract(...)`
|
|
119
142
|
- client query params/chips/reset logic derived from that source
|
|
143
|
+
- initial route/default resolution completes before the first list request
|
|
120
144
|
- lookup-backed filters use the shared lookup helper, not a page-local mini-framework
|
|
121
145
|
- the two-phase server exception is intentional and documented, not accidental drift
|
|
@@ -64,6 +64,7 @@ Exports
|
|
|
64
64
|
- `parseCrudListRangeQueryExpression(value = null)`
|
|
65
65
|
- `formatCrudListRangeQueryExpression(startValue = "", endValue = "", { collapseExact = false } = {})`
|
|
66
66
|
- `defineCrudListFilters(definitions = {})`
|
|
67
|
+
- `createCrudListFilterEmptyValue(filter = {})`
|
|
67
68
|
- `createCrudListFilterInitialValue(filter = {})`
|
|
68
69
|
- `isCrudListFilterMultiValue(filter = {})`
|
|
69
70
|
- `isCrudListFilterStructuredValue(filter = {})`
|
|
@@ -171,6 +172,12 @@ Exports
|
|
|
171
172
|
- `shouldRetryTransientQueryFailure`
|
|
172
173
|
- `transientQueryRetryDelay`
|
|
173
174
|
|
|
175
|
+
### `support/jsonApiFieldsets.js`
|
|
176
|
+
Exports
|
|
177
|
+
- `normalizeJsonApiFieldList(value = [])`
|
|
178
|
+
- `normalizeJsonApiFieldsets(value = {}, { primaryType = "" } = {})`
|
|
179
|
+
- `buildJsonApiFieldsetsToken(value = {})`
|
|
180
|
+
|
|
174
181
|
### `support/linkPath.js`
|
|
175
182
|
Exports
|
|
176
183
|
- `isExternalLinkTarget(target = "")`
|
|
@@ -165,6 +165,7 @@ Exports
|
|
|
165
165
|
- `createCrudCursorPaginationQueryValidator(list = {})`
|
|
166
166
|
- `listSearchQueryValidator`
|
|
167
167
|
- `lookupIncludeQueryValidator`
|
|
168
|
+
- `jsonApiFieldsetsQueryValidator`
|
|
168
169
|
- `resolveCrudParentFilterKeys(resource = {})`
|
|
169
170
|
- `createCrudParentFilterQueryValidator(resource = {})`
|
|
170
171
|
Local functions
|
|
@@ -247,6 +247,9 @@ Local functions
|
|
|
247
247
|
- `isRecord(value)`
|
|
248
248
|
- `normalizeQueryKey(key = "")`
|
|
249
249
|
- `buildFieldsTransportKey(responseType = "")`
|
|
250
|
+
- `parseFieldsTransportType(key = "")`
|
|
251
|
+
- `addJsonApiFieldset(fieldsets, type = "", value = [])`
|
|
252
|
+
- `createJsonApiFieldsTransportValueSchema()`
|
|
250
253
|
- `normalizeTransportQueryScalar(value)`
|
|
251
254
|
|
|
252
255
|
### `src/shared/validators/jsonApiResponses.js`
|
|
@@ -272,18 +275,18 @@ Local functions
|
|
|
272
275
|
### `src/shared/validators/jsonApiRouteTransport.js`
|
|
273
276
|
Exports
|
|
274
277
|
- `JSON_API_ERROR_DOCUMENT_SCHEMA`
|
|
275
|
-
- `createJsonApiResourceObjectTransportSchema({ type = "", attributes, requireId = true, includeLinks = false, includeMeta = false, excludeAttributeKeys = [], relationshipEntries = [], relationshipMembersRequired = false } = {})`
|
|
278
|
+
- `createJsonApiResourceObjectTransportSchema({ type = "", attributes, requireId = true, includeLinks = false, includeMeta = false, excludeAttributeKeys = [], relationshipEntries = [], relationshipMembersRequired = false, allowSparseFields = false } = {})`
|
|
276
279
|
- `createJsonApiResourceRequestBodyTransportSchema({ type = "", attributes, requireId = false, excludeAttributeKeys = [], relationshipEntries = [] } = {})`
|
|
277
|
-
- `createJsonApiResourceSuccessTransportSchema({ type = "", attributes, kind = "record", includeLinks = false, includeMeta = false, includeIncluded = false, excludeAttributeKeys = [], relationshipEntries = [] } = {})`
|
|
280
|
+
- `createJsonApiResourceSuccessTransportSchema({ type = "", attributes, kind = "record", includeLinks = false, includeMeta = false, includeIncluded = false, allowSparseFields = false, excludeAttributeKeys = [], relationshipEntries = [] } = {})`
|
|
278
281
|
- `withJsonApiErrorResponses(successResponses, { includeValidation400 = false } = {})`
|
|
279
282
|
- `createJsonApiResourceRouteTransport({ type = "", requestType = "", responseType = "", query = null, allowBodyId = false, successKind = "record", pointerPrefix = "/data/attributes", mapRequestRelationships = null, getRecordType = null, getRecordId = null, getRecordAttributes = null, getRecordRelationships = null, getRecordLinks = null, getRecordMeta = null, getIncluded = null, getDocumentLinks = null, getDocumentMeta = null, getCollectionItems = null } = {})`
|
|
280
|
-
- `createJsonApiResourceRouteContract({ type = "", requestType = "", responseType = "", body = null, query = null, output = null, outputKind = "record", successStatus = 200, includeValidation400 = false, allowBodyId = false, pointerPrefix = "/data/attributes", bodyAttributeExcludeKeys = [], outputAttributeExcludeKeys = [], bodyRelationshipEntries = [], outputRelationshipEntries = [], getRecordType = null, getRecordId = null, getRecordAttributes = null, getRecordRelationships = null, getRecordLinks = null, getRecordMeta = null, getIncluded = null, getDocumentLinks = null, getDocumentMeta = null, getCollectionItems = null, mapRequestRelationships = null } = {})`
|
|
283
|
+
- `createJsonApiResourceRouteContract({ type = "", requestType = "", responseType = "", body = null, query = null, output = null, outputKind = "record", successStatus = 200, includeValidation400 = false, allowSparseFields = false, allowBodyId = false, pointerPrefix = "/data/attributes", bodyAttributeExcludeKeys = [], outputAttributeExcludeKeys = [], bodyRelationshipEntries = [], outputRelationshipEntries = [], getRecordType = null, getRecordId = null, getRecordAttributes = null, getRecordRelationships = null, getRecordLinks = null, getRecordMeta = null, getIncluded = null, getDocumentLinks = null, getDocumentMeta = null, getCollectionItems = null, mapRequestRelationships = null } = {})`
|
|
281
284
|
Local functions
|
|
282
285
|
- `isRecord(value)`
|
|
283
286
|
- `createJsonApiTransportError(statusCode, message, code)`
|
|
284
287
|
- `resolveRouteType(type = "")`
|
|
285
288
|
- `resolveRouteTypes(value = {})`
|
|
286
|
-
- `resolveEmbeddedAttributesTransportSchema(definition, { context = "JSON:API resource", defaultMode = "replace", removeId = false, removeKeys = [] } = {})`
|
|
289
|
+
- `resolveEmbeddedAttributesTransportSchema(definition, { context = "JSON:API resource", defaultMode = "replace", removeId = false, removeKeys = [], allowSparseFields = false } = {})`
|
|
287
290
|
- `normalizeRelationshipSchemaEntries(entries = [])`
|
|
288
291
|
- `createJsonApiRelationshipDataSchema(relationshipType = "", { many = false, nullable = false } = {})`
|
|
289
292
|
- `createJsonApiRelationshipsTransportSchema(entries = [], { includeRequired = false } = {})`
|
|
@@ -31,6 +31,7 @@ Exports
|
|
|
31
31
|
- `extractJsonRestCollectionRows(payload = null)`
|
|
32
32
|
- `isJsonRestResourceMissingError(error = null)`
|
|
33
33
|
- `returnNullWhenJsonRestResourceMissing(run)`
|
|
34
|
+
- `returnBadRequestWhenJsonRestFieldsetInvalid(run)`
|
|
34
35
|
- `resolveWorkspaceScopeValue(context = null)`
|
|
35
36
|
- `resolveUserScopeValue(context = null)`
|
|
36
37
|
- `createJsonRestApiHost({ knex })`
|
|
@@ -47,7 +48,10 @@ Local functions
|
|
|
47
48
|
- `normalizeJsonRestQueryField(fieldName = "", fieldDefinition = {}, projectionDefinition = null)`
|
|
48
49
|
- `isJsonRestVirtualField(fieldDefinition = null)`
|
|
49
50
|
- `applyJsonRestQueryFields(scopeOptions = {}, extraQueryFields = {})`
|
|
51
|
+
- `resolveJsonRestDefaultExcludedFields(resource = {})`
|
|
52
|
+
- `applyJsonRestDefaultExclusions(scopeOptions = {}, resource = {})`
|
|
50
53
|
- `extractJsonApiInputRelationships(attributes = {}, resource = null, relationships = null)`
|
|
54
|
+
- `isJsonRestSparseFieldError(error = null)`
|
|
51
55
|
|
|
52
56
|
### root
|
|
53
57
|
|
|
@@ -229,6 +229,7 @@ Exports
|
|
|
229
229
|
- `parseCrudListRangeQueryExpression(value = null)`
|
|
230
230
|
- `formatCrudListRangeQueryExpression(startValue = "", endValue = "", { collapseExact = false } = {})`
|
|
231
231
|
- `defineCrudListFilters(definitions = {})`
|
|
232
|
+
- `createCrudListFilterEmptyValue(filter = {})`
|
|
232
233
|
- `createCrudListFilterInitialValue(filter = {})`
|
|
233
234
|
- `isCrudListFilterMultiValue(filter = {})`
|
|
234
235
|
- `isCrudListFilterStructuredValue(filter = {})`
|
|
@@ -336,6 +337,12 @@ Exports
|
|
|
336
337
|
- `shouldRetryTransientQueryFailure`
|
|
337
338
|
- `transientQueryRetryDelay`
|
|
338
339
|
|
|
340
|
+
### `shared/support/jsonApiFieldsets.js`
|
|
341
|
+
Exports
|
|
342
|
+
- `normalizeJsonApiFieldList(value = [])`
|
|
343
|
+
- `normalizeJsonApiFieldsets(value = {}, { primaryType = "" } = {})`
|
|
344
|
+
- `buildJsonApiFieldsetsToken(value = {})`
|
|
345
|
+
|
|
339
346
|
### `shared/support/linkPath.js`
|
|
340
347
|
Exports
|
|
341
348
|
- `isExternalLinkTarget(target = "")`
|
|
@@ -259,11 +259,11 @@ Exports
|
|
|
259
259
|
|
|
260
260
|
### `src/client/composables/records/useList.js`
|
|
261
261
|
Exports
|
|
262
|
-
- `useList({ ownershipFilter = ROUTE_VISIBILITY_WORKSPACE, surfaceId = "", access = "auto", apiSuffix = "", queryKeyFactory = null, viewPermissions = [], readEnabled = true, placementSource = "users-web.list", fallbackLoadError = "Unable to load list.", initialPageParam = null, getNextPageParam, selectItems, client = null, transport = null, requestOptions, queryOptions, requestRecovery, requestRecoveryLabel = "List", realtime = null, adapter = null, recordIdParam = "recordId", recordIdSelector = null, viewUrlTemplate = "", editUrlTemplate = "", search = null, queryParams = null, requestQueryParams = null, syncToRoute = false } = {})`
|
|
262
|
+
- `useList({ ownershipFilter = ROUTE_VISIBILITY_WORKSPACE, surfaceId = "", access = "auto", apiSuffix = "", queryKeyFactory = null, viewPermissions = [], readEnabled = true, placementSource = "users-web.list", fallbackLoadError = "Unable to load list.", initialPageParam = null, getNextPageParam, selectItems, client = null, transport = null, requestOptions, queryOptions, requestRecovery, requestRecoveryLabel = "List", realtime = null, adapter = null, recordIdParam = "recordId", recordIdSelector = null, viewUrlTemplate = "", editUrlTemplate = "", search = null, queryParams = null, routeQueryValueResolvers = null, requestQueryParams = null, requestFieldsets = null, syncToRoute = false } = {})`
|
|
263
263
|
|
|
264
264
|
### `src/client/composables/records/useView.js`
|
|
265
265
|
Exports
|
|
266
|
-
- `useView({ resource = null, ownershipFilter = ROUTE_VISIBILITY_WORKSPACE, surfaceId = "", access = "auto", apiSuffix = "", queryKeyFactory = null, viewPermissions = [], readMethod = "GET", readEnabled = true, client = null, transport = null, requestRecovery = null, requestRecoveryLabel = "Resource", placementSource = "users-web.view", fallbackLoadError = "Unable to load resource.", notFoundStatuses = [404], notFoundMessage = "Record not found.", model, mapLoadedToModel, requestQueryParams = null, recordIdParam = "recordId", routeParams = null, routeRecordId = null, apiUrlTemplate = "", listUrlTemplate = "", editUrlTemplate = "", includeRecordIdInQueryKey = false, realtime = undefined, adapter = null } = {})`
|
|
266
|
+
- `useView({ resource = null, ownershipFilter = ROUTE_VISIBILITY_WORKSPACE, surfaceId = "", access = "auto", apiSuffix = "", queryKeyFactory = null, viewPermissions = [], readMethod = "GET", readEnabled = true, client = null, transport = null, requestRecovery = null, requestRecoveryLabel = "Resource", placementSource = "users-web.view", fallbackLoadError = "Unable to load resource.", notFoundStatuses = [404], notFoundMessage = "Record not found.", model, mapLoadedToModel, requestQueryParams = null, requestFieldsets = null, recordIdParam = "recordId", routeParams = null, routeRecordId = null, apiUrlTemplate = "", listUrlTemplate = "", editUrlTemplate = "", includeRecordIdInQueryKey = false, realtime = undefined, adapter = null } = {})`
|
|
267
267
|
|
|
268
268
|
### `src/client/composables/runtime/addEditUiRuntime.js`
|
|
269
269
|
Exports
|
|
@@ -360,11 +360,11 @@ Local functions
|
|
|
360
360
|
### `src/client/composables/support/listQueryParamSupport.js`
|
|
361
361
|
Exports
|
|
362
362
|
- `normalizeListSyncToRouteConfig(syncToRoute = false, { defaultSearchParam = "q" } = {})`
|
|
363
|
-
- `resolveQueryParamDescriptors(queryParams, context = {})`
|
|
363
|
+
- `resolveQueryParamDescriptors(queryParams, context = {}, { routeValueResolvers = null } = {})`
|
|
364
364
|
- `resolveActiveQueryParamEntries(descriptors = [])`
|
|
365
365
|
- `resolveWritableQueryParamBindings(descriptors = [])`
|
|
366
366
|
- `buildQueryParamEntriesToken(entries = [])`
|
|
367
|
-
- `parseRouteBindingValue(binding, routeQueryValue)`
|
|
367
|
+
- `parseRouteBindingValue(binding, routeQueryValue, context = {})`
|
|
368
368
|
- `areQueryParamBindingValuesEqual(left, right)`
|
|
369
369
|
- `buildRouteQueryCompareToken(query = {})`
|
|
370
370
|
- `mergeManagedQueryParamKeyHistory(history = [], keys = [])`
|
|
@@ -375,7 +375,7 @@ Local functions
|
|
|
375
375
|
- `resolveQueryParamsInput(queryParams, context = {})`
|
|
376
376
|
- `resolveQueryParamBindingType(value)`
|
|
377
377
|
- `resolveArrayQueryParamItemType(values = [])`
|
|
378
|
-
- `createWritableQueryParamBinding({ source = {}, rawKey = "", rawValue = null, key = "" } = {})`
|
|
378
|
+
- `createWritableQueryParamBinding({ source = {}, rawKey = "", rawValue = null, key = "", resolveRouteValue = null } = {})`
|
|
379
379
|
- `firstRouteQueryValue(value)`
|
|
380
380
|
- `normalizeRouteQueryValues(value)`
|
|
381
381
|
- `parseRouteBooleanValue(value, fallback = false)`
|
|
@@ -398,11 +398,13 @@ Exports
|
|
|
398
398
|
|
|
399
399
|
### `src/client/composables/support/requestQueryRuntimeSupport.js`
|
|
400
400
|
Exports
|
|
401
|
-
- `
|
|
402
|
-
- `
|
|
403
|
-
|
|
404
|
-
- `resolveRequestQueryBaseKey(sourceQueryKey = null)`
|
|
401
|
+
- `buildRequestQueryObject(entries = [], { fieldsets = null } = {})`
|
|
402
|
+
- `createRequestQueryRuntime({ requestQueryParams = null, requestFieldsets = null, context = null, sourceQueryKey = null } = {})`
|
|
403
|
+
Local functions
|
|
405
404
|
- `resolveRequestQueryContext(context = null)`
|
|
405
|
+
- `resolveRequestQueryBaseKey(sourceQueryKey = null)`
|
|
406
|
+
- `resolveRequestFieldsets(requestFieldsets = null, context = {})`
|
|
407
|
+
- `appendRequestQueryValue(target = {}, key = "", values = [])`
|
|
406
408
|
|
|
407
409
|
### `src/client/composables/support/resourceLoadStateHelpers.js`
|
|
408
410
|
Exports
|
|
@@ -501,6 +503,8 @@ Local functions
|
|
|
501
503
|
- `resetFilterValue(values, filter = {})`
|
|
502
504
|
- `applyPresetFilterValue(values, filter = {}, rawValue)`
|
|
503
505
|
- `createQueryParams(values, filterEntries = [])`
|
|
506
|
+
- `resolveFilterRouteValue(filter, routeValue, { initial = false } = {})`
|
|
507
|
+
- `createRouteQueryValueResolvers(filterEntries = [])`
|
|
504
508
|
- `resolveAtomicValueLabel(filter = {}, value = "", labelResolvers = {})`
|
|
505
509
|
- `formatDefaultChipLabel(filter = {}, chipValue, labelResolvers = {})`
|
|
506
510
|
|
|
@@ -521,7 +525,7 @@ Local functions
|
|
|
521
525
|
|
|
522
526
|
### `src/client/composables/useCrudListScreen.js`
|
|
523
527
|
Exports
|
|
524
|
-
- `useCrudListScreen({ adapter = null, resource = null, resourceNamespace = "resource", apiSuffix = "", recordIdParam = "recordId", recordIdSelector = null, titleFallbackFieldKey = "", viewUrlTemplate = "", editUrlTemplate = "", newUrlTemplate = "", recordChangedEvents = [], listFilters = {}, listBulkActions = [], listRowActions = [], syntheticRows = null, routeQueryBlacklist = Object.freeze(["include", "cursor", "limit"]), requestQueryParams = null, readEnabled = true, requestRecoveryLabel = "Records", fallbackLoadError = "Unable to load records." } = {})`
|
|
528
|
+
- `useCrudListScreen({ adapter = null, resource = null, resourceNamespace = "resource", apiSuffix = "", recordIdParam = "recordId", recordIdSelector = null, titleFallbackFieldKey = "", viewUrlTemplate = "", editUrlTemplate = "", newUrlTemplate = "", recordChangedEvents = [], listFilters = {}, listBulkActions = [], listRowActions = [], syntheticRows = null, routeQueryBlacklist = Object.freeze(["include", "cursor", "limit"]), requestQueryParams = null, requestFieldsets = null, readEnabled = true, requestRecoveryLabel = "Records", fallbackLoadError = "Unable to load records." } = {})`
|
|
525
529
|
Local functions
|
|
526
530
|
- `formatCrudListCardValue(value)`
|
|
527
531
|
- `asList(value = [])`
|
|
@@ -533,7 +537,7 @@ Local functions
|
|
|
533
537
|
|
|
534
538
|
### `src/client/composables/useCrudViewScreen.js`
|
|
535
539
|
Exports
|
|
536
|
-
- `useCrudViewScreen({ adapter = null, resource = null, resourceNamespace = "resource", apiUrlTemplate = "", recordIdParam = "recordId", titleFallbackFieldKey = "", listUrlTemplate = "", editUrlTemplate = "", recordChangedEvent = "", requestQueryParams = null, readEnabled = true, queryKeyFactory = null, requestRecoveryLabel = "Record", fallbackLoadError = "Unable to load record.", notFoundMessage = "Record not found." } = {})`
|
|
540
|
+
- `useCrudViewScreen({ adapter = null, resource = null, resourceNamespace = "resource", apiUrlTemplate = "", recordIdParam = "recordId", titleFallbackFieldKey = "", listUrlTemplate = "", editUrlTemplate = "", recordChangedEvent = "", requestQueryParams = null, requestFieldsets = null, readEnabled = true, queryKeyFactory = null, requestRecoveryLabel = "Record", fallbackLoadError = "Unable to load record.", notFoundMessage = "Record not found." } = {})`
|
|
537
541
|
|
|
538
542
|
### `src/client/composables/usePagedCollection.js`
|
|
539
543
|
Exports
|
|
@@ -777,6 +777,19 @@ Local functions
|
|
|
777
777
|
Exports
|
|
778
778
|
- `runPackageCreateCommand(ctx = {}, { positional, options, cwd, io })`
|
|
779
779
|
|
|
780
|
+
### `src/server/commandHandlers/packageCommands/createMigration.js`
|
|
781
|
+
Exports
|
|
782
|
+
- `addInstallMigrationMutationToDescriptor(source = "", mutation = {})`
|
|
783
|
+
- `createMigrationTemplate({ packageId, migrationId } = {})`
|
|
784
|
+
- `runMigrationCreateCommand(ctx = {}, { options, cwd, io })`
|
|
785
|
+
Local functions
|
|
786
|
+
- `maskNonCode(source = "")`
|
|
787
|
+
- `findMatchingDelimiter(source, openIndex, openCharacter, closeCharacter)`
|
|
788
|
+
- `findMutationsFilesArray(source = "")`
|
|
789
|
+
- `lineIndentAt(source = "", index = 0)`
|
|
790
|
+
- `renderInstallMigrationMutation({ from, id, indent } = {})`
|
|
791
|
+
- `writeMigrationSourceAndDescriptor({ descriptorPath, descriptorSource, migrationPath, migrationSource, mkdir, rename, rm, writeFile, path } = {})`
|
|
792
|
+
|
|
780
793
|
### `src/server/commandHandlers/packageCommands/discoverabilityHelp.js`
|
|
781
794
|
Exports
|
|
782
795
|
- `isHelpToken(value = "")`
|