Skip to content

feat: add official TypeScript SDK to sdks/#64

Merged
KushagraJaiswar02 merged 2 commits intogeturbackend:mainfrom
KushagraJaiswar02:pr/typescript-sdk
Mar 30, 2026
Merged

feat: add official TypeScript SDK to sdks/#64
KushagraJaiswar02 merged 2 commits intogeturbackend:mainfrom
KushagraJaiswar02:pr/typescript-sdk

Conversation

@KushagraJaiswar02
Copy link
Copy Markdown
Collaborator

@KushagraJaiswar02 KushagraJaiswar02 commented Mar 29, 2026

Adds the first official SDK for urBackend — a fully typed TypeScript package wrapping all three core API modules.

Location: sdks/urbackend-sdk/
Package: @urbackend/sdk

Features:

  • Zero runtime dependencies (native fetch only)
  • Full TypeScript generics: db.getAll('products')
  • Typed errors: AuthError, NotFoundError, RateLimitError
  • ESM + CJS dual build via tsup
  • 16 unit tests, all passing
  • Node.js and browser compatible

Modules: auth (signUp/login/me/logout), db (CRUD), storage

Built with ❤️ for urBackend.

Summary by CodeRabbit

  • New Features

    • Released @urbackend/sdk TypeScript SDK with user authentication, database operations, and file storage
    • Added comprehensive documentation including quick-start examples and API reference
    • Implemented typed error handling for authentication, validation, rate limiting, and storage failures
  • Tests

    • Added test coverage for authentication, database, and storage functionality

Adds the first official SDK for urBackend — a fully typed
TypeScript package wrapping all three core API modules.

Location: sdks/urbackend-sdk/
Package:  @urbackend/sdk

Features:
- Zero runtime dependencies (native fetch only)
- Full TypeScript generics: db.getAll<Product>('products')
- Typed errors: AuthError, NotFoundError, RateLimitError
- ESM + CJS dual build via tsup
- 16 unit tests, all passing
- Node.js and browser compatible

Modules: auth (signUp/login/me/logout), db (CRUD), storage
@vercel
Copy link
Copy Markdown

vercel Bot commented Mar 29, 2026

@KushagraJaiswar02 is attempting to deploy a commit to the Yash Pouranik's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 29, 2026

📝 Walkthrough

Walkthrough

A new TypeScript SDK package @urbackend/sdk is introduced under sdks/urbackend-sdk/, featuring a client library with authentication, database, and storage modules, complete with error handling, type definitions, build configuration, comprehensive tests, and documentation.

Changes

Cohort / File(s) Summary
Project Configuration & Build
sdks/urbackend-sdk/.gitignore, sdks/urbackend-sdk/.prettierrc, sdks/urbackend-sdk/eslint.config.js, sdks/urbackend-sdk/tsconfig.json, sdks/urbackend-sdk/tsup.config.ts, sdks/urbackend-sdk/vitest.config.ts, sdks/urbackend-sdk/tests/tsconfig.json, sdks/urbackend-sdk/package.json
Configuration files for linting (ESLint), formatting (Prettier), TypeScript compilation, build tooling (tsup), and test execution (Vitest). Package manifest defines CommonJS/ESM entry points, dev dependencies, and build/test/lint scripts.
Core SDK Framework
sdks/urbackend-sdk/src/client.ts, sdks/urbackend-sdk/src/errors.ts, sdks/urbackend-sdk/src/types/index.ts, sdks/urbackend-sdk/src/index.ts
Central UrBackendClient class managing API configuration, HTTP requests with header/authentication handling, and lazy-loaded module access. Error hierarchy (UrBackendError and subclasses) with status-code-based error mapping. Comprehensive type interfaces for config, requests, auth, documents, and API responses. Main entrypoint exporting factory function and re-exporting types/errors.
Functional Modules
sdks/urbackend-sdk/src/modules/auth.ts, sdks/urbackend-sdk/src/modules/database.ts, sdks/urbackend-sdk/src/modules/storage.ts
Authentication module handling signup, login, session token management, current user queries, and logout. Database module providing generic CRUD operations (getAll, getOne, insert, update, delete) with NotFoundError handling. Storage module for file uploads (with Node.js Buffer support) and deletion via multipart and JSON requests.
Test Suite
sdks/urbackend-sdk/tests/auth.test.ts, sdks/urbackend-sdk/tests/database.test.ts, sdks/urbackend-sdk/tests/storage.test.ts
Vitest-based test coverage for auth flows (signup, login, token persistence, logout), database CRUD and error scenarios (404, 429, 400 validation errors), and storage operations (upload with FormData, deleteFile with JSON body).
Documentation
sdks/urbackend-sdk/README.md
SDK overview with installation, quick-start examples (client init, auth, CRUD, storage), API reference tables, error types, TypeScript examples, service limits, and security warnings regarding API key exposure.

Sequence Diagram(s)

sequenceDiagram
    participant App as Application
    participant Client as UrBackendClient
    participant Auth as AuthModule
    participant API as Backend API

    App->>Client: urBackend({ apiKey })
    Client-->>App: client instance
    
    App->>Auth: client.auth.login(credentials)
    Auth->>Client: client.request('POST', '/api/userAuth/login', {body})
    Client->>API: POST /api/userAuth/login<br/>(with x-api-key header)
    API-->>Client: {success: true, data: {token, user}}
    Client-->>Auth: AuthResponse
    Auth->>Auth: sessionToken = token
    Auth-->>App: AuthResponse

    App->>Auth: client.auth.me()
    Auth->>Client: client.request('GET', '/api/userAuth/me',<br/>{token: sessionToken})
    Client->>API: GET /api/userAuth/me<br/>(with Authorization header)
    API-->>Client: {success: true, data: user}
    Client-->>Auth: AuthUser
    Auth-->>App: AuthUser
Loading
sequenceDiagram
    participant App as Application
    participant Client as UrBackendClient
    participant DB as DatabaseModule
    participant API as Backend API

    App->>Client: urBackend({ apiKey })
    Client-->>App: client instance

    App->>DB: client.db.getAll('users')
    DB->>Client: client.request('GET', '/api/data/users')
    Client->>API: GET /api/data/users<br/>(with x-api-key header)
    API-->>Client: {success: true, data: [...]}
    Client-->>DB: T[]
    DB-->>App: T[]

    App->>DB: client.db.insert('users', {name, email})
    DB->>Client: client.request('POST', '/api/data/users',<br/>{body: payload})
    Client->>API: POST /api/data/users<br/>(with JSON body)
    API-->>Client: {success: true, data: {_id, ...}}
    Client-->>DB: T
    DB-->>App: T
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

🐰 Hop, hop, hurray! A brand new SDK awaits—
With auth, database, storage—oh what feats!
Client requests flow, modules organized neat,
Types keep us safe, tests make sure all's complete,
A full SDK bundled, from rabbit to API receipt! 🚀

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: add official TypeScript SDK to sdks/' clearly and concisely describes the primary change: introducing an official TypeScript SDK package in the sdks/ directory.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

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

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces the official TypeScript SDK for urBackend, providing structured modules for authentication, database management, and storage services. The implementation includes custom error handling, type definitions, and a Vitest-based test suite. Feedback focuses on correcting invalid dependency versions in package.json, replacing hardcoded browser headers with more appropriate SDK identifiers, and improving type safety during file uploads to prevent runtime errors.

Comment thread sdks/urbackend-sdk/package.json
Comment thread sdks/urbackend-sdk/src/client.ts
Comment thread sdks/urbackend-sdk/src/modules/storage.ts
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a new first-party TypeScript SDK package under sdks/urbackend-sdk (@urbackend/sdk) to provide typed wrappers around urBackend auth, database, and storage APIs.

Changes:

  • Introduces UrBackendClient with auth, db, and storage modules plus typed error classes and shared request handler.
  • Adds Vitest unit tests for auth/db/storage behavior and tsup-based dual ESM+CJS build config.
  • Adds SDK-local tooling/config (TypeScript config, ESLint flat config, Prettier config, README).

Reviewed changes

Copilot reviewed 19 out of 21 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
sdks/urbackend-sdk/vitest.config.ts Vitest configuration with Node environment + coverage.
sdks/urbackend-sdk/tsup.config.ts Dual-build (CJS/ESM) bundling configuration.
sdks/urbackend-sdk/tsconfig.json TS build configuration for SDK source.
sdks/urbackend-sdk/tests/tsconfig.json TS config for tests (Vitest globals).
sdks/urbackend-sdk/tests/storage.test.ts Storage module tests (upload/delete/error).
sdks/urbackend-sdk/tests/database.test.ts Database module tests (CRUD + error mapping).
sdks/urbackend-sdk/tests/auth.test.ts Auth module tests (signup/login/me/logout + errors).
sdks/urbackend-sdk/src/types/index.ts Public SDK types for config/payloads/responses.
sdks/urbackend-sdk/src/modules/storage.ts Storage API wrapper (upload/delete).
sdks/urbackend-sdk/src/modules/database.ts Database CRUD wrapper.
sdks/urbackend-sdk/src/modules/auth.ts Auth wrapper (signup/login/me/logout).
sdks/urbackend-sdk/src/index.ts SDK entrypoint + exports.
sdks/urbackend-sdk/src/errors.ts Typed error classes + HTTP error parsing.
sdks/urbackend-sdk/src/client.ts Core request implementation and module accessors.
sdks/urbackend-sdk/package.json Package metadata, scripts, and devDependencies.
sdks/urbackend-sdk/package-lock.json Lockfile for SDK workspace dependencies.
sdks/urbackend-sdk/lint.txt Committed lint output artifact (currently corrupted/binary).
sdks/urbackend-sdk/eslint.config.js ESLint flat config for the SDK.
sdks/urbackend-sdk/README.md SDK usage docs + examples.
sdks/urbackend-sdk/.prettierrc Prettier configuration.
sdks/urbackend-sdk/.gitignore SDK-local ignores.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread sdks/urbackend-sdk/src/client.ts
Comment thread sdks/urbackend-sdk/src/modules/storage.ts
Comment thread sdks/urbackend-sdk/src/errors.ts
Comment thread sdks/urbackend-sdk/eslint.config.js
Comment thread sdks/urbackend-sdk/tests/database.test.ts
Copy link
Copy Markdown
Contributor

@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: 5

🧹 Nitpick comments (4)
sdks/urbackend-sdk/package.json (1)

1-52: Consider adding a files field to control npm package contents.

The package.json is well-configured for dual ESM/CJS builds, but lacks a files field. Without it, npm will publish everything not excluded by .npmignore. Adding "files": ["dist"] ensures only the build output is published, reducing package size and avoiding accidental inclusion of tests or source files.

📦 Proposed addition
   "types": "./dist/index.d.ts",
+  "files": [
+    "dist"
+  ],
   "exports": {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sdks/urbackend-sdk/package.json` around lines 1 - 52, Add a "files" field to
package.json to limit published contents to the build output (e.g., "files":
["dist"]) so only the compiled artifacts referenced by "main", "module", and
"types" are published; update the top-level package.json object near the
existing "exports"/"scripts" entries to include this field and ensure .npmignore
or other publish settings remain consistent.
sdks/urbackend-sdk/src/modules/database.ts (1)

11-20: Consider documenting the empty array fallback behavior.

The getAll method silently returns an empty array when a NotFoundError occurs. This is a reasonable UX choice, but callers may want to distinguish between "collection exists but is empty" vs "collection not found." Consider adding a JSDoc note about this behavior.

📝 Suggested documentation update
   /**
    * Fetch all documents from a collection
+   * `@remarks` Returns an empty array if the collection does not exist
    */
   public async getAll<T extends DocumentData>(collection: string): Promise<T[]> {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sdks/urbackend-sdk/src/modules/database.ts` around lines 11 - 20, Document
that getAll<T extends DocumentData>(collection: string) returns an empty array
when the collection is not found (NotFoundError) so callers cannot distinguish
"collection missing" from "collection exists but empty"; add a JSDoc block above
the getAll method that clearly states this fallback behavior, the return type
(T[]), and a suggested alternative (e.g., use a separate exists/getMetadata
method or catch NotFoundError) so callers know how to detect a missing
collection if needed.
sdks/urbackend-sdk/tests/auth.test.ts (1)

4-6: Shared client instance may cause test order dependencies.

The client is instantiated at module scope and reused across all tests. Since AuthModule stores sessionToken internally, tests that call login() or logout() affect subsequent tests. For example, the test at line 80-83 depends on the state left by previous tests.

Consider using beforeEach to create a fresh client instance, or explicitly reset state in each test.

♻️ Alternative approach with fresh client per test
 const mockApiKey = 'test-api-key';
-const client = urBackend({ apiKey: mockApiKey });
+
+let client: ReturnType<typeof urBackend>;
+
+beforeEach(() => {
+  client = urBackend({ apiKey: mockApiKey });
+});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sdks/urbackend-sdk/tests/auth.test.ts` around lines 4 - 6, The test suite
currently creates a shared client at module scope (const client = urBackend({
apiKey: mockApiKey })) causing AuthModule state (sessionToken) leaks between
tests; change tests to instantiate a fresh client before each test (use
beforeEach to set client = urBackend({ apiKey: mockApiKey })) or explicitly
clear AuthModule state by calling logout()/reset on the client between tests so
login()/logout() calls do not affect other tests; update references to the
module-scope client variable and ensure tests use the per-test client instance
returned by urBackend and its AuthModule methods (login, logout, sessionToken)
when asserting behavior.
sdks/urbackend-sdk/README.md (1)

36-42: Add blank lines around tables for markdown consistency.

The tables in the API Reference section are missing blank lines before them, which causes markdownlint warnings (MD058). This applies to Auth (line 37), Database (line 45), and Storage (line 54) tables.

📝 Proposed fix
 ### Auth
+
 | Method | Params | Returns |

Apply the same pattern before each table in the document.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sdks/urbackend-sdk/README.md` around lines 36 - 42, The markdown tables under
the API Reference (Auth, Database, Storage) violate MD058 because they lack a
blank line above them; edit the README.md to insert a single blank line
immediately before each table (the Auth table starting with "| Method | Params |
Returns |", the Database table block, and the Storage table block) so each table
is preceded by an empty line for proper markdownlint compliance.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@sdks/urbackend-sdk/src/client.ts`:
- Around line 71-74: The current branch uses a truthiness check (else if
(options.body)) which drops valid falsy payloads like 0, false, '', and null;
change the condition to detect presence rather than truthiness (e.g., use "if
('body' in options)" or "if (options.body !== undefined)") so
headers['Content-Type'] is set and requestBody = JSON.stringify(options.body)
runs for those values; update the branch around headers['Content-Type'] /
requestBody in client.ts accordingly.
- Around line 55-60: The hardcoded 'Origin' and 'Referer' entries in the headers
object override browser behavior and are forbidden by Fetch; remove those keys
from the headers (the headers: Record<string,string> declaration in client.ts
where 'x-api-key' and 'User-Agent' are set) so the browser can control Origin
and, if you need to set referer, use the fetch option referrer or leave it
unset; ensure the rest of the code that builds the request (the same method that
uses this.headers and this.apiKey) still passes the remaining headers unchanged.

In `@sdks/urbackend-sdk/src/errors.ts`:
- Around line 75-77: The code handling status === 429 currently reads
Retry-After via response.headers.get('Retry-After') and uses
parseInt(retryAfter, 10), which only supports delta-seconds; update this logic
in the same block to detect whether retryAfter is a numeric string (use
/^\s*\d+\s*$/) and parseInt when so, otherwise attempt to parse it as an
HTTP-date using Date.parse(retryAfter) and compute seconds as
Math.ceil((Date.parse(retryAfter) - Date.now())/1000) only if the parsed time is
valid (not NaN); pass that seconds value (or undefined if invalid/negative) into
the RateLimitError constructor instead of blindly using parseInt.

In `@sdks/urbackend-sdk/src/modules/storage.ts`:
- Around line 22-25: The browser/Blob branch calls formData.append('file', file
as unknown as Blob, filename) but doesn't fallback when filename is undefined;
change the call in the same conditional to pass filename ?? 'file' (or
equivalent) so it defaults to 'file' like the Node Buffer branch; update the
formData.append usage referencing the filename variable and the file Blob to
ensure a consistent default filename in all environments.

In `@sdks/urbackend-sdk/tests/database.test.ts`:
- Around line 86-104: The test currently uses a try/catch so it will silently
succeed if client.db.getAll('products') doesn't throw; replace the try/catch
with an assertion that the promise rejects (e.g., use await
expect(client.db.getAll('products')).rejects...) and assert the error
shape—check name === 'RateLimitError' and retryAfter === 60 (or use
rejects.toMatchObject / rejects.toHaveProperty) so the test fails if no error is
thrown; locate this change around the test block named "RateLimitError thrown on
429" and the call to client.db.getAll('products').

---

Nitpick comments:
In `@sdks/urbackend-sdk/package.json`:
- Around line 1-52: Add a "files" field to package.json to limit published
contents to the build output (e.g., "files": ["dist"]) so only the compiled
artifacts referenced by "main", "module", and "types" are published; update the
top-level package.json object near the existing "exports"/"scripts" entries to
include this field and ensure .npmignore or other publish settings remain
consistent.

In `@sdks/urbackend-sdk/README.md`:
- Around line 36-42: The markdown tables under the API Reference (Auth,
Database, Storage) violate MD058 because they lack a blank line above them; edit
the README.md to insert a single blank line immediately before each table (the
Auth table starting with "| Method | Params | Returns |", the Database table
block, and the Storage table block) so each table is preceded by an empty line
for proper markdownlint compliance.

In `@sdks/urbackend-sdk/src/modules/database.ts`:
- Around line 11-20: Document that getAll<T extends DocumentData>(collection:
string) returns an empty array when the collection is not found (NotFoundError)
so callers cannot distinguish "collection missing" from "collection exists but
empty"; add a JSDoc block above the getAll method that clearly states this
fallback behavior, the return type (T[]), and a suggested alternative (e.g., use
a separate exists/getMetadata method or catch NotFoundError) so callers know how
to detect a missing collection if needed.

In `@sdks/urbackend-sdk/tests/auth.test.ts`:
- Around line 4-6: The test suite currently creates a shared client at module
scope (const client = urBackend({ apiKey: mockApiKey })) causing AuthModule
state (sessionToken) leaks between tests; change tests to instantiate a fresh
client before each test (use beforeEach to set client = urBackend({ apiKey:
mockApiKey })) or explicitly clear AuthModule state by calling logout()/reset on
the client between tests so login()/logout() calls do not affect other tests;
update references to the module-scope client variable and ensure tests use the
per-test client instance returned by urBackend and its AuthModule methods
(login, logout, sessionToken) when asserting behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 49c138fb-2cc4-4186-9118-53bde5a2d435

📥 Commits

Reviewing files that changed from the base of the PR and between b37fc82 and d1814b4.

⛔ Files ignored due to path filters (2)
  • package-lock.json is excluded by !**/package-lock.json
  • sdks/urbackend-sdk/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (20)
  • sdks/urbackend-sdk/.gitignore
  • sdks/urbackend-sdk/.prettierrc
  • sdks/urbackend-sdk/README.md
  • sdks/urbackend-sdk/eslint.config.js
  • sdks/urbackend-sdk/lint.txt
  • sdks/urbackend-sdk/package.json
  • sdks/urbackend-sdk/src/client.ts
  • sdks/urbackend-sdk/src/errors.ts
  • sdks/urbackend-sdk/src/index.ts
  • sdks/urbackend-sdk/src/modules/auth.ts
  • sdks/urbackend-sdk/src/modules/database.ts
  • sdks/urbackend-sdk/src/modules/storage.ts
  • sdks/urbackend-sdk/src/types/index.ts
  • sdks/urbackend-sdk/tests/auth.test.ts
  • sdks/urbackend-sdk/tests/database.test.ts
  • sdks/urbackend-sdk/tests/storage.test.ts
  • sdks/urbackend-sdk/tests/tsconfig.json
  • sdks/urbackend-sdk/tsconfig.json
  • sdks/urbackend-sdk/tsup.config.ts
  • sdks/urbackend-sdk/vitest.config.ts

Comment on lines +55 to +60
const headers: Record<string, string> = {
'x-api-key': this.apiKey,
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36',
'Origin': 'https://urbackend.bitbros.in',
'Referer': 'https://urbackend.bitbros.in/',
};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's locate and examine the client.ts file
fd -e ts -p "*client.ts" | grep -E "sdks/urbackend-sdk"

Repository: yash-pouranik/urBackend

Length of output: 356


🏁 Script executed:

# If found, let's read the relevant section (lines 55-60)
cat -n sdks/urbackend-sdk/src/client.ts | sed -n '50,75p'

Repository: yash-pouranik/urBackend

Length of output: 1110


🌐 Web query:

Fetch Standard forbidden request headers Origin Referer

💡 Result:

In the Fetch Standard, certain HTTP request headers known as "forbidden request-headers" cannot be set programmatically via the Fetch API (e.g., fetch or Headers object). This restriction ensures the user agent (browser) retains control over these headers for security and consistency. Both the "Origin" and "Referer" headers are explicitly forbidden request-headers. From the WHATWG Fetch Standard (last updated March 2026): A header is forbidden if its name matches (case-insensitive) names like Origin, and Referer is handled similarly in the spec's forbidden checks. Headers starting with Sec-, Proxy-, and others like Host, Cookie, Set-Cookie are also forbidden. MDN documentation confirms the full list includes: - Accept-Charset - Accept-Encoding - Access-Control-Request-Headers - Access-Control-Request-Method - Connection - Content-Length - Cookie - Date - DNT - Expect - Host - Keep-Alive - Origin - Proxy-* - Sec-* - Referer - Set-Cookie - TE - Trailer - Transfer-Encoding - Upgrade - Via - Certain X-* method override headers containing forbidden methods (CONNECT, TRACE, TRACK) Note: While "Referer" is spec-forbidden for direct setting, it can be indirectly controlled via the referrer option in fetch. "Origin" cannot be set at all by scripts.

Citations:


Remove manual Origin/Referer headers.

Fetch treats Origin and Referer as forbidden request-header names, so browser-side calls will ignore these hardcoded values. The browser controls Origin entirely, while Referer can only be indirectly set via the referrer option in the Fetch API. This causes a runtime discrepancy where the SDK behaves differently than its code suggests in the advertised browser environment.

Suggested fix
     const headers: Record<string, string> = {
       'x-api-key': this.apiKey,
       'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36',
-      'Origin': 'https://urbackend.bitbros.in',
-      'Referer': 'https://urbackend.bitbros.in/',
     };
📝 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 headers: Record<string, string> = {
'x-api-key': this.apiKey,
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36',
'Origin': 'https://urbackend.bitbros.in',
'Referer': 'https://urbackend.bitbros.in/',
};
const headers: Record<string, string> = {
'x-api-key': this.apiKey,
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36',
};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sdks/urbackend-sdk/src/client.ts` around lines 55 - 60, The hardcoded
'Origin' and 'Referer' entries in the headers object override browser behavior
and are forbidden by Fetch; remove those keys from the headers (the headers:
Record<string,string> declaration in client.ts where 'x-api-key' and
'User-Agent' are set) so the browser can control Origin and, if you need to set
referer, use the fetch option referrer or leave it unset; ensure the rest of the
code that builds the request (the same method that uses this.headers and
this.apiKey) still passes the remaining headers unchanged.

Comment on lines +71 to +74
} else if (options.body) {
headers['Content-Type'] = 'application/json';
requestBody = JSON.stringify(options.body);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Don't drop falsy JSON payloads.

This branch skips valid payloads like 0, false, '', and null because it checks truthiness instead of whether a body was provided.

Suggested fix
-    } else if (options.body) {
+    } else if (options.body !== undefined) {
       headers['Content-Type'] = 'application/json';
       requestBody = JSON.stringify(options.body);
     }
📝 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
} else if (options.body) {
headers['Content-Type'] = 'application/json';
requestBody = JSON.stringify(options.body);
}
} else if (options.body !== undefined) {
headers['Content-Type'] = 'application/json';
requestBody = JSON.stringify(options.body);
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sdks/urbackend-sdk/src/client.ts` around lines 71 - 74, The current branch
uses a truthiness check (else if (options.body)) which drops valid falsy
payloads like 0, false, '', and null; change the condition to detect presence
rather than truthiness (e.g., use "if ('body' in options)" or "if (options.body
!== undefined)") so headers['Content-Type'] is set and requestBody =
JSON.stringify(options.body) runs for those values; update the branch around
headers['Content-Type'] / requestBody in client.ts accordingly.

Comment on lines +75 to +77
if (status === 429) {
const retryAfter = response.headers.get('Retry-After');
return new RateLimitError(message, endpoint, retryAfter ? parseInt(retryAfter, 10) : undefined);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n sdks/urbackend-sdk/src/errors.ts | head -100 | tail -50

Repository: yash-pouranik/urBackend

Length of output: 1771


🏁 Script executed:

wc -l sdks/urbackend-sdk/src/errors.ts

Repository: yash-pouranik/urBackend

Length of output: 102


🌐 Web query:

RFC 9110 Retry-After header format specification

💡 Result:

The Retry-After header in RFC 9110 (HTTP Semantics) is defined in Section 10.2.3. It indicates the minimum time that the recipient ought to wait before making a follow-up request. Format specification (ABNF): Retry-After = HTTP-date / delta-seconds where: - HTTP-date is defined in Section 5.6.7 as IMF-fixdate / obs-date (preferred: IMF-fixdate = day-name "," SP date1 SP time-of-day SP GMT) - delta-seconds = 1*DIGIT (non-negative integer number of seconds to delay) Examples: Retry-After: 120 (wait 120 seconds) Retry-After: Sat, 31 Oct 2026 18:00:00 GMT (wait until that HTTP-date) Used primarily with 503 Service Unavailable, 429 Too Many Requests, and 3xx redirection status codes.

Citations:


🏁 Script executed:

rg -A 5 -B 5 "Retry-After" sdks/urbackend-sdk/src/

Repository: yash-pouranik/urBackend

Length of output: 772


🏁 Script executed:

fd -e test.ts -e spec.ts -e test.js -e spec.js sdks/urbackend-sdk | xargs rg -l "RateLimitError\|Retry-After" 2>/dev/null

Repository: yash-pouranik/urBackend

Length of output: 446


🏁 Script executed:

rg "class RateLimitError" sdks/urbackend-sdk/src/errors.ts -A 5

Repository: yash-pouranik/urBackend

Length of output: 291


🏁 Script executed:

fd . sdks/urbackend-sdk --full-path -e test.ts -e spec.ts -e test.js -e spec.js

Repository: yash-pouranik/urBackend

Length of output: 187


🏁 Script executed:

rg "429\|RateLimitError" sdks/urbackend-sdk/ -t ts -t js

Repository: yash-pouranik/urBackend

Length of output: 49


🏁 Script executed:

cat sdks/urbackend-sdk/tests/auth.test.ts | head -100

Repository: yash-pouranik/urBackend

Length of output: 3006


🏁 Script executed:

rg "429" sdks/urbackend-sdk/tests/

Repository: yash-pouranik/urBackend

Length of output: 220


🏁 Script executed:

rg "Retry-After\|retryAfter" sdks/urbackend-sdk/

Repository: yash-pouranik/urBackend

Length of output: 49


🏁 Script executed:

cat -n sdks/urbackend-sdk/tests/database.test.ts | grep -A 20 "RateLimitError"

Repository: yash-pouranik/urBackend

Length of output: 1240


🏁 Script executed:

cat sdks/urbackend-sdk/tests/database.test.ts | grep -A 20 "429"

Repository: yash-pouranik/urBackend

Length of output: 750


Handle both Retry-After formats defined in RFC 9110.

The Retry-After header allows two formats: numeric seconds (delta-seconds) or an HTTP date. The current code only handles numeric values via parseInt(), which silently fails when a server sends an HTTP-date (e.g., Sat, 31 Oct 2026 18:00:00 GMT). This results in NaN, which evaluates to undefined when passed to RateLimitError, causing callers to lose retry timing information.

Suggested fix
   if (status === 429) {
     const retryAfter = response.headers.get('Retry-After');
-    return new RateLimitError(message, endpoint, retryAfter ? parseInt(retryAfter, 10) : undefined);
+    let retryAfterSeconds: number | undefined;
+    if (retryAfter) {
+      if (/^\d+$/.test(retryAfter)) {
+        retryAfterSeconds = Number(retryAfter);
+      } else {
+        const retryAt = Date.parse(retryAfter);
+        if (!Number.isNaN(retryAt)) {
+          retryAfterSeconds = Math.max(0, Math.ceil((retryAt - Date.now()) / 1000));
+        }
+      }
+    }
+    return new RateLimitError(message, endpoint, retryAfterSeconds);
   }
📝 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
if (status === 429) {
const retryAfter = response.headers.get('Retry-After');
return new RateLimitError(message, endpoint, retryAfter ? parseInt(retryAfter, 10) : undefined);
if (status === 429) {
const retryAfter = response.headers.get('Retry-After');
let retryAfterSeconds: number | undefined;
if (retryAfter) {
if (/^\d+$/.test(retryAfter)) {
retryAfterSeconds = Number(retryAfter);
} else {
const retryAt = Date.parse(retryAfter);
if (!Number.isNaN(retryAt)) {
retryAfterSeconds = Math.max(0, Math.ceil((retryAt - Date.now()) / 1000));
}
}
}
return new RateLimitError(message, endpoint, retryAfterSeconds);
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sdks/urbackend-sdk/src/errors.ts` around lines 75 - 77, The code handling
status === 429 currently reads Retry-After via
response.headers.get('Retry-After') and uses parseInt(retryAfter, 10), which
only supports delta-seconds; update this logic in the same block to detect
whether retryAfter is a numeric string (use /^\s*\d+\s*$/) and parseInt when so,
otherwise attempt to parse it as an HTTP-date using Date.parse(retryAfter) and
compute seconds as Math.ceil((Date.parse(retryAfter) - Date.now())/1000) only if
the parsed time is valid (not NaN); pass that seconds value (or undefined if
invalid/negative) into the RateLimitError constructor instead of blindly using
parseInt.

Comment on lines +22 to +25
} else {
// Browser File/Blob or Node.js Blob/File
formData.append('file', file as unknown as Blob, filename);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Provide a default filename in the browser path.

When filename is undefined, the formData.append() call passes undefined as the third argument. Unlike the Node.js Buffer branch (line 21) which defaults to 'file', the browser path has no fallback. Some environments may handle this inconsistently.

🔧 Proposed fix
     } else {
       // Browser File/Blob or Node.js Blob/File
-      formData.append('file', file as unknown as Blob, filename);
+      formData.append('file', file as unknown as Blob, filename || 'file');
     }
📝 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
} else {
// Browser File/Blob or Node.js Blob/File
formData.append('file', file as unknown as Blob, filename);
}
} else {
// Browser File/Blob or Node.js Blob/File
formData.append('file', file as unknown as Blob, filename || 'file');
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sdks/urbackend-sdk/src/modules/storage.ts` around lines 22 - 25, The
browser/Blob branch calls formData.append('file', file as unknown as Blob,
filename) but doesn't fallback when filename is undefined; change the call in
the same conditional to pass filename ?? 'file' (or equivalent) so it defaults
to 'file' like the Node Buffer branch; update the formData.append usage
referencing the filename variable and the file Blob to ensure a consistent
default filename in all environments.

Comment on lines +86 to +104
test('RateLimitError thrown on 429', async () => {
vi.stubGlobal(
'fetch',
vi.fn().mockResolvedValue({
ok: false,
status: 429,
url: 'https://api.urbackend.bitbros.in/api/data/products',
headers: new Headers({ 'Retry-After': '60' }),
json: () => Promise.resolve({ success: false, message: 'Too Many Requests' }),
}),
);

try {
await client.db.getAll('products');
} catch (error: any) {
expect(error.name).toBe('RateLimitError');
expect(error.retryAfter).toBe(60);
}
});
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Test will pass even if no error is thrown.

The try/catch pattern here doesn't guarantee the catch block executes. If client.db.getAll() succeeds unexpectedly, the test passes without any assertions being run.

🔧 Proposed fix using expect().rejects
 test('RateLimitError thrown on 429', async () => {
   vi.stubGlobal(
     'fetch',
     vi.fn().mockResolvedValue({
       ok: false,
       status: 429,
       url: 'https://api.urbackend.bitbros.in/api/data/products',
       headers: new Headers({ 'Retry-After': '60' }),
       json: () => Promise.resolve({ success: false, message: 'Too Many Requests' }),
     }),
   );

-  try {
-    await client.db.getAll('products');
-  } catch (error: any) {
-    expect(error.name).toBe('RateLimitError');
-    expect(error.retryAfter).toBe(60);
-  }
+  await expect(client.db.getAll('products')).rejects.toMatchObject({
+    name: 'RateLimitError',
+    retryAfter: 60,
+  });
 });
📝 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
test('RateLimitError thrown on 429', async () => {
vi.stubGlobal(
'fetch',
vi.fn().mockResolvedValue({
ok: false,
status: 429,
url: 'https://api.urbackend.bitbros.in/api/data/products',
headers: new Headers({ 'Retry-After': '60' }),
json: () => Promise.resolve({ success: false, message: 'Too Many Requests' }),
}),
);
try {
await client.db.getAll('products');
} catch (error: any) {
expect(error.name).toBe('RateLimitError');
expect(error.retryAfter).toBe(60);
}
});
test('RateLimitError thrown on 429', async () => {
vi.stubGlobal(
'fetch',
vi.fn().mockResolvedValue({
ok: false,
status: 429,
url: 'https://api.urbackend.bitbros.in/api/data/products',
headers: new Headers({ 'Retry-After': '60' }),
json: () => Promise.resolve({ success: false, message: 'Too Many Requests' }),
}),
);
await expect(client.db.getAll('products')).rejects.toMatchObject({
name: 'RateLimitError',
retryAfter: 60,
});
});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sdks/urbackend-sdk/tests/database.test.ts` around lines 86 - 104, The test
currently uses a try/catch so it will silently succeed if
client.db.getAll('products') doesn't throw; replace the try/catch with an
assertion that the promise rejects (e.g., use await
expect(client.db.getAll('products')).rejects...) and assert the error
shape—check name === 'RateLimitError' and retryAfter === 60 (or use
rejects.toMatchObject / rejects.toHaveProperty) so the test fails if no error is
thrown; locate this change around the test block named "RateLimitError thrown on
429" and the call to client.db.getAll('products').


constructor(config: UrBackendConfig) {
this.apiKey = config.apiKey;
this.baseUrl = config.baseUrl || 'https://api.urbackend.bitbros.in';
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Our public api base URL is - https://api.ub.bitbros.in

@@ -0,0 +1,52 @@
{
"name": "@urbackend/sdk",
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

name should be - @urbackend/ts-sdk or @urbackend/client
i think client name is more valid

@@ -0,0 +1,52 @@
{
"name": "@urbackend/sdk",
"version": "1.0.0",
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

version should start from 0.1.0 then we will upgrade gradually

"typescript",
"backend-as-a-service"
],
"author": "urBackend Contributors",
Copy link
Copy Markdown
Collaborator

@yash-pouranik yash-pouranik Mar 30, 2026

Choose a reason for hiding this comment

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

update author field -
"author": "UrBackend Team urbackend@bitbros.in"

Official TypeScript SDK for [urBackend](https://urbackend.bitbros.in) — the instant Backend-as-a-Service for frontend developers.

## Installation
npm install @urbackend/sdk
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

rename accordingly

@vercel
Copy link
Copy Markdown

vercel Bot commented Mar 30, 2026

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

Project Deployment Actions Updated (UTC)
ur-backend-web-dashboard Ready Ready Preview, Comment Mar 30, 2026 8:11am

@KushagraJaiswar02
Copy link
Copy Markdown
Collaborator Author

@copilot apply changes based on the comments in this thread

@KushagraJaiswar02 KushagraJaiswar02 merged commit 5d3b58d into geturbackend:main Mar 30, 2026
9 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request Apr 10, 2026
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