@digilogiclabs/create-saas-app 2.0.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/README.md +975 -891
- package/dist/.tsbuildinfo +1 -1
- package/dist/generators/template-generator.d.ts +11 -0
- package/dist/generators/template-generator.d.ts.map +1 -1
- package/dist/generators/template-generator.js +389 -18
- package/dist/generators/template-generator.js.map +1 -1
- package/dist/index.js +1837 -0
- package/dist/index.js.map +1 -0
- package/dist/templates/infrastructure/kubernetes/base/template/README.md +253 -0
- package/dist/templates/infrastructure/kubernetes/base/template/configmap.yaml +12 -0
- package/dist/templates/infrastructure/kubernetes/base/template/deployment.yaml +123 -0
- package/dist/templates/infrastructure/kubernetes/base/template/hpa.yaml +45 -0
- package/dist/templates/infrastructure/kubernetes/base/template/ingress.yaml +31 -0
- package/dist/templates/infrastructure/kubernetes/base/template/kustomization.yaml +25 -0
- package/dist/templates/infrastructure/kubernetes/base/template/namespace.yaml +8 -0
- package/dist/templates/infrastructure/kubernetes/base/template/networkpolicy.yaml +48 -0
- package/dist/templates/infrastructure/kubernetes/base/template/pdb.yaml +14 -0
- package/dist/templates/infrastructure/kubernetes/base/template/secret.yaml +17 -0
- package/dist/templates/infrastructure/kubernetes/base/template/service.yaml +19 -0
- package/dist/templates/infrastructure/kubernetes/base/template/serviceaccount.yaml +9 -0
- package/dist/templates/infrastructure/kubernetes/production/template/kustomization.yaml +92 -0
- package/dist/templates/infrastructure/terraform/aws/template/README.md +156 -0
- package/dist/templates/infrastructure/terraform/aws/template/main.tf +343 -0
- package/dist/templates/infrastructure/terraform/aws/template/outputs.tf +66 -0
- package/dist/templates/infrastructure/terraform/aws/template/terraform.tfvars.example +28 -0
- package/dist/templates/infrastructure/terraform/aws/template/variables.tf +110 -0
- package/dist/templates/infrastructure/terraform/gcp/template/README.md +165 -0
- package/dist/templates/infrastructure/terraform/gcp/template/main.tf +397 -0
- package/dist/templates/infrastructure/terraform/gcp/template/outputs.tf +51 -0
- package/dist/templates/infrastructure/terraform/gcp/template/terraform.tfvars.example +29 -0
- package/dist/templates/infrastructure/terraform/gcp/template/variables.tf +115 -0
- package/dist/templates/shared/admin/web/app/admin/layout.tsx +34 -0
- package/dist/templates/shared/admin/web/components/admin-nav.tsx +48 -0
- package/dist/templates/shared/audit/web/lib/audit.ts +24 -0
- package/dist/templates/shared/auth/keycloak/web/app/api/auth/federated-logout/route.ts +173 -0
- package/dist/templates/shared/auth/keycloak/web/auth.config.ts +84 -0
- package/dist/templates/shared/auth/keycloak/web/auth.ts +26 -0
- package/dist/templates/shared/beta/web/app/api/beta-settings/route.ts +25 -0
- package/dist/templates/shared/beta/web/app/api/validate-beta-code/route.ts +67 -0
- package/dist/templates/shared/beta/web/lib/beta/settings.ts +31 -0
- package/dist/templates/shared/cache/web/lib/cache.ts +44 -0
- package/dist/templates/shared/config/web/lib/config.ts +112 -0
- package/dist/templates/shared/config/web/next.config.mjs +62 -0
- package/dist/templates/shared/contact/web/app/api/contact/route.ts +113 -0
- package/dist/templates/shared/contact/web/app/contact/page.tsx +195 -0
- package/dist/templates/shared/cookie-consent/web/components/cookie-consent.tsx +54 -0
- package/dist/templates/shared/database/postgresql/web/drizzle.config.ts +16 -0
- package/dist/templates/shared/database/postgresql/web/lib/db/drizzle.ts +39 -0
- package/dist/templates/shared/database/postgresql/web/lib/db/schema.ts +33 -0
- package/dist/templates/shared/database/supabase/web/lib/supabase/client.ts +12 -0
- package/dist/templates/shared/database/supabase/web/lib/supabase/server.ts +31 -0
- package/dist/templates/shared/database/supabase/web/lib/supabase/service.ts +15 -0
- package/dist/templates/shared/email/web/lib/email/branding.ts +18 -0
- package/dist/templates/shared/email/web/lib/email/client.ts +96 -0
- package/dist/templates/shared/error-pages/web/app/error.tsx +70 -0
- package/dist/templates/shared/error-pages/web/app/global-error.tsx +102 -0
- package/dist/templates/shared/error-pages/web/app/not-found.tsx +39 -0
- package/dist/templates/shared/health/web/app/api/health/route.ts +68 -0
- package/dist/templates/shared/legal/web/app/(legal)/privacy/page.tsx +205 -0
- package/dist/templates/shared/legal/web/app/(legal)/terms/page.tsx +154 -0
- package/dist/templates/shared/legal/web/lib/legal-config.ts +50 -0
- package/dist/templates/shared/loading/web/app/loading.tsx +5 -0
- package/dist/templates/shared/loading/web/components/skeleton.tsx +95 -0
- package/dist/templates/shared/middleware/web/middleware.ts +68 -0
- package/dist/templates/shared/observability/web/lib/observability.ts +135 -0
- package/dist/templates/shared/payments/web/app/api/webhooks/stripe/route.ts +109 -0
- package/dist/templates/shared/platform/web/lib/platform.ts +37 -0
- package/dist/templates/shared/redis/web/lib/rate-limit-store.ts +18 -0
- package/dist/templates/shared/redis/web/lib/redis.ts +48 -0
- package/dist/templates/shared/security/web/lib/api-security.ts +318 -0
- package/dist/templates/shared/seo/web/app/api/og/route.tsx +97 -0
- package/dist/templates/shared/seo/web/app/robots.ts +53 -0
- package/dist/templates/shared/seo/web/app/sitemap.ts +53 -0
- package/dist/templates/shared/utils/web/lib/api-response.ts +71 -0
- package/dist/templates/shared/utils/web/lib/utils.ts +85 -0
- package/dist/templates/web/ai-platform/template/.env.example +16 -0
- package/dist/templates/web/ai-platform/template/README.md +84 -0
- package/dist/templates/web/ai-platform/template/middleware.ts +55 -0
- package/dist/templates/web/ai-platform/template/next.config.js +14 -0
- package/dist/templates/web/ai-platform/template/package.json +55 -0
- package/dist/templates/web/ai-platform/template/src/app/api/chat/route.ts +54 -0
- package/dist/templates/web/ai-platform/template/src/app/chat/page.tsx +235 -0
- package/dist/templates/web/ai-platform/template/src/app/dashboard/page.tsx +142 -0
- package/dist/templates/web/ai-platform/template/src/app/globals.css +34 -0
- package/dist/templates/web/ai-platform/template/src/app/layout.tsx +27 -0
- package/dist/templates/web/ai-platform/template/src/app/page.tsx +203 -0
- package/dist/templates/web/ai-platform/template/src/components/providers/app-providers.tsx +27 -0
- package/dist/templates/web/ai-platform/template/src/lib/auth-server.ts +33 -0
- package/dist/templates/web/ai-platform/template/src/lib/supabase/client.ts +8 -0
- package/dist/templates/web/ai-platform/template/src/lib/supabase/server.ts +27 -0
- package/dist/templates/web/ai-platform/template/src/lib/utils.ts +6 -0
- package/dist/templates/web/ai-platform/template/tsconfig.json +27 -0
- package/dist/templates/web/iot-dashboard/template/.env.example +12 -0
- package/dist/templates/web/iot-dashboard/template/README.md +101 -0
- package/dist/templates/web/iot-dashboard/template/middleware.ts +56 -0
- package/dist/templates/web/iot-dashboard/template/next.config.js +14 -0
- package/dist/templates/web/iot-dashboard/template/package.json +49 -0
- package/dist/templates/web/iot-dashboard/template/src/app/dashboard/page.tsx +229 -0
- package/dist/templates/web/iot-dashboard/template/src/app/globals.css +20 -0
- package/dist/templates/web/iot-dashboard/template/src/app/layout.tsx +27 -0
- package/dist/templates/web/iot-dashboard/template/src/app/page.tsx +191 -0
- package/dist/templates/web/iot-dashboard/template/src/components/providers/app-providers.tsx +24 -0
- package/dist/templates/web/iot-dashboard/template/src/lib/auth-server.ts +33 -0
- package/dist/templates/web/iot-dashboard/template/src/lib/supabase/client.ts +8 -0
- package/dist/templates/web/iot-dashboard/template/src/lib/supabase/server.ts +27 -0
- package/dist/templates/web/iot-dashboard/template/src/lib/utils.ts +25 -0
- package/dist/templates/web/iot-dashboard/template/tsconfig.json +27 -0
- package/dist/templates/web/marketplace/template/.env.example +12 -0
- package/dist/templates/web/marketplace/template/README.md +66 -0
- package/dist/templates/web/marketplace/template/middleware.ts +56 -0
- package/dist/templates/web/marketplace/template/next.config.js +14 -0
- package/dist/templates/web/marketplace/template/package.json +51 -0
- package/dist/templates/web/marketplace/template/src/app/cart/page.tsx +147 -0
- package/dist/templates/web/marketplace/template/src/app/dashboard/page.tsx +149 -0
- package/dist/templates/web/marketplace/template/src/app/globals.css +20 -0
- package/dist/templates/web/marketplace/template/src/app/layout.tsx +27 -0
- package/dist/templates/web/marketplace/template/src/app/page.tsx +167 -0
- package/dist/templates/web/marketplace/template/src/app/products/page.tsx +129 -0
- package/dist/templates/web/marketplace/template/src/components/providers/app-providers.tsx +27 -0
- package/dist/templates/web/marketplace/template/src/lib/auth-server.ts +33 -0
- package/dist/templates/web/marketplace/template/src/lib/supabase/client.ts +8 -0
- package/dist/templates/web/marketplace/template/src/lib/supabase/server.ts +27 -0
- package/dist/templates/web/marketplace/template/src/lib/utils.ts +19 -0
- package/dist/templates/web/marketplace/template/tsconfig.json +27 -0
- package/dist/templates/web/micro-saas/template/.env.example +10 -0
- package/dist/templates/web/micro-saas/template/README.md +63 -0
- package/dist/templates/web/micro-saas/template/middleware.ts +53 -0
- package/dist/templates/web/micro-saas/template/next.config.js +14 -0
- package/dist/templates/web/micro-saas/template/package.json +41 -0
- package/dist/templates/web/micro-saas/template/src/app/dashboard/page.tsx +117 -0
- package/dist/templates/web/micro-saas/template/src/app/globals.css +20 -0
- package/dist/templates/web/micro-saas/template/src/app/layout.tsx +27 -0
- package/dist/templates/web/micro-saas/template/src/app/login/page.tsx +87 -0
- package/dist/templates/web/micro-saas/template/src/app/page.tsx +137 -0
- package/dist/templates/web/micro-saas/template/src/app/signup/page.tsx +108 -0
- package/dist/templates/web/micro-saas/template/src/components/providers/app-providers.tsx +24 -0
- package/dist/templates/web/micro-saas/template/src/lib/auth-server.ts +33 -0
- package/dist/templates/web/micro-saas/template/src/lib/supabase/client.ts +8 -0
- package/dist/templates/web/micro-saas/template/src/lib/supabase/server.ts +29 -0
- package/dist/templates/web/micro-saas/template/src/lib/utils.ts +6 -0
- package/dist/templates/web/micro-saas/template/tsconfig.json +27 -0
- package/package.json +5 -4
- package/src/templates/infrastructure/kubernetes/base/template/README.md +253 -0
- package/src/templates/infrastructure/kubernetes/base/template/configmap.yaml +12 -0
- package/src/templates/infrastructure/kubernetes/base/template/deployment.yaml +123 -0
- package/src/templates/infrastructure/kubernetes/base/template/hpa.yaml +45 -0
- package/src/templates/infrastructure/kubernetes/base/template/ingress.yaml +31 -0
- package/src/templates/infrastructure/kubernetes/base/template/kustomization.yaml +25 -0
- package/src/templates/infrastructure/kubernetes/base/template/namespace.yaml +8 -0
- package/src/templates/infrastructure/kubernetes/base/template/networkpolicy.yaml +48 -0
- package/src/templates/infrastructure/kubernetes/base/template/pdb.yaml +14 -0
- package/src/templates/infrastructure/kubernetes/base/template/secret.yaml +17 -0
- package/src/templates/infrastructure/kubernetes/base/template/service.yaml +19 -0
- package/src/templates/infrastructure/kubernetes/base/template/serviceaccount.yaml +9 -0
- package/src/templates/infrastructure/kubernetes/production/template/kustomization.yaml +92 -0
- package/src/templates/infrastructure/terraform/aws/template/README.md +156 -0
- package/src/templates/infrastructure/terraform/aws/template/main.tf +343 -0
- package/src/templates/infrastructure/terraform/aws/template/outputs.tf +66 -0
- package/src/templates/infrastructure/terraform/aws/template/terraform.tfvars.example +28 -0
- package/src/templates/infrastructure/terraform/aws/template/variables.tf +110 -0
- package/src/templates/infrastructure/terraform/gcp/template/README.md +165 -0
- package/src/templates/infrastructure/terraform/gcp/template/main.tf +397 -0
- package/src/templates/infrastructure/terraform/gcp/template/outputs.tf +51 -0
- package/src/templates/infrastructure/terraform/gcp/template/terraform.tfvars.example +29 -0
- package/src/templates/infrastructure/terraform/gcp/template/variables.tf +115 -0
- package/src/templates/shared/admin/web/app/admin/layout.tsx +34 -0
- package/src/templates/shared/admin/web/components/admin-nav.tsx +48 -0
- package/src/templates/shared/audit/web/lib/audit.ts +24 -0
- package/src/templates/shared/auth/keycloak/web/app/api/auth/federated-logout/route.ts +173 -0
- package/src/templates/shared/auth/keycloak/web/auth.config.ts +84 -0
- package/src/templates/shared/auth/keycloak/web/auth.ts +26 -0
- package/src/templates/shared/beta/web/app/api/beta-settings/route.ts +25 -0
- package/src/templates/shared/beta/web/app/api/validate-beta-code/route.ts +67 -0
- package/src/templates/shared/beta/web/lib/beta/settings.ts +31 -0
- package/src/templates/shared/cache/web/lib/cache.ts +44 -0
- package/src/templates/shared/config/web/lib/config.ts +112 -0
- package/src/templates/shared/config/web/next.config.mjs +62 -0
- package/src/templates/shared/contact/web/app/api/contact/route.ts +113 -0
- package/src/templates/shared/contact/web/app/contact/page.tsx +195 -0
- package/src/templates/shared/cookie-consent/web/components/cookie-consent.tsx +54 -0
- package/src/templates/shared/database/postgresql/web/drizzle.config.ts +16 -0
- package/src/templates/shared/database/postgresql/web/lib/db/drizzle.ts +39 -0
- package/src/templates/shared/database/postgresql/web/lib/db/schema.ts +33 -0
- package/src/templates/shared/database/supabase/web/lib/supabase/client.ts +12 -0
- package/src/templates/shared/database/supabase/web/lib/supabase/server.ts +31 -0
- package/src/templates/shared/database/supabase/web/lib/supabase/service.ts +15 -0
- package/src/templates/shared/email/web/lib/email/branding.ts +18 -0
- package/src/templates/shared/email/web/lib/email/client.ts +96 -0
- package/src/templates/shared/error-pages/web/app/error.tsx +70 -0
- package/src/templates/shared/error-pages/web/app/global-error.tsx +102 -0
- package/src/templates/shared/error-pages/web/app/not-found.tsx +39 -0
- package/src/templates/shared/health/web/app/api/health/route.ts +68 -0
- package/src/templates/shared/legal/web/app/(legal)/privacy/page.tsx +205 -0
- package/src/templates/shared/legal/web/app/(legal)/terms/page.tsx +154 -0
- package/src/templates/shared/legal/web/lib/legal-config.ts +50 -0
- package/src/templates/shared/loading/web/app/loading.tsx +5 -0
- package/src/templates/shared/loading/web/components/skeleton.tsx +95 -0
- package/src/templates/shared/middleware/web/middleware.ts +68 -0
- package/src/templates/shared/observability/web/lib/observability.ts +135 -0
- package/src/templates/shared/payments/web/app/api/webhooks/stripe/route.ts +109 -0
- package/src/templates/shared/platform/web/lib/platform.ts +37 -0
- package/src/templates/shared/redis/web/lib/rate-limit-store.ts +18 -0
- package/src/templates/shared/redis/web/lib/redis.ts +48 -0
- package/src/templates/shared/security/web/lib/api-security.ts +318 -0
- package/src/templates/shared/seo/web/app/api/og/route.tsx +97 -0
- package/src/templates/shared/seo/web/app/robots.ts +53 -0
- package/src/templates/shared/seo/web/app/sitemap.ts +53 -0
- package/src/templates/shared/utils/web/lib/api-response.ts +71 -0
- package/src/templates/shared/utils/web/lib/utils.ts +85 -0
- package/src/templates/web/ai-platform/template/.env.example +16 -0
- package/src/templates/web/ai-platform/template/README.md +84 -0
- package/src/templates/web/ai-platform/template/middleware.ts +55 -0
- package/src/templates/web/ai-platform/template/next.config.js +14 -0
- package/src/templates/web/ai-platform/template/package.json +55 -0
- package/src/templates/web/ai-platform/template/src/app/api/chat/route.ts +54 -0
- package/src/templates/web/ai-platform/template/src/app/chat/page.tsx +235 -0
- package/src/templates/web/ai-platform/template/src/app/dashboard/page.tsx +142 -0
- package/src/templates/web/ai-platform/template/src/app/globals.css +34 -0
- package/src/templates/web/ai-platform/template/src/app/layout.tsx +27 -0
- package/src/templates/web/ai-platform/template/src/app/page.tsx +203 -0
- package/src/templates/web/ai-platform/template/src/components/providers/app-providers.tsx +27 -0
- package/src/templates/web/ai-platform/template/src/lib/auth-server.ts +33 -0
- package/src/templates/web/ai-platform/template/src/lib/supabase/client.ts +8 -0
- package/src/templates/web/ai-platform/template/src/lib/supabase/server.ts +27 -0
- package/src/templates/web/ai-platform/template/src/lib/utils.ts +6 -0
- package/src/templates/web/ai-platform/template/tsconfig.json +27 -0
- package/src/templates/web/iot-dashboard/template/.env.example +12 -0
- package/src/templates/web/iot-dashboard/template/README.md +101 -0
- package/src/templates/web/iot-dashboard/template/middleware.ts +56 -0
- package/src/templates/web/iot-dashboard/template/next.config.js +14 -0
- package/src/templates/web/iot-dashboard/template/package.json +49 -0
- package/src/templates/web/iot-dashboard/template/src/app/dashboard/page.tsx +229 -0
- package/src/templates/web/iot-dashboard/template/src/app/globals.css +20 -0
- package/src/templates/web/iot-dashboard/template/src/app/layout.tsx +27 -0
- package/src/templates/web/iot-dashboard/template/src/app/page.tsx +191 -0
- package/src/templates/web/iot-dashboard/template/src/components/providers/app-providers.tsx +24 -0
- package/src/templates/web/iot-dashboard/template/src/lib/auth-server.ts +33 -0
- package/src/templates/web/iot-dashboard/template/src/lib/supabase/client.ts +8 -0
- package/src/templates/web/iot-dashboard/template/src/lib/supabase/server.ts +27 -0
- package/src/templates/web/iot-dashboard/template/src/lib/utils.ts +25 -0
- package/src/templates/web/iot-dashboard/template/tsconfig.json +27 -0
- package/src/templates/web/marketplace/template/.env.example +12 -0
- package/src/templates/web/marketplace/template/README.md +66 -0
- package/src/templates/web/marketplace/template/middleware.ts +56 -0
- package/src/templates/web/marketplace/template/next.config.js +14 -0
- package/src/templates/web/marketplace/template/package.json +51 -0
- package/src/templates/web/marketplace/template/src/app/cart/page.tsx +147 -0
- package/src/templates/web/marketplace/template/src/app/dashboard/page.tsx +149 -0
- package/src/templates/web/marketplace/template/src/app/globals.css +20 -0
- package/src/templates/web/marketplace/template/src/app/layout.tsx +27 -0
- package/src/templates/web/marketplace/template/src/app/page.tsx +167 -0
- package/src/templates/web/marketplace/template/src/app/products/page.tsx +129 -0
- package/src/templates/web/marketplace/template/src/components/providers/app-providers.tsx +27 -0
- package/src/templates/web/marketplace/template/src/lib/auth-server.ts +33 -0
- package/src/templates/web/marketplace/template/src/lib/supabase/client.ts +8 -0
- package/src/templates/web/marketplace/template/src/lib/supabase/server.ts +27 -0
- package/src/templates/web/marketplace/template/src/lib/utils.ts +19 -0
- package/src/templates/web/marketplace/template/tsconfig.json +27 -0
- package/src/templates/web/micro-saas/template/.env.example +10 -0
- package/src/templates/web/micro-saas/template/README.md +63 -0
- package/src/templates/web/micro-saas/template/middleware.ts +53 -0
- package/src/templates/web/micro-saas/template/next.config.js +14 -0
- package/src/templates/web/micro-saas/template/package.json +41 -0
- package/src/templates/web/micro-saas/template/src/app/dashboard/page.tsx +117 -0
- package/src/templates/web/micro-saas/template/src/app/globals.css +20 -0
- package/src/templates/web/micro-saas/template/src/app/layout.tsx +27 -0
- package/src/templates/web/micro-saas/template/src/app/login/page.tsx +87 -0
- package/src/templates/web/micro-saas/template/src/app/page.tsx +137 -0
- package/src/templates/web/micro-saas/template/src/app/signup/page.tsx +108 -0
- package/src/templates/web/micro-saas/template/src/components/providers/app-providers.tsx +24 -0
- package/src/templates/web/micro-saas/template/src/lib/auth-server.ts +33 -0
- package/src/templates/web/micro-saas/template/src/lib/supabase/client.ts +8 -0
- package/src/templates/web/micro-saas/template/src/lib/supabase/server.ts +29 -0
- package/src/templates/web/micro-saas/template/src/lib/utils.ts +6 -0
- package/src/templates/web/micro-saas/template/tsconfig.json +27 -0
- package/dist/cli/commands/add.d.ts +0 -6
- package/dist/cli/commands/add.d.ts.map +0 -1
- package/dist/cli/commands/add.js +0 -39
- package/dist/cli/commands/add.js.map +0 -1
- package/dist/cli/commands/create.d.ts +0 -45
- package/dist/cli/commands/create.d.ts.map +0 -1
- package/dist/cli/commands/create.js +0 -175
- package/dist/cli/commands/create.js.map +0 -1
- package/dist/cli/commands/index.d.ts +0 -4
- package/dist/cli/commands/index.d.ts.map +0 -1
- package/dist/cli/commands/index.js +0 -20
- package/dist/cli/commands/index.js.map +0 -1
- package/dist/cli/commands/update.d.ts +0 -6
- package/dist/cli/commands/update.d.ts.map +0 -1
- package/dist/cli/commands/update.js +0 -68
- package/dist/cli/commands/update.js.map +0 -1
- package/dist/cli/index.d.ts +0 -4
- package/dist/cli/index.d.ts.map +0 -1
- package/dist/cli/index.js +0 -61
- package/dist/cli/index.js.map +0 -1
- package/dist/cli/prompts/index.d.ts +0 -2
- package/dist/cli/prompts/index.d.ts.map +0 -1
- package/dist/cli/prompts/index.js +0 -18
- package/dist/cli/prompts/index.js.map +0 -1
- package/dist/cli/prompts/project-setup.d.ts +0 -5
- package/dist/cli/prompts/project-setup.d.ts.map +0 -1
- package/dist/cli/prompts/project-setup.js +0 -316
- package/dist/cli/prompts/project-setup.js.map +0 -1
- package/dist/cli/utils/git.d.ts +0 -9
- package/dist/cli/utils/git.d.ts.map +0 -1
- package/dist/cli/utils/git.js +0 -77
- package/dist/cli/utils/git.js.map +0 -1
- package/dist/cli/utils/index.d.ts +0 -5
- package/dist/cli/utils/index.d.ts.map +0 -1
- package/dist/cli/utils/index.js +0 -21
- package/dist/cli/utils/index.js.map +0 -1
- package/dist/cli/utils/logger.d.ts +0 -16
- package/dist/cli/utils/logger.d.ts.map +0 -1
- package/dist/cli/utils/logger.js +0 -55
- package/dist/cli/utils/logger.js.map +0 -1
- package/dist/cli/utils/package-manager.d.ts +0 -8
- package/dist/cli/utils/package-manager.d.ts.map +0 -1
- package/dist/cli/utils/package-manager.js +0 -92
- package/dist/cli/utils/package-manager.js.map +0 -1
- package/dist/cli/utils/spinner.d.ts +0 -7
- package/dist/cli/utils/spinner.d.ts.map +0 -1
- package/dist/cli/utils/spinner.js +0 -48
- package/dist/cli/utils/spinner.js.map +0 -1
- package/dist/cli/validators/dependencies.d.ts +0 -15
- package/dist/cli/validators/dependencies.d.ts.map +0 -1
- package/dist/cli/validators/dependencies.js +0 -108
- package/dist/cli/validators/dependencies.js.map +0 -1
- package/dist/cli/validators/index.d.ts +0 -3
- package/dist/cli/validators/index.d.ts.map +0 -1
- package/dist/cli/validators/index.js +0 -19
- package/dist/cli/validators/index.js.map +0 -1
- package/dist/cli/validators/project-name.d.ts +0 -5
- package/dist/cli/validators/project-name.d.ts.map +0 -1
- package/dist/cli/validators/project-name.js +0 -151
- package/dist/cli/validators/project-name.js.map +0 -1
- package/dist/generators/file-processor.d.ts +0 -28
- package/dist/generators/file-processor.d.ts.map +0 -1
- package/dist/generators/file-processor.js +0 -224
- package/dist/generators/file-processor.js.map +0 -1
- package/dist/generators/index.d.ts +0 -4
- package/dist/generators/index.d.ts.map +0 -1
- package/dist/generators/index.js +0 -20
- package/dist/generators/index.js.map +0 -1
- package/dist/generators/package-installer.d.ts +0 -29
- package/dist/generators/package-installer.d.ts.map +0 -1
- package/dist/generators/package-installer.js +0 -177
- package/dist/generators/package-installer.js.map +0 -1
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# {{titleCaseName}} - GCP Terraform Outputs
|
|
2
|
+
|
|
3
|
+
output "vercel_project_id" {
|
|
4
|
+
description = "Vercel project ID"
|
|
5
|
+
value = vercel_project.app.id
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
output "vercel_domains" {
|
|
9
|
+
description = "Vercel project domains"
|
|
10
|
+
value = [var.domain]
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
output "storage_bucket_name" {
|
|
14
|
+
description = "Cloud Storage bucket name"
|
|
15
|
+
value = google_storage_bucket.storage.name
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
output "storage_bucket_url" {
|
|
19
|
+
description = "Cloud Storage bucket URL"
|
|
20
|
+
value = google_storage_bucket.storage.url
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
output "cdn_ip_address" {
|
|
24
|
+
description = "CDN IP address"
|
|
25
|
+
value = google_compute_global_address.storage_cdn.address
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
output "cloud_tasks_queue_name" {
|
|
29
|
+
description = "Cloud Tasks queue name"
|
|
30
|
+
value = google_cloud_tasks_queue.jobs.name
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
output "pubsub_topic_name" {
|
|
34
|
+
description = "Pub/Sub topic name"
|
|
35
|
+
value = google_pubsub_topic.events.name
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
output "pubsub_subscription_name" {
|
|
39
|
+
description = "Pub/Sub subscription name"
|
|
40
|
+
value = google_pubsub_subscription.events.name
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
output "service_account_email" {
|
|
44
|
+
description = "Service account email"
|
|
45
|
+
value = google_service_account.app.email
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
output "logs_bucket_name" {
|
|
49
|
+
description = "Logs bucket name"
|
|
50
|
+
value = google_storage_bucket.logs.name
|
|
51
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# {{titleCaseName}} - GCP Terraform Variables
|
|
2
|
+
# Copy to terraform.tfvars and fill in values
|
|
3
|
+
|
|
4
|
+
# General
|
|
5
|
+
environment = "staging"
|
|
6
|
+
gcp_project_id = "your-gcp-project-id"
|
|
7
|
+
gcp_region = "us-central1"
|
|
8
|
+
|
|
9
|
+
# Vercel
|
|
10
|
+
vercel_api_token = "your-vercel-api-token"
|
|
11
|
+
vercel_team_id = null # Optional: your-team-id
|
|
12
|
+
github_repo = "your-org/{{projectName}}"
|
|
13
|
+
domain = "{{projectName}}.com"
|
|
14
|
+
|
|
15
|
+
# Supabase
|
|
16
|
+
supabase_url = "https://xxx.supabase.co"
|
|
17
|
+
supabase_anon_key = "your-supabase-anon-key"
|
|
18
|
+
supabase_service_role_key = "your-supabase-service-role-key"
|
|
19
|
+
|
|
20
|
+
# Stripe (Optional - leave empty if not using payments)
|
|
21
|
+
stripe_secret_key = ""
|
|
22
|
+
stripe_webhook_secret = ""
|
|
23
|
+
|
|
24
|
+
# AI (Optional - leave empty if not using AI features)
|
|
25
|
+
openai_api_key = ""
|
|
26
|
+
anthropic_api_key = ""
|
|
27
|
+
|
|
28
|
+
# Monitoring
|
|
29
|
+
alert_email = "alerts@{{projectName}}.com"
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# {{titleCaseName}} - GCP Terraform Variables
|
|
2
|
+
|
|
3
|
+
# ============================================
|
|
4
|
+
# General
|
|
5
|
+
# ============================================
|
|
6
|
+
|
|
7
|
+
variable "environment" {
|
|
8
|
+
description = "Environment name (staging, production)"
|
|
9
|
+
type = string
|
|
10
|
+
default = "staging"
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
variable "gcp_project_id" {
|
|
14
|
+
description = "GCP project ID"
|
|
15
|
+
type = string
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
variable "gcp_region" {
|
|
19
|
+
description = "GCP region"
|
|
20
|
+
type = string
|
|
21
|
+
default = "us-central1"
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
# ============================================
|
|
25
|
+
# Vercel
|
|
26
|
+
# ============================================
|
|
27
|
+
|
|
28
|
+
variable "vercel_api_token" {
|
|
29
|
+
description = "Vercel API token"
|
|
30
|
+
type = string
|
|
31
|
+
sensitive = true
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
variable "vercel_team_id" {
|
|
35
|
+
description = "Vercel team ID (optional)"
|
|
36
|
+
type = string
|
|
37
|
+
default = null
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
variable "github_repo" {
|
|
41
|
+
description = "GitHub repository (org/repo format)"
|
|
42
|
+
type = string
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
variable "domain" {
|
|
46
|
+
description = "Production domain"
|
|
47
|
+
type = string
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
# ============================================
|
|
51
|
+
# Supabase
|
|
52
|
+
# ============================================
|
|
53
|
+
|
|
54
|
+
variable "supabase_url" {
|
|
55
|
+
description = "Supabase project URL"
|
|
56
|
+
type = string
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
variable "supabase_anon_key" {
|
|
60
|
+
description = "Supabase anonymous key"
|
|
61
|
+
type = string
|
|
62
|
+
sensitive = true
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
variable "supabase_service_role_key" {
|
|
66
|
+
description = "Supabase service role key"
|
|
67
|
+
type = string
|
|
68
|
+
sensitive = true
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
# ============================================
|
|
72
|
+
# Stripe (Optional)
|
|
73
|
+
# ============================================
|
|
74
|
+
|
|
75
|
+
variable "stripe_secret_key" {
|
|
76
|
+
description = "Stripe secret key"
|
|
77
|
+
type = string
|
|
78
|
+
default = ""
|
|
79
|
+
sensitive = true
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
variable "stripe_webhook_secret" {
|
|
83
|
+
description = "Stripe webhook secret"
|
|
84
|
+
type = string
|
|
85
|
+
default = ""
|
|
86
|
+
sensitive = true
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
# ============================================
|
|
90
|
+
# AI (Optional)
|
|
91
|
+
# ============================================
|
|
92
|
+
|
|
93
|
+
variable "openai_api_key" {
|
|
94
|
+
description = "OpenAI API key"
|
|
95
|
+
type = string
|
|
96
|
+
default = ""
|
|
97
|
+
sensitive = true
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
variable "anthropic_api_key" {
|
|
101
|
+
description = "Anthropic API key"
|
|
102
|
+
type = string
|
|
103
|
+
default = ""
|
|
104
|
+
sensitive = true
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
# ============================================
|
|
108
|
+
# Monitoring
|
|
109
|
+
# ============================================
|
|
110
|
+
|
|
111
|
+
variable "alert_email" {
|
|
112
|
+
description = "Email address for alerts"
|
|
113
|
+
type = string
|
|
114
|
+
default = ""
|
|
115
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { redirect } from 'next/navigation';
|
|
2
|
+
import { auth } from '@/auth';
|
|
3
|
+
import { AdminNav } from '@/components/admin-nav';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Admin layout with authentication guard.
|
|
7
|
+
*
|
|
8
|
+
* Protects all /admin/* routes. Requires the user to have the 'admin' role
|
|
9
|
+
* from Keycloak. Customize the role check and nav links below.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
export default async function AdminLayout({
|
|
13
|
+
children,
|
|
14
|
+
}: {
|
|
15
|
+
children: React.ReactNode;
|
|
16
|
+
}) {
|
|
17
|
+
const session = await auth();
|
|
18
|
+
|
|
19
|
+
if (!session?.user) {
|
|
20
|
+
redirect('/api/auth/signin?callbackUrl=/admin');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const roles = (session.user as { roles?: string[] }).roles || [];
|
|
24
|
+
if (!roles.includes('admin')) {
|
|
25
|
+
redirect('/');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<div className="mx-auto max-w-7xl px-4 py-8 sm:px-6 lg:px-8">
|
|
30
|
+
<AdminNav />
|
|
31
|
+
<main className="mt-6">{children}</main>
|
|
32
|
+
</div>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import Link from 'next/link';
|
|
4
|
+
import { usePathname } from 'next/navigation';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Admin navigation component.
|
|
8
|
+
*
|
|
9
|
+
* Configuration-driven tab navigation with active state.
|
|
10
|
+
* Add your admin sections to the ADMIN_LINKS array below.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const ADMIN_LINKS = [
|
|
14
|
+
{ href: '/admin', label: 'Dashboard' },
|
|
15
|
+
{ href: '/admin/users', label: 'Users' },
|
|
16
|
+
{ href: '/admin/settings', label: 'Settings' },
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
export function AdminNav() {
|
|
20
|
+
const pathname = usePathname();
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<nav className="border-b border-gray-200 dark:border-gray-800">
|
|
24
|
+
<div className="flex gap-1">
|
|
25
|
+
{ADMIN_LINKS.map((link) => {
|
|
26
|
+
const isActive =
|
|
27
|
+
link.href === '/admin'
|
|
28
|
+
? pathname === '/admin'
|
|
29
|
+
: pathname.startsWith(link.href);
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<Link
|
|
33
|
+
key={link.href}
|
|
34
|
+
href={link.href}
|
|
35
|
+
className={`rounded-t-lg px-4 py-2.5 text-sm font-medium transition-colors ${
|
|
36
|
+
isActive
|
|
37
|
+
? 'border-b-2 border-blue-600 text-blue-600 dark:text-blue-400'
|
|
38
|
+
: 'text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-gray-200'
|
|
39
|
+
}`}
|
|
40
|
+
>
|
|
41
|
+
{link.label}
|
|
42
|
+
</Link>
|
|
43
|
+
);
|
|
44
|
+
})}
|
|
45
|
+
</div>
|
|
46
|
+
</nav>
|
|
47
|
+
);
|
|
48
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audit logging for admin/security-sensitive actions.
|
|
3
|
+
*
|
|
4
|
+
* Uses createAuditLogger from platform-core/auth. Currently console-only
|
|
5
|
+
* (structured logs to stdout). Persistence (Redis/DB) can be added later
|
|
6
|
+
* by providing a `persist` callback.
|
|
7
|
+
*/
|
|
8
|
+
import 'server-only';
|
|
9
|
+
import { createAuditLogger, StandardAuditActions } from '@digilogiclabs/platform-core/auth';
|
|
10
|
+
|
|
11
|
+
/** App-specific audit actions extending the standard set. */
|
|
12
|
+
export const AppAuditActions = {
|
|
13
|
+
...StandardAuditActions,
|
|
14
|
+
|
|
15
|
+
// Add your app-specific actions here:
|
|
16
|
+
// USER_ROLE_CHANGED: 'app.user.role_changed',
|
|
17
|
+
// SUBSCRIPTION_CREATED: 'app.subscription.created',
|
|
18
|
+
} as const;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Audit logger instance.
|
|
22
|
+
* Console-only persistence — logs structured events to stdout.
|
|
23
|
+
*/
|
|
24
|
+
export const audit = createAuditLogger();
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Federated Logout Route
|
|
3
|
+
*
|
|
4
|
+
* Handles proper logout from both Auth.js and Keycloak.
|
|
5
|
+
* Ensures the Keycloak session is cleared so users aren't auto-logged-in
|
|
6
|
+
* when they try to sign in again.
|
|
7
|
+
*
|
|
8
|
+
* Flow:
|
|
9
|
+
* 1. Get the id_token from the Auth.js session
|
|
10
|
+
* 2. Return an HTML page with Set-Cookie headers to clear all auth cookies
|
|
11
|
+
* 3. The HTML page auto-redirects to Keycloak's logout endpoint
|
|
12
|
+
* 4. Keycloak clears its session and redirects back to the app
|
|
13
|
+
*
|
|
14
|
+
* Returns HTML (200) instead of 307 redirect because browsers may not
|
|
15
|
+
* reliably process Set-Cookie headers on redirect responses.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
19
|
+
import { auth } from '@/auth';
|
|
20
|
+
import { getToken } from 'next-auth/jwt';
|
|
21
|
+
|
|
22
|
+
/** Serialize a Set-Cookie header string for cookie deletion. */
|
|
23
|
+
function expireCookie(
|
|
24
|
+
name: string,
|
|
25
|
+
options?: { domain?: string; secure?: boolean; hostPrefix?: boolean }
|
|
26
|
+
): string {
|
|
27
|
+
const parts = [
|
|
28
|
+
`${name}=`,
|
|
29
|
+
'Path=/',
|
|
30
|
+
'Expires=Thu, 01 Jan 1970 00:00:00 GMT',
|
|
31
|
+
'Max-Age=0',
|
|
32
|
+
'SameSite=Lax',
|
|
33
|
+
];
|
|
34
|
+
if (options?.hostPrefix) {
|
|
35
|
+
parts.push('Secure');
|
|
36
|
+
} else {
|
|
37
|
+
parts.push('HttpOnly');
|
|
38
|
+
if (options?.domain) parts.push(`Domain=${options.domain}`);
|
|
39
|
+
if (options?.secure) parts.push('Secure');
|
|
40
|
+
}
|
|
41
|
+
return parts.join('; ');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Validate callback URL to prevent open redirect attacks. */
|
|
45
|
+
function isAllowedCallbackUrl(url: string, baseUrl: string): boolean {
|
|
46
|
+
if (url.startsWith('/') && !url.startsWith('//')) return true;
|
|
47
|
+
try {
|
|
48
|
+
const parsed = new URL(url);
|
|
49
|
+
const base = new URL(baseUrl);
|
|
50
|
+
const allowedHosts = [base.hostname, `www.${base.hostname}`];
|
|
51
|
+
if (base.hostname.startsWith('www.')) {
|
|
52
|
+
allowedHosts.push(base.hostname.slice(4));
|
|
53
|
+
}
|
|
54
|
+
return allowedHosts.includes(parsed.hostname);
|
|
55
|
+
} catch {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export async function GET(request: NextRequest) {
|
|
61
|
+
const session = await auth();
|
|
62
|
+
const searchParams = request.nextUrl.searchParams;
|
|
63
|
+
const rawCallbackUrl = searchParams.get('callbackUrl') || '/';
|
|
64
|
+
const queryIdToken = searchParams.get('id_token_hint');
|
|
65
|
+
|
|
66
|
+
const baseUrl = process.env.NEXTAUTH_URL || process.env.AUTH_URL || 'http://localhost:3000';
|
|
67
|
+
const callbackUrl = isAllowedCallbackUrl(rawCallbackUrl, baseUrl) ? rawCallbackUrl : '/';
|
|
68
|
+
const postLogoutRedirectUri = callbackUrl.startsWith('http')
|
|
69
|
+
? callbackUrl
|
|
70
|
+
: `${baseUrl}${callbackUrl}`;
|
|
71
|
+
|
|
72
|
+
const keycloakIssuer = process.env.AUTH_KEYCLOAK_ISSUER;
|
|
73
|
+
if (!keycloakIssuer) {
|
|
74
|
+
console.error('[Federated Logout] Missing AUTH_KEYCLOAK_ISSUER');
|
|
75
|
+
return NextResponse.redirect(
|
|
76
|
+
new URL('/api/auth/signout?callbackUrl=' + encodeURIComponent(callbackUrl), request.url)
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Revoke refresh token (best-effort)
|
|
81
|
+
const jwtToken = await getToken({ req: request });
|
|
82
|
+
const refreshToken = jwtToken?.refreshToken as string | undefined;
|
|
83
|
+
if (refreshToken) {
|
|
84
|
+
try {
|
|
85
|
+
await fetch(`${keycloakIssuer}/protocol/openid-connect/revoke`, {
|
|
86
|
+
method: 'POST',
|
|
87
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
88
|
+
body: new URLSearchParams({
|
|
89
|
+
token: refreshToken,
|
|
90
|
+
token_type_hint: 'refresh_token',
|
|
91
|
+
...(process.env.AUTH_KEYCLOAK_ID && { client_id: process.env.AUTH_KEYCLOAK_ID }),
|
|
92
|
+
...(process.env.AUTH_KEYCLOAK_SECRET && {
|
|
93
|
+
client_secret: process.env.AUTH_KEYCLOAK_SECRET,
|
|
94
|
+
}),
|
|
95
|
+
}),
|
|
96
|
+
});
|
|
97
|
+
} catch {
|
|
98
|
+
// Best-effort — don't block logout
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Build Keycloak logout URL
|
|
103
|
+
const logoutUrl = new URL(`${keycloakIssuer}/protocol/openid-connect/logout`);
|
|
104
|
+
logoutUrl.searchParams.set('post_logout_redirect_uri', postLogoutRedirectUri);
|
|
105
|
+
if (process.env.AUTH_KEYCLOAK_ID) {
|
|
106
|
+
logoutUrl.searchParams.set('client_id', process.env.AUTH_KEYCLOAK_ID);
|
|
107
|
+
}
|
|
108
|
+
const idToken = session?.idToken || queryIdToken;
|
|
109
|
+
if (idToken) {
|
|
110
|
+
logoutUrl.searchParams.set('id_token_hint', idToken);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const escapedUrl = logoutUrl
|
|
114
|
+
.toString()
|
|
115
|
+
.replace(/&/g, '&')
|
|
116
|
+
.replace(/"/g, '"')
|
|
117
|
+
.replace(/</g, '<')
|
|
118
|
+
.replace(/>/g, '>');
|
|
119
|
+
|
|
120
|
+
const html = `<!DOCTYPE html>
|
|
121
|
+
<html><head>
|
|
122
|
+
<meta charset="utf-8">
|
|
123
|
+
<meta http-equiv="refresh" content="0;url=${escapedUrl}">
|
|
124
|
+
<title>Signing out...</title>
|
|
125
|
+
<style>body{display:flex;align-items:center;justify-content:center;min-height:100vh;margin:0;font-family:system-ui,sans-serif;background:#0a0a0a;color:#fff}p{font-size:1.1rem;opacity:0.7}</style>
|
|
126
|
+
</head><body>
|
|
127
|
+
<p>Signing out…</p>
|
|
128
|
+
<script>window.location.replace(${JSON.stringify(logoutUrl.toString()).replace(/</g, '\\u003c')});</script>
|
|
129
|
+
</body></html>`;
|
|
130
|
+
|
|
131
|
+
const response = new NextResponse(html, {
|
|
132
|
+
status: 200,
|
|
133
|
+
headers: {
|
|
134
|
+
'Content-Type': 'text/html; charset=utf-8',
|
|
135
|
+
'Cache-Control': 'no-store, no-cache, must-revalidate',
|
|
136
|
+
Pragma: 'no-cache',
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// Clear ALL Auth.js cookie variants
|
|
141
|
+
const isProduction = process.env.NODE_ENV === 'production';
|
|
142
|
+
const cookieNames = [
|
|
143
|
+
'authjs.session-token',
|
|
144
|
+
'__Secure-authjs.session-token',
|
|
145
|
+
'authjs.callback-url',
|
|
146
|
+
'__Secure-authjs.callback-url',
|
|
147
|
+
'authjs.csrf-token',
|
|
148
|
+
'__Secure-authjs.csrf-token',
|
|
149
|
+
'authjs.pkce.code_verifier',
|
|
150
|
+
'__Secure-authjs.pkce.code_verifier',
|
|
151
|
+
'authjs.state',
|
|
152
|
+
'__Secure-authjs.state',
|
|
153
|
+
// Legacy next-auth names
|
|
154
|
+
'next-auth.session-token',
|
|
155
|
+
'__Secure-next-auth.session-token',
|
|
156
|
+
'next-auth.callback-url',
|
|
157
|
+
'__Secure-next-auth.callback-url',
|
|
158
|
+
'next-auth.csrf-token',
|
|
159
|
+
'__Secure-next-auth.csrf-token',
|
|
160
|
+
];
|
|
161
|
+
|
|
162
|
+
for (const name of cookieNames) {
|
|
163
|
+
const needsSecure = isProduction || name.startsWith('__Secure-');
|
|
164
|
+
response.headers.append('Set-Cookie', expireCookie(name, { secure: needsSecure }));
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// __Host- prefix cookies
|
|
168
|
+
for (const name of ['__Host-authjs.csrf-token', '__Host-next-auth.csrf-token']) {
|
|
169
|
+
response.headers.append('Set-Cookie', expireCookie(name, { hostPrefix: true }));
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return response;
|
|
173
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth.js Base Configuration (Edge-compatible)
|
|
3
|
+
*
|
|
4
|
+
* This file contains ONLY Edge-runtime-compatible configuration.
|
|
5
|
+
* It is imported by middleware.ts for Edge middleware auth.
|
|
6
|
+
*
|
|
7
|
+
* Server-only code (database sync, events) lives in auth.ts which
|
|
8
|
+
* extends this config. API routes and server components use auth.ts.
|
|
9
|
+
*
|
|
10
|
+
* IMPORTANT: Do NOT add any imports of server-only modules here
|
|
11
|
+
* (ioredis, pg, nodemailer, platform-core barrel, etc.)
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import Keycloak from 'next-auth/providers/keycloak';
|
|
15
|
+
import type { NextAuthConfig } from 'next-auth';
|
|
16
|
+
import {
|
|
17
|
+
buildKeycloakCallbacks,
|
|
18
|
+
buildAuthCookies,
|
|
19
|
+
buildRedirectCallback,
|
|
20
|
+
} from '@digilogiclabs/platform-core/auth';
|
|
21
|
+
|
|
22
|
+
// Extend the built-in session types
|
|
23
|
+
declare module 'next-auth' {
|
|
24
|
+
interface Session {
|
|
25
|
+
user: {
|
|
26
|
+
id: string;
|
|
27
|
+
email?: string | null;
|
|
28
|
+
name?: string | null;
|
|
29
|
+
image?: string | null;
|
|
30
|
+
roles?: string[]; // Keycloak realm roles
|
|
31
|
+
};
|
|
32
|
+
idToken?: string; // For federated logout
|
|
33
|
+
accessToken?: string; // For API calls
|
|
34
|
+
// refreshToken intentionally NOT exposed to client — used server-side only via getToken()
|
|
35
|
+
error?: string; // Token refresh error — client should re-authenticate
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Keycloak callbacks — JWT token storage, role parsing, automatic refresh, session mapping */
|
|
40
|
+
const keycloakCallbacks = buildKeycloakCallbacks({
|
|
41
|
+
issuer: process.env.AUTH_KEYCLOAK_ISSUER!,
|
|
42
|
+
clientId: process.env.AUTH_KEYCLOAK_ID!,
|
|
43
|
+
clientSecret: process.env.AUTH_KEYCLOAK_SECRET!,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
export const authConfig: NextAuthConfig = {
|
|
47
|
+
// Trust the host in production (required for Auth.js v5 behind reverse proxy)
|
|
48
|
+
trustHost: true,
|
|
49
|
+
|
|
50
|
+
// Cookie configuration for cross-domain OIDC (www/non-www compatibility).
|
|
51
|
+
// csrfToken uses __Host- prefix which CANNOT have a Domain attribute.
|
|
52
|
+
// The federated-logout route handles clearing all cookie variants.
|
|
53
|
+
cookies: buildAuthCookies(),
|
|
54
|
+
|
|
55
|
+
providers: [
|
|
56
|
+
Keycloak({
|
|
57
|
+
clientId: process.env.AUTH_KEYCLOAK_ID!,
|
|
58
|
+
clientSecret: process.env.AUTH_KEYCLOAK_SECRET!,
|
|
59
|
+
issuer: process.env.AUTH_KEYCLOAK_ISSUER!,
|
|
60
|
+
}),
|
|
61
|
+
],
|
|
62
|
+
|
|
63
|
+
session: {
|
|
64
|
+
strategy: 'jwt',
|
|
65
|
+
maxAge: 30 * 24 * 60 * 60, // 30 days
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
callbacks: {
|
|
69
|
+
...keycloakCallbacks,
|
|
70
|
+
|
|
71
|
+
async signIn() {
|
|
72
|
+
return true;
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
redirect: buildRedirectCallback(),
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
pages: {
|
|
79
|
+
signIn: '/auth/signin',
|
|
80
|
+
error: '/auth/signin',
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
debug: process.env.NODE_ENV === 'development',
|
|
84
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth.js Server Configuration
|
|
3
|
+
*
|
|
4
|
+
* Extends the Edge-compatible auth.config.ts with server-only features
|
|
5
|
+
* (database sync, events, etc.). This file is used by API routes and
|
|
6
|
+
* server components.
|
|
7
|
+
*
|
|
8
|
+
* Middleware uses auth.config.ts directly (Edge-compatible).
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import NextAuth from 'next-auth';
|
|
12
|
+
import { authConfig } from './auth.config';
|
|
13
|
+
|
|
14
|
+
export const { handlers, auth, signIn, signOut } = NextAuth({
|
|
15
|
+
...authConfig,
|
|
16
|
+
|
|
17
|
+
// Server-only events — add database sync, audit logging, etc.
|
|
18
|
+
events: {
|
|
19
|
+
async signIn({ user }) {
|
|
20
|
+
// Optional: sync user to your database on sign-in
|
|
21
|
+
// const db = await getDatabase();
|
|
22
|
+
// await db.upsert('users', { id: user.id, email: user.email, name: user.name });
|
|
23
|
+
console.log(`[Auth] User signed in: ${user.email}`);
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
|
|
3
|
+
export const dynamic = 'force-dynamic';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* GET /api/beta-settings
|
|
7
|
+
*
|
|
8
|
+
* Returns beta mode configuration. Controlled via environment variables:
|
|
9
|
+
* BETA_MODE - 'true'/'false' (default: true)
|
|
10
|
+
* REQUIRE_INVITE_CODE - 'true'/'false' (default: true)
|
|
11
|
+
* BETA_MESSAGE - Custom message shown to users
|
|
12
|
+
*/
|
|
13
|
+
export async function GET() {
|
|
14
|
+
const betaMode = process.env.BETA_MODE !== 'false';
|
|
15
|
+
const requireInviteCode = process.env.REQUIRE_INVITE_CODE !== 'false';
|
|
16
|
+
const betaMessage =
|
|
17
|
+
process.env.BETA_MESSAGE ||
|
|
18
|
+
'We are currently in private beta. Enter your invite code to continue.';
|
|
19
|
+
|
|
20
|
+
return NextResponse.json({
|
|
21
|
+
betaMode,
|
|
22
|
+
requireInviteCode,
|
|
23
|
+
betaMessage,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
import { enforceRateLimit, CommonRateLimits } from '@digilogiclabs/platform-core/auth';
|
|
3
|
+
|
|
4
|
+
export const dynamic = 'force-dynamic';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* POST /api/validate-beta-code
|
|
8
|
+
*
|
|
9
|
+
* Validates a beta invite code against environment-defined codes.
|
|
10
|
+
* Rate limited to 5/min with 5-minute block to prevent brute force.
|
|
11
|
+
*
|
|
12
|
+
* Env vars:
|
|
13
|
+
* BETA_CODES - Comma-separated list of valid codes (e.g. "CODE1,CODE2")
|
|
14
|
+
*/
|
|
15
|
+
export async function POST(request: NextRequest) {
|
|
16
|
+
// Rate limit: 5 attempts per minute, 5-minute block on exceed
|
|
17
|
+
const rateLimitResult = await enforceRateLimit(
|
|
18
|
+
request,
|
|
19
|
+
'validate-beta-code',
|
|
20
|
+
CommonRateLimits.betaValidation
|
|
21
|
+
);
|
|
22
|
+
if (rateLimitResult) return rateLimitResult;
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
const body = await request.json();
|
|
26
|
+
const { code } = body;
|
|
27
|
+
|
|
28
|
+
if (!code || typeof code !== 'string') {
|
|
29
|
+
return NextResponse.json({ valid: false, message: 'Invalid code format' });
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const normalizedCode = code.trim().toUpperCase();
|
|
33
|
+
|
|
34
|
+
if (normalizedCode.length < 3) {
|
|
35
|
+
return NextResponse.json({
|
|
36
|
+
valid: false,
|
|
37
|
+
message: 'Code must be at least 3 characters',
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Get valid codes from environment
|
|
42
|
+
const validCodesEnv = process.env.BETA_CODES || '';
|
|
43
|
+
const validCodes = validCodesEnv
|
|
44
|
+
.split(',')
|
|
45
|
+
.map((c) => c.trim().toUpperCase())
|
|
46
|
+
.filter(Boolean);
|
|
47
|
+
|
|
48
|
+
const allValidCodes = new Set(validCodes);
|
|
49
|
+
|
|
50
|
+
if (allValidCodes.has(normalizedCode)) {
|
|
51
|
+
return NextResponse.json({
|
|
52
|
+
valid: true,
|
|
53
|
+
message: 'Welcome to the beta! You can now continue.',
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return NextResponse.json({
|
|
58
|
+
valid: false,
|
|
59
|
+
message: 'Invalid invite code. Please check your code and try again.',
|
|
60
|
+
});
|
|
61
|
+
} catch {
|
|
62
|
+
return NextResponse.json(
|
|
63
|
+
{ valid: false, message: 'Unable to validate code. Please try again.' },
|
|
64
|
+
{ status: 500 }
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
}
|