Skip to content

[1/3] Add instant db svelte package#2365

Closed
nezaj wants to merge 4 commits intomainfrom
svelte-sdk
Closed

[1/3] Add instant db svelte package#2365
nezaj wants to merge 4 commits intomainfrom
svelte-sdk

Conversation

@nezaj
Copy link
Contributor

@nezaj nezaj commented Mar 13, 2026

Adds @instantdb/svelte package with reactive hooks for Svelte 5, following the same composition-wrapper pattern as @instantdb/solidjs

Implements useQuery, useAuth, useUser, useConnectionStatus, useLocalId, and all room hooks (presence, topics, typing indicators) along with tests!

Svelte 5 primer

Runes are Svelte 5's reactivity primitives (replacing Svelte 4's stores). The two we use:

  • $state(value) creates a reactive proxy. When you mutate properties on it (result.data = newData), anything reading those properties re-renders. This is why our subscription callbacks mutate individual properties rather than reassigning the whole object.
  • $effect(() => { ... }) is the equivalent of SolidJS's createEffect or React's useEffect. It auto-tracks any reactive values read inside it and re-runs when they change. Returning a function from $effect registers a cleanup (like onCleanup in Solid).

.svelte.ts file extension is required for any file that uses runes. Regular .ts files will throw rune_outside_svelte at runtime. This is why the source files use .svelte.ts.

Build uses svelte-package instead of tshy because .svelte.ts files need the Svelte compiler to process runes. tshy/tsc can't handle them.

Key differences from SolidJS SDK

SolidJS Svelte
State createSignal() returns [getter, setter] $state({}) returns a mutable proxy
Reading state state().data (call the getter) state.data (read the property)
Cleanup onCleanup(unsub) return unsub from $effect
Primitives Accessor<string> (getter fn) { current: string } (wrapper object, since primitives can't be proxied)

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 13, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 60523a1c-907e-43f7-a673-a4482be75484

📥 Commits

Reviewing files that changed from the base of the PR and between b20b85a and 1138c12.

📒 Files selected for processing (3)
  • client/packages/svelte/src/lib/InstantSvelteDatabase.svelte.ts
  • client/packages/svelte/src/lib/InstantSvelteRoom.svelte.ts
  • client/packages/svelte/src/tests/InstantSvelteDatabase.svelte.test.ts

📝 Walkthrough

Walkthrough

Adds a new Svelte client package: package manifest, build/test configs, Svelte/Vite tooling, a TypeScript wrapper around InstantDB core with reactive hooks (queries, auth, rooms/presence/typing), unit tests, and publish mapping.

Changes

Cohort / File(s) Summary
Publish mapping
client/scripts/publish_packages.clj
Register new Svelte package path (:svelte -> "./packages/svelte").
Package manifest & ignore
client/packages/svelte/package.json, client/packages/svelte/.gitignore
Add @instantdb/svelte package manifest and ignore .svelte-kit and dist.
Build & tooling configs
client/packages/svelte/tsconfig.json, client/packages/svelte/svelte.config.js, client/packages/svelte/vite.config.ts
Add TypeScript, Svelte preprocess, and Vite/Vitest configs for building and testing the Svelte package.
Public exports & version
client/packages/svelte/src/lib/index.ts, client/packages/svelte/src/lib/version.ts
Re-export core API/types and expose Svelte-specific classes and version passthrough.
Svelte DB wrapper
client/packages/svelte/src/lib/InstantSvelteDatabase.svelte.ts
New InstantSvelteDatabase class wrapping core InstantDB with non-reactive APIs and Svelte reactive hooks (useQuery, useAuth, useUser, useConnectionStatus, useLocalId), plus init().
Rooms, presence & typing hooks
client/packages/svelte/src/lib/InstantSvelteRoom.svelte.ts
Room abstraction and hooks: topic publish/subscribe, presence sync, typing indicator, and InstantSvelteRoom class; typed reactive room APIs.
Tests
client/packages/svelte/src/tests/InstantSvelteDatabase.svelte.test.ts
Comprehensive unit tests with mocked core covering non-reactive APIs, reactive hook lifecycles, subscription handling, caching, and room creation.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant SvelteComponent as Svelte Component
    participant InstantSvelteDB as InstantSvelteDatabase
    participant Reactor as Core Reactor
    participant CoreDB as InstantDB Core

    User->>SvelteComponent: mount
    SvelteComponent->>InstantSvelteDB: init() / construct
    InstantSvelteDB->>CoreDB: core_init / create core instance
    InstantSvelteDB-->>SvelteComponent: db instance

    rect rgba(100, 200, 255, 0.5)
    Note over SvelteComponent,Reactor: useQuery flow
    SvelteComponent->>InstantSvelteDB: useQuery(query)
    InstantSvelteDB->>SvelteComponent: { loading: true }
    InstantSvelteDB->>Reactor: subscribeQuery(query, callback)
    Reactor-->>InstantSvelteDB: onData(result)
    InstantSvelteDB-->>SvelteComponent: update data/loading
    end

    rect rgba(200, 255, 100, 0.5)
    Note over SvelteComponent,Reactor: presence/typing flow
    SvelteComponent->>InstantSvelteDB: db.room(type,id).usePresence()
    InstantSvelteDB->>Reactor: room.subscribePresence(callback)
    SvelteComponent->>InstantSvelteDB: publishPresence(data)
    InstantSvelteDB->>Reactor: reactor.publishPresence(topic, data)
    Reactor-->>InstantSvelteDB: broadcast presence to peers
    InstantSvelteDB-->>SvelteComponent: presence updates
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • stopachka
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.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
Title check ✅ Passed The title '[1/3] Add instant db svelte package' clearly describes the main change: introducing a new Svelte package for InstantDB.
Description check ✅ Passed The description provides relevant context about the new @instantdb/svelte package, implemented hooks, and important Svelte 5 implementation details like runes and file extensions.

✏️ 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 svelte-sdk
📝 Coding Plan
  • Generate coding plan for human review comments

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.

Without this entry the svelte package version doesn't get set
before publish, causing CI to fail on first publish.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions
Copy link
Contributor

View Vercel preview at instant-www-js-svelte-sdk-jsv.vercel.app.

Copy link
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: 2

🧹 Nitpick comments (1)
client/packages/svelte/src/tests/InstantSvelteDatabase.svelte.test.ts (1)

262-279: Use a valid ConnectionStatus value in the test.

The test passes 'connected' to the status callback, but based on the core API, valid ConnectionStatus values are: 'connecting', 'opened', 'authenticated', 'closed', 'errored'. Using 'authenticated' would better document expected behavior.

📝 Suggested fix
-      statusCb!('connected');
+      statusCb!('authenticated');

-      expect(status.current).toBe('connected');
+      expect(status.current).toBe('authenticated');
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@client/packages/svelte/src/tests/InstantSvelteDatabase.svelte.test.ts` around
lines 262 - 279, The test uses an invalid connection string; update the value
passed to the mocked subscription callback to a valid ConnectionStatus (e.g.
replace the `'connected'` argument to statusCb in the "updates when connection
status changes" test with `'authenticated'`) so the call from
mockCore.subscribeConnectionStatus and the assertion against
db.useConnectionStatus() use a proper ConnectionStatus value.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@client/packages/svelte/src/lib/InstantSvelteDatabase.svelte.ts`:
- Around line 165-173: The branch that copies previous state only executes when
prev is truthy, leaving prior query data visible when switching to an uncached
query; update the logic around coerceQuery/coerceQuery(q) +
this.core._reactor.getPreviousResult(coerced) so that you always compute const
prevState = stateForResult(prev) (allowing prev to be undefined) and then assign
result.isLoading, result.data, result.pageInfo, and result.error from prevState
unconditionally (or explicitly set result = stateForResult(undefined) when prev
is falsy) so the UI resets immediately when switching to an uncached query.

In `@client/packages/svelte/src/lib/InstantSvelteRoom.svelte.ts`:
- Around line 185-193: The effect using $effect in InstantSvelteRoom.svelte.ts
currently calls room.core._reactor.publishPresence(room.type, room.id, data) but
does not return the publisher disposer and also uses deps.forEach((d) => (typeof
d === 'function' ? d() : d)) which returns values into forEach; change the deps
tracking to not return a value (e.g. use for (const d of deps) { if (typeof d
=== 'function') d(); } or call void on the result) and return the disposer from
room.core._reactor.publishPresence(...) so the effect cleans up the previous
publisher on deps/data changes and on unmount (mirror the behavior in
InstantReactRoom.ts).

---

Nitpick comments:
In `@client/packages/svelte/src/tests/InstantSvelteDatabase.svelte.test.ts`:
- Around line 262-279: The test uses an invalid connection string; update the
value passed to the mocked subscription callback to a valid ConnectionStatus
(e.g. replace the `'connected'` argument to statusCb in the "updates when
connection status changes" test with `'authenticated'`) so the call from
mockCore.subscribeConnectionStatus and the assertion against
db.useConnectionStatus() use a proper ConnectionStatus value.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 5c92b9e3-7da3-4049-85c2-9c92c9bd06fa

📥 Commits

Reviewing files that changed from the base of the PR and between dda1eb0 and f2f3479.

⛔ Files ignored due to path filters (1)
  • client/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (10)
  • client/packages/svelte/.gitignore
  • client/packages/svelte/package.json
  • client/packages/svelte/src/lib/InstantSvelteDatabase.svelte.ts
  • client/packages/svelte/src/lib/InstantSvelteRoom.svelte.ts
  • client/packages/svelte/src/lib/index.ts
  • client/packages/svelte/src/lib/version.ts
  • client/packages/svelte/src/tests/InstantSvelteDatabase.svelte.test.ts
  • client/packages/svelte/svelte.config.js
  • client/packages/svelte/tsconfig.json
  • client/packages/svelte/vite.config.ts

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* const auth = db.useAuth();
* // auth.isLoading, auth.user, auth.error
*/
useAuth = (): AuthState => {
Copy link
Contributor

Choose a reason for hiding this comment

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

same question on this and the stuff below re: the use primitive

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Same answer re: use

Copy link
Contributor

@stopachka stopachka left a comment

Choose a reason for hiding this comment

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

Some thoughts!

Copy link
Contributor

@stopachka stopachka left a comment

Choose a reason for hiding this comment

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

Let's ship it!!

@nezaj
Copy link
Contributor Author

nezaj commented Mar 16, 2026

All merged via #2367

@nezaj nezaj closed this Mar 16, 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.

2 participants