@forgeailab/create-spark 0.1.2 → 0.2.0
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/.claude/skills/architecture-cutline/SKILL.md +96 -0
- package/.claude/skills/board-review/SKILL.md +77 -0
- package/.claude/skills/code-review/SKILL.md +76 -0
- package/.claude/skills/execute-task/SKILL.md +80 -0
- package/.claude/skills/idea-sharpen/SKILL.md +65 -0
- package/.claude/skills/implementation-brief/SKILL.md +87 -0
- package/.claude/skills/mvp-board/SKILL.md +95 -0
- package/.claude/skills/mvp-grill/SKILL.md +60 -0
- package/.claude/skills/mvp-spec/SKILL.md +78 -0
- package/.claude/skills/new-pack/SKILL.md +156 -0
- package/.claude/skills/next-task/SKILL.md +65 -0
- package/.claude/skills/pack-add/SKILL.md +64 -0
- package/.claude/skills/pack-resolve/SKILL.md +67 -0
- package/.claude/skills/parallel-execution/SKILL.md +68 -0
- package/.claude/skills/qa-verify/SKILL.md +77 -0
- package/.claude/skills/risk-check/SKILL.md +88 -0
- package/.claude/skills/sync-board/SKILL.md +76 -0
- package/.claude/skills/ux-theme/SKILL.md +93 -0
- package/.codex/skills/architecture-cutline/SKILL.md +94 -0
- package/.codex/skills/board-review/SKILL.md +75 -0
- package/.codex/skills/code-review/SKILL.md +73 -0
- package/.codex/skills/execute-task/SKILL.md +76 -0
- package/.codex/skills/idea-sharpen/SKILL.md +63 -0
- package/.codex/skills/implementation-brief/SKILL.md +85 -0
- package/.codex/skills/mvp-board/SKILL.md +93 -0
- package/.codex/skills/mvp-grill/SKILL.md +58 -0
- package/.codex/skills/mvp-spec/SKILL.md +76 -0
- package/.codex/skills/new-pack/SKILL.md +153 -0
- package/.codex/skills/next-task/SKILL.md +64 -0
- package/.codex/skills/pack-add/SKILL.md +62 -0
- package/.codex/skills/pack-resolve/SKILL.md +65 -0
- package/.codex/skills/parallel-execution/SKILL.md +66 -0
- package/.codex/skills/qa-verify/SKILL.md +74 -0
- package/.codex/skills/risk-check/SKILL.md +86 -0
- package/.codex/skills/sync-board/SKILL.md +72 -0
- package/.codex/skills/ux-theme/SKILL.md +91 -0
- package/package.json +8 -5
- package/packs/README.md +22 -24
- package/packs/ai-anthropic/files/lib/anthropic.ts +46 -3
- package/packs/ai-anthropic/pack.toml +2 -3
- package/packs/auth-better-auth/files/app/api/auth/[...all]/route.ts +2 -2
- package/packs/auth-better-auth/files/lib/auth.ts +40 -1
- package/packs/auth-better-auth/pack.toml +1 -5
- package/packs/auth-better-auth-pg/files/app/api/auth/[...all]/route.ts +2 -2
- package/packs/auth-better-auth-pg/files/lib/auth.ts +40 -1
- package/packs/auth-better-auth-pg/pack.toml +1 -5
- package/packs/payments-stripe/files/lib/stripe.ts +104 -6
- package/packs/payments-stripe/pack.toml +1 -5
- package/packs/sync-zero/files/components/ZeroProvider.tsx +11 -1
- package/packs/sync-zero/files/lib/zero/client.ts +3 -3
- package/packs/sync-zero/files/lib/zero/schema.ts +15 -2
- package/packs/sync-zero/pack.toml +0 -4
- package/scripts/sync-skills.ts +223 -0
- /package/templates/nextjs/{anvil.config.json → spark.config.json} +0 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: qa-verify
|
|
3
|
+
description: Verify the app actually runs and the feature works end-to-end, not just that code compiles. Use after a feature batch lands, before a demo, when the user says "does this actually work?", "run it and check", or before flipping a task to `Validated`. Do NOT use as a substitute for `/code-review` — they cover different failure modes.
|
|
4
|
+
# Generated from .claude/skills/qa-verify/SKILL.md — DO NOT EDIT directly
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Skill: qa-verify
|
|
8
|
+
|
|
9
|
+
## Goal
|
|
10
|
+
|
|
11
|
+
Boot the app, click through the real user flow, and confirm the acceptance criteria hold when humans actually use the product. Type-checks and unit tests pass != feature works.
|
|
12
|
+
|
|
13
|
+
## Recommended model
|
|
14
|
+
|
|
15
|
+
Sonnet 4.6. This is execution, not judgment.
|
|
16
|
+
|
|
17
|
+
## Inputs
|
|
18
|
+
|
|
19
|
+
Read these (required):
|
|
20
|
+
|
|
21
|
+
- `.ai/board.md` — task(s) being verified
|
|
22
|
+
- `.ai/product-spec.md` — the core user journey
|
|
23
|
+
|
|
24
|
+
Read if useful:
|
|
25
|
+
|
|
26
|
+
- `.ai/ux-theme.md` for empty / loading / error patterns
|
|
27
|
+
- `README.md` / `package.json` for the run command
|
|
28
|
+
|
|
29
|
+
## Rules
|
|
30
|
+
|
|
31
|
+
- Always run the app. If you cannot launch it, report that explicitly — do not claim verification from reading code.
|
|
32
|
+
- Walk the **core user journey from `product-spec.md`**, not just the changed feature. Regressions in adjacent flows count.
|
|
33
|
+
- Check empty / loading / error / mobile states for every screen touched. MVPs feel broken at the seams, not the happy path.
|
|
34
|
+
- Capture exact commands and outputs so the user can reproduce.
|
|
35
|
+
- Use a real browser or device when relevant (Playwright MCP if available). Curl-ing an API endpoint is not UI verification.
|
|
36
|
+
|
|
37
|
+
## Workflow
|
|
38
|
+
|
|
39
|
+
1. Find the run command (project README, `package.json` scripts, or ask).
|
|
40
|
+
2. Boot the app. Note the URL.
|
|
41
|
+
3. Walk the core journey step by step from the spec.
|
|
42
|
+
4. Re-walk the specific feature(s) from the task(s).
|
|
43
|
+
5. Probe empty / loading / error / mobile.
|
|
44
|
+
6. Write the report.
|
|
45
|
+
|
|
46
|
+
## Output format
|
|
47
|
+
|
|
48
|
+
```md
|
|
49
|
+
## QA verification — <TASK-ID(s)> / <feature name>
|
|
50
|
+
|
|
51
|
+
### Boot
|
|
52
|
+
- Command: `<cmd>`
|
|
53
|
+
- Result: app running at <url> | failed (<reason>)
|
|
54
|
+
|
|
55
|
+
### Core user journey (from spec)
|
|
56
|
+
- [x|✗] Step 1: <description> — <observation>
|
|
57
|
+
- [x|✗] Step 2: ...
|
|
58
|
+
|
|
59
|
+
### Feature-specific checks
|
|
60
|
+
- [x|✗] <acceptance criterion> — <observation>
|
|
61
|
+
|
|
62
|
+
### Edge states
|
|
63
|
+
- Empty state: <ok | broken | missing>
|
|
64
|
+
- Loading state: <ok | broken | missing>
|
|
65
|
+
- Error state: <ok | broken | missing>
|
|
66
|
+
- Mobile / narrow viewport: <ok | broken>
|
|
67
|
+
|
|
68
|
+
### Broken flows discovered
|
|
69
|
+
- <one-line description> — <repro steps>
|
|
70
|
+
|
|
71
|
+
### Recommended board update
|
|
72
|
+
- <TASK-ID>: review → Validated | review → In progress
|
|
73
|
+
- New tasks to add: <list or none>
|
|
74
|
+
```
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: risk-check
|
|
3
|
+
description: Detect whether the project is drifting — scope creep, architecture creep, hidden dependencies, missing tests, unclear tasks, plus stale hybrid-pack helper versions (more than two minor versions behind the latest published). Use every few sessions, when the user says "are we on track?", "is this getting out of hand?", or before a demo. The anti-overthinking and anti-feature-creep skill.
|
|
4
|
+
# Generated from .claude/skills/risk-check/SKILL.md — DO NOT EDIT directly
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Skill: risk-check
|
|
8
|
+
|
|
9
|
+
## Goal
|
|
10
|
+
|
|
11
|
+
Be the brake. Compare the current state of the project to the spec and architecture, and call out where reality is drifting. Recommend concrete cuts.
|
|
12
|
+
|
|
13
|
+
## Recommended model
|
|
14
|
+
|
|
15
|
+
Opus 4.7 or GPT-5.5.
|
|
16
|
+
|
|
17
|
+
## Inputs
|
|
18
|
+
|
|
19
|
+
Read these (required):
|
|
20
|
+
|
|
21
|
+
- `.ai/product-spec.md`
|
|
22
|
+
- `.ai/architecture.md`
|
|
23
|
+
- `.ai/board.md`
|
|
24
|
+
- `.ai/decision-log.md` if it exists
|
|
25
|
+
- `.spark/state.json` if it exists
|
|
26
|
+
- `packs/*/pack.toml` if pack state exists and the registry is available
|
|
27
|
+
|
|
28
|
+
Sample reality:
|
|
29
|
+
|
|
30
|
+
- `git log --oneline -30`
|
|
31
|
+
- top-level directory listing
|
|
32
|
+
- list of dependencies in `package.json` / `pyproject.toml` / equivalent
|
|
33
|
+
|
|
34
|
+
## Rules
|
|
35
|
+
|
|
36
|
+
- Compare **what is in the code now** to **what the spec said**. Highlight gaps in both directions: missing must-haves, plus things built that the spec did not ask for.
|
|
37
|
+
- Treat the spec's non-goals list as a checklist of things that should NOT be present in code. Violations are creep, not features.
|
|
38
|
+
- Recommend cuts, not additions. The default fix is "remove or defer," not "build more."
|
|
39
|
+
- Distinguish **drift** (planned scope grew quietly) from **discovery** (new task properly added to the board). Discovery is fine; silent drift is not.
|
|
40
|
+
- For pack-level drift, inspect `.spark/state.json` when present. For each installed pack, determine its provided capabilities from state or from `packs/<name>/pack.toml`; if none of those capabilities are referenced in `.ai/product-spec.md` or `.ai/architecture.md`, flag it as drift.
|
|
41
|
+
- The pack-level drift recommendation is exactly: **review or revert the pack-install commit via git**. Do not suggest a CLI removal command; v1 has no pack uninstall flow.
|
|
42
|
+
- For each installed pack whose manifest declares `[runtime_package]` (hybrid pack), inspect the consumer project's `package.json` (`dependencies` + `devDependencies`) for the named helper. Compare the installed version against the latest published version on the npm registry (use `bun pm view <pkg> version` or `npm view <pkg> version` via Bash). If the installed version is more than two minor versions behind the latest, flag it under "Stale helper". A `file:` specifier counts as "local dev link" and is NOT stale.
|
|
43
|
+
|
|
44
|
+
## Checklist
|
|
45
|
+
|
|
46
|
+
- **Scope creep** — features in code that are not in `MVP feature list`, or are in `Non-goals`.
|
|
47
|
+
- **Architecture creep** — services / dependencies / abstractions beyond what `architecture.md` declared.
|
|
48
|
+
- **Pack-level drift** — installed packs whose provided capabilities are not justified by the spec or architecture.
|
|
49
|
+
- **Stale helper** — hybrid packs whose helper package is more than two minor versions behind the latest on npm.
|
|
50
|
+
- **Unclear tasks** — open board tasks without observable acceptance criteria.
|
|
51
|
+
- **Missing tests / verification** — tasks marked `Validated` with no run command or no review.
|
|
52
|
+
- **Hidden dependencies** — packages added not justified by a task or decision.
|
|
53
|
+
- **Stalled tasks** — tasks in `In progress` for more than ~2 sessions with no commits.
|
|
54
|
+
|
|
55
|
+
## Output format
|
|
56
|
+
|
|
57
|
+
```md
|
|
58
|
+
## Pack-level drift
|
|
59
|
+
- no drift detected
|
|
60
|
+
- <pack-name>: provides <capability tag(s)>; none are referenced in `.ai/product-spec.md` or `.ai/architecture.md` — **recommend: review or revert the pack-install commit via git**
|
|
61
|
+
|
|
62
|
+
## Stale helper
|
|
63
|
+
- no stale helpers
|
|
64
|
+
- <pack-name>: helper `<helper-package>` installed at <installed-version>, latest is <latest-version> — **recommend: `bun update <helper-package>`**
|
|
65
|
+
|
|
66
|
+
## Risk check
|
|
67
|
+
|
|
68
|
+
### Scope creep
|
|
69
|
+
- <thing built / in progress> — not in spec / in non-goals — **recommend: cut | defer | keep with decision log entry**
|
|
70
|
+
|
|
71
|
+
### Architecture creep
|
|
72
|
+
- <new service / dep / abstraction> — **recommend: revert | document in architecture.md**
|
|
73
|
+
|
|
74
|
+
### Unclear tasks
|
|
75
|
+
- <TASK-ID>: criteria are vague — **recommend: rewrite or send to `/board-review`**
|
|
76
|
+
|
|
77
|
+
### Hidden dependencies
|
|
78
|
+
- <package> added in <commit> — justification: <none | <task>>
|
|
79
|
+
|
|
80
|
+
### Stalled tasks
|
|
81
|
+
- <TASK-ID>: in progress since <when> — **recommend: split | unblock | drop**
|
|
82
|
+
|
|
83
|
+
### Summary
|
|
84
|
+
- Drift severity: low | medium | high
|
|
85
|
+
- Suggested next action: <one line>
|
|
86
|
+
```
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sync-board
|
|
3
|
+
description: Update `.ai/board.md` to reflect actual code progress — apply status changes from execution reports, add discovered tasks, and recommend the next batch. Use after `/execute-task`, at the end of a working session, or when the user says "update the board", "sync progress", "what's next?". Do NOT use to create the initial board — that is `/mvp-board`.
|
|
4
|
+
# Generated from .claude/skills/sync-board/SKILL.md — DO NOT EDIT directly
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Skill: sync-board
|
|
8
|
+
|
|
9
|
+
## Goal
|
|
10
|
+
|
|
11
|
+
Keep `.ai/board.md` in sync with reality. The board is the source of truth — if it drifts from what is actually built, the whole system breaks.
|
|
12
|
+
|
|
13
|
+
## Recommended model
|
|
14
|
+
|
|
15
|
+
Sonnet 4.6. This is mechanical reconciliation, not planning.
|
|
16
|
+
|
|
17
|
+
## Inputs
|
|
18
|
+
|
|
19
|
+
Read these (required):
|
|
20
|
+
|
|
21
|
+
- `.ai/board.md`
|
|
22
|
+
|
|
23
|
+
Read if available:
|
|
24
|
+
|
|
25
|
+
- the most recent `/execute-task` report in the conversation
|
|
26
|
+
- `git status` and `git log` (one screenful) to confirm what actually changed
|
|
27
|
+
- `.ai/execution-log.md` if it exists
|
|
28
|
+
|
|
29
|
+
## Rules
|
|
30
|
+
|
|
31
|
+
- **Trust git, not claims.** If a report says a file changed but git disagrees, flag it and do not advance the task.
|
|
32
|
+
- Never set status to `Validated` directly from execution. `Validated` requires a `/code-review` pass and, for user-facing changes, a `/qa-verify` pass. Update `Validation state` accordingly: `code-reviewed`, `qa-verified`, or `both`.
|
|
33
|
+
- Status flow is: `In progress` → `Needs review` → `Validated`. `Blocked` can come from any state.
|
|
34
|
+
- Never move a task to `Approved for execution`. That is `/board-review`'s job.
|
|
35
|
+
- New work discovered during execution becomes a new task in `Clarifying`, at the bottom of the relevant epic — not a silent edit to an existing task.
|
|
36
|
+
- Tasks the user explicitly cut go in the `Cut from MVP` section with a reason — never delete them.
|
|
37
|
+
- If a task is `Blocked`, record the specific blocker in a `Blocked by:` line.
|
|
38
|
+
- When a PR is opened, update `Linked PR:`. When a preview deploy exists, update `Demo URL:`.
|
|
39
|
+
- Append a one-line entry per state change to `.ai/execution-log.md` (create it if missing).
|
|
40
|
+
|
|
41
|
+
## Workflow
|
|
42
|
+
|
|
43
|
+
1. Read the board and the latest execution report.
|
|
44
|
+
2. Run `git status` and a short `git log` to confirm actual changes.
|
|
45
|
+
3. For each affected task: update status, append changed-files and verification result.
|
|
46
|
+
4. Add any follow-up tasks discovered.
|
|
47
|
+
5. Identify the next recommended task (or batch) based on dependencies.
|
|
48
|
+
6. Write the updated board and append to the execution log.
|
|
49
|
+
|
|
50
|
+
## Output format
|
|
51
|
+
|
|
52
|
+
After writing, return:
|
|
53
|
+
|
|
54
|
+
```md
|
|
55
|
+
## Board synced
|
|
56
|
+
|
|
57
|
+
### Status changes
|
|
58
|
+
- <TASK-ID>: <old> → <new>
|
|
59
|
+
|
|
60
|
+
### Tasks added
|
|
61
|
+
- <NEW-TASK-ID>: <title> (in <EPIC>)
|
|
62
|
+
|
|
63
|
+
### Blockers
|
|
64
|
+
- <TASK-ID>: <reason>
|
|
65
|
+
|
|
66
|
+
### Next recommended
|
|
67
|
+
- <TASK-ID> (or batch from `/parallel-execution`)
|
|
68
|
+
- Why now: <one line>
|
|
69
|
+
|
|
70
|
+
### Drift detected
|
|
71
|
+
- <e.g. "claimed edit to foo.ts but git shows no change"> | none
|
|
72
|
+
```
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ux-theme
|
|
3
|
+
description: Define the visual and product direction (vibe, layout, color, typography, component style) before coding starts. Use when the user says "what should this look like?", "pick a theme", "make it feel like Linear/Notion/Vercel", or right before scaffolding UI. Do NOT use for fine-grained component styling — that belongs in execution.
|
|
4
|
+
# Generated from .claude/skills/ux-theme/SKILL.md — DO NOT EDIT directly
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Skill: ux-theme
|
|
8
|
+
|
|
9
|
+
## Goal
|
|
10
|
+
|
|
11
|
+
Produce `.ai/ux-theme.md` — a concrete visual direction that every executor task can consult. Lovable-style theme control: one clear vibe, one set of patterns, one reference product.
|
|
12
|
+
|
|
13
|
+
## Recommended model
|
|
14
|
+
|
|
15
|
+
Opus 4.7 or GPT-5.5 for the direction. Sonnet 4.6 can implement against it later.
|
|
16
|
+
|
|
17
|
+
## Inputs
|
|
18
|
+
|
|
19
|
+
Read these if they exist:
|
|
20
|
+
|
|
21
|
+
- `.ai/product-spec.md`
|
|
22
|
+
- `.ai/architecture.md`
|
|
23
|
+
- `.ai/decision-log.md`
|
|
24
|
+
|
|
25
|
+
## Rules
|
|
26
|
+
|
|
27
|
+
- Pick **one** vibe. Not "minimal but playful but also enterprise."
|
|
28
|
+
- Name **one** reference product to imitate. "Linear-style productivity SaaS" beats "clean and modern."
|
|
29
|
+
- Give concrete tokens (color names, type scale, spacing) so executors do not invent their own.
|
|
30
|
+
- Define empty / loading / error patterns up front — these are where MVPs feel broken.
|
|
31
|
+
- Do not generate full design files. This is a brief, not Figma.
|
|
32
|
+
|
|
33
|
+
## Reference directions (pick one or describe a new one)
|
|
34
|
+
|
|
35
|
+
- Linear-style productivity SaaS
|
|
36
|
+
- Notion-like workspace
|
|
37
|
+
- Vercel-like developer tool
|
|
38
|
+
- Stripe-like admin dashboard
|
|
39
|
+
- Arc-like playful consumer app
|
|
40
|
+
|
|
41
|
+
## Output format
|
|
42
|
+
|
|
43
|
+
Write `.ai/ux-theme.md`:
|
|
44
|
+
|
|
45
|
+
```md
|
|
46
|
+
# UX Theme — <name>
|
|
47
|
+
|
|
48
|
+
## Vibe
|
|
49
|
+
<one sentence>
|
|
50
|
+
|
|
51
|
+
## Reference product
|
|
52
|
+
<one product, with a link or short description of what to copy>
|
|
53
|
+
|
|
54
|
+
## Layout style
|
|
55
|
+
<sidebar + content / centered single column / dashboard grid / etc.>
|
|
56
|
+
|
|
57
|
+
## Color direction
|
|
58
|
+
- Background:
|
|
59
|
+
- Surface:
|
|
60
|
+
- Text primary:
|
|
61
|
+
- Text muted:
|
|
62
|
+
- Accent:
|
|
63
|
+
- Danger:
|
|
64
|
+
(prefer Tailwind palette names or hex)
|
|
65
|
+
|
|
66
|
+
## Typography
|
|
67
|
+
- Display:
|
|
68
|
+
- Body:
|
|
69
|
+
- Mono:
|
|
70
|
+
- Scale: <e.g. 12 / 14 / 16 / 20 / 24 / 32>
|
|
71
|
+
|
|
72
|
+
## Component style
|
|
73
|
+
- Corners: <radius>
|
|
74
|
+
- Borders: <weight, color>
|
|
75
|
+
- Shadows: <none / soft / layered>
|
|
76
|
+
- Buttons: <filled / outlined / ghost variants>
|
|
77
|
+
- Inputs: <style>
|
|
78
|
+
|
|
79
|
+
## Patterns
|
|
80
|
+
- Empty state:
|
|
81
|
+
- Loading state:
|
|
82
|
+
- Error state:
|
|
83
|
+
- Table:
|
|
84
|
+
- Card:
|
|
85
|
+
- Dialog / modal:
|
|
86
|
+
|
|
87
|
+
## Constraints
|
|
88
|
+
- <hard "no" rules, e.g. "no gradients", "no emoji in UI">
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
After writing, recommend `/mvp-board` next.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forgeailab/create-spark",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Interactive scaffolder for spark projects with guided pack picker.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -9,16 +9,19 @@
|
|
|
9
9
|
"files": [
|
|
10
10
|
"src",
|
|
11
11
|
"README.md",
|
|
12
|
-
"templates",
|
|
13
12
|
"packs",
|
|
14
|
-
"presets"
|
|
13
|
+
"presets",
|
|
14
|
+
"templates",
|
|
15
|
+
".claude",
|
|
16
|
+
".codex",
|
|
17
|
+
"scripts"
|
|
15
18
|
],
|
|
16
19
|
"bin": {
|
|
17
20
|
"create-spark": "./src/cli.ts"
|
|
18
21
|
},
|
|
19
22
|
"dependencies": {
|
|
20
|
-
"@forgeailab/spark": "^0.
|
|
21
|
-
"@forgeailab/spark-schema": "^0.
|
|
23
|
+
"@forgeailab/spark": "^0.2.0",
|
|
24
|
+
"@forgeailab/spark-schema": "^0.2.0",
|
|
22
25
|
"@clack/prompts": "latest",
|
|
23
26
|
"citty": "latest",
|
|
24
27
|
"picocolors": "latest"
|
package/packs/README.md
CHANGED
|
@@ -91,32 +91,30 @@ See `packs/example/pack.toml` for a manifest that exercises every field.
|
|
|
91
91
|
|
|
92
92
|
## v1 catalog
|
|
93
93
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
|
97
|
-
|
|
98
|
-
| `auth-
|
|
99
|
-
| `
|
|
100
|
-
| `
|
|
101
|
-
| `db-
|
|
102
|
-
| `
|
|
103
|
-
| `
|
|
104
|
-
| `
|
|
105
|
-
| `
|
|
106
|
-
| `
|
|
107
|
-
| `
|
|
108
|
-
| `
|
|
109
|
-
| `
|
|
110
|
-
| `
|
|
111
|
-
| `
|
|
112
|
-
| `testing-playwright` | testing | copy | — |
|
|
113
|
-
| `deploy-vercel` | deploy | copy | — |
|
|
94
|
+
| Pack | Category |
|
|
95
|
+
|---|---|
|
|
96
|
+
| `auth-better-auth` | auth |
|
|
97
|
+
| `auth-better-auth-pg` | auth |
|
|
98
|
+
| `auth-supabase` | auth |
|
|
99
|
+
| `db-sqlite` | db |
|
|
100
|
+
| `db-postgres` | db |
|
|
101
|
+
| `db-supabase` | db |
|
|
102
|
+
| `sync-zero` | infra |
|
|
103
|
+
| `payments-stripe` | payments |
|
|
104
|
+
| `ai-anthropic` | ai |
|
|
105
|
+
| `ai-openai` | ai |
|
|
106
|
+
| `ui-shadcn` | ui |
|
|
107
|
+
| `email-resend` | email |
|
|
108
|
+
| `analytics-posthog` | analytics |
|
|
109
|
+
| `docker-compose-dev` | infra |
|
|
110
|
+
| `testing-playwright` | testing |
|
|
111
|
+
| `deploy-vercel` | deploy |
|
|
114
112
|
|
|
115
113
|
### Picking a db + auth pair
|
|
116
114
|
|
|
117
|
-
`auth-better-auth` and `auth-better-auth-pg` share the same
|
|
118
|
-
|
|
119
|
-
|
|
115
|
+
`auth-better-auth` and `auth-better-auth-pg` share the same Better Auth factory
|
|
116
|
+
code in their generated `lib/auth.ts` templates — they differ only in the
|
|
117
|
+
`provider:` handed to `drizzleAdapter`. Pair them:
|
|
120
118
|
|
|
121
119
|
- `db-sqlite` + `auth-better-auth` — fastest path, single file db, no infra.
|
|
122
120
|
- `db-postgres` + `auth-better-auth-pg` — production-shaped, **required for `sync-zero`** (Zero needs Postgres logical replication).
|
|
@@ -127,6 +125,6 @@ installing both. Mixing wrong pairs (e.g. `db-sqlite` + `auth-better-auth-pg`)
|
|
|
127
125
|
typechecks but fails at runtime — the drizzle adapter will reject sqlite tables
|
|
128
126
|
with `provider: 'pg'`.
|
|
129
127
|
|
|
130
|
-
The
|
|
128
|
+
The copy-mode packs were authored against [`reference/full-stack-saas/`](../reference/full-stack-saas/) — the canonical integration showing the copied templates working together. When debugging one of these packs, start there.
|
|
131
129
|
|
|
132
130
|
See the root `README.md` for the catalog summary.
|
|
@@ -1,5 +1,49 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import Anthropic from '@anthropic-ai/sdk';
|
|
2
|
+
|
|
3
|
+
export function createAnthropicClient(
|
|
4
|
+
apiKey: string,
|
|
5
|
+
options?: ConstructorParameters<typeof Anthropic>[0],
|
|
6
|
+
): Anthropic {
|
|
7
|
+
return new Anthropic({ apiKey, ...options });
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const encoder = new TextEncoder();
|
|
11
|
+
|
|
12
|
+
function isContentBlockDeltaEvent(event: unknown): event is { type: 'content_block_delta' } {
|
|
13
|
+
return (
|
|
14
|
+
typeof event === 'object' &&
|
|
15
|
+
event !== null &&
|
|
16
|
+
(event as { type?: unknown }).type === 'content_block_delta'
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function encodeSse(payload: unknown) {
|
|
21
|
+
return encoder.encode(`data: ${JSON.stringify(payload)}\n\n`);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function streamResponse(
|
|
25
|
+
client: Anthropic,
|
|
26
|
+
params: Parameters<Anthropic['messages']['stream']>[0],
|
|
27
|
+
): ReadableStream<Uint8Array> {
|
|
28
|
+
return new ReadableStream<Uint8Array>({
|
|
29
|
+
async start(controller) {
|
|
30
|
+
try {
|
|
31
|
+
const stream = client.messages.stream(params);
|
|
32
|
+
|
|
33
|
+
for await (const event of stream) {
|
|
34
|
+
if (isContentBlockDeltaEvent(event)) {
|
|
35
|
+
controller.enqueue(encodeSse(event));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
controller.enqueue(encoder.encode('data: [DONE]\n\n'));
|
|
40
|
+
controller.close();
|
|
41
|
+
} catch (error) {
|
|
42
|
+
controller.error(error);
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
}
|
|
3
47
|
|
|
4
48
|
function requireEnv(name: string): string {
|
|
5
49
|
const value = process.env[name];
|
|
@@ -11,5 +55,4 @@ function requireEnv(name: string): string {
|
|
|
11
55
|
|
|
12
56
|
export const anthropic = createAnthropicClient(requireEnv('ANTHROPIC_API_KEY'));
|
|
13
57
|
|
|
14
|
-
export { streamResponse };
|
|
15
58
|
export type AnthropicChatMessage = Anthropic.Messages.MessageParam;
|
|
@@ -8,9 +8,8 @@ conflicts = []
|
|
|
8
8
|
requires_runtime = ["server"]
|
|
9
9
|
compatible_scaffolds = []
|
|
10
10
|
|
|
11
|
-
[
|
|
12
|
-
|
|
13
|
-
version = "^0.1"
|
|
11
|
+
[dependencies]
|
|
12
|
+
runtime = ["@anthropic-ai/sdk"]
|
|
14
13
|
|
|
15
14
|
[env]
|
|
16
15
|
required = ["ANTHROPIC_API_KEY"]
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { toNextJsHandler } from 'better-auth/next-js';
|
|
2
2
|
import { auth } from '@/lib/auth';
|
|
3
3
|
|
|
4
|
-
export const { GET, POST } =
|
|
4
|
+
export const { GET, POST } = toNextJsHandler(auth);
|
|
@@ -1,4 +1,43 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { betterAuth } from 'better-auth';
|
|
2
|
+
|
|
3
|
+
type BetterAuthOptions = Parameters<typeof betterAuth>[0];
|
|
4
|
+
|
|
5
|
+
export type AuthInstance = ReturnType<typeof betterAuth>;
|
|
6
|
+
|
|
7
|
+
export type CreateBetterAuthOptions = {
|
|
8
|
+
adapter: BetterAuthOptions['database'];
|
|
9
|
+
basePath?: BetterAuthOptions['basePath'];
|
|
10
|
+
plugins?: BetterAuthOptions['plugins'];
|
|
11
|
+
emailAndPassword?: BetterAuthOptions['emailAndPassword'];
|
|
12
|
+
socialProviders?: BetterAuthOptions['socialProviders'];
|
|
13
|
+
secret?: BetterAuthOptions['secret'];
|
|
14
|
+
baseURL?: BetterAuthOptions['baseURL'];
|
|
15
|
+
trustedOrigins?: string[];
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export function createBetterAuth({
|
|
19
|
+
adapter,
|
|
20
|
+
basePath,
|
|
21
|
+
plugins,
|
|
22
|
+
emailAndPassword,
|
|
23
|
+
socialProviders,
|
|
24
|
+
secret,
|
|
25
|
+
baseURL,
|
|
26
|
+
trustedOrigins,
|
|
27
|
+
}: CreateBetterAuthOptions) {
|
|
28
|
+
const authOptions: BetterAuthOptions = {
|
|
29
|
+
database: adapter,
|
|
30
|
+
basePath,
|
|
31
|
+
plugins,
|
|
32
|
+
emailAndPassword,
|
|
33
|
+
socialProviders,
|
|
34
|
+
secret,
|
|
35
|
+
baseURL,
|
|
36
|
+
trustedOrigins: trustedOrigins ?? (typeof baseURL === 'string' ? [baseURL] : undefined),
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
return betterAuth(authOptions);
|
|
40
|
+
}
|
|
2
41
|
|
|
3
42
|
// Wire your database adapter here. Example (drizzle + sqlite):
|
|
4
43
|
//
|
|
@@ -8,12 +8,8 @@ conflicts = ["auth"]
|
|
|
8
8
|
requires_runtime = ["server"]
|
|
9
9
|
compatible_scaffolds = ["nextjs"]
|
|
10
10
|
|
|
11
|
-
[runtime_package]
|
|
12
|
-
package = "@forgeailab/spark-auth-better-auth"
|
|
13
|
-
version = "^0.1"
|
|
14
|
-
|
|
15
11
|
[dependencies]
|
|
16
|
-
runtime = ["@better-auth/drizzle-adapter"]
|
|
12
|
+
runtime = ["@better-auth/drizzle-adapter", "better-auth"]
|
|
17
13
|
|
|
18
14
|
[env]
|
|
19
15
|
required = ["BETTER_AUTH_SECRET", "BETTER_AUTH_URL"]
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { toNextJsHandler } from 'better-auth/next-js';
|
|
2
2
|
import { auth } from '@/lib/auth';
|
|
3
3
|
|
|
4
|
-
export const { GET, POST } =
|
|
4
|
+
export const { GET, POST } = toNextJsHandler(auth);
|
|
@@ -1,8 +1,47 @@
|
|
|
1
1
|
import { drizzleAdapter } from '@better-auth/drizzle-adapter';
|
|
2
|
-
import {
|
|
2
|
+
import { betterAuth } from 'better-auth';
|
|
3
3
|
import { db } from '@/lib/db';
|
|
4
4
|
import * as schema from '@/lib/db/schema';
|
|
5
5
|
|
|
6
|
+
type BetterAuthOptions = Parameters<typeof betterAuth>[0];
|
|
7
|
+
|
|
8
|
+
export type AuthInstance = ReturnType<typeof betterAuth>;
|
|
9
|
+
|
|
10
|
+
export type CreateBetterAuthOptions = {
|
|
11
|
+
adapter: BetterAuthOptions['database'];
|
|
12
|
+
basePath?: BetterAuthOptions['basePath'];
|
|
13
|
+
plugins?: BetterAuthOptions['plugins'];
|
|
14
|
+
emailAndPassword?: BetterAuthOptions['emailAndPassword'];
|
|
15
|
+
socialProviders?: BetterAuthOptions['socialProviders'];
|
|
16
|
+
secret?: BetterAuthOptions['secret'];
|
|
17
|
+
baseURL?: BetterAuthOptions['baseURL'];
|
|
18
|
+
trustedOrigins?: string[];
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export function createBetterAuth({
|
|
22
|
+
adapter,
|
|
23
|
+
basePath,
|
|
24
|
+
plugins,
|
|
25
|
+
emailAndPassword,
|
|
26
|
+
socialProviders,
|
|
27
|
+
secret,
|
|
28
|
+
baseURL,
|
|
29
|
+
trustedOrigins,
|
|
30
|
+
}: CreateBetterAuthOptions) {
|
|
31
|
+
const authOptions: BetterAuthOptions = {
|
|
32
|
+
database: adapter,
|
|
33
|
+
basePath,
|
|
34
|
+
plugins,
|
|
35
|
+
emailAndPassword,
|
|
36
|
+
socialProviders,
|
|
37
|
+
secret,
|
|
38
|
+
baseURL,
|
|
39
|
+
trustedOrigins: trustedOrigins ?? (typeof baseURL === 'string' ? [baseURL] : undefined),
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
return betterAuth(authOptions);
|
|
43
|
+
}
|
|
44
|
+
|
|
6
45
|
// Postgres-flavored Better Auth wiring. Pair this pack with `db-postgres`
|
|
7
46
|
// (or `db-supabase`), and add the four Better Auth tables to your
|
|
8
47
|
// `lib/db/schema.ts`: `user`, `session`, `account`, `verification`. Snake-case
|
|
@@ -8,12 +8,8 @@ conflicts = ["auth"]
|
|
|
8
8
|
requires_runtime = ["server"]
|
|
9
9
|
compatible_scaffolds = ["nextjs"]
|
|
10
10
|
|
|
11
|
-
[runtime_package]
|
|
12
|
-
package = "@forgeailab/spark-auth-better-auth"
|
|
13
|
-
version = "^0.1"
|
|
14
|
-
|
|
15
11
|
[dependencies]
|
|
16
|
-
runtime = ["@better-auth/drizzle-adapter"]
|
|
12
|
+
runtime = ["@better-auth/drizzle-adapter", "better-auth"]
|
|
17
13
|
|
|
18
14
|
[env]
|
|
19
15
|
required = ["BETTER_AUTH_SECRET", "BETTER_AUTH_URL"]
|