@jskit-ai/agent-docs 0.1.239 → 0.1.241
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/guide/agent/app-extras/assistant-conversation.md +11 -6
- package/guide/agent/app-setup/authentication.md +28 -2
- package/guide/agent/app-setup/existing-application-migration.md +5 -3
- package/guide/agent/app-setup/initial-scaffolding.md +4 -1
- package/guide/agent/app-setup/run-an-accounts-hub.md +152 -0
- package/guide/agent/app-setup/sign-in-through-oidc-issuer.md +148 -0
- package/guide/agent/app-setup/upgrading-jskit.md +13 -0
- package/guide/agent/framework/application-operations.md +3 -0
- package/guide/agent/framework/ui-operations.md +24 -0
- package/guide/agent/index.md +2 -0
- package/package.json +1 -1
- package/patterns/feature-package/example/booking-engine/package.json +1 -1
- package/patterns/minimal-foundation/example/package.json +3 -3
- package/patterns/shell-foundation/example/package.json +4 -4
- package/patterns/shell-foundation/example/packages/main/package.json +1 -1
- package/reference/autogen/KERNEL_MAP.md +1 -0
- package/reference/autogen/PATTERN_INDEX.md +57 -35
- package/reference/autogen/README.md +2 -0
- package/reference/autogen/packages/auth-core.md +1 -0
- package/reference/autogen/packages/auth-provider-oidc-core.md +144 -0
- package/reference/autogen/packages/auth-web.md +16 -0
- package/reference/autogen/packages/kernel.md +6 -1
- package/reference/autogen/packages/oidc-issuer-core.md +201 -0
- package/reference/autogen/packages/shell-web.md +3 -0
- package/reference/autogen/tooling/jskit-release.md +1 -0
- package/skills/jskit/references/app-operations.md +3 -0
- package/skills/jskit/references/existing-application-migration.md +5 -3
- package/skills/jskit/references/pattern-index.md +57 -35
- package/skills/jskit/references/patterns/app/minimal-foundation/example/package.json +3 -3
- package/skills/jskit/references/patterns/app/shell-foundation/example/package.json +4 -4
- package/skills/jskit/references/patterns/app/shell-foundation/example/packages/main/package.json +1 -1
- package/skills/jskit/references/patterns/auth/accounts-hub/PATTERN.md +97 -0
- package/skills/jskit/references/patterns/auth/accounts-hub/example/.env.example +10 -0
- package/skills/jskit/references/patterns/auth/accounts-hub/example/package.json +8 -0
- package/skills/jskit/references/patterns/auth/accounts-hub/example/server/hubPaths.js +7 -0
- package/skills/jskit/references/patterns/auth/auth-surface/PATTERN.md +33 -11
- package/skills/jskit/references/patterns/auth/oidc-sign-in/PATTERN.md +87 -0
- package/skills/jskit/references/patterns/auth/oidc-sign-in/example/.env.example +13 -0
- package/skills/jskit/references/patterns/auth/oidc-sign-in/example/package.json +8 -0
- package/skills/jskit/references/patterns/auth/supabase-auth/example/package.json +1 -1
- package/skills/jskit/references/patterns/connectors/calendar-cli/example/package.json +4 -4
- package/skills/jskit/references/patterns/connectors/oauth-connection/PATTERN.md +25 -0
- package/skills/jskit/references/patterns/crud/json-api-resource-package/example/packages/books/package.json +2 -2
- package/skills/jskit/references/patterns/database/mysql-application/example/package.json +1 -1
- package/skills/jskit/references/patterns/database/postgres-application/example/package.json +1 -1
- package/skills/jskit/references/patterns/realtime/realtime-application/example/package.json +2 -2
- package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/package.json +1 -1
- package/skills/jskit/references/patterns/shell/application-shell/PATTERN.md +9 -0
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users/package.json +2 -2
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/package.json +3 -3
- package/skills/jskit/references/ui-operations.md +24 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: auth/accounts-hub
|
|
3
|
+
title: Accounts hub
|
|
4
|
+
summary: Run one OpenID Connect sign-in for all of an owner's apps as its own JSKIT project, with production apps approved by the owner.
|
|
5
|
+
keywords: auth, authentication, oidc, openid connect, issuer, single sign-on, sso, accounts hub, master login
|
|
6
|
+
requires: @jskit-ai/oidc-issuer-core
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Accounts hub
|
|
10
|
+
|
|
11
|
+
## Use when
|
|
12
|
+
|
|
13
|
+
Use this pattern when one person or company owns several apps and wants one
|
|
14
|
+
account to sign in to all of them. The hub is its own project, deployed on a
|
|
15
|
+
domain of its own. Apps sign in through it with
|
|
16
|
+
`@jskit-ai/auth-provider-oidc-core` (pattern `auth/oidc-sign-in`).
|
|
17
|
+
|
|
18
|
+
## Do not use when
|
|
19
|
+
|
|
20
|
+
Do not use it inside an app that has its own users only: use local accounts.
|
|
21
|
+
Do not add it to an existing app as a second purpose; the hub's cookies and
|
|
22
|
+
pages belong on their own origin.
|
|
23
|
+
|
|
24
|
+
## Product decisions
|
|
25
|
+
|
|
26
|
+
- The hub's address (`APP_PUBLIC_URL`), on a domain no app shares.
|
|
27
|
+
- The owner (`OIDC_HUB_OWNER_EMAIL`): only this verified account opens Apps,
|
|
28
|
+
People and Setup.
|
|
29
|
+
- The email sender (`OIDC_HUB_EMAIL_FROM` with `RESEND_API_KEY` or `SMTP_URL`).
|
|
30
|
+
- Optional "Continue with Google" with the owner's own Google OAuth client
|
|
31
|
+
(`OIDC_HUB_GOOGLE_CLIENT_ID`, `OIDC_HUB_GOOGLE_CLIENT_SECRET`), redirect URI
|
|
32
|
+
`{APP_PUBLIC_URL}/hub/google/callback`.
|
|
33
|
+
- Development addresses approved automatically
|
|
34
|
+
(`OIDC_HUB_DEV_ORIGIN_PATTERNS`, comma-separated `https://` globs where `*`
|
|
35
|
+
stays inside one DNS label). Loopback is always included.
|
|
36
|
+
|
|
37
|
+
## Invariants
|
|
38
|
+
|
|
39
|
+
- Secrets (`OIDC_HUB_SECRET`, `OIDC_HUB_REGISTRATION_TOKEN`, sender keys,
|
|
40
|
+
Google secret) live in the host's secret store, never in source.
|
|
41
|
+
- Every production app address waits for one owner click in Apps. Names are
|
|
42
|
+
self-asserted; the full address is what the owner approves.
|
|
43
|
+
- Apps receive the authorization code flow with PKCE only, no refresh tokens,
|
|
44
|
+
exact redirect URIs, and the same `sub` everywhere.
|
|
45
|
+
- The issuer and `/hub` paths are never framed; in production no hub page is.
|
|
46
|
+
(Development lets an editor's preview pane show the hub's own pages.) The
|
|
47
|
+
hub's own sign-in is first-party: apps never see passwords.
|
|
48
|
+
- Passwords use the JSKIT local-account scrypt v1 format, so local accounts
|
|
49
|
+
import unchanged.
|
|
50
|
+
|
|
51
|
+
## Framework APIs
|
|
52
|
+
|
|
53
|
+
Install `@jskit-ai/oidc-issuer-core` with a database driver
|
|
54
|
+
(`@jskit-ai/database-runtime-mysql`). Its provider mounts on the app's Fastify
|
|
55
|
+
server:
|
|
56
|
+
|
|
57
|
+
- `/.well-known/openid-configuration` and `/oidc/*`: the issuer, built on
|
|
58
|
+
`oidc-provider` with a persistent Knex adapter;
|
|
59
|
+
- `/oidc/reg`: protected self-registration (RFC 7591/7592) with the
|
|
60
|
+
registration token as the initial access token;
|
|
61
|
+
- `/hub/interaction/:uid`, `/hub/google/*`, `/hub/api/*`: the hub's sign-in,
|
|
62
|
+
account and admin API that the app's own pages call.
|
|
63
|
+
|
|
64
|
+
Add `HUB_GLOBAL_PATHS` from `@jskit-ai/oidc-issuer-core/server` to the
|
|
65
|
+
server's global UI paths so a surface-filtered server still serves them.
|
|
66
|
+
Pages send `x-hub-request: 1` on every state-changing call.
|
|
67
|
+
|
|
68
|
+
Commands (`jskit-oidc-issuer`): `keys rotate`, `import-accounts --in <file>
|
|
69
|
+
[--apply]` (dry run by default), `preview-identity`.
|
|
70
|
+
|
|
71
|
+
## Example files
|
|
72
|
+
|
|
73
|
+
`example/package.json` declares the hub runtime. `example/.env.example` names
|
|
74
|
+
every variable without values. `example/server/hubPaths.js` shows the one
|
|
75
|
+
server change.
|
|
76
|
+
|
|
77
|
+
## Variation points
|
|
78
|
+
|
|
79
|
+
Page design, wording and branding are the app's. Development origin patterns,
|
|
80
|
+
the email sender and Google are configuration. The registration policy,
|
|
81
|
+
security headers and token rules are not variation points.
|
|
82
|
+
|
|
83
|
+
## Verification
|
|
84
|
+
|
|
85
|
+
- Start with a missing variable and read the one-sentence error.
|
|
86
|
+
- Register a loopback app: it is approved automatically and signs in.
|
|
87
|
+
- Register an https app on another domain: it waits until Approve.
|
|
88
|
+
- Rotate the signing key: old ID tokens verify for two hours, then fail.
|
|
89
|
+
- Import exported local accounts with a dry run first; an imported account
|
|
90
|
+
signs in with its old password.
|
|
91
|
+
|
|
92
|
+
## Avoid
|
|
93
|
+
|
|
94
|
+
- running the hub on a domain an app shares
|
|
95
|
+
- approving an app by its name without reading its address
|
|
96
|
+
- copying secrets into source or into the hub's Env defaults
|
|
97
|
+
- turning on development interactions or refresh tokens for apps
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
APP_PUBLIC_URL=https://accounts.example.com
|
|
2
|
+
OIDC_HUB_SECRET=
|
|
3
|
+
OIDC_HUB_REGISTRATION_TOKEN=
|
|
4
|
+
OIDC_HUB_OWNER_EMAIL=
|
|
5
|
+
OIDC_HUB_DEV_ORIGIN_PATTERNS=
|
|
6
|
+
OIDC_HUB_EMAIL_FROM=
|
|
7
|
+
RESEND_API_KEY=
|
|
8
|
+
SMTP_URL=
|
|
9
|
+
OIDC_HUB_GOOGLE_CLIENT_ID=
|
|
10
|
+
OIDC_HUB_GOOGLE_CLIENT_SECRET=
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { HUB_GLOBAL_PATHS } from "@jskit-ai/oidc-issuer-core/server";
|
|
2
|
+
|
|
3
|
+
// Pass these to registerSurfaceRequestConstraint({ globalUiPaths }) next to
|
|
4
|
+
// the runtime's own global paths, so every surface server serves the hub.
|
|
5
|
+
export function hubGlobalUiPaths(runtimeGlobalUiPaths = []) {
|
|
6
|
+
return [...new Set([...runtimeGlobalUiPaths, ...HUB_GLOBAL_PATHS])];
|
|
7
|
+
}
|
|
@@ -30,16 +30,33 @@ Use the views, auth guard, HTTP client integration, sign-out runtime, providers,
|
|
|
30
30
|
and Playwright auth helper exported by `@jskit-ai/auth-web`. Use auth policies
|
|
31
31
|
from `@jskit-ai/auth-core` for server authorization.
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
33
|
+
Every application with accounts includes the managed-preview login. It is
|
|
34
|
+
standard, not optional: adding this pattern adds it, so a managed host's
|
|
35
|
+
preview can sign its browser in as an existing account without anyone asking
|
|
36
|
+
for it. Copy the app-owned `tools/preview-identity` executable (keep it
|
|
37
|
+
executable) and declare it under `#### Preview identity` in the project's
|
|
38
|
+
web-presented Vibe64 `Outputs` target, exactly:
|
|
39
|
+
|
|
40
|
+
```markdown
|
|
41
|
+
#### Preview identity
|
|
42
|
+
|
|
43
|
+
- Command: `tools/preview-identity`
|
|
44
|
+
- Protocol: `vibe64.preview-identity.command.v1`
|
|
45
|
+
- Identity types: `email` `user-id`
|
|
46
|
+
- Enabled environment: `AUTH_DEV_BYPASS_ENABLED`
|
|
47
|
+
- Secret environment: `AUTH_DEV_BYPASS_SECRET`
|
|
48
|
+
- Runtimes: `nodejs`
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The preview host supplies fresh output-run-scoped values for both environment
|
|
52
|
+
names; users do not set them by hand, and the exchange stays disabled without
|
|
53
|
+
them. The person using the host chooses which existing accounts the preview may
|
|
54
|
+
sign in as; the application never creates users for it. JSKIT owns this
|
|
55
|
+
executable/library pattern, Vibe64 owns the `Outputs` grammar and runtime
|
|
56
|
+
behavior, and Genesis only composes that consumer-owned section as opaque text.
|
|
57
|
+
The executable calls the exported managed-preview identity library directly; it
|
|
58
|
+
does not require a JSKIT CLI. A project without Genesis or a managed host keeps
|
|
59
|
+
the executable; it is inert unless both environment values are present.
|
|
43
60
|
|
|
44
61
|
Choose local-auth storage through the installed capability provider. A
|
|
45
62
|
database-backed application installs `@jskit-ai/auth-provider-local-db-core`,
|
|
@@ -52,6 +69,8 @@ a user as a side effect.
|
|
|
52
69
|
## Invariants
|
|
53
70
|
|
|
54
71
|
- Credentials and provider secrets come from environment values.
|
|
72
|
+
- An application with accounts ships the executable `tools/preview-identity`
|
|
73
|
+
and declares it under `#### Preview identity` in its web `Outputs` target.
|
|
55
74
|
- Auth backend selection comes from the installed provider graph, not an
|
|
56
75
|
`AUTH_LOCAL_BACKEND` environment value.
|
|
57
76
|
- The selected auth backend and the storage containing the application's users
|
|
@@ -72,7 +91,8 @@ a user as a side effect.
|
|
|
72
91
|
|
|
73
92
|
`example/` contains concrete route wrappers, editable view wrappers, and the
|
|
74
93
|
client runtime helpers needed by an authentication surface. It also contains
|
|
75
|
-
the
|
|
94
|
+
the standard app-owned managed-preview identity executable,
|
|
95
|
+
`tools/preview-identity`. Compose their
|
|
76
96
|
surface and placement declarations into the application's ordinary config and
|
|
77
97
|
placement files.
|
|
78
98
|
|
|
@@ -87,6 +107,8 @@ Exercise failed and successful login, sign-out, reset, protected navigation,
|
|
|
87
107
|
keyboard interaction, warm-cache return navigation, and browser refresh.
|
|
88
108
|
Open the login route with an existing authenticated session and confirm it
|
|
89
109
|
returns to the requested screen; repeat signed out and confirm the form remains.
|
|
110
|
+
Confirm `tools/preview-identity` is committed as executable and the web
|
|
111
|
+
`Outputs` target declares the `#### Preview identity` block above.
|
|
90
112
|
|
|
91
113
|
## Avoid
|
|
92
114
|
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: auth/oidc-sign-in
|
|
3
|
+
title: Sign in through an OIDC issuer
|
|
4
|
+
summary: Let people sign in with the accounts they already have in an accounts hub or another OpenID Connect issuer, instead of app-local passwords.
|
|
5
|
+
keywords: auth, authentication, oidc, openid connect, single sign-on, sso, accounts hub, master login, issuer, back-channel logout, dynamic client registration
|
|
6
|
+
requires: @jskit-ai/auth-provider-oidc-core, @jskit-ai/auth-web
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Sign in through an OIDC issuer
|
|
10
|
+
|
|
11
|
+
## Use when
|
|
12
|
+
|
|
13
|
+
Several apps should share one set of accounts: people sign in once at an
|
|
14
|
+
accounts hub (see `auth/accounts-hub`) or at an organisation's OpenID Connect
|
|
15
|
+
issuer, and every app signs them in from there. The app keeps its own `users`
|
|
16
|
+
rows and its own session; the issuer only proves who the person is.
|
|
17
|
+
|
|
18
|
+
## Do not use when
|
|
19
|
+
|
|
20
|
+
The app needs its own passwords (use `auth-provider-local-core`), or the product
|
|
21
|
+
has deliberately chosen Supabase (`auth/supabase-auth`). Install exactly one
|
|
22
|
+
`auth.service` provider.
|
|
23
|
+
|
|
24
|
+
## Product decisions
|
|
25
|
+
|
|
26
|
+
- Which issuer. A hub gives each app a registration token; other issuers
|
|
27
|
+
(Google Workspace, Okta) give a fixed client id and secret instead.
|
|
28
|
+
- The button label people see.
|
|
29
|
+
- The production address, and who approves the app in the hub.
|
|
30
|
+
- Whether existing local accounts move to the hub (one-time commands below) or
|
|
31
|
+
the app starts fresh.
|
|
32
|
+
|
|
33
|
+
## Invariants
|
|
34
|
+
|
|
35
|
+
- One client per app address. With a registration token the app registers
|
|
36
|
+
itself the first time it is used from a new address (or at start when
|
|
37
|
+
`APP_PUBLIC_URL` is set) and stores the client in `auth_oidc_clients`.
|
|
38
|
+
- The redirect URI is auth-web's login route, `AUTH_OIDC_REDIRECT_PATH`
|
|
39
|
+
(`/auth/login`). Where to go afterwards travels in a sealed, ten-minute,
|
|
40
|
+
single-use attempt cookie, never in the redirect URI.
|
|
41
|
+
- Every sign-in uses PKCE, `state`, `nonce` and the RFC 9207 `iss` check; ID
|
|
42
|
+
tokens must name this issuer and this client.
|
|
43
|
+
- The app session is the app's own cookie (30 days), backed by
|
|
44
|
+
`auth_oidc_sessions`. Signing out of the app does not sign out of the issuer
|
|
45
|
+
unless the person asks for it.
|
|
46
|
+
- Secrets stay in Env, never in source.
|
|
47
|
+
|
|
48
|
+
## Framework APIs
|
|
49
|
+
|
|
50
|
+
- `@jskit-ai/auth-provider-oidc-core` provides `auth.service`, its migration and
|
|
51
|
+
the `jskit-oidc-sign-in` command.
|
|
52
|
+
- `@jskit-ai/auth-provider-oidc-core/shared` exports `AUTH_OIDC_PROVIDER_ID`,
|
|
53
|
+
`AUTH_OIDC_REDIRECT_PATH`, `AUTH_OIDC_LOGOUT_PATH` and
|
|
54
|
+
`AUTH_OIDC_BACKCHANNEL_LOGOUT_PATH`.
|
|
55
|
+
- auth-web's login page shows the one button. Inside a frame (an editor
|
|
56
|
+
Preview) it opens the issuer in a pop-up window and reloads signed in.
|
|
57
|
+
|
|
58
|
+
## Example files
|
|
59
|
+
|
|
60
|
+
`example/package.json` declares the provider and the login surface.
|
|
61
|
+
`example/.env.example` names every Env value without credentials.
|
|
62
|
+
|
|
63
|
+
## Variation points
|
|
64
|
+
|
|
65
|
+
- Static client (`AUTH_OIDC_CLIENT_ID`/`AUTH_OIDC_CLIENT_SECRET`) instead of
|
|
66
|
+
the registration token; never both.
|
|
67
|
+
- `AUTH_OIDC_LABEL` for the button.
|
|
68
|
+
- A sign-out-everywhere link: `/api/auth/oidc/logout?everywhere=1` also ends the
|
|
69
|
+
issuer session through its end-session endpoint.
|
|
70
|
+
|
|
71
|
+
## Verification
|
|
72
|
+
|
|
73
|
+
- Missing `AUTH_OIDC_ISSUER` shows "Sign-in is not set up yet" instead of a
|
|
74
|
+
crash.
|
|
75
|
+
- Sign in unframed and inside the Preview frame; refresh stays signed in.
|
|
76
|
+
- A production address the hub has not approved yet reaches the hub's waiting
|
|
77
|
+
page; a blocked one reads "Your accounts hub has blocked this app's address."
|
|
78
|
+
- Disabling the account in the hub ends the app session (back-channel logout).
|
|
79
|
+
- Preview identity (`tools/preview-identity`) still signs in as an existing
|
|
80
|
+
`users` row.
|
|
81
|
+
|
|
82
|
+
## Avoid
|
|
83
|
+
|
|
84
|
+
- keeping the local provider installed alongside this one
|
|
85
|
+
- putting the return path or any secret in the redirect URI
|
|
86
|
+
- sharing one registered client between addresses
|
|
87
|
+
- running the account move commands without the person's explicit yes
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# The accounts hub (or any OpenID Connect issuer). Discovery is used.
|
|
2
|
+
AUTH_OIDC_ISSUER=https://accounts.example.com/oidc
|
|
3
|
+
# Preferred: the app registers itself, once per address, with this token.
|
|
4
|
+
AUTH_OIDC_REGISTRATION_TOKEN=replace-me
|
|
5
|
+
# Instead of the token, for issuers without self-registration:
|
|
6
|
+
# AUTH_OIDC_CLIENT_ID=replace-me
|
|
7
|
+
# AUTH_OIDC_CLIENT_SECRET=replace-me
|
|
8
|
+
# Optional button label.
|
|
9
|
+
# AUTH_OIDC_LABEL=Continue with your account
|
|
10
|
+
# Required in production, at least 32 characters. Generated in development.
|
|
11
|
+
# AUTH_OIDC_SESSION_SECRET=replace-me
|
|
12
|
+
# The address people use. Registers at start; required behind a non-loopback proxy.
|
|
13
|
+
APP_PUBLIC_URL=http://localhost:5173
|
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
"db:migrate:status": "knex --knexfile ./knexfile.js migrate:list"
|
|
8
8
|
},
|
|
9
9
|
"dependencies": {
|
|
10
|
-
"@jskit-ai/connectors-core": "0.1.
|
|
11
|
-
"@jskit-ai/connector-google-calendar": "0.1.
|
|
12
|
-
"@jskit-ai/database-runtime": "0.1.
|
|
13
|
-
"@jskit-ai/database-runtime-mysql": "0.1.
|
|
10
|
+
"@jskit-ai/connectors-core": "0.1.62",
|
|
11
|
+
"@jskit-ai/connector-google-calendar": "0.1.62",
|
|
12
|
+
"@jskit-ai/database-runtime": "0.1.245",
|
|
13
|
+
"@jskit-ai/database-runtime-mysql": "0.1.243",
|
|
14
14
|
"knex": "^3.1.0"
|
|
15
15
|
}
|
|
16
16
|
}
|
|
@@ -181,6 +181,31 @@ comma-separated permissions. Oura handles reduced callback scopes and rotated
|
|
|
181
181
|
refresh tokens. Some providers do not return a refresh token; expired access
|
|
182
182
|
then needs consent again. Provider PKCE enforcement needs provider evidence.
|
|
183
183
|
|
|
184
|
+
## Shared connection from an Env refresh token
|
|
185
|
+
|
|
186
|
+
When the application's host already holds a long-lived grant for the shared
|
|
187
|
+
account (the owner connected it once with the same OAuth client), skip consent
|
|
188
|
+
in the app: add `refreshTokenRef` to a `shared` oauth2 integration whose
|
|
189
|
+
registration uses the authorization-code flow.
|
|
190
|
+
|
|
191
|
+
```json
|
|
192
|
+
"authentication": {
|
|
193
|
+
"method": "oauth2",
|
|
194
|
+
"registrationRef": "google",
|
|
195
|
+
"refreshTokenRef": "env:GOOGLE_REFRESH_TOKEN"
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
The Env value is a seed. On first use, and whenever the value or the OAuth
|
|
200
|
+
client changes, the runtime replaces the shared connection with one built from
|
|
201
|
+
that refresh token. From then on it refreshes and stores rotated tokens in the
|
|
202
|
+
application's own store as usual. `status()` reports `source: "env"` (show it as
|
|
203
|
+
"Connected from Env"). `beginAuthorization()` and `disconnect()` refuse with
|
|
204
|
+
`connector_env_managed`: "This connection comes from an Env value; unlink or
|
|
205
|
+
replace that value instead." A revoked token fails with "The refresh token in
|
|
206
|
+
Env no longer works; replace that Env value." The refresh token must come from
|
|
207
|
+
the same client as `registrationRef`; non-JSKIT apps read the variable directly.
|
|
208
|
+
|
|
184
209
|
## Twitch composition
|
|
185
210
|
|
|
186
211
|
Use `twitchProvider` from `@jskit-ai/connectors-catalog/server/twitch` in the
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
"./shared": "./src/shared/index.js"
|
|
9
9
|
},
|
|
10
10
|
"dependencies": {
|
|
11
|
-
"@jskit-ai/crud-core": "0.1.
|
|
12
|
-
"@jskit-ai/resource-crud-core": "0.1.
|
|
11
|
+
"@jskit-ai/crud-core": "0.1.256",
|
|
12
|
+
"@jskit-ai/resource-crud-core": "0.1.187"
|
|
13
13
|
},
|
|
14
14
|
"jskit": {
|
|
15
15
|
"kind": "runtime",
|
|
@@ -38,6 +38,15 @@ placement registry, topology, and adaptive smoke helper exported by
|
|
|
38
38
|
- Cached route/resource state hydrates writable UI state synchronously or with
|
|
39
39
|
immediate watchers.
|
|
40
40
|
- Loading uses stable skeletons, not spinners or shifting status banners.
|
|
41
|
+
- `ShellErrorHost` stays directly inside `v-app`. Its banners float below a top
|
|
42
|
+
app bar; on a surface without one (such as sign-in) they join the page flow
|
|
43
|
+
above the content so they never cover it. A full-viewport fixed screen on
|
|
44
|
+
such a surface starts at `var(--shell-error-banners-inline-height, 0px)`, as
|
|
45
|
+
`@jskit-ai/auth-web`'s login and reset views do.
|
|
46
|
+
- Restyle shell chrome through its `--shell-chrome-*`, `--shell-app-bar-*`,
|
|
47
|
+
`--shell-navigation-*` and `--shell-bottom-navigation-*` custom properties,
|
|
48
|
+
not by overriding Vuetify internals; a Material 3 restyle removes the dividers
|
|
49
|
+
and separates surfaces tonally.
|
|
41
50
|
- The adaptive browser check closes navigation through its public close control.
|
|
42
51
|
|
|
43
52
|
## Example files
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
"./shared": "./src/shared/index.js"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@jskit-ai/crud-core": "0.1.
|
|
13
|
-
"@jskit-ai/resource-crud-core": "0.1.
|
|
12
|
+
"@jskit-ai/crud-core": "0.1.256",
|
|
13
|
+
"@jskit-ai/resource-crud-core": "0.1.187"
|
|
14
14
|
},
|
|
15
15
|
"jskit": {
|
|
16
16
|
"kind": "runtime",
|
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
"./shared": "./src/shared/index.js"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@jskit-ai/crud-core": "0.1.
|
|
13
|
-
"@jskit-ai/resource-crud-core": "0.1.
|
|
14
|
-
"@jskit-ai/workspaces-core": "0.1.
|
|
12
|
+
"@jskit-ai/crud-core": "0.1.256",
|
|
13
|
+
"@jskit-ai/resource-crud-core": "0.1.187",
|
|
14
|
+
"@jskit-ai/workspaces-core": "0.1.223"
|
|
15
15
|
},
|
|
16
16
|
"jskit": {
|
|
17
17
|
"kind": "runtime",
|
|
@@ -50,6 +50,17 @@ shared-screen controls; avoid duplicates, drawer-only access, or adding a page
|
|
|
50
50
|
heading just to house it. Keep its meaning and accessible name clear at every
|
|
51
51
|
supported width.
|
|
52
52
|
|
|
53
|
+
### Scroll position
|
|
54
|
+
|
|
55
|
+
`createShellRouter()` from `@jskit-ai/kernel/client` installs
|
|
56
|
+
`shellScrollBehavior` by default: a new screen opens at the top (or at its
|
|
57
|
+
hash target), Back/Forward restore the saved position, and query, hash, tab or
|
|
58
|
+
sub-view changes within the same page keep the current position. A tab or
|
|
59
|
+
sub-view counts as the same page when both locations share a parent page record
|
|
60
|
+
below the surface root. Pass `scrollBehavior` to `createShellRouter()` to
|
|
61
|
+
replace it with your own Vue Router function, or `scrollBehavior: false` to
|
|
62
|
+
disable it. Do not wrap the router or reset scroll in page components.
|
|
63
|
+
|
|
53
64
|
## Application-owned files
|
|
54
65
|
|
|
55
66
|
Pattern source is ordinary customizable application source. When replacing a
|
|
@@ -88,6 +99,19 @@ icon/label and label/end gaps. The normal 80px rail centres 48px targets;
|
|
|
88
99
|
`railWidth` and `drawerWidth` are public density/width controls. Do not override
|
|
89
100
|
the shell's private implementation CSS.
|
|
90
101
|
|
|
102
|
+
The app bar, drawer/rail and compact bottom navigation follow the Vuetify theme
|
|
103
|
+
and expose restyling tokens instead of hard-coded chrome: `--shell-chrome-border-width`
|
|
104
|
+
and `--shell-chrome-border-color` for the shared dividers,
|
|
105
|
+
`--shell-app-bar-border-width`, `--shell-navigation-border-width` and
|
|
106
|
+
`--shell-bottom-navigation-border-width` per edge, and
|
|
107
|
+
`--shell-app-bar-background`, `--shell-navigation-background` and
|
|
108
|
+
`--shell-bottom-navigation-background` for the surfaces. The defaults keep one
|
|
109
|
+
thin divider on each separating edge, because Vuetify's default themes define
|
|
110
|
+
no Material 3 surface-container roles to separate surfaces tonally. A Material 3
|
|
111
|
+
restyle sets the border widths to `0` and gives navigation a tonal surface, for
|
|
112
|
+
example `--shell-navigation-background: rgb(var(--v-theme-surface-container-low))`
|
|
113
|
+
when the theme defines that role.
|
|
114
|
+
|
|
91
115
|
## Browser verification
|
|
92
116
|
|
|
93
117
|
Exercise user-facing changes with Playwright at compact, medium, and expanded
|