@close-by/clay 0.2.16 → 0.2.17
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/docs/ops-patterns.md +31 -3
- package/docs/production.md +29 -4
- package/package.json +5 -5
package/docs/ops-patterns.md
CHANGED
|
@@ -220,6 +220,28 @@ Still redact before display when possible. Prefer VPN + auth for hubs that surfa
|
|
|
220
220
|
Nav filtering is UX only — always enforce roles in the page builder.
|
|
221
221
|
|
|
222
222
|
```ts
|
|
223
|
+
import { ui } from '@close-by/clay';
|
|
224
|
+
import { getCurrentSession } from '@close-by/clay-core';
|
|
225
|
+
import { resolveUserIdFromAuthCookie } from '@close-by/clay-server';
|
|
226
|
+
import { createAuthGuards } from '@close-by/clay-auth';
|
|
227
|
+
|
|
228
|
+
type User = { role: 'admin' | 'member' };
|
|
229
|
+
const userById = new Map<string, User>(); // Your app's user store, keyed by user ID.
|
|
230
|
+
const authSecret = process.env.CLAY_AUTH_SECRET!;
|
|
231
|
+
const anonymousUserId = '__clay_anonymous__';
|
|
232
|
+
const resolveSignedUserId = resolveUserIdFromAuthCookie(authSecret);
|
|
233
|
+
|
|
234
|
+
function getSessionUser(): User | null {
|
|
235
|
+
const userId = getCurrentSession()?.userId;
|
|
236
|
+
if (!userId || userId === anonymousUserId) return null;
|
|
237
|
+
return userById.get(userId) ?? null;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const { requireRole } = createAuthGuards({
|
|
241
|
+
getUser: getSessionUser,
|
|
242
|
+
onUnauthenticated: () => ui.navigate('/login'),
|
|
243
|
+
});
|
|
244
|
+
|
|
223
245
|
// pageMeta
|
|
224
246
|
export const pageMeta = {
|
|
225
247
|
label: 'Admin',
|
|
@@ -230,20 +252,26 @@ export const pageMeta = {
|
|
|
230
252
|
|
|
231
253
|
// shell
|
|
232
254
|
ui.run({
|
|
233
|
-
authSecret
|
|
255
|
+
authSecret,
|
|
256
|
+
resolveUserId: (context) => resolveSignedUserId(context) ?? anonymousUserId,
|
|
234
257
|
app: {
|
|
235
258
|
title: 'Hub',
|
|
236
|
-
nav
|
|
259
|
+
get nav() {
|
|
260
|
+
const user = getSessionUser();
|
|
261
|
+
return ui.navFromPages(user ? { role: user.role } : {});
|
|
262
|
+
},
|
|
237
263
|
},
|
|
238
264
|
});
|
|
239
265
|
|
|
240
266
|
// page
|
|
241
267
|
ui.page('/admin', () => {
|
|
242
|
-
requireRole('admin');
|
|
268
|
+
if (!requireRole('admin')) return;
|
|
243
269
|
// …
|
|
244
270
|
});
|
|
245
271
|
```
|
|
246
272
|
|
|
273
|
+
`get nav()` is evaluated while each page shell is built, so it filters routes for the current session. Reserve `__clay_anonymous__` outside `userById`: the resolver substitutes it for missing or invalid cookies, and `getSessionUser` treats it as signed out. Replace `userById` with your app's user store.
|
|
274
|
+
|
|
247
275
|
See `/examples/auth` and [API — auth](./api.md).
|
|
248
276
|
|
|
249
277
|
## `ui.ai.chat` and state
|
package/docs/production.md
CHANGED
|
@@ -18,22 +18,47 @@ Clay ships hooks for real identity beyond anonymous `userId`:
|
|
|
18
18
|
|
|
19
19
|
```ts
|
|
20
20
|
import { ui } from '@close-by/clay';
|
|
21
|
-
import {
|
|
21
|
+
import { getCurrentSession } from '@close-by/clay-core';
|
|
22
|
+
import { resolveUserIdFromAuthCookie } from '@close-by/clay-server';
|
|
23
|
+
import { createAuthGuards } from '@close-by/clay-auth';
|
|
24
|
+
|
|
25
|
+
type User = { role: 'admin' | 'member' };
|
|
26
|
+
const userById = new Map<string, User>(); // Your app's user store, keyed by user ID.
|
|
27
|
+
const authSecret = process.env.CLAY_AUTH_SECRET!;
|
|
28
|
+
const anonymousUserId = '__clay_anonymous__';
|
|
29
|
+
const resolveSignedUserId = resolveUserIdFromAuthCookie(authSecret);
|
|
30
|
+
|
|
31
|
+
function getSessionUser(): User | null {
|
|
32
|
+
const userId = getCurrentSession()?.userId;
|
|
33
|
+
if (!userId || userId === anonymousUserId) return null;
|
|
34
|
+
return userById.get(userId) ?? null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const { requireRole } = createAuthGuards({
|
|
38
|
+
getUser: getSessionUser,
|
|
39
|
+
onUnauthenticated: () => ui.navigate('/login'),
|
|
40
|
+
});
|
|
22
41
|
|
|
23
42
|
ui.run({
|
|
24
|
-
authSecret
|
|
43
|
+
authSecret,
|
|
44
|
+
resolveUserId: (context) => resolveSignedUserId(context) ?? anonymousUserId,
|
|
25
45
|
app: {
|
|
26
46
|
title: 'Hub',
|
|
27
|
-
nav
|
|
47
|
+
get nav() {
|
|
48
|
+
const user = getSessionUser();
|
|
49
|
+
return ui.navFromPages(user ? { role: user.role } : {});
|
|
50
|
+
},
|
|
28
51
|
},
|
|
29
52
|
});
|
|
30
53
|
|
|
31
54
|
ui.page('/admin', () => {
|
|
32
|
-
requireRole('admin');
|
|
55
|
+
if (!requireRole('admin')) return;
|
|
33
56
|
// …
|
|
34
57
|
});
|
|
35
58
|
```
|
|
36
59
|
|
|
60
|
+
`get nav()` is evaluated while each page shell is built, so it filters routes for the current session. Reserve `__clay_anonymous__` outside `userById`: the resolver substitutes it for missing or invalid cookies, and `getSessionUser` treats it as signed out. Replace `userById` with your app's user store.
|
|
61
|
+
|
|
37
62
|
- `pageMeta.roles` — hide nav items via `ui.navFromPages({ role })` (UX only)
|
|
38
63
|
- `requireRole` / guards in the page builder — **enforce** access before building sensitive UI
|
|
39
64
|
- See [API — auth](./api.md), `/examples/auth`, and [Ops patterns — auth nav](./ops-patterns.md#auth--role-filtered-nav)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@close-by/clay",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.17",
|
|
4
4
|
"description": "NiceGUI-like ui.* facade for Clay apps",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -37,10 +37,10 @@
|
|
|
37
37
|
"access": "public"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@close-by/clay-compiler": "0.2.
|
|
41
|
-
"@close-by/clay-core": "0.2.
|
|
42
|
-
"@close-by/clay-components": "0.2.
|
|
43
|
-
"@close-by/clay-server": "0.2.
|
|
40
|
+
"@close-by/clay-compiler": "0.2.17",
|
|
41
|
+
"@close-by/clay-core": "0.2.17",
|
|
42
|
+
"@close-by/clay-components": "0.2.17",
|
|
43
|
+
"@close-by/clay-server": "0.2.17",
|
|
44
44
|
"@tailwindcss/cli": "^4.3.3",
|
|
45
45
|
"tailwindcss": "^4.3.3"
|
|
46
46
|
}
|