@vibes.diy/prompts 2.5.11 → 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.js +1 -1
- package/llms/fireproof.md +100 -33
- 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.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export const fireproofConfig = {
|
|
2
2
|
name: "fireproof",
|
|
3
3
|
label: "useFireproof",
|
|
4
|
-
description: "
|
|
4
|
+
description: "cloud-backed document database with live sync",
|
|
5
5
|
importModule: "use-fireproof",
|
|
6
6
|
importName: "useFireproof",
|
|
7
7
|
};
|
package/llms/fireproof.md
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
# Fireproof Database API Guide
|
|
2
2
|
|
|
3
|
-
Fireproof is a
|
|
3
|
+
Fireproof is a document database with live sync, designed to make browser apps easy. On vibes.diy it runs against Firefly, a cloud-centralized backend: writes are sent to a server that validates them with your `access.js`, persists them, and streams them live to every viewer. Use it in any JavaScript environment with a unified API that works both in React (with hooks) and as a standalone core API.
|
|
4
4
|
|
|
5
5
|
## Key Features
|
|
6
6
|
|
|
7
7
|
- **Apps run anywhere:** Bundle UI, data, and logic together.
|
|
8
|
-
- **Real-Time
|
|
8
|
+
- **Real-Time, cloud-backed:** Writes are validated and persisted server-side, then streamed live to every viewer. `useLiveQuery` keeps the UI in sync as data arrives, so you render empty states rather than loading spinners — but writes can fail (access denied, conflicts, network), so handle write rejections.
|
|
9
9
|
- **Unified API:** TypeScript works with Deno, Bun, Node.js, and the browser.
|
|
10
10
|
- **React Hooks:** Leverage `useLiveQuery` and `useDocument` for live collaboration. Note: these are NOT top-level exports — they are returned by the `useFireproof()` hook. Always destructure from `const { useLiveQuery, useDocument, database } = useFireproof("dbName")`.
|
|
11
11
|
|
|
12
12
|
**File structure:** A vibe's source is one or more files. `/App.jsx` is the entry point (React component). `/access.js` is optional — include it when the app needs per-document write validation or channel-based read isolation. Both files are pushed together and the server discovers `/access.js` automatically.
|
|
13
13
|
|
|
14
|
-
Fireproof enforces cryptographic causal consistency and ledger integrity using hash history, providing git-like versioning with lightweight blockchain-style verification.
|
|
14
|
+
Fireproof enforces cryptographic causal consistency and ledger integrity using hash history, providing git-like versioning with lightweight blockchain-style verification. On vibes.diy, the Firefly server is the authority for every write: it stores each document in a per-document append-only sequence, runs your `access.js` to validate and route it, and then syncs it to viewers. Because writes go through the server, they are subject to access rules and can be rejected.
|
|
15
15
|
|
|
16
16
|
## Installation
|
|
17
17
|
|
|
18
|
-
The `use-fireproof` package provides both the core API and React hooks. React hooks are the recommended way to use Fireproof in LLM code generation contexts. Fireproof databases
|
|
18
|
+
The `use-fireproof` package provides both the core API and React hooks. React hooks are the recommended way to use Fireproof in LLM code generation contexts. Fireproof databases persist data through the Firefly server and sync it live to every viewer. Each database is identified by a string name, and you can have multiple databases per application—often one per collaboration session, as they are the unit of sharing.
|
|
19
19
|
|
|
20
|
-
Each document has an `_id`, which can be auto-generated or set explicitly. Auto-generation is recommended to ensure uniqueness and avoid conflicts.
|
|
20
|
+
Each document has an `_id`, which can be auto-generated or set explicitly. Auto-generation is recommended to ensure uniqueness and avoid conflicts. The server keeps a per-document sequence, so two clients writing the same `_id` at the same time can collide and one write will be rejected — see the note on continuous updates below. Prefer one document per event over many rapid writes to a single hot document.
|
|
21
21
|
|
|
22
22
|
Use granular documents, e.g. one document per user action, so saving a form or clicking a button should typically create or update a single document, or just a few documents. Avoid patterns that require a single document to grow without bound.
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
`useLiveQuery` populates and refreshes the UI reactively as data arrives, so you usually render empty states rather than loading spinners. Writes, however, go to the server and can fail — wrap `put()`/`save()`/`del()` in `try/catch` (or attach a `.catch`) so a rejected write surfaces to the user instead of becoming an unhandled promise rejection.
|
|
25
25
|
|
|
26
26
|
### Basic Example
|
|
27
27
|
|
|
@@ -121,6 +121,44 @@ App.jsx
|
|
|
121
121
|
|
|
122
122
|
Never call hooks inside handlers — `const { doc, save } = useDocument({ _id: id })` inside an onClick BREAKS the Rules of Hooks.
|
|
123
123
|
|
|
124
|
+
### Continuous Controls — `merge()` on every event, `save()` once on commit
|
|
125
|
+
|
|
126
|
+
A continuous control (slider, drag, color picker, live-typed text bound to one doc) fires many events in quick succession. **Never call `database.put()` or `save()` on every `onChange`** — that floods the server with rapid concurrent writes to the same `_id`, which collide on the per-document sequence and get rejected (`Failed to put document …`). Instead, `merge()` locally on each event to keep the UI live, and `save()` once when the interaction commits (`onPointerUp`, `onBlur`, `onChange` for a range input's final value, or a debounced trailing call). Editing a single doc with a slider:
|
|
127
|
+
|
|
128
|
+
App.jsx
|
|
129
|
+
|
|
130
|
+
```jsx
|
|
131
|
+
<<<<<<< SEARCH
|
|
132
|
+
const { useDocument, useLiveQuery, database } = useFireproof("myLedger");
|
|
133
|
+
=======
|
|
134
|
+
const { useDocument, useLiveQuery, database } = useFireproof("myLedger");
|
|
135
|
+
|
|
136
|
+
// One shared mix doc; slider updates the UI on every event, persists on commit
|
|
137
|
+
const { doc: mix, merge: mergeMix, save: saveMix } = useDocument({ _id: "mix:current", level: 50 });
|
|
138
|
+
>>>>>>> REPLACE
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
App.jsx
|
|
142
|
+
|
|
143
|
+
```jsx
|
|
144
|
+
<<<<<<< SEARCH
|
|
145
|
+
<h3>Recent Documents</h3>
|
|
146
|
+
=======
|
|
147
|
+
<input
|
|
148
|
+
type="range"
|
|
149
|
+
min="0"
|
|
150
|
+
max="100"
|
|
151
|
+
value={mix.level}
|
|
152
|
+
onChange={(e) => mergeMix({ level: Number(e.target.value) })} // live, no write
|
|
153
|
+
onPointerUp={() => saveMix().catch((err) => console.error("save failed", err))} // one write on commit
|
|
154
|
+
/>
|
|
155
|
+
|
|
156
|
+
<h3>Recent Documents</h3>
|
|
157
|
+
>>>>>>> REPLACE
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
If you genuinely need to persist mid-drag, debounce the `save()` so at most one write is in flight, and still `.catch()` the rejection. Better yet, prefer one document per event (see the Counter Pattern) over hammering a single hot document.
|
|
161
|
+
|
|
124
162
|
### Query Data
|
|
125
163
|
|
|
126
164
|
Data is queried by sorted indexes defined by the application. Sort by strings, numbers, or booleans, as well as arrays for grouping. Use numbers when possible for sorting continuous data. You can use the `_id` field for temporal sorting so you don't have to write code to get simple recent document lists, as in the basic example above.
|
|
@@ -295,12 +333,23 @@ Other `acl` variants: `useFireproof("drafts", { acl: { read: ["editors"], write:
|
|
|
295
333
|
|
|
296
334
|
## Reading Resolved Grants (`access`)
|
|
297
335
|
|
|
298
|
-
`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`.
|
|
299
337
|
|
|
300
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.
|
|
301
339
|
|
|
302
340
|
App.jsx
|
|
303
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
|
+
|
|
304
353
|
```jsx
|
|
305
354
|
<<<<<<< SEARCH
|
|
306
355
|
const { useLiveQuery, database } = useFireproof("announcements", {
|
|
@@ -308,6 +357,7 @@ App.jsx
|
|
|
308
357
|
});
|
|
309
358
|
=======
|
|
310
359
|
const { database, useLiveQuery, access } = useFireproof("comments");
|
|
360
|
+
const { can, me } = useVibe("comments");
|
|
311
361
|
>>>>>>> REPLACE
|
|
312
362
|
```
|
|
313
363
|
|
|
@@ -327,17 +377,18 @@ App.jsx
|
|
|
327
377
|
))}
|
|
328
378
|
</ul>
|
|
329
379
|
=======
|
|
330
|
-
{
|
|
331
|
-
{
|
|
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 />}
|
|
332
383
|
{access.hasChannel("announcements") && <Announcements />}
|
|
333
384
|
>>>>>>> REPLACE
|
|
334
385
|
```
|
|
335
386
|
|
|
336
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.
|
|
337
388
|
|
|
338
|
-
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.
|
|
339
390
|
|
|
340
|
-
`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.
|
|
341
392
|
|
|
342
393
|
### Complete example: Team announcements with channels
|
|
343
394
|
|
|
@@ -346,7 +397,7 @@ This example shows the full round-trip — access.js declares channels and grant
|
|
|
346
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.
|
|
347
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()`.
|
|
348
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.
|
|
349
|
-
- **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.)
|
|
350
401
|
- **`ViewerTag`** takes `userHandle` when rendering another user.
|
|
351
402
|
|
|
352
403
|
access.js
|
|
@@ -382,20 +433,28 @@ export function announcements(doc, oldDoc, user, ctx) {
|
|
|
382
433
|
}
|
|
383
434
|
```
|
|
384
435
|
|
|
385
|
-
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:
|
|
386
437
|
|
|
387
438
|
```jsx
|
|
388
439
|
import React from "react";
|
|
389
440
|
import { useFireproof } from "use-fireproof";
|
|
390
|
-
import { useViewer } from "use-vibes";
|
|
441
|
+
import { useViewer, useVibe } from "use-vibes";
|
|
391
442
|
|
|
392
443
|
export default function App() {
|
|
393
|
-
const { viewer,
|
|
444
|
+
const { viewer, isViewerPending, ViewerTag } = useViewer();
|
|
394
445
|
const { database, useLiveQuery, access } = useFireproof("announcements");
|
|
446
|
+
const { can } = useVibe("announcements");
|
|
395
447
|
|
|
396
448
|
const { docs: posts } = useLiveQuery("type", { key: "post" });
|
|
397
449
|
const [draft, setDraft] = React.useState("");
|
|
398
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" });
|
|
399
458
|
|
|
400
459
|
if (isViewerPending) return null;
|
|
401
460
|
|
|
@@ -415,8 +474,8 @@ export default function App() {
|
|
|
415
474
|
<div>
|
|
416
475
|
<ViewerTag />
|
|
417
476
|
|
|
418
|
-
{/*
|
|
419
|
-
{
|
|
477
|
+
{/* gate the write surface on useVibe().can — it runs the access function */}
|
|
478
|
+
{canPost.ok ? (
|
|
420
479
|
<form
|
|
421
480
|
onSubmit={(e) => {
|
|
422
481
|
e.preventDefault();
|
|
@@ -426,10 +485,12 @@ export default function App() {
|
|
|
426
485
|
<textarea value={draft} onChange={(e) => setDraft(e.target.value)} />
|
|
427
486
|
<button type="submit">Post</button>
|
|
428
487
|
</form>
|
|
488
|
+
) : (
|
|
489
|
+
viewer && <p style={{ color: "var(--muted, #888)" }}>{canPost.reason}</p>
|
|
429
490
|
)}
|
|
430
491
|
|
|
431
|
-
{/* owner-only management */}
|
|
432
|
-
{
|
|
492
|
+
{/* owner-only management — gated on can.*, not isOwner */}
|
|
493
|
+
{canGrant.ok && (
|
|
433
494
|
<button onClick={() => database.put({ type: "roleGrant", role: "poster", userHandle: "newUser" })}>
|
|
434
495
|
Grant poster role
|
|
435
496
|
</button>
|
|
@@ -439,7 +500,7 @@ export default function App() {
|
|
|
439
500
|
<div key={p._id}>
|
|
440
501
|
<ViewerTag userHandle={p.authorHandle} />
|
|
441
502
|
<p>{p.body}</p>
|
|
442
|
-
{
|
|
503
|
+
{can.delete(p).ok && <button onClick={() => database.del(p._id)}>Delete</button>}
|
|
443
504
|
</div>
|
|
444
505
|
))}
|
|
445
506
|
</div>
|
|
@@ -447,11 +508,11 @@ export default function App() {
|
|
|
447
508
|
}
|
|
448
509
|
```
|
|
449
510
|
|
|
450
|
-
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.
|
|
451
512
|
|
|
452
513
|
### Example: Channel board with restricted channels
|
|
453
514
|
|
|
454
|
-
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.
|
|
455
516
|
|
|
456
517
|
access.js
|
|
457
518
|
|
|
@@ -480,7 +541,7 @@ export function chat(doc, oldDoc, user, ctx) {
|
|
|
480
541
|
}
|
|
481
542
|
```
|
|
482
543
|
|
|
483
|
-
App.jsx —
|
|
544
|
+
App.jsx — `access.hasChannel()` filters which channels are visible (display); `useVibe().can` gates the write surface:
|
|
484
545
|
|
|
485
546
|
```jsx
|
|
486
547
|
<<<<<<< SEARCH
|
|
@@ -488,6 +549,7 @@ App.jsx — the UI uses `access.hasChannel()` for everything. It has no idea whi
|
|
|
488
549
|
=======
|
|
489
550
|
const { database, useLiveQuery, access } = useFireproof("chat");
|
|
490
551
|
const { docs: channels } = useLiveQuery("type", { key: "channel" });
|
|
552
|
+
const canPost = useVibe("chat").can.create({ type: "post" });
|
|
491
553
|
>>>>>>> REPLACE
|
|
492
554
|
```
|
|
493
555
|
|
|
@@ -495,13 +557,13 @@ App.jsx — the UI uses `access.hasChannel()` for everything. It has no idea whi
|
|
|
495
557
|
<<<<<<< SEARCH
|
|
496
558
|
{viewer && access.hasChannel(channel) && (
|
|
497
559
|
=======
|
|
498
|
-
{/* 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) */}
|
|
499
561
|
{channels.filter((ch) => isOwner || access.hasChannel(ch._id)).map((ch) => (
|
|
500
562
|
<button key={ch._id} onClick={() => setChannel(ch._id)}>{ch.name}</button>
|
|
501
563
|
))}
|
|
502
564
|
|
|
503
|
-
{/*
|
|
504
|
-
{
|
|
565
|
+
{/* gate the write surface on useVibe().can */}
|
|
566
|
+
{canPost.ok ? (
|
|
505
567
|
>>>>>>> REPLACE
|
|
506
568
|
```
|
|
507
569
|
|
|
@@ -670,7 +732,7 @@ function crewChat(doc, oldDoc, user, ctx) {
|
|
|
670
732
|
ctx.requireAccess(doc.channelId);
|
|
671
733
|
return { channels: [doc.channelId] };
|
|
672
734
|
}
|
|
673
|
-
export { crewChat as "crew-chat" }
|
|
735
|
+
export { crewChat as "crew-chat" };
|
|
674
736
|
```
|
|
675
737
|
|
|
676
738
|
### Catch-all with `export default`
|
|
@@ -765,7 +827,7 @@ Other common `oldDoc` patterns: `if (oldDoc === null) { /* create-only logic */
|
|
|
765
827
|
|
|
766
828
|
## Architecture: Where's My Data?
|
|
767
829
|
|
|
768
|
-
Data
|
|
830
|
+
Data lives on the Firefly server, which is the source of truth. The browser keeps a local cache for instant reads, but every write is sent to the server, validated by your `access.js`, persisted, and then synced to all users who have read access. A write that fails validation, hits a conflict, or loses the network is rejected — handle those rejections rather than assuming the write always lands.
|
|
769
831
|
|
|
770
832
|
## Using Fireproof in JavaScript
|
|
771
833
|
|
|
@@ -785,12 +847,17 @@ import { fireproof } from "use-fireproof";
|
|
|
785
847
|
|
|
786
848
|
const database = fireproof("myLedger");
|
|
787
849
|
|
|
788
|
-
// The document API is async
|
|
850
|
+
// The document API is async — reads and writes both await the server.
|
|
851
|
+
// Writes can fail (access denied, conflict, network), so wrap them.
|
|
789
852
|
async function main() {
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
853
|
+
try {
|
|
854
|
+
const ok = await database.put({ text: "Sample Data" });
|
|
855
|
+
const doc = await database.get(ok.id);
|
|
856
|
+
const latest = await database.query("_id", { limit: 10, descending: true });
|
|
857
|
+
console.log("Latest documents:", latest.docs);
|
|
858
|
+
} catch (err) {
|
|
859
|
+
console.error("write failed (access denied, conflict, or network):", err);
|
|
860
|
+
}
|
|
794
861
|
}
|
|
795
862
|
>>>>>>> REPLACE
|
|
796
863
|
```
|
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
|
|
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
|