feat(client): scaffold @betterbase/client TypeScript SDK#2
Conversation
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
📝 WalkthroughWalkthroughAdds 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
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
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (4)
betterbase/packages/client/package.json (3)
18-18: The--watchflag is ignored by the build script.
Bun.builddoesn't have built-in watch mode, so the--watchargument passed here has no effect. Consider usingbun --watch run src/build.tsinstead, 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, andenginesfields 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 placingtypesfirst in the exports map.Some TypeScript configurations and bundlers resolve conditions in order. Placing
typesfirst 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 WebSocketonerrorhandler.The WebSocket lacks an
onerrorhandler. Whileonclosetypically 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.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
betterbase/packages/client/package.json (1)
25-30: Consider adding alintscript and using consistent tsconfig for typecheck.The
typecheckscript usestsconfig.test.jsonrather than the maintsconfig.json. If this is intentional (e.g., to include test files in type-checking), that's fine. Otherwise, consider usingtsconfig.jsonfor production code checks or adding a separatetypecheck:testscript.Also, consider adding a
lintscript 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.
There was a problem hiding this comment.
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.
| "repository": { | ||
| "type": "git", | ||
| "url": "https://github.com/betterbase/betterbase.git" | ||
| }, |
There was a problem hiding this comment.
🧩 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 -20Repository: 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.
Motivation
Description
@betterbase/clientpackage withpackage.json,tsconfig.json,README.md, and a Bun build script atsrc/build.tsthat emits ESM, CJS, and.d.tsoutputs and an entrypoint atsrc/index.ts.client.ts(factory and header/auth management),query-builder.ts(fluent query API withselect,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), plustypes.tsanderrors.tsfor shared types and custom error classes.exportsand ensure type coverage by generating declaration files withtsc, and include a small test suite and usage documentation inREADME.md.Testing
bun testinpackages/clientand the initial test suite passed (2 tests, 0 failures).bun run typecheck(TypeScripttsc --noEmit) and it completed successfully with no type errors.bun run build(the Bun build pipeline insrc/build.ts) and it completed successfully producing ESM/CJS bundles and TypeScript declaration files.Codex Task
Summary by CodeRabbit
New Features
Documentation
Tests
Chores