mirror of
https://github.com/temetro/temetro.git
synced 2026-07-26 11:58:14 +00:00
fix: default RELAY_URL to the hosted relay (v0.8.2)
The default http://localhost:8080 silently failed for clinics that joined the network without setting RELAY_URL — inside Docker localhost is the container itself, so the hub connection never reached the relay (endless "relay unreachable" retries) and pairing QRs encoded an unreachable localhost. Default to https://network.temetro.com so "Join Temetro Network" works out of the box; self-hosters running their own relay still override it. Also (re)ensure the hub is connected before pre-registering a pairing. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+14
-1
@@ -7,7 +7,20 @@ for how releases are cut and published.
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
## [0.8.1] — 2026-07-05
|
## [0.8.2] — 2026-07-05
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- **`RELAY_URL` now defaults to the hosted relay** (`https://network.temetro.com`) instead of
|
||||||
|
`http://localhost:8080`. The old default silently failed for anyone who joined the network without
|
||||||
|
explicitly setting `RELAY_URL` — the backend's hub connection could never reach the relay (inside
|
||||||
|
Docker `localhost` is the container itself), so it never authenticated and QR pairing generated a
|
||||||
|
QR pointing at an unreachable `localhost`. Self-hosters running their own relay still override
|
||||||
|
`RELAY_URL`. Updated `.env.example` accordingly.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Generating a pairing QR (`POST /api/patients/wallet/pair`) now ensures the clinic's relay hub is
|
||||||
|
connected before pre-registering the request, so the routing is set up even if the connection was
|
||||||
|
opened lazily.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- **QR "scan to connect" pairing** was broken by the multi-clinic relay routing (v0.8.0): pairing
|
- **QR "scan to connect" pairing** was broken by the multi-clinic relay routing (v0.8.0): pairing
|
||||||
|
|||||||
@@ -40,7 +40,11 @@ FRONTEND_PORT=3000
|
|||||||
# /hub with its own Ed25519 signing key, so no shared secret is needed.
|
# /hub with its own Ed25519 signing key, so no shared secret is needed.
|
||||||
# RELAY_TOKEN is OPTIONAL/LEGACY — set it only for a private relay that also
|
# RELAY_TOKEN is OPTIONAL/LEGACY — set it only for a private relay that also
|
||||||
# gates on a shared token (then use the SAME value here and on the relay).
|
# gates on a shared token (then use the SAME value here and on the relay).
|
||||||
RELAY_URL=http://localhost:8080
|
# Defaults to the hosted relay (https://network.temetro.com) when unset, so
|
||||||
|
# "Join Temetro Network" works out of the box; set RELAY_URL only to point at
|
||||||
|
# your own relay. Do NOT use http://localhost — inside Docker that's the
|
||||||
|
# container itself and the relay connection will silently fail.
|
||||||
|
RELAY_URL=https://network.temetro.com
|
||||||
RELAY_TOKEN=
|
RELAY_TOKEN=
|
||||||
|
|
||||||
# (Legacy, pre-relay self-hosting.) A phone-reachable URL for the QR when NOT
|
# (Legacy, pre-relay self-hosting.) A phone-reachable URL for the QR when NOT
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "temetro-backend",
|
"name": "temetro-backend",
|
||||||
"version": "0.8.1",
|
"version": "0.8.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "temetro backend — Express + Postgres API with Better Auth (email/password, organizations) and org-scoped patient records.",
|
"description": "temetro backend — Express + Postgres API with Better Auth (email/password, organizations) and org-scoped patient records.",
|
||||||
|
|||||||
+5
-1
@@ -35,7 +35,11 @@ const schema = z.object({
|
|||||||
// its own Ed25519 signing key, so no shared secret is needed. RELAY_TOKEN is
|
// its own Ed25519 signing key, so no shared secret is needed. RELAY_TOKEN is
|
||||||
// now *optional/legacy* — set it only for a private relay that also gates on a
|
// now *optional/legacy* — set it only for a private relay that also gates on a
|
||||||
// shared token (must then match the relay's RELAY_TOKEN).
|
// shared token (must then match the relay's RELAY_TOKEN).
|
||||||
RELAY_URL: z.string().min(1).default("http://localhost:8080"),
|
//
|
||||||
|
// Defaults to the hosted relay so "Join Temetro Network" works out of the box;
|
||||||
|
// override only when running your own relay. (A `localhost` default silently
|
||||||
|
// fails inside Docker, where localhost is the container itself.)
|
||||||
|
RELAY_URL: z.string().min(1).default("https://network.temetro.com"),
|
||||||
RELAY_TOKEN: z.string().default(""),
|
RELAY_TOKEN: z.string().default(""),
|
||||||
// Public, device-reachable URL of this backend's wallet relay, baked into the
|
// Public, device-reachable URL of this backend's wallet relay, baked into the
|
||||||
// QR a patient scans. Optional — when unset we derive it from the request host
|
// QR a patient scans. Optional — when unset we derive it from the request host
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import {
|
|||||||
} from "../middleware/auth.js";
|
} from "../middleware/auth.js";
|
||||||
import { emitToWallet } from "../realtime.js";
|
import { emitToWallet } from "../realtime.js";
|
||||||
import { recordActivity } from "../services/activity.js";
|
import { recordActivity } from "../services/activity.js";
|
||||||
import { expectResponse } from "../services/relay-client.js";
|
import { connectOrg, expectResponse } from "../services/relay-client.js";
|
||||||
import * as patientService from "../services/patients.js";
|
import * as patientService from "../services/patients.js";
|
||||||
import { awaitQuickTunnelUrl } from "../services/relay-url.js";
|
import { awaitQuickTunnelUrl } from "../services/relay-url.js";
|
||||||
import { getNetworkEnabled } from "../services/signing.js";
|
import { getNetworkEnabled } from "../services/signing.js";
|
||||||
@@ -95,6 +95,9 @@ patientsWalletRouter.post(
|
|||||||
);
|
);
|
||||||
// No wallet number to `wallet:send` to yet, so pre-register the request id
|
// No wallet number to `wallet:send` to yet, so pre-register the request id
|
||||||
// with the relay so the scanning device's response routes back to us.
|
// with the relay so the scanning device's response routes back to us.
|
||||||
|
// Ensure the hub is (re)connected first; if it's still mid-handshake the
|
||||||
|
// on-auth re-registration of pending requests will catch this one.
|
||||||
|
await connectOrg(req.organizationId!);
|
||||||
expectResponse(req.organizationId!, view.id);
|
expectResponse(req.organizationId!, view.id);
|
||||||
res.status(201).json({
|
res.status(201).json({
|
||||||
...view,
|
...view,
|
||||||
|
|||||||
@@ -49,7 +49,9 @@ export function expectResponse(orgId: string, requestId: string): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Open (and authenticate) a hub connection for a clinic, if not already open.
|
// Open (and authenticate) a hub connection for a clinic, if not already open.
|
||||||
// Idempotent — safe to call on startup and again when an org joins the network.
|
// Idempotent — safe to call on startup, when an org joins the network, and
|
||||||
|
// before generating a pairing QR. The socket auto-reconnects on its own, so an
|
||||||
|
// existing entry is left as-is.
|
||||||
export async function connectOrg(orgId: string): Promise<void> {
|
export async function connectOrg(orgId: string): Promise<void> {
|
||||||
if (hubs.has(orgId)) return;
|
if (hubs.has(orgId)) return;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "frontend",
|
"name": "frontend",
|
||||||
"version": "0.8.1",
|
"version": "0.8.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "temetro",
|
"name": "temetro",
|
||||||
"version": "0.8.1",
|
"version": "0.8.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"shadcn": "^4.11.0"
|
"shadcn": "^4.11.0"
|
||||||
|
|||||||
Reference in New Issue
Block a user