Skip to content

Add inspector SQLite shell and property bindings#4414

Open
NathanFlurry wants to merge 9 commits intomainfrom
wider-inspector-shots
Open

Add inspector SQLite shell and property bindings#4414
NathanFlurry wants to merge 9 commits intomainfrom
wider-inspector-shots

Conversation

@NathanFlurry
Copy link
Member

Description

This adds a manual SQLite shell to the actor Inspector UI, including query execution, result rendering, and editable named-property inputs that re-run the preview. It also adds POST /inspector/database/execute support for both positional args and named properties, updates the raw SQLite binding helpers, and documents the new flow.

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How Has This Been Tested?

Ran pnpm exec vitest run tests/driver-memory.test.ts -t "POST /inspector/database/execute|GET /inspector/state returns actor state" in rivetkit-typescript/packages/rivetkit.

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes

@railway-app
Copy link

railway-app bot commented Mar 13, 2026

🚅 Deployed to the rivet-pr-4414 environment in rivet-frontend

Service Status Web Updated (UTC)
website 😴 Sleeping (View Logs) Web Mar 13, 2026 at 4:51 am
frontend-inspector 😴 Sleeping (View Logs) Web Mar 13, 2026 at 4:50 am
frontend-cloud 😴 Sleeping (View Logs) Web Mar 13, 2026 at 4:48 am
mcp-hub ✅ Success (View Logs) Web Mar 13, 2026 at 4:39 am
ladle ❌ Build Failed (View Logs) Web Mar 13, 2026 at 4:39 am

@NathanFlurry
Copy link
Member Author

NathanFlurry commented Mar 13, 2026

Screenshots

Tables

Tables

Query results

Query results

Inline edit

Inline edit

Staged edits

Staged edits

Updated rows

Updated rows

Verify applied result

Verify applied result

Verify discard result

Verify discard result

@pkg-pr-new
Copy link

pkg-pr-new bot commented Mar 13, 2026

More templates

@rivetkit/cloudflare-workers

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/cloudflare-workers@4414

@rivetkit/framework-base

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/framework-base@4414

@rivetkit/next-js

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/next-js@4414

@rivetkit/react

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/react@4414

rivetkit

pnpm add https://pkg.pr.new/rivet-dev/rivet/rivetkit@4414

@rivetkit/sql-loader

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/sql-loader@4414

@rivetkit/sqlite-vfs

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/sqlite-vfs@4414

@rivetkit/traces

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/traces@4414

@rivetkit/workflow-engine

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/workflow-engine@4414

@rivetkit/virtual-websocket

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/virtual-websocket@4414

@rivetkit/engine-runner

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/engine-runner@4414

@rivetkit/engine-runner-protocol

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/engine-runner-protocol@4414

commit: 9e79ce7

@claude
Copy link

claude bot commented Mar 13, 2026

Code Review

Overall this is a well-structured addition. Clean API design, solid test coverage for the happy paths, and good validation gating in the router. A few things worth looking at.

Functional Issues

1. normalizeSqlitePropertyBindings triple-duplicates every key

actor-inspector.ts lines 408-422: for an unprefixed key like foo, the function emits :foo, @foo, and $foo simultaneously. SQLite silently ignores the unused prefixes at runtime so it works, but a properties object with N keys becomes 3N bindings. A simpler approach would be to add : as the single default prefix for unprefixed keys, or scan the SQL to determine which prefix each placeholder actually uses.

2. extractNamedBindings matches inside string literals and comments

actor-database.tsx lines 940-943: the regex runs over the entire SQL string including single-quoted string literals and -- comments. A query like SELECT comment-style :note FROM t would surface note as a binding input in the UI even though it is not an actual parameter.

3. hasPositionalBindings flags question marks inside string literals

actor-database.tsx line 537: sql.includes is too broad. A query with a question mark inside a string literal triggers the positional-bindings warning and blocks execution even though no actual placeholder is present.

4. Conflict check misses non-array args

router.ts lines 308-319: the guard checks Array.isArray on body.args before checking body.properties. If body.args is present but not an array and body.properties is also provided, the conflict check is skipped. The subsequent isSqliteBindingArray check fires with args must be a SQLite binding array rather than use either args or properties, not both. Not a breakage, but the user gets a confusing error message.

Missing Test Cases

The new tests cover happy paths well. The following edge cases are not exercised:

  • Providing both args and properties simultaneously should return the conflict error
  • args with an invalid entry type should return 400
  • properties with an invalid value type should return 400
  • Calling the endpoint when the actor has no database should return an error
  • Empty or whitespace-only sql should return 400

Minor Nit: parseBindingDraft silent fallback

actor-database.tsx lines 962-964: when JSON.parse throws, the raw string is returned as the binding value with error: null. This is a reasonable UX choice, but a user cannot easily distinguish intentionally passing the string true vs. the boolean true. A small UI hint like bare text is treated as a string would help without changing behavior.

Checklist items

The ladle build in the Railway deployment is failing, worth confirming that is pre-existing and not introduced by this PR.

The normalizeSqlitePropertyBindings triple-prefix behavior and the bindingChangeToken debounce pattern in ActorDatabaseSqlShell would both benefit from a brief comment explaining their intent.

@claude
Copy link

claude bot commented Mar 13, 2026

PR Review: Add inspector SQLite shell and property bindings

Overall this is a solid feature addition with good test coverage and documentation. The UI architecture is clean and the backend API is well-structured.


Issues

1. normalizeSqlitePropertyBindings triples every key

File: rivetkit-typescript/packages/rivetkit/src/inspector/actor-inspector.ts

For an unprefixed key like value, the function writes :value, @value, AND \$value into the binding object. Whether this is safe depends on wa-sqlite silently ignoring unmatched keys. The safer approach: require callers to include the prefix character, or detect which prefix appears in the SQL and emit only that one.


2. #withDatabase result cast is unsafe

File: rivetkit-typescript/packages/rivetkit/src/inspector/actor-inspector.ts

The pattern uses let result: T | undefined then return result as T. If Lock.lock() does not re-throw callback errors, result stays undefined and is silently returned. Worth verifying the Lock contract, and ideally returning the value directly from lock() to avoid the cast.


3. isSqliteBindingObject heuristic may break existing queries

Files: rivetkit-typescript/packages/rivetkit/src/db/mod.ts and db/drizzle/mod.ts

The detection uses args.length === 1 && isSqliteBindingObject(args[0]). But isSqliteBindingObject matches any plain object with SQLite-primitive values. A query with a single JSON column value {x: 1} would now take the named-binding path, silently breaking previously working queries. Suggestion: only treat args[0] as named bindings when it contains a key starting with :, @, or \$.


4. DEFAULT_SQL references the test fixture table

File: frontend/src/components/actors/actor-database.tsx

test_data is a driver-test fixture that does not exist in real actors. Users opening the SQL shell will see a broken default query. The default should be something generic (e.g. SELECT name FROM sqlite_master WHERE type = ‘table’;) or empty.


5. No error-path tests for POST /inspector/database/execute

File: rivetkit-typescript/packages/rivetkit/src/driver-test-suite/tests/actor-inspector.ts

All three new tests cover happy paths only. Suggested error cases: empty sql returns 400, both args and properties provided returns 400, non-array args returns 400, SQL syntax error returns an error response rather than 500.


6. parseBindingDraft coerces values non-obviously

File: frontend/src/components/actors/actor-database.tsx

Typing hello binds the string “hello” (JSON.parse fails, falls back to raw string), but typing 123 binds the number 123. This should be documented, a type selector added, or all inputs consistently treated as strings.


7. createResultColumns uses boolean false for notnull and pk

File: frontend/src/components/actors/actor-database.tsx

SQLite PRAGMA table_info returns notnull and pk as integers (0/1). The inspector now reads these as numbers. Using false (boolean) in createResultColumns may cause type errors where code checks column.pk > 0. Use 0 instead.


Minor observations

  • GET /inspector/state test now expects isStateEnabled: true — good catch; an inline comment would help future readers understand the addition.
  • Switching from SELECT * LIMIT 1 to PRAGMA table_info is a meaningful schema accuracy improvement worth highlighting in the PR description since it changes the response shape.
  • Table names are correctly escaped before PRAGMA table_info calls. Good.
  • SQL syntax errors from wa-sqlite may produce opaque messages; consider normalizing them in the error handler.

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.

1 participant