Repository navigation
Conversation
VITE_CARRIER=cloud sends the sealed session to wss://cloud.ftw.energy and falls back to relay.ftw.energy when that host does not speak the protocol. The default build still dials the relay. api.req query keys match the iPhone app. Co-authored-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
ftw-webapp | de21878 | Commit Preview URL Branch Preview URL |
Oct 15 2026, 01:03 PM |
6 tasks done
Member
Author
|
Please pause the carrier part of this. Fredrik decided on 15 October 2026 that the web app, like the iPhone, reaches the box through a tunnel inside its FTW Cloud session, not through the relay's 🤖 Generated with Claude Code |
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.
What changed
The webapp can send its existing sealed relay session — reads and remote commands, same frames, same
/r/<epoch>/<handle>/appjoin — to FTW Cloud instead ofrelay.ftw.energy.VITE_CARRIERunset, or anything other thancloud, keeps today's behaviour: dialwss://relay.ftw.energy(VITE_RELAY_URLstill overrides that host).VITE_CARRIER=clouddialsVITE_CLOUD_URLorwss://cloud.ftw.energyfirst. If that socket closes before the host speaks the relay protocol (ready,gone, a frame, or close codes 4400 / 4409 / 4410 / 4429), the carrier dials the relay once and stays there for the rest of that connection. The next launch tries the cloud host again.relay/,escrow/, and deploy/DNS are untouched. CSPconnect-srcnow also allowswss://cloud.ftw.energy, which is what lets a flagged build open the socket.api.requses the same field set as the iPhone app (APIRequest.cborin srcfl/ftw-app):maxBytes,method,path, thenqueryonly when it has entries and with keys sorted,bodyonly when present,stepUponly when true. A caller-suppliedmaxBytesstill overrides the 8 MiB ceiling.The default stays the relay because
cloud.ftw.energydoes not serve/r/...yet. A parallel port of this frame format onto srcfl/ftw-cloud is what makesVITE_CARRIER=clouduseful.API / JSON compared with the iPhone app
Aligned here:
api.reqfield set and query-key order, as above.Already the same on the wire, left as they were:
PUT /api/loadpoints/{id}/schedule:soc,time_of_day_min,time_of_day_min_utc,recurring,days,surplus_unlock_bat_socPOST /api/loadpoints/{id}/vehicle:{capacity_wh}site.mode.set {mode},planner.prefs.set {safety_k | battery_export},loadpoint.hold({id, power_w, hold_s, phase_mode}, pause{id, power_w: 0, hold_s: 0}, release{id, clear: true}),loadpoint.soc.set {id, soc},loadpoint.boost,loadpoint.surplus_only.setGET /api/savings/daily?days=readssaved_ore. The iPhone also readsactual_cost_orefrom the same object; this app's compact card does not.GET /api/energy/daily?days=GET /api/planner/prefs:safety_k,mapped_k,battery_export,mapped_modeGET /api/status,GET /api/loadpoints,GET /api/mpc/planDifferent, on purpose:
wss://cloud.ftw.energy/v1/app?home=<id>(Noise IK to the service key, CloudWire CBOR; that service can read). Its commands still go towss://relay.ftw.energy/r/<epoch>/<handle>/app. This app sends both reads and commands as the existing relay frames.VITE_CARRIER=cloudpoints that join atwss://cloud.ftw.energy. It does not open/v1/app.GET /api/energy/history?since&until&bucket=1h&scope=system, withpoints[]offlow,quality,bucket_start_ms,bucket_len_ms,energy_wh. This app's chart is the sessionhist.query(series,res5m|1h,fromMs,toMs, tilehave, binary columns). The frame port carrieshist.query, so the chart stays on it.GET /api/cloud(state,purposes,connected,purgedAtMs),POST /api/cloud/grant(scopes,policy: "ftw-cloud-2026-10"),POST /api/cloud/stats(policy: "ftw-stats-2026-10"), orDELETEof either.hello.app.uaispwahere andnativeon the iPhone.hello_ok.cloud(box P-256 key, home id, boot, source and loadpoint names) is parsed by the iPhone for the readable session. This app leaves that map unread.Still in Frankfurt (eu-central-1)
relay.ftw.energy— the relay process, dead-man push rows, and fleet totals. Still the default host and the fallback. DNS andrelay/deployare unchanged.escrow.ftw.energy— sealed recovery copies. Unchanged.app.ftw.energyand the passkey RP ID. Unchanged.Not Frankfurt: the web app is Cloudflare Pages (
wrangler.jsonc). FTW Cloud itself is already in Stockholm (eu-north-1) atcloud.ftw.energy, and it does not yet speak these frames.Tests
npm run checkandnpm run buildpass. New and nearby tests pass (origin,api.req, relay carrier including fallback, CSP, cloud claims, API passthrough). In this environment the fullnpm testalso fails onmainfor WebCrypto PRF (importKeyon Node 22.14) and the escrow service timing out; those paths are not part of this change.