Fix broken sources panel, stream-quota crash, token clipboard leak + code-review findings#14
Merged
Conversation
…face stream errors - /api/apps called GET /users/:id/apps, which does not exist in the Inform API (404 always). Connected sources live on the single-user GET, keyed by uid: the panel now calls GET /organizations/:org/users/:uid and renders the sources[] array (type, connected_at, last_processed_at). The copy-curl command was updated to match. - Stream setup no longer crashes the app. Sandbox orgs cap at 5 streams (documented limit); a 422 quota failure now logs a warning with cleanup curl commands and the app starts without live streaming. /api/stream/connect returns 503 and the Connect button is disabled; Replay keeps working. - sseProxy: non-2xx upstream responses (e.g. bad token) were silently dropped because plain JSON bodies never match the SSE frame delimiter. They now surface as a stream_error SSE event rendered in the feed. - Remove leftover debug console.log in /api/users. Verified against the live Inform API: sources render for a real user, replay streams real events, 20/20 jest tests pass. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- A missing DATAGEN_URL locked the entire workbench behind the
"Configuration Required" screen (three separate gates: config file
parsing, localStorage re-validation, and the /api/config dev route).
Only the Generate Data panel actually needs it: the app now unlocks
with just ORG_TOKEN, ORG_ID, and API_URL, and the Generate Data
service is disabled with an inline explanation until a Data Generator
URL is configured. executeApiRequest refuses generate-data requests
with no datagen URL rather than firing at an empty base.
- Pagination total read summary.total_count, but the API returns
{ data, meta: { offset, limit, total, sort } } — total was always
undefined. Now reads meta.total (summary kept as fallback), and
hasMore compares against the real total when known.
- Document that offset is a 0-indexed page index per the Inform API
docs, and mark DATAGEN_URL as optional in both READMEs and the
config-upload help text.
Verified live: workbench unlocks without DATAGEN_URL with Generate Data
disabled; with it, generation works end to end through /api/proxy;
users list shows "Showing 1-50 of 137 users". Lint 0 errors, build clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…license
- LICENSE: root copyright said "Chartspan Medical Technologies" (template
artifact); now Validic, Inc. Added the missing apps/explorer/LICENSE.
- app.js renderTable: escape source.type — the one unescaped interpolation.
- EventSource lifecycle: a finished replay (or a fatal stream_error like a
bad token) ends the server response, which native EventSource treats as a
drop and reconnects forever — re-replaying history or stacking identical
error rows every ~3s. Streams are now mode-aware: replay closes on
error/end (with an explicit end-of-replay row), live connect keeps native
reconnect but closes on stream_error.
- Stale-response guards: switching users mid-fetch no longer lets the slow
response render (or cache) under the newly selected user.
- API errors render as errors: failed /api/apps and /api/data responses
showed the empty state ("No data found") and were cached, so retries
never happened. Now they show the error and skip the cache.
- server.js: user_id is URL-encoded at all upstream interpolation sites
(path-traversal hardening); ensureUser throws a clear message if a user
row lacks a marketplace token instead of an unguarded TypeError.
- README (sub-app): setup steps now work from the monorepo layout; removed
the nonexistent GET /users/:id/apps endpoint from the feature table.
Tests: 20 → 23, all passing.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…, races - ResponsePanel: Copy JSON copied the raw response object, putting the live org token (actualRequest.url / Token header) on the clipboard while the on-screen view showed it redacted. Copies are now redacted the same way. - ConfigPanel: "stored in browser memory only" was false — uploaded configs persist to localStorage. The note now says so truthfully. - ResponsePanel: user-list detection keyed off marketplace/mobile presence; now keys off uid so user cards and pagination survive any real payload. - Deleted dead code: the never-wired "Fetch All Users" feature (130-line lib + unreachable buttons) and the unreachable "Impact" help mode; fixed a help step describing a source filter that doesn't exist for Get User Data. - InformDemo: stale-request guard (switching services mid-flight no longer shows the old service's response) and history entries now capture the auto-generated create-user uid so re-running them reproduces the request. - API routes: caller-supplied URLs are validated (well-formed, http/https) before fetching; root README notes these are local dev tools and the explorer should not be deployed publicly as-is. - RequestPreview: copy-curl button tooltip warns the copied command contains the live token (the preview shows it redacted). Lint 0 errors, build clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The Chartspan Medical Technologies attribution is correct — ChartSpan acquired Validic — not a template artifact as the earlier review-driven change assumed. Root LICENSE restored verbatim; the new explorer LICENSE now matches the root. apps/quickstart/LICENSE keeps its pre-existing Validic, Inc. line (attribution consistency across sub-licenses is a legal call, not a code fix). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Lead with what Inform is and what this repo is for, not just an app table - Numbered setup with the expected boot output, so readers know it worked - Panel-by-API-call table and the provision → connect → wait → verify pattern every integration follows - Repo layout, troubleshooting table (uid vs id 404s, stream quota, first-sync delay, explorer config, rate limit) - Fix dead links: developer.validic.com/agents.txt → llms.txt (the live agent index), api.dashboard.validic.com → dashboard.validic.com; same fixes in agents.txt - Add Node + CI badges Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.
Summary
Five commits from an end-to-end testing pass of both sample apps against a live sandbox org, followed by a full-repo code review. Every fix was verified against the production Inform API; test suite grew 16 → 23 (all passing), explorer lint/build clean.
Quickstart app
GET /users/:id/apps, which does not exist in the Inform API (404 always). It now reads thesources[]array from the uid-keyed single-user GET, matching the documented API. The copy-curl command and README were updated to match./api/stream/connect. Replay keeps working.stream_errorevent rendered in the feed instead of being dropped.source.typein the data table, stale-response guards when switching users mid-fetch, API errors render as errors instead of cached empty states,user_idURL-encoded at upstream interpolation sites, clearer boot error if a user payload lacks a marketplace token.Explorer app
DATAGEN_URLno longer blocks the whole app: only the Generate Data panel requires it; the panel is disabled with an inline explanation until it's configured./api/configand the config upload accept token/org/API URL alone.meta.total(the actual response envelope) instead ofsummary.total_count, which was always undefined;hasMoreuses the real total when known.apps/explorer/LICENSE.Verified
sources[],metaenvelope, stream quota).🤖 Generated with Claude Code