@pylonsync/create-pylon 0.3.304 → 0.3.306

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pylonsync/create-pylon",
3
- "version": "0.3.304",
3
+ "version": "0.3.306",
4
4
  "description": "Scaffold a new Pylon app — realtime backend + web/mobile/expo frontends in one command. Run via `npm create @pylonsync/pylon@latest`.",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
 
3
- import React, { useState } from "react";
4
- import { db } from "@pylonsync/react";
3
+ import React, { useEffect, useState } from "react";
4
+ import { db, callFn } from "@pylonsync/react";
5
5
  import { EnsureGuest, useAuth } from "@pylonsync/client";
6
6
  import { Button } from "@/components/ui/button";
7
7
 
@@ -32,6 +32,11 @@ export function Feed() {
32
32
  function FeedInner() {
33
33
  const { userId } = useAuth();
34
34
  const [text, setText] = useState("");
35
+ // Seed a few demo posts on first visit so the feed isn't empty. No-op once
36
+ // any post exists; safe to call every mount.
37
+ useEffect(() => {
38
+ void callFn("seedPosts", {});
39
+ }, []);
35
40
  const { data: posts, loading } = db.useQuery<Post>("Post");
36
41
  // Public-read, so this is every like in the system — we count + match them
37
42
  // client-side. db.useQuery is live, so counts update the instant anyone likes.
@@ -0,0 +1,56 @@
1
+ import { mutation } from "@pylonsync/functions";
2
+
3
+ // A few demo posts so the feed isn't an empty shell on first visit. The feed
4
+ // calls this on mount; it's a no-op once any post exists (the lock guards
5
+ // against a double-seed from two concurrent first-visits). Public so an
6
+ // anonymous first visitor seeds it — it only writes demo content.
7
+ //
8
+ // `unsafe.insert` sets the demo `authorId` + a backdated `createdAt` directly
9
+ // (bypassing the `field.owner()` stamp + policies) so the seed reads like a few
10
+ // different people already posted, instead of everything attributed to the
11
+ // first visitor.
12
+ const DEMO_POSTS: { author: string; text: string }[] = [
13
+ {
14
+ author: "guest_ada",
15
+ text: "just shipped my first Pylon app — one binary doing SSR + sync + auth. wild.",
16
+ },
17
+ {
18
+ author: "guest_lin",
19
+ text: "the feed updates across tabs with zero websocket code I wrote. open a second tab 👀",
20
+ },
21
+ {
22
+ author: "guest_rey",
23
+ text: "likes are just rows — delete the row to unlike. local-first, so it's instant.",
24
+ },
25
+ {
26
+ author: "guest_max",
27
+ text: "no separate backend to deploy. `pylon deploy` and it's live. that's the whole thing.",
28
+ },
29
+ ];
30
+
31
+ export default mutation<
32
+ Record<string, never>,
33
+ { seeded: boolean; count: number }
34
+ >({
35
+ auth: "public",
36
+ async handler(ctx) {
37
+ await ctx.db.advisoryLock("consumer_seed_posts");
38
+ const existing = await ctx.db.unsafe.list("Post");
39
+ if (existing.length > 0) return { seeded: false, count: existing.length };
40
+
41
+ const now = Date.now();
42
+ for (let i = 0; i < DEMO_POSTS.length; i++) {
43
+ const p = DEMO_POSTS[i];
44
+ // Backdate a minute apart so they sort into a natural order.
45
+ const createdAt = new Date(
46
+ now - (DEMO_POSTS.length - i) * 60_000,
47
+ ).toISOString();
48
+ await ctx.db.unsafe.insert("Post", {
49
+ authorId: p.author,
50
+ text: p.text,
51
+ createdAt,
52
+ });
53
+ }
54
+ return { seeded: true, count: DEMO_POSTS.length };
55
+ },
56
+ });