Skip to content

feat(client): scaffold @betterbase/client TypeScript SDK#2

Merged
Helal-maker merged 4 commits intomainfrom
codex/create-typescript-sdk-package
Feb 20, 2026
Merged

feat(client): scaffold @betterbase/client TypeScript SDK#2
Helal-maker merged 4 commits intomainfrom
codex/create-typescript-sdk-package

Conversation

@Helal-maker
Copy link
Copy Markdown
Owner

@Helal-maker Helal-maker commented Feb 20, 2026

Motivation

  • Provide a first-class, Bun-first TypeScript SDK for BetterBase that mirrors a Supabase-like developer experience with zero runtime dependencies and perfect TypeScript inference.
  • Ship a minimal, usable surface for queries, auth, and realtime subscriptions so apps can start integrating with BetterBase programmatically.
  • Ensure the package builds to both ESM and CJS and ships TypeScript declarations so it works across Bun, Node, Deno, browsers, and React Native.

Description

  • Add a new @betterbase/client package with package.json, tsconfig.json, README.md, and a Bun build script at src/build.ts that emits ESM, CJS, and .d.ts outputs and an entrypoint at src/index.ts.
  • Implement core SDK modules: client.ts (factory and header/auth management), query-builder.ts (fluent query API with select, eq, in, limit, offset, order, and CRUD helpers), auth.ts (signUp, signIn, signOut, getUser, token storage helpers), realtime.ts (WebSocket subscriptions with reconnect and unsubscribe lifecycle), plus types.ts and errors.ts for shared types and custom error classes.
  • Export both ESM and CJS via exports and ensure type coverage by generating declaration files with tsc, and include a small test suite and usage documentation in README.md.

Testing

  • Ran bun test in packages/client and the initial test suite passed (2 tests, 0 failures).
  • Ran bun run typecheck (TypeScript tsc --noEmit) and it completed successfully with no type errors.
  • Ran bun run build (the Bun build pipeline in src/build.ts) and it completed successfully producing ESM/CJS bundles and TypeScript declaration files.

Codex Task

Summary by CodeRabbit

  • New Features

    • Added a TypeScript client: auth flows (signup/signin/signout), typed query builder (filtering, pagination, sorting, CRUD), realtime subscriptions, consolidated public exports, and structured error types.
  • Documentation

    • Added a full README with installation, usage examples, and API reference.
  • Tests

    • Added tests for client creation and basic query builder usage.
  • Chores

    • Added package manifest, build scripts, and TypeScript configs for the client package.

@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 20, 2026

📝 Walkthrough

Walkthrough

Adds a new TypeScript client package: package manifest and tsconfigs, build script, core client, auth, query builder, realtime WebSocket client, types, errors, README, and basic tests—exposing a typed HTTP, auth, CRUD and realtime API surface.

Changes

Cohort / File(s) Summary
Package manifest & configs
betterbase/packages/client/package.json, betterbase/packages/client/tsconfig.json, betterbase/packages/client/tsconfig.test.json
New package.json with exports, scripts, devDependencies and Node engines; tsconfig files for build and test (declaration emission and test noEmit).
Documentation
betterbase/packages/client/README.md
Replaced scaffold header and placeholder with full README: install, usage examples (client creation, auth, queries, realtime), and API reference link.
Build orchestration
betterbase/packages/client/src/build.ts
Added Bun-based build script producing ESM and CJS outputs and TypeScript declarations; sequential build steps with error handling and logging.
Core client & entry
betterbase/packages/client/src/client.ts, betterbase/packages/client/src/index.ts
Introduces BetterBaseClient and createClient; wires AuthClient and RealtimeClient, syncs token to Authorization header; index.ts re-exports public API.
Authentication module
betterbase/packages/client/src/auth.ts
New AuthClient with signUp/signIn/signOut/getUser, token storage (localStorage), get/set token, standardized BetterBaseResponse, and AuthError/NetworkError handling.
Query builder
betterbase/packages/client/src/query-builder.ts
New generic QueryBuilder with fluent select/filters/pagination/sort and CRUD operations (execute/single/insert/update/delete) using fetch and structured error wrapping.
Realtime client
betterbase/packages/client/src/realtime.ts
New RealtimeClient managing WebSocket connection, exponential backoff reconnects, subscription tracking by table/event, subscribe/unsubscribe/re-subscribe flows and cleanup.
Types & errors
betterbase/packages/client/src/types.ts, betterbase/packages/client/src/errors.ts
Adds foundational types (BetterBaseConfig, BetterBaseResponse, QueryOptions, RealtimeCallback/Subscription) and error classes (BetterBaseError, NetworkError, AuthError, ValidationError).
Tests
betterbase/packages/client/test/client.test.ts
Adds basic Bun tests checking client creation and query builder instantiation.

Sequence Diagram(s)

sequenceDiagram
    participant App as Application
    participant Client as BetterBaseClient
    participant Auth as AuthClient
    participant Query as QueryBuilder
    participant Backend as Backend
    participant WS as WebSocket

    App->>Client: createClient(config)
    Client->>Auth: new AuthClient(url, headers, onAuthStateChange)
    Client->>WS: new RealtimeClient(url)

    App->>Auth: signIn(credentials)
    Auth->>Backend: POST /auth/signin
    Backend-->>Auth: { token, user }
    Auth-->>Client: onAuthStateChange(token)
    Client->>Client: set Authorization header

    App->>Query: client.from('users').select().eq(...).execute()
    Query->>Backend: GET /users?select=...&filters...
    Backend-->>Query: 200 OK (data)
    Query-->>App: BetterBaseResponse<data[]>

    App->>WS: client.realtime.from('users').on('UPDATE').subscribe()
    WS->>Backend: WebSocket SUBSCRIBE { table: "users", filter }
    Backend-->>WS: subscription confirmed
    Backend->>WS: realtime UPDATE event
    WS-->>App: dispatched to subscriber callback
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐇 I hopped through modules with a nibble and cheer,
New auth, queries, and sockets draw near.
Tokens snug in headers, types tidy and neat,
Subscriptions hum softly — the burrow's complete.
Hop, build, and ship — a betterbase treat!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.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 clearly and concisely describes the main changeset: scaffolding a new TypeScript SDK package for BetterBase with comprehensive implementation of core modules (client, auth, realtime, query builder) and build configuration.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/create-typescript-sdk-package

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

Copy link
Copy Markdown

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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@betterbase/packages/client/src/auth.ts`:
- Around line 21-26: The getStorage function currently accesses
globalThis.localStorage directly which can throw in some environments; wrap the
access in a try/catch inside getStorage (or a small helper) to safely detect
presence and return null on any error. Specifically, modify getStorage to try
reading globalThis and globalThis.localStorage inside a try block, return
globalThis.localStorage if available, and catch any exception to return
null—ensuring callers of getStorage (auth flows) won’t crash when localStorage
is inaccessible.

In `@betterbase/packages/client/src/realtime.ts`:
- Around line 27-31: The onopen handler and subscription logic drop per-table
filters because sendSubscribe(table) is called using only the table key; update
the subscription storage to map table -> filter (or table -> {filter, refCount})
when subscribe(filter) is called, have subscribe() and unsubscribe() read and
update that map, and change sendSubscribe(table) to accept and include the
stored filter when sending the subscribe payload so filters are preserved across
initial connect and reconnect (also apply same change to the code paths around
the reconnect logic referenced by sendSubscribe and this.subscriptions).

In `@betterbase/packages/client/tsconfig.json`:
- Around line 5-10: The tsconfig currently has "declaration": true and includes
both "src/**/*" and "test/**/*", which causes .d.ts files for tests to be
emitted; fix by excluding tests from declaration emit: either create a dedicated
tsconfig.test.json for tests (which includes "test/**/*") and leave the main
tsconfig.json include as "src/**/*" for declaration generation, or adjust the
build step that runs tsc --emitDeclarationOnly to point to a production tsconfig
(or add "exclude": ["test/**/*"] to the main tsconfig.json) so that
functions/classes in src emit .d.ts but test files do not; update any build
script that references tsconfig.json to use the new/modified config.

Comment thread betterbase/packages/client/src/auth.ts
Comment thread betterbase/packages/client/src/realtime.ts
Comment thread betterbase/packages/client/tsconfig.json Outdated
Copy link
Copy Markdown

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

🧹 Nitpick comments (4)
betterbase/packages/client/package.json (3)

18-18: The --watch flag is ignored by the build script.

Bun.build doesn't have built-in watch mode, so the --watch argument passed here has no effect. Consider using bun --watch run src/build.ts instead, which will re-run the entire script on file changes.

🔧 Suggested fix
-    "dev": "bun run src/build.ts --watch",
+    "dev": "bun --watch run src/build.ts",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@betterbase/packages/client/package.json` at line 18, The dev script in
package.json currently uses "bun run src/build.ts --watch" which is ineffective
because Bun.build has no watch mode; update the npm script named "dev" to invoke
Bun's CLI watch wrapper instead (e.g., use "bun --watch run src/build.ts") so
the entire build script is re-run on file changes; modify the "dev" entry in
package.json accordingly and keep the script name "dev" unchanged.

1-37: Consider adding standard npm metadata fields.

For a public SDK, adding license, repository, author, and engines fields improves discoverability and helps consumers understand compatibility requirements.

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

In `@betterbase/packages/client/package.json` around lines 1 - 37, The
package.json for the `@betterbase/client` package is missing standard npm metadata
fields; add "license" (e.g., "MIT" or your chosen license), "repository" (type
and URL), "author" (name and/or organization), and an "engines" entry (e.g.,
node version range) to the top-level object so consumers and registries can
discover license and compatibility info; update the existing package.json keys
(name, version, scripts) in the same file to include these new fields
consistently.

9-15: Consider placing types first in the exports map.

Some TypeScript configurations and bundlers resolve conditions in order. Placing types first ensures TypeScript finds declarations before attempting to load the JavaScript entry.

♻️ Suggested reorder
   "exports": {
     ".": {
+      "types": "./dist/index.d.ts",
       "import": "./dist/index.js",
-      "require": "./dist/index.cjs",
-      "types": "./dist/index.d.ts"
+      "require": "./dist/index.cjs"
     }
   },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@betterbase/packages/client/package.json` around lines 9 - 15, The exports map
currently lists "import" before "types", which can cause some TypeScript
resolvers to pick JS before declarations; reorder the properties under the "."
export so that "types" appears first (i.e., make the "." export order: "types",
"import", "require") to ensure TypeScript finds the declaration file (refer to
the "exports" object and the "." entry in package.json).
betterbase/packages/client/src/realtime.ts (1)

31-65: Consider adding a WebSocket onerror handler.

The WebSocket lacks an onerror handler. While onclose typically fires after errors, an explicit error handler aids debugging and allows for error-specific logging or recovery logic.

🔧 Suggested addition
     this.ws.onclose = () => {
       // ... existing code
     };
+
+    this.ws.onerror = (error) => {
+      console.error('[RealtimeClient] WebSocket error:', error);
+    };
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@betterbase/packages/client/src/realtime.ts` around lines 31 - 65, Add a
WebSocket error handler to surface and handle socket errors: implement
this.ws.onerror = (err) => { ... } alongside the existing
this.ws.onopen/onmessage/onclose handlers inside the connect logic, log the
error via your logger (or console) including the error object, clear/reset
this.reconnectTimeout and set this.ws = null if needed, and then trigger
reconnect behavior similar to the onclose path (increment this.reconnectAttempts
and call this.connect after the same exponential backoff). Reference this.ws,
this.ws.onerror, this.reconnectAttempts, this.reconnectTimeout, this.connect,
and this.subscriptions/sendSubscribe so the error handler mirrors onclose
recovery and records useful error details.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@betterbase/packages/client/src/realtime.ts`:
- Around line 105-110: The current subscribe implementation stores one
Subscription per table in this.subscriptions and sets subscription.filter, so
later calls to subscribe overwrite earlier filters and you subsequently call
sendSubscribe(table, subscription.filter) with only the last filter; to fix,
change the subscriptions structure to track multiple subscribers per table
(e.g., Map<table, Subscription[]> or Map<table, Map<callbackId, Subscription>>)
inside the subscribe method, store each callback+filter pair separately instead
of replacing subscription.filter, and update sendSubscribe (or introduce a new
sendSubscribeAll) to either send a composed filter representing all current
subscriber filters or iterate and send per-subscriber filters to the server;
update unsubscribe logic to remove the specific callback entry rather than
deleting the entire table entry.
- Around line 20-23: The connect() method currently returns silently when
WebSocket is undefined which hides failures; update the connect() implementation
to surface this condition by either throwing an Error or emitting/logging a
clear warning via the class logger (or an injected logger) so callers know
subscriptions won't receive events; locate the private connect() method and add
a guard that logs/throws with a message like "WebSocket is not available in this
environment" and ensure any public subscribe/open methods that call connect()
propagate or handle that error so the caller can detect the failure.

---

Nitpick comments:
In `@betterbase/packages/client/package.json`:
- Line 18: The dev script in package.json currently uses "bun run src/build.ts
--watch" which is ineffective because Bun.build has no watch mode; update the
npm script named "dev" to invoke Bun's CLI watch wrapper instead (e.g., use "bun
--watch run src/build.ts") so the entire build script is re-run on file changes;
modify the "dev" entry in package.json accordingly and keep the script name
"dev" unchanged.
- Around line 1-37: The package.json for the `@betterbase/client` package is
missing standard npm metadata fields; add "license" (e.g., "MIT" or your chosen
license), "repository" (type and URL), "author" (name and/or organization), and
an "engines" entry (e.g., node version range) to the top-level object so
consumers and registries can discover license and compatibility info; update the
existing package.json keys (name, version, scripts) in the same file to include
these new fields consistently.
- Around line 9-15: The exports map currently lists "import" before "types",
which can cause some TypeScript resolvers to pick JS before declarations;
reorder the properties under the "." export so that "types" appears first (i.e.,
make the "." export order: "types", "import", "require") to ensure TypeScript
finds the declaration file (refer to the "exports" object and the "." entry in
package.json).

In `@betterbase/packages/client/src/realtime.ts`:
- Around line 31-65: Add a WebSocket error handler to surface and handle socket
errors: implement this.ws.onerror = (err) => { ... } alongside the existing
this.ws.onopen/onmessage/onclose handlers inside the connect logic, log the
error via your logger (or console) including the error object, clear/reset
this.reconnectTimeout and set this.ws = null if needed, and then trigger
reconnect behavior similar to the onclose path (increment this.reconnectAttempts
and call this.connect after the same exponential backoff). Reference this.ws,
this.ws.onerror, this.reconnectAttempts, this.reconnectTimeout, this.connect,
and this.subscriptions/sendSubscribe so the error handler mirrors onclose
recovery and records useful error details.

Comment thread betterbase/packages/client/src/realtime.ts
Comment thread betterbase/packages/client/src/realtime.ts Outdated
Copy link
Copy Markdown

@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

🧹 Nitpick comments (1)
betterbase/packages/client/package.json (1)

25-30: Consider adding a lint script and using consistent tsconfig for typecheck.

The typecheck script uses tsconfig.test.json rather than the main tsconfig.json. If this is intentional (e.g., to include test files in type-checking), that's fine. Otherwise, consider using tsconfig.json for production code checks or adding a separate typecheck:test script.

Also, consider adding a lint script for code quality enforcement if ESLint or Biome is planned for this package.

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

In `@betterbase/packages/client/package.json` around lines 25 - 30, Update the
package.json "scripts" section to add a "lint" script (e.g., using your chosen
linter like eslint or biome) and make the "typecheck" script point to the
intended tsconfig; if you want to keep current test-specific checks, rename the
existing "typecheck" to "typecheck:test" (referencing tsconfig.test.json) and
create a new "typecheck" that uses tsconfig.json for production code checks so
tools and CI run consistent type checking; adjust the "scripts" block entries
"typecheck", "typecheck:test", and add "lint" accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@betterbase/packages/client/src/realtime.ts`:
- Around line 146-168: The unsubscribe handler currently calls
sendUnsubscribe(table) unconditionally then sendSubscribeAll(table) which
briefly fully-unsubscribes the table; change unsubscribe logic in the
unsubscribe closure for the class that manages this.subscriptions so that
sendUnsubscribe(table) is only called when currentSubscribers.size becomes 0
(i.e., when you delete the table from this.subscriptions and intend to fully
disconnect), and when other subscribers remain simply remove the id from
currentSubscribers and update the map without sending an unsubscribe followed by
sendSubscribeAll; keep the existing disconnect() call when
this.subscriptions.size === 0 and remove the unsubscribe+resubscribe cycle by
only calling sendSubscribeAll(table) when you have just added/changed
subscriptions (not on simple removal).

---

Nitpick comments:
In `@betterbase/packages/client/package.json`:
- Around line 25-30: Update the package.json "scripts" section to add a "lint"
script (e.g., using your chosen linter like eslint or biome) and make the
"typecheck" script point to the intended tsconfig; if you want to keep current
test-specific checks, rename the existing "typecheck" to "typecheck:test"
(referencing tsconfig.test.json) and create a new "typecheck" that uses
tsconfig.json for production code checks so tools and CI run consistent type
checking; adjust the "scripts" block entries "typecheck", "typecheck:test", and
add "lint" accordingly.

Comment thread betterbase/packages/client/src/realtime.ts
Copy link
Copy Markdown

@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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@betterbase/packages/client/package.json`:
- Around line 7-10: Update the "repository.url" value in package.json to the
correct GitHub repository; locate the repository object (the "repository" key
containing "type" and "url") and replace
"https://github.com/betterbase/betterbase.git" with
"https://github.com/Helal-maker/Betterbase.git" so npm links point to the actual
repo.

Comment on lines +7 to +10
"repository": {
"type": "git",
"url": "https://github.com/betterbase/betterbase.git"
},
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Git Remote Origin ==="
git config --get remote.origin.url 2>/dev/null || echo "No remote.origin found"

echo
echo "=== All package.json files with repository field ==="
fd -t f "package.json" | while read -r file; do
  if grep -q '"repository"' "$file" 2>/dev/null; then
    echo "File: $file"
    grep -A 3 '"repository"' "$file" | head -4
    echo
  fi
done

echo "=== Root directory structure ==="
ls -la | head -20

Repository: Helal-maker/Betterbase

Length of output: 934


Update the repository URL to match the actual repository.

The repository URL points to https://github.com/betterbase/betterbase.git, but the actual repository is at https://github.com/Helal-maker/Betterbase.git. Without this fix, npm will direct users to the wrong repository.

Proposed fix
   "repository": {
     "type": "git",
-    "url": "https://github.com/betterbase/betterbase.git"
+    "url": "https://github.com/Helal-maker/Betterbase.git"
   },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@betterbase/packages/client/package.json` around lines 7 - 10, Update the
"repository.url" value in package.json to the correct GitHub repository; locate
the repository object (the "repository" key containing "type" and "url") and
replace "https://github.com/betterbase/betterbase.git" with
"https://github.com/Helal-maker/Betterbase.git" so npm links point to the actual
repo.

@Helal-maker Helal-maker merged commit 4b17312 into main Feb 20, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant