@vibes.diy/prompts 2.4.4 → 2.4.6

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 (2) hide show
  1. package/llms/use-viewer.md +46 -23
  2. package/package.json +3 -3
@@ -10,12 +10,16 @@ The contract: **every write surface (form, submit button, edit input, delete but
10
10
  import { useViewer } from "use-vibes";
11
11
 
12
12
  function App() {
13
- const { viewer, can } = useViewer();
14
- if (!viewer) return <p>Sign in to use this app.</p>;
13
+ const { viewer, isViewerPending, can, ViewerTag } = useViewer();
14
+
15
+ // isViewerPending is true until the platform has resolved the viewer identity.
16
+ // Gate on it to avoid flashing the anonymous state on first render.
17
+ if (isViewerPending) return null;
18
+
15
19
  return (
16
20
  <header>
17
- <img src={viewer.avatarUrl} alt={viewer.userSlug} />
18
- <span>{viewer.displayName ?? viewer.userSlug}</span>
21
+ {/* ViewerTag renders a "Sign in" button when logged out, a user pill when logged in */}
22
+ <ViewerTag />
19
23
  </header>
20
24
  );
21
25
  }
@@ -24,16 +28,30 @@ function App() {
24
28
  ## What you get
25
29
 
26
30
  - `viewer` — `{ userSlug, displayName?, avatarUrl }` or `null` for anonymous visitors. `avatarUrl` is a stable opaque URL — just use it in `<img src>`, don't construct it yourself.
31
+ - `isViewerPending` — `true` while the platform is still resolving the viewer identity (e.g. on first render before the parent shell has pushed the identity update). **Gate any auth-dependent UI on `!isViewerPending`** to avoid flashing the wrong state. Once it becomes `false`, `viewer` is either populated or definitively `null`.
27
32
  - `can(action, dbName?)` — `true`/`false` for `"read"`, `"write"`, `"delete"`. Pass a `dbName` for multi-db apps; omit for single-db apps. Use it to hide forms when the viewer can't post.
33
+ - `ViewerTag` — ready-made user pill; see the ViewerTag section below.
28
34
 
29
35
  ## Gating UI
30
36
 
31
37
  ```jsx
32
38
  function CommentForm() {
33
- const { viewer, can } = useViewer();
34
- if (!viewer) return <p>Sign in to comment.</p>;
35
- if (!can("write", "comments")) return <p>Contact the owner to request write access so you can post.</p>;
36
- return <form>...</form>;
39
+ const { viewer, isViewerPending, can, ViewerTag } = useViewer();
40
+ if (isViewerPending) return null;
41
+
42
+ return (
43
+ <div>
44
+ {/* Always rendered: "Sign in" button when anonymous, identity pill when signed in.
45
+ The label only appears once viewer is known so it doesn't flash. */}
46
+ <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
47
+ {viewer && <span style={{ fontSize: 13, color: "var(--muted, #888)" }}>commenting as</span>}
48
+ <ViewerTag />
49
+ </div>
50
+
51
+ {viewer && !can("write", "comments") && <p>Contact the owner to request write access so you can post.</p>}
52
+ {viewer && can("write", "comments") && <form>...</form>}
53
+ </div>
54
+ );
37
55
  }
38
56
  ```
39
57
 
@@ -46,7 +64,7 @@ import { useFireproof } from "use-fireproof";
46
64
  import { useViewer } from "use-vibes";
47
65
 
48
66
  function CommentThread() {
49
- const { viewer, can } = useViewer();
67
+ const { viewer, isViewerPending, can, ViewerTag } = useViewer();
50
68
  const { useLiveQuery, database } = useFireproof("comments");
51
69
  const { docs: comments } = useLiveQuery("createdAt");
52
70
  const [body, setBody] = useState("");
@@ -77,20 +95,25 @@ function CommentThread() {
77
95
  ))}
78
96
  </ul>
79
97
 
80
- {!viewer ? (
81
- <p>Sign in to comment.</p>
82
- ) : !can("write", "comments") ? (
83
- <p>Contact the owner to request write access so you can post.</p>
84
- ) : (
85
- <form
86
- onSubmit={(e) => {
87
- e.preventDefault();
88
- post();
89
- }}
90
- >
91
- <input value={body} onChange={(e) => setBody(e.target.value)} />
92
- <button type="submit">Post</button>
93
- </form>
98
+ {!isViewerPending && (
99
+ <div>
100
+ <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
101
+ {viewer && <span style={{ fontSize: 13, color: "var(--muted, #888)" }}>commenting as</span>}
102
+ <ViewerTag />
103
+ </div>
104
+ {viewer && !can("write", "comments") && <p>Contact the owner to request write access so you can post.</p>}
105
+ {viewer && can("write", "comments") && (
106
+ <form
107
+ onSubmit={(e) => {
108
+ e.preventDefault();
109
+ post();
110
+ }}
111
+ >
112
+ <input value={body} onChange={(e) => setBody(e.target.value)} />
113
+ <button type="submit">Post</button>
114
+ </form>
115
+ )}
116
+ </div>
94
117
  )}
95
118
  </div>
96
119
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibes.diy/prompts",
3
- "version": "2.4.4",
3
+ "version": "2.4.6",
4
4
  "type": "module",
5
5
  "main": "./index.js",
6
6
  "description": "",
@@ -30,8 +30,8 @@
30
30
  "@fireproof/core-types-base": "~0.24.19",
31
31
  "@fireproof/core-types-protocols-cloud": "~0.24.19",
32
32
  "@fireproof/use-fireproof": "~0.24.19",
33
- "@vibes.diy/call-ai-v2": "^2.4.4",
34
- "@vibes.diy/use-vibes-types": "^2.4.4",
33
+ "@vibes.diy/call-ai-v2": "^2.4.6",
34
+ "@vibes.diy/use-vibes-types": "^2.4.6",
35
35
  "arktype": "~2.2.0",
36
36
  "json-schema-faker": "~0.6.1"
37
37
  },