feat: Support repository server - #237
Conversation
…pository-server # Conflicts: # .env # .env.production # src/lib/api/firmwareCDN.ts # src/lib/components/FirmwareChannelSelector.svelte # src/routes/(app)/hubs/[hubId=guid]/update/+page.svelte # src/routes/terminal/+page.svelte # src/routes/terminal/FirmwareBoardSelector.svelte # src/routes/terminal/FirmwareFlasher.svelte # svelte.config.js
There was a problem hiding this comment.
Pull request overview
This PR migrates the frontend’s firmware update/flash flow from the legacy firmware CDN endpoints to a new “repository server” API, and wires the new base URL through environment/config so different deployments can point at different firmware repositories.
Changes:
- Replace the firmware CDN client with a new
firmwareRepoAPI client (latest/version/history + artifact download + SHA-256 verification). - Update terminal flashing UI components to operate on a
FirmwareReleaseresponse (board extraction + artifact selection). - Make the firmware repository origin configurable via
PUBLIC_FIRMWARE_REPO_URLand include it in CSPconnect-src.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
vite.config.ts |
Adds firmware repo URL to CSP connect-src. |
src/routes/terminal/FirmwareFlasher.svelte |
Switches flashing to download/verify a selected artifact from the repo response. |
src/routes/terminal/FirmwareBoardSelector.svelte |
Derives board list from the fetched release metadata instead of fetching boards per version. |
src/routes/terminal/+page.svelte |
Plumbs latestResponse through the terminal flashing flow and updates component bindings. |
src/routes/(app)/hubs/[hubId=guid]/update/+page.svelte |
Updates firmware channel type import to the new module. |
src/lib/components/FirmwareChannelSelector.svelte |
Fetches latest firmware release per channel and caches responses. |
src/lib/api/firmwareRepo.ts |
Introduces repository server API client + artifact download/verification helpers. |
src/lib/api/firmwareCDN.ts |
Removes legacy firmware CDN implementation. |
.env.development |
Adds PUBLIC_FIRMWARE_REPO_URL for development. |
.env |
Adds PUBLIC_FIRMWARE_REPO_URL for default environment. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| dotenv.PUBLIC_GATEWAY_CSP_WILDCARD, | ||
| getWsUrlFromHttpUrl(dotenv.PUBLIC_GATEWAY_CSP_WILDCARD), | ||
| 'https://firmware.openshock.org', | ||
| dotenv.PUBLIC_FIRMWARE_REPO_URL, |
| // Capture the current channel to avoid race conditions if channel changes. | ||
| const currentChannel = channel; | ||
|
|
| changelog: string; | ||
| } | ||
|
|
||
| const BASE_URL = PUBLIC_FIRMWARE_REPO_URL.replace(/\/+$/, ''); |
| export async function DownloadAndVerifyArtifact(artifact: FirmwareArtifact): Promise<Uint8Array> { | ||
| const binary = await DownloadBinary(artifact.url); | ||
|
|
||
| const calculatedHash = await HashBuffer(binary.buffer as ArrayBuffer, 'SHA-256'); |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ❌ Deployment failed View logs |
openshock-app | 4640535 | Aug 13 2026, 12:49 PM |
Deploying openshockapp with
|
| Latest commit: |
d228ee3
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://0e718dbe.openshockapp.pages.dev |
| Branch Preview URL: | https://feature-support-repository-s.openshockapp.pages.dev |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.
Suppressed comments (3)
src/lib/api/firmwareRepo.ts:35
FirmwareVersionSummary.channelis typed asstring, which is inconsistent with theFirmwareChanneltype used elsewhere and weakens type-safety for consumers.
channel: string;
src/lib/api/firmwareRepo.ts:22
FirmwareRelease.channelis currently typed asstring, which loses the stronger guarantee provided byFirmwareChanneland makes it easier for invalid values to leak into the UI. Since this value is expected to be one of the known channels, type it asFirmwareChannel.
This issue also appears on line 35 of the same file.
channel: string;
src/lib/components/FirmwareChannelSelector.svelte:60
- In the error path, the selector caches a null entry for the channel. Because the effect treats any defined cache entry (including null) as a hit, the component will never retry fetching for that channel (even after a transient outage) unless the page is reloaded.
.catch((error) => {
latestResponse = null;
version = null;
cache[currentChannel] = null;
handleApiError(error);
The client was written against an earlier draft of the API and two of its four
calls could not succeed against the shipped server.
Route shapes: version lookups are not scoped by channel. FetchVersion hit
/versions/{channel}/{version}, which the server routes to GetVersionForBoard
with version="stable", and FetchVersionHistory hit /versions/{channel}, which
routes to GetVersion with the same. Both 404 permanently. Versions are
globally unique, so FetchVersion now takes only a version, and channel becomes
an optional query filter on the history call.
Field shapes: board.chip is an object with id and name, not a string, so the
chip filter added in 14d78b4 could never match — masked only because the
terminal page does not yet pass a chip. The discontinued flag is
'discontinued', not 'deprecated', so EOL boards were never filtered. Releases
carry a structured releaseNotes array rather than a changelog string; the
markdown form is what CI submits on ingestion, not what the server returns.
Compare against chip.name, which the spec pins to esptool-js identifiers and
which is what EspSerialConnection reads out of loader.chip.CHIP_NAME.
The boards map is keyed by board name. The client already assumed this — it
renders the keys as the visible board label — and the server now agrees.
Also add FetchBoardRelease and the missing source/repository types, and route
the four calls through one helper.
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
The server no longer exposes a chip UUID: chip names are unique and externally pinned to esptool-js identifiers, and no chip appears in a storage path, so a surrogate key bought nothing on the public surface. FirmwareChipRef.id was declared required and is now never sent. Nothing read it — the flashtool matches on chip.name, which is what EspSerialConnection reads out of loader.chip.CHIP_NAME.
The server routes on /{version:apiVersion}/, matching the OpenShock backend and
firmware-api-spec.md, so the firmware API lives at /2/firmware/... rather than
/v2/firmware/....
Split the monolithic firmwareRepo.ts into the same shape as src/lib/api/next: base.ts for the JSON fetch wrapper, endpoint functions grouped by area, one file per model, and a matching runtime transformer per model. Responses are now validated instead of blind-cast, so a malformed payload throws TransformError at the boundary rather than surfacing as undefined deep in the flasher. channel stays a plain string so an unknown channel cannot fail a whole response, and nullable source fields accept absent-or-null. Adds getFirmwareRepoURL alongside getBackendURL, which brings the HTTPS and no-query/hash validation the ad-hoc base URL handling lacked. releaseDate is now a Temporal.Instant, matching how next parses timestamps. The non-ProblemDetails branch of handleResponseError now raises a generic toast instead of only logging; without it the repository server's plain HTTP errors would fail silently once they started throwing ResponseError.
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ❌ Deployment failed View logs |
openshock-app-dev | 426ad2e | Aug 14 2026, 08:43 AM |
# Conflicts: # src/lib/api/firmwareCDN.ts # vite.config.ts
No description provided.