@donotdev/cli 0.0.11 → 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.
Files changed (68) hide show
  1. package/dependencies-matrix.json +30 -116
  2. package/dist/bin/commands/bump.js +137 -104
  3. package/dist/bin/commands/create-app.js +20 -0
  4. package/dist/bin/commands/create-project.js +63 -7
  5. package/dist/bin/commands/deploy.js +7606 -17
  6. package/dist/bin/commands/firebase-setup.d.ts +6 -0
  7. package/dist/bin/commands/firebase-setup.d.ts.map +1 -0
  8. package/dist/bin/commands/firebase-setup.js +7 -0
  9. package/dist/bin/commands/firebase-setup.js.map +1 -0
  10. package/dist/bin/commands/staging.d.ts +11 -0
  11. package/dist/bin/commands/staging.d.ts.map +1 -0
  12. package/dist/bin/commands/staging.js +12 -0
  13. package/dist/bin/commands/staging.js.map +1 -0
  14. package/dist/bin/dndev.js +28 -3
  15. package/dist/bin/donotdev.js +28 -3
  16. package/dist/index.d.ts +1 -1
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +7714 -62
  19. package/dist/index.js.map +1 -1
  20. package/package.json +1 -1
  21. package/templates/app-demo/src/pages/DetailPage.tsx.example +1 -1
  22. package/templates/app-demo/src/pages/FullPage.tsx.example +3 -3
  23. package/templates/app-demo/src/pages/HomePage.tsx.example +1 -1
  24. package/templates/app-demo/src/pages/components/ComponentRenderer.tsx.example +5 -5
  25. package/templates/app-demo/src/pages/components/DemoLayout.tsx.example +3 -3
  26. package/templates/app-next/.env.example +2 -0
  27. package/templates/app-next/src/pages/HomePage.tsx.example +2 -2
  28. package/templates/app-vite/.env.example +2 -0
  29. package/templates/app-vite/src/pages/HomePage.tsx.example +163 -73
  30. package/templates/functions-firebase/build.mjs.example +26 -10
  31. package/templates/functions-firebase/functions-firebase/build.mjs.example +26 -10
  32. package/templates/functions-firebase/functions.config.js.example +11 -15
  33. package/templates/github-consumer/.github/workflows/ci.yml.example +36 -0
  34. package/templates/root-consumer/.claude/agents/architect.md.example +2 -2
  35. package/templates/root-consumer/.claude/agents/builder.md.example +2 -2
  36. package/templates/root-consumer/.claude/agents/coder.md.example +2 -2
  37. package/templates/root-consumer/.claude/agents/extractor.md.example +2 -3
  38. package/templates/root-consumer/.claude/agents/polisher.md.example +67 -291
  39. package/templates/root-consumer/.claude/agents/prompt-engineer.md.example +4 -4
  40. package/templates/root-consumer/.claude/commands/build.md.example +2 -2
  41. package/templates/root-consumer/.claude/commands/polish.md.example +65 -81
  42. package/templates/root-consumer/.env.example +13 -13
  43. package/templates/root-consumer/.gemini/settings.json.example +9 -0
  44. package/templates/root-consumer/.gitignore.example +3 -1
  45. package/templates/root-consumer/AI.md.example +139 -0
  46. package/templates/root-consumer/CLAUDE.md.example +13 -104
  47. package/templates/root-consumer/README.md.example +81 -255
  48. package/templates/root-consumer/entities/Contact.ts.example +126 -0
  49. package/templates/root-consumer/entities/index.ts.example +6 -3
  50. package/templates/root-consumer/guides/dndev/AGENT_START_HERE.md.example +41 -342
  51. package/templates/root-consumer/guides/dndev/COMPONENTS_ADV.md.example +2 -1
  52. package/templates/root-consumer/guides/dndev/ENV_SETUP.md.example +144 -9
  53. package/templates/root-consumer/guides/dndev/INDEX.md.example +9 -0
  54. package/templates/root-consumer/guides/dndev/SETUP_APP_CONFIG.md.example +13 -16
  55. package/templates/root-consumer/guides/dndev/SETUP_BLOG.md.example +263 -0
  56. package/templates/root-consumer/guides/dndev/SETUP_CRUD.md.example +1 -1
  57. package/templates/root-consumer/guides/dndev/SETUP_FIREBASE.md.example +168 -0
  58. package/templates/root-consumer/guides/dndev/SETUP_FUNCTIONS.md.example +5 -12
  59. package/templates/root-consumer/guides/dndev/SETUP_TESTING.md.example +184 -0
  60. package/templates/root-consumer/guides/wai-way/WAI_WAY_CLI.md.example +134 -69
  61. package/templates/root-consumer/guides/wai-way/agents/polisher.md.example +66 -44
  62. package/templates/root-consumer/guides/wai-way/blueprints/0_brainstorm.md.example +18 -1
  63. package/templates/root-consumer/guides/wai-way/blueprints/1_scaffold.md.example +1 -0
  64. package/templates/root-consumer/guides/wai-way/blueprints/2_entities.md.example +2 -1
  65. package/templates/root-consumer/guides/wai-way/blueprints/3_compose.md.example +2 -1
  66. package/templates/root-consumer/guides/wai-way/blueprints/4_configure.md.example +180 -108
  67. package/templates/root-consumer/guides/wai-way/context_map.json.example +8 -7
  68. 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,GACP,MAAM,mBAAmB,CAAC"}
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@donotdev/cli",
3
- "version": "0.0.11",
3
+ "version": "0.0.13",
4
4
  "description": "Command-line interface for DoNotDev Framework",
5
5
  "type": "module",
6
6
  "private": false,
@@ -78,7 +78,7 @@ export default function DetailPage() {
78
78
  .map(([k, v]) => `${k}: ${v}`);
79
79
 
80
80
  return (
81
- <Stack key={idx} gap="medium" align="center">
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 gap="medium">
84
+ <Stack>
85
85
  <Card variant="muted" title="Stack Item 1">
86
- <Text variant="muted">Vertical stack with gap="medium"</Text>
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" gap="medium">
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" gap="medium">
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 gap="medium" className="dndev-w-full dndev-max-w-md">
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 gap="medium" align="stretch">
436
- <Stack direction="row" gap="medium" align="center">
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 gap="medium" align="center" justify="center" style={{ minHeight: '200px', position: 'relative', zIndex: 10000 }}>
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" gap="medium">
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 gap="medium">
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" gap="medium" align="center" justify="start">
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" gap="medium" justify="end" align="center">
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=
@@ -68,7 +68,7 @@ export default function HomePage() {
68
68
  <RadioGroup
69
69
  value={currentPreset || 'landing'}
70
70
  onValueChange={(value) => setLayoutPreset(value as LayoutPreset)}
71
- gridCols={3}
71
+ gridCols={[1,1,3,3]}
72
72
  items={LAYOUT_PRESETS.map((preset) => ({
73
73
  value: preset,
74
74
  label: preset.charAt(0).toUpperCase() + preset.slice(1),
@@ -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" gap="medium">
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
- * THIS FILE IS YOUR STARTING POINT. Modify the content below.
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 { Button, HeroSection, Section, Card, Grid, Stack } from '@donotdev/components';
16
+ import { HeroSection, Section, Card, Grid, List, Alert, Text, Stack } from '@donotdev/components';
16
17
  import type { PageMeta } from '@donotdev/core';
17
- import { PageContainer, Link } from '@donotdev/ui';
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="Welcome to Your App"
61
- subtitle="Built with DoNotDev Framework. Edit this page in src/pages/HomePage.tsx"
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
- {/* Section - Content block with optional title */}
66
- <Section title="Getting Started">
67
- <Grid cols={[1, 1, 2, 3]} gap="medium">
68
- <Card title="1. Configure" content="Edit src/config/app.ts to set your app name and preset." />
69
- <Card title="2. Create Pages" content="Add *Page.tsx files in src/pages/ - they auto-route." />
70
- <Card title="3. Add Content" content="Use components from @donotdev/components." />
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
- {/* Stack - Flexible container for buttons, inline items */}
75
- <Section title="Layout Components">
76
- <Stack direction="row" gap="medium" wrap>
77
- <Button variant="primary">Primary Button</Button>
78
- <Button variant="outline">Outline Button</Button>
79
- <Button variant="ghost">Ghost Button</Button>
80
- </Stack>
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
- {/* Call to Action */}
84
- <Section tone="muted" align="center">
85
- <Stack gap="medium" align="center">
86
- <h2>Ready to Build?</h2>
87
- <p>Check out the guides folder for setup instructions.</p>
88
- <Stack direction="row" gap="medium">
89
- <Button
90
- variant="primary"
91
- render={({ children, ...props }) => (
92
- <Link path="https://donotdev.com" {...props}>{children}</Link>
93
- )}
94
- >
95
- Documentation
96
- </Button>
97
- <Button
98
- variant="outline"
99
- render={({ children, ...props }) => (
100
- <Link path="https://discord.gg/donotdev" {...props}>{children}</Link>
101
- )}
102
- >
103
- Join Discord
104
- </Button>
105
- </Stack>
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
- const { yaml, staticFunctions, crudFunctions } = generateFunctionsYamlWithInfo(functionsConfig);
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
- const { yaml, staticFunctions, crudFunctions } = generateFunctionsYamlWithInfo(functionsConfig);
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
- * This config file is used to auto-generate functions.yaml during build.
9
- *
10
- * - Static functions: List your custom functions here
11
- * - CRUD functions: List entity names to auto-generate CRUD endpoints
12
- * (e.g., ['car', 'customer'] generates: create_car, get_car, list_car, update_car, delete_car, etc.)
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
- // Add your static (non-CRUD) functions here
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 entity will generate: create_*, get_*, list_*, update_*, delete_*
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
  };