@donotdev/cli 0.0.12 ā 0.0.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/dependencies-matrix.json +30 -116
- package/dist/bin/commands/bump.js +33 -7
- package/dist/bin/commands/create-project.js +43 -7
- package/dist/bin/commands/deploy.js +7606 -17
- package/dist/bin/commands/firebase-setup.d.ts +6 -0
- package/dist/bin/commands/firebase-setup.d.ts.map +1 -0
- package/dist/bin/commands/firebase-setup.js +7 -0
- package/dist/bin/commands/firebase-setup.js.map +1 -0
- package/dist/bin/commands/staging.d.ts +11 -0
- package/dist/bin/commands/staging.d.ts.map +1 -0
- package/dist/bin/commands/staging.js +12 -0
- package/dist/bin/commands/staging.js.map +1 -0
- package/dist/bin/dndev.js +28 -3
- package/dist/bin/donotdev.js +28 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7671 -39
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/app-demo/src/pages/DetailPage.tsx.example +1 -1
- package/templates/app-demo/src/pages/FullPage.tsx.example +3 -3
- package/templates/app-demo/src/pages/HomePage.tsx.example +1 -1
- package/templates/app-demo/src/pages/components/ComponentRenderer.tsx.example +5 -5
- package/templates/app-demo/src/pages/components/DemoLayout.tsx.example +3 -3
- package/templates/app-next/.env.example +2 -0
- package/templates/app-next/src/pages/HomePage.tsx.example +1 -1
- package/templates/app-vite/.env.example +2 -0
- package/templates/app-vite/src/pages/HomePage.tsx.example +163 -73
- package/templates/functions-firebase/build.mjs.example +26 -10
- package/templates/functions-firebase/functions-firebase/build.mjs.example +26 -10
- package/templates/functions-firebase/functions.config.js.example +11 -15
- package/templates/github-consumer/.github/workflows/ci.yml.example +36 -0
- package/templates/root-consumer/.claude/agents/architect.md.example +2 -2
- package/templates/root-consumer/.claude/agents/builder.md.example +2 -2
- package/templates/root-consumer/.claude/agents/coder.md.example +2 -2
- package/templates/root-consumer/.claude/agents/extractor.md.example +2 -3
- package/templates/root-consumer/.claude/agents/polisher.md.example +67 -291
- package/templates/root-consumer/.claude/agents/prompt-engineer.md.example +4 -4
- package/templates/root-consumer/.claude/commands/build.md.example +2 -2
- package/templates/root-consumer/.claude/commands/polish.md.example +65 -81
- package/templates/root-consumer/.env.example +13 -13
- package/templates/root-consumer/.gemini/settings.json.example +9 -0
- package/templates/root-consumer/.gitignore.example +3 -1
- package/templates/root-consumer/AI.md.example +139 -0
- package/templates/root-consumer/CLAUDE.md.example +13 -104
- package/templates/root-consumer/README.md.example +81 -255
- package/templates/root-consumer/entities/Contact.ts.example +126 -0
- package/templates/root-consumer/entities/index.ts.example +6 -3
- package/templates/root-consumer/guides/dndev/AGENT_START_HERE.md.example +41 -342
- package/templates/root-consumer/guides/dndev/COMPONENTS_ADV.md.example +2 -1
- package/templates/root-consumer/guides/dndev/ENV_SETUP.md.example +144 -9
- package/templates/root-consumer/guides/dndev/INDEX.md.example +9 -0
- package/templates/root-consumer/guides/dndev/SETUP_APP_CONFIG.md.example +13 -16
- package/templates/root-consumer/guides/dndev/SETUP_BLOG.md.example +263 -0
- package/templates/root-consumer/guides/dndev/SETUP_CRUD.md.example +1 -1
- package/templates/root-consumer/guides/dndev/SETUP_FIREBASE.md.example +168 -0
- package/templates/root-consumer/guides/dndev/SETUP_FUNCTIONS.md.example +5 -12
- package/templates/root-consumer/guides/dndev/SETUP_TESTING.md.example +184 -0
- package/templates/root-consumer/guides/wai-way/WAI_WAY_CLI.md.example +134 -69
- package/templates/root-consumer/guides/wai-way/agents/polisher.md.example +66 -44
- package/templates/root-consumer/guides/wai-way/blueprints/0_brainstorm.md.example +18 -1
- package/templates/root-consumer/guides/wai-way/blueprints/1_scaffold.md.example +1 -0
- package/templates/root-consumer/guides/wai-way/blueprints/2_entities.md.example +2 -1
- package/templates/root-consumer/guides/wai-way/blueprints/3_compose.md.example +2 -1
- package/templates/root-consumer/guides/wai-way/blueprints/4_configure.md.example +180 -108
- package/templates/root-consumer/guides/wai-way/context_map.json.example +8 -7
- package/templates/root-consumer/guides/wai-way/page_patterns.md.example +4 -4
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,4BAA4B;AAE5B;;;;;GAKG;AAEH,qFAAqF;AACrF,OAAO,EACL,SAAS,EACT,aAAa,EACb,MAAM,EACN,GAAG,EACH,KAAK,EACL,OAAO,EACP,GAAG,EACH,QAAQ,EACR,WAAW,EACX,MAAM,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,4BAA4B;AAE5B;;;;;GAKG;AAEH,qFAAqF;AACrF,OAAO,EACL,SAAS,EACT,aAAa,EACb,MAAM,EACN,GAAG,EACH,KAAK,EACL,OAAO,EACP,GAAG,EACH,QAAQ,EACR,WAAW,EACX,MAAM,EACN,OAAO,GACR,MAAM,mBAAmB,CAAC"}
|
package/package.json
CHANGED
|
@@ -78,7 +78,7 @@ export default function DetailPage() {
|
|
|
78
78
|
.map(([k, v]) => `${k}: ${v}`);
|
|
79
79
|
|
|
80
80
|
return (
|
|
81
|
-
<Stack key={idx}
|
|
81
|
+
<Stack key={idx} align="center">
|
|
82
82
|
{variantLabels.length > 0 && (
|
|
83
83
|
<Stack direction="row" gap="tight" wrap="wrap" justify="center">
|
|
84
84
|
{variantLabels.map((label) => (
|
|
@@ -81,14 +81,14 @@ export default function FullPage() {
|
|
|
81
81
|
default is vertical. Gap controls spacing between items.
|
|
82
82
|
</Text>
|
|
83
83
|
</Card>
|
|
84
|
-
<Stack
|
|
84
|
+
<Stack>
|
|
85
85
|
<Card variant="muted" title="Stack Item 1">
|
|
86
|
-
<Text variant="muted">Vertical stack with
|
|
86
|
+
<Text variant="muted">Vertical stack with</Text>
|
|
87
87
|
</Card>
|
|
88
88
|
<Card variant="muted" title="Stack Item 2">
|
|
89
89
|
<Text variant="muted">Items stack vertically by default</Text>
|
|
90
90
|
</Card>
|
|
91
|
-
<Stack direction="row"
|
|
91
|
+
<Stack direction="row">
|
|
92
92
|
<Card variant="muted" title="Row Item 1">
|
|
93
93
|
<Text variant="muted">Horizontal stack</Text>
|
|
94
94
|
</Card>
|
|
@@ -52,7 +52,7 @@ export default function HomePage() {
|
|
|
52
52
|
}
|
|
53
53
|
subtitle={`${componentsInTab.length} components`}
|
|
54
54
|
>
|
|
55
|
-
<Grid cols="auto-fit" minColWidth="240px"
|
|
55
|
+
<Grid cols="auto-fit" minColWidth="240px">
|
|
56
56
|
{componentsInTab.map((config) => {
|
|
57
57
|
const isFullPageComponent = config.cssFamily === 'layout';
|
|
58
58
|
return (
|
|
@@ -348,7 +348,7 @@ export function ComponentRenderer({
|
|
|
348
348
|
|
|
349
349
|
return (
|
|
350
350
|
<Stack gap="large" align="center" justify="center">
|
|
351
|
-
<Stack
|
|
351
|
+
<Stack className="dndev-w-full dndev-max-w-md">
|
|
352
352
|
<Stack direction="row" gap="tight" align="end">
|
|
353
353
|
<Input
|
|
354
354
|
placeholder="Enter toast message..."
|
|
@@ -432,8 +432,8 @@ export function ComponentRenderer({
|
|
|
432
432
|
try {
|
|
433
433
|
if (config.id === 'tabs') {
|
|
434
434
|
return (
|
|
435
|
-
<Stack
|
|
436
|
-
<Stack direction="row"
|
|
435
|
+
<Stack align="stretch">
|
|
436
|
+
<Stack direction="row" align="center">
|
|
437
437
|
<Input
|
|
438
438
|
type="number"
|
|
439
439
|
min={1}
|
|
@@ -453,7 +453,7 @@ export function ComponentRenderer({
|
|
|
453
453
|
const isActive = activeOverlayVariant === currentVariant;
|
|
454
454
|
return (
|
|
455
455
|
<>
|
|
456
|
-
<Stack
|
|
456
|
+
<Stack align="center" justify="center" style={{ minHeight: '200px', position: 'relative', zIndex: 10000 }}>
|
|
457
457
|
<Button
|
|
458
458
|
variant="ghost"
|
|
459
459
|
onClick={() => {
|
|
@@ -489,7 +489,7 @@ export function ComponentRenderer({
|
|
|
489
489
|
}
|
|
490
490
|
|
|
491
491
|
return (
|
|
492
|
-
<Stack direction="row" align="center"
|
|
492
|
+
<Stack direction="row" align="center">
|
|
493
493
|
<Component {...componentProps} />
|
|
494
494
|
<Text variant="muted">State: {stateLabel}</Text>
|
|
495
495
|
</Stack>
|
|
@@ -102,7 +102,7 @@ export function DemoLayout({
|
|
|
102
102
|
/>
|
|
103
103
|
</Stack>
|
|
104
104
|
|
|
105
|
-
<Stack
|
|
105
|
+
<Stack>
|
|
106
106
|
<Button
|
|
107
107
|
variant="primary"
|
|
108
108
|
fullWidth
|
|
@@ -173,7 +173,7 @@ export function DemoLayout({
|
|
|
173
173
|
borderBottom: 'var(--border-hairline) solid var(--border)',
|
|
174
174
|
}}
|
|
175
175
|
>
|
|
176
|
-
<Stack direction="row"
|
|
176
|
+
<Stack direction="row" align="center" justify="start">
|
|
177
177
|
<Button
|
|
178
178
|
variant="ghost"
|
|
179
179
|
icon={ArrowLeft}
|
|
@@ -222,7 +222,7 @@ export function DemoLayout({
|
|
|
222
222
|
</Stack>
|
|
223
223
|
|
|
224
224
|
{/* Right side: Theme Toggle + Mobile Menu */}
|
|
225
|
-
<Stack direction="row"
|
|
225
|
+
<Stack direction="row" justify="end" align="center">
|
|
226
226
|
<ThemeToggle />
|
|
227
227
|
{!isLaptop && (
|
|
228
228
|
<Sheet
|
|
@@ -52,8 +52,10 @@ NEXT_PUBLIC_DONOTDEV_LICENSE_KEY=dndev_your_key_here
|
|
|
52
52
|
# Firebase Configuration
|
|
53
53
|
# =============================================================================
|
|
54
54
|
# Get these values from your Firebase project settings
|
|
55
|
+
# Run `dndev firebase:setup` to auto-populate, or copy from Firebase Console
|
|
55
56
|
NEXT_PUBLIC_FIREBASE_API_KEY=
|
|
56
57
|
NEXT_PUBLIC_FIREBASE_PROJECT_ID=
|
|
58
|
+
# Copy from Firebase Console. Framework uses APP_URL hostname in production automatically.
|
|
57
59
|
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=
|
|
58
60
|
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=
|
|
59
61
|
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=
|
|
@@ -84,7 +84,7 @@ export default function HomePage() {
|
|
|
84
84
|
Stack creates flex containers. Default vertical, use direction="row"
|
|
85
85
|
for horizontal.
|
|
86
86
|
</Text>
|
|
87
|
-
<Stack direction="row"
|
|
87
|
+
<Stack direction="row">
|
|
88
88
|
<Card variant="primary" title="Item 1">
|
|
89
89
|
<Text>Horizontal</Text>
|
|
90
90
|
</Card>
|
|
@@ -37,8 +37,10 @@ VITE_DONOTDEV_LICENSE_KEY=dndev_your_key_here
|
|
|
37
37
|
# Firebase Configuration
|
|
38
38
|
# =============================================================================
|
|
39
39
|
# Get these values from your Firebase project settings
|
|
40
|
+
# Run `dndev firebase:setup` to auto-populate, or copy from Firebase Console
|
|
40
41
|
VITE_FIREBASE_API_KEY=
|
|
41
42
|
VITE_FIREBASE_PROJECT_ID=
|
|
43
|
+
# Copy from Firebase Console. Framework uses APP_URL hostname in production automatically.
|
|
42
44
|
VITE_FIREBASE_AUTH_DOMAIN=
|
|
43
45
|
VITE_FIREBASE_STORAGE_BUCKET=
|
|
44
46
|
VITE_FIREBASE_MESSAGING_SENDER_ID=
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview Home Page
|
|
2
|
+
* @fileoverview Home Page ā Setup Guide
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* This page guides you through setting up your app.
|
|
5
|
+
* Replace it with your actual landing page once setup is complete.
|
|
5
6
|
*
|
|
6
7
|
* HOW PAGES WORK:
|
|
7
8
|
* 1. Name files *Page.tsx in src/pages/ ā auto-discovered as routes
|
|
@@ -12,97 +13,186 @@
|
|
|
12
13
|
|
|
13
14
|
import { Home } from 'lucide-react';
|
|
14
15
|
|
|
15
|
-
import {
|
|
16
|
+
import { HeroSection, Section, Card, Grid, List, Alert, Text, Stack } from '@donotdev/components';
|
|
16
17
|
import type { PageMeta } from '@donotdev/core';
|
|
17
|
-
import { PageContainer
|
|
18
|
-
|
|
19
|
-
// ============================================================================
|
|
20
|
-
// PAGE METADATA - Controls routing, navigation, and access
|
|
21
|
-
// ============================================================================
|
|
22
|
-
//
|
|
23
|
-
// namespace ā i18n namespace for translations (matches locales/home_en.json)
|
|
24
|
-
// icon ā Navigation icon (from lucide-react)
|
|
25
|
-
// nav ā Show in navigation (default: true, set false to hide)
|
|
26
|
-
// navGroup ā Navigation group: 'main' | 'admin' | 'footer' (default: 'main')
|
|
27
|
-
// route ā Custom route path (default: derived from filename)
|
|
28
|
-
// auth ā Access control:
|
|
29
|
-
// - undefined ā public (anyone can view)
|
|
30
|
-
// - true ā requires login
|
|
31
|
-
// - 'admin' ā requires admin role
|
|
32
|
-
// - { required: true, role: 'admin' } ā full syntax
|
|
33
|
-
// tier ā Subscription tier required: 'pro' | 'enterprise'
|
|
34
|
-
// hideFromMenu ā Show in routing but hide from navigation menu
|
|
35
|
-
//
|
|
18
|
+
import { PageContainer } from '@donotdev/ui';
|
|
19
|
+
|
|
36
20
|
export const NAMESPACE = 'home';
|
|
37
21
|
|
|
38
22
|
export const meta: PageMeta = {
|
|
39
23
|
namespace: NAMESPACE,
|
|
40
24
|
icon: <Home />,
|
|
41
|
-
// nav: true, // Uncomment to hide from navigation
|
|
42
|
-
// navGroup: 'main', // 'main' | 'admin' | 'footer'
|
|
43
|
-
// route: '/', // Custom route (default: / for HomePage)
|
|
44
|
-
// auth: true, // Uncomment to require login
|
|
45
|
-
// auth: 'admin', // Uncomment to require admin role
|
|
46
|
-
// auth: { required: true, role: 'admin' }, // Full syntax
|
|
47
|
-
// tier: 'pro', // Uncomment to require subscription
|
|
48
|
-
// hideFromMenu: true, // Uncomment to hide from menu but keep route
|
|
49
25
|
};
|
|
50
26
|
|
|
51
|
-
// ============================================================================
|
|
52
|
-
// PAGE COMPONENT
|
|
53
|
-
// ============================================================================
|
|
54
|
-
|
|
55
27
|
export default function HomePage() {
|
|
56
28
|
return (
|
|
57
29
|
<PageContainer>
|
|
58
|
-
{/* Hero Section - Full-width banner with title and subtitle */}
|
|
59
30
|
<HeroSection
|
|
60
|
-
title="
|
|
61
|
-
subtitle="
|
|
31
|
+
title="Your App is Running"
|
|
32
|
+
subtitle="Follow the steps below to complete your setup. Replace this page when you're ready to build."
|
|
62
33
|
variant="primary"
|
|
63
34
|
/>
|
|
64
35
|
|
|
65
|
-
{/*
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
36
|
+
{/* ================================================================ */}
|
|
37
|
+
{/* REQUIRED SETUP */}
|
|
38
|
+
{/* ================================================================ */}
|
|
39
|
+
|
|
40
|
+
<Section title="Required Setup">
|
|
41
|
+
<Grid cols={[1, 1, 2, 2]}>
|
|
42
|
+
<Card
|
|
43
|
+
title="1. Git Repository"
|
|
44
|
+
content={[
|
|
45
|
+
'git init',
|
|
46
|
+
'git add . && git commit -m "Initial scaffold"',
|
|
47
|
+
'Create a repo on GitHub, then:',
|
|
48
|
+
'git remote add origin <your-repo-url>',
|
|
49
|
+
'git push -u origin main',
|
|
50
|
+
]}
|
|
51
|
+
/>
|
|
52
|
+
|
|
53
|
+
<Card
|
|
54
|
+
title="2. Firebase Setup"
|
|
55
|
+
content={[
|
|
56
|
+
'Run: dndev firebase:setup',
|
|
57
|
+
'This will:',
|
|
58
|
+
' - Create or select a Firebase project',
|
|
59
|
+
' - Create a web app if needed',
|
|
60
|
+
' - Write Firebase config to your .env automatically',
|
|
61
|
+
' - Update .firebaserc with your project ID',
|
|
62
|
+
'Then follow the prompts for the 2 manual steps:',
|
|
63
|
+
' - Download service account key',
|
|
64
|
+
' - Enable Auth + Firestore in Firebase Console',
|
|
65
|
+
]}
|
|
66
|
+
/>
|
|
71
67
|
</Grid>
|
|
72
68
|
</Section>
|
|
73
69
|
|
|
74
|
-
{/*
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
70
|
+
{/* ================================================================ */}
|
|
71
|
+
{/* VERIFY SETUP */}
|
|
72
|
+
{/* ================================================================ */}
|
|
73
|
+
|
|
74
|
+
<Section title="Verify It Works">
|
|
75
|
+
<Grid cols={[1, 1, 2, 3]}>
|
|
76
|
+
<Card
|
|
77
|
+
title="Local Dev"
|
|
78
|
+
content={[
|
|
79
|
+
'bun dev ā starts the app',
|
|
80
|
+
'Should load without errors',
|
|
81
|
+
]}
|
|
82
|
+
/>
|
|
83
|
+
<Card
|
|
84
|
+
title="Emulators"
|
|
85
|
+
content={[
|
|
86
|
+
'dndev emu start ā Firebase emulators',
|
|
87
|
+
'Select: Auth + Firestore + Functions',
|
|
88
|
+
'Test auth and CRUD locally',
|
|
89
|
+
]}
|
|
90
|
+
/>
|
|
91
|
+
<Card
|
|
92
|
+
title="Deploy"
|
|
93
|
+
content={[
|
|
94
|
+
'dndev deploy ā deploys to Firebase Hosting',
|
|
95
|
+
'Functions + hosting deployed automatically',
|
|
96
|
+
'Cloud Run IAM configured for you',
|
|
97
|
+
]}
|
|
98
|
+
/>
|
|
99
|
+
</Grid>
|
|
81
100
|
</Section>
|
|
82
101
|
|
|
83
|
-
{/*
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
)
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
102
|
+
{/* ================================================================ */}
|
|
103
|
+
{/* OPTIONAL SETUP */}
|
|
104
|
+
{/* ================================================================ */}
|
|
105
|
+
|
|
106
|
+
<Section title="Optional Setup">
|
|
107
|
+
<Alert
|
|
108
|
+
variant="info"
|
|
109
|
+
title="None of these are required to start building"
|
|
110
|
+
description="Set these up when you need them, not before."
|
|
111
|
+
/>
|
|
112
|
+
|
|
113
|
+
<Grid cols={[1, 1, 2, 2]}>
|
|
114
|
+
<Card
|
|
115
|
+
title="GitHub Actions (CI/CD)"
|
|
116
|
+
subtitle="Automatic deploy on push to main"
|
|
117
|
+
content={[
|
|
118
|
+
'WAI-WAY Phase 4 generates .github/workflows/ci.yml',
|
|
119
|
+
'Add secrets in GitHub ā Settings ā Secrets:',
|
|
120
|
+
'FIREBASE_SERVICE_ACCOUNT (paste service account JSON)',
|
|
121
|
+
'Pushes to main auto-deploy after tests pass',
|
|
122
|
+
]}
|
|
123
|
+
/>
|
|
124
|
+
|
|
125
|
+
<Card
|
|
126
|
+
title="Staging Environment"
|
|
127
|
+
subtitle="Separate Firebase project for testing"
|
|
128
|
+
content={[
|
|
129
|
+
'Create a second Firebase project (e.g. my-app-staging)',
|
|
130
|
+
'Add to .firebaserc: { "projects": { "staging": "my-app-staging" } }',
|
|
131
|
+
'Create .env.staging with staging Firebase config',
|
|
132
|
+
'Create service-account-key.staging.json',
|
|
133
|
+
'Deploy with: dndev staging',
|
|
134
|
+
]}
|
|
135
|
+
/>
|
|
136
|
+
|
|
137
|
+
<Card
|
|
138
|
+
title="Secrets (Stripe, OAuth, etc.)"
|
|
139
|
+
subtitle="Server-side API keys for Cloud Functions"
|
|
140
|
+
content={[
|
|
141
|
+
'Add secrets to functions/.env (not the app .env)',
|
|
142
|
+
'Run: dndev sync-secrets to push to Firebase Secret Manager',
|
|
143
|
+
'Secrets are auto-loaded by Cloud Functions at runtime',
|
|
144
|
+
'Never put server secrets in VITE_ variables',
|
|
145
|
+
]}
|
|
146
|
+
/>
|
|
147
|
+
|
|
148
|
+
<Card
|
|
149
|
+
title="Stripe (Payments)"
|
|
150
|
+
subtitle="Subscriptions, one-time payments, customer portal"
|
|
151
|
+
content={[
|
|
152
|
+
'Go to dashboard.stripe.com ā create account',
|
|
153
|
+
'Get API keys from Developers ā API Keys',
|
|
154
|
+
'Add to functions/.env: STRIPE_SECRET_KEY=sk_test_...',
|
|
155
|
+
'Add to .env: VITE_STRIPE_PUBLISHABLE_KEY=pk_test_...',
|
|
156
|
+
'Set up webhook: Developers ā Webhooks ā Add endpoint',
|
|
157
|
+
'Webhook URL: https://<your-functions-url>/stripeWebhook',
|
|
158
|
+
'Run: dndev sync-secrets to push secret key to Firebase',
|
|
159
|
+
]}
|
|
160
|
+
/>
|
|
161
|
+
|
|
162
|
+
<Card
|
|
163
|
+
title="Custom Domain"
|
|
164
|
+
subtitle="Use your own domain instead of .web.app"
|
|
165
|
+
content={[
|
|
166
|
+
'Firebase Console ā Hosting ā Add custom domain',
|
|
167
|
+
'Add DNS records as instructed',
|
|
168
|
+
'SSL certificate provisioned automatically',
|
|
169
|
+
]}
|
|
170
|
+
/>
|
|
171
|
+
</Grid>
|
|
172
|
+
</Section>
|
|
173
|
+
|
|
174
|
+
{/* ================================================================ */}
|
|
175
|
+
{/* NEXT STEPS */}
|
|
176
|
+
{/* ================================================================ */}
|
|
177
|
+
|
|
178
|
+
<Section title="Start Building" tone="muted" align="center">
|
|
179
|
+
<Stack align="center" gap="medium">
|
|
180
|
+
<Text level="body">
|
|
181
|
+
Once setup is complete, use WAI-WAY to build your app:
|
|
182
|
+
</Text>
|
|
183
|
+
<List
|
|
184
|
+
items={[
|
|
185
|
+
'Phase 0: Brainstorm ā describe your app, produce a spec',
|
|
186
|
+
'Phase 1: Scaffold ā create all pages and routes',
|
|
187
|
+
'Phase 2: Entities ā define your data models',
|
|
188
|
+
'Phase 3: Compose ā build pages with framework components',
|
|
189
|
+
'Phase 4: Configure ā generate tests, firestore rules, CI/CD',
|
|
190
|
+
]}
|
|
191
|
+
ordered
|
|
192
|
+
/>
|
|
193
|
+
<Text level="small">
|
|
194
|
+
Read guides/wai-way/WAI_WAY_CLI.md for the full workflow, or use the MCP tools if your IDE supports them.
|
|
195
|
+
</Text>
|
|
106
196
|
</Stack>
|
|
107
197
|
</Section>
|
|
108
198
|
</PageContainer>
|
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
|
|
7
7
|
import { build } from 'esbuild';
|
|
8
8
|
import { writeFileSync } from 'fs';
|
|
9
|
-
import { createAppFunctionsConfig, generateFunctionsYamlWithInfo } from '@donotdev/core/functions';
|
|
9
|
+
import { createAppFunctionsConfig, generateFunctionsYamlWithInfo, filterEnvSecrets } from '@donotdev/core/functions';
|
|
10
10
|
import { functionsConfig } from './functions.config.js';
|
|
11
11
|
|
|
12
12
|
async function buildFunctions() {
|
|
13
13
|
console.log('šØ Building {{APP_NAME}} functions...');
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
try {
|
|
16
16
|
const config = createAppFunctionsConfig({
|
|
17
17
|
entry: 'src/index.ts',
|
|
@@ -21,26 +21,42 @@ async function buildFunctions() {
|
|
|
21
21
|
});
|
|
22
22
|
|
|
23
23
|
console.log('š¦ Bundling @donotdev/types and importing framework functions...');
|
|
24
|
-
|
|
24
|
+
|
|
25
25
|
const result = await build(config);
|
|
26
|
-
|
|
26
|
+
|
|
27
27
|
if (result.errors.length > 0) {
|
|
28
28
|
console.error('ā Build errors:', result.errors);
|
|
29
29
|
process.exit(1);
|
|
30
30
|
}
|
|
31
|
-
|
|
31
|
+
|
|
32
32
|
if (result.warnings.length > 0) {
|
|
33
33
|
console.warn('ā ļø Build warnings:', result.warnings);
|
|
34
34
|
}
|
|
35
|
-
|
|
35
|
+
|
|
36
36
|
console.log('ā
{{APP_NAME}} functions built successfully!');
|
|
37
37
|
console.log('š Output directory: lib/');
|
|
38
38
|
|
|
39
|
-
// Generate functions.yaml from config
|
|
40
|
-
|
|
39
|
+
// Generate functions.yaml from config + auto-detection
|
|
40
|
+
// Auto-detects: exported functions from src/index.ts + secrets from .env
|
|
41
|
+
const { yaml, staticFunctions, crudFunctions, autoDetected, autoSecrets } = generateFunctionsYamlWithInfo(
|
|
42
|
+
functionsConfig,
|
|
43
|
+
{ entryFile: 'src/index.ts', envPath: '.env' }
|
|
44
|
+
);
|
|
41
45
|
writeFileSync('functions.yaml', yaml);
|
|
42
46
|
console.log(`š Generated functions.yaml: ${staticFunctions.length} static + ${crudFunctions.length} CRUD functions`);
|
|
43
|
-
|
|
47
|
+
if (autoDetected.length > 0) {
|
|
48
|
+
console.log(`š Auto-detected ${autoDetected.length} function(s) from src/index.ts: ${autoDetected.join(', ')}`);
|
|
49
|
+
}
|
|
50
|
+
if (autoSecrets.length > 0) {
|
|
51
|
+
console.log(`š Auto-detected ${autoSecrets.length} secret(s) from .env: ${autoSecrets.join(', ')}`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Filter .env: move secret keys to .env.local (emulator-only, never deployed)
|
|
55
|
+
const { stripped } = filterEnvSecrets(functionsConfig);
|
|
56
|
+
if (stripped.length > 0) {
|
|
57
|
+
console.log(`š Filtered ${stripped.length} secret(s) from .env ā .env.local`);
|
|
58
|
+
}
|
|
59
|
+
|
|
44
60
|
// Log bundle info if metafile is available
|
|
45
61
|
if (result.metafile) {
|
|
46
62
|
const { analyzeMetafile } = await import('esbuild');
|
|
@@ -48,7 +64,7 @@ async function buildFunctions() {
|
|
|
48
64
|
console.log('\nš Bundle analysis:');
|
|
49
65
|
console.log(analysis);
|
|
50
66
|
}
|
|
51
|
-
|
|
67
|
+
|
|
52
68
|
} catch (error) {
|
|
53
69
|
console.error('ā Build failed:', error);
|
|
54
70
|
process.exit(1);
|
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
|
|
7
7
|
import { build } from 'esbuild';
|
|
8
8
|
import { writeFileSync } from 'fs';
|
|
9
|
-
import { createAppFunctionsConfig, generateFunctionsYamlWithInfo } from '@donotdev/core/functions';
|
|
9
|
+
import { createAppFunctionsConfig, generateFunctionsYamlWithInfo, filterEnvSecrets } from '@donotdev/core/functions';
|
|
10
10
|
import { functionsConfig } from './functions.config.js';
|
|
11
11
|
|
|
12
12
|
async function buildFunctions() {
|
|
13
13
|
console.log('šØ Building {{APP_NAME}} functions...');
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
try {
|
|
16
16
|
const config = createAppFunctionsConfig({
|
|
17
17
|
entry: 'src/index.ts',
|
|
@@ -21,26 +21,42 @@ async function buildFunctions() {
|
|
|
21
21
|
});
|
|
22
22
|
|
|
23
23
|
console.log('š¦ Bundling @donotdev/types and importing framework functions...');
|
|
24
|
-
|
|
24
|
+
|
|
25
25
|
const result = await build(config);
|
|
26
|
-
|
|
26
|
+
|
|
27
27
|
if (result.errors.length > 0) {
|
|
28
28
|
console.error('ā Build errors:', result.errors);
|
|
29
29
|
process.exit(1);
|
|
30
30
|
}
|
|
31
|
-
|
|
31
|
+
|
|
32
32
|
if (result.warnings.length > 0) {
|
|
33
33
|
console.warn('ā ļø Build warnings:', result.warnings);
|
|
34
34
|
}
|
|
35
|
-
|
|
35
|
+
|
|
36
36
|
console.log('ā
{{APP_NAME}} functions built successfully!');
|
|
37
37
|
console.log('š Output directory: lib/');
|
|
38
38
|
|
|
39
|
-
// Generate functions.yaml from config
|
|
40
|
-
|
|
39
|
+
// Generate functions.yaml from config + auto-detection
|
|
40
|
+
// Auto-detects: exported functions from src/index.ts + secrets from .env
|
|
41
|
+
const { yaml, staticFunctions, crudFunctions, autoDetected, autoSecrets } = generateFunctionsYamlWithInfo(
|
|
42
|
+
functionsConfig,
|
|
43
|
+
{ entryFile: 'src/index.ts', envPath: '.env' }
|
|
44
|
+
);
|
|
41
45
|
writeFileSync('functions.yaml', yaml);
|
|
42
46
|
console.log(`š Generated functions.yaml: ${staticFunctions.length} static + ${crudFunctions.length} CRUD functions`);
|
|
43
|
-
|
|
47
|
+
if (autoDetected.length > 0) {
|
|
48
|
+
console.log(`š Auto-detected ${autoDetected.length} function(s) from src/index.ts: ${autoDetected.join(', ')}`);
|
|
49
|
+
}
|
|
50
|
+
if (autoSecrets.length > 0) {
|
|
51
|
+
console.log(`š Auto-detected ${autoSecrets.length} secret(s) from .env: ${autoSecrets.join(', ')}`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Filter .env: move secret keys to .env.local (emulator-only, never deployed)
|
|
55
|
+
const { stripped } = filterEnvSecrets(functionsConfig);
|
|
56
|
+
if (stripped.length > 0) {
|
|
57
|
+
console.log(`š Filtered ${stripped.length} secret(s) from .env ā .env.local`);
|
|
58
|
+
}
|
|
59
|
+
|
|
44
60
|
// Log bundle info if metafile is available
|
|
45
61
|
if (result.metafile) {
|
|
46
62
|
const { analyzeMetafile } = await import('esbuild');
|
|
@@ -48,7 +64,7 @@ async function buildFunctions() {
|
|
|
48
64
|
console.log('\nš Bundle analysis:');
|
|
49
65
|
console.log(analysis);
|
|
50
66
|
}
|
|
51
|
-
|
|
67
|
+
|
|
52
68
|
} catch (error) {
|
|
53
69
|
console.error('ā Build failed:', error);
|
|
54
70
|
process.exit(1);
|
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
* @fileoverview {{APP_NAME}} Functions Configuration
|
|
5
5
|
* @description Configuration for Firebase Functions deployment
|
|
6
6
|
* @type {import('@donotdev/types').FunctionsConfig}
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
7
|
+
*
|
|
8
|
+
* Static functions are AUTO-DETECTED from src/index.ts exports.
|
|
9
|
+
* Secrets are AUTO-DETECTED from .env (non-config keys).
|
|
10
|
+
* You only need to list CRUD entities and set defaults.
|
|
11
|
+
*
|
|
12
|
+
* Use the `functions` object ONLY for overrides (e.g., HTTP triggers for webhooks).
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
export const functionsConfig = {
|
|
@@ -18,18 +18,14 @@ export const functionsConfig = {
|
|
|
18
18
|
platform: 'gcfv2',
|
|
19
19
|
labels: { app: '{{APP_NAME}}' },
|
|
20
20
|
},
|
|
21
|
+
// Static functions are auto-detected from src/index.ts exports.
|
|
22
|
+
// Only add entries here for overrides:
|
|
21
23
|
functions: {
|
|
22
|
-
//
|
|
23
|
-
// Example:
|
|
24
|
-
// getCustomClaims: { category: 'auth' },
|
|
25
|
-
// setCustomClaims: { category: 'auth' },
|
|
26
|
-
// stripeWebhook: { category: 'billing', trigger: 'http' },
|
|
24
|
+
// stripeWebhook: { trigger: 'http' }, // Override: HTTP trigger instead of callable
|
|
27
25
|
},
|
|
28
26
|
crud: {
|
|
29
|
-
// List entity names to auto-generate CRUD functions
|
|
30
|
-
// Each
|
|
31
|
-
// Example:
|
|
32
|
-
// entities: ['car', 'customer', 'inquiry'],
|
|
27
|
+
// List entity collection names to auto-generate CRUD functions
|
|
28
|
+
// Each generates: create_*, get_*, list_*, listCard_*, update_*, delete_*
|
|
33
29
|
entities: [],
|
|
34
30
|
},
|
|
35
31
|
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
name: CI/CD
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
env:
|
|
10
|
+
NODE_VERSION: '20'
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
quality:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
- uses: oven-sh/setup-bun@v2
|
|
18
|
+
- run: bun install --frozen-lockfile
|
|
19
|
+
- run: bun run type-check
|
|
20
|
+
- run: bun test
|
|
21
|
+
|
|
22
|
+
deploy:
|
|
23
|
+
needs: quality
|
|
24
|
+
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
|
|
25
|
+
runs-on: ubuntu-latest
|
|
26
|
+
steps:
|
|
27
|
+
- uses: actions/checkout@v4
|
|
28
|
+
- uses: oven-sh/setup-bun@v2
|
|
29
|
+
- run: bun install --frozen-lockfile
|
|
30
|
+
- run: bun run build
|
|
31
|
+
- uses: FirebaseExtended/action-hosting-deploy@v0
|
|
32
|
+
with:
|
|
33
|
+
repoToken: ${{ secrets.GITHUB_TOKEN }}
|
|
34
|
+
firebaseServiceAccount: ${{ secrets.FIREBASE_SERVICE_ACCOUNT }}
|
|
35
|
+
channelId: live
|
|
36
|
+
projectId: {{firebaseProjectId}}
|