@jskit-ai/agent-docs 0.1.278 → 0.1.279

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.
@@ -154,8 +154,9 @@ like the recovery sender below; with it, `APP_PUBLIC_URL` is required and the
154
154
  link is never returned or logged. In development without one, the link is in
155
155
  the registration's answer (`confirmationUrl`) and the log, and the sign-in page
156
156
  shows it with a button that confirms it. In production (`NODE_ENV=production`)
157
- without one, the server refuses to start, naming both ways out: install a
158
- sender, or set `AUTH_LOCAL_EMAIL_CONFIRMATION=false`. For direct library
157
+ without one, while anyone may register, the server refuses to start, naming
158
+ the ways out: install a sender, set `AUTH_LOCAL_EMAIL_CONFIRMATION=false`, or
159
+ set `AUTH_LOCAL_SELF_REGISTRATION=false`. For direct library
159
160
  composition, pass the sender as `confirmationSender` to
160
161
  `createLocalAuthService()`, with `emailConfirmationSender: true` in
161
162
  `resolveLocalAuthConfig()`; without one, pass
@@ -164,6 +165,16 @@ composition, pass the sender as `confirmationSender` to
164
165
  | Env | Default | Meaning |
165
166
  | --- | --- | --- |
166
167
  | `AUTH_LOCAL_EMAIL_CONFIRMATION` | on | `false` registers and signs in at once, without confirming the email. |
168
+ | `AUTH_LOCAL_SELF_REGISTRATION` | on | `false`: only invited accounts and the first account register; anyone else is refused with 403 `auth.local.register.closed`. |
169
+
170
+ Confirmation guards self-registration. An app whose accounts are only invited,
171
+ or created through the first account, sets `AUTH_LOCAL_SELF_REGISTRATION=false`
172
+ and needs no confirmation sender: an invitation counts when a feature's
173
+ invitation context resolver (such as workspace invites) resolves it for that
174
+ email, and the first account is admitted by its setup code. In production
175
+ without a sender, those registrations sign in at once; with one, they confirm
176
+ as usual. An app that refused the register routes itself, with a 404 hook,
177
+ can drop the hook for this setting.
167
178
 
168
179
  Accounts that exist already are confirmed: only registrations made after the
169
180
  upgrade wait. Waiting registrations are kept in the file store
@@ -71,7 +71,11 @@ Delete, rather than port:
71
71
  page needs no frame at all;
72
72
  - `!important`, Sass variable overrides and component size or radius tweaks.
73
73
  `material.css` sets 40dp buttons with a 48dp touch target, 12dp cards, 28dp
74
- dialogs and sheets, 8dp chips and 16dp FABs, and an app's own props still win.
74
+ dialogs and sheets, 8dp chips and 16dp FABs, and an app's own props still win;
75
+ - every `height` and `min-height` on a button, as a prop, a style or CSS. A
76
+ button that should look smaller becomes `size="small"` or `size="x-small"`:
77
+ it keeps the 48dp touch target. A long label ends in an ellipsis instead of
78
+ spilling out; give a label that can run long its `title`.
75
79
 
76
80
  Use colour roles (`color="secondary-container"`, `bg-color="surface-container-high"`,
77
81
  the `on-surface-variant` class) instead of colours.
@@ -110,8 +114,13 @@ definePage({ meta: { jskit: { title: "Edit book", parent: "/books/:bookId" } } }
110
114
  ```
111
115
 
112
116
  `parent` is a path on the page's own surface, or `{ surface, path }` for
113
- another one. A main navigation destination declares no parent and shows no
114
- arrow. The shell's Up arrow returns to the page the person came from, or else
117
+ another one; its `:param` segments take the current route's values. A main
118
+ navigation destination declares no parent and shows no arrow. A page with a
119
+ parent renders in its surface's shell layout (`ShellLayout` around
120
+ `<RouterView />`), which draws the bar with its title, Up and actions:
121
+ `jskit check` reports `nav/missing-shell-layout` until it does. The account
122
+ settings page needs `src/pages/account.vue` from the users/account-settings
123
+ pattern. The shell's Up arrow returns to the page the person came from, or else
115
124
  to the parent, so:
116
125
 
117
126
  - delete "Back to X" buttons, `router.back()` and `history.back()` calls;
@@ -203,6 +212,11 @@ opens the drawer over the page. A modal drawer opens over the app bar, as
203
212
  Material 3 draws it, so a browser test that clicked the menu control again to
204
213
  close it taps the scrim or presses Escape instead.
205
214
 
215
+ Each main-navigation placement is literal data, one `addPlacement({ ... })`
216
+ per destination with plain string `surface` and suffixes; one a helper builds is
217
+ a `nav/placement-data` finding, and no page is judged for a missing parent until
218
+ it is declared literally.
219
+
206
220
  ## 9. Check it
207
221
 
208
222
  Look at every screen at 390, 768 and 1280 pixels wide, in light and dark. A
@@ -87,7 +87,10 @@ Exactly this, and nothing more:
87
87
  2. **Each top-level destination is a main-navigation item** (a `kind: "link"`
88
88
  placement with `target: "shell.primary-nav"` or `"shell.secondary-nav"`) and
89
89
  declares no parent; nor do its tabs. A shell page with no parent is
90
- top-level: no arrow, a fresh trail.
90
+ top-level: no arrow, a fresh trail. Placements are literal declarative data,
91
+ one `addPlacement({ ... })` per destination with plain string `surface`,
92
+ `scopedSuffix` and `unscopedSuffix`, never built by a helper, a spread or a
93
+ template, so a reader and `jskit check` can map every destination.
91
94
  3. **Every in-app link and navigation goes through JSKIT navigation:**
92
95
  `:to="paths.page('/suppliers')"` and `router.push(paths.page(...))` with
93
96
  `usePaths()`, the CRUD runtime's `resolveViewUrl()`, `resolveEditUrl()` and
@@ -103,7 +106,10 @@ Exactly this, and nothing more:
103
106
  5. **A full page load goes through the shell too:** `reloadAppPage(path)`
104
107
  (after sign-in or a user switch, to rebuild client state) and
105
108
  `leaveApp(url)` (an external site in the same tab, such as a payment page),
106
- from `@jskit-ai/shell-web/client/navigation/documentNavigation`.
109
+ from `@jskit-ai/shell-web/client/navigation/documentNavigation`. `leaveApp`
110
+ opens the site with a push, so Back returns to the page; a hand-off page
111
+ that only forwards (to an OAuth consent screen) uses
112
+ `leaveApp(url, { replace: true })`, so Back from the site doesn't rerun it.
107
113
 
108
114
  ### Forbidden in app code
109
115
 
@@ -115,6 +121,8 @@ Exactly this, and nothing more:
115
121
  | `nav/back-control` | any back control but the shell's Up that navigates the app: "Back to X", "← Suppliers", back arrows and navigating chevrons, breadcrumbs, a custom app-bar back button, a back component, a `goBack()`-style handler |
116
122
  | `nav/missing-parent` | an inner page of a shell surface without a declared parent |
117
123
  | `nav/top-level-parent` | a main-navigation destination that declares a parent |
124
+ | `nav/placement-data` | a main-navigation placement that isn't literal data (no page is judged for a missing parent until it is) |
125
+ | `nav/missing-shell-layout` | a page that declares a parent with no shell layout rendering it, so its title, Up and actions never show |
118
126
  | `nav/allow` | any `m3-check: allow nav/...` comment: nothing excuses a navigation rule |
119
127
 
120
128
  ### Each rule, right and wrong
@@ -187,10 +195,16 @@ JSKIT ships these exact sizes; an app never re-implements or overrides them,
187
195
  and needs no Sass and no `!important` (Vuetify 4 keeps its CSS in cascade
188
196
  layers):
189
197
 
190
- - 40dp buttons with a 48dp touch target, icon buttons included;
191
- - 12dp cards;
198
+ - 40dp buttons with a 48dp touch target, icon buttons included; a smaller
199
+ button is `size="small"` or `size="x-small"`, which keeps its smaller look
200
+ and the 48dp target;
201
+ - one-line button labels: a label longer than its button ends in an ellipsis.
202
+ Keep labels short, and give a button whose label can run long, such as a
203
+ name, the full label as its `title`;
204
+ - 12dp cards: elevated (the default) at level 1, flat and tonal at level 0;
192
205
  - 28dp dialogs and bottom-sheet top corners, square full-screen dialogs;
193
- - 8dp chips and 16dp FABs;
206
+ - 8dp chips, and FABs of 56dp (small 40dp, large 96dp; extended 56dp tall)
207
+ with 16dp corners;
194
208
  - emphasized easing, with reduced motion honoured.
195
209
 
196
210
  So never set `height` or `min-height` on a button, or a radius on a card,
@@ -202,7 +216,9 @@ dialog, chip or FAB. A missing size is a JSKIT defect.
202
216
  `useShellPageTitle(title)` (`@jskit-ai/shell-web/client/composables/useShellPageTitle`)
203
217
  for a runtime title such as the record's name. The shell renders it as the
204
218
  app bar's only `h1`; pages add no `h1`, page header, title block or
205
- standalone heading. A section inside a page uses a title role.
219
+ standalone heading. A section inside a page uses a title role. A page with
220
+ no top app bar (a hero front page, an intro, an invite or hand-off page)
221
+ has its own one `h1`.
206
222
  - **Up** sits in the bar on every inner page (see Navigation and Up). On phones
207
223
  it replaces the menu icon.
208
224
  - **A layout that draws its own top app bar** (a workspace bar with the
@@ -211,7 +227,9 @@ dialog, chip or FAB. A missing size is a JSKIT defect.
211
227
  once, so its pages enter the trail and their `ShellPageActions` show in its
212
228
  bar, and renders `ShellUpButton` first, then `ShellPageTitle` (the page's one
213
229
  `h1`: `useShellPageTitle()`, else the route's `jskit.title`, else its `title`
214
- prop) and `ShellPageActionsTarget`. `jskit check` counts it as a shell
230
+ prop) and `ShellPageActionsTarget`. A title that is also a switcher, such as a
231
+ project menu, goes in `ShellPageTitle`'s default slot (given `{ title }`) as
232
+ the menu's activator, so it stays the one `h1`. `jskit check` counts it as a shell
215
233
  layout, so its inner pages need parents; an Up the app draws itself is a
216
234
  `nav/back-control` finding.
217
235
  - **Actions:** a screen's actions go in the bar inside `ShellPageActions`
@@ -221,7 +239,9 @@ dialog, chip or FAB. A missing size is a JSKIT defect.
221
239
  On compact widths every action shows only its icon except the single
222
240
  `primary` one.
223
241
  - **Window size classes:** compact under 600 (navigation bar), medium 600–839
224
- (navigation rail), expanded 840–1199 and large from 1200 (drawer). Read them
242
+ (navigation rail), expanded 840–1199 and large from 1200 (drawer). A surface
243
+ with no navigation destinations, such as an account surface, draws no
244
+ navigation bar, rail or drawer; its pages keep the app bar. Read them
225
245
  from `useShellWindowSizeClass()`
226
246
  (`@jskit-ai/shell-web/client/composables/useShellWindowSizeClass`), never from
227
247
  copied breakpoint numbers.
@@ -321,8 +341,8 @@ and so every app's verify, fail on them too:
321
341
 
322
342
  | Rule | Finds |
323
343
  |---|---|
324
- | `m3/duplicate-h1` | a second `h1`, or an in-page `h1` in an app that uses the JSKIT shell |
325
- | `m3/raw-hex` | a hex colour outside `src/theme/` |
344
+ | `m3/duplicate-h1` | a second `h1`, or an in-page `h1` under the shell's page title |
345
+ | `m3/raw-hex` | a hex colour outside `src/theme/` (`palettes.js` holds content colours) |
326
346
  | `m3/dark-scheme` | no dark scheme, or the theme pinned to light |
327
347
  | `m3/outlined-card` | `variant="outlined"` or `border` on a card or sheet |
328
348
  | `m3/mdi-icon` | `mdi-*` icon strings and `@mdi/js` imports |
@@ -343,14 +363,36 @@ Take the approved route first; none needs an exception:
343
363
  `<v-chip color="partner">`. A hex string is harmonized toward the seed; a
344
364
  colour that must keep its hue is `{ value: "#F5C518", blend: false }`
345
365
  (Material Theme Builder's Blend switched off), with the same four roles.
346
- - **Chart and data colours** come from the theme: `const theme = useTheme()`,
347
- then `["primary", "tertiary"].map((role) => theme.current.value.colors[role])`.
366
+ - **Content colours**, colours that are content rather than UI, keep one
367
+ value in both schemes: an identity palette a person picks and the server
368
+ stores, avatar and illustration artwork, brand marks (a language's
369
+ file-type tint), fixed chart series, QR codes, colours written into
370
+ exported files. They are named exports of plain hex values in
371
+ `src/theme/palettes.js`, used as they are, never for UI chrome (a theme
372
+ colour is toned per scheme, so it can't keep an identity the same).
373
+ Components read them through bindings:
374
+
375
+ ```vue
376
+ <script setup>
377
+ // src/theme/palettes.js: export const botColours = ["#6750A4", "#B3261E"];
378
+ import { botColours } from "@/theme/palettes.js";
379
+ const props = defineProps({ bot: Object });
380
+ const ring = botColours[props.bot.colour];
381
+ </script>
382
+ <template>
383
+ <v-avatar :style="{ backgroundColor: ring }"><svg><path :fill="ring" /></svg></v-avatar>
384
+ </template>
385
+ <style scoped>.v-avatar { outline: 2px solid v-bind(ring); }</style>
386
+ ```
387
+ - **Chart and data colours** that follow the scheme come from the theme:
388
+ `const theme = useTheme()`, then
389
+ `["primary", "tertiary"].map((role) => theme.current.value.colors[role])`.
348
390
  - **A third-party widget** lives in one wrapper component, such as
349
391
  `src/components/RouteMap.vue`, that hands it theme colours; pages use only
350
392
  the wrapper.
351
393
 
352
- What is left may be excused one line at a time, on its line or the line
353
- before: `<!-- m3-check: allow m3/raw-hex - the partner's contractual logo colour -->`
394
+ What is left, such as a colour inside static SVG markup that can't import,
395
+ may be excused one line at a time, on its line or the line before: `<!-- m3-check: allow m3/raw-hex - the partner's contractual logo colour -->`
354
396
  (`// m3-check: ...` in scripts, `/* ... */` in CSS). **Never add one on your
355
397
  own:** ask the person first, naming the rule and the reason. A comment with no
356
398
  reason (`m3/allow-reason`) or an unknown rule (`m3/allow-rule`), and any
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jskit-ai/agent-docs",
3
- "version": "0.1.278",
3
+ "version": "0.1.279",
4
4
  "description": "Distributed JSKIT agent references, prompts, guides, and generated reference maps.",
5
5
  "type": "module",
6
6
  "files": [
@@ -35,7 +35,7 @@
35
35
  "@local/main": "0.1.0",
36
36
  "@fastify/static": "^10.1.3",
37
37
  "@jskit-ai/kernel": "0.2.10",
38
- "@jskit-ai/material-web": "0.1.1",
38
+ "@jskit-ai/material-web": "0.1.2",
39
39
  "@tanstack/vue-query": "^5.101.0",
40
40
  "fastify": "^5.12.7",
41
41
  "pino": "^10.3.1",
@@ -50,7 +50,7 @@
50
50
  },
51
51
  "devDependencies": {
52
52
  "@jskit-ai/config-eslint": "0.1.245",
53
- "@jskit-ai/jskit-catalog": "0.2.30",
53
+ "@jskit-ai/jskit-catalog": "0.2.31",
54
54
  "@playwright/test": "1.61.1",
55
55
  "@vitejs/plugin-vue": "^6.0.7",
56
56
  "eslint": "^10.8.0",
@@ -35,7 +35,7 @@
35
35
  "@local/main": "0.1.0",
36
36
  "@fastify/static": "^10.1.3",
37
37
  "@jskit-ai/kernel": "0.2.10",
38
- "@jskit-ai/material-web": "0.1.1",
38
+ "@jskit-ai/material-web": "0.1.2",
39
39
  "@tanstack/vue-query": "^5.101.0",
40
40
  "fastify": "^5.12.7",
41
41
  "pino": "^10.3.1",
@@ -45,13 +45,13 @@
45
45
  "vue-router": "^5.3.1",
46
46
  "vuetify": "^4.3.0",
47
47
  "@jskit-ai/http-runtime": "0.2.10",
48
- "@jskit-ai/shell-web": "0.2.12",
48
+ "@jskit-ai/shell-web": "0.2.13",
49
49
  "@fastify/fast-json-stringify-compiler": "^5.1.0",
50
50
  "@vue/devtools-api": "^8.2.1"
51
51
  },
52
52
  "devDependencies": {
53
53
  "@jskit-ai/config-eslint": "0.1.245",
54
- "@jskit-ai/jskit-catalog": "0.2.30",
54
+ "@jskit-ai/jskit-catalog": "0.2.31",
55
55
  "@playwright/test": "1.61.1",
56
56
  "@vitejs/plugin-vue": "^6.0.7",
57
57
  "eslint": "^10.8.0",
@@ -15,7 +15,7 @@ A concrete Fastify, Vue, and JSKIT application foundation for products that do n
15
15
 
16
16
  - Id: `app/minimal-foundation`
17
17
  - Keywords: `app`, `fastify`, `foundation`, `minimal`, `server`, `vite`, `vue`
18
- - Owner: `@jskit-ai/agent-docs@0.1.278`
18
+ - Owner: `@jskit-ai/agent-docs@0.1.279`
19
19
  - Read: [PATTERN.md](../../skills/jskit/references/patterns/app/minimal-foundation/PATTERN.md)
20
20
  - Examples: [example/](../../skills/jskit/references/patterns/app/minimal-foundation/example/)
21
21
  - Requires: `@jskit-ai/http-runtime`, `@jskit-ai/kernel`
@@ -26,7 +26,7 @@ A concrete JSKIT web application foundation with responsive shell navigation, se
26
26
 
27
27
  - Id: `app/shell-foundation`
28
28
  - Keywords: `app`, `foundation`, `material`, `navigation`, `placements`, `shell`, `vite`, `vue`
29
- - Owner: `@jskit-ai/agent-docs@0.1.278`
29
+ - Owner: `@jskit-ai/agent-docs@0.1.279`
30
30
  - Read: [PATTERN.md](../../skills/jskit/references/patterns/app/shell-foundation/PATTERN.md)
31
31
  - Examples: [example/](../../skills/jskit/references/patterns/app/shell-foundation/example/)
32
32
  - Requires: `@jskit-ai/http-runtime`, `@jskit-ai/kernel`, `@jskit-ai/shell-web`
@@ -37,7 +37,7 @@ Configure an assistant runtime for one application surface and expose its chat a
37
37
 
38
38
  - Id: `assistant/assistant-surface`
39
39
  - Keywords: `ai`, `assistant`, `chat`, `config`, `environment`, `page`, `placement`, `settings`, `surface`
40
- - Owner: `@jskit-ai/assistant-runtime@0.2.25`
40
+ - Owner: `@jskit-ai/assistant-runtime@0.2.26`
41
41
  - Read: [PATTERN.md](../../skills/jskit/references/patterns/assistant/assistant-surface/PATTERN.md)
42
42
  - Examples: [example/](../../skills/jskit/references/patterns/assistant/assistant-surface/example/)
43
43
  - Requires: `@jskit-ai/assistant-runtime`, `@jskit-ai/connectors-catalog`, `@jskit-ai/connectors-core`, `@jskit-ai/shell-web`
@@ -48,7 +48,7 @@ Run one OpenID Connect sign-in for all of an owner's apps as its own JSKIT proje
48
48
 
49
49
  - Id: `auth/accounts-hub`
50
50
  - Keywords: `accounts hub`, `auth`, `authentication`, `issuer`, `master login`, `oidc`, `openid connect`, `single sign-on`, `sso`
51
- - Owner: `@jskit-ai/oidc-issuer-core@0.1.17`
51
+ - Owner: `@jskit-ai/oidc-issuer-core@0.1.18`
52
52
  - Read: [PATTERN.md](../../skills/jskit/references/patterns/auth/accounts-hub/PATTERN.md)
53
53
  - Examples: [example/](../../skills/jskit/references/patterns/auth/accounts-hub/example/)
54
54
  - Requires: `@jskit-ai/oidc-issuer-core`
@@ -59,7 +59,7 @@ Compose JSKIT authentication routes, views, profile controls, and public surface
59
59
 
60
60
  - Id: `auth/auth-surface`
61
61
  - Keywords: `account`, `auth`, `login`, `logout`, `password`, `placement`, `profile`, `reset`, `surface`
62
- - Owner: `@jskit-ai/auth-web@0.2.14`
62
+ - Owner: `@jskit-ai/auth-web@0.2.15`
63
63
  - Read: [PATTERN.md](../../skills/jskit/references/patterns/auth/auth-surface/PATTERN.md)
64
64
  - Examples: [example/](../../skills/jskit/references/patterns/auth/auth-surface/example/)
65
65
  - Requires: `@jskit-ai/auth-core`, `@jskit-ai/auth-web`, `@jskit-ai/shell-web`
@@ -70,7 +70,7 @@ Let people sign in with the accounts they already have in an accounts hub or ano
70
70
 
71
71
  - Id: `auth/oidc-sign-in`
72
72
  - Keywords: `accounts hub`, `auth`, `authentication`, `back-channel logout`, `dynamic client registration`, `issuer`, `master login`, `oidc`, `openid connect`, `single sign-on`, `sso`
73
- - Owner: `@jskit-ai/auth-provider-oidc-core@0.2.16`
73
+ - Owner: `@jskit-ai/auth-provider-oidc-core@0.2.17`
74
74
  - Read: [PATTERN.md](../../skills/jskit/references/patterns/auth/oidc-sign-in/PATTERN.md)
75
75
  - Examples: [example/](../../skills/jskit/references/patterns/auth/oidc-sign-in/example/)
76
76
  - Requires: `@jskit-ai/auth-provider-oidc-core`, `@jskit-ai/auth-web`
@@ -246,7 +246,7 @@ Add a protected administration surface, settings shell, and semantic navigation
246
246
 
247
247
  - Id: `console/console-surface`
248
248
  - Keywords: `admin`, `console`, `navigation`, `owner`, `placement`, `settings`, `surface`
249
- - Owner: `@jskit-ai/console-web@0.1.236`
249
+ - Owner: `@jskit-ai/console-web@0.1.237`
250
250
  - Read: [PATTERN.md](../../skills/jskit/references/patterns/console/console-surface/PATTERN.md)
251
251
  - Examples: [example/](../../skills/jskit/references/patterns/console/console-surface/example/)
252
252
  - Requires: `@jskit-ai/console-core`, `@jskit-ai/console-web`, `@jskit-ai/shell-web`
@@ -257,7 +257,7 @@ Build a routed CRUD user interface as thin application pages over JSKIT's shared
257
257
 
258
258
  - Id: `crud/crud-screen-set`
259
259
  - Keywords: `actions`, `add`, `crud`, `delete`, `edit`, `filters`, `list`, `material`, `routes`, `view`, `vue`
260
- - Owner: `@jskit-ai/http-web@0.2.17`
260
+ - Owner: `@jskit-ai/http-web@0.2.18`
261
261
  - Read: [PATTERN.md](../../skills/jskit/references/patterns/crud/crud-screen-set/PATTERN.md)
262
262
  - Examples: [example/](../../skills/jskit/references/patterns/crud/crud-screen-set/example/)
263
263
  - Requires: `@jskit-ai/http-web`, `@jskit-ai/resource-crud-core`
@@ -312,7 +312,7 @@ Wrap a JSKIT web application in a Capacitor Android shell using native Capacitor
312
312
 
313
313
  - Id: `mobile/android-application`
314
314
  - Keywords: `android`, `capacitor`, `device`, `mobile`, `native`, `shell`, `webview`
315
- - Owner: `@jskit-ai/mobile-capacitor@0.2.12`
315
+ - Owner: `@jskit-ai/mobile-capacitor@0.2.13`
316
316
  - Read: [PATTERN.md](../../skills/jskit/references/patterns/mobile/android-application/PATTERN.md)
317
317
  - Examples: [example/](../../skills/jskit/references/patterns/mobile/android-application/example/)
318
318
  - Requires: `@capacitor/android`, `@capacitor/app`, `@capacitor/cli`, `@jskit-ai/mobile-capacitor`
@@ -323,7 +323,7 @@ Add JSKIT realtime events with an optional Redis backplane and an explicit shell
323
323
 
324
324
  - Id: `realtime/realtime-application`
325
325
  - Keywords: `realtime`, `redis`, `socket.io`, `sockets`, `status`, `websocket`
326
- - Owner: `@jskit-ai/realtime@0.2.15`
326
+ - Owner: `@jskit-ai/realtime@0.2.16`
327
327
  - Read: [PATTERN.md](../../skills/jskit/references/patterns/realtime/realtime-application/PATTERN.md)
328
328
  - Examples: [example/](../../skills/jskit/references/patterns/realtime/realtime-application/example/)
329
329
  - Requires: `@jskit-ai/realtime`, `@jskit-ai/shell-web`
@@ -334,7 +334,7 @@ Compose application-owned Google Publisher Tag delivery with the generic rewarde
334
334
 
335
335
  - Id: `rewards/google-rewarded`
336
336
  - Keywords: `ads`, `google`, `publisher tag`, `rewarded`, `unlock`
337
- - Owner: `@jskit-ai/rewarded-web@0.2.14`
337
+ - Owner: `@jskit-ai/rewarded-web@0.2.15`
338
338
  - Read: [PATTERN.md](../../skills/jskit/references/patterns/rewards/google-rewarded/PATTERN.md)
339
339
  - Examples: [example/](../../skills/jskit/references/patterns/rewards/google-rewarded/example/)
340
340
  - Requires: `@jskit-ai/rewarded-web`
@@ -345,7 +345,7 @@ Define a server feature through explicit capabilities and first-class actions, a
345
345
 
346
346
  - Id: `server/feature-package`
347
347
  - Keywords: `actions`, `feature`, `json-rest`, `knex`, `orchestration`, `package`, `provider`, `repository`, `routes`, `server`
348
- - Owner: `@jskit-ai/agent-docs@0.1.278`
348
+ - Owner: `@jskit-ai/agent-docs@0.1.279`
349
349
  - Read: [PATTERN.md](../../skills/jskit/references/patterns/server/feature-package/PATTERN.md)
350
350
  - Examples: [example/](../../skills/jskit/references/patterns/server/feature-package/example/)
351
351
  - Requires: `@jskit-ai/kernel`
@@ -356,7 +356,7 @@ Compose the JSKIT responsive shell, semantic placements, settings navigation, an
356
356
 
357
357
  - Id: `shell/application-shell`
358
358
  - Keywords: `adaptive`, `app`, `layout`, `navigation`, `placement`, `responsive`, `settings`, `shell`
359
- - Owner: `@jskit-ai/shell-web@0.2.12`
359
+ - Owner: `@jskit-ai/shell-web@0.2.13`
360
360
  - Read: [PATTERN.md](../../skills/jskit/references/patterns/shell/application-shell/PATTERN.md)
361
361
  - Examples: [example/](../../skills/jskit/references/patterns/shell/application-shell/example/)
362
362
  - Requires: `@jskit-ai/kernel`, `@jskit-ai/shell-web`
@@ -367,7 +367,7 @@ Add product routes and shell extensions through file routing, semantic placement
367
367
 
368
368
  - Id: `ui/page-and-placement`
369
369
  - Keywords: `component`, `navigation`, `outlet`, `page`, `placement`, `routes`, `section`, `shell`, `subpages`, `vue`
370
- - Owner: `@jskit-ai/shell-web@0.2.12`
370
+ - Owner: `@jskit-ai/shell-web@0.2.13`
371
371
  - Read: [PATTERN.md](../../skills/jskit/references/patterns/ui/page-and-placement/PATTERN.md)
372
372
  - Examples: [example/](../../skills/jskit/references/patterns/ui/page-and-placement/example/)
373
373
  - Requires: `@jskit-ai/kernel`, `@jskit-ai/shell-web`
@@ -378,7 +378,7 @@ Compose an account settings route and profile, preference, notification, and sig
378
378
 
379
379
  - Id: `users/account-settings`
380
380
  - Keywords: `account`, `link provider`, `notifications`, `oauth`, `preferences`, `profile`, `settings`, `sign-in methods`, `user`, `vue`
381
- - Owner: `@jskit-ai/users-web@0.2.19`
381
+ - Owner: `@jskit-ai/users-web@0.2.20`
382
382
  - Read: [PATTERN.md](../../skills/jskit/references/patterns/users/account-settings/PATTERN.md)
383
383
  - Examples: [example/](../../skills/jskit/references/patterns/users/account-settings/example/)
384
384
  - Requires: `@jskit-ai/shell-web`, `@jskit-ai/users-core`, `@jskit-ai/users-web`
@@ -411,7 +411,7 @@ Compose workspace selection, invitation, member administration, settings, and re
411
411
 
412
412
  - Id: `workspaces/workspace-surfaces`
413
413
  - Keywords: `admin`, `invite`, `member`, `navigation`, `settings`, `surface`, `switcher`, `workspace`
414
- - Owner: `@jskit-ai/workspaces-web@0.2.19`
414
+ - Owner: `@jskit-ai/workspaces-web@0.2.20`
415
415
  - Read: [PATTERN.md](../../skills/jskit/references/patterns/workspaces/workspace-surfaces/PATTERN.md)
416
416
  - Examples: [example/](../../skills/jskit/references/patterns/workspaces/workspace-surfaces/example/)
417
417
  - Requires: `@jskit-ai/shell-web`, `@jskit-ai/workspaces-core`, `@jskit-ai/workspaces-web`
@@ -52,7 +52,7 @@ Local functions
52
52
  - `resolveSetupCode(env, { isProduction })`
53
53
  - `resolveAppPublicUrl(env, { emailRecovery, emailedConfirmation, oauthEnabled })`
54
54
  - `resolveRecoveryDelivery(env, { emailRecovery, isProduction })`
55
- - `resolveConfirmationDelivery(env, { emailConfirmationSender, isProduction })`
55
+ - `resolveConfirmationDelivery(env, { emailConfirmationSender, isProduction, selfRegistration })`
56
56
  - `resolvePasswordMinLength(env)`
57
57
 
58
58
  ### `src/server/lib/emailConfirmation.js`
@@ -724,8 +724,6 @@ Exports
724
724
  ### `fixtures/crud-screens/main.js`
725
725
  Exports
726
726
  - None
727
- Local functions
728
- - `destination(order, label, suffix, icon)`
729
727
 
730
728
  ### `fixtures/crud-screens/vite.config.mjs`
731
729
  Exports
@@ -182,6 +182,10 @@ Exports
182
182
  - `shellNavigationLinkProps`
183
183
  - `useShellNavigationLink(props)`
184
184
 
185
+ ### `src/client/composables/useShellOutletPlacements.js`
186
+ Exports
187
+ - `useShellOutletPlacements(target, context = {})`
188
+
185
189
  ### `src/client/composables/useShellPageTitle.js`
186
190
  Exports
187
191
  - `useShellPageTitle(title)`
@@ -327,7 +331,7 @@ Local functions
327
331
 
328
332
  ### `src/client/navigation/documentNavigation.js`
329
333
  Exports
330
- - `leaveApp(url)`
334
+ - `leaveApp(url, { replace = false } = {})`
331
335
  - `reloadAppPage(target)`
332
336
 
333
337
  ### `src/client/navigation/linkResolver.js`
@@ -335,7 +339,7 @@ Exports
335
339
  - `resolveShellLinkPath({ context = null, surface = "", explicitTo = "", relativePath = "/", surfaceRelativePath = "", params = {}, strictParams = true } = {})`
336
340
  - `useShellLinkResolver({ surface = "" } = {})`
337
341
  Local functions
338
- - `materializeSurfaceRouteBase(routeBaseTemplate = "/", { params = {}, strictParams = true, surface = "" } = {})`
342
+ - `fillPathParams(pathTemplate = "/", { params = {}, strictParams = true, label = "route params" } = {})`
339
343
  - `resolveSurfaceBasePath(context = null, surface = "", { params = {}, strictParams = true } = {})`
340
344
 
341
345
  ### `src/client/navigation/shellNavigationRuntime.js`
@@ -547,6 +551,7 @@ Exports
547
551
  - `normalizeDesktopDrawerClosedMode(value = "rail")`
548
552
  - `resolveShellDrawerPresentation({ modal = false, open = false, desktopClosedMode = "rail" } = {})`
549
553
  - `resolveShellDrawerToggleLabel({ modal = false, open = false } = {})`
554
+ - `shellLayoutHasDrawer({ menuSlot = false, menuCount = 0, identityCount = 0, bottomNavigationCount = 0 } = {})`
550
555
 
551
556
  ### `src/client/support/drawerWidth.js`
552
557
  Exports
@@ -653,12 +658,14 @@ Exports
653
658
  Exports
654
659
  - None
655
660
 
661
+ ### `fixtures/adaptive-shell/src/ButtonsPage.vue`
662
+ Exports
663
+ - None
664
+
656
665
  ### `fixtures/adaptive-shell/src/main.js`
657
666
  Exports
658
667
  - None
659
668
  Local functions
660
- - `createSurfacePlacement(surface, order, label, suffix)`
661
- - `createSurfacePlacements(surface)`
662
669
  - `refuseBlockedRecord(to)`
663
670
 
664
671
  ### `fixtures/adaptive-shell/src/OwnBarLayout.vue`
@@ -209,6 +209,10 @@ Exports
209
209
  Exports
210
210
  - None
211
211
 
212
+ ### `patterns/account-settings/example/src/pages/account.vue`
213
+ Exports
214
+ - None
215
+
212
216
  ### `patterns/account-settings/example/src/pages/account/index.vue`
213
217
  Exports
214
218
  - None
@@ -131,6 +131,7 @@ Exports
131
131
  - `checkScriptBackNames(code, offset, report)`
132
132
  - `isInAppPath(value)`
133
133
  - `isPageFile(file)`
134
+ - `readTitledFiles({ root, appFiles })`
134
135
  Local functions
135
136
  - `compact(text)`
136
137
  - `isPlacementLink(code, offset)`
@@ -146,6 +147,7 @@ Local functions
146
147
  - `enclosingObject(text, offset)`
147
148
  - `stringValue(text, key)`
148
149
  - `readMainNavigation(sources)`
150
+ - `computedPlacementPart(placement)`
149
151
  - `normalisePath(value)`
150
152
  - `routeOf(file)`
151
153
  - `routePattern(route)`
@@ -153,7 +155,7 @@ Local functions
153
155
  - `surfaceOf(route, surfaces)`
154
156
  - `routeDeclarations(source)`
155
157
  - `readPage(file, source)`
156
- - `createShellBarReader(appFiles, read)`
158
+ - `createShellBarReader(appFiles, read, tag = SHELL_UP_TAG)`
157
159
  - `localComponent(file, specifier, known)`
158
160
  - `pageKey(file)`
159
161
 
@@ -82,7 +82,10 @@ Exactly this, and nothing more:
82
82
  2. **Each top-level destination is a main-navigation item** (a `kind: "link"`
83
83
  placement with `target: "shell.primary-nav"` or `"shell.secondary-nav"`) and
84
84
  declares no parent; nor do its tabs. A shell page with no parent is
85
- top-level: no arrow, a fresh trail.
85
+ top-level: no arrow, a fresh trail. Placements are literal declarative data,
86
+ one `addPlacement({ ... })` per destination with plain string `surface`,
87
+ `scopedSuffix` and `unscopedSuffix`, never built by a helper, a spread or a
88
+ template, so a reader and `jskit check` can map every destination.
86
89
  3. **Every in-app link and navigation goes through JSKIT navigation:**
87
90
  `:to="paths.page('/suppliers')"` and `router.push(paths.page(...))` with
88
91
  `usePaths()`, the CRUD runtime's `resolveViewUrl()`, `resolveEditUrl()` and
@@ -98,7 +101,10 @@ Exactly this, and nothing more:
98
101
  5. **A full page load goes through the shell too:** `reloadAppPage(path)`
99
102
  (after sign-in or a user switch, to rebuild client state) and
100
103
  `leaveApp(url)` (an external site in the same tab, such as a payment page),
101
- from `@jskit-ai/shell-web/client/navigation/documentNavigation`.
104
+ from `@jskit-ai/shell-web/client/navigation/documentNavigation`. `leaveApp`
105
+ opens the site with a push, so Back returns to the page; a hand-off page
106
+ that only forwards (to an OAuth consent screen) uses
107
+ `leaveApp(url, { replace: true })`, so Back from the site doesn't rerun it.
102
108
 
103
109
  ### Forbidden in app code
104
110
 
@@ -110,6 +116,8 @@ Exactly this, and nothing more:
110
116
  | `nav/back-control` | any back control but the shell's Up that navigates the app: "Back to X", "← Suppliers", back arrows and navigating chevrons, breadcrumbs, a custom app-bar back button, a back component, a `goBack()`-style handler |
111
117
  | `nav/missing-parent` | an inner page of a shell surface without a declared parent |
112
118
  | `nav/top-level-parent` | a main-navigation destination that declares a parent |
119
+ | `nav/placement-data` | a main-navigation placement that isn't literal data (no page is judged for a missing parent until it is) |
120
+ | `nav/missing-shell-layout` | a page that declares a parent with no shell layout rendering it, so its title, Up and actions never show |
113
121
  | `nav/allow` | any `m3-check: allow nav/...` comment: nothing excuses a navigation rule |
114
122
 
115
123
  ### Each rule, right and wrong
@@ -182,10 +190,16 @@ JSKIT ships these exact sizes; an app never re-implements or overrides them,
182
190
  and needs no Sass and no `!important` (Vuetify 4 keeps its CSS in cascade
183
191
  layers):
184
192
 
185
- - 40dp buttons with a 48dp touch target, icon buttons included;
186
- - 12dp cards;
193
+ - 40dp buttons with a 48dp touch target, icon buttons included; a smaller
194
+ button is `size="small"` or `size="x-small"`, which keeps its smaller look
195
+ and the 48dp target;
196
+ - one-line button labels: a label longer than its button ends in an ellipsis.
197
+ Keep labels short, and give a button whose label can run long, such as a
198
+ name, the full label as its `title`;
199
+ - 12dp cards: elevated (the default) at level 1, flat and tonal at level 0;
187
200
  - 28dp dialogs and bottom-sheet top corners, square full-screen dialogs;
188
- - 8dp chips and 16dp FABs;
201
+ - 8dp chips, and FABs of 56dp (small 40dp, large 96dp; extended 56dp tall)
202
+ with 16dp corners;
189
203
  - emphasized easing, with reduced motion honoured.
190
204
 
191
205
  So never set `height` or `min-height` on a button, or a radius on a card,
@@ -197,7 +211,9 @@ dialog, chip or FAB. A missing size is a JSKIT defect.
197
211
  `useShellPageTitle(title)` (`@jskit-ai/shell-web/client/composables/useShellPageTitle`)
198
212
  for a runtime title such as the record's name. The shell renders it as the
199
213
  app bar's only `h1`; pages add no `h1`, page header, title block or
200
- standalone heading. A section inside a page uses a title role.
214
+ standalone heading. A section inside a page uses a title role. A page with
215
+ no top app bar (a hero front page, an intro, an invite or hand-off page)
216
+ has its own one `h1`.
201
217
  - **Up** sits in the bar on every inner page (see Navigation and Up). On phones
202
218
  it replaces the menu icon.
203
219
  - **A layout that draws its own top app bar** (a workspace bar with the
@@ -206,7 +222,9 @@ dialog, chip or FAB. A missing size is a JSKIT defect.
206
222
  once, so its pages enter the trail and their `ShellPageActions` show in its
207
223
  bar, and renders `ShellUpButton` first, then `ShellPageTitle` (the page's one
208
224
  `h1`: `useShellPageTitle()`, else the route's `jskit.title`, else its `title`
209
- prop) and `ShellPageActionsTarget`. `jskit check` counts it as a shell
225
+ prop) and `ShellPageActionsTarget`. A title that is also a switcher, such as a
226
+ project menu, goes in `ShellPageTitle`'s default slot (given `{ title }`) as
227
+ the menu's activator, so it stays the one `h1`. `jskit check` counts it as a shell
210
228
  layout, so its inner pages need parents; an Up the app draws itself is a
211
229
  `nav/back-control` finding.
212
230
  - **Actions:** a screen's actions go in the bar inside `ShellPageActions`
@@ -216,7 +234,9 @@ dialog, chip or FAB. A missing size is a JSKIT defect.
216
234
  On compact widths every action shows only its icon except the single
217
235
  `primary` one.
218
236
  - **Window size classes:** compact under 600 (navigation bar), medium 600–839
219
- (navigation rail), expanded 840–1199 and large from 1200 (drawer). Read them
237
+ (navigation rail), expanded 840–1199 and large from 1200 (drawer). A surface
238
+ with no navigation destinations, such as an account surface, draws no
239
+ navigation bar, rail or drawer; its pages keep the app bar. Read them
220
240
  from `useShellWindowSizeClass()`
221
241
  (`@jskit-ai/shell-web/client/composables/useShellWindowSizeClass`), never from
222
242
  copied breakpoint numbers.
@@ -316,8 +336,8 @@ and so every app's verify, fail on them too:
316
336
 
317
337
  | Rule | Finds |
318
338
  |---|---|
319
- | `m3/duplicate-h1` | a second `h1`, or an in-page `h1` in an app that uses the JSKIT shell |
320
- | `m3/raw-hex` | a hex colour outside `src/theme/` |
339
+ | `m3/duplicate-h1` | a second `h1`, or an in-page `h1` under the shell's page title |
340
+ | `m3/raw-hex` | a hex colour outside `src/theme/` (`palettes.js` holds content colours) |
321
341
  | `m3/dark-scheme` | no dark scheme, or the theme pinned to light |
322
342
  | `m3/outlined-card` | `variant="outlined"` or `border` on a card or sheet |
323
343
  | `m3/mdi-icon` | `mdi-*` icon strings and `@mdi/js` imports |
@@ -338,14 +358,36 @@ Take the approved route first; none needs an exception:
338
358
  `<v-chip color="partner">`. A hex string is harmonized toward the seed; a
339
359
  colour that must keep its hue is `{ value: "#F5C518", blend: false }`
340
360
  (Material Theme Builder's Blend switched off), with the same four roles.
341
- - **Chart and data colours** come from the theme: `const theme = useTheme()`,
342
- then `["primary", "tertiary"].map((role) => theme.current.value.colors[role])`.
361
+ - **Content colours**, colours that are content rather than UI, keep one
362
+ value in both schemes: an identity palette a person picks and the server
363
+ stores, avatar and illustration artwork, brand marks (a language's
364
+ file-type tint), fixed chart series, QR codes, colours written into
365
+ exported files. They are named exports of plain hex values in
366
+ `src/theme/palettes.js`, used as they are, never for UI chrome (a theme
367
+ colour is toned per scheme, so it can't keep an identity the same).
368
+ Components read them through bindings:
369
+
370
+ ```vue
371
+ <script setup>
372
+ // src/theme/palettes.js: export const botColours = ["#6750A4", "#B3261E"];
373
+ import { botColours } from "@/theme/palettes.js";
374
+ const props = defineProps({ bot: Object });
375
+ const ring = botColours[props.bot.colour];
376
+ </script>
377
+ <template>
378
+ <v-avatar :style="{ backgroundColor: ring }"><svg><path :fill="ring" /></svg></v-avatar>
379
+ </template>
380
+ <style scoped>.v-avatar { outline: 2px solid v-bind(ring); }</style>
381
+ ```
382
+ - **Chart and data colours** that follow the scheme come from the theme:
383
+ `const theme = useTheme()`, then
384
+ `["primary", "tertiary"].map((role) => theme.current.value.colors[role])`.
343
385
  - **A third-party widget** lives in one wrapper component, such as
344
386
  `src/components/RouteMap.vue`, that hands it theme colours; pages use only
345
387
  the wrapper.
346
388
 
347
- What is left may be excused one line at a time, on its line or the line
348
- before: `<!-- m3-check: allow m3/raw-hex - the partner's contractual logo colour -->`
389
+ What is left, such as a colour inside static SVG markup that can't import,
390
+ may be excused one line at a time, on its line or the line before: `<!-- m3-check: allow m3/raw-hex - the partner's contractual logo colour -->`
349
391
  (`// m3-check: ...` in scripts, `/* ... */` in CSS). **Never add one on your
350
392
  own:** ask the person first, naming the rule and the reason. A comment with no
351
393
  reason (`m3/allow-reason`) or an unknown rule (`m3/allow-rule`), and any
@@ -15,7 +15,7 @@ A concrete Fastify, Vue, and JSKIT application foundation for products that do n
15
15
 
16
16
  - Id: `app/minimal-foundation`
17
17
  - Keywords: `app`, `fastify`, `foundation`, `minimal`, `server`, `vite`, `vue`
18
- - Owner: `@jskit-ai/agent-docs@0.1.278`
18
+ - Owner: `@jskit-ai/agent-docs@0.1.279`
19
19
  - Read: [PATTERN.md](patterns/app/minimal-foundation/PATTERN.md)
20
20
  - Examples: [example/](patterns/app/minimal-foundation/example/)
21
21
  - Requires: `@jskit-ai/http-runtime`, `@jskit-ai/kernel`
@@ -26,7 +26,7 @@ A concrete JSKIT web application foundation with responsive shell navigation, se
26
26
 
27
27
  - Id: `app/shell-foundation`
28
28
  - Keywords: `app`, `foundation`, `material`, `navigation`, `placements`, `shell`, `vite`, `vue`
29
- - Owner: `@jskit-ai/agent-docs@0.1.278`
29
+ - Owner: `@jskit-ai/agent-docs@0.1.279`
30
30
  - Read: [PATTERN.md](patterns/app/shell-foundation/PATTERN.md)
31
31
  - Examples: [example/](patterns/app/shell-foundation/example/)
32
32
  - Requires: `@jskit-ai/http-runtime`, `@jskit-ai/kernel`, `@jskit-ai/shell-web`
@@ -37,7 +37,7 @@ Configure an assistant runtime for one application surface and expose its chat a
37
37
 
38
38
  - Id: `assistant/assistant-surface`
39
39
  - Keywords: `ai`, `assistant`, `chat`, `config`, `environment`, `page`, `placement`, `settings`, `surface`
40
- - Owner: `@jskit-ai/assistant-runtime@0.2.25`
40
+ - Owner: `@jskit-ai/assistant-runtime@0.2.26`
41
41
  - Read: [PATTERN.md](patterns/assistant/assistant-surface/PATTERN.md)
42
42
  - Examples: [example/](patterns/assistant/assistant-surface/example/)
43
43
  - Requires: `@jskit-ai/assistant-runtime`, `@jskit-ai/connectors-catalog`, `@jskit-ai/connectors-core`, `@jskit-ai/shell-web`
@@ -48,7 +48,7 @@ Run one OpenID Connect sign-in for all of an owner's apps as its own JSKIT proje
48
48
 
49
49
  - Id: `auth/accounts-hub`
50
50
  - Keywords: `accounts hub`, `auth`, `authentication`, `issuer`, `master login`, `oidc`, `openid connect`, `single sign-on`, `sso`
51
- - Owner: `@jskit-ai/oidc-issuer-core@0.1.17`
51
+ - Owner: `@jskit-ai/oidc-issuer-core@0.1.18`
52
52
  - Read: [PATTERN.md](patterns/auth/accounts-hub/PATTERN.md)
53
53
  - Examples: [example/](patterns/auth/accounts-hub/example/)
54
54
  - Requires: `@jskit-ai/oidc-issuer-core`
@@ -59,7 +59,7 @@ Compose JSKIT authentication routes, views, profile controls, and public surface
59
59
 
60
60
  - Id: `auth/auth-surface`
61
61
  - Keywords: `account`, `auth`, `login`, `logout`, `password`, `placement`, `profile`, `reset`, `surface`
62
- - Owner: `@jskit-ai/auth-web@0.2.14`
62
+ - Owner: `@jskit-ai/auth-web@0.2.15`
63
63
  - Read: [PATTERN.md](patterns/auth/auth-surface/PATTERN.md)
64
64
  - Examples: [example/](patterns/auth/auth-surface/example/)
65
65
  - Requires: `@jskit-ai/auth-core`, `@jskit-ai/auth-web`, `@jskit-ai/shell-web`
@@ -70,7 +70,7 @@ Let people sign in with the accounts they already have in an accounts hub or ano
70
70
 
71
71
  - Id: `auth/oidc-sign-in`
72
72
  - Keywords: `accounts hub`, `auth`, `authentication`, `back-channel logout`, `dynamic client registration`, `issuer`, `master login`, `oidc`, `openid connect`, `single sign-on`, `sso`
73
- - Owner: `@jskit-ai/auth-provider-oidc-core@0.2.16`
73
+ - Owner: `@jskit-ai/auth-provider-oidc-core@0.2.17`
74
74
  - Read: [PATTERN.md](patterns/auth/oidc-sign-in/PATTERN.md)
75
75
  - Examples: [example/](patterns/auth/oidc-sign-in/example/)
76
76
  - Requires: `@jskit-ai/auth-provider-oidc-core`, `@jskit-ai/auth-web`
@@ -246,7 +246,7 @@ Add a protected administration surface, settings shell, and semantic navigation
246
246
 
247
247
  - Id: `console/console-surface`
248
248
  - Keywords: `admin`, `console`, `navigation`, `owner`, `placement`, `settings`, `surface`
249
- - Owner: `@jskit-ai/console-web@0.1.236`
249
+ - Owner: `@jskit-ai/console-web@0.1.237`
250
250
  - Read: [PATTERN.md](patterns/console/console-surface/PATTERN.md)
251
251
  - Examples: [example/](patterns/console/console-surface/example/)
252
252
  - Requires: `@jskit-ai/console-core`, `@jskit-ai/console-web`, `@jskit-ai/shell-web`
@@ -257,7 +257,7 @@ Build a routed CRUD user interface as thin application pages over JSKIT's shared
257
257
 
258
258
  - Id: `crud/crud-screen-set`
259
259
  - Keywords: `actions`, `add`, `crud`, `delete`, `edit`, `filters`, `list`, `material`, `routes`, `view`, `vue`
260
- - Owner: `@jskit-ai/http-web@0.2.17`
260
+ - Owner: `@jskit-ai/http-web@0.2.18`
261
261
  - Read: [PATTERN.md](patterns/crud/crud-screen-set/PATTERN.md)
262
262
  - Examples: [example/](patterns/crud/crud-screen-set/example/)
263
263
  - Requires: `@jskit-ai/http-web`, `@jskit-ai/resource-crud-core`
@@ -312,7 +312,7 @@ Wrap a JSKIT web application in a Capacitor Android shell using native Capacitor
312
312
 
313
313
  - Id: `mobile/android-application`
314
314
  - Keywords: `android`, `capacitor`, `device`, `mobile`, `native`, `shell`, `webview`
315
- - Owner: `@jskit-ai/mobile-capacitor@0.2.12`
315
+ - Owner: `@jskit-ai/mobile-capacitor@0.2.13`
316
316
  - Read: [PATTERN.md](patterns/mobile/android-application/PATTERN.md)
317
317
  - Examples: [example/](patterns/mobile/android-application/example/)
318
318
  - Requires: `@capacitor/android`, `@capacitor/app`, `@capacitor/cli`, `@jskit-ai/mobile-capacitor`
@@ -323,7 +323,7 @@ Add JSKIT realtime events with an optional Redis backplane and an explicit shell
323
323
 
324
324
  - Id: `realtime/realtime-application`
325
325
  - Keywords: `realtime`, `redis`, `socket.io`, `sockets`, `status`, `websocket`
326
- - Owner: `@jskit-ai/realtime@0.2.15`
326
+ - Owner: `@jskit-ai/realtime@0.2.16`
327
327
  - Read: [PATTERN.md](patterns/realtime/realtime-application/PATTERN.md)
328
328
  - Examples: [example/](patterns/realtime/realtime-application/example/)
329
329
  - Requires: `@jskit-ai/realtime`, `@jskit-ai/shell-web`
@@ -334,7 +334,7 @@ Compose application-owned Google Publisher Tag delivery with the generic rewarde
334
334
 
335
335
  - Id: `rewards/google-rewarded`
336
336
  - Keywords: `ads`, `google`, `publisher tag`, `rewarded`, `unlock`
337
- - Owner: `@jskit-ai/rewarded-web@0.2.14`
337
+ - Owner: `@jskit-ai/rewarded-web@0.2.15`
338
338
  - Read: [PATTERN.md](patterns/rewards/google-rewarded/PATTERN.md)
339
339
  - Examples: [example/](patterns/rewards/google-rewarded/example/)
340
340
  - Requires: `@jskit-ai/rewarded-web`
@@ -345,7 +345,7 @@ Define a server feature through explicit capabilities and first-class actions, a
345
345
 
346
346
  - Id: `server/feature-package`
347
347
  - Keywords: `actions`, `feature`, `json-rest`, `knex`, `orchestration`, `package`, `provider`, `repository`, `routes`, `server`
348
- - Owner: `@jskit-ai/agent-docs@0.1.278`
348
+ - Owner: `@jskit-ai/agent-docs@0.1.279`
349
349
  - Read: [PATTERN.md](patterns/server/feature-package/PATTERN.md)
350
350
  - Examples: [example/](patterns/server/feature-package/example/)
351
351
  - Requires: `@jskit-ai/kernel`
@@ -356,7 +356,7 @@ Compose the JSKIT responsive shell, semantic placements, settings navigation, an
356
356
 
357
357
  - Id: `shell/application-shell`
358
358
  - Keywords: `adaptive`, `app`, `layout`, `navigation`, `placement`, `responsive`, `settings`, `shell`
359
- - Owner: `@jskit-ai/shell-web@0.2.12`
359
+ - Owner: `@jskit-ai/shell-web@0.2.13`
360
360
  - Read: [PATTERN.md](patterns/shell/application-shell/PATTERN.md)
361
361
  - Examples: [example/](patterns/shell/application-shell/example/)
362
362
  - Requires: `@jskit-ai/kernel`, `@jskit-ai/shell-web`
@@ -367,7 +367,7 @@ Add product routes and shell extensions through file routing, semantic placement
367
367
 
368
368
  - Id: `ui/page-and-placement`
369
369
  - Keywords: `component`, `navigation`, `outlet`, `page`, `placement`, `routes`, `section`, `shell`, `subpages`, `vue`
370
- - Owner: `@jskit-ai/shell-web@0.2.12`
370
+ - Owner: `@jskit-ai/shell-web@0.2.13`
371
371
  - Read: [PATTERN.md](patterns/ui/page-and-placement/PATTERN.md)
372
372
  - Examples: [example/](patterns/ui/page-and-placement/example/)
373
373
  - Requires: `@jskit-ai/kernel`, `@jskit-ai/shell-web`
@@ -378,7 +378,7 @@ Compose an account settings route and profile, preference, notification, and sig
378
378
 
379
379
  - Id: `users/account-settings`
380
380
  - Keywords: `account`, `link provider`, `notifications`, `oauth`, `preferences`, `profile`, `settings`, `sign-in methods`, `user`, `vue`
381
- - Owner: `@jskit-ai/users-web@0.2.19`
381
+ - Owner: `@jskit-ai/users-web@0.2.20`
382
382
  - Read: [PATTERN.md](patterns/users/account-settings/PATTERN.md)
383
383
  - Examples: [example/](patterns/users/account-settings/example/)
384
384
  - Requires: `@jskit-ai/shell-web`, `@jskit-ai/users-core`, `@jskit-ai/users-web`
@@ -411,7 +411,7 @@ Compose workspace selection, invitation, member administration, settings, and re
411
411
 
412
412
  - Id: `workspaces/workspace-surfaces`
413
413
  - Keywords: `admin`, `invite`, `member`, `navigation`, `settings`, `surface`, `switcher`, `workspace`
414
- - Owner: `@jskit-ai/workspaces-web@0.2.19`
414
+ - Owner: `@jskit-ai/workspaces-web@0.2.20`
415
415
  - Read: [PATTERN.md](patterns/workspaces/workspace-surfaces/PATTERN.md)
416
416
  - Examples: [example/](patterns/workspaces/workspace-surfaces/example/)
417
417
  - Requires: `@jskit-ai/shell-web`, `@jskit-ai/workspaces-core`, `@jskit-ai/workspaces-web`
@@ -35,7 +35,7 @@
35
35
  "@local/main": "0.1.0",
36
36
  "@fastify/static": "^10.1.3",
37
37
  "@jskit-ai/kernel": "0.2.10",
38
- "@jskit-ai/material-web": "0.1.1",
38
+ "@jskit-ai/material-web": "0.1.2",
39
39
  "@tanstack/vue-query": "^5.101.0",
40
40
  "fastify": "^5.12.7",
41
41
  "pino": "^10.3.1",
@@ -50,7 +50,7 @@
50
50
  },
51
51
  "devDependencies": {
52
52
  "@jskit-ai/config-eslint": "0.1.245",
53
- "@jskit-ai/jskit-catalog": "0.2.30",
53
+ "@jskit-ai/jskit-catalog": "0.2.31",
54
54
  "@playwright/test": "1.61.1",
55
55
  "@vitejs/plugin-vue": "^6.0.7",
56
56
  "eslint": "^10.8.0",
@@ -35,7 +35,7 @@
35
35
  "@local/main": "0.1.0",
36
36
  "@fastify/static": "^10.1.3",
37
37
  "@jskit-ai/kernel": "0.2.10",
38
- "@jskit-ai/material-web": "0.1.1",
38
+ "@jskit-ai/material-web": "0.1.2",
39
39
  "@tanstack/vue-query": "^5.101.0",
40
40
  "fastify": "^5.12.7",
41
41
  "pino": "^10.3.1",
@@ -45,13 +45,13 @@
45
45
  "vue-router": "^5.3.1",
46
46
  "vuetify": "^4.3.0",
47
47
  "@jskit-ai/http-runtime": "0.2.10",
48
- "@jskit-ai/shell-web": "0.2.12",
48
+ "@jskit-ai/shell-web": "0.2.13",
49
49
  "@fastify/fast-json-stringify-compiler": "^5.1.0",
50
50
  "@vue/devtools-api": "^8.2.1"
51
51
  },
52
52
  "devDependencies": {
53
53
  "@jskit-ai/config-eslint": "0.1.245",
54
- "@jskit-ai/jskit-catalog": "0.2.30",
54
+ "@jskit-ai/jskit-catalog": "0.2.31",
55
55
  "@playwright/test": "1.61.1",
56
56
  "@vitejs/plugin-vue": "^6.0.7",
57
57
  "eslint": "^10.8.0",
@@ -3,6 +3,6 @@
3
3
  "type": "module",
4
4
  "dependencies": {
5
5
  "@jskit-ai/database-runtime-mysql": "0.1.257",
6
- "@jskit-ai/oidc-issuer-core": "0.1.17"
6
+ "@jskit-ai/oidc-issuer-core": "0.1.18"
7
7
  }
8
8
  }
@@ -2,7 +2,7 @@
2
2
  "private": true,
3
3
  "type": "module",
4
4
  "dependencies": {
5
- "@jskit-ai/auth-provider-oidc-core": "0.2.16",
6
- "@jskit-ai/auth-web": "0.2.14"
5
+ "@jskit-ai/auth-provider-oidc-core": "0.2.17",
6
+ "@jskit-ai/auth-web": "0.2.15"
7
7
  }
8
8
  }
@@ -2,7 +2,7 @@
2
2
  "private": true,
3
3
  "type": "module",
4
4
  "dependencies": {
5
- "@jskit-ai/realtime": "0.2.15",
6
- "@jskit-ai/shell-web": "0.2.12"
5
+ "@jskit-ai/realtime": "0.2.16",
6
+ "@jskit-ai/shell-web": "0.2.13"
7
7
  }
8
8
  }
@@ -57,10 +57,15 @@ provider offers provider linking (`providerLinking` in its capabilities).
57
57
  - Loading uses layout-stable skeletons, never an indeterminate spinner.
58
58
  - Pending controls keep stable labels and prevent duplicate submission.
59
59
  - The route and placement owner agree.
60
+ - The account surface renders in its own layout, `src/pages/account.vue`
61
+ (`ShellLayout` around `<RouterView />`, `meta.jskit.surface: "account"`), so
62
+ the settings page's title, Up arrow and Done action are in the top app bar.
63
+ With no navigation items, the surface shows no navigation bar, rail or drawer.
60
64
 
61
65
  ## Example files
62
66
 
63
- `example/` contains an account route and four concrete settings sections.
67
+ `example/` contains the account surface's layout, an account route and four
68
+ concrete settings sections.
64
69
  Adapt their fields and copy while retaining the shared account runtime.
65
70
 
66
71
  ## Variation points
@@ -0,0 +1,22 @@
1
+ <route lang="json">
2
+ {
3
+ "meta": {
4
+ "jskit": {
5
+ "surface": "account"
6
+ }
7
+ }
8
+ }
9
+ </route>
10
+
11
+ <script setup>
12
+ // The account surface's layout: the shell's top app bar carries the settings page's title, its Up arrow back to home
13
+ // and its Done action. The surface has no navigation items, so the shell draws no navigation bar, rail or drawer.
14
+ import ShellLayout from "@/components/ShellLayout.vue";
15
+ import { RouterView } from "vue-router";
16
+ </script>
17
+
18
+ <template>
19
+ <ShellLayout title="" subtitle="">
20
+ <RouterView />
21
+ </ShellLayout>
22
+ </template>