@pylonsync/create-pylon 0.3.295 → 0.3.297
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 +1 -1
- package/templates/agency/app/globals.css +8 -1
- package/templates/agency/app/layout.tsx +4 -6
- package/templates/agency/app.ts +15 -0
- package/templates/agency/components/marketing.tsx +2 -4
- package/templates/agency/lib/site.config.ts +3 -5
- package/templates/ai-chat/app/globals.css +8 -1
- package/templates/ai-chat/app/layout.tsx +4 -8
- package/templates/ai-chat/app.ts +18 -5
- package/templates/ai-chat/lib/site.config.ts +3 -3
- package/templates/ai-studio/app/globals.css +8 -1
- package/templates/ai-studio/app/layout.tsx +7 -11
- package/templates/ai-studio/app.ts +20 -7
- package/templates/ai-studio/lib/site.config.ts +2 -2
- package/templates/ai-studio/lib/studio.ts +1 -1
- package/templates/backend/b2b/apps/api/schema.ts +10 -24
- package/templates/backend/consumer/apps/api/schema.ts +4 -7
- package/templates/barebones/app/layout.tsx +3 -3
- package/templates/barebones/app.ts +2 -3
- package/templates/chat/app.ts +3 -9
- package/templates/consumer/app.ts +2 -3
- package/templates/creator/.env.example +3 -3
- package/templates/creator/app/globals.css +8 -1
- package/templates/creator/app/layout.tsx +4 -6
- package/templates/creator/app.ts +23 -10
- package/templates/creator/components/marketing.tsx +2 -4
- package/templates/default/app/globals.css +8 -1
- package/templates/default/app/layout.tsx +6 -14
- package/templates/default/app.ts +15 -0
- package/templates/default/lib/products.ts +2 -3
- package/templates/default/lib/site.config.ts +1 -2
- package/templates/default/lib/site.ts +3 -4
- package/templates/directory/app/auth-form.tsx +5 -5
- package/templates/directory/app/globals.css +8 -1
- package/templates/directory/app/layout.tsx +4 -6
- package/templates/directory/app/sitemap.ts +1 -1
- package/templates/directory/app.ts +15 -0
- package/templates/directory/lib/owner.ts +5 -5
- package/templates/expo/chat/apps/expo/App.tsx +2 -3
- package/templates/local-service/app/auth-form.tsx +4 -4
- package/templates/local-service/app/globals.css +8 -1
- package/templates/local-service/app/layout.tsx +4 -6
- package/templates/local-service/app/sitemap.ts +1 -1
- package/templates/local-service/app.ts +15 -0
- package/templates/local-service/components/marketing.tsx +2 -4
- package/templates/local-service/lib/owner.ts +3 -3
- package/templates/local-service/lib/site.config.ts +4 -6
- package/templates/marketplace/app/listing/[id]/page.tsx +3 -3
- package/templates/marketplace/functions/makeOffer.ts +0 -1
- package/templates/restaurant/app/auth-form.tsx +5 -5
- package/templates/restaurant/app/globals.css +8 -1
- package/templates/restaurant/app/layout.tsx +4 -6
- package/templates/restaurant/app/sitemap.ts +1 -1
- package/templates/restaurant/app.ts +15 -0
- package/templates/restaurant/lib/owner.ts +5 -5
- package/templates/shop/app/auth-form.tsx +5 -5
- package/templates/shop/app/globals.css +8 -1
- package/templates/shop/app/layout.tsx +5 -7
- package/templates/shop/app/sitemap.ts +1 -1
- package/templates/shop/app.ts +15 -0
- package/templates/shop/lib/owner.ts +6 -5
- package/templates/todo/app/layout.tsx +2 -2
- package/templates/todo/app/sitemap.ts +1 -1
- package/templates/todo/app.ts +4 -5
- package/templates/vite/todo/apps/web/vite.config.ts +5 -9
- package/templates/waitlist/app/globals.css +8 -1
- package/templates/waitlist/app/layout.tsx +4 -6
- package/templates/waitlist/app/waitlist-hero.tsx +4 -5
- package/templates/waitlist/app.ts +26 -9
- package/templates/waitlist/lib/site.config.ts +3 -5
- package/templates/web/barebones/apps/web/postcss.config.mjs +0 -1
- package/templates/web/barebones/apps/web/src/app/globals.css +1 -4
package/templates/shop/app.ts
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
auth,
|
|
6
6
|
buildManifest,
|
|
7
7
|
discoverAppRoutes,
|
|
8
|
+
font,
|
|
8
9
|
} from "@pylonsync/sdk";
|
|
9
10
|
|
|
10
11
|
// ---------------------------------------------------------------------------
|
|
@@ -126,6 +127,20 @@ const manifest = buildManifest({
|
|
|
126
127
|
actions: [],
|
|
127
128
|
policies: [productPolicy, orderPolicy, userPolicy],
|
|
128
129
|
auth: auth(),
|
|
130
|
+
// Self-hosted Inter (next/font parity): the build fetches the woff2, serves it
|
|
131
|
+
// same-origin (no third-party request, no FOUT), preloads it, and synthesizes a
|
|
132
|
+
// size-adjusted fallback face so there's no layout shift. globals.css reads it
|
|
133
|
+
// via `var(--font-sans, …)`; layout.tsx carries no font <link>.
|
|
134
|
+
fonts: [
|
|
135
|
+
font({
|
|
136
|
+
family: "Inter",
|
|
137
|
+
variable: "--font-sans",
|
|
138
|
+
weights: ["400", "500", "600", "700"],
|
|
139
|
+
subsets: ["latin"],
|
|
140
|
+
display: "swap",
|
|
141
|
+
preload: true,
|
|
142
|
+
}),
|
|
143
|
+
],
|
|
129
144
|
routes: await discoverAppRoutes(),
|
|
130
145
|
});
|
|
131
146
|
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
// Who owns this
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
1
|
+
// Who owns this shop? A shop is single-tenant — one business, one owner — so
|
|
2
|
+
// ownership is just "the email the owner signs in with", configured once via the
|
|
3
|
+
// PYLON_OWNER_EMAIL env var. The owner-only functions (ordersForOwner,
|
|
4
|
+
// fulfillOrder, cancelOrder, restockProduct) read that env (via `ctx.env`) and
|
|
5
|
+
// compare it here.
|
|
5
6
|
//
|
|
6
7
|
// Fail closed: if PYLON_OWNER_EMAIL is unset, NOBODY is the owner and the
|
|
7
8
|
// dashboard stays locked. That's deliberate — an unset owner on a public site
|
|
8
|
-
// must not mean "everyone can read the
|
|
9
|
+
// must not mean "everyone can read the orders". Set it in .env (see
|
|
9
10
|
// .env.example) before signing in.
|
|
10
11
|
|
|
11
12
|
export function normalizeOwner(raw: string | null | undefined): string | null {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
|
|
3
|
-
// A layout wraps every page. This one is intentionally minimal — a
|
|
4
|
-
//
|
|
3
|
+
// A layout wraps every page. This one is intentionally minimal — just a
|
|
4
|
+
// centered column. The page below it is server-rendered first (so the
|
|
5
5
|
// shell and copy are in the HTML), then hydrates into the live todo UI.
|
|
6
6
|
interface LayoutProps {
|
|
7
7
|
children: React.ReactNode;
|
|
@@ -14,7 +14,7 @@ export default async function sitemap(): Promise<Sitemap> {
|
|
|
14
14
|
{ url: `${SITE}/signup`, changeFrequency: "yearly", priority: 0.5 },
|
|
15
15
|
];
|
|
16
16
|
|
|
17
|
-
//
|
|
17
|
+
// Example — enumerate dynamic pages from a DB read:
|
|
18
18
|
//
|
|
19
19
|
// const posts = await fetchPublishedPosts();
|
|
20
20
|
// const postRoutes: Sitemap = posts.map((p) => ({
|
package/templates/todo/app.ts
CHANGED
|
@@ -7,11 +7,10 @@ import {
|
|
|
7
7
|
discoverAppRoutes,
|
|
8
8
|
} from "@pylonsync/sdk";
|
|
9
9
|
|
|
10
|
-
// A todo that belongs to one person. `userId: field.owner()`
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
// no round-trip) while ownership stays unspoofable. No createTodo function to
|
|
10
|
+
// A todo that belongs to one person. `userId: field.owner()` stamps the
|
|
11
|
+
// signed-in (here: guest) user's id server-side on insert and rejects any
|
|
12
|
+
// forged value — so the UI can do a plain, optimistic `db.insert("Todo",
|
|
13
|
+
// { title })` and never send (or spoof) userId. No createTodo function to
|
|
15
14
|
// write — every verb is a direct, policy-checked entity call.
|
|
16
15
|
const Todo = entity(
|
|
17
16
|
"Todo",
|
|
@@ -4,18 +4,14 @@ import tailwindcss from "@tailwindcss/vite";
|
|
|
4
4
|
|
|
5
5
|
// Pylon dev exposes TWO ports:
|
|
6
6
|
// :4321 → HTTP (functions, entity CRUD, /api/sync/pull, /api/auth/*)
|
|
7
|
-
// :4322 → dedicated WebSocket listener
|
|
8
|
-
//
|
|
9
|
-
// the reader thread's mutex is released every 200ms by the
|
|
10
|
-
// kernel-level read timeout — no client keepalive ping
|
|
11
|
-
// needed to break the wedge.
|
|
7
|
+
// :4322 → dedicated WebSocket listener that pushes broadcasts with
|
|
8
|
+
// lower latency than the HTTP-multiplexed path.
|
|
12
9
|
//
|
|
13
10
|
// We route the WS upgrade to :4322 and everything else to :4321. The
|
|
14
|
-
// HTTP-multiplexed `/api/sync/ws` on :4321 also works
|
|
11
|
+
// HTTP-multiplexed `/api/sync/ws` on :4321 also works and is the
|
|
15
12
|
// production fallback for proxies that can't forward to a secondary
|
|
16
|
-
// port
|
|
17
|
-
//
|
|
18
|
-
// are latency-bounded by the client SDK's 200ms keepalive ping.
|
|
13
|
+
// port, but its broadcasts are latency-bounded by the client SDK's
|
|
14
|
+
// 200ms keepalive ping.
|
|
19
15
|
const PYLON_HTTP_TARGET = process.env.PYLON_TARGET ?? "http://localhost:4321";
|
|
20
16
|
const PYLON_WS_TARGET = process.env.PYLON_WS_TARGET ?? "ws://localhost:4322";
|
|
21
17
|
|
|
@@ -139,7 +139,14 @@
|
|
|
139
139
|
body {
|
|
140
140
|
background-color: var(--color-background);
|
|
141
141
|
color: var(--color-foreground);
|
|
142
|
-
font-family:
|
|
142
|
+
font-family: var(
|
|
143
|
+
--font-sans,
|
|
144
|
+
Inter,
|
|
145
|
+
ui-sans-serif,
|
|
146
|
+
system-ui,
|
|
147
|
+
-apple-system,
|
|
148
|
+
sans-serif
|
|
149
|
+
);
|
|
143
150
|
-webkit-font-smoothing: antialiased;
|
|
144
151
|
}
|
|
145
152
|
button {
|
|
@@ -44,12 +44,10 @@ export default function RootLayout({ children, url, auth }: LayoutProps) {
|
|
|
44
44
|
<meta charSet="utf-8" />
|
|
45
45
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
46
46
|
{/* No <title> here — each page's exported `metadata` sets it. */}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"
|
|
52
|
-
/>
|
|
47
|
+
{/* Inter is declared in app.ts (fonts: [...]) and self-hosted by the
|
|
48
|
+
build — the runtime injects @font-face + <link rel=preload> + a
|
|
49
|
+
size-adjusted fallback here automatically. No third-party request,
|
|
50
|
+
no layout shift; change the family in app.ts. */}
|
|
53
51
|
{/* Tailwind is compiled by Pylon from app/globals.css and injected here. */}
|
|
54
52
|
</head>
|
|
55
53
|
<body className="flex min-h-screen flex-col bg-background text-foreground antialiased">
|
|
@@ -6,11 +6,10 @@ import { EnsureGuest } from "@pylonsync/client";
|
|
|
6
6
|
import type { WaitlistConfig } from "@/lib/site.config";
|
|
7
7
|
|
|
8
8
|
// The interactive top of the landing page: the email-capture form and the LIVE
|
|
9
|
-
// signup counter.
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
// refresh, no polling.
|
|
9
|
+
// signup counter. The counter is a live `db.useQuery("WaitlistStat")` over the
|
|
10
|
+
// public, PII-free aggregate row, so the moment anyone (this tab or another)
|
|
11
|
+
// submits an email, joinWaitlist updates that row and the new count syncs to
|
|
12
|
+
// every open tab through the replica. No refresh, no polling.
|
|
14
13
|
//
|
|
15
14
|
// The signup form (joinWaitlist) is a public mutation, so it works for any
|
|
16
15
|
// anonymous visitor. The counter needs a live sync connection, so it's wrapped
|
|
@@ -5,20 +5,23 @@ import {
|
|
|
5
5
|
auth,
|
|
6
6
|
buildManifest,
|
|
7
7
|
discoverAppRoutes,
|
|
8
|
+
font,
|
|
8
9
|
} from "@pylonsync/sdk";
|
|
9
10
|
|
|
10
11
|
// ---------------------------------------------------------------------------
|
|
11
12
|
// waitlist — a pre-launch / coming-soon landing page with a LIVE signup
|
|
12
|
-
// counter. The
|
|
13
|
-
//
|
|
14
|
-
// refresh. That's the proof it's a real live app and not a static page.
|
|
13
|
+
// counter. The realtime hook: open the page in two tabs, submit an email in
|
|
14
|
+
// one, and the counter on the other ticks up with no refresh.
|
|
15
15
|
//
|
|
16
|
-
// The data model is deliberately tiny —
|
|
17
|
-
// • Signup
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
16
|
+
// The data model is deliberately tiny — three entities:
|
|
17
|
+
// • Signup — one row per email. Holds visitor PII, so it denies ALL
|
|
18
|
+
// client reads/writes (writes go through the joinWaitlist
|
|
19
|
+
// mutation; the public page only ever sees an aggregate
|
|
20
|
+
// count, never an email).
|
|
21
|
+
// • WaitlistStat — a single-row, PII-free aggregate (just the count) the
|
|
22
|
+
// public page reads live for the counter.
|
|
23
|
+
// • User — the business owner's account (email/password is built in),
|
|
24
|
+
// so the owner can sign in to the dashboard and see signups.
|
|
22
25
|
// ---------------------------------------------------------------------------
|
|
23
26
|
|
|
24
27
|
// One waitlist signup. `email` is the only PII; `createdAt` powers the
|
|
@@ -125,6 +128,20 @@ const manifest = buildManifest({
|
|
|
125
128
|
// Email/password is on by default against the User entity above. No orgs,
|
|
126
129
|
// no billing — a waitlist is single-tenant (one business, one owner).
|
|
127
130
|
auth: auth(),
|
|
131
|
+
// Self-hosted Inter (next/font parity): the build fetches the woff2, serves it
|
|
132
|
+
// same-origin (no third-party request, no FOUT), preloads it, and synthesizes a
|
|
133
|
+
// size-adjusted fallback face so there's no layout shift. globals.css reads it
|
|
134
|
+
// via `var(--font-sans, …)`; layout.tsx carries no font <link>.
|
|
135
|
+
fonts: [
|
|
136
|
+
font({
|
|
137
|
+
family: "Inter",
|
|
138
|
+
variable: "--font-sans",
|
|
139
|
+
weights: ["400", "500", "600", "700"],
|
|
140
|
+
subsets: ["latin"],
|
|
141
|
+
display: "swap",
|
|
142
|
+
preload: true,
|
|
143
|
+
}),
|
|
144
|
+
],
|
|
128
145
|
routes: await discoverAppRoutes(),
|
|
129
146
|
});
|
|
130
147
|
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
// THE single source of truth for everything business-specific on this waitlist.
|
|
2
2
|
// Rebrand the whole page by editing this ONE file — the landing page and layout
|
|
3
|
-
// read from here and stay generic.
|
|
4
|
-
// generators (Mast) target this file too, so a whole site can be themed by
|
|
5
|
-
// producing one typed object.
|
|
3
|
+
// read from here and stay generic.
|
|
6
4
|
//
|
|
7
|
-
// Colors live here (applied as CSS variables on <html> in app/layout.tsx),
|
|
8
|
-
// you don't touch globals.css to re-theme.
|
|
5
|
+
// Colors live here too (applied as CSS variables on <html> in app/layout.tsx),
|
|
6
|
+
// so you don't touch globals.css to re-theme.
|
|
9
7
|
//
|
|
10
8
|
// Fictional demo copy — replace the values, keep the shape.
|
|
11
9
|
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
@import "tailwindcss";
|
|
2
2
|
@source "../../../../packages/ui/src/**/*.{ts,tsx}";
|
|
3
3
|
|
|
4
|
-
:root {
|
|
5
|
-
color-scheme: light dark;
|
|
6
|
-
}
|
|
7
|
-
|
|
4
|
+
:root { color-scheme: light dark; }
|
|
8
5
|
html, body { height: 100%; }
|
|
9
6
|
body { font-family: ui-sans-serif, system-ui, -apple-system, sans-serif; }
|