@vibes.diy/prompts 2.5.12 → 2.5.13
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/llms/fireproof.md +45 -21
- package/llms/index.d.ts +2 -1
- package/llms/index.js +3 -0
- package/llms/index.js.map +1 -1
- package/llms/use-vibe.d.ts +2 -0
- package/llms/use-vibe.js +8 -0
- package/llms/use-vibe.js.map +1 -0
- package/llms/use-vibe.md +46 -0
- package/llms/use-viewer.md +104 -60
- package/package.json +4 -4
- package/prompts.js +8 -3
- package/prompts.js.map +1 -1
- package/system-prompt-initial.md +12 -11
- package/system-prompt.md +68 -33
package/llms/fireproof.md
CHANGED
|
@@ -333,12 +333,23 @@ Other `acl` variants: `useFireproof("drafts", { acl: { read: ["editors"], write:
|
|
|
333
333
|
|
|
334
334
|
## Reading Resolved Grants (`access`)
|
|
335
335
|
|
|
336
|
-
`useFireproof()` returns an `access` property — the viewer's resolved roles and channels for that database, computed server-side from the access function's `members` and `grant` declarations. Use `access.roles` (ReadonlySet), `access.channels` (ReadonlySet), `access.hasRole(name)`, and `access.hasChannel(name)`.
|
|
336
|
+
`useFireproof()` returns an `access` property — the viewer's resolved roles and channels for that database, computed server-side from the access function's `members` and `grant` declarations. Use `access.roles` (ReadonlySet), `access.channels` (ReadonlySet), `access.hasRole(name)`, and `access.hasChannel(name)`. Use these to reflect roles/channels in the UI; gate writes with `useVibe(dbName).can`.
|
|
337
337
|
|
|
338
338
|
For databases without an access function export, `access` has empty roles and channels. No separate pending flag — grants arrive alongside the viewer identity, so `useViewer().isViewerPending` covers both.
|
|
339
339
|
|
|
340
340
|
App.jsx
|
|
341
341
|
|
|
342
|
+
```jsx
|
|
343
|
+
<<<<<<< SEARCH
|
|
344
|
+
import { useFireproof } from "use-fireproof";
|
|
345
|
+
=======
|
|
346
|
+
import { useFireproof } from "use-fireproof";
|
|
347
|
+
import { useVibe } from "use-vibes";
|
|
348
|
+
>>>>>>> REPLACE
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
App.jsx
|
|
352
|
+
|
|
342
353
|
```jsx
|
|
343
354
|
<<<<<<< SEARCH
|
|
344
355
|
const { useLiveQuery, database } = useFireproof("announcements", {
|
|
@@ -346,6 +357,7 @@ App.jsx
|
|
|
346
357
|
});
|
|
347
358
|
=======
|
|
348
359
|
const { database, useLiveQuery, access } = useFireproof("comments");
|
|
360
|
+
const { can, me } = useVibe("comments");
|
|
349
361
|
>>>>>>> REPLACE
|
|
350
362
|
```
|
|
351
363
|
|
|
@@ -365,17 +377,18 @@ App.jsx
|
|
|
365
377
|
))}
|
|
366
378
|
</ul>
|
|
367
379
|
=======
|
|
368
|
-
{
|
|
369
|
-
{
|
|
380
|
+
{/* gate writes with useVibe().can, not access.* — and gate the SAME db you write to */}
|
|
381
|
+
{can.create({ type: "comment", authorHandle: me?.userHandle }).ok && <CommentForm database={database} />}
|
|
382
|
+
{access.hasRole("moderator") && <ModToolsBadge />}
|
|
370
383
|
{access.hasChannel("announcements") && <Announcements />}
|
|
371
384
|
>>>>>>> REPLACE
|
|
372
385
|
```
|
|
373
386
|
|
|
374
387
|
The AI agent writes the access function (so it knows the role names) and writes the UI (so it knows which roles gate which components). The `access` object is the bridge — it lets the UI reflect server-enforced permissions without duplicating the logic.
|
|
375
388
|
|
|
376
|
-
The access function is the single source of truth for permissions.
|
|
389
|
+
The access function is the single source of truth for permissions. Gate write surfaces with `useVibe(dbName).can`, which runs this same access function. The `access` object (`access.hasRole(name)`, `access.hasChannel(name)`) reflects the viewer's resolved roles/channels for DISPLAY — role badges, showing/hiding read-only sections — not as the write gate.
|
|
377
390
|
|
|
378
|
-
`access.hasChannel()` covers every grant path — public channels, restricted channels, role-expanded channels. The access function decides who gets access and how; the UI
|
|
391
|
+
`access.hasChannel()` covers every grant path — public channels, restricted channels, role-expanded channels. The access function decides who gets access and how; the UI uses `access.hasChannel(name)` to reflect membership for display.
|
|
379
392
|
|
|
380
393
|
### Complete example: Team announcements with channels
|
|
381
394
|
|
|
@@ -384,7 +397,7 @@ This example shows the full round-trip — access.js declares channels and grant
|
|
|
384
397
|
- **Owner bootstrap:** `user.isOwner` gates management operations (channel setup, role grants, moderation). No bootstrap problem — the owner can always manage without needing a role granted first.
|
|
385
398
|
- **Channel identity:** Channel docs use `_id: "ch:" + name` so names are unique. The `_id` is the channel identifier everywhere — in `channels`, `grant`, and `ctx.requireAccess()`.
|
|
386
399
|
- **Channel grant:** A channel document grants the creator (`grant.users`), adds `grant.public` so all members can read, and `grant.roles` so posters can write.
|
|
387
|
-
- **Write surfaces** are gated with `
|
|
400
|
+
- **Write surfaces** are gated with `useVibe(dbName).can.create/edit/delete` — it runs this same access function, so the UI verdict matches the server. Render `.reason` when denied. (See use-vibe docs.)
|
|
388
401
|
- **`ViewerTag`** takes `userHandle` when rendering another user.
|
|
389
402
|
|
|
390
403
|
access.js
|
|
@@ -420,20 +433,28 @@ export function announcements(doc, oldDoc, user, ctx) {
|
|
|
420
433
|
}
|
|
421
434
|
```
|
|
422
435
|
|
|
423
|
-
App.jsx — `
|
|
436
|
+
App.jsx — `useVibe().can` gates every write surface (posts AND owner-only management); `access.hasChannel()` reflects display-only membership; `isOwner` is a display hint only:
|
|
424
437
|
|
|
425
438
|
```jsx
|
|
426
439
|
import React from "react";
|
|
427
440
|
import { useFireproof } from "use-fireproof";
|
|
428
|
-
import { useViewer } from "use-vibes";
|
|
441
|
+
import { useViewer, useVibe } from "use-vibes";
|
|
429
442
|
|
|
430
443
|
export default function App() {
|
|
431
|
-
const { viewer,
|
|
444
|
+
const { viewer, isViewerPending, ViewerTag } = useViewer();
|
|
432
445
|
const { database, useLiveQuery, access } = useFireproof("announcements");
|
|
446
|
+
const { can } = useVibe("announcements");
|
|
433
447
|
|
|
434
448
|
const { docs: posts } = useLiveQuery("type", { key: "post" });
|
|
435
449
|
const [draft, setDraft] = React.useState("");
|
|
436
450
|
const [channel, setChannel] = React.useState("general");
|
|
451
|
+
// Build each candidate from the doc you'll actually write — the access function
|
|
452
|
+
// checks authorHandle/channel (and owner-only for roleGrant), so a bare partial
|
|
453
|
+
// would be denied and hide the control even from users who can act.
|
|
454
|
+
const canPost = can.create({ type: "post", channel, authorHandle: viewer?.userHandle });
|
|
455
|
+
// Owner-only management gates on can.* too — the access fn throws "owner only"
|
|
456
|
+
// for non-owners, so this verdict is false for everyone but the owner.
|
|
457
|
+
const canGrant = can.create({ type: "roleGrant", role: "poster", userHandle: "newUser" });
|
|
437
458
|
|
|
438
459
|
if (isViewerPending) return null;
|
|
439
460
|
|
|
@@ -453,8 +474,8 @@ export default function App() {
|
|
|
453
474
|
<div>
|
|
454
475
|
<ViewerTag />
|
|
455
476
|
|
|
456
|
-
{/*
|
|
457
|
-
{
|
|
477
|
+
{/* gate the write surface on useVibe().can — it runs the access function */}
|
|
478
|
+
{canPost.ok ? (
|
|
458
479
|
<form
|
|
459
480
|
onSubmit={(e) => {
|
|
460
481
|
e.preventDefault();
|
|
@@ -464,10 +485,12 @@ export default function App() {
|
|
|
464
485
|
<textarea value={draft} onChange={(e) => setDraft(e.target.value)} />
|
|
465
486
|
<button type="submit">Post</button>
|
|
466
487
|
</form>
|
|
488
|
+
) : (
|
|
489
|
+
viewer && <p style={{ color: "var(--muted, #888)" }}>{canPost.reason}</p>
|
|
467
490
|
)}
|
|
468
491
|
|
|
469
|
-
{/* owner-only management */}
|
|
470
|
-
{
|
|
492
|
+
{/* owner-only management — gated on can.*, not isOwner */}
|
|
493
|
+
{canGrant.ok && (
|
|
471
494
|
<button onClick={() => database.put({ type: "roleGrant", role: "poster", userHandle: "newUser" })}>
|
|
472
495
|
Grant poster role
|
|
473
496
|
</button>
|
|
@@ -477,7 +500,7 @@ export default function App() {
|
|
|
477
500
|
<div key={p._id}>
|
|
478
501
|
<ViewerTag userHandle={p.authorHandle} />
|
|
479
502
|
<p>{p.body}</p>
|
|
480
|
-
{
|
|
503
|
+
{can.delete(p).ok && <button onClick={() => database.del(p._id)}>Delete</button>}
|
|
481
504
|
</div>
|
|
482
505
|
))}
|
|
483
506
|
</div>
|
|
@@ -485,11 +508,11 @@ export default function App() {
|
|
|
485
508
|
}
|
|
486
509
|
```
|
|
487
510
|
|
|
488
|
-
The pattern: `
|
|
511
|
+
The pattern: `useVibe().can` gates every write surface — including owner-only management, which the access function enforces via `if (!user.isOwner) throw` so `can.create({ type: "roleGrant", … })` is false for non-owners. `access.hasChannel()` reflects display-only membership, and `isOwner` is a display hint only, never the write gate. The access function is the server-side authority — `useVibe().can` is how the UI reflects its decisions for writes.
|
|
489
512
|
|
|
490
513
|
### Example: Channel board with restricted channels
|
|
491
514
|
|
|
492
|
-
Some channels are open to all members, others are restricted. The access function decides — the UI
|
|
515
|
+
Some channels are open to all members, others are restricted. The access function decides — the UI uses `access.hasChannel()` to filter which channels to display, and `useVibe().can` to gate writes.
|
|
493
516
|
|
|
494
517
|
access.js
|
|
495
518
|
|
|
@@ -518,7 +541,7 @@ export function chat(doc, oldDoc, user, ctx) {
|
|
|
518
541
|
}
|
|
519
542
|
```
|
|
520
543
|
|
|
521
|
-
App.jsx —
|
|
544
|
+
App.jsx — `access.hasChannel()` filters which channels are visible (display); `useVibe().can` gates the write surface:
|
|
522
545
|
|
|
523
546
|
```jsx
|
|
524
547
|
<<<<<<< SEARCH
|
|
@@ -526,6 +549,7 @@ App.jsx — the UI uses `access.hasChannel()` for everything. It has no idea whi
|
|
|
526
549
|
=======
|
|
527
550
|
const { database, useLiveQuery, access } = useFireproof("chat");
|
|
528
551
|
const { docs: channels } = useLiveQuery("type", { key: "channel" });
|
|
552
|
+
const canPost = useVibe("chat").can.create({ type: "post" });
|
|
529
553
|
>>>>>>> REPLACE
|
|
530
554
|
```
|
|
531
555
|
|
|
@@ -533,13 +557,13 @@ App.jsx — the UI uses `access.hasChannel()` for everything. It has no idea whi
|
|
|
533
557
|
<<<<<<< SEARCH
|
|
534
558
|
{viewer && access.hasChannel(channel) && (
|
|
535
559
|
=======
|
|
536
|
-
{/* filter to channels the viewer can see — use _id as channel identifier */}
|
|
560
|
+
{/* filter to channels the viewer can see — use _id as channel identifier (display only) */}
|
|
537
561
|
{channels.filter((ch) => isOwner || access.hasChannel(ch._id)).map((ch) => (
|
|
538
562
|
<button key={ch._id} onClick={() => setChannel(ch._id)}>{ch.name}</button>
|
|
539
563
|
))}
|
|
540
564
|
|
|
541
|
-
{/*
|
|
542
|
-
{
|
|
565
|
+
{/* gate the write surface on useVibe().can */}
|
|
566
|
+
{canPost.ok ? (
|
|
543
567
|
>>>>>>> REPLACE
|
|
544
568
|
```
|
|
545
569
|
|
|
@@ -708,7 +732,7 @@ function crewChat(doc, oldDoc, user, ctx) {
|
|
|
708
732
|
ctx.requireAccess(doc.channelId);
|
|
709
733
|
return { channels: [doc.channelId] };
|
|
710
734
|
}
|
|
711
|
-
export { crewChat as "crew-chat" }
|
|
735
|
+
export { crewChat as "crew-chat" };
|
|
712
736
|
```
|
|
713
737
|
|
|
714
738
|
### Catch-all with `export default`
|
package/llms/index.d.ts
CHANGED
|
@@ -6,5 +6,6 @@ export { d3Config } from "./d3.js";
|
|
|
6
6
|
export { threeJsConfig } from "./three-js.js";
|
|
7
7
|
export { webxrConfig } from "./webxr.js";
|
|
8
8
|
export { useViewerConfig } from "./use-viewer.js";
|
|
9
|
+
export { useVibeConfig } from "./use-vibe.js";
|
|
9
10
|
export type { LlmConfig } from "./types.js";
|
|
10
|
-
export declare const allConfigs: readonly [import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig];
|
|
11
|
+
export declare const allConfigs: readonly [import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig];
|
package/llms/index.js
CHANGED
|
@@ -6,6 +6,7 @@ import { d3Config } from "./d3.js";
|
|
|
6
6
|
import { threeJsConfig } from "./three-js.js";
|
|
7
7
|
import { webxrConfig } from "./webxr.js";
|
|
8
8
|
import { useViewerConfig } from "./use-viewer.js";
|
|
9
|
+
import { useVibeConfig } from "./use-vibe.js";
|
|
9
10
|
export { callaiConfig } from "./callai.js";
|
|
10
11
|
export { fireproofConfig } from "./fireproof.js";
|
|
11
12
|
export { imageGenConfig } from "./image-gen.js";
|
|
@@ -14,6 +15,7 @@ export { d3Config } from "./d3.js";
|
|
|
14
15
|
export { threeJsConfig } from "./three-js.js";
|
|
15
16
|
export { webxrConfig } from "./webxr.js";
|
|
16
17
|
export { useViewerConfig } from "./use-viewer.js";
|
|
18
|
+
export { useVibeConfig } from "./use-vibe.js";
|
|
17
19
|
export const allConfigs = [
|
|
18
20
|
callaiConfig,
|
|
19
21
|
imageGenConfig,
|
|
@@ -23,5 +25,6 @@ export const allConfigs = [
|
|
|
23
25
|
fireproofConfig,
|
|
24
26
|
webxrConfig,
|
|
25
27
|
useViewerConfig,
|
|
28
|
+
useVibeConfig,
|
|
26
29
|
];
|
|
27
30
|
//# sourceMappingURL=index.js.map
|
package/llms/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../jsr/llms/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../jsr/llms/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAI9C,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,YAAY;IACZ,cAAc;IACd,cAAc;IACd,QAAQ;IACR,aAAa;IACb,eAAe;IACf,WAAW;IACX,eAAe;IACf,aAAa;CACL,CAAC"}
|
package/llms/use-vibe.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-vibe.js","sourceRoot":"","sources":["../../jsr/llms/use-vibe.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,aAAa,GAAc;IACtC,IAAI,EAAE,UAAU;IAChB,KAAK,EAAE,mBAAmB;IAC1B,WAAW,EAAE,kEAAkE;IAC/E,YAAY,EAAE,WAAW;IACzB,UAAU,EAAE,SAAS;CACtB,CAAC"}
|
package/llms/use-vibe.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# useVibe Hook — write gating
|
|
2
|
+
|
|
3
|
+
`useVibe(dbName)` is how you gate write surfaces. It runs the app's own `access.js` — the **same function the server enforces** — against a candidate document, so the UI's enabled/disabled state matches what the server will actually allow. You never re-implement permissions; you ask the access function.
|
|
4
|
+
|
|
5
|
+
```jsx
|
|
6
|
+
const { me, can, ready } = useVibe("comments");
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Pass the Fireproof database name you are writing to. You get:
|
|
10
|
+
|
|
11
|
+
- `can.create(draft)` / `can.edit(doc)` / `can.delete(doc)` → `{ ok: boolean, reason?: string }`. Gate the write surface on `.ok`; when `!ok`, render `.reason` as the fallback copy (e.g. "authentication required", "not in channel: team").
|
|
12
|
+
- `ready` — `false` until identity and the access function have resolved. While `false`, show a neutral skeleton or disabled control; gating on it avoids a flash of the wrong state.
|
|
13
|
+
- `me` — `{ userHandle, displayName?, isOwner } | null` (null = anonymous). For display only.
|
|
14
|
+
|
|
15
|
+
**Build the candidate from the doc you'll actually write.** `can.create(draft)` runs the access function against `draft`, so `draft` must carry the fields the function checks — `authorHandle`, `channelId`, etc. A bare `can.create({ type: "post" })` gets denied (e.g. `"not author"`) and hides the form even from users who could post. Stamp the same fields you'll `put`: `can.create({ type: "post", channelId, authorHandle: me?.userHandle })`. And gate the **same database** you write to — `useVibe(dbName)` selects the access function and grants by `dbName`, so a gate on a different db won't reflect server enforcement.
|
|
16
|
+
|
|
17
|
+
## The rule
|
|
18
|
+
|
|
19
|
+
Gate every write affordance on `can.*`. Render `reason` when denied. Never branch write permission on `viewer`, `isOwner`, `access.hasRole()`/`access.hasChannel()`, or document fields — those drift from what `access.js` actually does. Identity display (avatars, "signed in as") comes from `useViewer()`'s `ViewerTag`, not from `useVibe`.
|
|
20
|
+
|
|
21
|
+
```jsx
|
|
22
|
+
import { useVibe, useViewer } from "use-vibes";
|
|
23
|
+
|
|
24
|
+
function PromptBar({ database }) {
|
|
25
|
+
const { can, ready } = useVibe("aestheticBoard");
|
|
26
|
+
const { ViewerTag } = useViewer();
|
|
27
|
+
if (!ready) return <div className="skeleton" />;
|
|
28
|
+
const v = can.create({ type: "tile" });
|
|
29
|
+
if (!v.ok) return <p className="muted">{v.reason}</p>; // e.g. "authentication required"
|
|
30
|
+
return (
|
|
31
|
+
<form onSubmit={/* … */}>
|
|
32
|
+
<ViewerTag />
|
|
33
|
+
<input placeholder="Add a tile…" />
|
|
34
|
+
<button type="submit">Post</button>
|
|
35
|
+
</form>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Owner-only and role-gated surfaces
|
|
41
|
+
|
|
42
|
+
Don't gate management UI on `isOwner` directly. Encode the rule in `access.js` (e.g. `if (!user.isOwner) throw { forbidden: "owner only" }`) and gate the UI on `can.*` for that database — the verdict reflects the same rule. Per-row edit/delete affordances: `{can.edit(doc).ok && <EditButton doc={doc} />}`.
|
|
43
|
+
|
|
44
|
+
## The server is still the authority
|
|
45
|
+
|
|
46
|
+
`can.*` is a fast, faithful preview, not the final word. A write can still be rejected server-side (the source may be stale, async, or unevaluable — in which case `can.*` optimistically returns `ok` and defers to the server). Keep the optimistic-write + rollback pattern: apply the change immediately, revert and surface an error if the `put` rejects.
|
package/llms/use-viewer.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# useViewer Hook
|
|
2
2
|
|
|
3
|
-
`useViewer()` is a **read-only window** into
|
|
3
|
+
`useViewer()` is a **read-only window** into viewer identity. The platform owns the rules — who's the owner, who has been granted read or write — and `useViewer()` lets your app see who's signed in and render their identity. You cannot grant or revoke access from code; you can only reflect the runtime's verdict in your UI.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Use `useViewer()` for identity and display only — `ViewerTag`, avatars, and showing who's signed in. **Write surfaces are gated with `useVibe(dbName).can`** (see use-vibe docs), not with `viewer`/`isOwner`/`access.*`.
|
|
6
6
|
|
|
7
7
|
## Basic Usage
|
|
8
8
|
|
|
@@ -25,7 +25,7 @@ export default function App() {
|
|
|
25
25
|
<header>
|
|
26
26
|
<ViewerTag />
|
|
27
27
|
</header>
|
|
28
|
-
{!viewer && <p>Sign in
|
|
28
|
+
{!viewer && <p>Sign in.</p>}
|
|
29
29
|
{viewer && <p>Welcome back!</p>}
|
|
30
30
|
</div>
|
|
31
31
|
);
|
|
@@ -36,31 +36,60 @@ export default function App() {
|
|
|
36
36
|
|
|
37
37
|
- `viewer` — `{ userHandle, displayName? }` or `null` for anonymous visitors. Avatars are not on the payload — render them with `<ViewerTag userHandle={...} />`, which resolves the avatar from the handle. Don't build avatar URLs yourself.
|
|
38
38
|
- `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`.
|
|
39
|
-
- `isOwner` — `true` when the viewer owns this vibe.
|
|
40
|
-
- `can(action, dbName?)` —
|
|
39
|
+
- `isOwner` — `true` when the viewer owns this vibe. A display hint only (e.g. an "admin" badge). Gate owner-only management WRITES (settings, role grants, moderation) on `useVibe(dbName).can` — the access function encodes the owner-only rule — never on `isOwner`.
|
|
40
|
+
- `can(action, dbName?)` — legacy ACL boolean for `"read"`/`"write"`/`"delete"`. Prefer `useVibe(dbName).can.create/edit/delete` for write gating; it runs the app's access function and returns a `reason`.
|
|
41
41
|
- `ViewerTag` — ready-made user pill; see the ViewerTag section below.
|
|
42
42
|
|
|
43
43
|
## Gating UI
|
|
44
44
|
|
|
45
|
-
Add a "commenting as" label and a gated form.
|
|
45
|
+
Add a "commenting as" label and a write-gated form. Use `useVibe("comments").can` to gate the form; `ViewerTag` handles sign-in/identity display:
|
|
46
46
|
|
|
47
47
|
App.jsx
|
|
48
48
|
|
|
49
49
|
```jsx
|
|
50
50
|
<<<<<<< SEARCH
|
|
51
|
-
|
|
51
|
+
import { useViewer } from "use-vibes";
|
|
52
|
+
=======
|
|
53
|
+
import { useViewer, useVibe } from "use-vibes";
|
|
54
|
+
>>>>>>> REPLACE
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
App.jsx
|
|
58
|
+
|
|
59
|
+
```jsx
|
|
60
|
+
<<<<<<< SEARCH
|
|
61
|
+
const { viewer, isViewerPending, ViewerTag } = useViewer();
|
|
62
|
+
=======
|
|
63
|
+
const { viewer, isViewerPending, ViewerTag } = useViewer();
|
|
64
|
+
const { can, ready, me } = useVibe("comments");
|
|
65
|
+
>>>>>>> REPLACE
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
App.jsx
|
|
69
|
+
|
|
70
|
+
```jsx
|
|
71
|
+
<<<<<<< SEARCH
|
|
72
|
+
{!viewer && <p>Sign in.</p>}
|
|
52
73
|
{viewer && <p>Welcome back!</p>}
|
|
53
74
|
=======
|
|
75
|
+
{/* identity display */}
|
|
54
76
|
<div style={{ display: "flex", alignItems: "center", gap: 8 }}>
|
|
55
77
|
{viewer && <span style={{ fontSize: 13, color: "var(--muted, #888)" }}>commenting as</span>}
|
|
56
78
|
<ViewerTag />
|
|
57
79
|
</div>
|
|
58
80
|
|
|
59
|
-
{
|
|
60
|
-
{
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
81
|
+
{/* write gate: useVibe().can, not viewer */}
|
|
82
|
+
{!ready ? null : (() => {
|
|
83
|
+
const v = can.create({ type: "comment", authorHandle: me?.userHandle });
|
|
84
|
+
return v.ok ? (
|
|
85
|
+
<form>
|
|
86
|
+
<input placeholder="Add a comment..." />
|
|
87
|
+
<button type="submit">Post</button>
|
|
88
|
+
</form>
|
|
89
|
+
) : (
|
|
90
|
+
<p>{v.reason}</p>
|
|
91
|
+
);
|
|
92
|
+
})()}
|
|
64
93
|
>>>>>>> REPLACE
|
|
65
94
|
```
|
|
66
95
|
|
|
@@ -74,50 +103,41 @@ App.jsx
|
|
|
74
103
|
|
|
75
104
|
```jsx
|
|
76
105
|
<<<<<<< SEARCH
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
<div>
|
|
84
|
-
<header>
|
|
85
|
-
<ViewerTag />
|
|
86
|
-
</header>
|
|
87
|
-
<div style={{ display: "flex", alignItems: "center", gap: 8 }}>
|
|
88
|
-
{viewer && <span style={{ fontSize: 13, color: "var(--muted, #888)" }}>commenting as</span>}
|
|
89
|
-
<ViewerTag />
|
|
90
|
-
</div>
|
|
106
|
+
import { useViewer, useVibe } from "use-vibes";
|
|
107
|
+
=======
|
|
108
|
+
import { useViewer, useVibe } from "use-vibes";
|
|
109
|
+
import { useFireproof } from "use-fireproof";
|
|
110
|
+
>>>>>>> REPLACE
|
|
111
|
+
```
|
|
91
112
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
</form>}
|
|
97
|
-
</div>
|
|
98
|
-
);
|
|
99
|
-
}
|
|
113
|
+
```jsx
|
|
114
|
+
<<<<<<< SEARCH
|
|
115
|
+
const { viewer, isViewerPending, ViewerTag } = useViewer();
|
|
116
|
+
const { can, ready, me } = useVibe("comments");
|
|
100
117
|
=======
|
|
101
|
-
export default function App() {
|
|
102
118
|
const { viewer, isViewerPending, ViewerTag } = useViewer();
|
|
119
|
+
const { can, ready, me } = useVibe("comments");
|
|
103
120
|
const { useLiveQuery, database } = useFireproof("comments");
|
|
104
121
|
const { docs: comments } = useLiveQuery("createdAt");
|
|
105
122
|
const [body, setBody] = React.useState("");
|
|
123
|
+
>>>>>>> REPLACE
|
|
124
|
+
```
|
|
106
125
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
126
|
+
```jsx
|
|
127
|
+
<<<<<<< SEARCH
|
|
128
|
+
{/* write gate: useVibe().can, not viewer */}
|
|
129
|
+
{!ready ? null : (() => {
|
|
130
|
+
const v = can.create({ type: "comment", authorHandle: me?.userHandle });
|
|
131
|
+
return v.ok ? (
|
|
132
|
+
<form>
|
|
133
|
+
<input placeholder="Add a comment..." />
|
|
134
|
+
<button type="submit">Post</button>
|
|
135
|
+
</form>
|
|
136
|
+
) : (
|
|
137
|
+
<p>{v.reason}</p>
|
|
138
|
+
);
|
|
139
|
+
})()}
|
|
140
|
+
=======
|
|
121
141
|
<ul>
|
|
122
142
|
{comments.map((c) => (
|
|
123
143
|
<li key={c._id}>
|
|
@@ -127,20 +147,44 @@ export default function App() {
|
|
|
127
147
|
))}
|
|
128
148
|
</ul>
|
|
129
149
|
|
|
150
|
+
{/* identity display */}
|
|
130
151
|
<div style={{ display: "flex", alignItems: "center", gap: 8 }}>
|
|
131
152
|
{viewer && <span style={{ fontSize: 13, color: "var(--muted, #888)" }}>commenting as</span>}
|
|
132
153
|
<ViewerTag />
|
|
133
154
|
</div>
|
|
134
|
-
|
|
135
|
-
{
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
155
|
+
|
|
156
|
+
{/* write gate: useVibe().can, not viewer */}
|
|
157
|
+
{!ready ? null : (() => {
|
|
158
|
+
const v = can.create({ type: "comment", authorHandle: me?.userHandle });
|
|
159
|
+
return v.ok ? (
|
|
160
|
+
<form onSubmit={(e) => { e.preventDefault(); post(); }}>
|
|
161
|
+
<input value={body} onChange={(e) => setBody(e.target.value)} placeholder="Add a comment..." />
|
|
162
|
+
<button type="submit">Post</button>
|
|
163
|
+
</form>
|
|
164
|
+
) : (
|
|
165
|
+
<p>{v.reason}</p>
|
|
166
|
+
);
|
|
167
|
+
})()}
|
|
168
|
+
>>>>>>> REPLACE
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Also add the `post` handler before `if (isViewerPending)`:
|
|
172
|
+
|
|
173
|
+
```jsx
|
|
174
|
+
<<<<<<< SEARCH
|
|
175
|
+
if (isViewerPending) return null;
|
|
176
|
+
=======
|
|
177
|
+
async function post() {
|
|
178
|
+
if (!body.trim()) return;
|
|
179
|
+
await database.put({
|
|
180
|
+
body: body.trim(),
|
|
181
|
+
createdAt: Date.now(),
|
|
182
|
+
authorHandle: me?.userHandle,
|
|
183
|
+
});
|
|
184
|
+
setBody("");
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (isViewerPending) return null;
|
|
144
188
|
>>>>>>> REPLACE
|
|
145
189
|
```
|
|
146
190
|
|
|
@@ -154,7 +198,7 @@ Key points:
|
|
|
154
198
|
|
|
155
199
|
- Never use Clerk user IDs. Only `userHandle` crosses into vibe code.
|
|
156
200
|
- Avatar URLs are stable indirection URLs — when a user changes their avatar, the URL stays the same and the bytes update. Treat them as opaque strings.
|
|
157
|
-
-
|
|
201
|
+
- To reflect a viewer's roles/channels for display, use `access` from `useFireproof()`: `access.hasRole("moderator")`, `access.hasChannel("engineering")`. To gate a write surface, use `useVibe(dbName).can` (it runs the same access.js). The access function is the server-side authority either way.
|
|
158
202
|
|
|
159
203
|
## ViewerTag
|
|
160
204
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibes.diy/prompts",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.13",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./index.js",
|
|
6
6
|
"description": "",
|
|
@@ -30,9 +30,9 @@
|
|
|
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.5.
|
|
34
|
-
"@vibes.diy/identity": "^2.5.
|
|
35
|
-
"@vibes.diy/use-vibes-types": "^2.5.
|
|
33
|
+
"@vibes.diy/call-ai-v2": "^2.5.13",
|
|
34
|
+
"@vibes.diy/identity": "^2.5.13",
|
|
35
|
+
"@vibes.diy/use-vibes-types": "^2.5.13",
|
|
36
36
|
"arktype": "~2.2.1",
|
|
37
37
|
"json-schema-faker": "~0.6.2"
|
|
38
38
|
},
|
package/prompts.js
CHANGED
|
@@ -24,9 +24,9 @@ export async function resolveEffectiveModel(settingsDoc, vibeDoc) {
|
|
|
24
24
|
return defaultCodingModel();
|
|
25
25
|
}
|
|
26
26
|
export async function getDefaultSkills() {
|
|
27
|
-
return ["fireproof", "callai", "image-gen", "web-audio"];
|
|
27
|
+
return ["fireproof", "callai", "image-gen", "web-audio", "use-vibe"];
|
|
28
28
|
}
|
|
29
|
-
const PRE_ALLOC_PLATFORM_PARAGRAPH = "Platform stack: a vibe is a single-file React app that runs in the user's browser. Fireproof is a cloud-backed document database — `useFireproof(name)` returns a database handle and `useLiveQuery(field)` keeps every viewer's UI in lockstep with the underlying docs in real time; writes are validated and persisted server-side and can fail, so handle write rejections. callAI is a typed call to a hosted LLM that returns JSON matching a schema the app declares; the JSON is saved as a Fireproof doc so it persists and shows up live for every viewer. useViewer
|
|
29
|
+
const PRE_ALLOC_PLATFORM_PARAGRAPH = "Platform stack: a vibe is a single-file React app that runs in the user's browser. Fireproof is a cloud-backed document database — `useFireproof(name)` returns a database handle and `useLiveQuery(field)` keeps every viewer's UI in lockstep with the underlying docs in real time; writes are validated and persisted server-side and can fail, so handle write rejections. callAI is a typed call to a hosted LLM that returns JSON matching a schema the app declares; the JSON is saved as a Fireproof doc so it persists and shows up live for every viewer. useViewer surfaces the signed-in viewer's identity for display (avatars, who's posting). Write surfaces are gated with `useVibe(dbName).can`, which runs the app's own access function and tells the UI whether a create/edit/delete is allowed — the app reflects that verdict, it never sets it. ImgGen renders a generated illustration tile when imagery is naturally part of the experience, not as decoration.";
|
|
30
30
|
export async function makePreAllocUserMessage(userPrompt) {
|
|
31
31
|
const catalog = await getLlmCatalog();
|
|
32
32
|
const catalogText = catalog.map((l) => `- ${l.name}: ${l.description}`).join("\n");
|
|
@@ -82,7 +82,7 @@ export const preAllocSchema = {
|
|
|
82
82
|
"REQUIRED. A 3-sentence preamble grounding THIS app in our platform — dense narrative, no padding, no flourishes.",
|
|
83
83
|
"Sentence 1: what users see and do in this app, and that Fireproof's live sync shares the activity with every viewer in real time.",
|
|
84
84
|
"Sentence 2: name the callAI role that fits this app's central activity. Common roles to pick from: (a) AI-suggest / autofill for form fields — the user taps a button next to an input and callAI returns an example value drawn from the app's domain, ready to accept or edit; (b) critique or extend user-authored content — callAI scores, rewrites, summarizes, or proposes the next thing (next line of a poem, follow-up task, related recipe); (c) categorize, tag, or score content on save — sentiment, topical tags, priority. Pick ONE role that genuinely fits this app. Name the user action that triggers the call and what kind of structured response comes back.",
|
|
85
|
-
"Sentence 3: name the write actions in this app, and that non-owners see a read-only view because the runtime's access control hides the write surfaces —
|
|
85
|
+
"Sentence 3: name the write actions in this app, and that non-owners see a read-only view because the runtime's access control hides the write surfaces — useVibe().can reflects that verdict (and useViewer shows identity), the app never sets it. If generated imagery is naturally part of the app's domain, add a brief clause naming what an ImgGen tile depicts.",
|
|
86
86
|
'Do NOT include code: no function names like `useLiveQuery` or `database.put`, no doc-shape objects in braces, no `can("write")` syntax, no backtick-quoted field names. Plain narrative, not a code spec.',
|
|
87
87
|
"Do NOT invent imagery features when the app's domain wouldn't naturally include them.",
|
|
88
88
|
].join(" "),
|
|
@@ -138,6 +138,11 @@ export async function makeBaseSystemPrompt(model, sessionDoc) {
|
|
|
138
138
|
if (selectedNames.length === 0) {
|
|
139
139
|
selectedNames = [...(await getDefaultSkills())];
|
|
140
140
|
}
|
|
141
|
+
for (const required of ["use-vibe", "use-viewer"]) {
|
|
142
|
+
if (llmsCatalogNames.has(required) && !selectedNames.includes(required)) {
|
|
143
|
+
selectedNames.push(required);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
141
146
|
const includeDemoData = sessionDoc?.demoData === true;
|
|
142
147
|
const chosenLlms = llmsCatalog.filter((l) => selectedNames.includes(l.name));
|
|
143
148
|
const concatenatedLlmsTxts = [];
|
package/prompts.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompts.js","sourceRoot":"","sources":["../jsr/prompts.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"prompts.js","sourceRoot":"","sources":["../jsr/prompts.ts"],"names":[],"mappings":"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"}
|
package/system-prompt-initial.md
CHANGED
|
@@ -17,7 +17,7 @@ You are an AI assistant tasked with creating React components. You should create
|
|
|
17
17
|
- Always show loading states during any async operation (callAI, fetch, database queries): use a useState boolean (e.g. `isLoading`), set it true before the call and false in .finally(). While loading: (1) disable the trigger button with `disabled={isLoading}`, (2) replace the button text with a spinning SVG icon using CSS animation `animate-spin` (a simple circle with a gap), (3) optionally show a short status text like 'Loading...' near the button. Never leave the user clicking a button with no visual feedback. Pattern: `setIsLoading(true); try { await callAI(...); } finally { setIsLoading(false); }`
|
|
18
18
|
- Give instant feedback for Fireproof writes too, not just for callAI/fetch. A `database.put` (toggling a checkbox, marking done, inline edits, reorder, like/vote counters) resolves fast but isn't instant, so the UI must react the moment the user acts. Apply the change optimistically — flip the visible value immediately and let `useLiveQuery` reconcile when the write lands. While the write is in flight, show ONE subtle per-item saving cue on that row: disable it, dim it slightly, and add a small inline `Saving…` spinner or text. Do NOT change the value's own glyph to signal saving — no indeterminate/half-checked checkbox, since that reads as a real tri-state value rather than a transient network state. Track pending state in a keyed collection (e.g. a `Set` of saving ids in `useState` — add the id before the write, delete it in `.finally()`), not a single `savingId` or one global flag, so concurrent writes to different rows each keep their own cue and unrelated rows stay interactive. On failure, revert the optimistic value and surface a brief error (inline or toast) with a way to retry — never let the optimistic UI silently lie when a `put` rejects. Never let a checkbox tap, toggle, or saved inline edit sit with no visible response.
|
|
19
19
|
- For file uploads use drag and drop and store using the `doc._files` API; for AI image generation use `<ImgGen prompt="..." />`
|
|
20
|
-
- Access control is decided by the runtime, not
|
|
20
|
+
- Access control is decided by the runtime, not your code. Gate every write surface — forms, submit/edit/delete buttons, any mutating action — on `useVibe(dbName).can`. `const { me, can, ready } = useVibe("comments")` from `"use-vibes"`, passing the Fireproof database name you write to. Show the editor when `can.create(draft).ok` (or `can.edit(doc)` / `can.delete(doc)`); while `ready` is false show a neutral skeleton/disabled state; when denied, render `can.create(draft).reason` as the fallback copy (the sign-in or join prompt). `can.*` runs the app's own `access.js` — the same function the server enforces — so NEVER derive write permission from `viewer`, `isOwner`, `access.hasRole()`/`access.hasChannel()`, or document fields. `useViewer()` is identity/display only: `const { ViewerTag } = useViewer()` for avatars and showing who's signed in. Owner-only management UI is gated on `can.*` too (the access.js encodes the owner rule). This applies to every app — the runtime decides sharing, not the prompt. Writes can still be rejected server-side even when `can.*` allows, so keep the optimistic-write + rollback handling. See use-vibe docs.
|
|
21
21
|
- Don't try to generate png or base64 data, use placeholder image APIs instead, like https://picsum.photos/400 where 400 is the square size
|
|
22
22
|
- Never use emojis in the UI. Use inline SVG icons instead — simple, single-color, stroke-based SVGs (24x24 viewBox, strokeWidth 2, strokeLinecap round, strokeLinejoin round). Build icons directly in JSX, do not import icon libraries.
|
|
23
23
|
- List data items on the main page of your app so users don't have to hunt for them
|
|
@@ -41,35 +41,36 @@ Every code block must be preceded by the file name on its own line — `App.jsx`
|
|
|
41
41
|
- The `<header>` with the real brand title and any always-visible chrome.
|
|
42
42
|
- One stub function component per feature with a heading — these are the anchors for later edits.
|
|
43
43
|
- A default-exported `App` function composing them inside `<main id="app">` with `<header id="app-header">`.
|
|
44
|
-
- `
|
|
44
|
+
- When a write surface needs gating, destructure `useVibe` for the database it writes to — `const { can, ready } = useVibe("<dbName>");` — and `useViewer` for identity — `const { ViewerTag } = useViewer();`
|
|
45
45
|
- **Be creative with the layout, but respect mobile idioms.** Thumb-reachable primary actions, generous tap targets (`min-h-[44px]`), scrollable lists, no hover-only interactions.
|
|
46
|
-
- NO hooks beyond `useViewer`, NO data wiring — those land in the feature edits.
|
|
46
|
+
- NO hooks beyond `useVibe`/`useViewer`, NO data wiring — those land in the feature edits.
|
|
47
47
|
|
|
48
48
|
Target ~40–60 lines. The shell should look like a real app with empty sections, not a blank page.
|
|
49
49
|
|
|
50
|
-
**Step 2 — Access function (if needed).** Emit `access.js` as a complete fenced block with comments explaining the permission model: what each doc type does, who can write it, what channels/roles it creates. This commits to the permission design before any feature edits, so every subsequent edit can
|
|
50
|
+
**Step 2 — Access function (if needed).** Emit `access.js` as a complete fenced block with comments explaining the permission model: what each doc type does, who can write it, what channels/roles it creates. This commits to the permission design before any feature edits, so every subsequent edit can gate its write surfaces on `useVibe(dbName).can` — the same rules the access function enforces.
|
|
51
51
|
|
|
52
52
|
**Step 3 — Feature edits.** Wire each feature with SEARCH/REPLACE edits. Each edit gets exactly one prose line (≤25 words) before it. Wire hooks, data, handlers, and `useFireproof` with `access` in these edits. The first feature edit should also add the `useFireproof` destructure to `App()`. Keep edits focused — one feature per edit, fully working after it lands.
|
|
53
53
|
|
|
54
54
|
> Access function — owner manages channels, authenticated users post to channels they have access to.
|
|
55
55
|
>
|
|
56
56
|
> access.js
|
|
57
|
+
>
|
|
57
58
|
> ```js
|
|
58
59
|
> // Each channel doc grants public read access to that channel.
|
|
59
60
|
> // Posts require channel access — the server enforces this via ctx.requireAccess.
|
|
60
61
|
> // Only the owner can create channels.
|
|
61
62
|
> export function chat(doc, oldDoc, user, ctx) {
|
|
62
|
-
> if (!user) throw { forbidden: "sign in" }
|
|
63
|
+
> if (!user) throw { forbidden: "sign in" };
|
|
63
64
|
> if (doc.type === "channel") {
|
|
64
|
-
> if (!user.isOwner) throw { forbidden: "owner only" }
|
|
65
|
-
> return { channels: [doc.name], grant: { public: [doc.name] } }
|
|
65
|
+
> if (!user.isOwner) throw { forbidden: "owner only" };
|
|
66
|
+
> return { channels: [doc.name], grant: { public: [doc.name] } };
|
|
66
67
|
> }
|
|
67
68
|
> if (doc.type === "message") {
|
|
68
|
-
> if (doc.authorHandle !== user.userHandle) throw { forbidden: "not author" }
|
|
69
|
-
> ctx.requireAccess(doc.channelId)
|
|
70
|
-
> return { channels: [doc.channelId] }
|
|
69
|
+
> if (doc.authorHandle !== user.userHandle) throw { forbidden: "not author" };
|
|
70
|
+
> ctx.requireAccess(doc.channelId);
|
|
71
|
+
> return { channels: [doc.channelId] };
|
|
71
72
|
> }
|
|
72
|
-
> throw { forbidden: "unknown document type" }
|
|
73
|
+
> throw { forbidden: "unknown document type" };
|
|
73
74
|
> }
|
|
74
75
|
> ```
|
|
75
76
|
|
package/system-prompt.md
CHANGED
|
@@ -17,7 +17,7 @@ You are an AI assistant tasked with creating React components. You should create
|
|
|
17
17
|
- Always show loading states during any async operation (callAI, fetch, database queries): use a useState boolean (e.g. `isLoading`), set it true before the call and false in .finally(). While loading: (1) disable the trigger button with `disabled={isLoading}`, (2) replace the button text with a spinning SVG icon using CSS animation `animate-spin` (a simple circle with a gap), (3) optionally show a short status text like 'Loading...' near the button. Never leave the user clicking a button with no visual feedback. Pattern: `setIsLoading(true); try { await callAI(...); } finally { setIsLoading(false); }`
|
|
18
18
|
- Give instant feedback for Fireproof writes too, not just for callAI/fetch. A `database.put` (toggling a checkbox, marking done, inline edits, reorder, like/vote counters) resolves fast but isn't instant, so the UI must react the moment the user acts. Apply the change optimistically — flip the visible value immediately and let `useLiveQuery` reconcile when the write lands. While the write is in flight, show ONE subtle per-item saving cue on that row: disable it, dim it slightly, and add a small inline `Saving…` spinner or text. Do NOT change the value's own glyph to signal saving — no indeterminate/half-checked checkbox, since that reads as a real tri-state value rather than a transient network state. Track pending state in a keyed collection (e.g. a `Set` of saving ids in `useState` — add the id before the write, delete it in `.finally()`), not a single `savingId` or one global flag, so concurrent writes to different rows each keep their own cue and unrelated rows stay interactive. On failure, revert the optimistic value and surface a brief error (inline or toast) with a way to retry — never let the optimistic UI silently lie when a `put` rejects. Never let a checkbox tap, toggle, or saved inline edit sit with no visible response.
|
|
19
19
|
- For file uploads use drag and drop and store using the `doc._files` API; for AI image generation use `<ImgGen prompt="..." />`
|
|
20
|
-
- Access control is decided by the runtime, not
|
|
20
|
+
- Access control is decided by the runtime, not your code. Gate every write surface — forms, submit/edit/delete buttons, any mutating action — on `useVibe(dbName).can`. `const { me, can, ready } = useVibe("comments")` from `"use-vibes"`, passing the Fireproof database name you write to. Show the editor when `can.create(draft).ok` (or `can.edit(doc)` / `can.delete(doc)`); while `ready` is false show a neutral skeleton/disabled state; when denied, render `can.create(draft).reason` as the fallback copy (the sign-in or join prompt). `can.*` runs the app's own `access.js` — the same function the server enforces — so NEVER derive write permission from `viewer`, `isOwner`, `access.hasRole()`/`access.hasChannel()`, or document fields. `useViewer()` is identity/display only: `const { ViewerTag } = useViewer()` for avatars and showing who's signed in. Owner-only management UI is gated on `can.*` too (the access.js encodes the owner rule). This applies to every app — the runtime decides sharing, not the prompt. Writes can still be rejected server-side even when `can.*` allows, so keep the optimistic-write + rollback handling. See use-vibe docs.
|
|
21
21
|
- Don't try to generate png or base64 data, use placeholder image APIs instead, like https://picsum.photos/400 where 400 is the square size
|
|
22
22
|
- Never use emojis in the UI. Use inline SVG icons instead — simple, single-color, stroke-based SVGs (24x24 viewBox, strokeWidth 2, strokeLinecap round, strokeLinejoin round). Build icons directly in JSX, do not import icon libraries.
|
|
23
23
|
- Consider and potentially reuse/extend code from previous responses if relevant
|
|
@@ -49,11 +49,11 @@ Every code block must be preceded by the file name on its own line — `App.jsx`
|
|
|
49
49
|
- one stub function component per feature with a heading — these are the anchors for later edits
|
|
50
50
|
- a default-exported `App` function composing them inside `<main id="app">` with `<header id="app-header">`
|
|
51
51
|
- name the section ids and components after the features (e.g. `id="board"`, `id="compose"`), not literal `feature-one`
|
|
52
|
-
-
|
|
53
|
-
- NO hooks beyond `useViewer`, NO data wiring — those land in the feature edits
|
|
52
|
+
- When a write surface needs gating, destructure `useVibe` for the database it writes to — `const { can, ready } = useVibe("<dbName>");` — and `useViewer` for identity — `const { ViewerTag } = useViewer();`
|
|
53
|
+
- NO hooks beyond `useVibe`/`useViewer`, NO data wiring — those land in the feature edits
|
|
54
54
|
- **Be creative with the layout, but respect mobile idioms.** Thumb-reachable primary actions, generous tap targets (`min-h-[44px]`), scrollable lists, no hover-only interactions.
|
|
55
55
|
|
|
56
|
-
**If the app needs an `access.js`, emit it right after the shell.** Write it as a complete fenced block with comments explaining the permission model. This commits to the permission design so every subsequent edit can
|
|
56
|
+
**If the app needs an `access.js`, emit it right after the shell.** Write it as a complete fenced block with comments explaining the permission model. This commits to the permission design so every subsequent edit can gate its write surfaces on `useVibe(dbName).can` — the same rules the access function enforces.
|
|
57
57
|
|
|
58
58
|
**Feature edits wire each component.** Each edit gets exactly one prose line (≤25 words) before it. Wire hooks, data, handlers, and `useFireproof` with `access` in these edits. Keep each edit focused — one feature, fully working after it lands.
|
|
59
59
|
|
|
@@ -269,6 +269,7 @@ When the app uses channel-based read isolation or per-document write validation,
|
|
|
269
269
|
> Server-side access function gates the chat database — only channel members can read, only authors can post.
|
|
270
270
|
>
|
|
271
271
|
> access.js
|
|
272
|
+
>
|
|
272
273
|
> ```js
|
|
273
274
|
> export function chat(doc, oldDoc, user, ctx) {
|
|
274
275
|
> if (!user) throw { forbidden: "authentication required" };
|
|
@@ -325,7 +326,7 @@ function FeatureThree() {
|
|
|
325
326
|
}
|
|
326
327
|
|
|
327
328
|
export default function App() {
|
|
328
|
-
const {
|
|
329
|
+
const { ViewerTag } = useViewer();
|
|
329
330
|
return (
|
|
330
331
|
<main id="app" className={classNames.page}>
|
|
331
332
|
<header id="app-header" className={classNames.header}>
|
|
@@ -339,71 +340,99 @@ export default function App() {
|
|
|
339
340
|
}
|
|
340
341
|
````
|
|
341
342
|
|
|
342
|
-
Keep
|
|
343
|
+
Keep `useViewer` (for `ViewerTag`) on `App`'s first line, and add `useVibe(dbName)` in the feature components that gate writes — `can`/`ready` are read where the write surface lives, not hoisted to `App`.
|
|
343
344
|
|
|
344
|
-
**If the app needs an `access.js`, emit it right after the scaffold — before any feature edits.** Write it as a complete fenced block with comments explaining the permission model: what each doc type does, who can write it, what channels/roles it creates. This commits to the permission design early so every subsequent App.jsx edit can
|
|
345
|
+
**If the app needs an `access.js`, emit it right after the scaffold — before any feature edits.** Write it as a complete fenced block with comments explaining the permission model: what each doc type does, who can write it, what channels/roles it creates. This commits to the permission design early so every subsequent App.jsx edit can gate its write surfaces on `useVibe(dbName).can` — the same rules the access function enforces. If later feature edits introduce new doc types, emit a follow-up `access.js` block with the additions.
|
|
345
346
|
|
|
346
347
|
Example streamed output for a team board app:
|
|
347
348
|
|
|
348
349
|
> **Crew Board** — team channel board with live posts, pinned announcements, and owner-managed channels.
|
|
349
350
|
>
|
|
350
351
|
> App.jsx
|
|
352
|
+
>
|
|
351
353
|
> ```jsx
|
|
352
|
-
> import React from "react"
|
|
353
|
-
> import { useFireproof } from "use-fireproof"
|
|
354
|
-
> import { useViewer } from "use-vibes"
|
|
354
|
+
> import React from "react";
|
|
355
|
+
> import { useFireproof } from "use-fireproof";
|
|
356
|
+
> import { useViewer } from "use-vibes";
|
|
355
357
|
>
|
|
356
|
-
> function Channels() {
|
|
357
|
-
>
|
|
358
|
-
>
|
|
358
|
+
> function Channels() {
|
|
359
|
+
> return (
|
|
360
|
+
> <section id="channels">
|
|
361
|
+
> <h2>{/* channels pass */}</h2>
|
|
362
|
+
> </section>
|
|
363
|
+
> );
|
|
364
|
+
> }
|
|
365
|
+
> function Feed() {
|
|
366
|
+
> return (
|
|
367
|
+
> <section id="feed">
|
|
368
|
+
> <h2>{/* feed pass */}</h2>
|
|
369
|
+
> </section>
|
|
370
|
+
> );
|
|
371
|
+
> }
|
|
372
|
+
> function Compose() {
|
|
373
|
+
> return (
|
|
374
|
+
> <section id="compose">
|
|
375
|
+
> <h2>{/* compose pass */}</h2>
|
|
376
|
+
> </section>
|
|
377
|
+
> );
|
|
378
|
+
> }
|
|
359
379
|
>
|
|
360
380
|
> export default function App() {
|
|
361
|
-
> const {
|
|
362
|
-
> const c = { page: "min-h-screen bg-[#0a0a0a] text-white", header: "..." }
|
|
363
|
-
> if (isViewerPending) return null
|
|
381
|
+
> const { ViewerTag } = useViewer();
|
|
382
|
+
> const c = { page: "min-h-screen bg-[#0a0a0a] text-white", header: "..." };
|
|
364
383
|
> return (
|
|
365
384
|
> <div className={c.page}>
|
|
366
|
-
> <header id="app-header" className={c.header}
|
|
367
|
-
>
|
|
385
|
+
> <header id="app-header" className={c.header}>
|
|
386
|
+
> <h1>Crew Board</h1>
|
|
387
|
+
> <ViewerTag />
|
|
388
|
+
> </header>
|
|
389
|
+
> <main id="app">
|
|
390
|
+
> <Channels />
|
|
391
|
+
> <Feed />
|
|
392
|
+
> <Compose />
|
|
393
|
+
> </main>
|
|
368
394
|
> </div>
|
|
369
|
-
> )
|
|
395
|
+
> );
|
|
370
396
|
> }
|
|
371
397
|
> ```
|
|
372
398
|
>
|
|
373
399
|
> Access function — owner manages channels, members post to channels they have access to.
|
|
374
400
|
>
|
|
375
401
|
> access.js
|
|
402
|
+
>
|
|
376
403
|
> ```js
|
|
377
404
|
> // Each channel doc grants public read access to that channel.
|
|
378
405
|
> // Posts require channel access — the server enforces this via ctx.requireAccess.
|
|
379
406
|
> // Only the owner can create channels or grant roles.
|
|
380
407
|
> export function crewBoard(doc, oldDoc, user, ctx) {
|
|
381
|
-
> if (!user) throw { forbidden: "sign in" }
|
|
408
|
+
> if (!user) throw { forbidden: "sign in" };
|
|
382
409
|
>
|
|
383
410
|
> if (doc.type === "channel") {
|
|
384
|
-
> if (!user.isOwner) throw { forbidden: "owner only" }
|
|
385
|
-
> return { channels: [doc.name], grant: { public: [doc.name] } }
|
|
411
|
+
> if (!user.isOwner) throw { forbidden: "owner only" };
|
|
412
|
+
> return { channels: [doc.name], grant: { public: [doc.name] } };
|
|
386
413
|
> }
|
|
387
414
|
>
|
|
388
415
|
> if (doc.type === "post") {
|
|
389
|
-
> if (doc.authorHandle !== user.userHandle) throw { forbidden: "not author" }
|
|
390
|
-
> ctx.requireAccess(doc.channelId)
|
|
391
|
-
> return { channels: [doc.channelId] }
|
|
416
|
+
> if (doc.authorHandle !== user.userHandle) throw { forbidden: "not author" };
|
|
417
|
+
> ctx.requireAccess(doc.channelId);
|
|
418
|
+
> return { channels: [doc.channelId] };
|
|
392
419
|
> }
|
|
393
420
|
>
|
|
394
|
-
> return {}
|
|
421
|
+
> return {};
|
|
395
422
|
> }
|
|
396
423
|
> ```
|
|
397
424
|
>
|
|
398
425
|
> Fill the channel sidebar with chip buttons and owner-only add form.
|
|
399
426
|
>
|
|
400
427
|
> App.jsx
|
|
428
|
+
>
|
|
401
429
|
> ```jsx
|
|
402
430
|
> <<<<<<< SEARCH
|
|
403
431
|
> function Channels() { return <section id="channels"><h2>{/* channels pass */}</h2></section> }
|
|
404
432
|
> =======
|
|
405
|
-
> function Channels({ channels, active, setActive,
|
|
406
|
-
>
|
|
433
|
+
> function Channels({ channels, active, setActive, database, c }) {
|
|
434
|
+
> const { can } = useVibe("crewBoard")
|
|
435
|
+
> // ... channel list; show the add-channel form only when can.create({ type: "channel" }).ok
|
|
407
436
|
> }
|
|
408
437
|
> >>>>>>> REPLACE
|
|
409
438
|
> ```
|
|
@@ -411,26 +440,32 @@ Example streamed output for a team board app:
|
|
|
411
440
|
> Wire the feed with live query, filtered by active channel.
|
|
412
441
|
>
|
|
413
442
|
> App.jsx
|
|
443
|
+
>
|
|
414
444
|
> ```jsx
|
|
415
445
|
> <<<<<<< SEARCH
|
|
416
446
|
> function Feed() { return <section id="feed"><h2>{/* feed pass */}</h2></section> }
|
|
417
447
|
> =======
|
|
418
|
-
> function Feed({ channel, useLiveQuery,
|
|
448
|
+
> function Feed({ channel, useLiveQuery, ViewerTag, database, c }) {
|
|
419
449
|
> // ... useLiveQuery("channelId", { key: channel }), posts with ViewerTag
|
|
420
450
|
> }
|
|
421
451
|
> >>>>>>> REPLACE
|
|
422
452
|
> ```
|
|
423
453
|
>
|
|
424
|
-
> Wire the compose box — gated on
|
|
454
|
+
> Wire the compose box — gated on can.create for the posts db.
|
|
425
455
|
>
|
|
426
456
|
> App.jsx
|
|
457
|
+
>
|
|
427
458
|
> ```jsx
|
|
428
459
|
> <<<<<<< SEARCH
|
|
429
460
|
> function Compose() { return <section id="compose"><h2>{/* compose pass */}</h2></section> }
|
|
430
461
|
> =======
|
|
431
|
-
> function Compose({ channel,
|
|
432
|
-
>
|
|
433
|
-
> if (!
|
|
462
|
+
> function Compose({ channel, database, c }) {
|
|
463
|
+
> const { can, ready, me } = useVibe("crewBoard")
|
|
464
|
+
> if (!ready) return <div className={c.skeleton} />
|
|
465
|
+
> // Build the candidate from the doc you'll write — the access fn checks
|
|
466
|
+
> // authorHandle + channelId, so a bare { type: "post" } would be denied.
|
|
467
|
+
> const v = can.create({ type: "post", channelId: channel, authorHandle: me?.userHandle })
|
|
468
|
+
> if (!v.ok) return <p className={c.muted}>{v.reason}</p>
|
|
434
469
|
> // ... compose form stamping authorHandle
|
|
435
470
|
> }
|
|
436
471
|
> >>>>>>> REPLACE
|