@jskit-ai/agent-docs 0.1.27 → 0.1.28

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 (40) hide show
  1. package/DISTR_AGENT.md +1 -0
  2. package/guide/agent/app-extras/assistant.md +2 -2
  3. package/guide/agent/app-extras/mobile-capacitor.md +10 -3
  4. package/guide/agent/app-extras/realtime.md +11 -11
  5. package/guide/agent/app-setup/a-more-interesting-shell.md +52 -44
  6. package/guide/agent/app-setup/authentication.md +40 -22
  7. package/guide/agent/app-setup/console.md +5 -5
  8. package/guide/agent/app-setup/database-layer.md +15 -15
  9. package/guide/agent/app-setup/initial-scaffolding.md +37 -5
  10. package/guide/agent/app-setup/multi-homing.md +28 -28
  11. package/guide/agent/app-setup/users.md +22 -22
  12. package/guide/agent/app-setup/working-with-the-jskit-cli.md +13 -6
  13. package/guide/agent/generators/advanced-cruds.md +111 -68
  14. package/guide/agent/generators/crud-generators.md +5 -5
  15. package/guide/agent/generators/ui-generators.md +15 -13
  16. package/guide/agent/index.md +1 -1
  17. package/package.json +1 -1
  18. package/patterns/INDEX.md +4 -1
  19. package/patterns/client-requests.md +23 -6
  20. package/patterns/crud-repository-mapping.md +1 -1
  21. package/patterns/crud-scaffolding.md +10 -1
  22. package/patterns/filters.md +28 -10
  23. package/patterns/generated-ui-contract-tracking.md +62 -0
  24. package/patterns/page-scaffolding.md +17 -0
  25. package/patterns/placements.md +60 -0
  26. package/patterns/surfaces.md +5 -1
  27. package/patterns/ui-testing.md +3 -0
  28. package/reference/autogen/KERNEL_MAP.md +30 -1
  29. package/reference/autogen/packages/assistant.md +1 -1
  30. package/reference/autogen/packages/crud-ui-generator.md +19 -8
  31. package/reference/autogen/packages/kernel.md +38 -6
  32. package/reference/autogen/packages/realtime.md +1 -0
  33. package/reference/autogen/packages/shell-web.md +35 -3
  34. package/reference/autogen/packages/ui-generator.md +26 -5
  35. package/reference/autogen/packages/users-core.md +2 -0
  36. package/reference/autogen/packages/users-web.md +92 -3
  37. package/reference/autogen/packages/workspaces-web.md +3 -1
  38. package/reference/autogen/tooling/jskit-cli.md +24 -8
  39. package/templates/app/AGENTS.md +1 -0
  40. package/workflow/bootstrap.md +1 -0
@@ -17,21 +17,35 @@ Ask first:
17
17
  - whether lookup filters need remote autocomplete search
18
18
  - whether there are presets such as "Today", "Last 7 Days", or "Only Archived"
19
19
 
20
- Default JSKIT pattern:
21
- 1. Put shared filter definitions in the CRUD package.
20
+ Default JSKIT client pattern:
21
+ 1. Generated CRUD list pages include a page-local `listFilters.js` file next to `index.vue`.
22
+ 2. Put client filter definitions in that file with `defineCrudListFilters(...)`.
23
+ 3. The generated `index.vue` passes `listFilters` into `useCrudListScreen(...)`; the shared list screen builds `useCrudListFilters(listFilters)`, passes `filterRuntime.queryParams` into the list request, and renders `CrudListFilterSurface`.
24
+ 4. If `listFilters` is empty, the filter surface renders nothing and the page behaves like a normal searchable list.
25
+ 5. The AI/app author is responsible for ensuring the server accepts and applies the query params declared in `listFilters.js`.
26
+ 6. For lookup-backed filters, use `useCrudListFilterLookups(...)` when the page needs remote options or readable chip labels.
27
+
28
+ Generated client shape:
29
+ - `src/pages/<surface>/<resource>/listFilters.js`
30
+ - `const listFilters = defineCrudListFilters({ ... })`
31
+ - `useCrudListScreen({ ..., listFilters })`
32
+ - shared screen runtime owns:
33
+ - `const filterRuntime = useCrudListFilters(listFilters)`
34
+ - `queryParams: filterRuntime.queryParams`
35
+ - `<CrudListFilterSurface :filters="listFilters" :runtime="filterRuntime" />`
36
+
37
+ Server-side pattern, only when implementing real backend filter semantics:
38
+ 1. Put reusable server-aware filter definitions in the CRUD package if the filter contract needs to be shared outside one generated page.
22
39
  Example path: `packages/<crud>/src/shared/<crud>ListFilters.js`
23
40
  2. Build the server runtime from that module with `createCrudListFilters(...)`.
24
41
  3. Build route/action validators explicitly with `createCrudListFilterQueryField(...)` plus `createCrudListFilterQuerySchema(...)`, and use `applyQuery(...)` in the repository. There is no default validator mode or route-runtime alias.
25
- 4. Build the client runtime from the same shared definitions with `useCrudListFilters(...)`. Presets can use static `values` or dynamic `resolveValues({ values, filters, presetKey, preset })`.
26
- 5. Pass `listFilters.queryParams` into `useCrudList(...)`.
27
- 6. For lookup-backed filters, use `useCrudListFilterLookups(...)` instead of hand-rolling `useList()` in each page.
28
42
 
29
43
  Exact file checklist:
30
44
  - create `packages/<crud>/src/shared/<crud>ListFilters.js`
31
45
  - update `packages/<crud>/src/server/registerRoutes.js` and `packages/<crud>/src/server/actions.js` so the list query validator lists structured filter params explicitly with `createCrudListFilterQueryField(...)` inside `createCrudListFilterQuerySchema(...)`, or update `packages/<crud>/src/server/listQueryValidators.js` if that package already extracts list-query composition there
32
46
  - update `packages/<crud>/src/server/repository.js` so list queries call the runtime's `applyQuery(...)`
33
- - update the app-owned list page or list-runtime composable under `src/pages/...` or `src/composables/...` so it builds `useCrudListFilters(...)`, passes `queryParams` into `useCrudList(...)`, and binds chips / reset behavior
34
- - for lookup-backed filters, update that same client file to build `useCrudListFilterLookups(...)` and bind the lookup control from `resolveLookup(...)`
47
+ - update the generated page-local `listFilters.js` first; only edit `index.vue` if a specialist lookup label/runtime integration is needed
48
+ - for lookup-backed filters, wire `useCrudListFilterLookups(...)` beside the existing generated filter runtime instead of replacing `CrudListFilterSurface`
35
49
 
36
50
  Validation mode is part of the contract:
37
51
  - there is no default mode and no fallback alias, so every explicit structured filter field must choose `invalidValues: "reject"` or `invalidValues: "discard"` deliberately
@@ -72,11 +86,15 @@ Avoid:
72
86
  - hiding accepted structured filter params behind whole-query validator generation when the route/action contract can list them directly
73
87
  - hand-rolled preset apply/reset/active-state helpers when `useCrudListFilters(..., { presets })`, `applyPreset(...)`, and `matchesPreset(...)` fit
74
88
  - per-screen `useList()` wrappers for lookup-backed filters when `useCrudListFilterLookups(...)` fits
75
- - a second page-local filter-definition file when `packages/<crud>/src/shared/<crud>ListFilters.js` should be the source of truth
89
+ - editing generated `.vue` files just to add basic filter controls; use the page-local `listFilters.js` seam first
76
90
  - overloading `q` with structured filter meaning
77
- - local or inline filter-definition objects passed into `useCrudListFilters(...)` or `createCrudListFilters(...)`; `jskit doctor` expects those runtimes to import from a CRUD shared `*ListFilters` module
91
+ - inline filter-definition objects passed into `useCrudListFilters(...)` or `createCrudListFilters(...)`; keep definitions in a named module
78
92
 
79
93
  Good shape:
94
+ - `src/pages/home/customers/listFilters.js`
95
+ - `const listFilters = defineCrudListFilters({ status: { type: "enum", ... } })`
96
+ - generated page passes `listFilters` into `useCrudListScreen(...)`
97
+ - shared screen runtime passes `filterRuntime.queryParams` into the list request
80
98
  - `packages/receivals/src/shared/receivalListFilters.js`
81
99
  - `createCrudListFilters(RECEIVAL_LIST_FILTER_DEFINITIONS, ...)`
82
100
  - `const listFilters = useCrudListFilters(RECEIVAL_LIST_FILTER_DEFINITIONS, { presets: [...] })`
@@ -89,7 +107,7 @@ Preset contract notes:
89
107
  - if the URL contains `status=archived&status=bogus`, a preset for only `archived` should not render as active while the `bogus` chip is still visible
90
108
 
91
109
  Review checks:
92
- - one shared filter definition source of truth
110
+ - 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
93
111
  - server validator/repository logic derived from that source, with route/action query params still listed explicitly
94
112
  - client query params/chips/reset logic derived from that source
95
113
  - lookup-backed filters use the shared lookup helper, not a page-local mini-framework
@@ -0,0 +1,62 @@
1
+ # Generated UI Contract Tracking
2
+
3
+ Use this file to track the generator-level UI contract work. Keep entries concrete and update the checklist as each slice lands.
4
+
5
+ ## Goal
6
+
7
+ Generated JSKIT apps should feel like real adaptive apps by default, not framework demos. The contract must be enforced in generators, descriptors, docs, and tests so it does not drift.
8
+
9
+ ## Current Scope
10
+
11
+ - [x] Centralize navigation role behavior beyond per-generator helpers.
12
+ - [x] Improve product-aware navigation inference and CLI prompting.
13
+ - [x] Audit generated/package UI templates for placeholder or instructional live-page copy.
14
+ - [x] Formalize surface density rules for app, admin, console, and settings screens.
15
+ - [x] Add shared typography/density primitives or generator support helpers where they reduce duplication.
16
+ - [x] Enforce "no cards inside cards" for generated page architecture while preserving intentional tool/dialog cards.
17
+ - [x] Expand UI verification from shell smoke coverage to generator-pattern smoke coverage for current page, CRUD, and shell outputs.
18
+ - [x] Centralize the JSKIT design contract and make tests consume it.
19
+
20
+ ## Work Slices
21
+
22
+ - [x] Slice 1: create the central contract/support seam and move navigation-role constants into it.
23
+ - [x] Slice 2: wire `ui-generator` and `crud-ui-generator` to the shared contract.
24
+ - [x] Slice 3: add template/content contract scans for placeholder copy, card-shell misuse, and missing responsive hooks.
25
+ - [x] Slice 4: audit package templates that ship live UI and classify intentional cards.
26
+ - [x] Slice 5a: extend generated app Playwright smoke coverage to assert the generated screen contract.
27
+ - [x] Slice 5b: enforce page, CRUD, and shell generator-pattern verification through shared source contracts plus responsive smoke checks.
28
+ - [x] Slice 6: update distributed agent docs and regenerated references/catalog outputs.
29
+
30
+ ## Verification Checklist
31
+
32
+ - [x] `npm run lint`
33
+ - [x] `npm run check:runtime-deps`
34
+ - [x] `npm run jskit -- lint-descriptors`
35
+ - [x] `npm run catalog:build`
36
+ - [x] `npm run agent-docs:build`
37
+ - [x] `npm test --workspace @jskit-ai/kernel`
38
+ - [x] `npm test --workspace @jskit-ai/ui-generator`
39
+ - [x] `npm test --workspace @jskit-ai/crud-ui-generator`
40
+ - [x] `npm test --workspace @jskit-ai/shell-web`
41
+ - [x] `npm test --workspace @jskit-ai/users-web`
42
+ - [x] `npm test --workspace @jskit-ai/workspaces-web`
43
+ - [x] `npm test --workspace @jskit-ai/jskit-cli`
44
+ - [x] `npm test --workspace @jskit-ai/create-app`
45
+ - [x] `npm test --workspace @jskit-ai/agent-docs`
46
+ - [x] `git diff --check`
47
+
48
+ ## Notes
49
+
50
+ - Do not weaken semantic placement defaults while adding navigation inference.
51
+ - Do not turn the contract into runtime business logic; it is generator and template policy.
52
+ - Do not remove intentional cards from specialist UI components just to satisfy a broad scan.
53
+ - Keep generated files deterministic and update catalog/agent-doc outputs when descriptors or exported symbols change.
54
+ - Kernel shared UI contract must stay surface-id agnostic. Concrete mappings like admin/console to operator profile belong in generators or package templates.
55
+ - Item 3 is complete for current generated surfaces: page, CRUD, shell, and starter outputs require compact/medium/expanded coverage, horizontal overflow checks, generated screen checks, and 48px tap target checks. Calendar/grid/bottom-sheet specialist generators remain future scope until those generators exist.
56
+ - Item 5 is complete for current generators: `primary`, `secondary`, `utility`, `detail`, `workflow`, and `none` are centralized in the generated UI contract, generators consume that contract, and `utility` resolves to seeded `shell.global-actions` topology.
57
+ - Item 6 is complete for the default shell: compact app bars use compact density and bounded top-left/top-right regions, while primary navigation remains in semantic bottom navigation instead of app-bar chrome.
58
+ - CRUD filters are client-side by default: generated list pages create a page-local `listFilters.js` and pass it into `useCrudListScreen(...)`; the shared list screen wires `filterRuntime.queryParams` into the list request and renders `CrudListFilterSurface`. Server filter behavior remains explicit app/package work.
59
+ - CRUD bulk actions are client-side by default: generated list pages create a page-local `listBulkActions.js` and pass it into `useCrudListScreen(...)`; the shared list screen wires `useCrudListBulkActions(...)` and keeps selection controls hidden until actions are declared.
60
+ - Generated CRUD page templates delegate their screen chrome to shared `users-web` screen components (`CrudListScreen`, `CrudViewScreen`, and `CrudAddEditScreen`) so list/view/form load states, retry actions, responsive shell layout, filters, and bulk actions do not drift across generated pages.
61
+ - Routine resource-load errors stay local to the generated screen and retry affordance. Action feedback uses the shell error policy through `action-feedback`.
62
+ - `page.supporting-content` is a semantic supporting region in the default shell. Compact layout renders it as a closed bottom sheet; medium/expanded layouts render it as a closed side panel.
@@ -18,14 +18,31 @@ Rules:
18
18
 
19
19
  - Default to `jskit generate ui-generator page ...` for a new app-owned non-CRUD route page.
20
20
  - Let the generator create both the page file and the matching `src/placement.js` entry, then adapt the generated output if needed.
21
+ - Choose the generated page's product navigation role deliberately. Use `--navigation-role primary` for main destinations, `secondary` for lower-priority shell links, and `detail`, `workflow`, or `none` when the page should not appear in navigation.
21
22
  - If the page link belongs in a non-default semantic slot, discover the public placement first with `jskit list-placements` and pass `--link-placement`.
22
23
  - If you need the concrete outlet inventory, use `jskit list-placements --concrete`; do not target concrete outlets by default.
23
24
  - If the page sits under an existing routed host, check whether `ui-generator page` can infer the correct `page.section-nav` owner before writing a custom link by hand.
24
25
  - If you do not use `ui-generator page`, state exactly why the generator does not fit before editing code.
25
26
  - For a small placeholder route inside an existing route family, update the workboard rather than rewriting the blueprint unless the durable route or surface plan changed.
27
+ - Generated live pages must be usable screens, not instructional scaffolds. Do not ship copy such as "replace this", "use this area", or "this page is ready".
28
+ - Prefer a page header plus a direct `v-sheet` working region. Do not wrap every generated page in a generic `v-card`.
29
+ - If the screen is not implemented yet, use a product-shaped empty state with one clear next action or status, not developer instructions.
30
+ - Primary navigation links belong in semantic placements such as `shell.primary-nav` or `page.section-nav`; do not place every generated route into one drawer by default.
31
+ - Compact layouts must be checked first: no horizontal overflow, no unreachable primary action, and tap targets should be at least 48 px.
32
+
33
+ Generated UI contract:
34
+
35
+ - App-facing screens are phone-first and task-first; admin/console screens may be denser but still need responsive controls.
36
+ - Navigation uses semantic placements by default. Raw `host:position` outlets are advanced infrastructure.
37
+ - Page architecture is header plus direct work region, normally `v-sheet`; do not use generic page-level `v-card` shells.
38
+ - Empty/loading/error states are product-shaped and resource-named.
39
+ - Detail and workflow routes are not primary navigation by default.
40
+ - Generated UI must have compact, medium, and expanded browser checks when it changes user-facing behavior.
26
41
 
27
42
  Avoid:
28
43
 
29
44
  - hand-writing both `src/pages/...` and `src/placement.js` for a normal non-CRUD page before checking `ui-generator`
30
45
  - treating a small page stub as permission to rewrite marketing copy, route architecture, or blueprint scope
31
46
  - claiming that no generator exists without checking the actual `jskit` generator inventory first
47
+ - adding cards inside cards or repeating the page title inside a card title
48
+ - treating Vuetify component defaults as the product architecture
@@ -16,6 +16,65 @@ Check first:
16
16
  - package placement topology
17
17
  - linked component token props
18
18
 
19
+ Mental model:
20
+
21
+ - `src/placement.js` answers "what is being placed?"
22
+ - `src/placementTopology.js` answers "where does this semantic placement render for compact, medium, and expanded layouts?"
23
+ - `<ShellOutlet target="host:position" />` is the concrete recipient rendered by Vue.
24
+ - Semantic ids use dot notation, for example `shell.primary-nav`, `shell.status`, `page.section-nav`, `page.supporting-content`, `settings.sections`.
25
+ - Concrete outlet ids use colon notation, for example `shell-layout:primary-menu`, `shell-layout:top-right`, `home-settings:primary-menu`.
26
+ - Authoring should target semantic placements by default. Concrete outlets are an advanced escape hatch.
27
+
28
+ Placement entries:
29
+
30
+ - Add entries with `addPlacement(...)` in `src/placement.js`.
31
+ - Use `target: "area.slot"` for normal entries.
32
+ - Use `owner` when the semantic placement is scoped to a specific host, for example `target: "page.section-nav", owner: "home-settings"`.
33
+ - Use `kind: "link"` for navigation/menu/tab links. Do not add a link renderer token to the entry unless there is a deliberate override.
34
+ - Use `kind: "component"` for widgets/sections/elements. These entries require `componentToken`.
35
+ - Use `surfaces` to say where the entry is eligible. Missing or `["*"]` means any surface.
36
+ - Use `order` for ordering. Equal order preserves source order.
37
+ - Use `props` for the rendered component props, including labels, icons, `surface`, `scopedSuffix`, `unscopedSuffix`, or explicit `to`.
38
+ - Use `when(context)` only for auth, permissions, feature flags, and runtime state. Do not use `when()` for layout adaptation.
39
+ - Direct concrete placement must use `target: "host:position"` plus `internal: true`. Treat this as low-level infrastructure, not normal app authoring.
40
+
41
+ Placement topology:
42
+
43
+ - `src/placementTopology.js` should be append-friendly: keep a `placements` array, export `addPlacementTopology(value)`, and append `addPlacementTopology(...)` blocks at the bottom.
44
+ - Every semantic placement topology entry needs `id`, optional `owner`, optional `description`, `surfaces`, and all three variants: `compact`, `medium`, and `expanded`.
45
+ - Every variant needs an `outlet: "host:position"`.
46
+ - Variant `renderers` maps semantic `kind` values to component tokens, for example `renderers: { link: "local.main.ui.surface-aware-menu-link-item" }`.
47
+ - Renderer choice for semantic `kind: "link"` placements belongs in topology, not in each placement entry.
48
+ - `default: true` marks the fallback semantic placement that page generators use when no nearer host applies.
49
+ - Package topology is discovered too, but app topology with the same `id` and `owner` overrides package topology in CLI discovery.
50
+
51
+ Runtime behavior:
52
+
53
+ - The shell runtime loads `/src/placementTopology.js` and `/src/placement.js`.
54
+ - Each `ShellOutlet` asks for placements by concrete `target`, current `surface`, and current layout class.
55
+ - Layout classes are `compact`, `medium`, and `expanded`.
56
+ - For semantic entries, runtime matches topology by `target`, `owner`, and `surface`, then chooses the current layout variant.
57
+ - A semantic entry renders only when the selected variant's `outlet` equals the concrete `ShellOutlet target`.
58
+ - Runtime resolves the component token as `entry.componentToken || variant.renderers[entry.kind]`.
59
+ - Entries without a resolvable component token do not render.
60
+ - `when()` receives placement context including `app`, `surface`, `target`, `layoutClass`, runtime context, local outlet context, and context contributors.
61
+
62
+ CLI and generators:
63
+
64
+ - `jskit list-placements` shows semantic placements by default.
65
+ - `jskit list-placements --concrete` shows concrete `ShellOutlet` recipients.
66
+ - `jskit list-placements --all` shows both.
67
+ - `jskit list-placements --json` returns structured semantic and concrete placement data.
68
+ - `ui-generator page`, CRUD UI list generation, and assistant page generation target semantic placements.
69
+ - `--link-placement` for generated pages is a semantic placement id, not a concrete outlet id.
70
+ - If a generated page is under a parent host with a mapped `ShellOutlet`, the generator infers the semantic placement and owner from topology.
71
+ - `ui-generator add-subpages` upgrades a page into a routed child-page host and appends a `page.section-nav` topology entry for the generated concrete outlet.
72
+ - `ui-generator outlet` injects a plain concrete `ShellOutlet` and appends the semantic topology mapping in the same command.
73
+ - `ui-generator page` and `crud-ui-generator crud` accept `--navigation-role` so detail, workflow, and utility routes do not accidentally become primary navigation.
74
+ - `page.supporting-content` is the default semantic place for supporting detail/content overlays. The default shell maps it to a closed compact bottom sheet and a closed medium/expanded side panel.
75
+ - When adding a public concrete outlet by hand, add its semantic topology mapping in the same change.
76
+ - If `jskit list-placements` reports unmapped concrete outlets, either add semantic topology for them or keep those outlets private/internal.
77
+
19
78
  Rules:
20
79
 
21
80
  - In JSKIT, tab-like links and shell/menu entries are often placement-owned, not page-owned.
@@ -25,6 +84,7 @@ Rules:
25
84
  - If the request is really about where a link appears, check the placement `target`, `owner`, `surfaces`, `order`, and `when` fields before changing UI markup.
26
85
  - Placement targets should be semantic by default, such as `shell.primary-nav` or `page.section-nav`; concrete `host:position` outlets are the advanced escape hatch.
27
86
  - Renderer choice for semantic `kind: "link"` placements belongs in topology, not in each placement entry.
87
+ - Supporting detail content should target `page.supporting-content` rather than generating per-page bottom-sheet markup.
28
88
  - Adding a public concrete `ShellOutlet` should happen with a matching semantic topology entry in the same change.
29
89
 
30
90
  Avoid:
@@ -19,12 +19,16 @@ Rules:
19
19
  - Do not silently default new functionality to `app`.
20
20
  - Surface choice is architectural, not cosmetic. It controls routes, access, placement visibility, and often data ownership expectations.
21
21
  - When a link or widget should only appear on certain surfaces, use placement `surfaces` first and keep runtime `when` conditions for behavior-specific gating.
22
+ - App surfaces should be phone-first and task-first: lower chrome, bottom primary navigation on compact layouts, and prominent task actions.
23
+ - Admin and console surfaces can be denser and more utilitarian, but they still need responsive controls and must not become generic drawer-only mobile UIs.
24
+ - Settings surfaces should expose section navigation, direct controls, and real saved state. Avoid fake overview cards and instructional placeholder copy.
25
+ - Utility/status widgets belong in semantic status/action placements such as `shell.status` or `shell.global-actions`, not primary navigation.
22
26
 
23
27
  Ask explicitly about:
24
28
 
25
29
  - route pages
26
30
  - menu entries
27
- - top-left/top-right widgets
31
+ - semantic shell widgets such as `shell.identity`, `shell.status`, and `shell.global-actions`
28
32
  - settings pages
29
33
  - CRUD screens
30
34
  - helper components that only make sense on one surface
@@ -10,6 +10,9 @@ Use when:
10
10
  Rules:
11
11
 
12
12
  - Any chunk that adds or changes user-facing UI must include a Playwright flow that exercises the changed behavior before the chunk is done.
13
+ - Generator or package template UI changes must be checked at compact phone, tablet-ish medium, and expanded desktop widths.
14
+ - For generated UI, the browser checks should cover horizontal overflow, clipped text, invisible text, duplicate navigation, broken route placement, and tap targets under 48 px.
15
+ - Apps with `shell-web` installed should start from the generated `tests/e2e/adaptive-shell.spec.ts` smoke and extend it for feature-specific assertions.
13
16
  - Record that Playwright run with `jskit app verify-ui --command "<playwright command>" --feature "<label>" --auth-mode <mode>`.
14
17
  - `jskit doctor` expects `.jskit/verification/ui.json` to match the current dirty UI file set when UI files are changed.
15
18
  - For local pre-merge review, follow the recorded Playwright run with `jskit doctor --against <base-ref>` so `doctor` compares against the branch delta instead of only the local dirty worktree.
@@ -124,6 +124,35 @@ Exports
124
124
  Exports
125
125
  - `formatDateTime(value, { fallback = "unknown" } = {})`
126
126
 
127
+ ### `support/generatedUiContract.js`
128
+ Exports
129
+ - `GENERATED_UI_FORBIDDEN_CARD_SHELL_PATTERNS`
130
+ - `GENERATED_UI_FORBIDDEN_LIVE_COPY_PATTERNS`
131
+ - `GENERATED_UI_NAVIGATION_ROLE_DEFAULT`
132
+ - `GENERATED_UI_NAVIGATION_ROLE_LINK_PLACEMENTS`
133
+ - `GENERATED_UI_NAVIGATION_ROLE_OPTION`
134
+ - `GENERATED_UI_NAVIGATION_ROLE_VALUES`
135
+ - `GENERATED_UI_NO_LINK_NAVIGATION_ROLES`
136
+ - `GENERATED_UI_SOURCE_CONTRACT_PROFILES`
137
+ - `GENERATED_UI_SURFACE_PROFILES`
138
+ - `assertGeneratedUiSourceContract(source = "", options = {})`
139
+ - `buildGeneratedUiScreenClassName(baseClassName = "", { surfaceProfile = "" } = {})`
140
+ - `collectGeneratedUiSourceContractIssues(source = "", { profile = "", forbidLiveCopy = undefined, forbidCardShell = undefined, forbiddenPatterns = [], requiredPatterns = [] } = {})`
141
+ - `inferGeneratedUiNavigationRole(options = {}, { dynamicRoutePolicy = "leaf", routePath = "" } = {})`
142
+ - `isGeneratedUiNoLinkNavigationRole(value = "")`
143
+ - `normalizeGeneratedUiNavigationRole(value = "")`
144
+ - `resolveGeneratedUiSurfaceProfile(surfaceProfile = "")`
145
+ - `resolveGeneratedUiNavigationRoleLinkPlacement(options = {}, inferenceContext = {})`
146
+ - `shouldCreateGeneratedUiNavigationLink(options = {}, { allowLinkTo = false, dynamicRoutePolicy = "leaf", routePath = "" } = {})`
147
+ Local functions
148
+ - `matchesGeneratedUiContractPattern(source = "", pattern)`
149
+ - `normalizeGeneratedUiContractPattern(patternEntry = {}, fallbackMessage = "")`
150
+ - `normalizeGeneratedUiContractPatternList(patternEntries = [], fallbackMessage = "")`
151
+ - `resolveGeneratedUiSourceContractProfile(profile = "")`
152
+ - `hasExplicitGeneratedUiNavigationRole(options = {})`
153
+ - `normalizeGeneratedUiRouteSegments(routePath = "")`
154
+ - `isGeneratedUiDynamicRouteSegment(routeSegment = "")`
155
+
127
156
  ### `support/index.js`
128
157
  Exports
129
158
  - `isRecord`
@@ -235,7 +264,7 @@ Local functions
235
264
  Exports
236
265
  - `PLACEMENT_LAYOUT_CLASSES`
237
266
  - `describeShellOutletTargets(targets = [])`
238
- - `discoverShellOutletTargetsFromVueSource(source = "", { context = "shell layout" } = {})`
267
+ - `discoverShellOutletTargetsFromVueSource(source = "", { context = "shell layout", enforceSingleDefault = true } = {})`
239
268
  - `findShellOutletTargetById(targets = [], targetId = "")`
240
269
  - `normalizePlacementKind(value = "")`
241
270
  - `normalizePlacementLayoutClass(value = "")`
@@ -54,7 +54,7 @@ Exports
54
54
  - `normalizeConfigScope(value = "")`
55
55
  - `loadAppConfig(appRoot = "")`
56
56
  - `resolveSurfaceDefinition(appConfig = {}, surfaceId = "", optionName = "surface")`
57
- - `assertAssistantSurfaceIsAvailable(appConfig = {}, surfaceId = "")`
57
+ - `assertAssistantSurfaceIsAvailable(appConfig = {}, surfaceId = "", expected = {})`
58
58
  - `resolveAiConfigPrefix(surfaceId = "", explicitPrefix = "")`
59
59
 
60
60
  ### templates
@@ -25,19 +25,26 @@ Local functions
25
25
  - `toSingularKebab(value = "")`
26
26
  - `toPluralKebab(value = "")`
27
27
  - `toTitleFromKebab(value = "", fallback = "")`
28
+ - `buildCrudListCopy(resourceLabels = {})`
28
29
  - `normalizeRelativeAppPath(value = "")`
29
30
  - `requireTargetRootOption(options = {})`
30
31
  - `resolveListTargetFile(targetRoot = "")`
31
32
  - `parseOperationsOption(options)`
32
33
  - `parseDisplayFieldsOption(options)`
33
34
  - `parseParentTitleOption(options)`
35
+ - `shouldCreateNavigationLink(options = {}, inferenceContext = {})`
36
+ - `resolveNavigationRoleLinkPlacement(options = {}, inferenceContext = {})`
34
37
  - `validateDisplayFieldsForOperation(selectedFieldKeys, fields, operationName)`
35
38
  - `filterDisplayFields(selectedFieldKeys, fields)`
36
39
  - `rewriteGeneratedBlockIndent(source = "", { trimPrefix = "", addPrefix = "" } = {})`
37
40
  - `hasLookupFormFields(fields = [])`
41
+ - `hasLookupDisplayFields(fields = [])`
42
+ - `buildListCardSlotProps(fields = [])`
43
+ - `buildListRowSlotProps(fields = [])`
44
+ - `buildCrudFieldsSlotProps(fields = [], { includeMode = false } = {})`
38
45
  - `buildLookupImportLine(fields = [])`
39
46
  - `buildLookupRuntimeSetup(fields = [], { formFieldsVariable = "", resourceNamespace = "", mode = "" } = {})`
40
- - `buildLookupFormProps(fields = [])`
47
+ - `buildLookupFormProps(fields = [], { sourcePrefix = "" } = {})`
41
48
  - `buildLookupFormPropDefinitions({ createFields = [], editFields = [] } = {})`
42
49
  - `filterDefaultHiddenListFields(selectedFieldKeys, fields, { recordIdFieldKey = "" } = {})`
43
50
  - `ensureFields(fields, fallbackFields = createFieldDefinitions({}))`
@@ -45,8 +52,10 @@ Local functions
45
52
  - `resolveResourceNamespace(resource = {}, pageTarget = {}, options = {})`
46
53
  - `resolveResourceLabels(namespace = "", pageTarget = {})`
47
54
  - `resolveTargetRootRelativeRoutePath(pageTarget = {})`
55
+ - `resolveNavigationInferenceRoutePath(pageTarget = {})`
48
56
  - `resolveMenuToPropLine(linkTo = "")`
49
57
  - `resolveMenuOwnerLine(owner = "")`
58
+ - `buildMenuAppendBlock({ hasListOperation = false, menuMarker = "", pageLinkTarget = null, pageTarget = {} } = {})`
50
59
  - `resolveCrudRelativePath(namespace = "")`
51
60
  - `buildListParentTitleImportLine(parentTitleMode = "contextual")`
52
61
  - `buildListHeadingTitleSetup({ parentTitleMode = "contextual", resourceNamespace = "", routeTitle = "Records" } = {})`
@@ -70,6 +79,7 @@ Exports
70
79
  - `resolveNearestParentRouteParamKey(routePath = "", { recordIdParam = "recordId" } = {})`
71
80
  - `buildListHeaderColumns(fields = [])`
72
81
  - `buildListRowColumns(fields = [])`
82
+ - `buildListCardFields(fields = [])`
73
83
  - `buildViewColumns(fields = [])`
74
84
  - `buildFormColumns(fields = [])`
75
85
  - `resolveRecordIdFieldKey(fields = [])`
@@ -132,9 +142,6 @@ Local functions
132
142
  ### `templates/src/pages/admin/ui-generator/AddEditForm.vue`
133
143
  Exports
134
144
  - None
135
- Local functions
136
- - `resolveFieldErrors(fieldKey)`
137
- - `resolveCancelTo(target)`
138
145
 
139
146
  ### `templates/src/pages/admin/ui-generator/AddEditFormFields.js`
140
147
  Exports
@@ -144,22 +151,26 @@ Exports
144
151
  ### `templates/src/pages/admin/ui-generator/EditElement.vue`
145
152
  Exports
146
153
  - None
147
- Local functions
148
- - `resolveFieldErrors(fieldKey)`
149
154
 
150
155
  ### `templates/src/pages/admin/ui-generator/EditWrapperElement.vue`
151
156
  Exports
152
157
  - None
153
158
 
159
+ ### `templates/src/pages/admin/ui-generator/listBulkActions.js`
160
+ Exports
161
+ - `listBulkActions`
162
+
154
163
  ### `templates/src/pages/admin/ui-generator/ListElement.vue`
155
164
  Exports
156
165
  - None
157
166
 
167
+ ### `templates/src/pages/admin/ui-generator/listFilters.js`
168
+ Exports
169
+ - `listFilters`
170
+
158
171
  ### `templates/src/pages/admin/ui-generator/NewElement.vue`
159
172
  Exports
160
173
  - None
161
- Local functions
162
- - `resolveFieldErrors(fieldKey)`
163
174
 
164
175
  ### `templates/src/pages/admin/ui-generator/NewWrapperElement.vue`
165
176
  Exports
@@ -288,6 +288,35 @@ Exports
288
288
  Exports
289
289
  - `formatDateTime(value, { fallback = "unknown" } = {})`
290
290
 
291
+ ### `shared/support/generatedUiContract.js`
292
+ Exports
293
+ - `GENERATED_UI_FORBIDDEN_CARD_SHELL_PATTERNS`
294
+ - `GENERATED_UI_FORBIDDEN_LIVE_COPY_PATTERNS`
295
+ - `GENERATED_UI_NAVIGATION_ROLE_DEFAULT`
296
+ - `GENERATED_UI_NAVIGATION_ROLE_LINK_PLACEMENTS`
297
+ - `GENERATED_UI_NAVIGATION_ROLE_OPTION`
298
+ - `GENERATED_UI_NAVIGATION_ROLE_VALUES`
299
+ - `GENERATED_UI_NO_LINK_NAVIGATION_ROLES`
300
+ - `GENERATED_UI_SOURCE_CONTRACT_PROFILES`
301
+ - `GENERATED_UI_SURFACE_PROFILES`
302
+ - `assertGeneratedUiSourceContract(source = "", options = {})`
303
+ - `buildGeneratedUiScreenClassName(baseClassName = "", { surfaceProfile = "" } = {})`
304
+ - `collectGeneratedUiSourceContractIssues(source = "", { profile = "", forbidLiveCopy = undefined, forbidCardShell = undefined, forbiddenPatterns = [], requiredPatterns = [] } = {})`
305
+ - `inferGeneratedUiNavigationRole(options = {}, { dynamicRoutePolicy = "leaf", routePath = "" } = {})`
306
+ - `isGeneratedUiNoLinkNavigationRole(value = "")`
307
+ - `normalizeGeneratedUiNavigationRole(value = "")`
308
+ - `resolveGeneratedUiSurfaceProfile(surfaceProfile = "")`
309
+ - `resolveGeneratedUiNavigationRoleLinkPlacement(options = {}, inferenceContext = {})`
310
+ - `shouldCreateGeneratedUiNavigationLink(options = {}, { allowLinkTo = false, dynamicRoutePolicy = "leaf", routePath = "" } = {})`
311
+ Local functions
312
+ - `matchesGeneratedUiContractPattern(source = "", pattern)`
313
+ - `normalizeGeneratedUiContractPattern(patternEntry = {}, fallbackMessage = "")`
314
+ - `normalizeGeneratedUiContractPatternList(patternEntries = [], fallbackMessage = "")`
315
+ - `resolveGeneratedUiSourceContractProfile(profile = "")`
316
+ - `hasExplicitGeneratedUiNavigationRole(options = {})`
317
+ - `normalizeGeneratedUiRouteSegments(routePath = "")`
318
+ - `isGeneratedUiDynamicRouteSegment(routeSegment = "")`
319
+
291
320
  ### `shared/support/index.js`
292
321
  Exports
293
322
  - `isRecord`
@@ -399,7 +428,7 @@ Local functions
399
428
  Exports
400
429
  - `PLACEMENT_LAYOUT_CLASSES`
401
430
  - `describeShellOutletTargets(targets = [])`
402
- - `discoverShellOutletTargetsFromVueSource(source = "", { context = "shell layout" } = {})`
431
+ - `discoverShellOutletTargetsFromVueSource(source = "", { context = "shell layout", enforceSingleDefault = true } = {})`
403
432
  - `findShellOutletTargetById(targets = [], targetId = "")`
404
433
  - `normalizePlacementKind(value = "")`
405
434
  - `normalizePlacementLayoutClass(value = "")`
@@ -667,7 +696,7 @@ Local functions
667
696
 
668
697
  ### `client/moduleBootstrap.js`
669
698
  Exports
670
- - `bootClientModules({ clientModules = [], app, pinia = null, router, surfaceRuntime, surfaceMode, env, logger = console } = {})`
699
+ - `bootClientModules({ clientModules = [], app, pinia = null, queryClient = null, router, surfaceRuntime, surfaceMode, env, logger = console } = {})`
671
700
  Local functions
672
701
  - `normalizePackageId(value)`
673
702
  - `toRouteSnapshot(route)`
@@ -684,7 +713,7 @@ Local functions
684
713
  - `assertRoutesDeclaredInDescriptor({ packageId, source, normalizedRoutes = [], descriptorRouteDeclarations = null } = {})`
685
714
  - `resolveDescriptorClientRoutes({ packageId, descriptorUiRoutes = [], routeComponents = {}, logger = null } = {})`
686
715
  - `normalizeClientModuleEntries(clientModules)`
687
- - `createClientRuntimeApp({ profile = "client", app, pinia = null, router, env, logger, surfaceRuntime, surfaceMode } = {})`
716
+ - `createClientRuntimeApp({ profile = "client", app, pinia = null, queryClient = null, router, env, logger, surfaceRuntime, surfaceMode } = {})`
688
717
 
689
718
  ### `client/pageRedirects.js`
690
719
  Exports
@@ -697,7 +726,7 @@ Exports
697
726
  - `resolveClientBootstrapDebugEnabled({ env = {}, debugEnabled = undefined, debugEnvKey = "VITE_JSKIT_CLIENT_DEBUG" } = {})`
698
727
  - `createClientBootstrapLogger({ env = {}, logger = console, debugEnabled = undefined, debugEnvKey = "VITE_JSKIT_CLIENT_DEBUG" } = {})`
699
728
  - `createSurfaceShellRouter({ createRouter, history, routes = [], surfaceRuntime, surfaceMode, fallbackRoute = null, notFoundComponent = null, guard = false } = {})`
700
- - `bootstrapClientShellApp({ createApp, rootComponent, appConfig = {}, appPlugins = [], pinia = null, router, bootClientModules, surfaceRuntime, surfaceMode, env = {}, fallbackRoute = null, logger = console, createBootstrapLogger = null, debugEnabled = undefined, debugEnvKey = "VITE_JSKIT_CLIENT_DEBUG", debugMessage = "Client modules bootstrapped before router install.", onAfterModulesBootstrapped = null, onAfterRouterReady = null, mountSelector = "#app" } = {})`
729
+ - `bootstrapClientShellApp({ createApp, rootComponent, appConfig = {}, appPlugins = [], pinia = null, queryClient = null, router, bootClientModules, surfaceRuntime, surfaceMode, env = {}, fallbackRoute = null, logger = console, createBootstrapLogger = null, debugEnabled = undefined, debugEnvKey = "VITE_JSKIT_CLIENT_DEBUG", debugMessage = "Client modules bootstrapped before router install.", onAfterModulesBootstrapped = null, onAfterRouterReady = null, mountSelector = "#app" } = {})`
701
730
  Local functions
702
731
  - `installAppPlugins(app, appPlugins = [])`
703
732
 
@@ -1357,6 +1386,7 @@ Exports
1357
1386
  - `resolveNearestParentSubpagesHost`
1358
1387
  - `resolvePageLinkTargetDetails`
1359
1388
  - `discoverPlacementTopologyFromApp`
1389
+ - `discoverShellOutletSourcePathsFromApp`
1360
1390
  - `discoverShellOutletTargetsFromApp`
1361
1391
  - `resolveSemanticPlacementTargetFromApp`
1362
1392
  - `resolveShellOutletPlacementTargetFromApp`
@@ -1399,7 +1429,7 @@ Local functions
1399
1429
  - `normalizePlacementTargetId(target = {})`
1400
1430
  - `resolveConcreteTargetOwner(target = "")`
1401
1431
  - `topologyPlacementTargetsConcreteOutlet(placement = {}, target = "")`
1402
- - `resolveSemanticPlacementTargetForConcreteOutlet({ appRoot, concreteTarget = "", surface = "" } = {})`
1432
+ - `resolveSemanticPlacementTargetForConcreteOutlet({ appRoot, concreteTarget = "", surface = "", context = "page target" } = {})`
1403
1433
  - `resolveRelativeLinkToFromParent(pageTarget = {}, parentHost = null)`
1404
1434
  - `resolveRelativeLinkToFromNearestIndexOwner(pageTarget = {})`
1405
1435
  - `resolveInferredPageLinkTo({ explicitLinkTo = "", pageTarget = {}, parentHost = null, preservesRelativeSubpageLinks = false, suppressImplicitRelativeLinks = false } = {})`
@@ -1418,6 +1448,7 @@ Exports
1418
1448
  ### `server/support/shellOutlets.js`
1419
1449
  Exports
1420
1450
  - `discoverPlacementTopologyFromApp({ appRoot } = {})`
1451
+ - `discoverShellOutletSourcePathsFromApp({ appRoot, sourceRoot = "src" } = {})`
1421
1452
  - `discoverShellOutletTargetsFromApp({ appRoot, sourceRoot = "src" } = {})`
1422
1453
  - `resolveSemanticPlacementTargetFromApp({ appRoot, placement = "", owner = "", surface = "", context = "ui-generator" } = {})`
1423
1454
  - `resolveShellOutletPlacementTargetFromApp({ appRoot, placement = "", context = "ui-generator" } = {})`
@@ -1425,7 +1456,7 @@ Local functions
1425
1456
  - `parseTagAttributes(attributesSource = "")`
1426
1457
  - `isDefaultEnabled(value)`
1427
1458
  - `normalizeAppRouteOutletTarget({ outlet = {}, sourcePath = "" } = {})`
1428
- - `discoverRouteMetaOutletTargetsFromVueSource(source = "", { context = "shell layout" } = {})`
1459
+ - `discoverRouteMetaOutletTargetsFromVueSource(source = "", { context = "shell layout", enforceSingleDefault = true } = {})`
1429
1460
  - `collectVueFilePaths(rootDirectoryPath)`
1430
1461
  - `readInstalledPackageStates(appRoot)`
1431
1462
  - `normalizePackageOutletTarget({ packageId = "", outlet = {}, descriptorPath = "" } = {})`
@@ -1434,6 +1465,7 @@ Local functions
1434
1465
  - `loadAppPlacementTopology(appRoot)`
1435
1466
  - `collectInstalledPackagePlacementTopology(appRoot)`
1436
1467
  - `findSemanticPlacementById(placements = [], { id = "", owner = "", surface = "" } = {})`
1468
+ - `collectAppSourceShellOutletTargets({ appRoot, sourceRoot = "src", enforceSingleDefault = true, context = "discoverShellOutletTargetsFromApp" } = {})`
1437
1469
 
1438
1470
  ### `server/support/SupportCoreServiceProvider.js`
1439
1471
  Exports
@@ -42,6 +42,7 @@ Local functions
42
42
  Exports
43
43
  - `RealtimeClientProvider`
44
44
  Local functions
45
+ - `isCapacitorRuntimeAvailable(app)`
45
46
  - `resolveRealtimeClientConfig(app)`
46
47
 
47
48
  ### `src/client/runtime.js`
@@ -39,6 +39,7 @@ Exports
39
39
  - None
40
40
  Local functions
41
41
  - `resolveSeverityColor(severity = "error")`
42
+ - `resolveSeverityIcon(severity = "error")`
42
43
  - `resolveTimeout(entry)`
43
44
  - `dismiss(entry)`
44
45
  - `runAction(entry)`
@@ -48,6 +49,17 @@ Local functions
48
49
  ### `src/client/components/ShellLayout.vue`
49
50
  Exports
50
51
  - None
52
+ Local functions
53
+ - `handlePullPointerDown(event)`
54
+ - `handlePullPointerMove(event)`
55
+ - `handlePullPointerEnd(event)`
56
+ - `handlePullPointerCancel(event)`
57
+ - `cancelPullRefresh()`
58
+ - `refreshFromPullGesture()`
59
+ - `canStartPullRefresh(event)`
60
+ - `isPrimaryTouchPointer(event)`
61
+ - `isAtPageTop()`
62
+ - `isPullRefreshIgnoredTarget(target)`
51
63
 
52
64
  ### `src/client/components/ShellMenuLinkItem.vue`
53
65
  Exports
@@ -61,6 +73,21 @@ Exports
61
73
  Exports
62
74
  - None
63
75
 
76
+ ### `src/client/components/ShellRouteTransition.vue`
77
+ Exports
78
+ - None
79
+ Local functions
80
+ - `handlePointerDown(event)`
81
+ - `handlePointerMove(event)`
82
+ - `handlePointerEnd(event)`
83
+ - `handlePointerCancel(event)`
84
+ - `navigateBySwipe(offset = 0)`
85
+ - `isAcceptedSwipe({ deltaX = 0, deltaY = 0, elapsed = 1, velocity = null } = {})`
86
+ - `normalizeComparablePathname(value = "")`
87
+ - `pathMatchesNavigationEntry(pathname = "", entry = {})`
88
+ - `isPrimaryPointerEvent(event)`
89
+ - `isSwipeIgnoredTarget(target)`
90
+
64
91
  ### `src/client/components/ShellSurfaceAwareMenuLinkItem.vue`
65
92
  Exports
66
93
  - None
@@ -96,16 +123,18 @@ Exports
96
123
  Exports
97
124
  - `ERROR_CHANNELS`
98
125
  - `ERROR_SEVERITIES`
126
+ - `ERROR_INTENTS`
99
127
  - `isRecord`
100
128
  - `normalizeText(value, fallback = "")`
101
129
  - `normalizeChannel(value, fallback = "")`
102
130
  - `normalizeSeverity(value, fallback = "error")`
131
+ - `normalizeErrorIntent(value, fallback = "")`
103
132
  - `normalizeNonNegativeInteger(value, fallback = 0)`
104
133
  - `normalizeAction(value)`
105
134
 
106
135
  ### `src/client/error/policy.js`
107
136
  Exports
108
- - `createDefaultErrorPolicy({ defaultChannel = "snackbar", unauthorizedChannel = "banner", serverErrorChannel = "dialog", defaultSeverity = "error" } = {})`
137
+ - `createDefaultErrorPolicy({ defaultChannel = "snackbar", resourceLoadChannel = "silent", actionFeedbackChannel = "snackbar", appRecoverableChannel = "banner", blockingChannel = "dialog", defaultSeverity = "error" } = {})`
109
138
 
110
139
  ### `src/client/error/presentationDefaults.js`
111
140
  Exports
@@ -143,6 +172,7 @@ Exports
143
172
  - `ShellLayout`
144
173
  - `ShellOutlet`
145
174
  - `ShellOutletMenuWidget`
175
+ - `ShellRouteTransition`
146
176
  - `ShellErrorHost`
147
177
  - `ShellMenuLinkItem`
148
178
  - `ShellSurfaceAwareMenuLinkItem`
@@ -267,14 +297,16 @@ Local functions
267
297
  ### `src/client/providers/ShellWebClientProvider.js`
268
298
  Exports
269
299
  - `ShellWebClientProvider`
300
+ - `resolveAppPlacementTopologyExport(exported, logger)`
270
301
  Local functions
271
- - `createShellWebQueryClient()`
272
302
  - `isMissingDynamicModule(error, moduleSpecifier)`
273
303
  - `loadAppPlacementDefinitions(logger)`
274
304
  - `loadAppPlacementTopology(logger)`
275
305
  - `createErrorConfigToolkit(errorRuntime)`
276
306
  - `loadAppErrorConfig(logger, errorRuntime)`
277
307
  - `applyAppErrorConfig(errorRuntime, errorConfig = {})`
308
+ - `isPullRefreshQuery(query = null)`
309
+ - `createShellRefreshRuntime({ app, logger = null } = {})`
278
310
  - `installVueErrorBridge(vueApp, errorRuntime, logger)`
279
311
  - `installRouterErrorBridge(app, errorRuntime, logger)`
280
312
 
@@ -350,7 +382,7 @@ Exports
350
382
 
351
383
  ### `templates/src/components/ShellLayout.vue`
352
384
  Exports
353
- - None
385
+ - `default`
354
386
 
355
387
  ### `templates/src/error.js`
356
388
  Exports