@symbo.ls/channels
v3.14.678
Published
Symbols platform API/socket channel URLs — single source of truth across sdk, smbls, server, editor, workspace, platform.
Maintainers
Keywords
Readme
@symbo.ls/channels
Single source of truth for the Symbols platform's per-channel URLs. Every consumer (sdk, smbls,
server, editor, workspace, platform, mermaid, preview, CI workflows) resolves channels through this
package — no hardcoded https://*.symbols.app / *.symbo.ls literals anywhere else.
channels.json is the schema; index.js exposes accessors. Build-time consumers that can't import
JS (Cloudflare wrangler.toml, k8s values.yaml) template the JSON via
server/scripts/sync-channels.mjs and CI runs --check to catch drift.
Channels
| Channel | api | shell | preview | mermaidApex | deploy targets |
| ------------- | ---------------------------------- | --------------------------------- | -------------------------------------- | ------------------- | ----------------------------------------------------------------- |
| local | http://localhost:8080 | http://my.localhost:1355 | http://preview.localhost:1355 | localhost:1355 | — |
| development | https://dev.api.symbols.app | https://dev.my.symbols.app | https://dev.preview.symbols.app | dev.symbo.ls | smbls-my-dev, smbls-preview-dev, mermaid-dev |
| next | https://next.api.symbols.app | https://next.my.symbols.app | https://next.preview.symbols.app | next.symbo.ls | smbls-my-next, smbls-preview-next, mermaid-next |
| test | https://test.api.symbols.app | https://test.my.symbols.app | https://test.preview.symbols.app | test.symbo.ls | smbls-my-test, smbls-preview-test, mermaid-test |
| upcoming | https://upcoming.api.symbols.app | https://upcoming.my.symbols.app | https://upcoming.preview.symbols.app | upcoming.symbo.ls | smbls-my-upcoming, smbls-preview-upcoming, mermaid-upcoming |
| staging | https://staging.api.symbols.app | https://staging.my.symbols.app | https://staging.preview.symbols.app | staging.symbo.ls | smbls-my-staging, smbls-preview-staging, mermaid-staging |
| production | https://api.symbols.app | https://my.symbols.app | https://preview.symbols.app | at.symbo.ls | smbls-my-prod, smbls-preview, mermaid |
Default channel: next (set via defaultChannel in channels.json).
socketUrl mirrors apiUrl for every channel (the API server fronts both HTTP and WebSocket).
Usage
import {
apiUrl,
socketUrl,
shellUrl,
previewUrl,
mermaidUrl,
deployTarget,
currentChannel,
resolveChannel,
channelNames,
isKnownChannel,
defaultChannel,
} from '@symbo.ls/channels';
apiUrl(); // → 'https://next.api.symbols.app' (defaultChannel)
apiUrl('production'); // → 'https://api.symbols.app'
socketUrl('staging'); // → 'https://staging.api.symbols.app'
shellUrl(); // → 'https://next.my.symbols.app'
previewUrl('production'); // → 'https://preview.symbols.app'
// Per-project hosted URL — composes user-env + system-channel.
mermaidUrl({ owner: 'toko', key: 'myapp' });
// → 'https://toko--myapp.next.symbo.ls' (current channel = next)
mermaidUrl({ owner: 'toko', key: 'myapp', env: 'staging' }, 'production');
// → 'https://toko--myapp--staging.at.symbo.ls'
deployTarget('next'); // → { shellBucket, previewWorker, mermaidWorker }
currentChannel(); // → 'next' (or env override)
resolveChannel('test'); // → full channel record from channels.jsonMermaid URL composition
mermaidUrl({ owner, key, env? }, channel?) returns the canonical project hosting URL:
{owner}--{key}[--{userEnv}].{mermaidApex}Two-level env model:
- user env (
env) — the project's published environment slot (productionis the default and is omitted from the label;staging,development, custom names are appended as--{env}). - system env (
channel) — the platform channel currently in scope. Resolved fromNODE_ENV/defaultChannel.
Owner+key are joined with -- into a single DNS label because wildcard certificates only match one
label deep (RFC 4592). One *.{apex} cert per channel covers every project under that channel — no
per-project DNS provisioning.
Examples (system production apex at.symbo.ls):
toko + myapp → toko--myapp.at.symbo.ls
toko + myapp + env=staging → toko--myapp--staging.at.symbo.ls
toko + myapp + system=next → toko--myapp.next.symbo.ls
toko + myapp + env=staging + next → toko--myapp--staging.next.symbo.lsResolution order
For apiUrl() / socketUrl() / shellUrl() / previewUrl() / mermaidUrl():
- Explicit
nameargument (apiUrl('staging')) NODE_ENV(the deploy-time signal CI passes —production/staging/development/test/next/localmap 1:1)defaultChannelfromchannels.json
Direct URL overrides (always win, even over an explicit channel name):
SYMBOLS_API_URL— overridesapiUrl()outputSYMBOLS_SOCKET_URL— overridessocketUrl()output
These escape hatches exist for local proxies, ngrok tunnels, and per-process mirrors. They never persist into committed config.
Switching the default channel
One line. To flip the whole monorepo from next → production:
// channels.json
- "defaultChannel": "next"
+ "defaultChannel": "production"Bump the version (X.Y.0 → X.Y.1 for an existing-channel URL change, X.(Y+1).0 for a channel
add/remove), reinstall at the monorepo root to re-link, redeploy.
Adding a new channel
- Add the entry in
channels.jsonwithapi,socket,shell,preview,mermaidApex, anddeploy(shellBucket,previewWorker,mermaidWorker). - Bump version (minor — schema add).
- Reinstall at the monorepo root.
- Run
server/scripts/sync-channels.mjsto refresh the templatedwrangler.toml/values.yamlfiles.
If a consumer references a channel that doesn't exist in channels.json, resolveChannel(name)
falls back to defaultChannel. To fail loud instead, gate with isKnownChannel(name) first.
Consumers
| Package | Import path | What it uses |
| ----------------------------- | -------------------------------------------------------- | ---------------------------------------------------------------------- |
| @symbo.ls/sdk | import { apiUrl, socketUrl } from '@symbo.ls/channels' | Per-env URL lookup in sdk/src/config/environment.js |
| @symbo.ls/cli (smbls) | same + mermaidUrl, previewUrl, currentChannel | bin/start.js, bin/publish.js — published / dev preview link output |
| @symbo.ls/server-config | apiUrl, socketUrl | api.publicBaseUrl default in loader.js |
| @symbo.ls/screenshot | apiUrl | API_BASE fallback |
| @symbo.ls/tauri | apiUrl, socketUrl | Desktop-app prod default |
| editor / workspace / platform | full surface | Runtime config injection, cross-app deep links |
| mermaid / preview workers | deployTarget, mermaidUrl | Build-time bucket/worker name; per-project URL self-discovery |
| CI deploy workflows | deployTarget(NODE_ENV) | Bucket / worker upload destination — kept aligned with channel resolve |
What does NOT belong here
- Per-channel auth/secret material (JWT keys, DNS API keys, Supabase service tokens) — those stay in env vars / k8s secrets / wrangler secrets.
- Per-channel auxiliary URLs that aren't channel-shaped (
kvUrl,dnsWorkerUrl,grafanaUrl,typesense*,githubClientId) — those stay in their respective per-env config blocks (sdk'senvironment.js, server'sconfig/<env>.js). - CORS allowlists — server's per-env config files compose channel hosts plus server-private allowlist additions.
The package's job is exactly the URL+target shape per channel. Nothing else.
Wrangler / Helm / k8s
Build-time consumers (Cloudflare Workers wrangler.toml, k8s values.yaml) can't import JS at
deploy time. For those, run server/scripts/sync-channels.mjs which reads channels.json and
templates the generated config files. CI runs --check to catch drift between committed
wrangler/helm files and the channel source of truth.
