Skip to content

Commit b24a057

Browse files
Add SKU-aware OTA release artifacts (#56)
* feat: add SKU-aware OTA release artifacts Persist OTA artifact URL/hash data separately from rollout state so stable release responses can choose artifacts by compatible SKU while release rollout remains version/type based. * fix: select compatible OTA releases by SKU Ensure stable release selection only considers releases with artifacts compatible with the requested SKU, and tighten tests around the DB-backed OTA contract. * fix: match production OTA release responses Only expose stable signature URLs that actually exist and preserve production's version-first SKU error behavior. * fix: restrict legacy OTA artifacts and make sync create-only Pre-SKU artifacts (no skus/ folder) are jetkvm-v2 only. Marking them compatible with jetkvm-v2-sdmmc would brick devices that received firmware predating their hardware. Future SKUs must opt in via an explicit skus/<sku>/ upload. sync-releases now skips releases already in the DB instead of upserting them. This prevents routine sync runs from rewriting Release.url/hash or appending duplicate ReleaseArtifact rows if R2_CDN_URL ever changes. Backfills and repairs are left to one-off scripts. * refactor: drop forceUpdate query parameter from /releases The flag is no longer sent by any client. Routine update checks now always go through the rollout-aware default-and-latest path, which is what forceUpdate effectively short-circuited to. Removes one query parameter, one branch in the handler, and the corresponding axis from the compare-releases sweep. * fix: skip incompatible defaults and parallelize stable DB lookups getDefaultRelease previously picked the newest 100%-rolled-out release without checking SKU compatibility. If that release lacked a compatible artifact, the request 404'd downstream even though older 100%-rolled-out releases had valid binaries for the SKU. It now filters to releases that actually ship a compatible artifact before selecting the latest, falling back to a 404 only when no compatible default exists. The four DB lookups in the stable rollout-aware path are independent; run them concurrently so background-check latency drops from ~4 round trips to ~1.
1 parent edf9b17 commit b24a057

11 files changed

Lines changed: 1987 additions & 698 deletions

File tree

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"prisma-dev-migrate": "prisma migrate dev",
1212
"prisma-migrate": "prisma migrate deploy",
1313
"seed": "NODE_ENV=development node -r ts-node/register --env-file=.env.development ./scripts/seed.ts",
14+
"sync-releases": "NODE_ENV=development node -r ts-node/register --env-file=.env.development ./scripts/sync-releases.ts",
1415
"build": "tsc",
1516
"test": "vitest run",
1617
"test:watch": "vitest",
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
-- CreateTable
2+
CREATE TABLE "ReleaseArtifact" (
3+
"id" BIGSERIAL NOT NULL,
4+
"releaseId" BIGINT NOT NULL,
5+
"url" TEXT NOT NULL,
6+
"hash" TEXT NOT NULL,
7+
"compatibleSkus" TEXT[] NOT NULL,
8+
9+
CONSTRAINT "ReleaseArtifact_pkey" PRIMARY KEY ("id")
10+
);
11+
12+
-- Backfill one artifact for every existing release.
13+
-- Pre-SKU artifacts only target the original jetkvm-v2 hardware; future SKUs
14+
-- (e.g. jetkvm-v2-sdmmc) require explicit SKU-folder uploads to be registered
15+
-- by scripts/sync-releases.ts.
16+
INSERT INTO "ReleaseArtifact" ("releaseId", "url", "hash", "compatibleSkus")
17+
SELECT
18+
"id",
19+
"url",
20+
"hash",
21+
ARRAY['jetkvm-v2']::TEXT[]
22+
FROM "Release";
23+
24+
-- CreateIndex
25+
CREATE UNIQUE INDEX "ReleaseArtifact_releaseId_url_key" ON "ReleaseArtifact"("releaseId", "url");
26+
27+
-- AddForeignKey
28+
ALTER TABLE "ReleaseArtifact" ADD CONSTRAINT "ReleaseArtifact_releaseId_fkey" FOREIGN KEY ("releaseId") REFERENCES "Release"("id") ON DELETE CASCADE ON UPDATE CASCADE;

prisma/schema.prisma

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,26 @@ model TurnActivity {
4343
}
4444

4545
model Release {
46-
id BigInt @id @default(autoincrement())
46+
id BigInt @id @default(autoincrement())
4747
version String
48-
rolloutPercentage Int @default(10) // 10% of users
49-
createdAt DateTime @default(now())
50-
updatedAt DateTime @updatedAt
48+
rolloutPercentage Int @default(10) // 10% of users
49+
createdAt DateTime @default(now())
50+
updatedAt DateTime @updatedAt
5151
url String
52-
type String @default("app") // "app" or "system"
52+
type String @default("app") // "app" or "system"
5353
hash String
54+
artifacts ReleaseArtifact[]
5455
5556
@@unique([version, type])
5657
}
58+
59+
model ReleaseArtifact {
60+
id BigInt @id @default(autoincrement())
61+
release Release @relation(fields: [releaseId], references: [id], onDelete: Cascade)
62+
releaseId BigInt
63+
url String
64+
hash String
65+
compatibleSkus String[]
66+
67+
@@unique([releaseId, url])
68+
}

0 commit comments

Comments
 (0)