create-skit 0.1.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/README.md +36 -0
- package/bin/create-skit.mjs +1064 -0
- package/lib/module-application.mjs +281 -0
- package/lib/module-resolver.mjs +179 -0
- package/modules/README.md +22 -0
- package/modules/ai-dx/files/AGENTS.md +116 -0
- package/modules/ai-dx/files/ARCHITECTURE.md +103 -0
- package/modules/ai-dx/module.json +14 -0
- package/modules/ai-dx-claude/files/CLAUDE.md +8 -0
- package/modules/ai-dx-claude/module.json +13 -0
- package/modules/ai-dx-cursor/files/.cursor/rules/auth.mdc +53 -0
- package/modules/ai-dx-cursor/files/.cursor/rules/database.mdc +48 -0
- package/modules/ai-dx-cursor/files/.cursor/rules/env.mdc +43 -0
- package/modules/ai-dx-cursor/files/.cursor/rules/nextjs.mdc +58 -0
- package/modules/ai-dx-cursor/files/.cursor/rules/project.mdc +33 -0
- package/modules/ai-dx-cursor/files/.cursor/rules/testing.mdc +55 -0
- package/modules/ai-dx-cursor/module.json +18 -0
- package/modules/ai-dx-gemini/files/.gemini/GEMINI.md +5 -0
- package/modules/ai-dx-gemini/module.json +13 -0
- package/modules/auth-core/module.json +8 -0
- package/modules/auth-github/module.json +20 -0
- package/modules/billing-polar/module.json +20 -0
- package/modules/billing-stripe/module.json +23 -0
- package/modules/dashboard-shell/files/src/app/globals.css +756 -0
- package/modules/dashboard-shell/files/src/app/settings/page.tsx +67 -0
- package/modules/dashboard-shell/module.json +11 -0
- package/modules/db-pg/module.json +21 -0
- package/modules/db-postgresjs/module.json +21 -0
- package/modules/deploy-docker/files/.dockerignore +19 -0
- package/modules/deploy-docker/files/Dockerfile +25 -0
- package/modules/deploy-docker/module.json +11 -0
- package/modules/email-resend/module.json +21 -0
- package/modules/quality-baseline/module.json +8 -0
- package/modules/testing-baseline/module.json +8 -0
- package/package.json +40 -0
- package/presets/README.md +12 -0
- package/presets/blank.json +67 -0
- package/presets/dashboard.json +67 -0
- package/templates/base-web/.env.example +17 -0
- package/templates/base-web/.github/workflows/ci.yml +34 -0
- package/templates/base-web/.husky/pre-commit +3 -0
- package/templates/base-web/.husky/pre-push +3 -0
- package/templates/base-web/.prettierignore +3 -0
- package/templates/base-web/README.md +42 -0
- package/templates/base-web/drizzle.config.ts +16 -0
- package/templates/base-web/eslint.config.mjs +127 -0
- package/templates/base-web/manifest.json +5 -0
- package/templates/base-web/next-env.d.ts +4 -0
- package/templates/base-web/next.config.ts +5 -0
- package/templates/base-web/package.json +75 -0
- package/templates/base-web/playwright.config.ts +21 -0
- package/templates/base-web/prettier.config.mjs +9 -0
- package/templates/base-web/proxy.ts +23 -0
- package/templates/base-web/src/app/api/auth/[...all]/route.ts +5 -0
- package/templates/base-web/src/app/api/billing/checkout/route.ts +26 -0
- package/templates/base-web/src/app/api/billing/portal/route.ts +25 -0
- package/templates/base-web/src/app/api/email/test/route.ts +28 -0
- package/templates/base-web/src/app/api/webhooks/polar/route.ts +5 -0
- package/templates/base-web/src/app/api/webhooks/stripe/route.ts +5 -0
- package/templates/base-web/src/app/billing/page.tsx +55 -0
- package/templates/base-web/src/app/dashboard/page.tsx +15 -0
- package/templates/base-web/src/app/email/page.tsx +46 -0
- package/templates/base-web/src/app/error.tsx +27 -0
- package/templates/base-web/src/app/globals.css +534 -0
- package/templates/base-web/src/app/layout.tsx +19 -0
- package/templates/base-web/src/app/llms-full.txt/route.ts +158 -0
- package/templates/base-web/src/app/llms.txt/route.ts +59 -0
- package/templates/base-web/src/app/loading.tsx +24 -0
- package/templates/base-web/src/app/not-found.tsx +16 -0
- package/templates/base-web/src/app/page.tsx +5 -0
- package/templates/base-web/src/app/sign-in/page.tsx +14 -0
- package/templates/base-web/src/app/sign-up/page.tsx +14 -0
- package/templates/base-web/src/components/auth/email-auth-form.test.tsx +40 -0
- package/templates/base-web/src/components/auth/email-auth-form.tsx +128 -0
- package/templates/base-web/src/components/auth/sign-out-button.tsx +29 -0
- package/templates/base-web/src/db/index.ts +16 -0
- package/templates/base-web/src/db/schema/auth.ts +4 -0
- package/templates/base-web/src/db/schema/index.ts +2 -0
- package/templates/base-web/src/db/schema/projects.ts +17 -0
- package/templates/base-web/src/db/seeds/index.ts +32 -0
- package/templates/base-web/src/lib/auth-client.ts +5 -0
- package/templates/base-web/src/lib/auth-session.ts +21 -0
- package/templates/base-web/src/lib/auth.ts +23 -0
- package/templates/base-web/src/lib/billing/index.ts +37 -0
- package/templates/base-web/src/lib/billing/providers/polar.ts +80 -0
- package/templates/base-web/src/lib/billing/providers/stripe.ts +77 -0
- package/templates/base-web/src/lib/billing/types.ts +25 -0
- package/templates/base-web/src/lib/email/index.ts +19 -0
- package/templates/base-web/src/lib/email/templates.test.ts +12 -0
- package/templates/base-web/src/lib/email/templates.ts +40 -0
- package/templates/base-web/src/lib/env.ts +83 -0
- package/templates/base-web/tests/e2e/home.spec.ts +8 -0
- package/templates/base-web/tsconfig.json +34 -0
- package/templates/base-web/vitest.config.ts +19 -0
- package/templates/blank/.env.example +16 -0
- package/templates/blank/.github/workflows/ci.yml +34 -0
- package/templates/blank/.husky/pre-commit +3 -0
- package/templates/blank/.husky/pre-push +3 -0
- package/templates/blank/.prettierignore +3 -0
- package/templates/blank/drizzle.config.ts +16 -0
- package/templates/blank/eslint.config.mjs +127 -0
- package/templates/blank/next-env.d.ts +4 -0
- package/templates/blank/next.config.ts +5 -0
- package/templates/blank/package.json +75 -0
- package/templates/blank/playwright.config.ts +21 -0
- package/templates/blank/prettier.config.mjs +9 -0
- package/templates/blank/proxy.ts +28 -0
- package/templates/blank/src/app/api/auth/[...all]/route.ts +5 -0
- package/templates/blank/src/app/api/billing/checkout/route.ts +26 -0
- package/templates/blank/src/app/api/billing/portal/route.ts +25 -0
- package/templates/blank/src/app/api/email/test/route.ts +28 -0
- package/templates/blank/src/app/api/webhooks/polar/route.ts +5 -0
- package/templates/blank/src/app/api/webhooks/stripe/route.ts +5 -0
- package/templates/blank/src/app/billing/page.tsx +70 -0
- package/templates/blank/src/app/email/page.tsx +46 -0
- package/templates/blank/src/app/globals.css +394 -0
- package/templates/blank/src/app/layout.tsx +19 -0
- package/templates/blank/src/app/page.tsx +23 -0
- package/templates/blank/src/app/sign-in/page.tsx +18 -0
- package/templates/blank/src/app/sign-up/page.tsx +18 -0
- package/templates/blank/src/components/auth/email-auth-form.test.tsx +39 -0
- package/templates/blank/src/components/auth/email-auth-form.tsx +109 -0
- package/templates/blank/src/components/auth/sign-out-button.tsx +29 -0
- package/templates/blank/src/db/index.ts +16 -0
- package/templates/blank/src/db/schema/auth.ts +4 -0
- package/templates/blank/src/db/schema/index.ts +2 -0
- package/templates/blank/src/db/schema/projects.ts +17 -0
- package/templates/blank/src/db/seeds/index.ts +28 -0
- package/templates/blank/src/lib/auth-client.ts +5 -0
- package/templates/blank/src/lib/auth-session.ts +11 -0
- package/templates/blank/src/lib/auth.ts +23 -0
- package/templates/blank/src/lib/billing/index.ts +37 -0
- package/templates/blank/src/lib/billing/providers/polar.ts +80 -0
- package/templates/blank/src/lib/billing/providers/stripe.ts +77 -0
- package/templates/blank/src/lib/billing/types.ts +25 -0
- package/templates/blank/src/lib/email/index.ts +19 -0
- package/templates/blank/src/lib/email/templates.test.ts +15 -0
- package/templates/blank/src/lib/email/templates.ts +40 -0
- package/templates/blank/src/lib/env.ts +80 -0
- package/templates/blank/tsconfig.json +34 -0
- package/templates/blank/vitest.config.ts +19 -0
- package/templates/dashboard/.env.example +16 -0
- package/templates/dashboard/.github/workflows/ci.yml +34 -0
- package/templates/dashboard/.husky/pre-commit +3 -0
- package/templates/dashboard/.husky/pre-push +3 -0
- package/templates/dashboard/.prettierignore +3 -0
- package/templates/dashboard/drizzle.config.ts +16 -0
- package/templates/dashboard/eslint.config.mjs +127 -0
- package/templates/dashboard/next-env.d.ts +4 -0
- package/templates/dashboard/next.config.ts +5 -0
- package/templates/dashboard/package.json +75 -0
- package/templates/dashboard/playwright.config.ts +21 -0
- package/templates/dashboard/prettier.config.mjs +9 -0
- package/templates/dashboard/proxy.ts +36 -0
- package/templates/dashboard/src/app/api/auth/[...all]/route.ts +5 -0
- package/templates/dashboard/src/app/api/billing/checkout/route.ts +26 -0
- package/templates/dashboard/src/app/api/billing/portal/route.ts +25 -0
- package/templates/dashboard/src/app/api/email/test/route.ts +28 -0
- package/templates/dashboard/src/app/api/webhooks/polar/route.ts +5 -0
- package/templates/dashboard/src/app/api/webhooks/stripe/route.ts +5 -0
- package/templates/dashboard/src/app/billing/layout.tsx +22 -0
- package/templates/dashboard/src/app/billing/page.tsx +73 -0
- package/templates/dashboard/src/app/dashboard/layout.tsx +22 -0
- package/templates/dashboard/src/app/dashboard/page.tsx +104 -0
- package/templates/dashboard/src/app/email/layout.tsx +22 -0
- package/templates/dashboard/src/app/email/page.tsx +54 -0
- package/templates/dashboard/src/app/globals.css +1357 -0
- package/templates/dashboard/src/app/layout.tsx +25 -0
- package/templates/dashboard/src/app/page.tsx +154 -0
- package/templates/dashboard/src/app/settings/layout.tsx +22 -0
- package/templates/dashboard/src/app/settings/page.tsx +85 -0
- package/templates/dashboard/src/app/sign-in/page.tsx +47 -0
- package/templates/dashboard/src/app/sign-up/page.tsx +47 -0
- package/templates/dashboard/src/components/auth/email-auth-form.test.tsx +39 -0
- package/templates/dashboard/src/components/auth/email-auth-form.tsx +160 -0
- package/templates/dashboard/src/components/auth/sign-out-button.tsx +29 -0
- package/templates/dashboard/src/components/dashboard/shell.tsx +158 -0
- package/templates/dashboard/src/db/index.ts +16 -0
- package/templates/dashboard/src/db/schema/auth.ts +4 -0
- package/templates/dashboard/src/db/schema/index.ts +2 -0
- package/templates/dashboard/src/db/schema/projects.ts +17 -0
- package/templates/dashboard/src/db/seeds/index.ts +28 -0
- package/templates/dashboard/src/lib/auth-client.ts +5 -0
- package/templates/dashboard/src/lib/auth-session.ts +11 -0
- package/templates/dashboard/src/lib/auth.ts +41 -0
- package/templates/dashboard/src/lib/billing/index.ts +37 -0
- package/templates/dashboard/src/lib/billing/providers/polar.ts +80 -0
- package/templates/dashboard/src/lib/billing/providers/stripe.ts +77 -0
- package/templates/dashboard/src/lib/billing/types.ts +25 -0
- package/templates/dashboard/src/lib/email/index.ts +19 -0
- package/templates/dashboard/src/lib/email/templates.test.ts +15 -0
- package/templates/dashboard/src/lib/email/templates.ts +40 -0
- package/templates/dashboard/src/lib/env.ts +88 -0
- package/templates/dashboard/tsconfig.json +34 -0
- package/templates/dashboard/vitest.config.ts +19 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
|
|
4
|
+
import { defineConfig, globalIgnores } from "eslint/config";
|
|
5
|
+
import prettier from "eslint-config-prettier/flat";
|
|
6
|
+
import nextTs from "eslint-config-next/typescript";
|
|
7
|
+
import nextVitals from "eslint-config-next/core-web-vitals";
|
|
8
|
+
import importPlugin from "eslint-plugin-import";
|
|
9
|
+
import unusedImports from "eslint-plugin-unused-imports";
|
|
10
|
+
import globals from "globals";
|
|
11
|
+
|
|
12
|
+
const SOURCE_FILES = ["**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"];
|
|
13
|
+
const dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
14
|
+
|
|
15
|
+
export default defineConfig([
|
|
16
|
+
...nextVitals,
|
|
17
|
+
...nextTs,
|
|
18
|
+
{
|
|
19
|
+
files: SOURCE_FILES,
|
|
20
|
+
languageOptions: {
|
|
21
|
+
parserOptions: {
|
|
22
|
+
projectService: true,
|
|
23
|
+
tsconfigRootDir: dirname
|
|
24
|
+
},
|
|
25
|
+
globals: {
|
|
26
|
+
...globals.browser,
|
|
27
|
+
...globals.nodeBuiltin
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
plugins: {
|
|
31
|
+
import: importPlugin,
|
|
32
|
+
"unused-imports": unusedImports
|
|
33
|
+
},
|
|
34
|
+
settings: {
|
|
35
|
+
"import/resolver": {
|
|
36
|
+
typescript: true
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
rules: {
|
|
40
|
+
"@typescript-eslint/consistent-type-imports": [
|
|
41
|
+
"error",
|
|
42
|
+
{
|
|
43
|
+
prefer: "type-imports",
|
|
44
|
+
fixStyle: "inline-type-imports"
|
|
45
|
+
}
|
|
46
|
+
],
|
|
47
|
+
"@typescript-eslint/no-floating-promises": "error",
|
|
48
|
+
"@typescript-eslint/no-misused-promises": [
|
|
49
|
+
"error",
|
|
50
|
+
{
|
|
51
|
+
checksVoidReturn: {
|
|
52
|
+
attributes: false
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
],
|
|
56
|
+
"@typescript-eslint/no-unused-vars": "off",
|
|
57
|
+
"import/first": "error",
|
|
58
|
+
"import/newline-after-import": "error",
|
|
59
|
+
"import/no-duplicates": "error",
|
|
60
|
+
"import/order": [
|
|
61
|
+
"error",
|
|
62
|
+
{
|
|
63
|
+
groups: [
|
|
64
|
+
"builtin",
|
|
65
|
+
"external",
|
|
66
|
+
"internal",
|
|
67
|
+
["parent", "sibling", "index"],
|
|
68
|
+
"object",
|
|
69
|
+
"type"
|
|
70
|
+
],
|
|
71
|
+
alphabetize: {
|
|
72
|
+
order: "asc",
|
|
73
|
+
caseInsensitive: true
|
|
74
|
+
},
|
|
75
|
+
"newlines-between": "always",
|
|
76
|
+
pathGroups: [
|
|
77
|
+
{
|
|
78
|
+
pattern: "@/**",
|
|
79
|
+
group: "internal",
|
|
80
|
+
position: "before"
|
|
81
|
+
}
|
|
82
|
+
],
|
|
83
|
+
pathGroupsExcludedImportTypes: ["builtin"]
|
|
84
|
+
}
|
|
85
|
+
],
|
|
86
|
+
"unused-imports/no-unused-imports": "error",
|
|
87
|
+
"unused-imports/no-unused-vars": [
|
|
88
|
+
"warn",
|
|
89
|
+
{
|
|
90
|
+
vars: "all",
|
|
91
|
+
varsIgnorePattern: "^_",
|
|
92
|
+
args: "after-used",
|
|
93
|
+
argsIgnorePattern: "^_"
|
|
94
|
+
}
|
|
95
|
+
]
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
files: SOURCE_FILES,
|
|
100
|
+
ignores: ["drizzle.config.ts", "src/lib/env.ts"],
|
|
101
|
+
rules: {
|
|
102
|
+
"no-restricted-properties": [
|
|
103
|
+
"error",
|
|
104
|
+
{
|
|
105
|
+
object: "process",
|
|
106
|
+
property: "env",
|
|
107
|
+
message: "Use the validated env object from src/lib/env.ts."
|
|
108
|
+
}
|
|
109
|
+
]
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
prettier,
|
|
113
|
+
globalIgnores([
|
|
114
|
+
".next/**",
|
|
115
|
+
"out/**",
|
|
116
|
+
"build/**",
|
|
117
|
+
"coverage/**",
|
|
118
|
+
"drizzle.config.ts",
|
|
119
|
+
"eslint.config.mjs",
|
|
120
|
+
"next.config.ts",
|
|
121
|
+
"playwright.config.ts",
|
|
122
|
+
"prettier.config.mjs",
|
|
123
|
+
"proxy.ts",
|
|
124
|
+
"next-env.d.ts",
|
|
125
|
+
"vitest.config.ts"
|
|
126
|
+
])
|
|
127
|
+
]);
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "__PROJECT_NAME__",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"packageManager": "__PACKAGE_MANAGER__",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"dev": "next dev",
|
|
9
|
+
"build": "next build",
|
|
10
|
+
"start": "next start",
|
|
11
|
+
"lint": "eslint . --max-warnings=0",
|
|
12
|
+
"lint:fix": "eslint . --fix",
|
|
13
|
+
"typecheck": "tsc --noEmit",
|
|
14
|
+
"format": "prettier . --write",
|
|
15
|
+
"format:check": "prettier . --check",
|
|
16
|
+
"check": "__CHECK_COMMAND__",
|
|
17
|
+
"prepare": "husky",
|
|
18
|
+
"lint-staged": "lint-staged",
|
|
19
|
+
"test": "vitest run",
|
|
20
|
+
"test:watch": "vitest",
|
|
21
|
+
"test:e2e": "playwright test",
|
|
22
|
+
"test:e2e:headed": "playwright test --headed",
|
|
23
|
+
"db:generate": "drizzle-kit generate",
|
|
24
|
+
"db:migrate": "drizzle-kit migrate",
|
|
25
|
+
"db:push": "drizzle-kit push",
|
|
26
|
+
"db:studio": "drizzle-kit studio",
|
|
27
|
+
"db:seed": "tsx src/db/seeds/index.ts",
|
|
28
|
+
"auth:generate": "npx @better-auth/cli@latest generate --config src/lib/auth.ts --output src/db/schema/auth.ts",
|
|
29
|
+
"auth:secret": "npx @better-auth/cli@latest secret"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"better-auth": "1.3.8",
|
|
33
|
+
"drizzle-orm": "0.44.x",
|
|
34
|
+
"next": "16.2.x",
|
|
35
|
+
__DATABASE_DEPENDENCIES__
|
|
36
|
+
"react": "19.2.x",
|
|
37
|
+
"react-dom": "19.2.x",
|
|
38
|
+
__PROVIDER_PACKAGE_DEPENDENCIES__
|
|
39
|
+
"server-only": "^0.0.1",
|
|
40
|
+
"zod": "4.1.5"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@better-auth/cli": "1.3.8",
|
|
44
|
+
"@playwright/test": "1.55.0",
|
|
45
|
+
"@testing-library/react": "16.3.0",
|
|
46
|
+
"@types/node": "^24.0.0",
|
|
47
|
+
__DATABASE_DEV_DEPENDENCIES__
|
|
48
|
+
"@types/react": "^19.0.0",
|
|
49
|
+
"@types/react-dom": "^19.0.0",
|
|
50
|
+
"drizzle-kit": "0.31.x",
|
|
51
|
+
"eslint": "9.35.0",
|
|
52
|
+
"eslint-config-next": "16.2.x",
|
|
53
|
+
"eslint-config-prettier": "10.1.8",
|
|
54
|
+
"eslint-import-resolver-typescript": "^3.10.1",
|
|
55
|
+
"eslint-plugin-import": "2.32.0",
|
|
56
|
+
"eslint-plugin-unused-imports": "4.2.0",
|
|
57
|
+
"globals": "16.3.0",
|
|
58
|
+
"husky": "^9.1.7",
|
|
59
|
+
"jsdom": "26.1.0",
|
|
60
|
+
"lint-staged": "^16.1.6",
|
|
61
|
+
"playwright": "1.55.0",
|
|
62
|
+
"prettier": "3.6.2",
|
|
63
|
+
"tsx": "4.20.x",
|
|
64
|
+
"typescript": "5.9.x",
|
|
65
|
+
"vitest": "3.2.4"
|
|
66
|
+
},
|
|
67
|
+
"lint-staged": {
|
|
68
|
+
"*.{js,jsx,ts,tsx,mjs,cjs}": [
|
|
69
|
+
"eslint --fix"
|
|
70
|
+
],
|
|
71
|
+
"*.{json,md,css,yml,yaml,html}": [
|
|
72
|
+
"prettier --write"
|
|
73
|
+
]
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { defineConfig, devices } from "@playwright/test";
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
testDir: "./tests/e2e",
|
|
5
|
+
fullyParallel: true,
|
|
6
|
+
use: {
|
|
7
|
+
baseURL: "http://127.0.0.1:3000",
|
|
8
|
+
trace: "on-first-retry"
|
|
9
|
+
},
|
|
10
|
+
webServer: {
|
|
11
|
+
command: "npm run dev",
|
|
12
|
+
url: "http://127.0.0.1:3000",
|
|
13
|
+
reuseExistingServer: !process.env.CI
|
|
14
|
+
},
|
|
15
|
+
projects: [
|
|
16
|
+
{
|
|
17
|
+
name: "chromium",
|
|
18
|
+
use: { ...devices["Desktop Chrome"] }
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
import type { NextRequest } from "next/server";
|
|
3
|
+
|
|
4
|
+
import { getSessionCookie } from "better-auth/cookies";
|
|
5
|
+
|
|
6
|
+
export function proxy(request: NextRequest) {
|
|
7
|
+
const sessionCookie = getSessionCookie(request);
|
|
8
|
+
const { pathname } = request.nextUrl;
|
|
9
|
+
|
|
10
|
+
if (!sessionCookie && (__PROTECTED_ROUTE_CONDITION__)) {
|
|
11
|
+
return NextResponse.redirect(new URL("/sign-in", request.url));
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (sessionCookie && (pathname === "/sign-in" || pathname === "/sign-up")) {
|
|
15
|
+
return NextResponse.redirect(new URL("/dashboard", request.url));
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return NextResponse.next();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const config = {
|
|
22
|
+
matcher: [__PROTECTED_ROUTE_MATCHERS__, "/sign-in", "/sign-up"]
|
|
23
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { redirect } from "next/navigation";
|
|
2
|
+
|
|
3
|
+
import { getSession } from "@/lib/auth-session";
|
|
4
|
+
import { getBillingProvider, getBillingProviderName } from "@/lib/billing";
|
|
5
|
+
import { env } from "@/lib/env";
|
|
6
|
+
|
|
7
|
+
export async function POST(request: Request) {
|
|
8
|
+
const session = await getSession();
|
|
9
|
+
|
|
10
|
+
if (!session) {
|
|
11
|
+
redirect("/sign-in");
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const formData = await request.formData();
|
|
15
|
+
const selected = String(formData.get("provider") ?? "");
|
|
16
|
+
const providerName = getBillingProviderName(selected);
|
|
17
|
+
const provider = getBillingProvider(providerName);
|
|
18
|
+
const checkout = await provider.createCheckoutSession({
|
|
19
|
+
userId: session.user.id,
|
|
20
|
+
customerEmail: session.user.email,
|
|
21
|
+
successUrl: `${env.NEXT_PUBLIC_APP_URL}/billing?success=1&provider=${providerName}`,
|
|
22
|
+
cancelUrl: `${env.NEXT_PUBLIC_APP_URL}/billing?canceled=1&provider=${providerName}`
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
redirect(checkout.url);
|
|
26
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { redirect } from "next/navigation";
|
|
2
|
+
|
|
3
|
+
import { getSession } from "@/lib/auth-session";
|
|
4
|
+
import { getBillingProvider, getBillingProviderName } from "@/lib/billing";
|
|
5
|
+
import { env } from "@/lib/env";
|
|
6
|
+
|
|
7
|
+
export async function POST(request: Request) {
|
|
8
|
+
const session = await getSession();
|
|
9
|
+
|
|
10
|
+
if (!session) {
|
|
11
|
+
redirect("/sign-in");
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const formData = await request.formData();
|
|
15
|
+
const selected = String(formData.get("provider") ?? "");
|
|
16
|
+
const providerName = getBillingProviderName(selected);
|
|
17
|
+
const provider = getBillingProvider(providerName);
|
|
18
|
+
const portal = await provider.createCustomerPortalSession({
|
|
19
|
+
userId: session.user.id,
|
|
20
|
+
customerEmail: session.user.email,
|
|
21
|
+
returnUrl: `${env.NEXT_PUBLIC_APP_URL}/billing?provider=${providerName}`
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
redirect(portal.url);
|
|
25
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { redirect } from "next/navigation";
|
|
2
|
+
|
|
3
|
+
import { getSession } from "@/lib/auth-session";
|
|
4
|
+
import { sendEmail } from "@/lib/email";
|
|
5
|
+
import { createWelcomeEmailTemplate } from "@/lib/email/templates";
|
|
6
|
+
import { env } from "@/lib/env";
|
|
7
|
+
|
|
8
|
+
export async function POST() {
|
|
9
|
+
const session = await getSession();
|
|
10
|
+
|
|
11
|
+
if (!session) {
|
|
12
|
+
redirect("/sign-in");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (env.EMAIL_PROVIDER === "none") {
|
|
16
|
+
redirect("/email");
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
await sendEmail({
|
|
20
|
+
to: session.user.email,
|
|
21
|
+
template: createWelcomeEmailTemplate({
|
|
22
|
+
appName: "Skit",
|
|
23
|
+
recipientName: session.user.name
|
|
24
|
+
})
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
redirect("/email?sent=1");
|
|
28
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
__BILLING_REDIRECT_IMPORT__
|
|
2
|
+
import { getSession } from "@/lib/auth-session";
|
|
3
|
+
import { env } from "@/lib/env";
|
|
4
|
+
|
|
5
|
+
export default async function BillingPage({
|
|
6
|
+
searchParams
|
|
7
|
+
}: {
|
|
8
|
+
searchParams: Promise<Record<string, string | string[] | undefined>>;
|
|
9
|
+
}) {
|
|
10
|
+
const session = await getSession();
|
|
11
|
+
|
|
12
|
+
__BILLING_SESSION_SETUP__
|
|
13
|
+
__BILLING_AUTH_GUARD__
|
|
14
|
+
|
|
15
|
+
const params = await searchParams;
|
|
16
|
+
const success = params.success === "1";
|
|
17
|
+
const canceled = params.canceled === "1";
|
|
18
|
+
const providers =
|
|
19
|
+
env.BILLING_PROVIDER === "both"
|
|
20
|
+
? ["stripe", "polar"]
|
|
21
|
+
: env.BILLING_PROVIDER === "none"
|
|
22
|
+
? []
|
|
23
|
+
: [env.BILLING_PROVIDER];
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<main className="__AUTH_SCREEN_CLASS__">
|
|
27
|
+
<section className="__AUTH_PANEL_CLASS__">
|
|
28
|
+
<p className="eyebrow">Billing</p>
|
|
29
|
+
<h1>Choose your billing provider</h1>
|
|
30
|
+
<p className="lede">
|
|
31
|
+
The starter routes all billing actions through a provider abstraction. Current
|
|
32
|
+
default: <strong>{env.BILLING_PROVIDER}</strong>.
|
|
33
|
+
</p>
|
|
34
|
+
|
|
35
|
+
{success ? <p className="form-success">Checkout completed or redirected successfully.</p> : null}
|
|
36
|
+
{canceled ? <p className="form-error">Checkout was canceled.</p> : null}
|
|
37
|
+
|
|
38
|
+
__BILLING_DEMO_BANNER__
|
|
39
|
+
|
|
40
|
+
{providers.length === 0 ? (
|
|
41
|
+
<p className="form-error">
|
|
42
|
+
Billing is disabled for this generated app. Re-run the starter with a billing
|
|
43
|
+
provider to enable checkout flows.
|
|
44
|
+
</p>
|
|
45
|
+
) : (
|
|
46
|
+
<div className="billing-grid">
|
|
47
|
+
{providers.map((provider) => (
|
|
48
|
+
__BILLING_PROVIDER_CARD__
|
|
49
|
+
))}
|
|
50
|
+
</div>
|
|
51
|
+
)}
|
|
52
|
+
</section>
|
|
53
|
+
</main>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import Link from "next/link";
|
|
2
|
+
__DASHBOARD_REDIRECT_IMPORT__
|
|
3
|
+
import { SignOutButton } from "@/components/auth/sign-out-button";
|
|
4
|
+
import { getSession } from "@/lib/auth-session";
|
|
5
|
+
|
|
6
|
+
__DASHBOARD_PAGE_PRELUDE__
|
|
7
|
+
|
|
8
|
+
export default async function DashboardPage() {
|
|
9
|
+
const session = await getSession();
|
|
10
|
+
|
|
11
|
+
__DASHBOARD_SESSION_SETUP__
|
|
12
|
+
__DASHBOARD_AUTH_GUARD__
|
|
13
|
+
|
|
14
|
+
return __DASHBOARD_PAGE_CONTENT__;
|
|
15
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import Link from "next/link";
|
|
2
|
+
__EMAIL_REDIRECT_IMPORT__
|
|
3
|
+
import { getSession } from "@/lib/auth-session";
|
|
4
|
+
import { env } from "@/lib/env";
|
|
5
|
+
|
|
6
|
+
export default async function EmailPage({
|
|
7
|
+
searchParams
|
|
8
|
+
}: {
|
|
9
|
+
searchParams: Promise<Record<string, string | string[] | undefined>>;
|
|
10
|
+
}) {
|
|
11
|
+
const session = await getSession();
|
|
12
|
+
|
|
13
|
+
__EMAIL_SESSION_SETUP__
|
|
14
|
+
__EMAIL_AUTH_GUARD__
|
|
15
|
+
|
|
16
|
+
const params = await searchParams;
|
|
17
|
+
const sent = params.sent === "1";
|
|
18
|
+
const emailDisabled = env.EMAIL_PROVIDER === "none";
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<main className="__AUTH_SCREEN_CLASS__">
|
|
22
|
+
<section className="__AUTH_PANEL_CLASS__">
|
|
23
|
+
<p className="eyebrow">Email</p>
|
|
24
|
+
<h1>Transactional email baseline</h1>
|
|
25
|
+
<p className="lede">
|
|
26
|
+
{emailDisabled
|
|
27
|
+
? "Email provider is disabled for this generated app. Switch EMAIL_PROVIDER to resend when you want to wire transactional email."
|
|
28
|
+
: "The starter routes email sending through a single server-side Resend service. Use this page to verify the wiring and then connect real auth and billing emails."}
|
|
29
|
+
</p>
|
|
30
|
+
|
|
31
|
+
{sent ? <p className="form-success">Test email sent to {displayEmailRecipient}.</p> : null}
|
|
32
|
+
|
|
33
|
+
__EMAIL_DEMO_BANNER__
|
|
34
|
+
|
|
35
|
+
<div className="hero-actions">
|
|
36
|
+
<form action="/api/email/test" method="post">
|
|
37
|
+
<button type="submit" className="auth-button" disabled={emailDisabled || emailSendingDisabled}>
|
|
38
|
+
Send test email
|
|
39
|
+
</button>
|
|
40
|
+
</form>
|
|
41
|
+
<Link href="/dashboard">Back to dashboard</Link>
|
|
42
|
+
</div>
|
|
43
|
+
</section>
|
|
44
|
+
</main>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import Link from "next/link";
|
|
4
|
+
|
|
5
|
+
export default function Error({
|
|
6
|
+
error,
|
|
7
|
+
reset
|
|
8
|
+
}: {
|
|
9
|
+
error: Error & { digest?: string };
|
|
10
|
+
reset: () => void;
|
|
11
|
+
}) {
|
|
12
|
+
return (
|
|
13
|
+
<main className="shell">
|
|
14
|
+
<section className="hero">
|
|
15
|
+
<p className="eyebrow">Error</p>
|
|
16
|
+
<h1>Something went wrong</h1>
|
|
17
|
+
<p className="lede">{error.message || "An unexpected error occurred."}</p>
|
|
18
|
+
<div className="hero-actions">
|
|
19
|
+
<button type="button" onClick={reset}>
|
|
20
|
+
Try again
|
|
21
|
+
</button>
|
|
22
|
+
<Link href="/">Go home</Link>
|
|
23
|
+
</div>
|
|
24
|
+
</section>
|
|
25
|
+
</main>
|
|
26
|
+
);
|
|
27
|
+
}
|