refactor: migrate runtime context from global store to scoped RuntimeClient#8932
Closed
ericpgreen2 wants to merge 27 commits intomainfrom
Closed
refactor: migrate runtime context from global store to scoped RuntimeClient#8932ericpgreen2 wants to merge 27 commits intomainfrom
RuntimeClient#8932ericpgreen2 wants to merge 27 commits intomainfrom
Conversation
8 tasks
…hase 1)
Introduce the foundation for replacing the global mutable `runtime`
store with scoped Svelte context.
- Generate ConnectRPC TypeScript service descriptors for RuntimeService,
QueryService, and ConnectorService via buf (new buf.gen.runtime.yaml)
- Add RuntimeClient class that encapsulates transport, JWT lifecycle,
and lazy service client creation
- Add RuntimeProvider component that creates a RuntimeClient, sets it in
Svelte context, and bridges to the global store for unmigrated consumers
- Add useRuntimeClient() context helper
- Wire RuntimeProvider into web-admin project layout with {#key} on
host::instanceId for correct re-mounting on project navigation
- Wire RuntimeProvider into web-local root layout
- Extract JWT expiry constants to shared constants.ts
Add a build-time code generator that reads ConnectRPC *_connect.ts service descriptors and produces TanStack Query hooks for Svelte. For each unary query method, generates 4 tiers: raw RPC function, query key factory, query options factory, and convenience createQuery hook. Mutation methods get 3 tiers: raw function, mutation options, and createMutation hook. Output: 59 queries + 28 mutations across QueryService, RuntimeService, and ConnectorService. Streaming methods (watchFiles, watchResources, watchLogs, completeStreaming, queryBatch) are skipped. Generated hooks take RuntimeClient as first argument and inject instanceId automatically, matching the Phase 1 context architecture.
…ase 3)
Update cache invalidation and query matchers to support both the old
URL-path query key format ("/v1/instances/{id}/...") and the new
service/method format ("QueryService", "metricsViewAggregation",
instanceId, request).
This enables incremental migration: as consumers switch from Orval
hooks to v2 generated hooks, both key formats are correctly matched
for invalidation, profiling, metrics view, and component queries.
The generator was producing `PartialMessage<Omit<Request, "instanceId">>`, but `Omit<...>` strips the `Message<T>` constraint that `PartialMessage` requires. Fix by swapping to `Omit<PartialMessage<Request>, "instanceId">`. Also detect at generation time whether each request type actually has an `instanceId` field; methods like `ListInstances` and `IssueDevJWT` don't have it and should not receive auto-injection.
When RuntimeProvider calls setRuntime with no JWT (local dev), the
equality check compared authContext ("user") against current.jwt?.authContext
(undefined), always returning false. This caused the store to emit a new
value on every call, triggering an infinite reactive loop:
RuntimeProvider bridge → store update → layout re-render → bridge again.
Fix by treating JWT as unchanged when both old and new JWT are absent,
regardless of authContext.
Generated hooks now accept/return Orval-compatible types (V1*) in their public API, converting to/from proto internally via fromJson/toJson. This lets consumers switch to v2 hooks without changing their existing type usage (V1Expression, V1Resource, etc.). The generator reads the Orval schemas file at generation time to determine which V1 types exist. Response types always use V1 (100% coverage). Request types use V1 when available (~25%, POST endpoints) and fall back to PartialMessage<ProtoType> for GET endpoints.
The generated hooks now accept a TData type parameter (defaulting to the response type), enabling select transforms that narrow the return type. This mirrors the Orval pattern and avoids forcing consumers to use derived stores as workarounds.
Proto fromJson() rejects undefined field values, but callers may pass them (e.g., TanStack Query's pageParam starts as undefined, or reactive props that resolve asynchronously). Orval's HTTP client silently omitted undefined values; the JSON bridge must do the same.
Proto3 toJson() omits fields with default values (0, "", false) by default. gRPC-Gateway includes them. This caused missing fields like low: 0 in histogram bins, breaking D3 scale computations and rendering blank histograms for columns with data starting near zero.
…st objects
The shallow `stripUndefined` only removed top-level undefined values.
Nested objects like `timeRange: { start: undefined }` passed through
to `fromJson()` which rejects undefined, causing JSON decode errors.
Port the two-level heap request queue as a ConnectRPC interceptor. Maps method names (instead of URLs) to priorities and controls concurrency via the same architecture as HttpRequestQueue.
Migrate 8 files from the global runtime store to useRuntimeClient(): - ConnectorExplorer, ConnectorEntry, TableEntry, TableSchema, TableMenuItems, TableWorkspaceHeader, ConnectorRefreshButton - ColumnProfile Exercises all key migration patterns: - $runtime.instanceId → useRuntimeClient() + client.instanceId - Orval createQuery hooks → v2 generated hooks (request object style) - Orval createMutation → v2 generated mutation hooks - Structural type compatibility between proto and Orval response types
Migrate DatabaseExplorer, DatabaseEntry, DatabaseSchemaEntry, TableInspector, and References to use useRuntimeClient() from context. This demonstrates eliminating instanceId prop drilling: child components now get the RuntimeClient from Svelte context instead of receiving instanceId as a prop from parents.
… v2 RuntimeClient - column-profile/queries.ts: all functions accept RuntimeClient instead of instanceId - connectors/selectors.ts: useListDatabaseSchemas, useInfiniteListTables, useGetTable accept RuntimeClient; useIsModelingSupported* functions left as-is (callers out of scope) - Column profile components (NumericProfile, TimestampProfile, VarcharProfile, NestedProfile): replace $runtime with useRuntimeClient() - WorkspaceInspector: replace $runtime with useRuntimeClient(), switch Orval hooks to v2 - Canvas components (CanvasInitialization, KPIProvider, PageEditor): replace $runtime with useRuntimeClient(), switch Orval hooks to v2 - Update already-migrated callers to pass client instead of client.instanceId
Reverts the derived-store workarounds in queries.ts and selectors.ts, using select transforms directly as the v2 code generator now supports generic TData inference.
…ntimeClient Chart providers (batch 1): all 6 providers now accept RuntimeClient instead of Writable<Runtime>, use v2 query hooks, and remove runtime from derived store inputs since the client is a stable object. Canvas leaf components (batch 2): 13 Svelte components migrated from $runtime store to useRuntimeClient() context. CanvasStore extended with runtimeClient field to bridge chart providers in canvas context.
…re stores to v2 Bridge pattern: adds runtimeClient alongside runtime in StateManagers. Migrates validSpecStore and timeRangeSummaryStore to v2 hooks, removing runtime from their derived() dependencies.
…ntimeClient Migrates 5 TS modules that receive StateManagers: timeseries-data-store, totals-data-store, multiple-dimension-queries, dimension-filters selector, and dashboard selectors. Removes ctx.runtime from derived() dependencies and switches to v2 query hooks.
…seRuntimeClient Replaces direct `runtime` store imports with `useRuntimeClient()` across 13 dashboard Svelte components. Uses stable `client.instanceId` instead of reactive `$runtime.instanceId`.
- Add ConnectRPC URL routing to `DashboardFetchMocks` (handles
`/rill.runtime.v1.{Service}/{Method}` requests with proper body
decoding and RFC 3339 timestamp normalization)
- Inject `RuntimeClient` context in test renders that mount components
calling `useRuntimeClient()`
…o v2 RuntimeClient Replace `get(runtime).instanceId` with explicit `instanceId` parameters in tdd-export, pivot-export, and dimension-table-export. Switch pivot-queries from Orval hook to v2 `createQueryServiceMetricsViewAggregation`, threading `runtimeClient` through `PivotDashboardContext`.
… explicit instanceId Add `instanceId` parameter to `deriveInterval()` and `resolveTimeRanges()` instead of reading from the global `runtime` store. Thread `instanceId` through callers: DashboardStateSync, Filters, FiltersForm, canvas TimeState, and explore-mappers utils.
…tore to v2 RuntimeClient - Remove unused `runtime` property from dashboard and canvas StateManagers - Delete dead code: `getValidDashboardsQueryOptions` and `getMetricsViewSchemaOptions` - Migrate 10 canvas Svelte components to `useRuntimeClient()` - Migrate canvas markdown `util.ts` to accept explicit `instanceId` parameter - Migrate 2 explores Svelte components to `useRuntimeClient()`
…move dead code Migrate leaf query option factories, intermediate callers, and module-level singletons to accept `client: RuntimeClient` instead of reading the global `runtime` store. Delete dead code (`getCanvasQueryOptions`, `utils.ts`). Chat context functions updated as necessary follow-through from leaf factory signature changes.
…eClient` Migrate ~100 files across chat, alerts, scheduled reports, file management, entity management, workspaces, sources, models, metrics-views, connectors, explore-mappers, exports, and other features from the global `runtime` store to `useRuntimeClient()` / `RuntimeClient` parameter threading. Key changes: - Add `host` property to `RuntimeClient` class - Convert `canvasChatConfig` to `createCanvasChatConfig(client)` factory - Thread `RuntimeClient` through `Conversation` and `ConversationManager` - Migrate `resource-selectors.ts` query option factories to accept `client` - Migrate chat picker data (models, canvases) to accept `client` - Migrate `connectors/code-utils.ts`, `file-artifact.ts`, `new-files.ts`, `submitAddDataForm.ts`, `explore-mappers/*.ts` to accept instanceId/client - Migrate `vega-embed-options.ts` to accept `RuntimeClient` - Migrate `RillIntakeClient` to accept `host` parameter - All `.svelte` callers updated to use `useRuntimeClient()`
Replace the old `runtime-store` mock with a `RuntimeClient` stub, matching the updated `Conversation` constructor signature.
…meClient - Create `local-runtime-config.ts` with shared `LOCAL_HOST` and `LOCAL_INSTANCE_ID` constants for web-local - Migrate web-local load functions and layout to use constants instead of reading from the runtime store - Add `getJwt` parameter to `SSEFetchClient.start()`, removing its direct import of the runtime store - Thread `RuntimeClient` through `updateDevJWT` (dual-write bridge) - Decouple `local-service.ts` from runtime store via `setLocalServiceHost()` - Replace `Runtime` type import in `selectors.ts` with inline type - Rewrite `query-options.ts` to use `fetch` instead of `httpClient` - Rewrite `open-query.ts` to use `fetch` instead of `httpClient` - Rewrite `getFeatureFlags()` to use `fetch` instead of `httpClient` - Migrate `download-report.ts` to accept `host` via mutation data
e2e0ca5 to
2102ddd
Compare
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.
Replaces the global mutable
runtimestore with a scopedRuntimeClientprovided via Svelte context. This is the infrastructure and consumer migration half of the runtime context refactor described in the tech design.RuntimeClientclass,RuntimeProvidercomponent, and ConnectRPC-based code generator that produces TanStack Query hooks from protobuf definitions$runtime.instanceId→useRuntimeClient()acrossweb-common,web-admin, andweb-local305 files changed. No API hook changes yet — all files still call Orval-generated hooks, just with
clientinstead ofinstanceIdas the first argument. The Orval → v2/gen hook migration and legacy code deletion happen in the follow-up PR.See tech design: #8590
Checklist:
Developed in collaboration with Claude Code