Skip to content

Conversation

@softmarshmallow
Copy link
Member

@softmarshmallow softmarshmallow commented Apr 1, 2025

Allow user to customize default www name

day-221-grida-sites-claim-grida-site-domain.mp4

Summary by CodeRabbit

  • New Features

    • Added domain name management to site settings, allowing users to check availability and change their site's domain name with instant feedback and validation.
    • Introduced a user interface for editing and updating domain names, including dialog-based editing and error handling.
    • Domains now follow stricter naming rules and are automatically assigned if not provided.
  • Integration

    • Added integration with Vercel for domain verification.
  • Database

    • Enhanced validation and assignment of domain names, including new functions for checking and changing domain names and stricter constraints on domain name format.
  • Chores

    • Updated environment variable documentation and added the Vercel SDK dependency.

@codesandbox
Copy link

codesandbox bot commented Apr 1, 2025

Review or Edit in CodeSandbox

Open the branch in Web EditorVS CodeInsiders

Open Preview

@vercel
Copy link

vercel bot commented Apr 1, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
backgrounds ✅ Ready (Inspect) Visit Preview 💬 Add feedback Apr 18, 2025 6:51am
blog ✅ Ready (Inspect) Visit Preview 💬 Add feedback Apr 18, 2025 6:51am
docs ✅ Ready (Inspect) Visit Preview 💬 Add feedback Apr 18, 2025 6:51am
grida ✅ Ready (Inspect) Visit Preview 💬 Add feedback Apr 18, 2025 6:51am
legacy-www ✅ Ready (Inspect) Visit Preview 💬 Add feedback Apr 18, 2025 6:51am
viewer ✅ Ready (Inspect) Visit Preview 💬 Add feedback Apr 18, 2025 6:51am
3 Skipped Deployments
Name Status Preview Comments Updated (UTC)
code ⬜️ Ignored (Inspect) Apr 18, 2025 6:51am
legacy ⬜️ Ignored (Inspect) Apr 18, 2025 6:51am
sites ⬜️ Ignored (Inspect) Visit Preview Apr 18, 2025 6:51am

@coderabbitai
Copy link

coderabbitai bot commented Apr 1, 2025

Walkthrough

This update introduces domain name management for web projects, including backend, frontend, and database changes. The frontend now allows users to view and update their site's domain name, checking availability and applying changes via new RPC calls. The backend integrates with the Vercel SDK for domain verification, exposing a new API route for this purpose. The database schema is updated to enforce stricter domain name constraints, automate random name assignment, and provide functions for checking and changing domain names. New environment variables and dependencies are added to support Vercel integration and these new features.

Changes

File(s) Change Summary
editor/.env.example, editor/package.json Added Vercel integration environment variables and the @vercel/sdk dependency.
editor/clients/vercel/index.ts New Vercel client module for domain verification, reading credentials from environment variables.
editor/app/(api)/private/domains/[domain]/verify/route.ts Added new API route for verifying domains via Vercel SDK.
editor/database-generated.types.ts Added function declarations for checking, changing, and generating www names in the database types.
editor/app/(workbench)/[org]/[proj]/(console)/(resources)/www/page.tsx Added domain management UI: callbacks for checking/changing domain, new form component, and integration into settings page.
editor/app/(workbench)/[org]/[proj]/(console)/(resources)/www/section-domain.tsx Added new SiteDomainsSection component and internal dialog for editing domain names with validation and feedback.
supabase/schemas/grida_www.sql, supabase/migrations/20250418050733_www_name.sql Introduced www_name domain, stricter constraints, random name assignment, triggers, and functions for checking/changing names.
supabase/migrations/20250418063117_www_name_drop_default.sql Removed default value from grida_www.www.name column.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant ProjectWWWSettingsPage
    participant FormSiteDomain
    participant SiteDomainsSection
    participant BackendAPI
    participant Database

    User->>ProjectWWWSettingsPage: Open site settings
    ProjectWWWSettingsPage->>FormSiteDomain: Render with current domain
    FormSiteDomain->>SiteDomainsSection: Pass domain and callbacks

    User->>SiteDomainsSection: Click edit, enter new domain, click save
    SiteDomainsSection->>FormSiteDomain: onSubmit(newDomain)
    FormSiteDomain->>BackendAPI: check_www_name_available(newDomain)
    BackendAPI->>Database: Run check_www_name_available
    Database-->>BackendAPI: Return availability
    BackendAPI-->>FormSiteDomain: Return boolean

    alt Domain available
        FormSiteDomain->>BackendAPI: change_www_name(newDomain)
        BackendAPI->>Database: Run change_www_name
        Database-->>BackendAPI: Update and confirm
        BackendAPI-->>FormSiteDomain: Success
        FormSiteDomain->>SiteDomainsSection: Show success, update UI
    else Domain unavailable
        FormSiteDomain->>SiteDomainsSection: Show error
    end
Loading
sequenceDiagram
    participant APIClient
    participant VercelClient
    participant VercelAPI

    APIClient->>VercelClient: projectsVerifyProjectDomain(domain)
    VercelClient->>VercelAPI: Verify domain with credentials
    VercelAPI-->>VercelClient: Verification result
    VercelClient-->>APIClient: Return result
Loading

Poem

🐇
In fields of code, a new domain blooms,
With checks and triggers, it brightly resumes.
From settings to Vercel, the journey is clear,
A name for your site—unique and sincere.
With forms and toasts, the UI delights,
Hopping through schemas and API flights.
Oh, what a warren of features tonight!

Tip

⚡💬 Agentic Chat (Pro Plan, General Availability)
  • We're introducing multi-step agentic chat in review comments and issue comments, within and outside of PR's. This feature enhances review and issue discussions with the CodeRabbit agentic chat by enabling advanced interactions, including the ability to create pull requests directly from comments and add commits to existing pull requests.
✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

♻️ Duplicate comments (4)
supabase/migrations/20250418050733_www_name.sql (1)

86-94: Duplicate of domain-pattern mismatch already flagged.

The availability regex {2,32} is misaligned with the domain’s constraints. See first comment for the unified pattern.

supabase/schemas/grida_www.sql (3)

30-37: Duplicate domain‐constraint mismatch.

The grida_www.www_name definition here uses the same loose pattern as the migration. Align it with the revised pattern from the migration review.


43-58: Same gen_random_www_name logic appears here—apply the truncation and collision‐retry refactor.


218-225: Availability regex mismatch mirrored here.

Ensure check_www_name_available uses the same pattern bounds as the domain.

🧹 Nitpick comments (12)
editor/.env.example (1)

31-38: Ensure .env.example placeholders and security boundaries are clear.

  • The new VERCEL_* variables are correctly added for Vercel integration.
  • Recommend using descriptive placeholders (e.g. <YOUR_TOKEN>) instead of empty strings to guide users.
  • Remind users that VERCEL_AUTH_BEARER_TOKEN should remain server‐side (not exposed in client bundles) and be stored in .env.local, not committed.
supabase/migrations/20250418050733_www_name.sql (1)

32-38: Optional: retry on duplicate random names.

Right now, if gen_random_www_name produces an existing name, the insert will error. For better UX, consider wrapping generation in a loop that retries when a collision occurs.

supabase/schemas/grida_www.sql (2)

64-70: Assign trigger logic is fine; consider collision handling.


98-99: Consider idempotent trigger creation.

Add a DROP TRIGGER IF EXISTS set_www_name ON grida_www.www; before this to avoid errors on repeated deployments.

editor/app/(api)/private/domains/[domain]/verify/route.ts (1)

5-5: Remove or implement commented code

This commented line suggests you intended to extract JSON from the request body but didn't implement it.

Either implement this functionality if needed or remove the commented line to keep the codebase clean.

editor/clients/vercel/index.ts (2)

13-17: Decide on commented out functionality

This commented-out function suggests incomplete implementation for domain deletion functionality.

Either complete and enable this functionality if needed for future use, or remove it to avoid confusion.


19-24: Add JSDoc documentation

The exported function lacks documentation which would help other developers understand its purpose and usage.

Consider adding JSDoc comments:

+/**
+ * Verifies a domain with Vercel for the configured project
+ * @param domain - The domain to verify
+ * @returns Promise with verification result from Vercel API
+ */
export const projectsVerifyProjectDomain = (domain: string) =>
  _projectsVerifyProjectDomain(__vercel_core, {
    teamId: VERCEL_TEAM_ID,
    idOrName: VERCEL_PROJECT_ID,
    domain,
  });
editor/app/(workbench)/[org]/[proj]/(console)/(resources)/www/section-domain.tsx (3)

83-86: Provide more specific error messages

The error message combines two distinct error cases: "already taken" and "not allowed". This makes it harder for users to understand the specific issue.

Consider distinguishing these cases in the backend and providing more specific error messages based on the actual error case:

- setError(
-   "This domain is either already taken or not allowed. Please try a different name using only letters, numbers, or dashes."
- );
+ // Example of more specific error handling
+ if (!ok) {
+   // Assuming onSubmit could return different error types
+   if (error === "TAKEN") {
+     setError("This domain is already taken. Please try a different name.");
+   } else if (error === "INVALID_FORMAT") {
+     setError("Domain names can only contain lowercase letters, numbers, or dashes.");
+   } else {
+     setError("Failed to update domain. Please try again.");
+   }
+ }

75-87: Improve error handling in form submission

The current implementation doesn't distinguish between different types of errors and doesn't handle network failures.

Add proper try/catch and more detailed error handling:

const onSubmitHandler = async () => {
  setBusy(true);
+ try {
    const ok = await onSubmit(name);
-   setBusy(false);
    if (ok) {
      toast.success("Domain name updated successfully");
      props.onOpenChange?.(false);
    } else {
      setError(
        "This domain is either already taken or not allowed. Please try a different name using only letters, numbers, or dashes."
      );
    }
+ } catch (error) {
+   console.error("Error updating domain:", error);
+   setError("Failed to update domain due to a network error. Please try again.");
+ } finally {
+   setBusy(false);
+ }
};

102-126: Improve form accessibility

The current implementation lacks proper form semantics and accessibility enhancements.

Consider these improvements:

  1. Wrap the form fields in a <form> element
  2. Add proper labels with htmlFor attributes
  3. Add aria-invalid attributes for error states
  4. Auto-focus the input field when the dialog opens
- <div className="py-4 flex flex-col gap-2">
+ <form
+   className="py-4 flex flex-col gap-2"
+   onSubmit={(e) => {
+     e.preventDefault();
+     onSubmitHandler();
+   }}
+ >
+   <label htmlFor="domain-name" className="text-sm font-medium">Domain Name</label>
    <div className="flex h-9 items-center border rounded-md px-3 py-1 focus-within:ring-2 focus-within:ring-ring focus-within:ring-offset-2 bg-muted">
      <Input
+       id="domain-name"
+       autoFocus
+       aria-invalid={!!error}
        className="border-none bg-transparent focus-visible:ring-0 focus-visible:ring-offset-0 px-0 shadow-none"
        placeholder="your-domain"
        disabled={busy}
        value={name}
        onChange={(e) => {
          setName(e.target.value);
          setError(null);
        }}
      />
      <span className="ml-2 text-muted-foreground text-sm">
        .grida.site
      </span>
    </div>
    <p
+     id="domain-name-error"
+     aria-live="polite"
      data-error={!!error}
      className="text-xs text-muted-foreground data-[error=true]:text-destructive"
    >
      {error
        ? error
        : "lowercase letters, numbers, and dashes are allowed"}
    </p>
- </div>
+ </form>
editor/app/(workbench)/[org]/[proj]/(console)/(resources)/www/page.tsx (2)

82-96: Consider adding more detailed error handling.

The changeDomainName function correctly validates data existence, calls the RPC function, and refreshes the UI through SWR cache invalidation. However, the error handling is minimal - it only returns false when an error occurs.

Consider enhancing error handling to provide more specific feedback:

- const { error } = await client.rpc("change_www_name", {
+ const { data: result, error } = await client.rpc("change_www_name", {
  p_www_id: data.id,
  p_name: name,
});

- if (error) return false;
+ if (error) {
+   console.error("Failed to change domain name:", error.message);
+   return false;
+ }

303-331: Consider adding loading state and error feedback to the domain form.

The FormSiteDomain component correctly implements the domain management functionality, but unlike the FormSiteGeneral component (lines 252-301), it doesn't provide visual feedback during the domain change operation or display error messages.

Consider enhancing the user experience by adding:

  1. Loading indicators during the availability check and domain change
  2. Error messages when operations fail
  3. Success confirmation when the operation completes
function FormSiteDomain({
  defaultValues,
  changeDomainName,
  checkDomainName,
}: {
  checkDomainName: (name: string) => Promise<boolean>;
  changeDomainName: (name: string) => Promise<boolean>;
  defaultValues: {
    name: string;
  };
}) {
+  const [isLoading, setIsLoading] = useState(false);
+  const [errorMessage, setErrorMessage] = useState<string | null>(null);
+  const [successMessage, setSuccessMessage] = useState<string | null>(null);

  return (
    <Card>
      <CardHeader>
        <CardTitle>Domains</CardTitle>
      </CardHeader>
      <CardContent className="space-y-6">
+       {errorMessage && <div className="text-red-500 mb-2">{errorMessage}</div>}
+       {successMessage && <div className="text-green-500 mb-2">{successMessage}</div>}
        <SiteDomainsSection
          onDomainNameChange={async (name) => {
+           setIsLoading(true);
+           setErrorMessage(null);
+           setSuccessMessage(null);
+           
            const available = await checkDomainName(name);
-           if (!available) return false;
-           return await changeDomainName(name);
+           if (!available) {
+             setErrorMessage(`Domain name "${name}" is not available.`);
+             setIsLoading(false);
+             return false;
+           }
+           
+           const success = await changeDomainName(name);
+           setIsLoading(false);
+           if (success) {
+             setSuccessMessage("Domain name updated successfully!");
+           } else {
+             setErrorMessage("Failed to update domain name. Please try again.");
+           }
+           return success;
          }}
          name={defaultValues.name}
+         isLoading={isLoading}
        />
      </CardContent>
    </Card>
  );
}

Note: You would need to import useState from React and update the SiteDomainsSection component to handle the isLoading prop.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0a6bc5a and f0bc9c7.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (10)
  • editor/.env.example (1 hunks)
  • editor/app/(api)/private/domains/[domain]/verify/route.ts (1 hunks)
  • editor/app/(workbench)/[org]/[proj]/(console)/(resources)/www/page.tsx (6 hunks)
  • editor/app/(workbench)/[org]/[proj]/(console)/(resources)/www/section-domain.tsx (1 hunks)
  • editor/clients/vercel/index.ts (1 hunks)
  • editor/database-generated.types.ts (1 hunks)
  • editor/package.json (1 hunks)
  • supabase/migrations/20250418050733_www_name.sql (1 hunks)
  • supabase/migrations/20250418063117_www_name_drop_default.sql (1 hunks)
  • supabase/schemas/grida_www.sql (3 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
editor/app/(api)/private/domains/[domain]/verify/route.ts (1)
editor/clients/vercel/index.ts (1)
  • projectsVerifyProjectDomain (19-24)
🔇 Additional comments (12)
supabase/migrations/20250418050733_www_name.sql (2)

56-82: Views re-created correctly after schema change.

The drop/create sequence ensures no broken dependencies. The column selection remains unchanged.


99-117: Change function enforces RLS and availability correctly.

The implementation properly checks ownership (rls_www), name validity, and updates the table. Nothing to refactor here.

supabase/schemas/grida_www.sql (2)

80-80: Domain‐typed column added correctly.


231-249: Change‐name RPC remains correct.

supabase/migrations/20250418063117_www_name_drop_default.sql (1)

1-2: Dropping the old default is straightforward.

editor/package.json (1)

97-97: New dependency looks correct.

@vercel/sdk@^1.5.0 is added to support Vercel integration. Verify this version meets your compatibility and security requirements.

editor/database-generated.types.ts (1)

3202-3213: New domain management functions look good

The type definitions for the new domain management functions are correctly defined, providing a type-safe interface for domain name operations.

editor/app/(workbench)/[org]/[proj]/(console)/(resources)/www/page.tsx (5)

21-21: New import for domain management functionality.

The import of SiteDomainsSection from "./section-domain" supports the new domain management feature being added to this page.


67-80: Implementation of domain availability checker looks good.

This function makes an RPC call to check if a domain name is available, with appropriate error handling. It returns a boolean result which simplifies usage in the UI.


165-167: Properly exposing new domain management functions.

The hook correctly exposes the new domain name management functions alongside existing functions.


178-180: New domain management functions are properly destructured.

The component correctly destructures the new domain name management functions from the hook.


213-220: Good implementation of the new domain form in the page layout.

The FormSiteDomain component is properly integrated into the page layout with the right props.

Comment on lines +12 to +27
CREATE OR REPLACE FUNCTION grida_www.gen_random_www_name(p_project_id INTEGER)
RETURNS TEXT AS $$
DECLARE
org_name TEXT;
project_name TEXT;
suffix TEXT := encode(gen_random_bytes(2), 'hex');
BEGIN
SELECT o.name, p.name INTO org_name, project_name
FROM public.project p
JOIN public.organization o ON o.id = p.organization_id
WHERE p.id = p_project_id;

RETURN lower(regexp_replace(org_name, '[^a-zA-Z0-9]+', '', 'g')) || '-' ||
lower(regexp_replace(project_name, '[^a-zA-Z0-9]+', '', 'g')) || '-' || suffix;
END;
$$ LANGUAGE plpgsql STABLE;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Guard against over‑long random names and possible collisions.

  • The concatenation of full org/project names + suffix may exceed the 32‑char limit and cause migration failures.
  • A 2‑byte suffix (4 hex chars) yields ~65k possibilities; collisions are possible in high‑volume setups.

Consider truncating sanitized org_name/project_name segments to ensure the final string ≤32 chars, and loop on collision:

DECLARE
  max_base_len INT := 32 - length(suffix) - 2; -- 2 hyphens
  base TEXT := lower(regexp_replace(org_name, '[^a-zA-Z0-9]+', '', 'g'))
           || '-' || lower(regexp_replace(project_name, '[^a-zA-Z0-9]+', '', 'g'));
  truncated_base TEXT := substring(base from 1 for max_base_len);
BEGIN
  RETURN truncated_base || '-' || suffix;
END;

This keeps names within constraints and reduces collision risk.

Comment on lines +1 to +7
-- [www name type] --
---------------------------------------------------------------------
CREATE DOMAIN grida_www.www_name AS TEXT
CHECK (
length(VALUE) <= 32 AND
VALUE ~ '^[a-zA-Z0-9][a-zA-Z0-9\-]*$'
);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Align domain constraints with availability checks to avoid mismatches.

The grida_www.www_name domain currently allows names as short as 1 character and up to 32 (length(VALUE) <= 32), whereas the check_www_name_available function enforces a 3–32 character length (^[a-zA-Z0-9][a-zA-Z0-9\-]{2,32}$)—leading to inconsistent validation.

Proposed diff to unify both rules (3–32 alphanumeric/hyphen, starting with alphanumeric):

 CREATE DOMAIN grida_www.www_name AS TEXT
-CHECK (
-  length(VALUE) <= 32 AND
-  VALUE ~ '^[a-zA-Z0-9][a-zA-Z0-9\-]*$'
-);
+CHECK (
+  length(VALUE) BETWEEN 3 AND 32 AND
+  VALUE ~ '^[a-zA-Z0-9][a-zA-Z0-9\-]{2,31}$'
+);

This ensures domain and RPC validations remain consistent.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
-- [www name type] --
---------------------------------------------------------------------
CREATE DOMAIN grida_www.www_name AS TEXT
CHECK (
length(VALUE) <= 32 AND
VALUE ~ '^[a-zA-Z0-9][a-zA-Z0-9\-]*$'
);
-- [www name type] --
---------------------------------------------------------------------
CREATE DOMAIN grida_www.www_name AS TEXT
CHECK (
length(VALUE) BETWEEN 3 AND 32 AND
VALUE ~ '^[a-zA-Z0-9][a-zA-Z0-9\\-]{2,31}$'
);

Comment on lines +46 to +54
DROP VIEW IF EXISTS grida_www.www_public;
DROP VIEW IF EXISTS grida_www.public_route;

-- alter the column to use the new domain
ALTER TABLE grida_www.www ALTER COLUMN name TYPE grida_www.www_name USING name::TEXT;

-- add the trigger
CREATE TRIGGER set_www_name BEFORE INSERT ON grida_www.www FOR EACH ROW WHEN (NEW.name IS NULL) EXECUTE FUNCTION grida_www.assign_random_www_name();

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Verify existing data compatibility and drop stale triggers/views.

  • Altering name to grida_www.www_name will fail if existing values violate the new domain constraints. Ensure a data‑cleanup step precedes this migration.
  • You currently add the trigger without dropping any prior set_www_name trigger. Add:
    DROP TRIGGER IF EXISTS set_www_name ON grida_www.www;
    before creating the new trigger to prevent duplicate‑trigger errors.

Run this script to confirm all existing name values conform to the new regex:


🏁 Script executed:

#!/bin/bash
rg -e "^[a-zA-Z0-9][a-zA-Z0-9\\-]{2,31}$" --invert-match -U supabase/migrations/20250418050733_www_name.sql

Length of output: 3557


Ensure data cleanup and idempotent trigger creation

  • Before you alter the column to use the new grida_www.www_name domain, verify that no existing rows violate its CHECK constraint. For example, in psql run:

    SELECT id, name
    FROM grida_www.www
    WHERE name !~ '^[a-zA-Z0-9][a-zA-Z0-9-]{2,31}$';

    Fix or remove any rows returned so the migration won’t fail.

  • Prevent duplicate‑trigger errors by dropping the old trigger first. Add this immediately before your CREATE TRIGGER:

    DROP TRIGGER IF EXISTS set_www_name ON grida_www.www;

Comment on lines +4 to +12
export async function GET(req: NextRequest) {
// const reqjson = await req.json()
const r = await projectsVerifyProjectDomain("domain-name.com");
console.log(r);

return NextResponse.json(r, {
status: 200,
});
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Use dynamic route parameter instead of hardcoded domain

The route handler uses a hardcoded domain string "domain-name.com" instead of utilizing the dynamic route parameter [domain] available in the URL. This defeats the purpose of having a dynamic route.

- const r = await projectsVerifyProjectDomain("domain-name.com");
+ // Extract domain from route parameters
+ const domain = req.nextUrl.pathname.split('/').pop();
+ const r = await projectsVerifyProjectDomain(domain);

Additionally, there's no error handling for the API call to the Vercel SDK. Consider adding a try/catch block to handle potential failures.

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +5 to +7
const VERCEL_AUTH_BEARER_TOKEN = process.env.VERCEL_AUTH_BEARER_TOKEN || "";
const VERCEL_TEAM_ID = process.env.VERCEL_TEAM_ID || "";
const VERCEL_PROJECT_ID = process.env.VERCEL_PROJECT_ID || "";
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add validation for environment variables

The environment variables lack validation and default to empty strings, which could lead to silent failures when making API calls if they're not configured properly.

- const VERCEL_AUTH_BEARER_TOKEN = process.env.VERCEL_AUTH_BEARER_TOKEN || "";
- const VERCEL_TEAM_ID = process.env.VERCEL_TEAM_ID || "";
- const VERCEL_PROJECT_ID = process.env.VERCEL_PROJECT_ID || "";
+ const VERCEL_AUTH_BEARER_TOKEN = process.env.VERCEL_AUTH_BEARER_TOKEN;
+ const VERCEL_TEAM_ID = process.env.VERCEL_TEAM_ID;
+ const VERCEL_PROJECT_ID = process.env.VERCEL_PROJECT_ID;
+ 
+ if (!VERCEL_AUTH_BEARER_TOKEN || !VERCEL_TEAM_ID || !VERCEL_PROJECT_ID) {
+   console.error("Missing required Vercel environment variables");
+ }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const VERCEL_AUTH_BEARER_TOKEN = process.env.VERCEL_AUTH_BEARER_TOKEN || "";
const VERCEL_TEAM_ID = process.env.VERCEL_TEAM_ID || "";
const VERCEL_PROJECT_ID = process.env.VERCEL_PROJECT_ID || "";
const VERCEL_AUTH_BEARER_TOKEN = process.env.VERCEL_AUTH_BEARER_TOKEN;
const VERCEL_TEAM_ID = process.env.VERCEL_TEAM_ID;
const VERCEL_PROJECT_ID = process.env.VERCEL_PROJECT_ID;
if (!VERCEL_AUTH_BEARER_TOKEN || !VERCEL_TEAM_ID || !VERCEL_PROJECT_ID) {
console.error("Missing required Vercel environment variables");
}

Comment on lines +104 to +117
<Input
className="border-none bg-transparent focus-visible:ring-0 focus-visible:ring-offset-0 px-0 shadow-none"
placeholder="your-domain"
disabled={busy}
value={name}
onChange={(e) => {
setName(e.target.value);
setError(null);
}}
/>
<span className="ml-2 text-muted-foreground text-sm">
.grida.site
</span>
</div>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enforce input validation on domain name

The help text mentions restrictions (lowercase letters, numbers, and dashes), but there's no enforcement in the input field itself.

<Input
  className="border-none bg-transparent focus-visible:ring-0 focus-visible:ring-offset-0 px-0 shadow-none"
  placeholder="your-domain"
  disabled={busy}
  value={name}
+ pattern="^[a-z0-9-]+$"
  onChange={(e) => {
+   // Only allow lowercase letters, numbers, and dashes
+   const value = e.target.value.toLowerCase().replace(/[^a-z0-9-]/g, '');
-   setName(e.target.value);
+   setName(value);
    setError(null);
  }}
/>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<Input
className="border-none bg-transparent focus-visible:ring-0 focus-visible:ring-offset-0 px-0 shadow-none"
placeholder="your-domain"
disabled={busy}
value={name}
onChange={(e) => {
setName(e.target.value);
setError(null);
}}
/>
<span className="ml-2 text-muted-foreground text-sm">
.grida.site
</span>
</div>
<Input
className="border-none bg-transparent focus-visible:ring-0 focus-visible:ring-offset-0 px-0 shadow-none"
placeholder="your-domain"
disabled={busy}
value={name}
pattern="^[a-z0-9-]+$"
onChange={(e) => {
// Only allow lowercase letters, numbers, and dashes
const value = e.target.value.toLowerCase().replace(/[^a-z0-9-]/g, '');
setName(value);
setError(null);
}}
/>

@softmarshmallow softmarshmallow merged commit 3912402 into main Apr 18, 2025
8 of 12 checks passed
@softmarshmallow softmarshmallow changed the title [Multi-Tenancy] Custom domain [Multi-Tenancy] Claim your Custom Domain Apr 18, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant