Skip to content

Conversation

@marcrupt
Copy link
Collaborator

@marcrupt marcrupt commented Nov 17, 2025

Summary by CodeRabbit

  • New Features

    • Added copy-to-clipboard for inbox IDs with visual feedback.
    • Added key-secret display blocks with copy functionality to inbox cards.
    • Switched inbox creation from domain-based to email-based input.
  • Improvements

    • Enhanced responsive grid layout for inbox management across device sizes.
    • SDK version bumped to 0.4.0 with improved distribution configuration.

@marcrupt marcrupt requested a review from ahmedmawiri November 17, 2025 15:51
@vercel
Copy link

vercel bot commented Nov 17, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
sendook Ready Ready Preview Comment Nov 17, 2025 3:53pm
sendook-app Ready Ready Preview Comment Nov 17, 2025 3:53pm

@coderabbitai
Copy link

coderabbitai bot commented Nov 17, 2025

Walkthrough

The PR modifies inbox creation to accept email addresses instead of domain fields, adds a copy-to-clipboard feature for inbox IDs in the dashboard, updates SDK packaging configuration with entry points and exports, and introduces comprehensive TypeScript type definitions for the SendookAPI surface.

Changes

Cohort / File(s) Summary
API Inbox Creation Logic
api/routes/v1/inboxes/index.ts
Changed request body from domain field to email field; added email validation by extracting domain part; resolves domainId from extracted domain and organization; aborts with 400 on invalid email or 404 if domain not found; passes email to createInbox call.
Frontend Inbox Dashboard
app/app/pages/inboxes.vue
Added per-inbox copy-to-clipboard feature for inbox IDs with temporary "Copied" feedback state; introduced copiedInboxId ref and copyTimeout for state management; added copyInboxId method with clipboard API guards and error handling; cleanup on component unmount; adjusted inbox grid CSS to enforce 3-column layout with responsive breakpoints for smaller screens.
SDK Type Definitions
node-sdk/types/sendook-api.d.ts
Introduced comprehensive TypeScript interfaces for API parameters (CreateInboxParams, CreateApiKeyParams, CreateDomainParams, SendMessageParams, ReplyMessageParams, etc.) and public method groupings (ApiKeyMethods, DomainMethods, InboxMethods, MessageMethods, ThreadMethods).
SDK Configuration & Types
node-sdk/index.ts
Added explicit public type annotations for apiKey (ApiKeyMethods), domain (DomainMethods), and inbox (InboxMethods) properties without behavioral changes.
SDK Packaging
node-sdk/package.json
Version bump from 0.2.0 to 0.4.0; added distributable metadata with files set to ["dist"]; reconfigured entry points from source to compiled output (module, main, types); added conditional exports for ESM and CJS with type definitions.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant API as POST /inboxes
    participant Validator
    participant DomainResolver
    participant InboxService

    Client->>API: Request with email
    API->>Validator: Validate email format
    
    alt Invalid Email
        Validator-->>API: Validation error
        API-->>Client: 400 Bad Request
    else Valid Email
        Validator-->>API: Extract domain part
        API->>DomainResolver: Resolve domain by name + org
        
        alt Domain Not Found
            DomainResolver-->>API: Not found
            API-->>Client: 404 Not Found
        else Domain Found
            DomainResolver-->>API: Return domainId
            API->>InboxService: Create inbox (name, email, domainId)
            InboxService-->>API: Inbox created
            API-->>Client: 201 Created
        end
    end
Loading
sequenceDiagram
    participant User
    participant UI as Inbox Card
    participant Clipboard
    participant Component as State

    User->>UI: Click Copy button
    UI->>Component: copyInboxId(inbox)
    Component->>Clipboard: navigator.clipboard.writeText(inboxId)
    
    alt Copy Success
        Clipboard-->>Component: Resolved
        Component->>Component: Set copiedInboxId = inboxId
        Component->>UI: Update button to "Copied"
        Component->>Component: Schedule cleanup (2s)
        
        alt Timeout fires
            Component->>Component: Clear copiedInboxId
            Component->>UI: Revert button to "Copy"
        end
    else Copy Failed
        Clipboard-->>Component: Rejected
        Component->>Component: Log error
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Email validation and domain resolution logic: Review for proper error handling, edge cases (malformed emails, missing domains), and correct HTTP status codes.
  • Copy-to-clipboard implementation: Verify state management correctness, timeout cleanup on unmount, and clipboard API availability checks to prevent silent failures.
  • CSS grid responsiveness: Confirm breakpoint values and layout behavior across different screen sizes.
  • SDK type-to-implementation alignment: Ensure new type definitions in sendook-api.d.ts match actual method signatures and parameter shapes throughout the SDK.
  • Package.json export paths: Validate that conditional exports and entry points correctly map to compiled outputs.

Possibly related PRs

Suggested reviewers

  • ahmedmawiri

Poem

🐰 An email springs where domains dwelt,
Copy buttons softly felt,
Types precise, the SDK's dressed,
New paths for bundles, fully blessed!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Title check ⚠️ Warning The title is too vague and does not accurately reflect the scope of changes, which include API endpoint modifications, UI enhancements, and type definitions across multiple files beyond just npm types. Update the title to be more specific, such as 'Refactor inbox creation to use email instead of domain, add inbox ID copy feature, and add TypeScript type definitions' to better represent all major changes.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch marc/node-sdk-type-fixes

Comment @coderabbitai help to get the list of available commands and usage tips.

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: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/app/pages/inboxes.vue (1)

402-418: Remove the invalid max-width declaration

The fr unit is a flexible fraction (), not a length type, so it cannot be used inside calc() or combined with length/percentage values in calc() expressions. The line max-width: calc(3 * 1fr + 3 * 1.5rem); is invalid and browsers will ignore it. Remove it as suggested, or replace it with a concrete value like max-width: 960px; if width constraint is needed.

🧹 Nitpick comments (3)
api/routes/v1/inboxes/index.ts (1)

29-64: Email-to-domain inbox creation flow looks sound; consider tightening validation

The new flow of deriving domainId from req.body.email and short‑circuiting with 400 (invalid email) and 404 (domain not found) is logically consistent and matches the updated payload { name: string; email?: string }. Persisting email only when a verified domainId exists also makes sense.

If you want to harden this further, two optional tweaks:

  • Use .isEmail() in the validator chain for body("email") so obviously malformed addresses never reach the handler.
  • Normalize domainName (e.g., toLowerCase()) before calling getVerifiedDomainByOrganizationIdAndName to avoid case‑sensitive mismatches.
node-sdk/package.json (1)

3-23: Dual ESM/CJS entry points look good; please verify the .d.cts actually exists

The move to "files": ["dist"] plus module/main and conditional exports is aligned with standard Node dual‑package patterns.

One thing to double‑check before publishing: "require": { "types": "./dist/index.d.cts" } assumes your build emits index.d.cts. If the build only emits index.d.ts, that types path will be broken for consumers resolving types via the exports map.

node-sdk/index.ts (1)

2-16: Public method typings align with the new interfaces; consider reusing the param types in signatures

Typing apiKey, domain, and inbox as ApiKeyMethods, DomainMethods, and InboxMethods cleanly exposes the SDK surface and matches the new declarations in types/sendook-api.d.ts. The implementations also look structurally consistent with those interfaces.

Since you already import the parameter types, you can tighten things up and avoid duplication by using them directly in the method signatures. For example:

-  public apiKey: ApiKeyMethods = {
-    create: async ({
-      name,
-    }: {
-      name: string;
-    }) => {
+  public apiKey: ApiKeyMethods = {
+    create: async ({ name }: CreateApiKeyParams) => {
       const response = await axios.post(`${this.apiUrl}/v1/api_keys`, { name }, {
         headers: { Authorization: `Bearer ${this.apiSecret}` },
       });
       return response.data;
     },
@@
-    create: async ({
-      name,
-      email,
-    }: {
-      name: string;
-      email?: string;
-    }) => {
+    create: async ({ name, email }: CreateInboxParams) => {
@@
-      send: async ({
-        inboxId,
-        to,
-        cc,
-        bcc,
-        labels,
-        subject,
-        text,
-        html,
-      }: {
-        inboxId: string;
-        to: string[];
-        cc?: string[];
-        bcc?: string[];
-        labels?: string[];
-        subject: string;
-        text: string;
-        html: string;
-      }) => {
+      send: async ({
+        inboxId,
+        to,
+        cc,
+        bcc,
+        labels,
+        subject,
+        text,
+        html,
+      }: SendMessageParams) => {
@@
-      reply: async ({
-        inboxId,
-        messageId,
-        text,
-        html,
-      }: {
-        inboxId: string;
-        messageId: string;
-        text: string;
-        html: string;
-      }) => {
+      reply: async ({
+        inboxId,
+        messageId,
+        text,
+        html,
+      }: ReplyMessageParams) => {

Same pattern can be applied to the other API key and domain methods (CreateDomainParams, GetDomainParams, etc.) if you’d like everything fully aligned.

Also applies to: 27-265

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 723e0b7 and 2d2ce81.

📒 Files selected for processing (5)
  • api/routes/v1/inboxes/index.ts (2 hunks)
  • app/app/pages/inboxes.vue (5 hunks)
  • node-sdk/index.ts (4 hunks)
  • node-sdk/package.json (1 hunks)
  • node-sdk/types/sendook-api.d.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
node-sdk/index.ts (1)
node-sdk/types/sendook-api.d.ts (3)
  • ApiKeyMethods (56-61)
  • DomainMethods (63-68)
  • InboxMethods (82-89)
api/routes/v1/inboxes/index.ts (2)
api/middlewares/expressValidatorMiddleware.ts (1)
  • expressValidatorMiddleware (4-16)
api/controllers/DomainController.ts (1)
  • getVerifiedDomainByOrganizationIdAndName (43-55)
🔇 Additional comments (1)
node-sdk/types/sendook-api.d.ts (1)

1-90: Type declaration surface is coherent and matches the SDK methods

The new sendook-api.d.ts cleanly documents the SDK surface:

  • Parameter interfaces (Create*Params, SendMessageParams, ReplyMessageParams) line up with what node-sdk/index.ts expects.
  • Method group interfaces (ApiKeyMethods, DomainMethods, MessageMethods, ThreadMethods, InboxMethods) match the methods exposed on SendookAPI.

Using Promise<any> everywhere is fine for now; you can always tighten those return types later once the API response shapes are stable.

Comment on lines +46 to +53
<div class="key-secret">
<span class="secret-label">ID</span>
<span class="secret-value">{{ inbox._id ?? '••••••••••••••••' }}</span>
<button type="button" class="button-copy" aria-label="Copy API key" @click="copyInboxId(inbox)">
<span v-if="copiedInboxId === (inbox._id ?? inbox.email)">Copied</span>
<span v-else>Copy</span>
</button>
</div>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Copy‑ID UX is solid; fix “API key” wording and tighten copied state check

The clipboard implementation with guards and a 2s reset is clean. A couple of small inconsistencies:

  • The button aria-label and the error message say “API key”, but the UI is clearly copying the inbox ID.
  • copiedInboxId is only ever set from inbox._id, so comparing against (inbox._id ?? inbox.email) is unnecessary and slightly confusing.

You can address both with a small tweak:

-          <button type="button" class="button-copy" aria-label="Copy API key" @click="copyInboxId(inbox)">
-            <span v-if="copiedInboxId === (inbox._id ?? inbox.email)">Copied</span>
+          <button type="button" class="button-copy" aria-label="Copy inbox ID" @click="copyInboxId(inbox)">
+            <span v-if="copiedInboxId === inbox._id">Copied</span>
             <span v-else>Copy</span>
           </button>
-  } catch (error) {
-    console.error('Failed to copy API key', error);
+  } catch (error) {
+    console.error('Failed to copy inbox ID', error);
   }

Also applies to: 171-207

🤖 Prompt for AI Agents
In app/app/pages/inboxes.vue around lines 46 to 53 (and similarly at lines
171–207), the button aria-label and error text incorrectly reference "API key"
while the UI copies an inbox ID, and the copied state comparison mixes fallback
email causing unnecessary complexity; change the aria-label and any error text
to "Copy inbox ID" (or similar consistent wording), and simplify the copied
state check to compare only against inbox._id (remove the (inbox._id ??
inbox.email) fallback) and ensure copiedInboxId is set/reset consistently with
that value.

@ahmedmawiri ahmedmawiri merged commit eee0a6c into main Nov 17, 2025
4 checks passed
@ahmedmawiri ahmedmawiri deleted the marc/node-sdk-type-fixes branch November 17, 2025 16:50
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.

3 participants