@jskit-ai/agent-docs 0.1.52 → 0.1.53
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/a-more-interesting-shell.md +38 -0
- package/guide/agent/generators/advanced-cruds.md +17 -0
- package/package.json +1 -1
- package/patterns/client-requests.md +3 -0
- package/reference/autogen/packages/http-runtime.md +1 -0
- package/reference/autogen/packages/users-web.md +12 -6
|
@@ -609,6 +609,44 @@ For JSKIT read-composable screens, the default is automatic. Hand-written TanSta
|
|
|
609
609
|
|
|
610
610
|
Writes are different. JSKIT does not automatically replay `POST`, `PATCH`, `PUT`, or `DELETE` after a network failure because the server may already have received the request. Save and command screens keep ownership of mutation state, field errors, conflict handling, and user feedback.
|
|
611
611
|
|
|
612
|
+
Some apps need API URLs to be scoped by the active route before the browser request is sent. Configure that once at app startup instead of replacing `fetchImpl` in a local transport wrapper:
|
|
613
|
+
|
|
614
|
+
```js
|
|
615
|
+
import { configureUsersWebHttpClient } from "@jskit-ai/users-web/client/lib/httpClient";
|
|
616
|
+
|
|
617
|
+
configureUsersWebHttpClient({
|
|
618
|
+
csrf: {
|
|
619
|
+
enabled: false
|
|
620
|
+
},
|
|
621
|
+
resolveRequestUrl(url, context) {
|
|
622
|
+
if (!url.startsWith("/api/")) {
|
|
623
|
+
return url;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
const projectSlug = readProjectSlugFromAppRoute();
|
|
627
|
+
return url.replace(/^\/api\//u, `/api/app/${encodeURIComponent(projectSlug)}/`);
|
|
628
|
+
}
|
|
629
|
+
});
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
Call `configureUsersWebHttpClient()` before Vue mounts or before JSKIT composables are created. The resolver can close over the app router/store when it needs route data, and the `context` argument carries request details such as `originalUrl`, `method`, `requestOptions`, and whether the request is a stream. After configuration, normal `useEndpointResource()`, `useList()`, `useView()`, `useAddEdit()`, and `useCommand()` calls use the configured client. `resolveRequestUrl` runs after JSKIT adds query strings and before the underlying browser `fetch`, so request recovery metadata, JSON:API transport, credentials, CSRF, and command feedback stay on the standard path.
|
|
633
|
+
|
|
634
|
+
For packages that create their own client, use the same lower-level hook directly:
|
|
635
|
+
|
|
636
|
+
```js
|
|
637
|
+
import { createTransientRetryHttpClient } from "@jskit-ai/http-runtime/client";
|
|
638
|
+
|
|
639
|
+
const studioHttpClient = createTransientRetryHttpClient({
|
|
640
|
+
credentials: "include",
|
|
641
|
+
csrf: {
|
|
642
|
+
enabled: false
|
|
643
|
+
},
|
|
644
|
+
resolveRequestUrl(url) {
|
|
645
|
+
return scopedStudioApiUrl(url);
|
|
646
|
+
}
|
|
647
|
+
});
|
|
648
|
+
```
|
|
649
|
+
|
|
612
650
|
### The home page talks to the backend
|
|
613
651
|
|
|
614
652
|
`src/pages/home/index.vue` uses Vue Query to fetch `/api/health` and display the result in the UI.
|
|
@@ -685,6 +685,23 @@ Why this is the standard JSKIT shape:
|
|
|
685
685
|
- `shell-web` observes the shared TanStack Query client for recoverable transport failures. Generated CRUD reads and custom reads built with `useEndpointResource()`, `useList()`, `useView()`, or `useAddEdit()` get the shell recovery banner with a Retry action that refetches the failed query.
|
|
686
686
|
- Automatic shell request recovery is only for safe `GET`/`HEAD` read refetches. JSKIT read composables mark Query entries with `jskit.requestRecoveryMethod`, and the shell ignores unmarked or unsafe methods. Do not rely on it to replay `POST`, `PATCH`, `PUT`, or `DELETE`; mutation screens own save state, field errors, and user feedback.
|
|
687
687
|
|
|
688
|
+
When an app needs all JSKIT reads and commands to rewrite API URLs before fetch, configure the users-web HTTP client once instead of passing custom paths or replacing `fetchImpl` in each local helper:
|
|
689
|
+
|
|
690
|
+
```js
|
|
691
|
+
import { configureUsersWebHttpClient } from "@jskit-ai/users-web/client/lib/httpClient";
|
|
692
|
+
|
|
693
|
+
configureUsersWebHttpClient({
|
|
694
|
+
csrf: {
|
|
695
|
+
enabled: false
|
|
696
|
+
},
|
|
697
|
+
resolveRequestUrl(url) {
|
|
698
|
+
return scopedApiUrlForCurrentRoute(url);
|
|
699
|
+
}
|
|
700
|
+
});
|
|
701
|
+
```
|
|
702
|
+
|
|
703
|
+
After that, `useEndpointResource()`, `useList()`, `useView()`, `useAddEdit()`, and `useCommand()` keep their normal call shape. JSKIT still owns Query metadata, request recovery, JSON:API transport, command feedback, credentials, and CSRF behavior. Use `createTransientRetryHttpClient({ resolveRequestUrl })` directly only when a package needs its own separate client instance.
|
|
704
|
+
|
|
688
705
|
When a custom read needs a better recovery banner label, pass it through the read primitive rather than reporting the failure manually:
|
|
689
706
|
|
|
690
707
|
```js
|
package/package.json
CHANGED
|
@@ -63,6 +63,8 @@ Why this is the standard JSKIT shape:
|
|
|
63
63
|
- `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.
|
|
64
64
|
- Use `requestQueryParams` for endpoint query strings on list, view, and add/edit runtimes.
|
|
65
65
|
- Keep `apiUrlTemplate` path-only. Do not put `?include=...` or other query strings in URL templates.
|
|
66
|
+
- 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.
|
|
67
|
+
- `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.
|
|
66
68
|
|
|
67
69
|
Error presentation rules:
|
|
68
70
|
|
|
@@ -80,6 +82,7 @@ Avoid:
|
|
|
80
82
|
|
|
81
83
|
- raw `fetch(...)` for standard page or component work
|
|
82
84
|
- page-local HTTP helpers that duplicate JSKIT runtime seams
|
|
85
|
+
- custom `fetchImpl` wrappers whose only job is to rewrite `/api/...` URLs
|
|
83
86
|
- manually concatenating scoped route params into API URLs
|
|
84
87
|
- using a lower-level seam when a higher-level routed CRUD or command runtime already fits
|
|
85
88
|
- smuggling query params into `apiUrlTemplate`
|
|
@@ -68,6 +68,7 @@ Local functions
|
|
|
68
68
|
- `normalizeMethod(method)`
|
|
69
69
|
- `resolveUnsafeMethods(value)`
|
|
70
70
|
- `resolveFetch()`
|
|
71
|
+
- `normalizeResolvedRequestUrl(value, fallback = "")`
|
|
71
72
|
- `isObjectBody(value)`
|
|
72
73
|
- `isQueryValuePresent(value)`
|
|
73
74
|
- `appendRequestQueryToUrl(url, query = null, transport = null)`
|
|
@@ -212,7 +212,7 @@ Local functions
|
|
|
212
212
|
|
|
213
213
|
### `src/client/composables/records/useAddEdit.js`
|
|
214
214
|
Exports
|
|
215
|
-
- `useAddEdit({ ownershipFilter = ROUTE_VISIBILITY_WORKSPACE, surfaceId = "", access = "auto", resource = null, apiSuffix = "", queryKeyFactory = null, viewPermissions = [], savePermissions = [], readMethod = "GET", readEnabled = true, writeMethod = "PATCH", transport = null, requestRecovery = null, requestRecoveryLabel = "Resource", placementSource = "users-web.add-edit", fallbackLoadError = "Unable to load resource.", fallbackSaveError = "Unable to save resource.", fieldErrorKeys = [], clearOnRouteChange = true, model, input, mapLoadedToModel, buildRawPayload, buildSavePayload, onSaveSuccess, requestQueryParams = null, recordIdParam = "recordId", routeParams = null, routeRecordId = null, apiUrlTemplate = "", viewUrlTemplate = "", listUrlTemplate = "", saveRecordIdSelector = null, messages = {}, realtime = null, adapter = null } = {})`
|
|
215
|
+
- `useAddEdit({ ownershipFilter = ROUTE_VISIBILITY_WORKSPACE, surfaceId = "", access = "auto", resource = null, apiSuffix = "", queryKeyFactory = null, viewPermissions = [], savePermissions = [], readMethod = "GET", readEnabled = true, writeMethod = "PATCH", client = null, transport = null, requestRecovery = null, requestRecoveryLabel = "Resource", placementSource = "users-web.add-edit", fallbackLoadError = "Unable to load resource.", fallbackSaveError = "Unable to save resource.", fieldErrorKeys = [], clearOnRouteChange = true, model, input, mapLoadedToModel, buildRawPayload, buildSavePayload, onSaveSuccess, requestQueryParams = null, recordIdParam = "recordId", routeParams = null, routeRecordId = null, apiUrlTemplate = "", viewUrlTemplate = "", listUrlTemplate = "", saveRecordIdSelector = null, messages = {}, realtime = null, adapter = null } = {})`
|
|
216
216
|
|
|
217
217
|
### `src/client/composables/records/useCrudAddEdit.js`
|
|
218
218
|
Exports
|
|
@@ -234,11 +234,11 @@ Exports
|
|
|
234
234
|
|
|
235
235
|
### `src/client/composables/records/useList.js`
|
|
236
236
|
Exports
|
|
237
|
-
- `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, 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 } = {})`
|
|
237
|
+
- `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 } = {})`
|
|
238
238
|
|
|
239
239
|
### `src/client/composables/records/useView.js`
|
|
240
240
|
Exports
|
|
241
|
-
- `useView({ resource = null, ownershipFilter = ROUTE_VISIBILITY_WORKSPACE, surfaceId = "", access = "auto", apiSuffix = "", queryKeyFactory = null, viewPermissions = [], readMethod = "GET", readEnabled = true, 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 } = {})`
|
|
241
|
+
- `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 } = {})`
|
|
242
242
|
|
|
243
243
|
### `src/client/composables/runtime/addEditUiRuntime.js`
|
|
244
244
|
Exports
|
|
@@ -290,7 +290,7 @@ Exports
|
|
|
290
290
|
Exports
|
|
291
291
|
- `buildEndpointReadRequestOptions({ method = "GET", query = null, transport = null } = {})`
|
|
292
292
|
- `buildEndpointWriteRequestOptions({ method = "PATCH", body = undefined, options = null, transport = null } = {})`
|
|
293
|
-
- `useEndpointResource({ queryKey, path = "", enabled = true, client =
|
|
293
|
+
- `useEndpointResource({ queryKey, path = "", enabled = true, client = null, readMethod = "GET", writeMethod = "PATCH", readQuery = null, transport = null, refreshOnPull = false, realtime = null, queryOptions = null, mutationOptions = null, requestRecovery = null, requestRecoveryLabel = "Request", fallbackLoadError = "Unable to load resource.", fallbackSaveError = "Unable to save resource." } = {})`
|
|
294
294
|
Local functions
|
|
295
295
|
- `resolveRequestQuery(value = null)`
|
|
296
296
|
|
|
@@ -303,7 +303,7 @@ Local functions
|
|
|
303
303
|
### `src/client/composables/runtime/useListCore.js`
|
|
304
304
|
Exports
|
|
305
305
|
- `buildListRequestOptions({ requestOptions = null, transport = null, pageParam = null } = {})`
|
|
306
|
-
- `useListCore({ queryKey, path = "", enabled = true, client =
|
|
306
|
+
- `useListCore({ queryKey, path = "", enabled = true, client = null, transport = null, initialPageParam = null, getNextPageParam, selectItems, requestOptions = null, queryOptions = null, requestRecovery = null, requestRecoveryLabel = "List", fallbackLoadError = "Unable to load list." } = {})`
|
|
307
307
|
Local functions
|
|
308
308
|
- `resolveRequestOptionsObject(value = null)`
|
|
309
309
|
- `resolveListRequestMethod(requestOptions = null)`
|
|
@@ -445,7 +445,7 @@ Exports
|
|
|
445
445
|
|
|
446
446
|
### `src/client/composables/useCommand.js`
|
|
447
447
|
Exports
|
|
448
|
-
- `useCommand({ ownershipFilter = ROUTE_VISIBILITY_WORKSPACE, surfaceId = "", access = "auto", apiSuffix = "", runPermissions = [], writeMethod = "POST", transport = null, placementSource = "users-web.command", fallbackRunError = "Unable to complete action.", fieldErrorKeys = [], clearOnRouteChange = true, model, input, buildRawPayload, buildCommandPayload, buildCommandOptions, onRunSuccess, onRunError, suppressSuccessMessage = false, messages = {}, realtime = null } = {})`
|
|
448
|
+
- `useCommand({ ownershipFilter = ROUTE_VISIBILITY_WORKSPACE, surfaceId = "", access = "auto", apiSuffix = "", runPermissions = [], writeMethod = "POST", client = null, transport = null, placementSource = "users-web.command", fallbackRunError = "Unable to complete action.", fieldErrorKeys = [], clearOnRouteChange = true, model, input, buildRawPayload, buildCommandPayload, buildCommandOptions, onRunSuccess, onRunError, suppressSuccessMessage = false, messages = {}, realtime = null } = {})`
|
|
449
449
|
|
|
450
450
|
### `src/client/composables/useCrudAddEditScreen.js`
|
|
451
451
|
Exports
|
|
@@ -567,7 +567,13 @@ Exports
|
|
|
567
567
|
|
|
568
568
|
### `src/client/lib/httpClient.js`
|
|
569
569
|
Exports
|
|
570
|
+
- `configureUsersWebHttpClient(optionsOrClient = {})`
|
|
571
|
+
- `createUsersWebHttpClient(options = {})`
|
|
572
|
+
- `getUsersWebHttpClient()`
|
|
573
|
+
- `resetUsersWebHttpClientForTests()`
|
|
570
574
|
- `usersWebHttpClient`
|
|
575
|
+
Local functions
|
|
576
|
+
- `normalizeOptions(value = null)`
|
|
571
577
|
|
|
572
578
|
### `src/client/lib/permissions.js`
|
|
573
579
|
Exports
|