@jskit-ai/agent-docs 0.1.51 → 0.1.52

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.
@@ -574,31 +574,40 @@ try {
574
574
 
575
575
  Use the narrow `@jskit-ai/shell-web/client/asyncModuleRecovery` subpath for this runtime, especially from modules that are imported by Node-mode Vitest suites. The aggregate `@jskit-ai/shell-web/client` barrel also exports the composable for normal Vite app code, but that barrel includes `.vue` component exports and can require Vue SFC handling in tests.
576
576
 
577
- Request connectivity failures use a separate shell recovery path. Generated apps already configure TanStack Query to retry transient failures with capped backoff. `shell-web` then observes the app's `jskit.client.query-client` and, when an active query finishes in a transport failure such as `Network request failed.` or `Failed to fetch`, reports an `app-recoverable` banner with a `Retry` action that refetches that exact query. Normal HTTP validation and application errors stay local to the screen.
577
+ Request connectivity failures use a separate shell recovery path. Generated apps already configure TanStack Query to retry transient failures with capped backoff. `shell-web` then observes the app's `jskit.client.query-client` and, when an active safe-read query finishes in a transport failure such as `Network request failed.` or `Failed to fetch`, reports an `app-recoverable` banner with a `Retry` action that refetches that exact query. Normal HTTP validation and application errors stay local to the screen.
578
578
 
579
- Imperative app code only needs the public runtime when it catches a request failure outside the standard query/resource composables:
579
+ That recovery path is intentionally a safe `GET`/`HEAD` read refetch system, not a general HTTP replay system. User-visible reads should go through Query-backed JSKIT primitives such as `useEndpointResource()`, `useList()`, `useView()`, `useAddEdit()`, or generated CRUD screen composables. Those primitives mark Query entries with `jskit.requestRecoveryMethod`, so the shell only offers Retry for safe reads. Do not catch raw `fetch(...)` failures in each panel just to call the shell recovery runtime manually.
580
+
581
+ For a custom endpoint read, attach the recovery label to the Query-backed resource:
580
582
 
581
583
  ```js
582
- import { useShellRequestRecoveryRuntime } from "@jskit-ai/shell-web/client/requestRecovery";
583
-
584
- const requestRecovery = useShellRequestRecoveryRuntime();
585
-
586
- async function loadProjectAccess() {
587
- try {
588
- return await fetch("/api/project-access");
589
- } catch (error) {
590
- requestRecovery?.report(error, {
591
- label: "Project access",
592
- retry: loadProjectAccess
593
- });
594
- throw error;
584
+ const projectAccess = useEndpointResource({
585
+ queryKey: ["project-access", projectId],
586
+ path: `/api/projects/${projectId}/access`,
587
+ requestRecoveryLabel: "Project access"
588
+ });
589
+ ```
590
+
591
+ If you need lower-level Query options, the same metadata can live on query meta:
592
+
593
+ ```js
594
+ const projectAccess = useEndpointResource({
595
+ queryKey: ["project-access", projectId],
596
+ path: `/api/projects/${projectId}/access`,
597
+ queryOptions: {
598
+ meta: {
599
+ jskit: {
600
+ requestRecoveryLabel: "Project access",
601
+ requestRecoveryMethod: "GET"
602
+ }
603
+ }
595
604
  }
596
- }
605
+ });
597
606
  ```
598
607
 
599
- `useShellRequestRecoveryRuntime()` returns `null` when the shell runtime is not available in the current Vue context. Use the narrow `@jskit-ai/shell-web/client/requestRecovery` subpath for the same reason as async module recovery: it avoids pulling `.vue` component exports into Node-mode test suites.
608
+ For JSKIT read-composable screens, the default is automatic. Hand-written TanStack Query reads outside those composables must set `meta.jskit.requestRecoveryMethod` to `GET` or `HEAD`; unmarked queries are ignored by the shell recovery observer. Set `meta: { jskit: { requestRecovery: false } }` only when a query deliberately owns its entire connectivity recovery UI.
600
609
 
601
- For query-backed screens, the default is automatic. Set `meta: { jskit: { requestRecovery: false } }` only when a query deliberately owns its entire connectivity recovery UI. Set `meta: { jskit: { requestRecoveryLabel: "Project access" } }` when the default `Request` label is too generic.
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.
602
611
 
603
612
  ### The home page talks to the backend
604
613
 
@@ -682,6 +682,18 @@ Why this is the standard JSKIT shape:
682
682
  - The higher-level list, view, add/edit, and command runtimes send requests through the standard HTTP runtime instead of ad hoc request code.
683
683
  - The default client runtime uses `usersWebHttpClient`, which already handles credentials and CSRF token behavior.
684
684
  - `useEndpointResource()` gives the shared endpoint primitive for loading, saving, and standard load/save error handling. Higher-level runtimes like `useCommand()` and `useAddEdit()` layer UI feedback and field-error behavior on top of that primitive.
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
+ - 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
+
688
+ When a custom read needs a better recovery banner label, pass it through the read primitive rather than reporting the failure manually:
689
+
690
+ ```js
691
+ const resource = useEndpointResource({
692
+ queryKey: ["project-access", projectId],
693
+ path: `/api/projects/${projectId}/access`,
694
+ requestRecoveryLabel: "Project access"
695
+ });
696
+ ```
685
697
 
686
698
  If you need a custom scoped endpoint path outside the higher-level runtimes, prefer `usePaths().api(...)` rather than hand-building scoped URLs:
687
699
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jskit-ai/agent-docs",
3
- "version": "0.1.51",
3
+ "version": "0.1.52",
4
4
  "description": "Distributed JSKIT agent references, prompts, guides, and generated reference maps.",
5
5
  "type": "module",
6
6
  "files": [
@@ -68,9 +68,11 @@ Error presentation rules:
68
68
 
69
69
  - Resource load failures should stay local to the screen with the runtime's `loadError` state and a retry action.
70
70
  - Do not force global banners for ordinary list/view/add-edit load failures; the shell error policy treats `resource-load` as `silent` by default.
71
- - Transport/connectivity failures are different from ordinary resource-load errors. `shell-web` observes the app QueryClient and reports active query failures such as `Network request failed.` or `Failed to fetch` through request recovery with a `Retry` action.
72
- - For imperative app-caught request failures outside the standard query/resource composables, use `useShellRequestRecoveryRuntime()` from `@jskit-ai/shell-web/client/requestRecovery` and pass a retry callback.
73
- - Use query meta `jskit.requestRecovery = false` only when a query owns its full connectivity recovery UI, and `jskit.requestRecoveryLabel` when the recovery banner needs a better label.
71
+ - Transport/connectivity failures are different from ordinary resource-load errors. `shell-web` observes the app QueryClient and reports active safe-read query failures such as `Network request failed.` or `Failed to fetch` through request recovery with a `Retry` action that calls `query.refetch()`.
72
+ - User-visible reads should be TanStack Query-backed through `useEndpointResource()`, `useList()`, `useView()`, `useAddEdit()`, or CRUD screen composables. Do not load panel data with raw `fetch(...)` plus manual request recovery reporting.
73
+ - Automatic shell request recovery is for `GET` and `HEAD` read refetches. Do not use it to replay `POST`, `PATCH`, `PUT`, or `DELETE`; saving and command screens own their mutation state and feedback.
74
+ - JSKIT read composables mark their Query entries with `jskit.requestRecoveryMethod`. For hand-written TanStack Query reads outside those composables, set `meta.jskit.requestRecoveryMethod` to `GET` or `HEAD`.
75
+ - Use `requestRecoveryLabel` on JSKIT read composables, or query meta `jskit.requestRecoveryLabel`, when the recovery banner needs a better label. Use `jskit.requestRecovery = false` only when a query owns its full connectivity recovery UI.
74
76
  - Use `useUiFeedback()` or `useCommand()` for user-triggered action feedback. Those flows report `action-feedback`, and the app-owned shell error policy decides the channel.
75
77
  - Use explicit shell error intents only for exceptional app-level cases: `app-recoverable` for recoverable shell/runtime failures and `blocking` for failures that require user attention.
76
78
 
@@ -82,3 +84,4 @@ Avoid:
82
84
  - using a lower-level seam when a higher-level routed CRUD or command runtime already fits
83
85
  - smuggling query params into `apiUrlTemplate`
84
86
  - reporting routine resource load errors through hand-written global snackbar/banner calls
87
+ - calling `useShellRequestRecoveryRuntime().report(...)` from normal panels just to recover an HTTP read
@@ -374,6 +374,11 @@ Local functions
374
374
  - `resolveQueryMeta(query = null)`
375
375
  - `isRequestRecoveryDisabled(query = null)`
376
376
  - `resolveQueryRecoveryLabel(query = null)`
377
+ - `resolveQueryRecoverySource(query = null)`
378
+ - `resolveQueryRecoveryDedupeKey(query = null, fallback = "")`
379
+ - `resolveQueryRecoveryDedupeWindowMs(query = null)`
380
+ - `resolveQueryRecoveryMethod(query = null)`
381
+ - `isSafeQueryRecoveryMethod(query = null)`
377
382
  - `isActiveQuery(query = null)`
378
383
  - `recoverableQueryError(query = null)`
379
384
  - `createQueryRetry(queryClient, query = 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, 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", 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, 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, 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, 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, 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 = usersWebHttpClient, readMethod = "GET", writeMethod = "PATCH", readQuery = null, transport = null, refreshOnPull = false, realtime = null, queryOptions = null, mutationOptions = null, fallbackLoadError = "Unable to load resource.", fallbackSaveError = "Unable to save resource." } = {})`
293
+ - `useEndpointResource({ queryKey, path = "", enabled = true, client = usersWebHttpClient, 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,9 +303,10 @@ 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 = usersWebHttpClient, transport = null, initialPageParam = null, getNextPageParam, selectItems, requestOptions = null, queryOptions = null, fallbackLoadError = "Unable to load list." } = {})`
306
+ - `useListCore({ queryKey, path = "", enabled = true, client = usersWebHttpClient, 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
+ - `resolveListRequestMethod(requestOptions = null)`
309
310
 
310
311
  ### `src/client/composables/runtime/useUiFeedback.js`
311
312
  Exports
@@ -380,8 +381,21 @@ Exports
380
381
 
381
382
  ### `src/client/composables/support/resourceLoadStateHelpers.js`
382
383
  Exports
384
+ - `buildRequestRecoveryMeta(requestRecovery = null, defaults = {})`
383
385
  - `hasResolvedQueryData({ query = null, data = null } = {})`
384
386
  - `mergeQueryMeta(queryOptions = null, meta = {})`
387
+ - `mergeRequestRecoveryQueryMeta(queryOptions = null, requestRecovery = null, defaults = {})`
388
+ Local functions
389
+ - `normalizeText(value = "")`
390
+ - `firstNormalizedText(...values)`
391
+ - `firstNonNegativeFiniteNumber(...values)`
392
+ - `normalizePlainObject(value = null)`
393
+ - `normalizeRequestRecoveryInput(requestRecovery = null)`
394
+ - `normalizeRequestRecoveryMethod(value = "")`
395
+ - `isRequestRecoveryMetaDisabled(sourceJskitMeta = {}, sourceMeta = {})`
396
+ - `hasUsableMetaValue(source = {}, key = "")`
397
+ - `hasRequestRecoveryMetaValue(sourceJskitMeta = {}, sourceMeta = {}, key = "")`
398
+ - `resolveRequestRecoveryDefaults(queryOptions = null, defaults = {})`
385
399
 
386
400
  ### `src/client/composables/support/routeTemplateHelpers.js`
387
401
  Exports
@@ -472,13 +486,13 @@ Local functions
472
486
 
473
487
  ### `src/client/composables/useCrudListScreen.js`
474
488
  Exports
475
- - `useCrudListScreen({ adapter = null, resource = null, resourceNamespace = "resource", apiSuffix = "", recordIdParam = "recordId", recordIdSelector = null, titleFallbackFieldKey = "", viewUrlTemplate = "", editUrlTemplate = "", newUrlTemplate = "", recordChangedEvents = [], listFilters = {}, listBulkActions = [], routeQueryBlacklist = Object.freeze(["include", "cursor", "limit"]), fallbackLoadError = "Unable to load records." } = {})`
489
+ - `useCrudListScreen({ adapter = null, resource = null, resourceNamespace = "resource", apiSuffix = "", recordIdParam = "recordId", recordIdSelector = null, titleFallbackFieldKey = "", viewUrlTemplate = "", editUrlTemplate = "", newUrlTemplate = "", recordChangedEvents = [], listFilters = {}, listBulkActions = [], routeQueryBlacklist = Object.freeze(["include", "cursor", "limit"]), requestRecoveryLabel = "Records", fallbackLoadError = "Unable to load records." } = {})`
476
490
  Local functions
477
491
  - `formatCrudListCardValue(value)`
478
492
 
479
493
  ### `src/client/composables/useCrudViewScreen.js`
480
494
  Exports
481
- - `useCrudViewScreen({ adapter = null, resource = null, resourceNamespace = "resource", apiUrlTemplate = "", recordIdParam = "recordId", titleFallbackFieldKey = "", listUrlTemplate = "", editUrlTemplate = "", recordChangedEvent = "", fallbackLoadError = "Unable to load record.", notFoundMessage = "Record not found." } = {})`
495
+ - `useCrudViewScreen({ adapter = null, resource = null, resourceNamespace = "resource", apiUrlTemplate = "", recordIdParam = "recordId", titleFallbackFieldKey = "", listUrlTemplate = "", editUrlTemplate = "", recordChangedEvent = "", requestRecoveryLabel = "Record", fallbackLoadError = "Unable to load record.", notFoundMessage = "Record not found." } = {})`
482
496
 
483
497
  ### `src/client/composables/usePagedCollection.js`
484
498
  Exports