@pylonsync/create-pylon 0.3.284 → 0.3.286
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/bin/create-pylon.js +6 -0
- package/package.json +1 -1
- package/templates/_root/AGENTS.md +2 -2
- package/templates/agency/AGENTS.md +26 -10
- package/templates/agency/bunfig +4 -0
- package/templates/agency/package.json +3 -0
- package/templates/agency/tests/button.test.tsx +16 -0
- package/templates/agency/tests/setup.ts +5 -0
- package/templates/ai-chat/AGENTS.md +26 -10
- package/templates/ai-chat/bunfig +4 -0
- package/templates/ai-chat/package.json +3 -0
- package/templates/ai-chat/tests/setup.ts +5 -0
- package/templates/ai-studio/AGENTS.md +26 -10
- package/templates/ai-studio/bunfig +4 -0
- package/templates/ai-studio/package.json +3 -0
- package/templates/ai-studio/tests/setup.ts +5 -0
- package/templates/barebones/AGENTS.md +26 -10
- package/templates/barebones/bunfig +4 -0
- package/templates/barebones/package.json +3 -0
- package/templates/barebones/tests/button.test.tsx +16 -0
- package/templates/barebones/tests/setup.ts +5 -0
- package/templates/chat/AGENTS.md +26 -10
- package/templates/chat/bunfig +4 -0
- package/templates/chat/package.json +3 -0
- package/templates/chat/tests/button.test.tsx +16 -0
- package/templates/chat/tests/setup.ts +5 -0
- package/templates/consumer/AGENTS.md +26 -10
- package/templates/consumer/bunfig +4 -0
- package/templates/consumer/package.json +3 -0
- package/templates/consumer/tests/button.test.tsx +16 -0
- package/templates/consumer/tests/setup.ts +5 -0
- package/templates/creator/AGENTS.md +26 -10
- package/templates/creator/bunfig +4 -0
- package/templates/creator/package.json +3 -0
- package/templates/creator/tests/button.test.tsx +16 -0
- package/templates/creator/tests/setup.ts +5 -0
- package/templates/default/AGENTS.md +26 -10
- package/templates/default/bunfig +4 -0
- package/templates/default/package.json +3 -0
- package/templates/default/tests/button.test.tsx +16 -0
- package/templates/default/tests/setup.ts +5 -0
- package/templates/directory/AGENTS.md +26 -10
- package/templates/directory/bunfig +4 -0
- package/templates/directory/package.json +3 -0
- package/templates/directory/tests/button.test.tsx +16 -0
- package/templates/directory/tests/setup.ts +5 -0
- package/templates/local-service/AGENTS.md +26 -10
- package/templates/local-service/bunfig +4 -0
- package/templates/local-service/package.json +3 -0
- package/templates/local-service/tests/button.test.tsx +16 -0
- package/templates/local-service/tests/setup.ts +5 -0
- package/templates/marketplace/AGENTS.md +26 -10
- package/templates/marketplace/bunfig +4 -0
- package/templates/marketplace/package.json +3 -0
- package/templates/marketplace/tests/setup.ts +5 -0
- package/templates/restaurant/AGENTS.md +26 -10
- package/templates/restaurant/bunfig +4 -0
- package/templates/restaurant/package.json +3 -0
- package/templates/restaurant/tests/button.test.tsx +16 -0
- package/templates/restaurant/tests/setup.ts +5 -0
- package/templates/shop/AGENTS.md +26 -10
- package/templates/shop/bunfig +4 -0
- package/templates/shop/package.json +3 -0
- package/templates/shop/tests/button.test.tsx +16 -0
- package/templates/shop/tests/setup.ts +5 -0
- package/templates/todo/AGENTS.md +26 -10
- package/templates/todo/bunfig +4 -0
- package/templates/todo/package.json +3 -0
- package/templates/todo/tests/button.test.tsx +16 -0
- package/templates/todo/tests/setup.ts +5 -0
- package/templates/waitlist/AGENTS.md +26 -10
- package/templates/waitlist/bunfig +4 -0
- package/templates/waitlist/package.json +3 -0
- package/templates/waitlist/tests/button.test.tsx +16 -0
- package/templates/waitlist/tests/setup.ts +5 -0
package/bin/create-pylon.js
CHANGED
|
@@ -465,6 +465,12 @@ function walkAndSubstitute(dir) {
|
|
|
465
465
|
// scaffold time — otherwise the new project has no ignore file
|
|
466
466
|
// and node_modules / .pylon / *.db get committed.
|
|
467
467
|
if (renamed === "gitignore") renamed = ".gitignore";
|
|
468
|
+
// `bun publish` (which the release uses) strips a literal
|
|
469
|
+
// `bunfig.toml` — it treats it as Bun's own runtime config and
|
|
470
|
+
// refuses to ship it in a package. Templates ship it as `bunfig`
|
|
471
|
+
// and we restore the `.toml` here, so the happy-dom test preload
|
|
472
|
+
// actually lands and component tests can render.
|
|
473
|
+
if (renamed === "bunfig") renamed = "bunfig.toml";
|
|
468
474
|
let target = abs;
|
|
469
475
|
if (renamed !== entry) {
|
|
470
476
|
target = join(dir, renamed);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pylonsync/create-pylon",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.286",
|
|
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,6 +1,6 @@
|
|
|
1
1
|
# AGENTS.md — working in a Pylon project
|
|
2
2
|
|
|
3
|
-
Operating rules for a coding agent in this Pylon app. Pylon is a Rails-like framework for realtime apps: you declare entities, policies, and server functions in TypeScript, and a single Rust binary (`pylon`) serves the API, auth, sync, WebSocket, SSE, and native React 19 SSR — one process, one port. The full API reference is
|
|
3
|
+
Operating rules for a coding agent in this Pylon app. Pylon is a Rails-like framework for realtime apps: you declare entities, policies, and server functions in TypeScript, and a single Rust binary (`pylon`) serves the API, auth, sync, WebSocket, SSE, and native React 19 SSR — one process, one port. The full API reference is the **llms-full.txt** at https://docs.pylonsync.com/llms-full.txt. Read it before guessing an API name.
|
|
4
4
|
|
|
5
5
|
## Directory conventions
|
|
6
6
|
|
|
@@ -50,4 +50,4 @@ Operating rules for a coding agent in this Pylon app. Pylon is a Rails-like fram
|
|
|
50
50
|
|
|
51
51
|
`--json` works on every command for machine-readable output. Prefer one-shot/agent-safe flags (`pylon logs --limit N`, not a blocking `--follow`).
|
|
52
52
|
|
|
53
|
-
For full signatures, env vars, the complete CLI, and SSR/client/server-primitive details:
|
|
53
|
+
For full signatures, env vars, the complete CLI, and SSR/client/server-primitive details: **https://docs.pylonsync.com/llms-full.txt**.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# AGENTS.md — working in a Pylon project
|
|
2
2
|
|
|
3
|
-
Operating rules for a coding agent in this Pylon app. Pylon is a Rails-like framework for realtime apps: you declare entities, policies, and server functions in TypeScript, and a single Rust binary (`pylon`) serves the API, auth, sync, WebSocket, SSE, and native React 19 SSR — one process, one port. The full API reference is
|
|
3
|
+
Operating rules for a coding agent in this Pylon app. Pylon is a Rails-like framework for realtime apps: you declare entities, policies, and server functions in TypeScript, and a single Rust binary (`pylon`) serves the API, auth, sync, WebSocket, SSE, and native React 19 SSR — one process, one port. The full API reference is the **llms-full.txt** at https://docs.pylonsync.com/llms-full.txt. Read it before guessing an API name.
|
|
4
4
|
|
|
5
5
|
## Directory conventions
|
|
6
6
|
|
|
@@ -39,9 +39,9 @@ Operating rules for a coding agent in this Pylon app. Pylon is a Rails-like fram
|
|
|
39
39
|
|
|
40
40
|
## Testing
|
|
41
41
|
|
|
42
|
-
`pylon test` discovers every `*.test.ts`
|
|
42
|
+
`pylon test` discovers every `*.test.ts` / `*.test.tsx` file under `tests/` (or `functions/`) and runs it with **Bun's test runner** (`import { test, expect } from "bun:test"`). Run the suite with `pylon test` (or `npm test`); filter with `pylon test <substring>`. This template ships `bunfig.toml` + `tests/setup.ts` (registers happy-dom) so component tests render out of the box, plus starter tests under `tests/` — replace them with your own.
|
|
43
43
|
|
|
44
|
-
**
|
|
44
|
+
**Tier 1 — pure logic (reach for this first).** Keep the decisions that matter — access/plan gating, pricing, credit math, validation, formatting — in pure functions in `lib/`, and test those exhaustively. No server, instant, and it's where the real bugs live. Keep your `query`/`mutation`/`action` handlers as thin wrappers around them, so the logic is testable without a running app.
|
|
45
45
|
|
|
46
46
|
```ts
|
|
47
47
|
import { expect, test } from "bun:test";
|
|
@@ -52,7 +52,25 @@ test("unknown slug → undefined", () => {
|
|
|
52
52
|
});
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
-
**
|
|
55
|
+
**Tier 2 — React components.** `@testing-library/react` + happy-dom are already wired (`tests/setup.ts`). Render and assert. The template uses the classic JSX transform, so add `import React from "react"` in `.tsx` tests. For a component that reads Pylon data hooks, **mock the boundary**, then dynamic-`import` the component so the mock is in place first:
|
|
56
|
+
|
|
57
|
+
```tsx
|
|
58
|
+
import { test, expect, mock } from "bun:test";
|
|
59
|
+
import React from "react";
|
|
60
|
+
import { render, screen } from "@testing-library/react";
|
|
61
|
+
|
|
62
|
+
mock.module("@pylonsync/react", () => ({
|
|
63
|
+
db: { useQuery: () => ({ data: [{ id: "1", name: "Acme" }], loading: false }) },
|
|
64
|
+
}));
|
|
65
|
+
const { OrgList } = await import("../app/orgs/org-list"); // your component
|
|
66
|
+
|
|
67
|
+
test("renders orgs from the query", () => {
|
|
68
|
+
render(<OrgList />);
|
|
69
|
+
expect(screen.getByText("Acme")).toBeDefined();
|
|
70
|
+
});
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**Tier 3 — functions over HTTP (only when Tier 1 can't cover it).** A handler's full behavior (policies, `ctx.db`, auth) lives in the running app. Start `pylon dev` in another terminal and call the API; `resetDb()` from `@pylonsync/functions` clears the in-memory DB between cases (no-ops if the server's down, refuses production).
|
|
56
74
|
|
|
57
75
|
```ts
|
|
58
76
|
import { afterEach, expect, test } from "bun:test";
|
|
@@ -61,16 +79,14 @@ import { resetDb } from "@pylonsync/functions";
|
|
|
61
79
|
const BASE = "http://localhost:4321";
|
|
62
80
|
afterEach(() => resetDb(BASE)); // or installTestIsolation(BASE) once at top-of-file
|
|
63
81
|
|
|
64
|
-
test("createThing then it
|
|
65
|
-
const
|
|
82
|
+
test("createThing then read it back", async () => {
|
|
83
|
+
const t = await fetch(`${BASE}/api/fn/createThing`, {
|
|
66
84
|
method: "POST",
|
|
67
85
|
headers: { "Content-Type": "application/json" },
|
|
68
86
|
body: JSON.stringify({ name: "hello" }),
|
|
69
87
|
}).then((r) => r.json());
|
|
70
|
-
expect(created.name).toBe("hello");
|
|
71
|
-
|
|
72
88
|
const rows = await fetch(`${BASE}/api/entities/Thing`).then((r) => r.json());
|
|
73
|
-
expect(rows.some((
|
|
89
|
+
expect(rows.some((r: { id: string }) => r.id === t.id)).toBe(true);
|
|
74
90
|
});
|
|
75
91
|
```
|
|
76
92
|
|
|
@@ -97,4 +113,4 @@ test("createThing then it shows up", async () => {
|
|
|
97
113
|
|
|
98
114
|
`--json` works on every command for machine-readable output. Prefer one-shot/agent-safe flags (`pylon logs --limit N`, not a blocking `--follow`).
|
|
99
115
|
|
|
100
|
-
For full signatures, env vars, the complete CLI, and SSR/client/server-primitive details:
|
|
116
|
+
For full signatures, env vars, the complete CLI, and SSR/client/server-primitive details: **https://docs.pylonsync.com/llms-full.txt**.
|
|
@@ -28,6 +28,9 @@
|
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"@pylonsync/cli": "^__PYLON_VERSION__",
|
|
31
|
+
"@happy-dom/global-registrator": "^20.10.0",
|
|
32
|
+
"@testing-library/dom": "^10.4.0",
|
|
33
|
+
"@testing-library/react": "^16.3.0",
|
|
31
34
|
"@types/node": "^22.0.0",
|
|
32
35
|
"@types/react": "^19.0.0",
|
|
33
36
|
"@types/react-dom": "^19.0.0",
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { afterEach, expect, test } from "bun:test";
|
|
2
|
+
// This project uses the classic JSX transform, so .tsx tests import React.
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { render, screen, cleanup } from "@testing-library/react";
|
|
5
|
+
import { Button } from "../components/ui/button";
|
|
6
|
+
|
|
7
|
+
afterEach(cleanup);
|
|
8
|
+
|
|
9
|
+
// A React component test. happy-dom + @testing-library/react are wired via
|
|
10
|
+
// bunfig.toml — render a component and assert on the DOM. For a component that
|
|
11
|
+
// reads Pylon data hooks (db.useQuery, callFn), mock the boundary first — see
|
|
12
|
+
// AGENTS.md → Testing (Tier 2).
|
|
13
|
+
test("Button renders its label", () => {
|
|
14
|
+
render(<Button>Click me</Button>);
|
|
15
|
+
expect(screen.getByRole("button", { name: "Click me" })).toBeDefined();
|
|
16
|
+
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# AGENTS.md — working in a Pylon project
|
|
2
2
|
|
|
3
|
-
Operating rules for a coding agent in this Pylon app. Pylon is a Rails-like framework for realtime apps: you declare entities, policies, and server functions in TypeScript, and a single Rust binary (`pylon`) serves the API, auth, sync, WebSocket, SSE, and native React 19 SSR — one process, one port. The full API reference is
|
|
3
|
+
Operating rules for a coding agent in this Pylon app. Pylon is a Rails-like framework for realtime apps: you declare entities, policies, and server functions in TypeScript, and a single Rust binary (`pylon`) serves the API, auth, sync, WebSocket, SSE, and native React 19 SSR — one process, one port. The full API reference is the **llms-full.txt** at https://docs.pylonsync.com/llms-full.txt. Read it before guessing an API name.
|
|
4
4
|
|
|
5
5
|
## Directory conventions
|
|
6
6
|
|
|
@@ -39,9 +39,9 @@ Operating rules for a coding agent in this Pylon app. Pylon is a Rails-like fram
|
|
|
39
39
|
|
|
40
40
|
## Testing
|
|
41
41
|
|
|
42
|
-
`pylon test` discovers every `*.test.ts`
|
|
42
|
+
`pylon test` discovers every `*.test.ts` / `*.test.tsx` file under `tests/` (or `functions/`) and runs it with **Bun's test runner** (`import { test, expect } from "bun:test"`). Run the suite with `pylon test` (or `npm test`); filter with `pylon test <substring>`. This template ships `bunfig.toml` + `tests/setup.ts` (registers happy-dom) so component tests render out of the box, plus starter tests under `tests/` — replace them with your own.
|
|
43
43
|
|
|
44
|
-
**
|
|
44
|
+
**Tier 1 — pure logic (reach for this first).** Keep the decisions that matter — access/plan gating, pricing, credit math, validation, formatting — in pure functions in `lib/`, and test those exhaustively. No server, instant, and it's where the real bugs live. Keep your `query`/`mutation`/`action` handlers as thin wrappers around them, so the logic is testable without a running app.
|
|
45
45
|
|
|
46
46
|
```ts
|
|
47
47
|
import { expect, test } from "bun:test";
|
|
@@ -52,7 +52,25 @@ test("unknown slug → undefined", () => {
|
|
|
52
52
|
});
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
-
**
|
|
55
|
+
**Tier 2 — React components.** `@testing-library/react` + happy-dom are already wired (`tests/setup.ts`). Render and assert. The template uses the classic JSX transform, so add `import React from "react"` in `.tsx` tests. For a component that reads Pylon data hooks, **mock the boundary**, then dynamic-`import` the component so the mock is in place first:
|
|
56
|
+
|
|
57
|
+
```tsx
|
|
58
|
+
import { test, expect, mock } from "bun:test";
|
|
59
|
+
import React from "react";
|
|
60
|
+
import { render, screen } from "@testing-library/react";
|
|
61
|
+
|
|
62
|
+
mock.module("@pylonsync/react", () => ({
|
|
63
|
+
db: { useQuery: () => ({ data: [{ id: "1", name: "Acme" }], loading: false }) },
|
|
64
|
+
}));
|
|
65
|
+
const { OrgList } = await import("../app/orgs/org-list"); // your component
|
|
66
|
+
|
|
67
|
+
test("renders orgs from the query", () => {
|
|
68
|
+
render(<OrgList />);
|
|
69
|
+
expect(screen.getByText("Acme")).toBeDefined();
|
|
70
|
+
});
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**Tier 3 — functions over HTTP (only when Tier 1 can't cover it).** A handler's full behavior (policies, `ctx.db`, auth) lives in the running app. Start `pylon dev` in another terminal and call the API; `resetDb()` from `@pylonsync/functions` clears the in-memory DB between cases (no-ops if the server's down, refuses production).
|
|
56
74
|
|
|
57
75
|
```ts
|
|
58
76
|
import { afterEach, expect, test } from "bun:test";
|
|
@@ -61,16 +79,14 @@ import { resetDb } from "@pylonsync/functions";
|
|
|
61
79
|
const BASE = "http://localhost:4321";
|
|
62
80
|
afterEach(() => resetDb(BASE)); // or installTestIsolation(BASE) once at top-of-file
|
|
63
81
|
|
|
64
|
-
test("createThing then it
|
|
65
|
-
const
|
|
82
|
+
test("createThing then read it back", async () => {
|
|
83
|
+
const t = await fetch(`${BASE}/api/fn/createThing`, {
|
|
66
84
|
method: "POST",
|
|
67
85
|
headers: { "Content-Type": "application/json" },
|
|
68
86
|
body: JSON.stringify({ name: "hello" }),
|
|
69
87
|
}).then((r) => r.json());
|
|
70
|
-
expect(created.name).toBe("hello");
|
|
71
|
-
|
|
72
88
|
const rows = await fetch(`${BASE}/api/entities/Thing`).then((r) => r.json());
|
|
73
|
-
expect(rows.some((
|
|
89
|
+
expect(rows.some((r: { id: string }) => r.id === t.id)).toBe(true);
|
|
74
90
|
});
|
|
75
91
|
```
|
|
76
92
|
|
|
@@ -97,4 +113,4 @@ test("createThing then it shows up", async () => {
|
|
|
97
113
|
|
|
98
114
|
`--json` works on every command for machine-readable output. Prefer one-shot/agent-safe flags (`pylon logs --limit N`, not a blocking `--follow`).
|
|
99
115
|
|
|
100
|
-
For full signatures, env vars, the complete CLI, and SSR/client/server-primitive details:
|
|
116
|
+
For full signatures, env vars, the complete CLI, and SSR/client/server-primitive details: **https://docs.pylonsync.com/llms-full.txt**.
|
|
@@ -27,6 +27,9 @@
|
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@pylonsync/cli": "^__PYLON_VERSION__",
|
|
30
|
+
"@happy-dom/global-registrator": "^20.10.0",
|
|
31
|
+
"@testing-library/dom": "^10.4.0",
|
|
32
|
+
"@testing-library/react": "^16.3.0",
|
|
30
33
|
"@types/node": "^22.0.0",
|
|
31
34
|
"@types/react": "^19.0.0",
|
|
32
35
|
"@types/react-dom": "^19.0.0",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# AGENTS.md — working in a Pylon project
|
|
2
2
|
|
|
3
|
-
Operating rules for a coding agent in this Pylon app. Pylon is a Rails-like framework for realtime apps: you declare entities, policies, and server functions in TypeScript, and a single Rust binary (`pylon`) serves the API, auth, sync, WebSocket, SSE, and native React 19 SSR — one process, one port. The full API reference is
|
|
3
|
+
Operating rules for a coding agent in this Pylon app. Pylon is a Rails-like framework for realtime apps: you declare entities, policies, and server functions in TypeScript, and a single Rust binary (`pylon`) serves the API, auth, sync, WebSocket, SSE, and native React 19 SSR — one process, one port. The full API reference is the **llms-full.txt** at https://docs.pylonsync.com/llms-full.txt. Read it before guessing an API name.
|
|
4
4
|
|
|
5
5
|
## Directory conventions
|
|
6
6
|
|
|
@@ -39,9 +39,9 @@ Operating rules for a coding agent in this Pylon app. Pylon is a Rails-like fram
|
|
|
39
39
|
|
|
40
40
|
## Testing
|
|
41
41
|
|
|
42
|
-
`pylon test` discovers every `*.test.ts`
|
|
42
|
+
`pylon test` discovers every `*.test.ts` / `*.test.tsx` file under `tests/` (or `functions/`) and runs it with **Bun's test runner** (`import { test, expect } from "bun:test"`). Run the suite with `pylon test` (or `npm test`); filter with `pylon test <substring>`. This template ships `bunfig.toml` + `tests/setup.ts` (registers happy-dom) so component tests render out of the box, plus starter tests under `tests/` — replace them with your own.
|
|
43
43
|
|
|
44
|
-
**
|
|
44
|
+
**Tier 1 — pure logic (reach for this first).** Keep the decisions that matter — access/plan gating, pricing, credit math, validation, formatting — in pure functions in `lib/`, and test those exhaustively. No server, instant, and it's where the real bugs live. Keep your `query`/`mutation`/`action` handlers as thin wrappers around them, so the logic is testable without a running app.
|
|
45
45
|
|
|
46
46
|
```ts
|
|
47
47
|
import { expect, test } from "bun:test";
|
|
@@ -52,7 +52,25 @@ test("unknown slug → undefined", () => {
|
|
|
52
52
|
});
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
-
**
|
|
55
|
+
**Tier 2 — React components.** `@testing-library/react` + happy-dom are already wired (`tests/setup.ts`). Render and assert. The template uses the classic JSX transform, so add `import React from "react"` in `.tsx` tests. For a component that reads Pylon data hooks, **mock the boundary**, then dynamic-`import` the component so the mock is in place first:
|
|
56
|
+
|
|
57
|
+
```tsx
|
|
58
|
+
import { test, expect, mock } from "bun:test";
|
|
59
|
+
import React from "react";
|
|
60
|
+
import { render, screen } from "@testing-library/react";
|
|
61
|
+
|
|
62
|
+
mock.module("@pylonsync/react", () => ({
|
|
63
|
+
db: { useQuery: () => ({ data: [{ id: "1", name: "Acme" }], loading: false }) },
|
|
64
|
+
}));
|
|
65
|
+
const { OrgList } = await import("../app/orgs/org-list"); // your component
|
|
66
|
+
|
|
67
|
+
test("renders orgs from the query", () => {
|
|
68
|
+
render(<OrgList />);
|
|
69
|
+
expect(screen.getByText("Acme")).toBeDefined();
|
|
70
|
+
});
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**Tier 3 — functions over HTTP (only when Tier 1 can't cover it).** A handler's full behavior (policies, `ctx.db`, auth) lives in the running app. Start `pylon dev` in another terminal and call the API; `resetDb()` from `@pylonsync/functions` clears the in-memory DB between cases (no-ops if the server's down, refuses production).
|
|
56
74
|
|
|
57
75
|
```ts
|
|
58
76
|
import { afterEach, expect, test } from "bun:test";
|
|
@@ -61,16 +79,14 @@ import { resetDb } from "@pylonsync/functions";
|
|
|
61
79
|
const BASE = "http://localhost:4321";
|
|
62
80
|
afterEach(() => resetDb(BASE)); // or installTestIsolation(BASE) once at top-of-file
|
|
63
81
|
|
|
64
|
-
test("createThing then it
|
|
65
|
-
const
|
|
82
|
+
test("createThing then read it back", async () => {
|
|
83
|
+
const t = await fetch(`${BASE}/api/fn/createThing`, {
|
|
66
84
|
method: "POST",
|
|
67
85
|
headers: { "Content-Type": "application/json" },
|
|
68
86
|
body: JSON.stringify({ name: "hello" }),
|
|
69
87
|
}).then((r) => r.json());
|
|
70
|
-
expect(created.name).toBe("hello");
|
|
71
|
-
|
|
72
88
|
const rows = await fetch(`${BASE}/api/entities/Thing`).then((r) => r.json());
|
|
73
|
-
expect(rows.some((
|
|
89
|
+
expect(rows.some((r: { id: string }) => r.id === t.id)).toBe(true);
|
|
74
90
|
});
|
|
75
91
|
```
|
|
76
92
|
|
|
@@ -97,4 +113,4 @@ test("createThing then it shows up", async () => {
|
|
|
97
113
|
|
|
98
114
|
`--json` works on every command for machine-readable output. Prefer one-shot/agent-safe flags (`pylon logs --limit N`, not a blocking `--follow`).
|
|
99
115
|
|
|
100
|
-
For full signatures, env vars, the complete CLI, and SSR/client/server-primitive details:
|
|
116
|
+
For full signatures, env vars, the complete CLI, and SSR/client/server-primitive details: **https://docs.pylonsync.com/llms-full.txt**.
|
|
@@ -27,6 +27,9 @@
|
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@pylonsync/cli": "^__PYLON_VERSION__",
|
|
30
|
+
"@happy-dom/global-registrator": "^20.10.0",
|
|
31
|
+
"@testing-library/dom": "^10.4.0",
|
|
32
|
+
"@testing-library/react": "^16.3.0",
|
|
30
33
|
"@types/node": "^22.0.0",
|
|
31
34
|
"@types/react": "^19.0.0",
|
|
32
35
|
"@types/react-dom": "^19.0.0",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# AGENTS.md — working in a Pylon project
|
|
2
2
|
|
|
3
|
-
Operating rules for a coding agent in this Pylon app. Pylon is a Rails-like framework for realtime apps: you declare entities, policies, and server functions in TypeScript, and a single Rust binary (`pylon`) serves the API, auth, sync, WebSocket, SSE, and native React 19 SSR — one process, one port. The full API reference is
|
|
3
|
+
Operating rules for a coding agent in this Pylon app. Pylon is a Rails-like framework for realtime apps: you declare entities, policies, and server functions in TypeScript, and a single Rust binary (`pylon`) serves the API, auth, sync, WebSocket, SSE, and native React 19 SSR — one process, one port. The full API reference is the **llms-full.txt** at https://docs.pylonsync.com/llms-full.txt. Read it before guessing an API name.
|
|
4
4
|
|
|
5
5
|
## Directory conventions
|
|
6
6
|
|
|
@@ -39,9 +39,9 @@ Operating rules for a coding agent in this Pylon app. Pylon is a Rails-like fram
|
|
|
39
39
|
|
|
40
40
|
## Testing
|
|
41
41
|
|
|
42
|
-
`pylon test` discovers every `*.test.ts`
|
|
42
|
+
`pylon test` discovers every `*.test.ts` / `*.test.tsx` file under `tests/` (or `functions/`) and runs it with **Bun's test runner** (`import { test, expect } from "bun:test"`). Run the suite with `pylon test` (or `npm test`); filter with `pylon test <substring>`. This template ships `bunfig.toml` + `tests/setup.ts` (registers happy-dom) so component tests render out of the box, plus starter tests under `tests/` — replace them with your own.
|
|
43
43
|
|
|
44
|
-
**
|
|
44
|
+
**Tier 1 — pure logic (reach for this first).** Keep the decisions that matter — access/plan gating, pricing, credit math, validation, formatting — in pure functions in `lib/`, and test those exhaustively. No server, instant, and it's where the real bugs live. Keep your `query`/`mutation`/`action` handlers as thin wrappers around them, so the logic is testable without a running app.
|
|
45
45
|
|
|
46
46
|
```ts
|
|
47
47
|
import { expect, test } from "bun:test";
|
|
@@ -52,7 +52,25 @@ test("unknown slug → undefined", () => {
|
|
|
52
52
|
});
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
-
**
|
|
55
|
+
**Tier 2 — React components.** `@testing-library/react` + happy-dom are already wired (`tests/setup.ts`). Render and assert. The template uses the classic JSX transform, so add `import React from "react"` in `.tsx` tests. For a component that reads Pylon data hooks, **mock the boundary**, then dynamic-`import` the component so the mock is in place first:
|
|
56
|
+
|
|
57
|
+
```tsx
|
|
58
|
+
import { test, expect, mock } from "bun:test";
|
|
59
|
+
import React from "react";
|
|
60
|
+
import { render, screen } from "@testing-library/react";
|
|
61
|
+
|
|
62
|
+
mock.module("@pylonsync/react", () => ({
|
|
63
|
+
db: { useQuery: () => ({ data: [{ id: "1", name: "Acme" }], loading: false }) },
|
|
64
|
+
}));
|
|
65
|
+
const { OrgList } = await import("../app/orgs/org-list"); // your component
|
|
66
|
+
|
|
67
|
+
test("renders orgs from the query", () => {
|
|
68
|
+
render(<OrgList />);
|
|
69
|
+
expect(screen.getByText("Acme")).toBeDefined();
|
|
70
|
+
});
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**Tier 3 — functions over HTTP (only when Tier 1 can't cover it).** A handler's full behavior (policies, `ctx.db`, auth) lives in the running app. Start `pylon dev` in another terminal and call the API; `resetDb()` from `@pylonsync/functions` clears the in-memory DB between cases (no-ops if the server's down, refuses production).
|
|
56
74
|
|
|
57
75
|
```ts
|
|
58
76
|
import { afterEach, expect, test } from "bun:test";
|
|
@@ -61,16 +79,14 @@ import { resetDb } from "@pylonsync/functions";
|
|
|
61
79
|
const BASE = "http://localhost:4321";
|
|
62
80
|
afterEach(() => resetDb(BASE)); // or installTestIsolation(BASE) once at top-of-file
|
|
63
81
|
|
|
64
|
-
test("createThing then it
|
|
65
|
-
const
|
|
82
|
+
test("createThing then read it back", async () => {
|
|
83
|
+
const t = await fetch(`${BASE}/api/fn/createThing`, {
|
|
66
84
|
method: "POST",
|
|
67
85
|
headers: { "Content-Type": "application/json" },
|
|
68
86
|
body: JSON.stringify({ name: "hello" }),
|
|
69
87
|
}).then((r) => r.json());
|
|
70
|
-
expect(created.name).toBe("hello");
|
|
71
|
-
|
|
72
88
|
const rows = await fetch(`${BASE}/api/entities/Thing`).then((r) => r.json());
|
|
73
|
-
expect(rows.some((
|
|
89
|
+
expect(rows.some((r: { id: string }) => r.id === t.id)).toBe(true);
|
|
74
90
|
});
|
|
75
91
|
```
|
|
76
92
|
|
|
@@ -97,4 +113,4 @@ test("createThing then it shows up", async () => {
|
|
|
97
113
|
|
|
98
114
|
`--json` works on every command for machine-readable output. Prefer one-shot/agent-safe flags (`pylon logs --limit N`, not a blocking `--follow`).
|
|
99
115
|
|
|
100
|
-
For full signatures, env vars, the complete CLI, and SSR/client/server-primitive details:
|
|
116
|
+
For full signatures, env vars, the complete CLI, and SSR/client/server-primitive details: **https://docs.pylonsync.com/llms-full.txt**.
|
|
@@ -27,6 +27,9 @@
|
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@pylonsync/cli": "^__PYLON_VERSION__",
|
|
30
|
+
"@happy-dom/global-registrator": "^20.10.0",
|
|
31
|
+
"@testing-library/dom": "^10.4.0",
|
|
32
|
+
"@testing-library/react": "^16.3.0",
|
|
30
33
|
"@types/react": "^19.0.0",
|
|
31
34
|
"@types/react-dom": "^19.0.0",
|
|
32
35
|
"typescript": "^5.6.0"
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { afterEach, expect, test } from "bun:test";
|
|
2
|
+
// This project uses the classic JSX transform, so .tsx tests import React.
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { render, screen, cleanup } from "@testing-library/react";
|
|
5
|
+
import { Button } from "../components/ui/button";
|
|
6
|
+
|
|
7
|
+
afterEach(cleanup);
|
|
8
|
+
|
|
9
|
+
// A React component test. happy-dom + @testing-library/react are wired via
|
|
10
|
+
// bunfig.toml — render a component and assert on the DOM. For a component that
|
|
11
|
+
// reads Pylon data hooks (db.useQuery, callFn), mock the boundary first — see
|
|
12
|
+
// AGENTS.md → Testing (Tier 2).
|
|
13
|
+
test("Button renders its label", () => {
|
|
14
|
+
render(<Button>Click me</Button>);
|
|
15
|
+
expect(screen.getByRole("button", { name: "Click me" })).toBeDefined();
|
|
16
|
+
});
|
package/templates/chat/AGENTS.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# AGENTS.md — working in a Pylon project
|
|
2
2
|
|
|
3
|
-
Operating rules for a coding agent in this Pylon app. Pylon is a Rails-like framework for realtime apps: you declare entities, policies, and server functions in TypeScript, and a single Rust binary (`pylon`) serves the API, auth, sync, WebSocket, SSE, and native React 19 SSR — one process, one port. The full API reference is
|
|
3
|
+
Operating rules for a coding agent in this Pylon app. Pylon is a Rails-like framework for realtime apps: you declare entities, policies, and server functions in TypeScript, and a single Rust binary (`pylon`) serves the API, auth, sync, WebSocket, SSE, and native React 19 SSR — one process, one port. The full API reference is the **llms-full.txt** at https://docs.pylonsync.com/llms-full.txt. Read it before guessing an API name.
|
|
4
4
|
|
|
5
5
|
## Directory conventions
|
|
6
6
|
|
|
@@ -39,9 +39,9 @@ Operating rules for a coding agent in this Pylon app. Pylon is a Rails-like fram
|
|
|
39
39
|
|
|
40
40
|
## Testing
|
|
41
41
|
|
|
42
|
-
`pylon test` discovers every `*.test.ts`
|
|
42
|
+
`pylon test` discovers every `*.test.ts` / `*.test.tsx` file under `tests/` (or `functions/`) and runs it with **Bun's test runner** (`import { test, expect } from "bun:test"`). Run the suite with `pylon test` (or `npm test`); filter with `pylon test <substring>`. This template ships `bunfig.toml` + `tests/setup.ts` (registers happy-dom) so component tests render out of the box, plus starter tests under `tests/` — replace them with your own.
|
|
43
43
|
|
|
44
|
-
**
|
|
44
|
+
**Tier 1 — pure logic (reach for this first).** Keep the decisions that matter — access/plan gating, pricing, credit math, validation, formatting — in pure functions in `lib/`, and test those exhaustively. No server, instant, and it's where the real bugs live. Keep your `query`/`mutation`/`action` handlers as thin wrappers around them, so the logic is testable without a running app.
|
|
45
45
|
|
|
46
46
|
```ts
|
|
47
47
|
import { expect, test } from "bun:test";
|
|
@@ -52,7 +52,25 @@ test("unknown slug → undefined", () => {
|
|
|
52
52
|
});
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
-
**
|
|
55
|
+
**Tier 2 — React components.** `@testing-library/react` + happy-dom are already wired (`tests/setup.ts`). Render and assert. The template uses the classic JSX transform, so add `import React from "react"` in `.tsx` tests. For a component that reads Pylon data hooks, **mock the boundary**, then dynamic-`import` the component so the mock is in place first:
|
|
56
|
+
|
|
57
|
+
```tsx
|
|
58
|
+
import { test, expect, mock } from "bun:test";
|
|
59
|
+
import React from "react";
|
|
60
|
+
import { render, screen } from "@testing-library/react";
|
|
61
|
+
|
|
62
|
+
mock.module("@pylonsync/react", () => ({
|
|
63
|
+
db: { useQuery: () => ({ data: [{ id: "1", name: "Acme" }], loading: false }) },
|
|
64
|
+
}));
|
|
65
|
+
const { OrgList } = await import("../app/orgs/org-list"); // your component
|
|
66
|
+
|
|
67
|
+
test("renders orgs from the query", () => {
|
|
68
|
+
render(<OrgList />);
|
|
69
|
+
expect(screen.getByText("Acme")).toBeDefined();
|
|
70
|
+
});
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**Tier 3 — functions over HTTP (only when Tier 1 can't cover it).** A handler's full behavior (policies, `ctx.db`, auth) lives in the running app. Start `pylon dev` in another terminal and call the API; `resetDb()` from `@pylonsync/functions` clears the in-memory DB between cases (no-ops if the server's down, refuses production).
|
|
56
74
|
|
|
57
75
|
```ts
|
|
58
76
|
import { afterEach, expect, test } from "bun:test";
|
|
@@ -61,16 +79,14 @@ import { resetDb } from "@pylonsync/functions";
|
|
|
61
79
|
const BASE = "http://localhost:4321";
|
|
62
80
|
afterEach(() => resetDb(BASE)); // or installTestIsolation(BASE) once at top-of-file
|
|
63
81
|
|
|
64
|
-
test("createThing then it
|
|
65
|
-
const
|
|
82
|
+
test("createThing then read it back", async () => {
|
|
83
|
+
const t = await fetch(`${BASE}/api/fn/createThing`, {
|
|
66
84
|
method: "POST",
|
|
67
85
|
headers: { "Content-Type": "application/json" },
|
|
68
86
|
body: JSON.stringify({ name: "hello" }),
|
|
69
87
|
}).then((r) => r.json());
|
|
70
|
-
expect(created.name).toBe("hello");
|
|
71
|
-
|
|
72
88
|
const rows = await fetch(`${BASE}/api/entities/Thing`).then((r) => r.json());
|
|
73
|
-
expect(rows.some((
|
|
89
|
+
expect(rows.some((r: { id: string }) => r.id === t.id)).toBe(true);
|
|
74
90
|
});
|
|
75
91
|
```
|
|
76
92
|
|
|
@@ -97,4 +113,4 @@ test("createThing then it shows up", async () => {
|
|
|
97
113
|
|
|
98
114
|
`--json` works on every command for machine-readable output. Prefer one-shot/agent-safe flags (`pylon logs --limit N`, not a blocking `--follow`).
|
|
99
115
|
|
|
100
|
-
For full signatures, env vars, the complete CLI, and SSR/client/server-primitive details:
|
|
116
|
+
For full signatures, env vars, the complete CLI, and SSR/client/server-primitive details: **https://docs.pylonsync.com/llms-full.txt**.
|
|
@@ -27,6 +27,9 @@
|
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@pylonsync/cli": "^__PYLON_VERSION__",
|
|
30
|
+
"@happy-dom/global-registrator": "^20.10.0",
|
|
31
|
+
"@testing-library/dom": "^10.4.0",
|
|
32
|
+
"@testing-library/react": "^16.3.0",
|
|
30
33
|
"@types/react": "^19.0.0",
|
|
31
34
|
"@types/react-dom": "^19.0.0",
|
|
32
35
|
"typescript": "^5.6.0"
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { afterEach, expect, test } from "bun:test";
|
|
2
|
+
// This project uses the classic JSX transform, so .tsx tests import React.
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { render, screen, cleanup } from "@testing-library/react";
|
|
5
|
+
import { Button } from "../components/ui/button";
|
|
6
|
+
|
|
7
|
+
afterEach(cleanup);
|
|
8
|
+
|
|
9
|
+
// A React component test. happy-dom + @testing-library/react are wired via
|
|
10
|
+
// bunfig.toml — render a component and assert on the DOM. For a component that
|
|
11
|
+
// reads Pylon data hooks (db.useQuery, callFn), mock the boundary first — see
|
|
12
|
+
// AGENTS.md → Testing (Tier 2).
|
|
13
|
+
test("Button renders its label", () => {
|
|
14
|
+
render(<Button>Click me</Button>);
|
|
15
|
+
expect(screen.getByRole("button", { name: "Click me" })).toBeDefined();
|
|
16
|
+
});
|