@jskit-ai/agent-docs 0.1.18 → 0.1.20

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 (29) hide show
  1. package/guide/agent/app-setup/initial-scaffolding.md +12 -8
  2. package/guide/agent/app-setup/multi-homing.md +59 -0
  3. package/guide/agent/app-setup/users.md +19 -4
  4. package/guide/agent/app-setup/working-with-the-jskit-cli.md +1 -0
  5. package/guide/agent/generators/crud-generators.md +210 -62
  6. package/guide/agent/generators/ui-generators.md +31 -0
  7. package/package.json +1 -1
  8. package/patterns/INDEX.md +3 -0
  9. package/patterns/client-requests.md +5 -0
  10. package/patterns/filters.md +4 -0
  11. package/patterns/page-redirects.md +5 -1
  12. package/patterns/server-search.md +211 -0
  13. package/reference/autogen/README.md +1 -0
  14. package/reference/autogen/packages/assistant-core.md +13 -0
  15. package/reference/autogen/packages/assistant-runtime.md +2 -0
  16. package/reference/autogen/packages/auth-provider-supabase-core.md +1 -0
  17. package/reference/autogen/packages/console-core.md +2 -0
  18. package/reference/autogen/packages/crud-core.md +12 -0
  19. package/reference/autogen/packages/crud-server-generator.md +1 -0
  20. package/reference/autogen/packages/crud-ui-generator.md +3 -0
  21. package/reference/autogen/packages/feature-server-generator.md +74 -0
  22. package/reference/autogen/packages/http-runtime.md +12 -6
  23. package/reference/autogen/packages/json-rest-api-core.md +3 -6
  24. package/reference/autogen/packages/kernel.md +1 -0
  25. package/reference/autogen/packages/ui-generator.md +2 -2
  26. package/reference/autogen/packages/users-web.md +23 -9
  27. package/reference/autogen/packages/workspaces-web.md +0 -1
  28. package/reference/autogen/tooling/create-app.md +4 -16
  29. package/reference/autogen/tooling/jskit-cli.md +14 -0
package/patterns/INDEX.md CHANGED
@@ -28,6 +28,8 @@ How to use it:
28
28
  - `ui-testing.md`
29
29
  - filter, filters, search facets, chips, date range, enum filter, lookup filter, `useCrudListFilters`, `createCrudListFilters`
30
30
  - `filters.md`
31
+ - `searchSchema`, `search: true`, `applyFilter`, server search, query validators, backend filters, internal JSON REST filters
32
+ - `server-search.md`
31
33
  - `actualField`, `storage.writeSerializer`, `storage.virtual`, computed field, virtual field, projection, `createCrudResourceRuntime`, `remainingBatchWeight`, datetime write serialization
32
34
  - `crud-repository-mapping.md`
33
35
 
@@ -42,4 +44,5 @@ How to use it:
42
44
  - [client-requests.md](./client-requests.md)
43
45
  - [ui-testing.md](./ui-testing.md)
44
46
  - [filters.md](./filters.md)
47
+ - [server-search.md](./server-search.md)
45
48
  - [crud-repository-mapping.md](./crud-repository-mapping.md)
@@ -41,6 +41,11 @@ Use the CRUD wrappers when they fit:
41
41
  - `useCrudView()` for routed CRUD record loading
42
42
  - `useCrudAddEdit()` for routed CRUD forms
43
43
 
44
+ CRUD hook transport defaults:
45
+
46
+ - CRUD hooks derive the standard JSON:API transport from the shared CRUD `resource` automatically.
47
+ - Do not pass `transport` to CRUD hooks. If you need a non-standard wire contract, drop to `useList()`, `useView()`, `useAddEdit()`, or `usersWebHttpClient.request(...)` instead of the CRUD wrappers.
48
+
44
49
  Why this is the standard JSKIT shape:
45
50
 
46
51
  - `useCommand()` resolves the scoped API path for the current route and surface.
@@ -5,6 +5,10 @@ Use when:
5
5
  - the user asks to "add a filter", "make the list filterable", or "keep filters in the URL"
6
6
  - a screen mixes free-text search with structured facets
7
7
 
8
+ Server-side note:
9
+ - for the current CRUD server contract on the JSON REST path, see `server-search.md`
10
+ - this file is about the shared structured-filter runtime used by CRUD list pages and explicit list-filter modules
11
+
8
12
  Ask first:
9
13
  - which fields are filterable
10
14
  - whether each filter is a flag, enum, multi-enum, date/date-range, number-range, record id, or lookup-backed record id
@@ -6,16 +6,18 @@ Use when:
6
6
  - writing `definePage({ redirect: ... })`
7
7
  - seeding settings landing pages such as `/home/settings`
8
8
  - wiring a section shell that should land on a real child page first
9
+ - making a routed host page open a default child tab such as `comments`
9
10
 
10
11
  Check first:
11
12
 
12
- - whether the page is only a landing route for child pages
13
+ - whether the page is only a landing route for child pages or a host page that should always land on one child first
13
14
  - whether the destination child route is explicit and stable
14
15
  - whether the redirect should preserve incoming query and hash
15
16
 
16
17
  Rules:
17
18
 
18
19
  - For “index page lands on child page” redirects, use `redirectToChild()` from `@jskit-ai/kernel/client/pageRedirects`.
20
+ - The same helper is also the explicit pattern for “this host page should open child X by default”.
19
21
  - Do not hand-build child redirects with string surgery such as `` `${String(to.path || "").replace(/\\/$/, "")}/general` ``.
20
22
  - Keep the destination explicit. Do not infer it from placements, menu order, or “first child page wins” behavior.
21
23
  - If the redirect is just “go to this child page”, prefer:
@@ -28,6 +30,8 @@ definePage({
28
30
  });
29
31
  ```
30
32
 
33
+ - This can live on a host page that still renders its own shell and `RouterView`. The parent route remains matched and the child route renders underneath it.
34
+
31
35
  Why:
32
36
 
33
37
  - the helper centralizes slash handling
@@ -0,0 +1,211 @@
1
+ # Server Search
2
+
3
+ Use when:
4
+ - a CRUD list accepts `q` or other server-side query params
5
+ - a resource needs alias filters such as `onlyArchived -> archived`
6
+ - a list needs access-scoped filters that the repository injects before querying
7
+ - the user asks where search belongs on the server in a current JSKIT app
8
+
9
+ Core rule:
10
+ - for current JSKIT CRUD apps, the server search contract lives in `resource.searchSchema` on the internal JSON REST path
11
+ - route validators decide which public query keys HTTP callers may send
12
+ - repositories may add internal-only filter keys before forwarding the query to JSON REST
13
+
14
+ Fresh generated CRUD repositories already follow this path:
15
+
16
+ ```js
17
+ return api.resources.contacts.query({
18
+ queryParams: buildJsonRestQueryParams(RESOURCE_TYPE, query),
19
+ simplified: false
20
+ }, createJsonRestContext(context));
21
+ ```
22
+
23
+ The normal layer split is:
24
+ 1. `actions.js` / `registerRoutes.js`: accept and validate public query keys
25
+ 2. `repository.js`: add internal-only filter keys such as visibility scope
26
+ 3. `*Resource.js`: define the backend filter behavior in `searchSchema`
27
+
28
+ ## Decision Rules
29
+
30
+ Use `search: true` on a schema field when:
31
+ - the public filter key should be the same as the field name
32
+ - direct field filtering is enough
33
+ - you are happy with the generated/effective search entry for that one field
34
+
35
+ Example:
36
+
37
+ ```js
38
+ schema: {
39
+ archived: {
40
+ type: "boolean",
41
+ search: true,
42
+ operations: {
43
+ output: { required: true }
44
+ }
45
+ }
46
+ }
47
+ ```
48
+
49
+ Good fit:
50
+ - `archived=true`
51
+ - `statusSid=active`
52
+ - direct field-by-field filtering with no aliasing
53
+
54
+ Do not use `search: true` when:
55
+ - you want a different public key than the storage field
56
+ - you need one key to search several fields
57
+ - you need custom SQL semantics
58
+ - you need an internal-only injected filter
59
+
60
+ Use explicit `searchSchema` when:
61
+ - the public key differs from the field name
62
+ - one key searches multiple fields
63
+ - the route/API contract should stay stable even if field names change
64
+ - the filter is internal-only and injected by the repository
65
+ - you need to override the simple `search: true` behavior
66
+
67
+ Example:
68
+
69
+ ```js
70
+ searchSchema: {
71
+ onlyArchived: {
72
+ type: "boolean",
73
+ actualField: "archived",
74
+ filterOperator: "="
75
+ },
76
+ q: {
77
+ type: "string",
78
+ oneOf: ["firstName", "lastName", "email"],
79
+ filterOperator: "like",
80
+ splitBy: " ",
81
+ matchAll: true
82
+ }
83
+ }
84
+ ```
85
+
86
+ Important merge rule:
87
+ - explicit `searchSchema` is the authored contract
88
+ - fields marked `search: true` are added to the effective search schema too
89
+ - if both define the same public key, explicit `searchSchema` wins
90
+
91
+ Use `applyFilter` when:
92
+ - `actualField`, `oneOf`, and normal operators are not enough
93
+ - the filter needs compound SQL
94
+ - the filter encodes visibility rules, status buckets, or null/not-null semantics that are more complex than a direct field comparison
95
+
96
+ Example:
97
+
98
+ ```js
99
+ searchSchema: {
100
+ "__viewerAccess": {
101
+ type: "string",
102
+ applyFilter(query, rawValue) {
103
+ const value = String(rawValue || "").trim();
104
+
105
+ query.whereNull("deleted_at");
106
+ if (value === "privileged") {
107
+ return;
108
+ }
109
+
110
+ const userId = value.startsWith("user:")
111
+ ? String(value.slice(5) || "").trim()
112
+ : "";
113
+
114
+ query.where(function () {
115
+ this.where("user_added", 0);
116
+ if (userId) {
117
+ this.orWhere("added_by_user_id", userId);
118
+ }
119
+ });
120
+ }
121
+ }
122
+ }
123
+ ```
124
+
125
+ Keep `applyFilter` focused on query semantics:
126
+ - build the SQL/knex filter there
127
+ - do not put permission checks there
128
+ - do not turn it into a second service layer
129
+
130
+ Add route validators when:
131
+ - the filter key is public and may arrive from HTTP query params
132
+ - the page/UI needs a stable, validated query contract
133
+ - malformed values should either be rejected or deliberately discarded
134
+
135
+ Example route layer:
136
+
137
+ ```js
138
+ input: composeSchemaDefinitions([
139
+ workspaceSlugParamsValidator,
140
+ listCursorPaginationQueryValidator,
141
+ listSearchQueryValidator,
142
+ vetsListFiltersQueryValidator,
143
+ ])
144
+ ```
145
+
146
+ That means:
147
+ - `q` and the structured filter keys are accepted publicly
148
+ - the repository may still add internal-only keys later
149
+
150
+ Do not add route validators for:
151
+ - repository-injected internal keys such as `"__viewerAccess"`
152
+ - filters that must never be supplied by the client directly
153
+
154
+ ## Recommended Shapes
155
+
156
+ Simple direct field exposure:
157
+
158
+ ```js
159
+ schema: {
160
+ vip: { type: "boolean", search: true }
161
+ }
162
+ ```
163
+
164
+ Public alias for a real field:
165
+
166
+ ```js
167
+ searchSchema: {
168
+ onlyVip: { type: "boolean", actualField: "vip", filterOperator: "=" }
169
+ }
170
+ ```
171
+
172
+ Grouped text search:
173
+
174
+ ```js
175
+ searchSchema: {
176
+ q: {
177
+ type: "string",
178
+ oneOf: ["name", "email", "phone"],
179
+ filterOperator: "like",
180
+ splitBy: " ",
181
+ matchAll: true
182
+ }
183
+ }
184
+ ```
185
+
186
+ Repository-injected internal filter:
187
+
188
+ ```js
189
+ function buildScopedQuery(query = {}, context = null) {
190
+ return {
191
+ ...(query || {}),
192
+ "__viewerAccess": resolveViewerAccess(context)
193
+ };
194
+ }
195
+ ```
196
+
197
+ ## Keep These Boundaries Clean
198
+
199
+ - Put backend filter behavior in `searchSchema`, not in page code.
200
+ - Put permission checks in the action/service layer, not in `applyFilter`.
201
+ - Put repository-only scoping in the repository, not in route query validation.
202
+ - Do not expose a query key publicly just because the repository uses it internally.
203
+ - Do not rely on route validators alone; a public key still needs a matching backend search definition.
204
+
205
+ ## Quick Rule Of Thumb
206
+
207
+ - Same key, same field, simple behavior: `search: true`
208
+ - Public alias or multi-field search: `searchSchema`
209
+ - Complex SQL semantics: `searchSchema` + `applyFilter`
210
+ - Public HTTP query key: add a route validator
211
+ - Internal-only repository key: inject it in `repository.js`, skip the public validator
@@ -22,6 +22,7 @@ Startup navigation stays in `KERNEL_MAP.md`.
22
22
  - [database-runtime](/packages/agent-docs/reference/autogen/packages/database-runtime.md)
23
23
  - [database-runtime-mysql](/packages/agent-docs/reference/autogen/packages/database-runtime-mysql.md)
24
24
  - [database-runtime-postgres](/packages/agent-docs/reference/autogen/packages/database-runtime-postgres.md)
25
+ - [feature-server-generator](/packages/agent-docs/reference/autogen/packages/feature-server-generator.md)
25
26
  - [http-runtime](/packages/agent-docs/reference/autogen/packages/http-runtime.md)
26
27
  - [json-rest-api-core](/packages/agent-docs/reference/autogen/packages/json-rest-api-core.md)
27
28
  - [kernel](/packages/agent-docs/reference/autogen/packages/kernel.md)
@@ -216,6 +216,7 @@ Exports
216
216
  - `MAX_INPUT_CHARS`
217
217
  - `MAX_HISTORY_MESSAGES`
218
218
  - `assistantResource`
219
+ - `assistantConversationOutputValidator`
219
220
 
220
221
  ### `src/shared/assistantSettingsResource.js`
221
222
  Exports
@@ -245,14 +246,26 @@ Exports
245
246
  - `MAX_INPUT_CHARS`
246
247
  - `MAX_HISTORY_MESSAGES`
247
248
  - `assistantResource`
249
+ - `assistantConversationOutputValidator`
248
250
  - `MAX_SYSTEM_PROMPT_CHARS`
249
251
  - `assistantConfigResource`
252
+ - `ASSISTANT_SETTINGS_TRANSPORT`
253
+ - `ASSISTANT_SETTINGS_UPDATE_TRANSPORT`
254
+ - `ASSISTANT_CONVERSATIONS_TRANSPORT`
255
+ - `ASSISTANT_CONVERSATION_MESSAGES_TRANSPORT`
250
256
  - `assistantSettingsEvents`
251
257
  - `ASSISTANT_CONVERSATION_STATUSES`
252
258
  - `normalizeConversationStatus`
253
259
  - `parseJsonObject`
254
260
  - `toPositiveInteger`
255
261
 
262
+ ### `src/shared/jsonApiTransports.js`
263
+ Exports
264
+ - `ASSISTANT_SETTINGS_TRANSPORT`
265
+ - `ASSISTANT_SETTINGS_UPDATE_TRANSPORT`
266
+ - `ASSISTANT_CONVERSATIONS_TRANSPORT`
267
+ - `ASSISTANT_CONVERSATION_MESSAGES_TRANSPORT`
268
+
256
269
  ### `src/shared/queryKeys.js`
257
270
  Exports
258
271
  - `ASSISTANT_QUERY_KEY_PREFIX`
@@ -100,6 +100,8 @@ Local functions
100
100
  - `sendPreStreamErrorResponse(reply, error)`
101
101
  - `resolveRouteRequestState(request, { resolveCurrentAppConfig = () => ({}), kind = "runtime", requiresWorkspace = false, workspaceScopeSupport = null } = {})`
102
102
  - `buildChatStreamActionInput(routeInput = {}, requestBody = {})`
103
+ - `resolveAssistantSettingsRecordId(record = {})`
104
+ - `resolveAssistantConversationMessagesRecordId(record = {})`
103
105
  - `registerSettingsRoutes(router, resolveCurrentAppConfig, { requiresWorkspace = false, workspaceScopeSupport = null } = {})`
104
106
  - `registerRuntimeRoutes(router, resolveCurrentAppConfig, { requiresWorkspace = false, workspaceScopeSupport = null } = {})`
105
107
 
@@ -244,6 +244,7 @@ Local functions
244
244
  - `resolveCommonDependencies(scope)`
245
245
  - `resolveRuntimeEnv(scope)`
246
246
  - `resolveOptionalRepositories(scope)`
247
+ - `isDeferredJsonRestBootGap(app, error)`
247
248
  - `applyAuthServiceDecorators(scope, authService)`
248
249
 
249
250
  ### root
@@ -31,6 +31,8 @@ Exports
31
31
  ### `src/server/consoleSettings/bootConsoleSettingsRoutes.js`
32
32
  Exports
33
33
  - `bootConsoleSettingsRoutes(app)`
34
+ Local functions
35
+ - `resolveConsoleSettingsRecordId()`
34
36
 
35
37
  ### `src/server/consoleSettings/consoleService.js`
36
38
  Exports
@@ -296,6 +296,18 @@ Local functions
296
296
  ### `src/server/routeContracts.js`
297
297
  Exports
298
298
  - `createCrudJsonApiRouteContracts({ resource = {}, routeParamsValidator = null, listSearchQueryValidator = defaultListSearchQueryValidator, lookupIncludeQueryValidator = defaultLookupIncludeQueryValidator } = {})`
299
+ Local functions
300
+ - `isRecord(value)`
301
+ - `resolveSchemaFieldDefinitions(definition = null)`
302
+ - `resolveJsonApiRelationshipEntries(definition = null)`
303
+ - `createRecordAttributesResolver(definition = null, { excludeKeys = [] } = {})`
304
+ - `createRecordRelationshipsResolver(definition = null)`
305
+ - `createRequestRelationshipMapper(definition = null)`
306
+ - `resolveOutputAttributeExcludeKeys(resource = {})`
307
+ - `resolveLookupContainerKey(resource = {})`
308
+ - `normalizeLookupId(value)`
309
+ - `normalizeIncludedLookupRecord(source = null, fallbackId = null)`
310
+ - `createLookupIncludedResolver(definition = null, { lookupContainerKey = "" } = {})`
299
311
 
300
312
  ### `src/server/serviceEvents.js`
301
313
  Exports
@@ -132,6 +132,7 @@ Local functions
132
132
  - `requireVariableDeclarator(programNode, variableName = "", context = "crud-server-generator scaffold-field")`
133
133
  - `requireCrudResourceConfigObject(programNode, context = "crud-server-generator scaffold-field")`
134
134
  - `requireResourceSchemaObject(programNode, context = "crud-server-generator scaffold-field")`
135
+ - `assertNoExplicitCrudSchemaOverrides(resourceObject, context = "crud-server-generator scaffold-field")`
135
136
  - `findObjectPropertyByName(objectNode, propertyName = "")`
136
137
  - `hasObjectProperty(objectNode, propertyName = "")`
137
138
  - `insertObjectProperty(objectNode, propertyName = "", valueExpressionSource = "", { context = "crud-server-generator scaffold-field", insertBeforeComputed = false } = {})`
@@ -30,6 +30,7 @@ Local functions
30
30
  - `resolveListTargetFile(targetRoot = "")`
31
31
  - `parseOperationsOption(options)`
32
32
  - `parseDisplayFieldsOption(options)`
33
+ - `parseParentTitleOption(options)`
33
34
  - `validateDisplayFieldsForOperation(selectedFieldKeys, fields, operationName)`
34
35
  - `filterDisplayFields(selectedFieldKeys, fields)`
35
36
  - `rewriteGeneratedBlockIndent(source = "", { trimPrefix = "", addPrefix = "" } = {})`
@@ -46,6 +47,8 @@ Local functions
46
47
  - `resolveTargetRootRelativeRoutePath(pageTarget = {})`
47
48
  - `resolveMenuToPropLine(linkTo = "")`
48
49
  - `resolveCrudRelativePath(namespace = "")`
50
+ - `buildListParentTitleImportLine(parentTitleMode = "contextual")`
51
+ - `buildListHeadingTitleSetup({ parentTitleMode = "contextual", resourceNamespace = "", routeTitle = "Records" } = {})`
49
52
 
50
53
  ### `src/server/resourceSupport.js`
51
54
  Exports
@@ -0,0 +1,74 @@
1
+ # packages/feature-server-generator
2
+
3
+ Generated by `npm run agent-docs:build`.
4
+ Do not edit manually.
5
+
6
+ Generated inventory for `packages/feature-server-generator`.
7
+ Use this on demand; do not load the full index at startup.
8
+
9
+ ## Scope
10
+ - Source: `packages/feature-server-generator/**/*{.js,.mjs,.cjs,.vue}`
11
+ - Excludes: `test/`, `tests/`, `__tests__/`, `*.test.*`, `*.spec.*`, `*.vitest.*`, `node_modules/`, `dist/`, `coverage/`, `docs/`, `LEGACY/`, `.vitepress/cache/`, `.vitepress/dist/`
12
+
13
+ ## Sections
14
+
15
+ ### src
16
+
17
+ ### `src/server/buildTemplateContext.js`
18
+ Exports
19
+ - `buildTemplateContext({ options = {} } = {})`
20
+ Local functions
21
+ - `splitTextIntoWords(value)`
22
+ - `wordsToPascal(words = [])`
23
+ - `wordsToKebab(words = [])`
24
+ - `wordsToCamel(words = [])`
25
+ - `normalizeFeatureName(value)`
26
+ - `normalizeSurfaceId(value)`
27
+ - `normalizeRoutePrefix(value)`
28
+ - `quoteArray(values = [])`
29
+ - `buildProviderContext({ featureName, mode, routePrefix, surface })`
30
+ - `buildActionsContext({ surface })`
31
+ - `buildServiceContext({ featureName, mode })`
32
+ - `buildRouteContext({ surface })`
33
+ - `buildDescriptorContext({ featureName, mode })`
34
+
35
+ ### templates
36
+
37
+ ### `templates/src/local-package/package.descriptor.mjs`
38
+ Exports
39
+ - None
40
+
41
+ ### `templates/src/local-package/server/actions.js`
42
+ Exports
43
+ - `featureActions`
44
+
45
+ ### `templates/src/local-package/server/FeatureProvider.js`
46
+ Exports
47
+ - `${option:feature-name|pascal`
48
+
49
+ ### `templates/src/local-package/server/inputSchemas.js`
50
+ Exports
51
+ - `statusQueryInputValidator`
52
+ - `executeCommandInputValidator`
53
+
54
+ ### `templates/src/local-package/server/registerRoutes.js`
55
+ Exports
56
+ - `registerRoutes(app, { routeSurface = "", routeRelativePath = "" } = {})`
57
+
58
+ ### `templates/src/local-package/server/repositoryCustomKnex.js`
59
+ Exports
60
+ - `createRepository({ knex } = {})`
61
+
62
+ ### `templates/src/local-package/server/repositoryJsonRest.js`
63
+ Exports
64
+ - `createRepository({ api } = {})`
65
+
66
+ ### `templates/src/local-package/server/service.js`
67
+ Exports
68
+ - `createService({ featureRepository } = {})`
69
+
70
+ ### root
71
+
72
+ ### `package.descriptor.mjs`
73
+ Exports
74
+ - None
@@ -111,7 +111,10 @@ Local functions
111
111
  - `isRecord(value)`
112
112
  - `normalizeTransportKind(transport = null)`
113
113
  - `defaultEncodeAttributes(body = {})`
114
- - `simplifyResourceObject(resource = {})`
114
+ - `resolveRelationshipFieldKey(relationshipName = "", lookupFieldMap = null)`
115
+ - `createIncludedResourceIndex(document = {})`
116
+ - `simplifyRelationshipResource(linkage = {}, options = {})`
117
+ - `simplifyResourceObject(resource = {}, options = {})`
115
118
  - `assertPrimaryDataType(resource = {}, expectedType = "")`
116
119
  - `resolveCollectionPageMeta(document = {})`
117
120
 
@@ -262,18 +265,21 @@ Local functions
262
265
  ### `src/shared/validators/jsonApiRouteTransport.js`
263
266
  Exports
264
267
  - `JSON_API_ERROR_DOCUMENT_SCHEMA`
265
- - `createJsonApiResourceObjectTransportSchema({ type = "", attributes, requireId = true, includeLinks = false, includeMeta = false } = {})`
266
- - `createJsonApiResourceRequestBodyTransportSchema({ type = "", attributes, requireId = false } = {})`
267
- - `createJsonApiResourceSuccessTransportSchema({ type = "", attributes, kind = "record", includeLinks = false, includeMeta = false, includeIncluded = false } = {})`
268
+ - `createJsonApiResourceObjectTransportSchema({ type = "", attributes, requireId = true, includeLinks = false, includeMeta = false, excludeAttributeKeys = [], relationshipEntries = [], relationshipMembersRequired = false } = {})`
269
+ - `createJsonApiResourceRequestBodyTransportSchema({ type = "", attributes, requireId = false, excludeAttributeKeys = [], relationshipEntries = [] } = {})`
270
+ - `createJsonApiResourceSuccessTransportSchema({ type = "", attributes, kind = "record", includeLinks = false, includeMeta = false, includeIncluded = false, excludeAttributeKeys = [], relationshipEntries = [] } = {})`
268
271
  - `withJsonApiErrorResponses(successResponses, { includeValidation400 = false } = {})`
269
272
  - `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 } = {})`
270
- - `createJsonApiResourceRouteContract({ type = "", requestType = "", responseType = "", body = null, query = null, output = null, outputKind = "record", successStatus = 200, includeValidation400 = false, allowBodyId = false, pointerPrefix = "/data/attributes", getRecordType = null, getRecordId = null, getRecordAttributes = null, getRecordRelationships = null, getRecordLinks = null, getRecordMeta = null, getIncluded = null, getDocumentLinks = null, getDocumentMeta = null, getCollectionItems = null, mapRequestRelationships = null } = {})`
273
+ - `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 } = {})`
271
274
  Local functions
272
275
  - `isRecord(value)`
273
276
  - `createJsonApiTransportError(statusCode, message, code)`
274
277
  - `resolveRouteType(type = "")`
275
278
  - `resolveRouteTypes(value = {})`
276
- - `resolveEmbeddedAttributesTransportSchema(definition, { context = "JSON:API resource", defaultMode = "replace", removeId = false } = {})`
279
+ - `resolveEmbeddedAttributesTransportSchema(definition, { context = "JSON:API resource", defaultMode = "replace", removeId = false, removeKeys = [] } = {})`
280
+ - `normalizeRelationshipSchemaEntries(entries = [])`
281
+ - `createJsonApiRelationshipDataSchema(relationshipType = "", { nullable = false } = {})`
282
+ - `createJsonApiRelationshipsTransportSchema(entries = [], { includeRequired = false } = {})`
277
283
  - `createJsonApiMetaSuccessTransportSchema({ meta } = {})`
278
284
  - `defaultRecordTypeResolver(type)`
279
285
  - `defaultRecordIdResolver(record = {})`
@@ -24,15 +24,15 @@ Exports
24
24
  - `JSON_REST_AUTOFILTER_PRESETS`
25
25
  - `addResourceIfMissing(api, scopeName, resourceConfig)`
26
26
  - `buildJsonRestQueryParams(resourceType = "", query = {}, { include = undefined } = {})`
27
- - `createJsonApiInputRecord(resourceType = "", attributes = {}, { id = null, relationships = null } = {})`
27
+ - `createJsonApiInputRecord(resourceType = "", attributes = {}, { id = null, relationships = null, resource = null } = {})`
28
28
  - `createJsonApiRelationship(resourceType = "", id = null)`
29
29
  - `createJsonRestResourceScopeOptions(resource = {}, { writeSerializers = {}, normalizeId = null } = {})`
30
30
  - `createJsonRestContext(context = null)`
31
+ - `extractJsonRestCollectionRows(payload = null)`
31
32
  - `isJsonRestResourceMissingError(error = null)`
32
33
  - `returnNullWhenJsonRestResourceMissing(run)`
33
34
  - `resolveWorkspaceScopeValue(context = null)`
34
35
  - `resolveUserScopeValue(context = null)`
35
- - `simplifyJsonApiDocument(payload = {})`
36
36
  - `createJsonRestApiHost({ knex })`
37
37
  - `registerJsonRestApiHost(app)`
38
38
  Local functions
@@ -42,10 +42,7 @@ Local functions
42
42
  - `normalizeJsonRestText(value, { fallback = "" } = {})`
43
43
  - `normalizeJsonRestObject(value)`
44
44
  - `normalizeJsonRestList(value)`
45
- - `normalizeJsonApiResourceObject(resource = {})`
46
- - `buildJsonApiIncludedIndex(payload = {})`
47
- - `simplifyJsonApiRelationshipData(data, { includedIndex = null, seen = null } = {})`
48
- - `simplifyJsonApiResourceObject(resource = {}, { includedIndex = null, seen = null } = {})`
45
+ - `extractJsonApiInputRelationships(attributes = {}, resource = null, relationships = null)`
49
46
 
50
47
  ### root
51
48
 
@@ -878,6 +878,7 @@ Exports
878
878
  - `registerRoutes(fastify, { routes = [], app = null, applyRoutePolicy = defaultApplyRoutePolicy, missingHandler = defaultMissingHandler, enableRequestScope = true, requestScopeProperty = "scope", requestActionExecutorProperty = "executeAction", actionExecutorToken = "actionExecutor", requestActionDefaultChannel = "api", requestActionDefaultSurface = "", requestScopeIdPrefix = "http", requestIdResolver = null, middleware = {} } = {})`
879
879
  Local functions
880
880
  - `toFastifyRouteOptions(route)`
881
+ - `shouldStripFastifyBodySchema(route = null, schema = null)`
881
882
  - `normalizeHeaderValue(value)`
882
883
  - `normalizeMediaType(value = "")`
883
884
  - `routeDefinesRequestBody(route = null)`
@@ -54,8 +54,8 @@ Exports
54
54
  - `DEFAULT_SUBPAGES_POSITION`
55
55
  - `DEFAULT_COMPONENT_DIRECTORY`
56
56
  - `SECTION_CONTAINER_SHELL_COMPONENT`
57
- - `TAB_LINK_COMPONENT`
58
- - `TAB_LINK_COMPONENT_TOKEN`
57
+ - `SUBPAGES_LINK_COMPONENT`
58
+ - `SUBPAGES_LINK_COMPONENT_TOKEN`
59
59
  - `resolvePageTargetDetails`
60
60
  - `resolveNearestParentSubpagesHost`
61
61
  - `deriveDefaultSubpagesHost`
@@ -18,7 +18,6 @@ Use this on demand; do not load the full index at startup.
18
18
  Exports
19
19
  - `ACCOUNT_SETTINGS_SECTION_TARGET`
20
20
  - `EMPTY_ACCOUNT_SETTINGS_SECTIONS`
21
- - `RESERVED_ACCOUNT_SETTINGS_SECTION_VALUES`
22
21
  - `normalizeAccountSettingsSectionEntry(entry = null)`
23
22
  - `resolveAccountSettingsSections(entries = [])`
24
23
  - `sortAccountSettingsSections(entries = [])`
@@ -29,6 +28,13 @@ Exports
29
28
  - `createUsersBootstrapUserHandler()`
30
29
  - `registerUsersBootstrapPayloadHandlers(app)`
31
30
 
31
+ ### `src/client/components/AccountSettingsClientElement.vue`
32
+ Exports
33
+ - None
34
+ Local functions
35
+ - `normalizeSection(value)`
36
+ - `readRouteSection()`
37
+
32
38
  ### `src/client/components/ProfileClientElement.vue`
33
39
  Exports
34
40
  - None
@@ -75,6 +81,18 @@ Exports
75
81
  - `resolveCrudBindingValues(values, context = {})`
76
82
  - `resolveCrudBoundValues({ binding = {}, routeValues = {}, context = {} } = {})`
77
83
 
84
+ ### `src/client/composables/crud/crudJsonApiTransportSupport.js`
85
+ Exports
86
+ - `inferCrudJsonApiTransport(resource = null, { mode = "", operationName = "" } = {})`
87
+ - `inferCrudLookupJsonApiTransport({ namespace = "", apiPath = "" } = {})`
88
+ - `resolveCrudJsonApiTransport(transport = null, resource = null, options = {})`
89
+ - `resolveLookupFieldMap(resource = null)`
90
+ Local functions
91
+ - `isRecord(value)`
92
+ - `resolveSchemaFieldDefinitions(definition = null)`
93
+ - `isJsonApiResourceTransport(transport = null)`
94
+ - `resolveCrudJsonApiResourceType(resource = null)`
95
+
78
96
  ### `src/client/composables/crud/crudLookupFieldLabelSupport.js`
79
97
  Exports
80
98
  - `resolveLookupItemLabel(item = {}, labelKey = "")`
@@ -84,6 +102,7 @@ Local functions
84
102
  - `hasDisplayValue(value)`
85
103
  - `resolveComposedLabel(source = {}, candidates = LOOKUP_LABEL_COMPOSITION_CANDIDATES)`
86
104
  - `resolveLookupFieldDescriptor(field = {}, relationKind = "", valueKey = "", labelKey = "")`
105
+ - `resolveFallbackLookupKey(key = "")`
87
106
 
88
107
  ### `src/client/composables/crud/crudLookupFieldRuntime.js`
89
108
  Exports
@@ -108,6 +127,7 @@ Local functions
108
127
  - `resolveFormFieldType(field = {})`
109
128
  - `resolveFormFieldFormat(field = {})`
110
129
  - `isNullableFormField(field = {})`
130
+ - `isLookupFormField(field = {})`
111
131
  - `padDateTimePart(value)`
112
132
  - `normalizeTimeWhitespace(value)`
113
133
  - `toTimeInputValue(value)`
@@ -166,7 +186,7 @@ Local functions
166
186
 
167
187
  ### `src/client/composables/records/useCrudView.js`
168
188
  Exports
169
- - `useCrudView({ paramBinding = null, route = null, ...viewOptions } = {})`
189
+ - `useCrudView({ resource = null, paramBinding = null, route = null, ...viewOptions } = {})`
170
190
 
171
191
  ### `src/client/composables/records/useList.js`
172
192
  Exports
@@ -433,6 +453,7 @@ Exports
433
453
  ### `src/client/index.js`
434
454
  Exports
435
455
  - `UsersWebClientProvider`
456
+ - `AccountSettingsClientElement`
436
457
  - `clientProviders`
437
458
 
438
459
  ### `src/client/lib/bootstrap.js`
@@ -486,13 +507,6 @@ Exports
486
507
 
487
508
  ### templates
488
509
 
489
- ### `templates/src/components/account/settings/AccountSettingsClientElement.vue`
490
- Exports
491
- - None
492
- Local functions
493
- - `normalizeSection(value)`
494
- - `readRouteSection()`
495
-
496
510
  ### `templates/src/components/account/settings/AccountSettingsNotificationsSection.vue`
497
511
  Exports
498
512
  - None
@@ -333,7 +333,6 @@ Local functions
333
333
  - `normalizePendingInvitesCount(value)`
334
334
  - `resolveReturnTo()`
335
335
  - `resolveReturnToHref()`
336
- - `countPendingInvites(entries = [])`
337
336
 
338
337
  ### `templates/packages/main/src/client/components/AccountSettingsInvitesSection.vue`
339
338
  Exports