@odvi/create-dtt-framework 0.1.6 → 0.1.8
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/dist/index.js +0 -0
- package/dist/utils/template.js +15 -1
- package/dist/utils/template.js.map +1 -1
- package/package.json +50 -51
- package/template/DESIGN.md +1052 -0
- package/template/LICENSE +21 -0
- package/template/README.md +157 -7
- package/template/drizzle/0000_awesome_argent.sql +18 -0
- package/template/drizzle/meta/0000_snapshot.json +129 -0
- package/template/drizzle/meta/_journal.json +13 -0
- package/template/eslint.config.js +61 -0
- package/template/start-database.sh +88 -0
- package/template/supabase/.temp/cli-latest +1 -0
- package/template/supabase/functions/health-check/index.ts +84 -0
package/template/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 DTT Framework
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/template/README.md
CHANGED
|
@@ -2,25 +2,64 @@
|
|
|
2
2
|
|
|
3
3
|
This is a DTT Framework application created with the CLI.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Quick Start
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
### Prerequisites
|
|
8
|
+
|
|
9
|
+
- **Node.js** 20 or higher
|
|
10
|
+
- **pnpm** 10 or higher
|
|
11
|
+
- **Supabase account** ([Sign up](https://supabase.com/))
|
|
12
|
+
- **Clerk account** ([Sign up](https://clerk.com/))
|
|
13
|
+
- **Snowflake account** (optional)
|
|
14
|
+
|
|
15
|
+
### 1. Environment Setup
|
|
16
|
+
|
|
17
|
+
Copy the example environment file and fill in your credentials:
|
|
8
18
|
|
|
9
19
|
```bash
|
|
10
|
-
|
|
20
|
+
cp .env.example .env
|
|
11
21
|
```
|
|
12
22
|
|
|
13
|
-
|
|
23
|
+
Edit `.env` and fill in the required keys for Clerk and Supabase. See [Environment Variables](docs/framework/environment-variables.md) for details.
|
|
24
|
+
|
|
25
|
+
### 2. Database Setup
|
|
26
|
+
|
|
27
|
+
Push the database schema to your Supabase project:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pnpm db:push
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
This will create the necessary tables, including `health_check_tests` required for the health dashboard.
|
|
34
|
+
|
|
35
|
+
### 3. Deploy Edge Functions
|
|
36
|
+
|
|
37
|
+
The health check system requires a Supabase Edge Function. Deploy it using the Supabase CLI:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
# Login to Supabase
|
|
41
|
+
npx supabase login
|
|
42
|
+
|
|
43
|
+
# Link your project (get your-project-ref from Supabase dashboard URL)
|
|
44
|
+
npx supabase link --project-ref your-project-ref
|
|
45
|
+
|
|
46
|
+
# Deploy the function
|
|
47
|
+
npx supabase functions deploy health-check
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### 4. Start Development Server
|
|
14
51
|
|
|
15
52
|
```bash
|
|
16
53
|
pnpm dev
|
|
17
54
|
```
|
|
18
55
|
|
|
19
|
-
Open [http://localhost:3000](http://localhost:3000) with your browser
|
|
56
|
+
Open [http://localhost:3000](http://localhost:3000) with your browser.
|
|
57
|
+
|
|
58
|
+
### 5. Verify Health
|
|
20
59
|
|
|
21
|
-
|
|
60
|
+
Visit [http://localhost:3000/health](http://localhost:3000/health) to verify all services are connected and working.
|
|
22
61
|
|
|
23
|
-
|
|
62
|
+
---
|
|
24
63
|
|
|
25
64
|
## Documentation
|
|
26
65
|
|
|
@@ -28,3 +67,114 @@ To learn more about DTT Framework, visit the [documentation](./docs/framework/01
|
|
|
28
67
|
- [Tech Stack](./docs/framework/02-techstack.md)
|
|
29
68
|
- [Environment Variables](./docs/framework/environment-variables.md)
|
|
30
69
|
- [CLI Installation](./docs/framework/cli-installation.md)
|
|
70
|
+
- [Health Check System](./docs/framework/health-check-system.md)
|
|
71
|
+
- [Clerk Authentication](./docs/framework/clerk-authentication.md)
|
|
72
|
+
- [Supabase Integration](./docs/framework/supabase-integration.md)
|
|
73
|
+
- [Snowflake Integration](./docs/framework/snowflake-integration.md)
|
|
74
|
+
|
|
75
|
+
## Key Features
|
|
76
|
+
|
|
77
|
+
### 1. Authentication & User Management
|
|
78
|
+
- **Clerk Integration**: Complete authentication solution with sign-in, sign-up, and user management
|
|
79
|
+
- **Organization Support**: Multi-tenant architecture with organization memberships
|
|
80
|
+
- **Webhook Synchronization**: Automatic user data sync to local database
|
|
81
|
+
- **Protected Routes**: Middleware-based route protection
|
|
82
|
+
|
|
83
|
+
### 2. Database Layer
|
|
84
|
+
- **PostgreSQL**: Robust relational database via Supabase
|
|
85
|
+
- **Drizzle ORM**: Type-safe database queries with excellent TypeScript support
|
|
86
|
+
- **Connection Pooling**: Optimized for Supabase Transaction mode
|
|
87
|
+
- **Schema Management**: Migration-based schema evolution
|
|
88
|
+
|
|
89
|
+
### 3. Storage & Edge Computing
|
|
90
|
+
- **Supabase Storage**: File upload/download with signed URLs
|
|
91
|
+
- **Edge Functions**: Serverless compute with auth header passthrough
|
|
92
|
+
- **Bucket Management**: Organized file storage structure
|
|
93
|
+
|
|
94
|
+
### 4. Data Warehouse
|
|
95
|
+
- **Snowflake Integration**: Direct connection to Snowflake data warehouse
|
|
96
|
+
- **Query Execution**: Execute SQL queries from the application
|
|
97
|
+
- **Warehouse Configuration**: Support for multiple warehouses and databases
|
|
98
|
+
|
|
99
|
+
### 5. API Layer
|
|
100
|
+
- **Hono Framework**: Lightweight and fast API framework
|
|
101
|
+
- **Middleware Support**: Authentication, logging, CORS
|
|
102
|
+
- **Route Organization**: Modular route structure
|
|
103
|
+
- **Type Safety**: Full TypeScript support with inferred types
|
|
104
|
+
|
|
105
|
+
### 6. State Management
|
|
106
|
+
- **TanStack Query**: Server state management with caching and synchronization
|
|
107
|
+
- **Zustand**: Lightweight client state management
|
|
108
|
+
- **React Hooks**: Custom hooks for common patterns
|
|
109
|
+
|
|
110
|
+
### 7. Health Check System
|
|
111
|
+
- **Comprehensive Monitoring**: Health checks for all integrated services
|
|
112
|
+
- **Dashboard UI**: Visual health status display
|
|
113
|
+
- **Response Time Tracking**: Performance monitoring
|
|
114
|
+
- **Error Reporting**: Detailed error messages and status codes
|
|
115
|
+
|
|
116
|
+
### 8. Developer Experience
|
|
117
|
+
- **TypeScript**: Full type safety across the stack
|
|
118
|
+
- **Tailwind CSS**: Utility-first styling
|
|
119
|
+
- **Shadcn/ui**: Beautiful, accessible UI components
|
|
120
|
+
- **Hot Reload**: Fast development with Next.js Turbo
|
|
121
|
+
- **Linting & Formatting**: ESLint and Prettier configured
|
|
122
|
+
|
|
123
|
+
## Folder Structure
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
dtt-framework/
|
|
127
|
+
├── docs/ # Framework documentation
|
|
128
|
+
├── public/ # Static assets
|
|
129
|
+
├── src/ # Source code
|
|
130
|
+
│ ├── app/ # Next.js App Router
|
|
131
|
+
│ ├── components/ # React components
|
|
132
|
+
│ ├── features/ # Feature modules
|
|
133
|
+
│ ├── hooks/ # React hooks
|
|
134
|
+
│ ├── lib/ # Utility libraries and clients
|
|
135
|
+
│ ├── server/ # Server-side code (API, database)
|
|
136
|
+
│ ├── stores/ # Zustand state stores
|
|
137
|
+
│ ├── types/ # TypeScript types
|
|
138
|
+
│ ├── config/ # Configuration files
|
|
139
|
+
│ ├── env.js # Environment variables
|
|
140
|
+
│ ├── middleware.ts # Next.js middleware
|
|
141
|
+
│ └── styles/ # Styles
|
|
142
|
+
├── .env.example # Environment variables template
|
|
143
|
+
├── drizzle.config.ts # Drizzle ORM configuration
|
|
144
|
+
├── next.config.js # Next.js configuration
|
|
145
|
+
├── package.json # Dependencies and scripts
|
|
146
|
+
└── README.md # This file
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## Development
|
|
150
|
+
|
|
151
|
+
### Available Scripts
|
|
152
|
+
|
|
153
|
+
| Script | Description |
|
|
154
|
+
|--------|-------------|
|
|
155
|
+
| `pnpm dev` | Start development server with Turbo |
|
|
156
|
+
| `pnpm build` | Build for production |
|
|
157
|
+
| `pnpm start` | Start production server |
|
|
158
|
+
| `pnpm lint` | Run ESLint |
|
|
159
|
+
| `pnpm format:write` | Format code with Prettier |
|
|
160
|
+
| `pnpm typecheck` | Run TypeScript type checking |
|
|
161
|
+
| `pnpm db:generate` | Generate database migrations |
|
|
162
|
+
| `pnpm db:migrate` | Apply database migrations |
|
|
163
|
+
| `pnpm db:push` | Push schema changes to database |
|
|
164
|
+
| `pnpm db:studio` | Open Drizzle Studio |
|
|
165
|
+
|
|
166
|
+
## Deployment
|
|
167
|
+
|
|
168
|
+
For deployment instructions, please refer to the [Deployment Guide](docs/framework/deployment/vercel.md).
|
|
169
|
+
|
|
170
|
+
## Support
|
|
171
|
+
|
|
172
|
+
If you need help:
|
|
173
|
+
|
|
174
|
+
1. **Check the documentation** in `docs/` folder
|
|
175
|
+
2. **Check the health dashboard** at `/health`
|
|
176
|
+
3. **Open an issue** on GitHub
|
|
177
|
+
|
|
178
|
+
## License
|
|
179
|
+
|
|
180
|
+
MIT
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
CREATE TABLE "users" (
|
|
2
|
+
"id" text PRIMARY KEY NOT NULL,
|
|
3
|
+
"email" varchar(255) NOT NULL,
|
|
4
|
+
"first_name" varchar(255),
|
|
5
|
+
"last_name" varchar(255),
|
|
6
|
+
"image_url" text,
|
|
7
|
+
"clerk_org_id" text,
|
|
8
|
+
"created_at" timestamp DEFAULT now() NOT NULL,
|
|
9
|
+
"updated_at" timestamp DEFAULT now() NOT NULL,
|
|
10
|
+
CONSTRAINT "users_email_unique" UNIQUE("email")
|
|
11
|
+
);
|
|
12
|
+
--> statement-breakpoint
|
|
13
|
+
CREATE TABLE "health_check_tests" (
|
|
14
|
+
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
15
|
+
"test_key" text NOT NULL,
|
|
16
|
+
"test_value" text,
|
|
17
|
+
"created_at" timestamp DEFAULT now() NOT NULL
|
|
18
|
+
);
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "8ef2966f-b7b3-4fd4-adfc-84bfe2fdbf38",
|
|
3
|
+
"prevId": "00000000-0000-0000-0000-000000000000",
|
|
4
|
+
"version": "7",
|
|
5
|
+
"dialect": "postgresql",
|
|
6
|
+
"tables": {
|
|
7
|
+
"public.users": {
|
|
8
|
+
"name": "users",
|
|
9
|
+
"schema": "",
|
|
10
|
+
"columns": {
|
|
11
|
+
"id": {
|
|
12
|
+
"name": "id",
|
|
13
|
+
"type": "text",
|
|
14
|
+
"primaryKey": true,
|
|
15
|
+
"notNull": true
|
|
16
|
+
},
|
|
17
|
+
"email": {
|
|
18
|
+
"name": "email",
|
|
19
|
+
"type": "varchar(255)",
|
|
20
|
+
"primaryKey": false,
|
|
21
|
+
"notNull": true
|
|
22
|
+
},
|
|
23
|
+
"first_name": {
|
|
24
|
+
"name": "first_name",
|
|
25
|
+
"type": "varchar(255)",
|
|
26
|
+
"primaryKey": false,
|
|
27
|
+
"notNull": false
|
|
28
|
+
},
|
|
29
|
+
"last_name": {
|
|
30
|
+
"name": "last_name",
|
|
31
|
+
"type": "varchar(255)",
|
|
32
|
+
"primaryKey": false,
|
|
33
|
+
"notNull": false
|
|
34
|
+
},
|
|
35
|
+
"image_url": {
|
|
36
|
+
"name": "image_url",
|
|
37
|
+
"type": "text",
|
|
38
|
+
"primaryKey": false,
|
|
39
|
+
"notNull": false
|
|
40
|
+
},
|
|
41
|
+
"clerk_org_id": {
|
|
42
|
+
"name": "clerk_org_id",
|
|
43
|
+
"type": "text",
|
|
44
|
+
"primaryKey": false,
|
|
45
|
+
"notNull": false
|
|
46
|
+
},
|
|
47
|
+
"created_at": {
|
|
48
|
+
"name": "created_at",
|
|
49
|
+
"type": "timestamp",
|
|
50
|
+
"primaryKey": false,
|
|
51
|
+
"notNull": true,
|
|
52
|
+
"default": "now()"
|
|
53
|
+
},
|
|
54
|
+
"updated_at": {
|
|
55
|
+
"name": "updated_at",
|
|
56
|
+
"type": "timestamp",
|
|
57
|
+
"primaryKey": false,
|
|
58
|
+
"notNull": true,
|
|
59
|
+
"default": "now()"
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"indexes": {},
|
|
63
|
+
"foreignKeys": {},
|
|
64
|
+
"compositePrimaryKeys": {},
|
|
65
|
+
"uniqueConstraints": {
|
|
66
|
+
"users_email_unique": {
|
|
67
|
+
"name": "users_email_unique",
|
|
68
|
+
"nullsNotDistinct": false,
|
|
69
|
+
"columns": [
|
|
70
|
+
"email"
|
|
71
|
+
]
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
"policies": {},
|
|
75
|
+
"checkConstraints": {},
|
|
76
|
+
"isRLSEnabled": false
|
|
77
|
+
},
|
|
78
|
+
"public.health_check_tests": {
|
|
79
|
+
"name": "health_check_tests",
|
|
80
|
+
"schema": "",
|
|
81
|
+
"columns": {
|
|
82
|
+
"id": {
|
|
83
|
+
"name": "id",
|
|
84
|
+
"type": "uuid",
|
|
85
|
+
"primaryKey": true,
|
|
86
|
+
"notNull": true,
|
|
87
|
+
"default": "gen_random_uuid()"
|
|
88
|
+
},
|
|
89
|
+
"test_key": {
|
|
90
|
+
"name": "test_key",
|
|
91
|
+
"type": "text",
|
|
92
|
+
"primaryKey": false,
|
|
93
|
+
"notNull": true
|
|
94
|
+
},
|
|
95
|
+
"test_value": {
|
|
96
|
+
"name": "test_value",
|
|
97
|
+
"type": "text",
|
|
98
|
+
"primaryKey": false,
|
|
99
|
+
"notNull": false
|
|
100
|
+
},
|
|
101
|
+
"created_at": {
|
|
102
|
+
"name": "created_at",
|
|
103
|
+
"type": "timestamp",
|
|
104
|
+
"primaryKey": false,
|
|
105
|
+
"notNull": true,
|
|
106
|
+
"default": "now()"
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
"indexes": {},
|
|
110
|
+
"foreignKeys": {},
|
|
111
|
+
"compositePrimaryKeys": {},
|
|
112
|
+
"uniqueConstraints": {},
|
|
113
|
+
"policies": {},
|
|
114
|
+
"checkConstraints": {},
|
|
115
|
+
"isRLSEnabled": false
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
"enums": {},
|
|
119
|
+
"schemas": {},
|
|
120
|
+
"sequences": {},
|
|
121
|
+
"roles": {},
|
|
122
|
+
"policies": {},
|
|
123
|
+
"views": {},
|
|
124
|
+
"_meta": {
|
|
125
|
+
"columns": {},
|
|
126
|
+
"schemas": {},
|
|
127
|
+
"tables": {}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { FlatCompat } from "@eslint/eslintrc";
|
|
2
|
+
import tseslint from "typescript-eslint";
|
|
3
|
+
// @ts-ignore -- no types for this plugin
|
|
4
|
+
import drizzle from "eslint-plugin-drizzle";
|
|
5
|
+
|
|
6
|
+
const compat = new FlatCompat({
|
|
7
|
+
baseDirectory: import.meta.dirname,
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
export default tseslint.config(
|
|
11
|
+
{
|
|
12
|
+
ignores: [".next"],
|
|
13
|
+
},
|
|
14
|
+
...compat.extends("next/core-web-vitals"),
|
|
15
|
+
{
|
|
16
|
+
files: ["**/*.ts", "**/*.tsx"],
|
|
17
|
+
plugins: {
|
|
18
|
+
drizzle,
|
|
19
|
+
},
|
|
20
|
+
extends: [
|
|
21
|
+
...tseslint.configs.recommended,
|
|
22
|
+
...tseslint.configs.recommendedTypeChecked,
|
|
23
|
+
...tseslint.configs.stylisticTypeChecked,
|
|
24
|
+
],
|
|
25
|
+
rules: {
|
|
26
|
+
"@typescript-eslint/array-type": "off",
|
|
27
|
+
"@typescript-eslint/consistent-type-definitions": "off",
|
|
28
|
+
"@typescript-eslint/consistent-type-imports": [
|
|
29
|
+
"warn",
|
|
30
|
+
{ prefer: "type-imports", fixStyle: "inline-type-imports" },
|
|
31
|
+
],
|
|
32
|
+
"@typescript-eslint/no-unused-vars": [
|
|
33
|
+
"warn",
|
|
34
|
+
{ argsIgnorePattern: "^_" },
|
|
35
|
+
],
|
|
36
|
+
"@typescript-eslint/require-await": "off",
|
|
37
|
+
"@typescript-eslint/no-misused-promises": [
|
|
38
|
+
"error",
|
|
39
|
+
{ checksVoidReturn: { attributes: false } },
|
|
40
|
+
],
|
|
41
|
+
"drizzle/enforce-delete-with-where": [
|
|
42
|
+
"error",
|
|
43
|
+
{ drizzleObjectName: ["db", "ctx.db"] },
|
|
44
|
+
],
|
|
45
|
+
"drizzle/enforce-update-with-where": [
|
|
46
|
+
"error",
|
|
47
|
+
{ drizzleObjectName: ["db", "ctx.db"] },
|
|
48
|
+
],
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
linterOptions: {
|
|
53
|
+
reportUnusedDisableDirectives: true,
|
|
54
|
+
},
|
|
55
|
+
languageOptions: {
|
|
56
|
+
parserOptions: {
|
|
57
|
+
projectService: true,
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
);
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Use this script to start a docker container for a local development database
|
|
3
|
+
|
|
4
|
+
# TO RUN ON WINDOWS:
|
|
5
|
+
# 1. Install WSL (Windows Subsystem for Linux) - https://learn.microsoft.com/en-us/windows/wsl/install
|
|
6
|
+
# 2. Install Docker Desktop or Podman Deskop
|
|
7
|
+
# - Docker Desktop for Windows - https://docs.docker.com/docker-for-windows/install/
|
|
8
|
+
# - Podman Desktop - https://podman.io/getting-started/installation
|
|
9
|
+
# 3. Open WSL - `wsl`
|
|
10
|
+
# 4. Run this script - `./start-database.sh`
|
|
11
|
+
|
|
12
|
+
# On Linux and macOS you can run this script directly - `./start-database.sh`
|
|
13
|
+
|
|
14
|
+
# import env variables from .env
|
|
15
|
+
set -a
|
|
16
|
+
source .env
|
|
17
|
+
|
|
18
|
+
DB_PASSWORD=$(echo "$DATABASE_URL" | awk -F':' '{print $3}' | awk -F'@' '{print $1}')
|
|
19
|
+
DB_PORT=$(echo "$DATABASE_URL" | awk -F':' '{print $4}' | awk -F'\/' '{print $1}')
|
|
20
|
+
DB_NAME=$(echo "$DATABASE_URL" | awk -F'/' '{print $4}')
|
|
21
|
+
DB_CONTAINER_NAME="$DB_NAME-postgres"
|
|
22
|
+
|
|
23
|
+
if ! [ -x "$(command -v docker)" ] && ! [ -x "$(command -v podman)" ]; then
|
|
24
|
+
echo -e "Docker or Podman is not installed. Please install docker or podman and try again.\nDocker install guide: https://docs.docker.com/engine/install/\nPodman install guide: https://podman.io/getting-started/installation"
|
|
25
|
+
exit 1
|
|
26
|
+
fi
|
|
27
|
+
|
|
28
|
+
# determine which docker command to use
|
|
29
|
+
if [ -x "$(command -v docker)" ]; then
|
|
30
|
+
DOCKER_CMD="docker"
|
|
31
|
+
elif [ -x "$(command -v podman)" ]; then
|
|
32
|
+
DOCKER_CMD="podman"
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
if ! $DOCKER_CMD info > /dev/null 2>&1; then
|
|
36
|
+
echo "$DOCKER_CMD daemon is not running. Please start $DOCKER_CMD and try again."
|
|
37
|
+
exit 1
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
if command -v nc >/dev/null 2>&1; then
|
|
41
|
+
if nc -z localhost "$DB_PORT" 2>/dev/null; then
|
|
42
|
+
echo "Port $DB_PORT is already in use."
|
|
43
|
+
exit 1
|
|
44
|
+
fi
|
|
45
|
+
else
|
|
46
|
+
echo "Warning: Unable to check if port $DB_PORT is already in use (netcat not installed)"
|
|
47
|
+
read -p "Do you want to continue anyway? [y/N]: " -r REPLY
|
|
48
|
+
if ! [[ $REPLY =~ ^[Yy]$ ]]; then
|
|
49
|
+
echo "Aborting."
|
|
50
|
+
exit 1
|
|
51
|
+
fi
|
|
52
|
+
fi
|
|
53
|
+
|
|
54
|
+
if [ "$($DOCKER_CMD ps -q -f name=$DB_CONTAINER_NAME)" ]; then
|
|
55
|
+
echo "Database container '$DB_CONTAINER_NAME' already running"
|
|
56
|
+
exit 0
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
if [ "$($DOCKER_CMD ps -q -a -f name=$DB_CONTAINER_NAME)" ]; then
|
|
60
|
+
$DOCKER_CMD start "$DB_CONTAINER_NAME"
|
|
61
|
+
echo "Existing database container '$DB_CONTAINER_NAME' started"
|
|
62
|
+
exit 0
|
|
63
|
+
fi
|
|
64
|
+
|
|
65
|
+
if [ "$DB_PASSWORD" = "password" ]; then
|
|
66
|
+
echo "You are using the default database password"
|
|
67
|
+
read -p "Should we generate a random password for you? [y/N]: " -r REPLY
|
|
68
|
+
if ! [[ $REPLY =~ ^[Yy]$ ]]; then
|
|
69
|
+
echo "Please change the default password in the .env file and try again"
|
|
70
|
+
exit 1
|
|
71
|
+
fi
|
|
72
|
+
# Generate a random URL-safe password
|
|
73
|
+
DB_PASSWORD=$(openssl rand -base64 12 | tr '+/' '-_')
|
|
74
|
+
if [[ "$(uname)" == "Darwin" ]]; then
|
|
75
|
+
# macOS requires an empty string to be passed with the `i` flag
|
|
76
|
+
sed -i '' "s#:password@#:$DB_PASSWORD@#" .env
|
|
77
|
+
else
|
|
78
|
+
sed -i "s#:password@#:$DB_PASSWORD@#" .env
|
|
79
|
+
fi
|
|
80
|
+
fi
|
|
81
|
+
|
|
82
|
+
$DOCKER_CMD run -d \
|
|
83
|
+
--name $DB_CONTAINER_NAME \
|
|
84
|
+
-e POSTGRES_USER="postgres" \
|
|
85
|
+
-e POSTGRES_PASSWORD="$DB_PASSWORD" \
|
|
86
|
+
-e POSTGRES_DB="$DB_NAME" \
|
|
87
|
+
-p "$DB_PORT":5432 \
|
|
88
|
+
docker.io/postgres && echo "Database container '$DB_CONTAINER_NAME' was successfully created"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
v2.67.1
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// Follow this setup guide to deploy the function:
|
|
2
|
+
// https://supabase.com/docs/guides/functions/deploy
|
|
3
|
+
|
|
4
|
+
import { serve } from "https://deno.land/std@0.168.0/http/server.ts"
|
|
5
|
+
|
|
6
|
+
const corsHeaders = {
|
|
7
|
+
'Access-Control-Allow-Origin': '*',
|
|
8
|
+
'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
serve(async (req) => {
|
|
12
|
+
if (req.method === 'OPTIONS') {
|
|
13
|
+
return new Response('ok', { headers: corsHeaders })
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
const { message } = await req.json()
|
|
18
|
+
let authHeader = req.headers.get('Authorization')
|
|
19
|
+
const testAuthHeader = req.headers.get('x-test-auth')
|
|
20
|
+
|
|
21
|
+
// Handle ping check
|
|
22
|
+
if (message === 'ping') {
|
|
23
|
+
return new Response(
|
|
24
|
+
JSON.stringify({
|
|
25
|
+
message: 'pong',
|
|
26
|
+
timestamp: new Date().toISOString(),
|
|
27
|
+
}),
|
|
28
|
+
{
|
|
29
|
+
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
|
|
30
|
+
status: 200,
|
|
31
|
+
},
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Handle auth check
|
|
36
|
+
if (message === 'auth-check') {
|
|
37
|
+
// Prioritize test header if present (allows testing without bypassing Supabase Gateway auth)
|
|
38
|
+
if (testAuthHeader) {
|
|
39
|
+
authHeader = testAuthHeader
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (!authHeader) {
|
|
43
|
+
return new Response(
|
|
44
|
+
JSON.stringify({ error: 'No authorization header provided' }),
|
|
45
|
+
{
|
|
46
|
+
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
|
|
47
|
+
status: 401,
|
|
48
|
+
},
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return new Response(
|
|
53
|
+
JSON.stringify({
|
|
54
|
+
message: 'Auth header received',
|
|
55
|
+
hasAuth: true,
|
|
56
|
+
// Don't log/return the full token in production for security
|
|
57
|
+
tokenPrefix: authHeader.substring(0, 10) + '...',
|
|
58
|
+
source: testAuthHeader ? 'x-test-auth' : 'Authorization'
|
|
59
|
+
}),
|
|
60
|
+
{
|
|
61
|
+
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
|
|
62
|
+
status: 200,
|
|
63
|
+
},
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return new Response(
|
|
68
|
+
JSON.stringify({ error: 'Unknown message type' }),
|
|
69
|
+
{
|
|
70
|
+
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
|
|
71
|
+
status: 400,
|
|
72
|
+
},
|
|
73
|
+
)
|
|
74
|
+
} catch (error) {
|
|
75
|
+
return new Response(
|
|
76
|
+
JSON.stringify({ error: error.message }),
|
|
77
|
+
{
|
|
78
|
+
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
|
|
79
|
+
status: 400,
|
|
80
|
+
},
|
|
81
|
+
)
|
|
82
|
+
}
|
|
83
|
+
})
|
|
84
|
+
|