From 390b063f8909187ec71295a6ce3e4b3375d0de06 Mon Sep 17 00:00:00 2001 From: Ori Marx Date: Fri, 10 Apr 2026 14:30:00 -0400 Subject: [PATCH 01/11] installed dependencies / initiated supabase --- package-lock.json | 154 ++++++++++++++++- package.json | 4 +- supabase/.gitignore | 8 + supabase/config.toml | 403 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 566 insertions(+), 3 deletions(-) create mode 100644 supabase/.gitignore create mode 100644 supabase/config.toml diff --git a/package-lock.json b/package-lock.json index 541af52..69a8638 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,8 @@ "name": "swale", "version": "0.1.0", "dependencies": { + "@supabase/ssr": "^0.10.2", + "@supabase/supabase-js": "^2.103.0", "next": "16.2.3", "react": "19.2.4", "react-dom": "19.2.4" @@ -1235,6 +1237,104 @@ "dev": true, "license": "MIT" }, + "node_modules/@supabase/auth-js": { + "version": "2.103.0", + "resolved": "https://registry.npmjs.org/@supabase/auth-js/-/auth-js-2.103.0.tgz", + "integrity": "sha512-6zAanO6c+6gpHOlt5Lb9TlBBkJdZiUWkWCJKAxzkywBDcwaHlLJKXnjQGX6GyVCyKRR1e7sTq4re/yRTH6U/9A==", + "license": "MIT", + "dependencies": { + "tslib": "2.8.1" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@supabase/functions-js": { + "version": "2.103.0", + "resolved": "https://registry.npmjs.org/@supabase/functions-js/-/functions-js-2.103.0.tgz", + "integrity": "sha512-YrneV2NjskUkkmkZ2Jt2n3elBgbWzV4Y1M9MM370z2Zd5ZPFqFbY8KIoPwuNjtAGE9YrpKBxnbZqeF07BiN9Og==", + "license": "MIT", + "dependencies": { + "tslib": "2.8.1" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@supabase/phoenix": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@supabase/phoenix/-/phoenix-0.4.0.tgz", + "integrity": "sha512-RHSx8bHS02xwfHdAbX5Lpbo6PXbgyf7lTaXTlwtFDPwOIw64NnVRwFAXGojHhjtVYI+PEPNSWwkL90f4agN3bw==", + "license": "MIT" + }, + "node_modules/@supabase/postgrest-js": { + "version": "2.103.0", + "resolved": "https://registry.npmjs.org/@supabase/postgrest-js/-/postgrest-js-2.103.0.tgz", + "integrity": "sha512-rC3sRxYdPZymkp2CZR1MiNQgbOleD01bGsW8VxEKRR5nMkLZ1NgAS1QTQf78Wh30czFyk505ZYr9Od8/mWT2TA==", + "license": "MIT", + "dependencies": { + "tslib": "2.8.1" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@supabase/realtime-js": { + "version": "2.103.0", + "resolved": "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-2.103.0.tgz", + "integrity": "sha512-gcPtXzZ6izyyBVf2of7K3dEt8CScPJn8VcSlQq6oWL9QoE1kqfQl0oFrOMHd5qrcADewxI7OxxosLB8W4XqtIQ==", + "license": "MIT", + "dependencies": { + "@supabase/phoenix": "^0.4.0", + "@types/ws": "^8.18.1", + "tslib": "2.8.1", + "ws": "^8.18.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@supabase/ssr": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@supabase/ssr/-/ssr-0.10.2.tgz", + "integrity": "sha512-JFbchN63CXLFHJRNT7udec4/RoD9PmXkSGko3QSO6vUuqGBtSzdmxR7FPfQNr7SuFd65I7Xv46q66ALjEN1cgQ==", + "license": "MIT", + "dependencies": { + "cookie": "^1.0.2" + }, + "peerDependencies": { + "@supabase/supabase-js": "^2.102.1" + } + }, + "node_modules/@supabase/storage-js": { + "version": "2.103.0", + "resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-2.103.0.tgz", + "integrity": "sha512-DHmlvdAXwtOmZNbkIZi4lkobPR3XjIzoOgzoz5duMf6G+sDeY015YrzMJCnqdccuYr7X5x4yYuSwF//RoN2dvQ==", + "license": "MIT", + "dependencies": { + "iceberg-js": "^0.8.1", + "tslib": "2.8.1" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@supabase/supabase-js": { + "version": "2.103.0", + "resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.103.0.tgz", + "integrity": "sha512-j/6q5+LtXbR/YOLSLhy7Na74RD1cV2v+KwIIuuqMEjk1JpLEEyu0ynwDHpGoxMncDQl+R5FogaVqZm+85lZvtw==", + "license": "MIT", + "dependencies": { + "@supabase/auth-js": "2.103.0", + "@supabase/functions-js": "2.103.0", + "@supabase/postgrest-js": "2.103.0", + "@supabase/realtime-js": "2.103.0", + "@supabase/storage-js": "2.103.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, "node_modules/@swc/helpers": { "version": "0.5.15", "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", @@ -1551,7 +1651,6 @@ "version": "20.19.39", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.39.tgz", "integrity": "sha512-orrrD74MBUyK8jOAD/r0+lfa1I2MO6I+vAkmAWzMYbCcgrN4lCrmK52gRFQq/JRxfYPfonkr4b0jcY7Olqdqbw==", - "dev": true, "license": "MIT", "dependencies": { "undici-types": "~6.21.0" @@ -1577,6 +1676,15 @@ "@types/react": "^19.2.0" } }, + "node_modules/@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "8.58.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.58.1.tgz", @@ -2720,6 +2828,19 @@ "dev": true, "license": "MIT" }, + "node_modules/cookie": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", + "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -4032,6 +4153,15 @@ "url": "https://github.com/sponsors/typicode" } }, + "node_modules/iceberg-js": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/iceberg-js/-/iceberg-js-0.8.1.tgz", + "integrity": "sha512-1dhVQZXhcHje7798IVM+xoo/1ZdVfzOMIc8/rgVSijRK38EDqOJoGula9N/8ZI5RD8QTxNQtK/Gozpr+qUqRRA==", + "license": "MIT", + "engines": { + "node": ">=20.0.0" + } + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -6731,7 +6861,6 @@ "version": "6.21.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "dev": true, "license": "MIT" }, "node_modules/unrs-resolver": { @@ -6981,6 +7110,27 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/ws": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz", + "integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", diff --git a/package.json b/package.json index 245bb7a..d981c2e 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,8 @@ "prepare": "husky" }, "dependencies": { + "@supabase/ssr": "^0.10.2", + "@supabase/supabase-js": "^2.103.0", "next": "16.2.3", "react": "19.2.4", "react-dom": "19.2.4" @@ -32,4 +34,4 @@ "eslint --fix" ] } -} \ No newline at end of file +} diff --git a/supabase/.gitignore b/supabase/.gitignore new file mode 100644 index 0000000..ad9264f --- /dev/null +++ b/supabase/.gitignore @@ -0,0 +1,8 @@ +# Supabase +.branches +.temp + +# dotenvx +.env.keys +.env.local +.env.*.local diff --git a/supabase/config.toml b/supabase/config.toml new file mode 100644 index 0000000..fd9841e --- /dev/null +++ b/supabase/config.toml @@ -0,0 +1,403 @@ +# For detailed configuration reference documentation, visit: +# https://supabase.com/docs/guides/local-development/cli/config +# A string used to distinguish different Supabase projects on the same host. Defaults to the +# working directory name when running `supabase init`. +project_id = "swale" + +[api] +enabled = true +# Port to use for the API URL. +port = 54321 +# Schemas to expose in your API. Tables, views and stored procedures in this schema will get API +# endpoints. `public` and `graphql_public` schemas are included by default. +schemas = ["public", "graphql_public"] +# Extra schemas to add to the search_path of every request. +extra_search_path = ["public", "extensions"] +# The maximum number of rows returns from a view, table, or stored procedure. Limits payload size +# for accidental or malicious requests. +max_rows = 1000 + +[api.tls] +# Enable HTTPS endpoints locally using a self-signed certificate. +enabled = false +# Paths to self-signed certificate pair. +# cert_path = "../certs/my-cert.pem" +# key_path = "../certs/my-key.pem" + +[db] +# Port to use for the local database URL. +port = 54322 +# Port used by db diff command to initialize the shadow database. +shadow_port = 54320 +# Maximum amount of time to wait for health check when starting the local database. +health_timeout = "2m" +# The database major version to use. This has to be the same as your remote database's. Run `SHOW +# server_version;` on the remote database to check. +major_version = 17 + +[db.pooler] +enabled = false +# Port to use for the local connection pooler. +port = 54329 +# Specifies when a server connection can be reused by other clients. +# Configure one of the supported pooler modes: `transaction`, `session`. +pool_mode = "transaction" +# How many server connections to allow per user/database pair. +default_pool_size = 20 +# Maximum number of client connections allowed. +max_client_conn = 100 + +# [db.vault] +# secret_key = "env(SECRET_VALUE)" + +[db.migrations] +# If disabled, migrations will be skipped during a db push or reset. +enabled = true +# Specifies an ordered list of schema files that describe your database. +# Supports glob patterns relative to supabase directory: "./schemas/*.sql" +schema_paths = [] + +[db.seed] +# If enabled, seeds the database after migrations during a db reset. +enabled = true +# Specifies an ordered list of seed files to load during db reset. +# Supports glob patterns relative to supabase directory: "./seeds/*.sql" +sql_paths = ["./seed.sql"] + +[db.network_restrictions] +# Enable management of network restrictions. +enabled = false +# List of IPv4 CIDR blocks allowed to connect to the database. +# Defaults to allow all IPv4 connections. Set empty array to block all IPs. +allowed_cidrs = ["0.0.0.0/0"] +# List of IPv6 CIDR blocks allowed to connect to the database. +# Defaults to allow all IPv6 connections. Set empty array to block all IPs. +allowed_cidrs_v6 = ["::/0"] + +# Uncomment to reject non-secure connections to the database. +# [db.ssl_enforcement] +# enabled = true + +[realtime] +enabled = true +# Bind realtime via either IPv4 or IPv6. (default: IPv4) +# ip_version = "IPv6" +# The maximum length in bytes of HTTP request headers. (default: 4096) +# max_header_length = 4096 + +[studio] +enabled = true +# Port to use for Supabase Studio. +port = 54323 +# External URL of the API server that frontend connects to. +api_url = "http://127.0.0.1" +# OpenAI API Key to use for Supabase AI in the Supabase Studio. +openai_api_key = "env(OPENAI_API_KEY)" + +# Email testing server. Emails sent with the local dev setup are not actually sent - rather, they +# are monitored, and you can view the emails that would have been sent from the web interface. +[inbucket] +enabled = true +# Port to use for the email testing server web interface. +port = 54324 +# Uncomment to expose additional ports for testing user applications that send emails. +# smtp_port = 54325 +# pop3_port = 54326 +# admin_email = "admin@email.com" +# sender_name = "Admin" + +[storage] +enabled = true +# The maximum file size allowed (e.g. "5MB", "500KB"). +file_size_limit = "50MiB" + +# Uncomment to configure local storage buckets +# [storage.buckets.images] +# public = false +# file_size_limit = "50MiB" +# allowed_mime_types = ["image/png", "image/jpeg"] +# objects_path = "./images" + +# Allow connections via S3 compatible clients +[storage.s3_protocol] +enabled = true + +# Image transformation API is available to Supabase Pro plan. +# [storage.image_transformation] +# enabled = true + +# Store analytical data in S3 for running ETL jobs over Iceberg Catalog +# This feature is only available on the hosted platform. +[storage.analytics] +enabled = false +max_namespaces = 5 +max_tables = 10 +max_catalogs = 2 + +# Analytics Buckets is available to Supabase Pro plan. +# [storage.analytics.buckets.my-warehouse] + +# Store vector embeddings in S3 for large and durable datasets +# This feature is only available on the hosted platform. +[storage.vector] +enabled = false +max_buckets = 10 +max_indexes = 5 + +# Vector Buckets is available to Supabase Pro plan. +# [storage.vector.buckets.documents-openai] + +[auth] +enabled = true +# The base URL of your website. Used as an allow-list for redirects and for constructing URLs used +# in emails. +site_url = "http://127.0.0.1:3000" +# A list of *exact* URLs that auth providers are permitted to redirect to post authentication. +additional_redirect_urls = ["https://127.0.0.1:3000"] +# How long tokens are valid for, in seconds. Defaults to 3600 (1 hour), maximum 604,800 (1 week). +jwt_expiry = 3600 +# JWT issuer URL. If not set, defaults to the local API URL (http://127.0.0.1:/auth/v1). +# jwt_issuer = "" +# Path to JWT signing key. DO NOT commit your signing keys file to git. +# signing_keys_path = "./signing_keys.json" +# If disabled, the refresh token will never expire. +enable_refresh_token_rotation = true +# Allows refresh tokens to be reused after expiry, up to the specified interval in seconds. +# Requires enable_refresh_token_rotation = true. +refresh_token_reuse_interval = 10 +# Allow/disallow new user signups to your project. +enable_signup = true +# Allow/disallow anonymous sign-ins to your project. +enable_anonymous_sign_ins = false +# Allow/disallow testing manual linking of accounts +enable_manual_linking = false +# Passwords shorter than this value will be rejected as weak. Minimum 6, recommended 8 or more. +minimum_password_length = 6 +# Passwords that do not meet the following requirements will be rejected as weak. Supported values +# are: `letters_digits`, `lower_upper_letters_digits`, `lower_upper_letters_digits_symbols` +password_requirements = "" + +# Configure passkey sign-ins. +# [auth.passkey] +# enabled = false +# rp_display_name = "Supabase" +# rp_id = "localhost" +# rp_origins = ["http://127.0.0.1:3000"] + +[auth.rate_limit] +# Number of emails that can be sent per hour. Requires auth.email.smtp to be enabled. +email_sent = 2 +# Number of SMS messages that can be sent per hour. Requires auth.sms to be enabled. +sms_sent = 30 +# Number of anonymous sign-ins that can be made per hour per IP address. Requires enable_anonymous_sign_ins = true. +anonymous_users = 30 +# Number of sessions that can be refreshed in a 5 minute interval per IP address. +token_refresh = 150 +# Number of sign up and sign-in requests that can be made in a 5 minute interval per IP address (excludes anonymous users). +sign_in_sign_ups = 30 +# Number of OTP / Magic link verifications that can be made in a 5 minute interval per IP address. +token_verifications = 30 +# Number of Web3 logins that can be made in a 5 minute interval per IP address. +web3 = 30 + +# Configure one of the supported captcha providers: `hcaptcha`, `turnstile`. +# [auth.captcha] +# enabled = true +# provider = "hcaptcha" +# secret = "" + +[auth.email] +# Allow/disallow new user signups via email to your project. +enable_signup = true +# If enabled, a user will be required to confirm any email change on both the old, and new email +# addresses. If disabled, only the new email is required to confirm. +double_confirm_changes = true +# If enabled, users need to confirm their email address before signing in. +enable_confirmations = false +# If enabled, users will need to reauthenticate or have logged in recently to change their password. +secure_password_change = false +# Controls the minimum amount of time that must pass before sending another signup confirmation or password reset email. +max_frequency = "1s" +# Number of characters used in the email OTP. +otp_length = 6 +# Number of seconds before the email OTP expires (defaults to 1 hour). +otp_expiry = 3600 + +# Use a production-ready SMTP server +# [auth.email.smtp] +# enabled = true +# host = "smtp.sendgrid.net" +# port = 587 +# user = "apikey" +# pass = "env(SENDGRID_API_KEY)" +# admin_email = "admin@email.com" +# sender_name = "Admin" + +# Uncomment to customize email template +# [auth.email.template.invite] +# subject = "You have been invited" +# content_path = "./supabase/templates/invite.html" + +# Uncomment to customize notification email template +# [auth.email.notification.password_changed] +# enabled = true +# subject = "Your password has been changed" +# content_path = "./templates/password_changed_notification.html" + +[auth.sms] +# Allow/disallow new user signups via SMS to your project. +enable_signup = false +# If enabled, users need to confirm their phone number before signing in. +enable_confirmations = false +# Template for sending OTP to users +template = "Your code is {{ .Code }}" +# Controls the minimum amount of time that must pass before sending another sms otp. +max_frequency = "5s" + +# Use pre-defined map of phone number to OTP for testing. +# [auth.sms.test_otp] +# 4152127777 = "123456" + +# Configure logged in session timeouts. +# [auth.sessions] +# Force log out after the specified duration. +# timebox = "24h" +# Force log out if the user has been inactive longer than the specified duration. +# inactivity_timeout = "8h" + +# This hook runs before a new user is created and allows developers to reject the request based on the incoming user object. +# [auth.hook.before_user_created] +# enabled = true +# uri = "pg-functions://postgres/auth/before-user-created-hook" + +# This hook runs before a token is issued and allows you to add additional claims based on the authentication method used. +# [auth.hook.custom_access_token] +# enabled = true +# uri = "pg-functions:////" + +# Configure one of the supported SMS providers: `twilio`, `twilio_verify`, `messagebird`, `textlocal`, `vonage`. +[auth.sms.twilio] +enabled = false +account_sid = "" +message_service_sid = "" +# DO NOT commit your Twilio auth token to git. Use environment variable substitution instead: +auth_token = "env(SUPABASE_AUTH_SMS_TWILIO_AUTH_TOKEN)" + +# Multi-factor-authentication is available to Supabase Pro plan. +[auth.mfa] +# Control how many MFA factors can be enrolled at once per user. +max_enrolled_factors = 10 + +# Control MFA via App Authenticator (TOTP) +[auth.mfa.totp] +enroll_enabled = false +verify_enabled = false + +# Configure MFA via Phone Messaging +[auth.mfa.phone] +enroll_enabled = false +verify_enabled = false +otp_length = 6 +template = "Your code is {{ .Code }}" +max_frequency = "5s" + +# Configure MFA via WebAuthn +# [auth.mfa.web_authn] +# enroll_enabled = true +# verify_enabled = true + +# Use an external OAuth provider. The full list of providers are: `apple`, `azure`, `bitbucket`, +# `discord`, `facebook`, `github`, `gitlab`, `google`, `keycloak`, `linkedin_oidc`, `notion`, `twitch`, +# `twitter`, `x`, `slack`, `spotify`, `workos`, `zoom`. +[auth.external.apple] +enabled = false +client_id = "" +# DO NOT commit your OAuth provider secret to git. Use environment variable substitution instead: +secret = "env(SUPABASE_AUTH_EXTERNAL_APPLE_SECRET)" +# Overrides the default auth redirectUrl. +redirect_uri = "" +# Overrides the default auth provider URL. Used to support self-hosted gitlab, single-tenant Azure, +# or any other third-party OIDC providers. +url = "" +# If enabled, the nonce check will be skipped. Required for local sign in with Google auth. +skip_nonce_check = false +# If enabled, it will allow the user to successfully authenticate when the provider does not return an email address. +email_optional = false + +# Allow Solana wallet holders to sign in to your project via the Sign in with Solana (SIWS, EIP-4361) standard. +# You can configure "web3" rate limit in the [auth.rate_limit] section and set up [auth.captcha] if self-hosting. +[auth.web3.solana] +enabled = false + +# Use Firebase Auth as a third-party provider alongside Supabase Auth. +[auth.third_party.firebase] +enabled = false +# project_id = "my-firebase-project" + +# Use Auth0 as a third-party provider alongside Supabase Auth. +[auth.third_party.auth0] +enabled = false +# tenant = "my-auth0-tenant" +# tenant_region = "us" + +# Use AWS Cognito (Amplify) as a third-party provider alongside Supabase Auth. +[auth.third_party.aws_cognito] +enabled = false +# user_pool_id = "my-user-pool-id" +# user_pool_region = "us-east-1" + +# Use Clerk as a third-party provider alongside Supabase Auth. +[auth.third_party.clerk] +enabled = false +# Obtain from https://clerk.com/setup/supabase +# domain = "example.clerk.accounts.dev" + +# OAuth server configuration +[auth.oauth_server] +# Enable OAuth server functionality +enabled = false +# Path for OAuth consent flow UI +authorization_url_path = "/oauth/consent" +# Allow dynamic client registration +allow_dynamic_registration = false + +[edge_runtime] +enabled = true +# Supported request policies: `oneshot`, `per_worker`. +# `per_worker` (default) — enables hot reload during local development. +# `oneshot` — fallback mode if hot reload causes issues (e.g. in large repos or with symlinks). +policy = "per_worker" +# Port to attach the Chrome inspector for debugging edge functions. +inspector_port = 8083 +# The Deno major version to use. +deno_version = 2 + +# [edge_runtime.secrets] +# secret_key = "env(SECRET_VALUE)" + +[analytics] +enabled = true +port = 54327 +# Configure one of the supported backends: `postgres`, `bigquery`. +backend = "postgres" + +# Experimental features may be deprecated any time +[experimental] +# Configures Postgres storage engine to use OrioleDB (S3) +orioledb_version = "" +# Configures S3 bucket URL, eg. .s3-.amazonaws.com +s3_host = "env(S3_HOST)" +# Configures S3 bucket region, eg. us-east-1 +s3_region = "env(S3_REGION)" +# Configures AWS_ACCESS_KEY_ID for S3 bucket +s3_access_key = "env(S3_ACCESS_KEY)" +# Configures AWS_SECRET_ACCESS_KEY for S3 bucket +s3_secret_key = "env(S3_SECRET_KEY)" + +# [experimental.pgdelta] +# When enabled, pg-delta becomes the active engine for supported schema flows. +# enabled = false +# Directory under `supabase/` where declarative files are written. +# declarative_schema_path = "./database" +# JSON string passed through to pg-delta SQL formatting. +# format_options = "{\"keywordCase\":\"upper\",\"indent\":2,\"maxWidth\":80,\"commaStyle\":\"trailing\"}" From 3a92832b1cb3e9ae619a5bf1c79717639010a016 Mon Sep 17 00:00:00 2001 From: Ori Marx Date: Mon, 20 Apr 2026 13:18:14 -0400 Subject: [PATCH 02/11] supabase middleware setup --- src/middleware.ts | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 src/middleware.ts diff --git a/src/middleware.ts b/src/middleware.ts new file mode 100644 index 0000000..3695b51 --- /dev/null +++ b/src/middleware.ts @@ -0,0 +1,43 @@ +import { createServerClient } from "@supabase/ssr"; +import { NextResponse, type NextRequest } from "next/server"; + +export async function middleware(request: NextRequest) { + const supabaseResponse = NextResponse.next({ + request, + }); + + const supabase = createServerClient( + process.env.NEXT_PUBLIC_SUPABASE_URL!, + process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, + { + cookies: { + getAll() { + return request.cookies.getAll(); + }, + setAll(cookiesToSet) { + cookiesToSet.forEach(({ name, value, options }) => { + supabaseResponse.cookies.set(name, value, options); + }); + }, + }, + } + ); + + // Check session + await supabase.auth.getUser(); + + return supabaseResponse; +} + +export const config = { + matcher: [ + /* + * Match all request paths except for the ones starting with: + * - _next/static (static files) + * - _next/image (image optimization files) + * - favicon.ico (favicon file) + * - public folder + */ + "/((?!_next/static|_next/image|favicon.ico|.*\\.svg).*)", + ], +}; From 0e1a15dd8fe523f57536be8e3d954167669928ba Mon Sep 17 00:00:00 2001 From: Ori Marx Date: Mon, 20 Apr 2026 13:18:33 -0400 Subject: [PATCH 03/11] login/signup mock routes (for testing) --- src/app/api/auth/login/route.ts | 25 +++++++++++++++++++++++++ src/app/api/auth/signup/route.ts | 25 +++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 src/app/api/auth/login/route.ts create mode 100644 src/app/api/auth/signup/route.ts diff --git a/src/app/api/auth/login/route.ts b/src/app/api/auth/login/route.ts new file mode 100644 index 0000000..ac48c58 --- /dev/null +++ b/src/app/api/auth/login/route.ts @@ -0,0 +1,25 @@ +import { createServerSupabaseClient } from "@/lib/supabase/server"; +import { NextRequest, NextResponse } from "next/server"; + +export async function POST(request: NextRequest) { + try { + const { email, password } = await request.json(); + const supabase = await createServerSupabaseClient(); + + const { data, error } = await supabase.auth.signInWithPassword({ + email, + password, + }); + + if (error) { + return NextResponse.json({ error: error.message }, { status: 400 }); + } + + return NextResponse.json(data); + } catch (error) { + return NextResponse.json( + { error: "Internal server error" }, + { status: 500 } + ); + } +} diff --git a/src/app/api/auth/signup/route.ts b/src/app/api/auth/signup/route.ts new file mode 100644 index 0000000..460db39 --- /dev/null +++ b/src/app/api/auth/signup/route.ts @@ -0,0 +1,25 @@ +import { createServerSupabaseClient } from "@/lib/supabase/server"; +import { NextRequest, NextResponse } from "next/server"; + +export async function POST(request: NextRequest) { + try { + const { email, password } = await request.json(); + const supabase = await createServerSupabaseClient(); + + const { data, error } = await supabase.auth.signUp({ + email, + password, + }); + + if (error) { + return NextResponse.json({ error: error.message }, { status: 400 }); + } + + return NextResponse.json(data); + } catch (error) { + return NextResponse.json( + { error: "Internal server error" }, + { status: 500 } + ); + } +} From 0f35e94ae9cd259ed336d03c7b12a9cd67aa30ce Mon Sep 17 00:00:00 2001 From: Ori Marx Date: Mon, 20 Apr 2026 13:18:57 -0400 Subject: [PATCH 04/11] temp useAuth --- src/lib/hooks/useAuth.ts | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 src/lib/hooks/useAuth.ts diff --git a/src/lib/hooks/useAuth.ts b/src/lib/hooks/useAuth.ts new file mode 100644 index 0000000..cfb1078 --- /dev/null +++ b/src/lib/hooks/useAuth.ts @@ -0,0 +1,30 @@ +"use client"; + +import { createClient } from "@/lib/supabase/client"; +import { useEffect, useState } from "react"; +import type { Session } from "@supabase/supabase-js"; + +export function useAuth() { + const [session, setSession] = useState(null); + const [loading, setLoading] = useState(true); + const supabase = createClient(); + + useEffect(() => { + // Check active sessions and sets the user + supabase.auth.getSession().then(({ data: { session } }) => { + setSession(session); + setLoading(false); + }); + + // Listen for changes on auth state (logged in, signed out, etc.) + const { + data: { subscription }, + } = supabase.auth.onAuthStateChange((_event, session) => { + setSession(session); + }); + + return () => subscription?.unsubscribe(); + }, [supabase.auth]); + + return { session, loading }; +} From ed4107a191c91244f8490498bb2802d40bb6a280 Mon Sep 17 00:00:00 2001 From: Ori Marx Date: Mon, 20 Apr 2026 13:19:29 -0400 Subject: [PATCH 05/11] supabase-client interaction handling --- src/lib/supabase/client.ts | 8 ++++++++ src/lib/supabase/server.ts | 30 ++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 src/lib/supabase/client.ts create mode 100644 src/lib/supabase/server.ts diff --git a/src/lib/supabase/client.ts b/src/lib/supabase/client.ts new file mode 100644 index 0000000..9f2891b --- /dev/null +++ b/src/lib/supabase/client.ts @@ -0,0 +1,8 @@ +import { createBrowserClient } from "@supabase/ssr"; + +export function createClient() { + return createBrowserClient( + process.env.NEXT_PUBLIC_SUPABASE_URL!, + process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY! + ); +} diff --git a/src/lib/supabase/server.ts b/src/lib/supabase/server.ts new file mode 100644 index 0000000..b0827ca --- /dev/null +++ b/src/lib/supabase/server.ts @@ -0,0 +1,30 @@ +import { createServerClient } from "@supabase/ssr"; +import { cookies } from "next/headers"; + +export async function createServerSupabaseClient() { + const cookieStore = await cookies(); + + return createServerClient( + process.env.NEXT_PUBLIC_SUPABASE_URL!, + process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, + { + cookies: { + getAll() { + return cookieStore.getAll(); + }, + setAll(cookiesToSet) { + try { + cookiesToSet.forEach(({ name, value, options }) => + cookieStore.set(name, value, options) + ); + } catch { + // The `setAll` method was called from a Server Component. + // This can be ignored if you have middleware or Edge Routes that + // will handle the set-cookie header. If this gets logged to help + // you debug, you can ignore it. + } + }, + }, + } + ); +} From 51fd0e14d57a7b37e39367bb3cd44b5667212880 Mon Sep 17 00:00:00 2001 From: Ori M <155787690+orimcoding@users.noreply.github.com> Date: Mon, 20 Apr 2026 13:31:55 -0400 Subject: [PATCH 06/11] Update src/app/api/auth/login/route.ts CodeRabbit suggestion Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- src/app/api/auth/login/route.ts | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/src/app/api/auth/login/route.ts b/src/app/api/auth/login/route.ts index ac48c58..5537383 100644 --- a/src/app/api/auth/login/route.ts +++ b/src/app/api/auth/login/route.ts @@ -3,7 +3,29 @@ import { NextRequest, NextResponse } from "next/server"; export async function POST(request: NextRequest) { try { - const { email, password } = await request.json(); + let body: unknown; + try { + body = await request.json(); + } catch { + return NextResponse.json({ error: "Invalid JSON body" }, { status: 400 }); + } + + const { email, password } = body as { + email?: unknown; + password?: unknown; + }; + if ( + typeof email !== "string" || + typeof password !== "string" || + !email || + !password + ) { + return NextResponse.json( + { error: "Email and password are required" }, + { status: 400 } + ); + } + const supabase = await createServerSupabaseClient(); const { data, error } = await supabase.auth.signInWithPassword({ @@ -16,10 +38,11 @@ export async function POST(request: NextRequest) { } return NextResponse.json(data); - } catch (error) { + } catch { return NextResponse.json( { error: "Internal server error" }, { status: 500 } ); } + } } From 0b6d13b5014103d6d03c76890e2099f2aa47f9fe Mon Sep 17 00:00:00 2001 From: Ori Marx Date: Mon, 20 Apr 2026 13:33:02 -0400 Subject: [PATCH 07/11] proper input validation (CodeRabbit suggestion) --- src/app/api/auth/signup/route.ts | 56 ++++++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/src/app/api/auth/signup/route.ts b/src/app/api/auth/signup/route.ts index 460db39..4953378 100644 --- a/src/app/api/auth/signup/route.ts +++ b/src/app/api/auth/signup/route.ts @@ -3,11 +3,63 @@ import { NextRequest, NextResponse } from "next/server"; export async function POST(request: NextRequest) { try { - const { email, password } = await request.json(); + // Parse request body + let body: unknown; + try { + body = await request.json(); + } catch { + return NextResponse.json( + { error: "Invalid JSON request" }, + { status: 400 } + ); + } + + // Validate body is an object + if (!body || typeof body !== "object") { + return NextResponse.json( + { error: "Invalid request body" }, + { status: 400 } + ); + } + + const { email, password } = body as Record; + + // Validate email and password exist and are strings + if (typeof email !== "string" || email.trim().length === 0) { + return NextResponse.json( + { error: "Email is required and must be a string" }, + { status: 400 } + ); + } + + if (typeof password !== "string" || password.length === 0) { + return NextResponse.json( + { error: "Password is required and must be a string" }, + { status: 400 } + ); + } + + // Validate email format + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + if (!emailRegex.test(email)) { + return NextResponse.json( + { error: "Invalid email format" }, + { status: 400 } + ); + } + + // Validate password length + if (password.length < 8) { + return NextResponse.json( + { error: "Password must be at least 8 characters" }, + { status: 400 } + ); + } + const supabase = await createServerSupabaseClient(); const { data, error } = await supabase.auth.signUp({ - email, + email: email.trim(), password, }); From b93d06f4c6f6b7655a1f17ffced4a26dff692475 Mon Sep 17 00:00:00 2001 From: Ori Marx Date: Mon, 20 Apr 2026 13:34:40 -0400 Subject: [PATCH 08/11] client instance stabilization --- src/lib/hooks/useAuth.ts | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/lib/hooks/useAuth.ts b/src/lib/hooks/useAuth.ts index cfb1078..bea1c61 100644 --- a/src/lib/hooks/useAuth.ts +++ b/src/lib/hooks/useAuth.ts @@ -1,20 +1,17 @@ "use client"; import { createClient } from "@/lib/supabase/client"; -import { useEffect, useState } from "react"; +import { useEffect, useMemo, useState } from "react"; import type { Session } from "@supabase/supabase-js"; export function useAuth() { const [session, setSession] = useState(null); const [loading, setLoading] = useState(true); - const supabase = createClient(); + const supabase = useMemo(() => createClient(), []); useEffect(() => { // Check active sessions and sets the user - supabase.auth.getSession().then(({ data: { session } }) => { - setSession(session); - setLoading(false); - }); + supabase.auth.getSession().then(({ data: { session } }) => setSession(session)).finally(() => setLoading(false)); // Listen for changes on auth state (logged in, signed out, etc.) const { @@ -24,7 +21,7 @@ export function useAuth() { }); return () => subscription?.unsubscribe(); - }, [supabase.auth]); + }, [supabase]); return { session, loading }; } From c6c0f2504789e6d13d14c9cf825a15167a9877a0 Mon Sep 17 00:00:00 2001 From: Ori M <155787690+orimcoding@users.noreply.github.com> Date: Mon, 20 Apr 2026 13:38:57 -0400 Subject: [PATCH 09/11] Update src/middleware.ts middleware error handling Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- src/middleware.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/middleware.ts b/src/middleware.ts index 3695b51..5102fde 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -24,7 +24,11 @@ export async function middleware(request: NextRequest) { ); // Check session - await supabase.auth.getUser(); + try { + await supabase.auth.getUser(); + } catch { + return supabaseResponse; + } return supabaseResponse; } From f5a2b774201787d14b4186326d24b7b00ef09120 Mon Sep 17 00:00:00 2001 From: Ori Marx Date: Mon, 20 Apr 2026 13:39:42 -0400 Subject: [PATCH 10/11] removed potential ReDoS regex cause --- src/app/api/auth/signup/route.ts | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/app/api/auth/signup/route.ts b/src/app/api/auth/signup/route.ts index 4953378..bf64bf7 100644 --- a/src/app/api/auth/signup/route.ts +++ b/src/app/api/auth/signup/route.ts @@ -39,9 +39,16 @@ export async function POST(request: NextRequest) { ); } - // Validate email format - const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; - if (!emailRegex.test(email)) { + // Validate email format - simple check, Supabase will do deeper validation + const trimmedEmail = email.trim(); + if (!trimmedEmail.includes("@") || !trimmedEmail.includes(".")) { + return NextResponse.json( + { error: "Invalid email format" }, + { status: 400 } + ); + } + const [localPart, domain] = trimmedEmail.split("@"); + if (!localPart || !domain || localPart.length === 0 || domain.length < 3) { return NextResponse.json( { error: "Invalid email format" }, { status: 400 } From 85d38bfadf5a2d2892099d4b85221e2c5bde963e Mon Sep 17 00:00:00 2001 From: Ori Marx Date: Mon, 20 Apr 2026 13:41:48 -0400 Subject: [PATCH 11/11] lint fixes --- src/app/api/auth/login/route.ts | 1 - src/app/api/auth/signup/route.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/app/api/auth/login/route.ts b/src/app/api/auth/login/route.ts index 5537383..38045a0 100644 --- a/src/app/api/auth/login/route.ts +++ b/src/app/api/auth/login/route.ts @@ -44,5 +44,4 @@ export async function POST(request: NextRequest) { { status: 500 } ); } - } } diff --git a/src/app/api/auth/signup/route.ts b/src/app/api/auth/signup/route.ts index bf64bf7..f6ece3e 100644 --- a/src/app/api/auth/signup/route.ts +++ b/src/app/api/auth/signup/route.ts @@ -75,7 +75,7 @@ export async function POST(request: NextRequest) { } return NextResponse.json(data); - } catch (error) { + } catch { return NextResponse.json( { error: "Internal server error" }, { status: 500 }