@donotdev/cli 0.0.14 → 0.0.15

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 (151) hide show
  1. package/dependencies-matrix.json +356 -88
  2. package/dist/bin/commands/agent-setup.js +7 -1
  3. package/dist/bin/commands/build.js +118 -38
  4. package/dist/bin/commands/bump.js +74 -28
  5. package/dist/bin/commands/cacheout.js +37 -9
  6. package/dist/bin/commands/create-app.js +222 -115
  7. package/dist/bin/commands/create-project.js +455 -140
  8. package/dist/bin/commands/deploy.js +1736 -697
  9. package/dist/bin/commands/dev.js +138 -23
  10. package/dist/bin/commands/emu.js +215 -58
  11. package/dist/bin/commands/format.js +37 -9
  12. package/dist/bin/commands/lint.js +37 -9
  13. package/dist/bin/commands/preview.js +142 -23
  14. package/dist/bin/commands/supabase-setup.d.ts +6 -0
  15. package/dist/bin/commands/supabase-setup.d.ts.map +1 -0
  16. package/dist/bin/commands/supabase-setup.js +7 -0
  17. package/dist/bin/commands/supabase-setup.js.map +1 -0
  18. package/dist/bin/commands/sync-secrets.js +211 -34
  19. package/dist/bin/commands/type-check.d.ts +14 -0
  20. package/dist/bin/commands/type-check.d.ts.map +1 -0
  21. package/dist/bin/commands/type-check.js +314 -0
  22. package/dist/bin/commands/type-check.js.map +1 -0
  23. package/dist/bin/commands/wai.js +3 -1
  24. package/dist/bin/dndev.js +27 -2
  25. package/dist/bin/donotdev.js +27 -2
  26. package/dist/index.js +3960 -3015
  27. package/package.json +2 -2
  28. package/templates/app-demo/src/App.tsx.example +1 -0
  29. package/templates/app-demo/src/pages/FullPage.tsx.example +2 -2
  30. package/templates/app-demo/src/pages/components/DemoLayout.tsx.example +2 -2
  31. package/templates/app-demo/src/themes.css.example +5 -12
  32. package/templates/app-expo/.env.example +64 -0
  33. package/templates/app-expo/.expo/README.md.example +5 -0
  34. package/templates/app-expo/.gitignore.example +36 -0
  35. package/templates/app-expo/README.md.example +58 -0
  36. package/templates/app-expo/app/.gitkeep +2 -0
  37. package/templates/app-expo/app/_layout.tsx.example +41 -0
  38. package/templates/app-expo/app/form.tsx.example +52 -0
  39. package/templates/app-expo/app/index.tsx.example +89 -0
  40. package/templates/app-expo/app/list.tsx.example +32 -0
  41. package/templates/app-expo/app/profile.tsx.example +76 -0
  42. package/templates/app-expo/app/signin.tsx.example +53 -0
  43. package/templates/app-expo/app.json.example +39 -0
  44. package/templates/app-expo/babel.config.js.example +10 -0
  45. package/templates/app-expo/eas.json.example +20 -0
  46. package/templates/app-expo/expo-env.d.ts.example +4 -0
  47. package/templates/app-expo/metro.config.js.example +20 -0
  48. package/templates/app-expo/service-account-key.json.example +12 -0
  49. package/templates/app-expo/tsconfig.json.example +19 -0
  50. package/templates/app-next/.env.example +4 -33
  51. package/templates/app-next/src/app/ClientLayout.tsx.example +2 -0
  52. package/templates/app-next/src/app/layout.tsx.example +7 -6
  53. package/templates/app-next/src/globals.css.example +2 -11
  54. package/templates/app-next/src/pages/HomePage.tsx.example +1 -1
  55. package/templates/app-next/src/themes.css.example +10 -13
  56. package/templates/app-vite/.env.example +3 -32
  57. package/templates/app-vite/index.html.example +2 -24
  58. package/templates/app-vite/src/App.tsx.example +2 -0
  59. package/templates/app-vite/src/globals.css.example +2 -12
  60. package/templates/app-vite/src/pages/FormPageExample.tsx.example +1 -2
  61. package/templates/app-vite/src/pages/HomePage.tsx.example +1 -1
  62. package/templates/app-vite/src/themes.css.example +109 -79
  63. package/templates/app-vite/vercel.json.example +11 -0
  64. package/templates/functions-firebase/build.mjs.example +2 -72
  65. package/templates/functions-firebase/functions-firebase/.env.example.example +23 -25
  66. package/templates/functions-firebase/functions-firebase/build.mjs.example +2 -72
  67. package/templates/functions-firebase/functions-firebase/tsconfig.json.example +1 -1
  68. package/templates/functions-supabase/supabase/functions/cancel-subscription/index.ts.example +7 -0
  69. package/templates/functions-supabase/supabase/functions/change-plan/index.ts.example +11 -0
  70. package/templates/functions-supabase/supabase/functions/create-checkout-session/index.ts.example +11 -0
  71. package/templates/functions-supabase/supabase/functions/create-customer-portal/index.ts.example +7 -0
  72. package/templates/functions-supabase/supabase/functions/crud/index.ts.example +16 -0
  73. package/templates/functions-supabase/supabase/functions/delete-account/index.ts.example +7 -0
  74. package/templates/functions-supabase/supabase/functions/get-custom-claims/index.ts.example +7 -0
  75. package/templates/functions-supabase/supabase/functions/get-user-auth-status/index.ts.example +7 -0
  76. package/templates/functions-supabase/supabase/functions/refresh-subscription-status/index.ts.example +7 -0
  77. package/templates/functions-supabase/supabase/functions/remove-custom-claims/index.ts.example +7 -0
  78. package/templates/functions-supabase/supabase/functions/set-custom-claims/index.ts.example +7 -0
  79. package/templates/functions-supabase/supabase/migrations/20250101000000_idempotency.sql +24 -0
  80. package/templates/functions-supabase/supabase/migrations/20250101000001_rate_limits.sql +22 -0
  81. package/templates/functions-supabase/supabase/migrations/20250101000002_cleanup_jobs.sql +28 -0
  82. package/templates/functions-supabase/supabase/migrations/20250101000003_operation_metrics.sql +28 -0
  83. package/templates/functions-vercel/functions-vercel/tsconfig.json.example +1 -1
  84. package/templates/functions-vercel/functions-vercel/vercel.json.example +1 -1
  85. package/templates/functions-vercel/vercel.json.example +1 -1
  86. package/templates/github/github/workflows/firebase-deploy.yml.example +1 -1
  87. package/templates/github/workflows/firebase-deploy.yml.example +1 -1
  88. package/templates/overlay-firebase/env.fragment.example +34 -0
  89. package/templates/overlay-firebase/env.fragment.expo.example +34 -0
  90. package/templates/overlay-firebase/env.fragment.nextjs.example +34 -0
  91. package/templates/overlay-firebase/src/config/providers.expo.ts.example +49 -0
  92. package/templates/overlay-firebase/src/config/providers.ts.example +23 -0
  93. package/templates/overlay-supabase/env.fragment.example +7 -0
  94. package/templates/overlay-supabase/env.fragment.expo.example +7 -0
  95. package/templates/overlay-supabase/env.fragment.nextjs.example +7 -0
  96. package/templates/overlay-supabase/src/config/providers.expo.ts.example +35 -0
  97. package/templates/overlay-supabase/src/config/providers.ts.example +33 -0
  98. package/templates/overlay-supabase/vercel.headers.example +23 -0
  99. package/templates/overlay-supabase/vercel.json.example +22 -0
  100. package/templates/overlay-vercel/env.fragment.example +34 -0
  101. package/templates/overlay-vercel/env.fragment.nextjs.example +34 -0
  102. package/templates/overlay-vercel/src/config/providers.ts.example +24 -0
  103. package/templates/root-consumer/.claude/agents/architect.md.example +2 -310
  104. package/templates/root-consumer/.claude/agents/builder.md.example +2 -326
  105. package/templates/root-consumer/.claude/agents/coder.md.example +2 -83
  106. package/templates/root-consumer/.claude/agents/extractor.md.example +2 -231
  107. package/templates/root-consumer/.claude/agents/polisher.md.example +2 -132
  108. package/templates/root-consumer/.claude/agents/prompt-engineer.md.example +2 -81
  109. package/templates/root-consumer/.claude/commands/grill.md.example +30 -0
  110. package/templates/root-consumer/.claude/commands/techdebt.md.example +28 -0
  111. package/templates/root-consumer/.clinerules.example +1 -0
  112. package/templates/root-consumer/.cursor/rules/no-docs.mdc.example +15 -0
  113. package/templates/root-consumer/.cursorrules.example +1 -0
  114. package/templates/root-consumer/.github/copilot-instructions.md.example +1 -0
  115. package/templates/root-consumer/.windsurfrules.example +1 -0
  116. package/templates/root-consumer/AI.md.example +29 -123
  117. package/templates/root-consumer/CLAUDE.md.example +1 -134
  118. package/templates/root-consumer/CONVENTIONS.md.example +1 -0
  119. package/templates/root-consumer/GEMINI.md.example +1 -0
  120. package/templates/root-consumer/firebase.json.example +1 -1
  121. package/templates/root-consumer/guides/dndev/AGENT_START_HERE.md.example +20 -0
  122. package/templates/root-consumer/guides/dndev/COMPONENTS_ADV.md.example +0 -18
  123. package/templates/root-consumer/guides/dndev/COMPONENTS_UI.md.example +1 -1
  124. package/templates/root-consumer/guides/dndev/ENV_SETUP.md.example +99 -30
  125. package/templates/root-consumer/guides/dndev/INDEX.md.example +3 -1
  126. package/templates/root-consumer/guides/dndev/SETUP_CRUD.md.example +143 -12
  127. package/templates/root-consumer/guides/dndev/SETUP_FIREBASE.md.example +9 -3
  128. package/templates/root-consumer/guides/dndev/SETUP_SOC2.md.example +234 -0
  129. package/templates/root-consumer/guides/dndev/SETUP_SUPABASE.md.example +124 -0
  130. package/templates/root-consumer/guides/dndev/SETUP_THEMES.md.example +6 -2
  131. package/templates/root-consumer/guides/dndev/SETUP_VERCEL.md.example +176 -0
  132. package/templates/root-consumer/guides/dndev/USE_ROUTING.md.example +5 -9
  133. package/templates/root-consumer/guides/dndev/essences_reference.css.example +174 -0
  134. package/templates/root-consumer/guides/wai-way/agents/builder.md.example +10 -0
  135. package/templates/root-consumer/guides/wai-way/agents/extractor.md.example +25 -5
  136. package/templates/root-consumer/guides/wai-way/agents/polisher.md.example +13 -2
  137. package/templates/root-consumer/guides/wai-way/blueprints/0_brainstorm.md.example +2 -2
  138. package/templates/root-consumer/guides/wai-way/blueprints/1_scaffold.md.example +47 -11
  139. package/templates/root-consumer/guides/wai-way/blueprints/3_compose.md.example +15 -4
  140. package/templates/root-consumer/guides/wai-way/spec_template.md.example +7 -6
  141. package/templates/app-payload/.env.example +0 -28
  142. package/templates/app-payload/README.md.example +0 -233
  143. package/templates/app-payload/collections/Company.ts.example +0 -125
  144. package/templates/app-payload/collections/Hero.ts.example +0 -62
  145. package/templates/app-payload/collections/Media.ts.example +0 -41
  146. package/templates/app-payload/collections/Products.ts.example +0 -115
  147. package/templates/app-payload/collections/Services.ts.example +0 -104
  148. package/templates/app-payload/collections/Testimonials.ts.example +0 -92
  149. package/templates/app-payload/collections/Users.ts.example +0 -35
  150. package/templates/app-payload/src/server.ts.example +0 -79
  151. package/templates/app-payload/tsconfig.json.example +0 -24
@@ -1,75 +1,5 @@
1
1
  #!/usr/bin/env node
2
- /**
3
- * @fileoverview Build script for {{APP_NAME}} functions
4
- * @description Bundles @donotdev/types and imports framework functions
5
- */
6
-
7
- import { build } from 'esbuild';
8
- import { writeFileSync } from 'fs';
9
- import { createAppFunctionsConfig, generateFunctionsYamlWithInfo, filterEnvSecrets } from '@donotdev/core/functions';
2
+ import { buildFunctions } from '@donotdev/core/functions';
10
3
  import { functionsConfig } from './functions.config.js';
11
4
 
12
- async function buildFunctions() {
13
- console.log('🔨 Building {{APP_NAME}} functions...');
14
-
15
- try {
16
- const config = createAppFunctionsConfig({
17
- entry: 'src/index.ts',
18
- outDir: 'lib',
19
- minify: process.env.NODE_ENV === 'production',
20
- sourcemap: true,
21
- });
22
-
23
- console.log('📦 Bundling @donotdev/types and importing framework functions...');
24
-
25
- const result = await build(config);
26
-
27
- if (result.errors.length > 0) {
28
- console.error('❌ Build errors:', result.errors);
29
- process.exit(1);
30
- }
31
-
32
- if (result.warnings.length > 0) {
33
- console.warn('⚠️ Build warnings:', result.warnings);
34
- }
35
-
36
- console.log('✅ {{APP_NAME}} functions built successfully!');
37
- console.log('📁 Output directory: lib/');
38
-
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
- );
45
- writeFileSync('functions.yaml', yaml);
46
- console.log(`📄 Generated functions.yaml: ${staticFunctions.length} static + ${crudFunctions.length} CRUD functions`);
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
-
60
- // Log bundle info if metafile is available
61
- if (result.metafile) {
62
- const { analyzeMetafile } = await import('esbuild');
63
- const analysis = await analyzeMetafile(result.metafile);
64
- console.log('\n📊 Bundle analysis:');
65
- console.log(analysis);
66
- }
67
-
68
- } catch (error) {
69
- console.error('❌ Build failed:', error);
70
- process.exit(1);
71
- }
72
- }
73
-
74
- // Run the build
75
- buildFunctions();
5
+ buildFunctions(functionsConfig);
@@ -1,45 +1,43 @@
1
1
  # =============================================================================
2
- # {{APP_NAME}} Firebase Functions Environment Variables
2
+ # {{APP_NAME}} Server-Side Environment Variables
3
3
  # =============================================================================
4
- # Copy this file to .env in the functions directory and update with your values
4
+ # Copy this file to .env in the functions directory and fill in your values.
5
+ #
6
+ # IMPORTANT: These are SECRET keys. Never put them in VITE_* or NEXT_PUBLIC_*
7
+ # variables. Never commit this file to git.
8
+ #
9
+ # Sync to runtime: dndev sync-secrets
10
+ # Sync to GitHub: dndev sync-secrets --target github
5
11
 
6
12
  # =============================================================================
7
13
  # Stripe Configuration
14
+ # Get keys from: https://dashboard.stripe.com/apikeys
8
15
  # =============================================================================
9
- # Stripe Secret Key (server-side only)
10
- STRIPE_SECRET_KEY=sk_test_1234567890abcdef
16
+ STRIPE_SECRET_KEY=sk_test_...
17
+ STRIPE_WEBHOOK_SECRET=whsec_...
11
18
 
12
- # Stripe Webhook Secret (for webhook signature verification)
13
- STRIPE_WEBHOOK_SECRET=whsec_1234567890abcdef
19
+ # =============================================================================
20
+ # Supabase (server-side only — if using Supabase backend)
21
+ # Get from: https://supabase.com/dashboard → Settings → API
22
+ # =============================================================================
23
+ # SUPABASE_SERVICE_ROLE_KEY=eyJ...
14
24
 
15
25
  # =============================================================================
16
26
  # GitHub Configuration
17
- # =============================================================================
18
- # GitHub Personal Access Token (for repository access management)
27
+ # Get token from: https://github.com/settings/tokens
19
28
  # Required scopes: repo (full control of private repositories)
20
- GITHUB_PERSONAL_ACCESS_TOKEN=ghp_1234567890abcdef
21
-
22
- # GitHub Repository Configuration
23
- GITHUB_REPO_OWNER=your-org
24
- GITHUB_REPO_NAME=your-repo
29
+ # =============================================================================
30
+ # GITHUB_PERSONAL_ACCESS_TOKEN=ghp_...
31
+ # GITHUB_REPO_OWNER=your-org
32
+ # GITHUB_REPO_NAME=your-repo
25
33
 
26
34
  # =============================================================================
27
- # Firebase Configuration
35
+ # Firebase Configuration (auto-detected, rarely needed manually)
28
36
  # =============================================================================
29
- # Firebase Project ID (usually auto-detected from Firebase Admin SDK)
30
37
  FIREBASE_PROJECT_ID=your-project-id
31
-
32
- # Firebase Region (default: us-central1)
33
38
  FIREBASE_REGION=us-central1
34
39
 
35
40
  # =============================================================================
36
- # Development Configuration
41
+ # Development
37
42
  # =============================================================================
38
- # Node Environment
39
43
  NODE_ENV=development
40
-
41
- # =============================================================================
42
- # Setup Instructions
43
- # =============================================================================
44
- # 1. Get Stripe keys from: https://dashboard.stripe.com/apikeys
45
- # 2. Get GitHub token from: https://github.com/settings/tokens
@@ -1,75 +1,5 @@
1
1
  #!/usr/bin/env node
2
- /**
3
- * @fileoverview Build script for {{APP_NAME}} functions
4
- * @description Bundles @donotdev/types and imports framework functions
5
- */
6
-
7
- import { build } from 'esbuild';
8
- import { writeFileSync } from 'fs';
9
- import { createAppFunctionsConfig, generateFunctionsYamlWithInfo, filterEnvSecrets } from '@donotdev/core/functions';
2
+ import { buildFunctions } from '@donotdev/core/functions';
10
3
  import { functionsConfig } from './functions.config.js';
11
4
 
12
- async function buildFunctions() {
13
- console.log('🔨 Building {{APP_NAME}} functions...');
14
-
15
- try {
16
- const config = createAppFunctionsConfig({
17
- entry: 'src/index.ts',
18
- outDir: 'lib',
19
- minify: process.env.NODE_ENV === 'production',
20
- sourcemap: true,
21
- });
22
-
23
- console.log('📦 Bundling @donotdev/types and importing framework functions...');
24
-
25
- const result = await build(config);
26
-
27
- if (result.errors.length > 0) {
28
- console.error('❌ Build errors:', result.errors);
29
- process.exit(1);
30
- }
31
-
32
- if (result.warnings.length > 0) {
33
- console.warn('⚠️ Build warnings:', result.warnings);
34
- }
35
-
36
- console.log('✅ {{APP_NAME}} functions built successfully!');
37
- console.log('📁 Output directory: lib/');
38
-
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
- );
45
- writeFileSync('functions.yaml', yaml);
46
- console.log(`📄 Generated functions.yaml: ${staticFunctions.length} static + ${crudFunctions.length} CRUD functions`);
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
-
60
- // Log bundle info if metafile is available
61
- if (result.metafile) {
62
- const { analyzeMetafile } = await import('esbuild');
63
- const analysis = await analyzeMetafile(result.metafile);
64
- console.log('\n📊 Bundle analysis:');
65
- console.log(analysis);
66
- }
67
-
68
- } catch (error) {
69
- console.error('❌ Build failed:', error);
70
- process.exit(1);
71
- }
72
- }
73
-
74
- // Run the build
75
- buildFunctions();
5
+ buildFunctions(functionsConfig);
@@ -1,5 +1,5 @@
1
1
  {
2
- "extends": "../../tsconfig.base.json",
2
+ "extends": "../../../tsconfig.functions.json",
3
3
  "compilerOptions": {
4
4
  "outDir": "./lib",
5
5
  "rootDir": "./src",
@@ -0,0 +1,7 @@
1
+ // supabase/functions/cancel-subscription/index.ts
2
+ // Supabase Edge Function — Cancel Subscription
3
+ // Deploy: supabase functions deploy cancel-subscription
4
+
5
+ import { createCancelSubscription } from '@donotdev/functions/supabase';
6
+
7
+ Deno.serve(createCancelSubscription());
@@ -0,0 +1,11 @@
1
+ // supabase/functions/change-plan/index.ts
2
+ // Supabase Edge Function — Change Subscription Plan
3
+ // Deploy: supabase functions deploy change-plan
4
+
5
+ import { createChangePlan } from '@donotdev/functions/supabase';
6
+
7
+ // Import your billing config
8
+ // import { billingConfig } from '../_shared/billingConfig.ts';
9
+ const billingConfig = {}; // TODO: Replace with your StripeBackConfig
10
+
11
+ Deno.serve(createChangePlan(billingConfig));
@@ -0,0 +1,11 @@
1
+ // supabase/functions/create-checkout-session/index.ts
2
+ // Supabase Edge Function — Stripe Checkout Session
3
+ // Deploy: supabase functions deploy create-checkout-session
4
+
5
+ import { createCheckoutSession } from '@donotdev/functions/supabase';
6
+
7
+ // Import your billing config
8
+ // import { billingConfig } from '../_shared/billingConfig.ts';
9
+ const billingConfig = {}; // TODO: Replace with your StripeBackConfig
10
+
11
+ Deno.serve(createCheckoutSession(billingConfig));
@@ -0,0 +1,7 @@
1
+ // supabase/functions/create-customer-portal/index.ts
2
+ // Supabase Edge Function — Stripe Customer Portal
3
+ // Deploy: supabase functions deploy create-customer-portal
4
+
5
+ import { createCustomerPortal } from '@donotdev/functions/supabase';
6
+
7
+ Deno.serve(createCustomerPortal());
@@ -0,0 +1,16 @@
1
+ // supabase/functions/crud/index.ts
2
+ // Supabase Edge Function — CRUD Operations
3
+ // Deploy: supabase functions deploy crud
4
+ //
5
+ // This single Edge Function handles all CRUD operations for all entities.
6
+ // The SupabaseCallableProvider automatically routes CRUD calls here.
7
+
8
+ import { createSupabaseCrudFunctions } from '@donotdev/functions/supabase';
9
+
10
+ // Import your entities
11
+ // import * as entities from '../_shared/entities.ts';
12
+ const entities = {}; // TODO: Replace with your entity imports
13
+
14
+ const { serve } = createSupabaseCrudFunctions(entities);
15
+
16
+ Deno.serve(serve);
@@ -0,0 +1,7 @@
1
+ // supabase/functions/delete-account/index.ts
2
+ // Supabase Edge Function — Account Deletion
3
+ // Deploy: supabase functions deploy delete-account
4
+
5
+ import { createDeleteAccount } from '@donotdev/functions/supabase';
6
+
7
+ Deno.serve(createDeleteAccount());
@@ -0,0 +1,7 @@
1
+ // supabase/functions/get-custom-claims/index.ts
2
+ // Supabase Edge Function — Get Custom Claims (app_metadata)
3
+ // Deploy: supabase functions deploy get-custom-claims
4
+
5
+ import { createGetCustomClaims } from '@donotdev/functions/supabase';
6
+
7
+ Deno.serve(createGetCustomClaims());
@@ -0,0 +1,7 @@
1
+ // supabase/functions/get-user-auth-status/index.ts
2
+ // Supabase Edge Function — Get User Auth Status
3
+ // Deploy: supabase functions deploy get-user-auth-status
4
+
5
+ import { createGetUserAuthStatus } from '@donotdev/functions/supabase';
6
+
7
+ Deno.serve(createGetUserAuthStatus());
@@ -0,0 +1,7 @@
1
+ // supabase/functions/refresh-subscription-status/index.ts
2
+ // Supabase Edge Function — Refresh Subscription Status
3
+ // Deploy: supabase functions deploy refresh-subscription-status
4
+
5
+ import { createRefreshSubscriptionStatus } from '@donotdev/functions/supabase';
6
+
7
+ Deno.serve(createRefreshSubscriptionStatus());
@@ -0,0 +1,7 @@
1
+ // supabase/functions/remove-custom-claims/index.ts
2
+ // Supabase Edge Function — Remove Custom Claims from app_metadata
3
+ // Deploy: supabase functions deploy remove-custom-claims
4
+
5
+ import { createRemoveCustomClaims } from '@donotdev/functions/supabase';
6
+
7
+ Deno.serve(createRemoveCustomClaims());
@@ -0,0 +1,7 @@
1
+ // supabase/functions/set-custom-claims/index.ts
2
+ // Supabase Edge Function — Set Custom Claims (app_metadata)
3
+ // Deploy: supabase functions deploy set-custom-claims
4
+
5
+ import { createSetCustomClaims } from '@donotdev/functions/supabase';
6
+
7
+ Deno.serve(createSetCustomClaims());
@@ -0,0 +1,24 @@
1
+ -- Migration: Create idempotency table for Supabase CRUD operations
2
+ -- Generated: 2026-02-19
3
+ -- Purpose: Store operation results to prevent duplicate processing
4
+ -- TTL: 24 hours default, configurable per operation
5
+
6
+ CREATE TABLE IF NOT EXISTS idempotency (
7
+ id TEXT PRIMARY KEY, -- Format: "{operation}_{idempotencyKey}"
8
+ operation TEXT NOT NULL, -- 'create', 'update', 'delete', etc.
9
+ idempotency_key TEXT NOT NULL UNIQUE, -- Client-provided key
10
+ result JSONB NOT NULL, -- Cached operation result
11
+ processed_at TIMESTAMPTZ NOT NULL DEFAULT now(),
12
+ processed_by TEXT NOT NULL, -- User ID
13
+ expires_at TIMESTAMPTZ NOT NULL -- TTL for cleanup (default: 24h)
14
+ );
15
+
16
+ -- Indexes for efficient lookups
17
+ CREATE INDEX IF NOT EXISTS idx_idempotency_expires ON idempotency(expires_at);
18
+ CREATE INDEX IF NOT EXISTS idx_idempotency_key ON idempotency(idempotency_key);
19
+ CREATE INDEX IF NOT EXISTS idx_idempotency_operation ON idempotency(operation, expires_at);
20
+
21
+ -- Comments
22
+ COMMENT ON TABLE idempotency IS 'Stores idempotency keys and cached operation results to prevent duplicate processing';
23
+ COMMENT ON COLUMN idempotency.id IS 'Composite key: {operation}_{idempotencyKey}';
24
+ COMMENT ON COLUMN idempotency.expires_at IS 'TTL for automatic cleanup - defaults to 24 hours from processed_at';
@@ -0,0 +1,22 @@
1
+ -- Migration: Create rate_limits table for Supabase Edge Functions
2
+ -- Generated: 2026-02-19
3
+ -- Purpose: Track API call rates per user/IP to prevent abuse
4
+ -- Pattern: Same as Firebase Firestore rateLimits collection
5
+
6
+ CREATE TABLE IF NOT EXISTS rate_limits (
7
+ key TEXT PRIMARY KEY, -- Format: "{operation}_{identifier}" (e.g., "create_apartment_uid_123")
8
+ attempts INTEGER NOT NULL DEFAULT 1,
9
+ window_start TIMESTAMPTZ NOT NULL DEFAULT now(),
10
+ block_until TIMESTAMPTZ, -- NULL if not blocked
11
+ last_updated TIMESTAMPTZ NOT NULL DEFAULT now()
12
+ );
13
+
14
+ -- Indexes for efficient lookups and cleanup
15
+ CREATE INDEX IF NOT EXISTS idx_rate_limits_window ON rate_limits(window_start);
16
+ CREATE INDEX IF NOT EXISTS idx_rate_limits_block ON rate_limits(block_until) WHERE block_until IS NOT NULL;
17
+ CREATE INDEX IF NOT EXISTS idx_rate_limits_updated ON rate_limits(last_updated);
18
+
19
+ -- Comments
20
+ COMMENT ON TABLE rate_limits IS 'Tracks API call rates per operation and identifier (user ID or IP)';
21
+ COMMENT ON COLUMN rate_limits.key IS 'Composite key: {operation}_{identifier_type}_{identifier_value}';
22
+ COMMENT ON COLUMN rate_limits.block_until IS 'Timestamp when rate limit block expires (NULL if not blocked)';
@@ -0,0 +1,28 @@
1
+ -- Migration: Create cleanup cron jobs for idempotency and rate_limits tables
2
+ -- Generated: 2026-02-19
3
+ -- Purpose: Automatically clean up expired records to prevent table bloat
4
+ -- Schedule: Daily at 2 AM UTC (idempotency), 3 AM UTC (rate_limits), 4 AM UTC (metrics)
5
+
6
+ -- Enable pg_cron extension (if not already enabled)
7
+ CREATE EXTENSION IF NOT EXISTS pg_cron;
8
+
9
+ -- Cleanup expired idempotency records (daily at 2 AM UTC)
10
+ SELECT cron.schedule(
11
+ 'cleanup-idempotency',
12
+ '0 2 * * *',
13
+ $$DELETE FROM idempotency WHERE expires_at < now()$$
14
+ );
15
+
16
+ -- Cleanup old rate limit records (daily at 3 AM UTC)
17
+ SELECT cron.schedule(
18
+ 'cleanup-rate-limits',
19
+ '0 3 * * *',
20
+ $$DELETE FROM rate_limits WHERE window_start + interval '7 days' < now()$$
21
+ );
22
+
23
+ -- Cleanup old operation metrics (daily at 4 AM UTC)
24
+ SELECT cron.schedule(
25
+ 'cleanup-operation-metrics',
26
+ '0 4 * * *',
27
+ $$DELETE FROM operation_metrics WHERE timestamp < now() - interval '90 days'$$
28
+ );
@@ -0,0 +1,28 @@
1
+ -- Migration: Create operation_metrics table for Supabase Edge Functions monitoring
2
+ -- Generated: 2026-02-19
3
+ -- Purpose: Track operation success/failure rates, duration, and user activity
4
+ -- Retention: 90 days (configurable via cleanup job)
5
+
6
+ CREATE TABLE IF NOT EXISTS operation_metrics (
7
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
8
+ operation TEXT NOT NULL, -- e.g., 'create_apartment', 'get_user'
9
+ user_id TEXT, -- NULL for guest operations
10
+ status TEXT NOT NULL, -- 'success', 'failed', 'pending'
11
+ duration_ms INTEGER, -- Operation duration in milliseconds
12
+ timestamp TIMESTAMPTZ NOT NULL DEFAULT now(),
13
+ metadata JSONB, -- Additional context (request ID, etc.)
14
+ error_code TEXT, -- If status = 'failed'
15
+ error_message TEXT -- If status = 'failed'
16
+ );
17
+
18
+ -- Indexes for efficient queries
19
+ CREATE INDEX IF NOT EXISTS idx_metrics_operation ON operation_metrics(operation, timestamp DESC);
20
+ CREATE INDEX IF NOT EXISTS idx_metrics_user ON operation_metrics(user_id, timestamp DESC) WHERE user_id IS NOT NULL;
21
+ CREATE INDEX IF NOT EXISTS idx_metrics_status ON operation_metrics(status, timestamp DESC);
22
+ CREATE INDEX IF NOT EXISTS idx_metrics_timestamp ON operation_metrics(timestamp DESC);
23
+
24
+ -- Comments
25
+ COMMENT ON TABLE operation_metrics IS 'Tracks operation metrics for monitoring and analytics';
26
+ COMMENT ON COLUMN operation_metrics.operation IS 'Operation name (e.g., create_apartment, get_user)';
27
+ COMMENT ON COLUMN operation_metrics.duration_ms IS 'Operation duration in milliseconds';
28
+ COMMENT ON COLUMN operation_metrics.metadata IS 'Additional context as JSON (request ID, etc.)';
@@ -1,5 +1,5 @@
1
1
  {
2
- "extends": "../../tsconfig.base.json",
2
+ "extends": "../../../tsconfig.functions.json",
3
3
  "compilerOptions": {
4
4
  "outDir": "./lib",
5
5
  "rootDir": "./src",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "functions": {
3
3
  "src/api/**/*.ts": {
4
- "runtime": "nodejs20.x"
4
+ "runtime": "nodejs22.x"
5
5
  }
6
6
  },
7
7
  "env": {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "functions": {
3
3
  "src/api/**/*.ts": {
4
- "runtime": "nodejs20.x"
4
+ "runtime": "nodejs22.x"
5
5
  }
6
6
  },
7
7
  "env": {
@@ -32,7 +32,7 @@ jobs:
32
32
  - name: Set up Node.js
33
33
  uses: actions/setup-node@v4
34
34
  with:
35
- node-version: '20' # Using Node 20
35
+ node-version: '22' # Using Node 22 LTS
36
36
 
37
37
  # Step 5: Setup Bun
38
38
  - name: Install Bun
@@ -32,7 +32,7 @@ jobs:
32
32
  - name: Set up Node.js
33
33
  uses: actions/setup-node@v4
34
34
  with:
35
- node-version: '20' # Using Node 20
35
+ node-version: '22' # Using Node 22 LTS
36
36
 
37
37
  # Step 5: Setup Bun
38
38
  - name: Install Bun
@@ -0,0 +1,34 @@
1
+
2
+ # =============================================================================
3
+ # Firebase Configuration
4
+ # =============================================================================
5
+ # Get these values from your Firebase project settings
6
+ # Run `dndev firebase:setup` to auto-populate, or copy from Firebase Console
7
+ VITE_FIREBASE_API_KEY=
8
+ VITE_FIREBASE_PROJECT_ID=
9
+ # Copy from Firebase Console. Framework uses APP_URL hostname in production automatically.
10
+ VITE_FIREBASE_AUTH_DOMAIN=
11
+ VITE_FIREBASE_STORAGE_BUCKET=
12
+ VITE_FIREBASE_MESSAGING_SENDER_ID=
13
+ VITE_FIREBASE_APP_ID=
14
+ VITE_FIREBASE_MEASUREMENT_ID=
15
+ VITE_FIREBASE_FUNCTIONS_REGION=
16
+
17
+ # =============================================================================
18
+ # Firebase Emulator (Development only)
19
+ # =============================================================================
20
+ # Set to true to use Firebase emulators instead of production services
21
+ VITE_USE_FIREBASE_EMULATOR=false
22
+ VITE_FIREBASE_EMULATOR_HOST=localhost
23
+ VITE_FIREBASE_EMULATOR_PORT=9099
24
+ VITE_FIREBASE_AUTH_EMULATOR_HOST=http://localhost:9099
25
+ VITE_FIREBASE_FIRESTORE_EMULATOR_HOST=localhost:8080
26
+ VITE_FIREBASE_FUNCTIONS_EMULATOR_PORT=5001
27
+
28
+ # =============================================================================
29
+ # Firebase App Check (Abuse Protection)
30
+ # =============================================================================
31
+ # reCAPTCHA v3 site key for App Check
32
+ # VITE_RECAPTCHA_SITE_KEY=6LcXXXX...
33
+ # Optional: Debug token for localhost testing
34
+ # VITE_APPCHECK_DEBUG_TOKEN=XXXX-XXXX-XXXX
@@ -0,0 +1,34 @@
1
+
2
+ # =============================================================================
3
+ # Firebase Configuration
4
+ # =============================================================================
5
+ # Get these values from your Firebase project settings
6
+ # Run `dndev firebase:setup` to auto-populate, or copy from Firebase Console
7
+ EXPO_PUBLIC_FIREBASE_API_KEY=
8
+ EXPO_PUBLIC_FIREBASE_PROJECT_ID=
9
+ # Copy from Firebase Console. Framework uses APP_URL hostname in production automatically.
10
+ EXPO_PUBLIC_FIREBASE_AUTH_DOMAIN=
11
+ EXPO_PUBLIC_FIREBASE_STORAGE_BUCKET=
12
+ EXPO_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=
13
+ EXPO_PUBLIC_FIREBASE_APP_ID=
14
+ EXPO_PUBLIC_FIREBASE_MEASUREMENT_ID=
15
+ EXPO_PUBLIC_FIREBASE_FUNCTIONS_REGION=
16
+
17
+ # =============================================================================
18
+ # Firebase Emulator (Development only)
19
+ # =============================================================================
20
+ # Set to true to use Firebase emulators instead of production services
21
+ EXPO_PUBLIC_USE_FIREBASE_EMULATOR=false
22
+ EXPO_PUBLIC_FIREBASE_EMULATOR_HOST=localhost
23
+ EXPO_PUBLIC_FIREBASE_EMULATOR_PORT=9099
24
+ EXPO_PUBLIC_FIREBASE_AUTH_EMULATOR_HOST=http://localhost:9099
25
+ EXPO_PUBLIC_FIREBASE_FIRESTORE_EMULATOR_HOST=localhost:8080
26
+ EXPO_PUBLIC_FIREBASE_FUNCTIONS_EMULATOR_PORT=5001
27
+
28
+ # =============================================================================
29
+ # Firebase App Check (Abuse Protection)
30
+ # =============================================================================
31
+ # reCAPTCHA v3 site key for App Check
32
+ # EXPO_PUBLIC_RECAPTCHA_SITE_KEY=6LcXXXX...
33
+ # Optional: Debug token for localhost testing
34
+ # EXPO_PUBLIC_APPCHECK_DEBUG_TOKEN=XXXX-XXXX-XXXX
@@ -0,0 +1,34 @@
1
+
2
+ # =============================================================================
3
+ # Firebase Configuration
4
+ # =============================================================================
5
+ # Get these values from your Firebase project settings
6
+ # Run `dndev firebase:setup` to auto-populate, or copy from Firebase Console
7
+ NEXT_PUBLIC_FIREBASE_API_KEY=
8
+ NEXT_PUBLIC_FIREBASE_PROJECT_ID=
9
+ # Copy from Firebase Console. Framework uses APP_URL hostname in production automatically.
10
+ NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=
11
+ NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=
12
+ NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=
13
+ NEXT_PUBLIC_FIREBASE_APP_ID=
14
+ NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID=
15
+ NEXT_PUBLIC_FIREBASE_FUNCTIONS_REGION=
16
+
17
+ # =============================================================================
18
+ # Firebase Emulator (Development only)
19
+ # =============================================================================
20
+ # Set to true to use Firebase emulators instead of production services
21
+ NEXT_PUBLIC_USE_FIREBASE_EMULATOR=false
22
+ NEXT_PUBLIC_FIREBASE_EMULATOR_HOST=localhost
23
+ NEXT_PUBLIC_FIREBASE_EMULATOR_PORT=9099
24
+ NEXT_PUBLIC_FIREBASE_AUTH_EMULATOR_HOST=http://localhost:9099
25
+ NEXT_PUBLIC_FIREBASE_FIRESTORE_EMULATOR_HOST=localhost:8080
26
+ NEXT_PUBLIC_FIREBASE_FUNCTIONS_EMULATOR_PORT=5001
27
+
28
+ # =============================================================================
29
+ # Firebase App Check (Abuse Protection)
30
+ # =============================================================================
31
+ # reCAPTCHA v3 site key for App Check
32
+ # NEXT_PUBLIC_RECAPTCHA_SITE_KEY=6LcXXXX...
33
+ # Optional: Debug token for localhost testing
34
+ # NEXT_PUBLIC_APPCHECK_DEBUG_TOKEN=XXXX-XXXX-XXXX