Skip to content

Commit d4fede1

Browse files
mpstatonclaude
andcommitted
fix(workspace, apps, shell): resolve the workspace WS endpoint from PUBLIC_WS_URL in one place, not sixteen literals
Org Workbench rendered its chrome and nothing else on augment.didi.sh: no roster, no organizations, a red `closed` pill in the corner. The cause was a single line repeated across the app tree — every remote declared `const WS_URL = 'ws://localhost:3001/ws'` and never read the environment, so a deployed surface opened its data socket against the *visitor's* laptop. It could not have worked in production for two independent reasons: the host is wrong, and `ws://` from an `https://` origin is blocked as mixed content. Local dev hid it perfectly, because the operator's machine really is running workspace-service on :3001. Three of the sixteen affected remotes are deployed, which took down the whole Augment-from-DB flow rather than one surface. The endpoint now has exactly one home. `packages/workspace/src/ws-url.ts` exports `resolveWsUrl()` and `resolveHttpBase()`, and `TransportConfig.url` becomes optional — omit it and the transport resolves from PUBLIC_WS_URL on every connect attempt. That is the part that makes the bug structurally unavailable: the failure mode was never a logic error, it was copy-paste into a new remote, and the copy-pasteable thing no longer exists. Every call site was converted, including the two that had quietly got it right (chat, and corpora-curator's real client in curation.svelte.ts) so there is no second pattern to imitate, and the WorkspaceSwitcher tooltip stops telling operators that localhost is unreachable when the endpoint is somewhere else entirely. Verified by building org-workbench with PUBLIC_WS_URL set and reading the emitted bundle: the resolver compiles to the prod endpoint with localhost left only as the dead fallback branch. A new guard in the workspace suite sweeps apps/, shell/, and packages/ for the literal and fails with the offending filenames; planting the old line back into org-workbench makes it fail, so it is not vacuous. svelte-check is clean across all 17 surfaces. Deploy note: PUBLIC_* is baked at build time, so the three deployed remotes need a rebuild, not a restart, once their variables are set. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017HuzSPdPK4QEhs7eztHgoC
1 parent 4b42030 commit d4fede1

24 files changed

Lines changed: 164 additions & 50 deletions

File tree

apps/affiliation-rating-resolver/src/App.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// context-v/specs/Augment-From-Affiliations.md.
99
1010
import { onMount } from 'svelte';
11-
import { workspace, type RecordSet, type Row } from '@augment-it/workspace';
11+
import { workspace, type RecordSet, type Row, resolveWsUrl } from '@augment-it/workspace';
1212
import ColumnMapper from './components/ColumnMapper.svelte';
1313
import { normalizeRatingRecord, guessMapping, MAPPING_NONE } from './lib/normalize';
1414
import {
@@ -23,7 +23,7 @@
2323
import type { RatingFieldMapping, RatingNormRecord, AffiliationDetail, Link, CorpusEntry } from './lib/types';
2424
2525
const TOKEN_KEY = 'augment-it:session-token';
26-
const WS_URL = 'ws://localhost:3001/ws';
26+
const WS_URL = resolveWsUrl();
2727
const ACTIVE_RECORD_SET_KEY = 'augment-it:active-record-set';
2828
const MAPPING_KEY_PREFIX = 'augment-it:affiliation-rating-resolver:mapping:';
2929

apps/chat/src/App.svelte

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
// is established independently (no shared workspace singleton).
77
88
import { onMount } from 'svelte';
9-
import { workspace } from '@augment-it/workspace';
9+
import { workspace, resolveWsUrl } from '@augment-it/workspace';
1010
import CharacterCastRow from './CharacterCastRow.svelte';
1111
import ChatSurface from './ChatSurface.svelte';
1212
@@ -15,9 +15,7 @@
1515
// even when mounted inside the shell, so it needs the same env-configured
1616
// WS_URL the shell and corpora-curator each read (rsbuild inlines
1717
// PUBLIC_-prefixed vars into import.meta.env at build time).
18-
const WS_URL =
19-
((import.meta as { env?: Record<string, string> }).env?.PUBLIC_WS_URL as string | undefined) ||
20-
'ws://localhost:3001/ws';
18+
const WS_URL = resolveWsUrl();
2119
2220
let connectionStatus = $state<'connecting' | 'open' | 'closed' | 'error' | 'auth_required'>('connecting');
2321

apps/corpora-curator/src/App.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
<script lang="ts">
22
import { onMount } from 'svelte';
3-
import { workspace } from '@augment-it/workspace';
3+
import { workspace, resolveWsUrl } from '@augment-it/workspace';
44
import { curation } from './curation.svelte';
55
import CorpusPicker from './CorpusPicker.svelte';
66
import SourceList from './SourceList.svelte';
77
import SourceDetail from './SourceDetail.svelte';
88
9-
const WS_URL = 'ws://localhost:3001/ws';
9+
const WS_URL = resolveWsUrl();
1010
1111
onMount(() => {
1212
curation.init();

apps/corpora-curator/src/curation.svelte.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// $state is assigned in the constructor (not as a class-field initializer) to
99
// match the workspace package's placement-invariant note about field lowering.
1010

11-
import { workspace, WORKSPACE_CHANGED_EVENT, type WorkspaceSummary } from '@augment-it/workspace';
11+
import { workspace, WORKSPACE_CHANGED_EVENT, type WorkspaceSummary, resolveWsUrl } from '@augment-it/workspace';
1212
import type { ExtractKind, Source, Strategy } from './types';
1313

1414
const TOKEN_KEY = 'augment-it:session-token';
@@ -18,9 +18,7 @@ const TOKEN_KEY = 'augment-it:session-token';
1818
// shell and chat each read (rsbuild inlines PUBLIC_-prefixed vars into
1919
// import.meta.env at build time — applies to plain .ts modules too, not
2020
// just .svelte files).
21-
const WS_URL =
22-
((import.meta as { env?: Record<string, string> }).env?.PUBLIC_WS_URL as string | undefined) ||
23-
'ws://localhost:3001/ws';
21+
const WS_URL = resolveWsUrl();
2422
// Stores "<type>:<slug>" since gh #88 — uniqueness is (type, slug), so a bare
2523
// slug can restore the wrong corpus once a workspace holds both. Bare slugs
2624
// from before #88 still resolve; see loadStrategies().

apps/enhanced-records-list/src/App.svelte

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
onMount(() => {
2929
const TOKEN_KEY = 'augment_it_session_token';
3030
workspace.connect({
31-
url: 'ws://localhost:3001/ws',
3231
getToken: () => localStorage.getItem(TOKEN_KEY),
3332
saveToken: (t) => localStorage.setItem(TOKEN_KEY, t),
3433
onStatus: (s) => {

apps/org-workbench/src/App.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
// from person-db-resolver. See context-v/specs/Augment-From-DB-Flow.md.
88
99
import { onMount } from 'svelte';
10-
import { workspace } from '@augment-it/workspace';
10+
import { workspace, resolveWsUrl } from '@augment-it/workspace';
1111
import OrgSearch from './OrgSearch.svelte';
1212
import OrgCard from './OrgCard.svelte';
1313
import OrgCreateInline from './OrgCreateInline.svelte';
@@ -17,7 +17,7 @@
1717
import type { OrgDetail, OrgSuggestion } from './lib/types';
1818
1919
const TOKEN_KEY = 'augment-it:session-token';
20-
const WS_URL = 'ws://localhost:3001/ws';
20+
const WS_URL = resolveWsUrl();
2121
// Restore the last-worked org on remount (HMR, flow switch, tab reopen).
2222
const ACTIVE_ORG_KEY = 'augment-it:org-workbench:active-org';
2323
// Cross-remote focused-entity broadcast — the chat rail includes it in

apps/pack-runner/src/App.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<script lang="ts">
22
import { onMount } from 'svelte';
3-
import { workspace, type RecordSet, type Row } from '@augment-it/workspace';
3+
import { workspace, type RecordSet, type Row, resolveWsUrl } from '@augment-it/workspace';
44
import {
55
BUNDLES, getBundle, packDisplayName, inferEntityNameField,
66
PACK_PALETTE_META,
@@ -23,7 +23,7 @@
2323
let rowPackFired = $state<Record<string, Set<string>>>({});
2424
2525
const TOKEN_KEY = 'augment-it:session-token';
26-
const WS_URL = 'ws://localhost:3001/ws';
26+
const WS_URL = resolveWsUrl();
2727
2828
// Remember the user's last record-set + column picks so re-entry doesn't
2929
// require re-selecting everything. Keys keep the augment-it prefix per

apps/person-db-resolver/src/App.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
// context-v/plans/Person-Aware-Canonical-Resolver-Extension.md.
88
99
import { onMount } from 'svelte';
10-
import { workspace, type RecordSet, type Row } from '@augment-it/workspace';
10+
import { workspace, type RecordSet, type Row, resolveWsUrl } from '@augment-it/workspace';
1111
import RecordCard from './components/RecordCard.svelte';
1212
import ColumnMapper from './components/ColumnMapper.svelte';
1313
import PersonCandidateList from './components/PersonCandidateList.svelte';
@@ -35,7 +35,7 @@
3535
} from './lib/types';
3636
3737
const TOKEN_KEY = 'augment-it:session-token';
38-
const WS_URL = 'ws://localhost:3001/ws';
38+
const WS_URL = resolveWsUrl();
3939
const ACTIVE_RECORD_SET_KEY = 'augment-it:active-record-set';
4040
const MAPPING_KEY_PREFIX = 'augment-it:person-db-resolver:mapping:';
4141
// Per-record-set "where I left off" — restored on every selectRecordSet()

apps/prompt-template-manager/src/App.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
<script lang="ts">
22
import { onMount } from 'svelte';
3-
import { workspace, type PromptTemplate, type PromptTool } from '@augment-it/workspace';
3+
import { workspace, type PromptTemplate, type PromptTool, resolveWsUrl } from '@augment-it/workspace';
44
55
const TOKEN_KEY = 'augment-it:session-token';
6-
const WS_URL = 'ws://localhost:3001/ws';
6+
const WS_URL = resolveWsUrl();
77
const TOKEN_RE = /\{\{\s*([^{}]+?)\s*\}\}/g;
88
99
let status = $state<'connecting' | 'open' | 'closed' | 'error' | 'auth_required'>('connecting');

apps/record-collector/src/App.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
<script lang="ts">
22
import { onMount } from 'svelte';
3-
import { workspace, type RecordSet, type Row } from '@augment-it/workspace';
3+
import { workspace, type RecordSet, type Row, resolveWsUrl } from '@augment-it/workspace';
44
import RecordSetsList from './components/RecordSetsList.svelte';
55
import { formatFieldValue } from './logic/format';
66
77
const TOKEN_KEY = 'augment-it:session-token';
8-
const WS_URL = 'ws://localhost:3001/ws';
8+
const WS_URL = resolveWsUrl();
99
1010
let status = $state<'connecting' | 'open' | 'closed' | 'error' | 'auth_required'>('connecting');
1111
let selectedId = $state<string | null>(null);

0 commit comments

Comments
 (0)