@jskit-ai/agent-docs 0.1.49 → 0.1.51

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.
@@ -557,7 +557,7 @@ The default error policy is intent-based. Runtime code reports what kind of erro
557
557
  When app code catches a dynamic import failure itself, report it through the shell async module recovery runtime so it uses the same reload banner as router chunk failures:
558
558
 
559
559
  ```js
560
- import { useShellAsyncModuleRecoveryRuntime } from "@jskit-ai/shell-web/client";
560
+ import { useShellAsyncModuleRecoveryRuntime } from "@jskit-ai/shell-web/client/asyncModuleRecovery";
561
561
 
562
562
  const asyncModuleRecovery = useShellAsyncModuleRecoveryRuntime();
563
563
 
@@ -572,6 +572,34 @@ try {
572
572
 
573
573
  `useShellAsyncModuleRecoveryRuntime()` returns `null` when the shell runtime is not available in the current Vue context. That lets app-owned components use optional chaining instead of duplicating shell-web's internal injection token.
574
574
 
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
+
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.
578
+
579
+ Imperative app code only needs the public runtime when it catches a request failure outside the standard query/resource composables:
580
+
581
+ ```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;
595
+ }
596
+ }
597
+ ```
598
+
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.
600
+
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.
602
+
575
603
  ### The home page talks to the backend
576
604
 
577
605
  `src/pages/home/index.vue` uses Vue Query to fetch `/api/health` and display the result in the UI.
@@ -358,7 +358,7 @@ void bootstrapClientShellApp({
358
358
  });
359
359
  ```
360
360
 
361
- The flow is simple once you read it in order: config in, runtime in memory, router built from that runtime, app-owned Vue plugins created once, app bootstrapped. Pinia, Vue Query, the router, and Vuetify are owned by the base app bootstrap so runtime packages share the same instances instead of carrying independent copies.
361
+ The flow is simple once you read it in order: config in, runtime in memory, router built from that runtime, app-owned Vue plugins created once, app bootstrapped. Pinia, Vue Query, the router, and Vuetify are owned by the base app bootstrap so runtime packages share the same instances instead of carrying independent copies. Passing the same `queryClient` into `bootstrapClientShellApp(...)` also gives `shell-web` the QueryClient it observes for automatic request recovery when transport failures exhaust their normal retries.
362
362
 
363
363
  <DocsInDepth title="In depth" preview-height="15rem">
364
364
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jskit-ai/agent-docs",
3
- "version": "0.1.49",
3
+ "version": "0.1.51",
4
4
  "description": "Distributed JSKIT agent references, prompts, guides, and generated reference maps.",
5
5
  "type": "module",
6
6
  "files": [
package/patterns/INDEX.md CHANGED
@@ -18,7 +18,7 @@ How to use it:
18
18
  - `page-scaffolding.md`
19
19
  - child crud, nested crud, embedded list, subroute, separate page, parent/child layout
20
20
  - `child-cruds.md`
21
- - crud scaffold, crud server, crud ui, table creation, migrations, `crud-server-generator`, `crud-ui-generator`
21
+ - crud scaffold, crud server, crud ui, table creation, migrations, direct knex, weird-custom persistence, `crud-server-generator`, `crud-ui-generator`
22
22
  - `crud-scaffolding.md`
23
23
  - CRUD links, record placeholders, `paths.page()`, `resolveViewUrl`, `resolveEditUrl`, `resolveParams`
24
24
  - `crud-links.md`
@@ -68,6 +68,9 @@ 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
74
  - Use `useUiFeedback()` or `useCommand()` for user-triggered action feedback. Those flows report `action-feedback`, and the app-owned shell error policy decides the channel.
72
75
  - 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.
73
76
 
@@ -40,6 +40,18 @@ Meaning of `--internal`:
40
40
  - it only suppresses public HTTP CRUD route registration
41
41
  - it is not a substitute for ownership columns or action/route permissions
42
42
 
43
+ When a weird-custom persistence lane is proposed:
44
+
45
+ - Treat hand-written repositories for persisted app-owned entity tables as an exception path, not a normal choice.
46
+ - That includes things like:
47
+ - direct knex instead of generated CRUD ownership
48
+ - a custom repository/service/provider stack for a normal persisted entity table
49
+ - inherited-ownership or mixed-visibility workarounds that dodge the standard CRUD ownership model
50
+ - Before taking that path, stop and ask the developer for explicit approval.
51
+ - Record the exact approval and the approved exception in `.jskit/WORKBOARD.md` before coding.
52
+ - If that exception changes the durable architecture rather than only the current chunk, record it in `.jskit/APP_BLUEPRINT.md` too.
53
+ - Without that explicit approval record, do not take the weird-custom persistence path.
54
+
43
55
  Avoid:
44
56
 
45
57
  - writing a hand migration for a CRUD table that JSKIT CRUD scaffolding is supposed to own
@@ -207,6 +207,10 @@ Exports
207
207
  - `useShellErrorPresentationStore`
208
208
  - `SHELL_ASYNC_MODULE_RECOVERY_RUNTIME_KEY`
209
209
  - `useShellAsyncModuleRecoveryRuntime`
210
+ - `SHELL_REQUEST_RECOVERY_RUNTIME_KEY`
211
+ - `isRecoverableRequestError`
212
+ - `requestRecoveryMessage`
213
+ - `useShellRequestRecoveryRuntime`
210
214
  - `BOOTSTRAP_PAYLOAD_HANDLER_TAG`
211
215
  - `registerBootstrapPayloadHandler`
212
216
  - `resolveBootstrapPayloadHandlers`
@@ -342,6 +346,40 @@ Local functions
342
346
  - `installRouterErrorBridge(app, errorRuntime, logger)`
343
347
  - `createShellAsyncModuleRecoveryRuntime({ app, logger = null } = {})`
344
348
 
349
+ ### `src/client/requestRecovery/index.js`
350
+ Exports
351
+ - `SHELL_REQUEST_RECOVERY_RUNTIME_KEY`
352
+ - `useShellRequestRecoveryRuntime`
353
+ - `isRecoverableRequestError`
354
+ - `requestRecoveryMessage`
355
+
356
+ ### `src/client/requestRecovery/inject.js`
357
+ Exports
358
+ - `SHELL_REQUEST_RECOVERY_RUNTIME_KEY`
359
+ - `isShellRequestRecoveryRuntime(value)`
360
+ - `useShellRequestRecoveryRuntime()`
361
+
362
+ ### `src/client/requestRecovery/runtime.js`
363
+ Exports
364
+ - `createShellRequestRecoveryRuntime({ app, logger = null } = {})`
365
+ - `isRecoverableRequestError(error = null)`
366
+ - `requestRecoveryMessage(error = null, { label = "Request", message = "" } = {})`
367
+ Local functions
368
+ - `normalizeText(value, fallback = "")`
369
+ - `errorMessage(error = null)`
370
+ - `errorCode(error = null)`
371
+ - `errorName(error = null)`
372
+ - `normalizeRequestErrorStatus(error = null)`
373
+ - `isCanceledRequestError(error = null)`
374
+ - `resolveQueryMeta(query = null)`
375
+ - `isRequestRecoveryDisabled(query = null)`
376
+ - `resolveQueryRecoveryLabel(query = null)`
377
+ - `isActiveQuery(query = null)`
378
+ - `recoverableQueryError(query = null)`
379
+ - `createQueryRetry(queryClient, query = null)`
380
+ - `resolveQueryHash(query = null)`
381
+ - `installRecoverableQueryObserver({ app, runtime, logger } = {})`
382
+
345
383
  ### `src/client/runtime/bootstrapRuntime.js`
346
384
  Exports
347
385
  - `createShellBootstrapRuntime({ app, logger = null, fetchImplementation = globalThis.fetch, bootstrapPath = DEFAULT_BOOTSTRAP_PATH } = {})`