Revamp site & playground; new RPC + live + scope features (#74)#74
Merged
Conversation
There was a problem hiding this comment.
Pull request overview
This PR modernizes the Typegres demo/playground and extends core library capabilities to support (1) capability-rooted RPC over exoeval with streaming results, and (2) scoped queries that carry a per-request “principal/context” tag through relation traversal and hydration.
Changes:
- Add scoped query context propagation (
Table.scope(ctx)+Table.contextOf(row)) and update codegen to preserve scope through relation methods. - Improve type/runtime ergonomics for expressions and rows (e.g.,
TsTypeOfnon-Any→never,SetRowaccepts expressions; addAny.in(...); hardenAny.from(...)against accidental class-instance params). - Replace the site’s Next-based demo with an Astro-based static site + new in-browser playground, including live queries and RPC streaming.
Reviewed changes
Copilot reviewed 73 out of 77 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| tsdown.config.ts | Adds exoeval entry point to the build outputs. |
| src/types/runtime.ts | Refines TsTypeOf, SetRow, and runtime guards for update expressions. |
| src/types/overrides/any.ts | Adds Any.in(...) and tightens Any.from(...) runtime validation. |
| src/types/index.test.ts | Adds/updates type & runtime tests for TsTypeOf, Any.in, and Any.from. |
| src/tables/generate.ts | Adds @tool() decoration defaults + scope propagation in generated relations; introduces block-update mode. |
| src/tables/generate.test.ts | Tests for new table generation/update behavior and decorator preservation. |
| src/table.ts | Introduces scoped query tagging API (scope, context, contextOf) and context typing. |
| src/scope.test.ts | End-to-end tests for scope propagation across hydration and relation hops. |
| src/rpc.test.ts | Updates RPC usage to pass captures via second argument. |
| src/live/ISSUES.md | Documents a new live-update ambiguity issue and suggested fixes. |
| src/live/extractor.ts | Adjusts runLiveIteration DB typing to Database<any>. |
| src/live/events.ts | Moves events-table DDL out to a standalone module; re-exports for compatibility. |
| src/live/events-ddl.ts | New standalone module exporting events table name + DDL statements. |
| src/live/bus.ts | Adds subscription cancellation to unblock parked consumers on stop/shutdown. |
| src/index.ts | Re-exports RPC/tooling and live-events entry points; makes typegres generic over context type. |
| src/exoeval/rpc.ts | Changes RawChannel to streaming, adds hybrid run() return (thenable + async iterable), improves safeStringify. |
| src/exoeval/rpc.test.ts | Adds tests for captures-as-arg, streaming behavior, and array non-streaming semantics. |
| src/exoeval/index.ts | Re-exports tool and RPC utilities from exoeval package entry. |
| src/database.ts | Makes Database generic over context; forwards context into db.Table; ensures live events DDL exists on startLive; abort-aware live iteration. |
| src/builder/update.ts | Allows SET values to be typed expressions (Any) without re-wrapping. |
| src/builder/update.test.ts | Adds coverage for .set() with expressions and returning projections. |
| src/builder/query.ts | Documents/locks RowTypeToTsType behavior; adds .live(db) terminator; broadens db arg types. |
| src/builder/query.test.ts | Pins nested scalar typing + verifies row method keys become never. |
| src/builder/insert.ts | Broadens db arg typing to Database<any>. |
| src/builder/delete.ts | Broadens db arg typing to Database<any>. |
| site/vitest.config.ts | Adds SWC decorators support for vitest and widens deps handling for file:.. typegres. |
| site/tsconfig.json | Switches to Astro strict tsconfig base and updates includes/excludes. |
| site/tailwind.config.js | Adds table flash animations for the playground output UI. |
| site/src/styles/globals.css | New consolidated global styles for Astro site. |
| site/src/pages/play.astro | Adds /play route for the new playground. |
| site/src/pages/index.astro | Adds Astro home route wrapper around the React home page component. |
| site/src/pages/docs.astro | Static redirect page for typedoc output under /api/. |
| site/src/pages/_PlayWidgets.tsx | Widget UI + code stamping for the playground; uses Any.in and live/execute terminators. |
| site/src/pages/_PlayPaths.ts | Centralizes widget file path constants. |
| site/src/pages/_PlayPageInner.tsx | Eager Monaco/editor shell with lazy-loaded active output area. |
| site/src/pages/_PlayPage.tsx | Client-only React entry for Astro with error boundary wrapper. |
| site/src/pages/_PlayActiveArea.tsx | Lazy-loaded runtime area: runs/stops RPC streams, renders table/SQL, captures .debug() output. |
| site/src/pages/_HomePage.tsx | Updates home content and removes Next-specific UI artifacts. |
| site/src/layouts/BaseLayout.astro | New Astro base layout w/ meta tags and plausible analytics. |
| site/src/demo/widgets/orders.ts | Demo widget script for orders (live query). |
| site/src/demo/widgets/inventory.ts | Demo widget script for inventory (live query + debug). |
| site/src/demo/server/api.ts | New capability-rooted API and in-memory RPC client wiring for the demo. |
| site/src/demo/seed.ts | New demo DDL + seed data for PGlite runtime. |
| site/src/demo/schema/users.ts | Demo schema class for users with @tool() fields/relations + live transformer. |
| site/src/demo/schema/shipments.ts | Demo schema class for shipments + relations + live transformer. |
| site/src/demo/schema/organizations.ts | Demo schema class for organizations + relations + live transformer. |
| site/src/demo/schema/orders.ts | Demo schema class for orders + row action method demonstrating SQL CASE update. |
| site/src/demo/schema/order_lines.ts | Demo schema class for order_lines + relations + live transformer. |
| site/src/demo/schema/locations.ts | Demo schema class for locations + relations + live transformer. |
| site/src/demo/schema/inventory_positions.ts | Demo schema class for inventory_positions + row action method for adjustments. |
| site/src/demo/schema/customers.ts | Demo schema class for customers + relations + live transformer. |
| site/src/demo/runtime.ts | Boots PGlite + runs migrations/seed + starts live bus for the playground. |
| site/src/demo/demo.test.ts | E2E tests covering scoped reads, Any.in, relation traversal scope, live streaming, stop semantics, and debug logging. |
| site/src/components/SyntaxHighlight.tsx | Removes Next "use client" directive (Astro/React islands). |
| site/src/components/CodeEditor.tsx | Replaces Next dynamic import with React.lazy for Monaco editor integration. |
| site/package.json | Switches site from Next to Astro; updates deps/scripts; uses typegres: file:... |
| site/next.config.js | Removes Next configuration (deleted). |
| site/next-env.d.ts | Removes Next TypeScript env file (deleted). |
| site/index.html | Removes prior static entrypoint (deleted). |
| site/globals.css | Removes prior global styles file (deleted). |
| site/astro.config.mjs | Adds Astro config with SWC decorators, PGlite asset handling, and dev fs widening. |
| site/app/play/page.tsx | Removes Next App Router playground page (deleted). |
| site/app/layout.tsx | Removes Next root layout (deleted). |
| site/app/icon.svg | Removes Next icon asset (deleted). |
| site/app/docs/route.ts | Removes Next redirect route (deleted). |
| site/.gitignore | Adds Astro build artifacts and generated/public outputs to ignores. |
| site/.eslintrc.json | Removes Next ESLint config (deleted). |
| README.md | Updates examples, status section, and adds link to /play demo. |
| package.json | Adds ./exoeval export path for consumers. |
| ISSUES.md | Marks several “critical” issues as fixed and updates roadmap items. |
| examples/basic/typegres.config.ts | Updates config import path to typegres root export. |
| examples/basic/src/tables/toys.ts | Updates imports to typegres root export. |
| examples/basic/src/tables/teams.ts | Updates imports to typegres root export. |
| examples/basic/src/tables/microchips.ts | Updates imports to typegres root export. |
| examples/basic/src/tables/dogs.ts | Updates imports to typegres root export and consolidates sql import. |
| examples/basic/src/tables/collars.ts | Updates imports to typegres root export. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+7
to
+9
| import type { OperatorRoot } from "./server/api"; | ||
|
|
||
| export const db = await typegres<OperatorRoot>({ type: "pglite" }); |
Comment on lines
+1
to
+4
| import { Int8, Text, Timestamptz, TypegresLiveEvents, sql, tool, type Database } from "typegres"; | ||
| import { db } from "../runtime"; | ||
| import type { OperatorRoot } from "../server/api"; | ||
| import { Customers } from "./customers"; |
Comment on lines
+1
to
+4
| import { Int8, Text, TypegresLiveEvents, sql, tool, type Database } from "typegres"; | ||
| import { db } from "../runtime"; | ||
| import type { OperatorRoot } from "../server/api"; | ||
| import { Locations } from "./locations"; |
| @tool() organization_id = (Int8<1>).column({ nonNull: true }); | ||
| // relations | ||
| @tool() organization() { return Organizations.scope(Locations.contextOf(this)).where(({ organizations }) => organizations.id["="](this.organization_id)).cardinality("one"); } | ||
| @tool() inventory_positions() { return InventoryPositions.scope(Locations.contextOf(this)).where(({ inventory_positions }) => inventory_positions.location_id["="](this.id)).cardinality("one"); } |
Comment on lines
18
to
22
| } | ||
|
|
||
| const MonacoEditor = dynamic(() => import("@monaco-editor/react"), { | ||
| ssr: false, | ||
| }); | ||
| const MonacoEditor = lazy(() => import("@monaco-editor/react")); | ||
|
|
||
| export interface CodeEditorProps { |
Comment on lines
+11
to
+23
| sql`CREATE TABLE organizations ( | ||
| id int8 GENERATED ALWAYS AS IDENTITY PRIMARY KEY, | ||
| name text NOT NULL, | ||
| slug text NOT NULL UNIQUE | ||
| )`, | ||
| sql`CREATE TABLE users ( | ||
| id int8 GENERATED ALWAYS AS IDENTITY PRIMARY KEY, | ||
| organization_id int8 NOT NULL REFERENCES organizations(id), | ||
| name text NOT NULL, | ||
| email text NOT NULL UNIQUE, | ||
| role text NOT NULL, | ||
| token text NOT NULL UNIQUE | ||
| )`, |
1. RPC: exoeval safely interprets restricted JS against `@tool`-marked
methods; streaming via AsyncIterable.
2. Live queries: `qb.live(db)` re-yields rows when committed mutations
would change the result.
3. Principals: `.scope(ctx)` / `.contextOf(row)` thread a principal
object through the query graph (codegen flows it n joins deep).
4. Site: Next → Astro.
5. Playground: WMS-themed demo exercising RPC + live + scoped reads.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
@tool-markedmethods; streaming via AsyncIterable.
qb.live(db)re-yields rows when committed mutationswould change the result.
.scope(ctx)/.contextOf(row)thread a principalobject through the query graph (codegen flows it n joins deep).