aboutsummaryrefslogtreecommitdiffstats
path: root/src/routes/(app)/flash/+page.server.ts
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-09-21 22:49:19 -0700
committerAdam Soltys <[email protected]>2026-09-21 22:49:19 -0700
commit6735d9ec73949046932716dba90ebd9cd63b513d (patch)
tree1dc7d59bb7586ca7a2e883bc6657990716962da6 /src/routes/(app)/flash/+page.server.ts
parent2e98fba55d572186f39d00235db1024791ba1561 (diff)
downloadcoinos-ui-6735d9ec73949046932716dba90ebd9cd63b513d.tar.gz
coinos-ui-6735d9ec73949046932716dba90ebd9cd63b513d.zip
Web flasher moves from /pos to /flash; /pos redirects there.
coinos v3 takes /pos for the point-of-sale till, so the terminal flasher needs its own address. Old links keep working through the redirect. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01Tmfg8k5f3TbNJS34qiqHAp
Diffstat (limited to 'src/routes/(app)/flash/+page.server.ts')
-rw-r--r--src/routes/(app)/flash/+page.server.ts58
1 files changed, 58 insertions, 0 deletions
diff --git a/src/routes/(app)/flash/+page.server.ts b/src/routes/(app)/flash/+page.server.ts
new file mode 100644
index 00000000..1e3e1e99
--- /dev/null
+++ b/src/routes/(app)/flash/+page.server.ts
@@ -0,0 +1,58 @@
+import { PUBLIC_COINOS_URL } from "$env/static/public";
+import { auth, fd, get } from "$lib/utils";
+import { hex } from "@scure/base";
+import { fail } from "@sveltejs/kit";
+
+const LITTLEFS_SIZE = 0x20000;
+const LITTLEFS_MAGIC = "littlefs";
+
+// A valid image is exactly one partition long and carries the LittleFS
+// superblock magic at byte 8. Anything else (e.g. a JSON error body from
+// the server) must never reach the flasher.
+const isLittleFS = (buf: Uint8Array) =>
+ buf.length === LITTLEFS_SIZE &&
+ new TextDecoder().decode(buf.subarray(8, 8 + LITTLEFS_MAGIC.length)) ===
+ LITTLEFS_MAGIC;
+
+export async function load({ cookies }) {
+ let token;
+
+ try {
+ token = await get("/ro", auth(cookies));
+ } catch (e) {}
+
+ return { token };
+}
+
+export const actions = {
+ default: async ({ fetch, request }) => {
+ const body = await fd(request);
+ const res = await fetch(`${PUBLIC_COINOS_URL}/flash`, {
+ method: "POST",
+ body: JSON.stringify(body),
+ headers: {
+ "content-type": "application/json",
+ accept: "application/octet-stream",
+ },
+ });
+
+ const buf = new Uint8Array(await res.arrayBuffer());
+
+ if (!res.ok) {
+ let message = `Config server returned ${res.status}`;
+ try {
+ message = JSON.parse(new TextDecoder().decode(buf)).message || message;
+ } catch (e) {}
+ return fail(res.status >= 400 && res.status < 600 ? res.status : 500, {
+ error: message,
+ });
+ }
+
+ if (!isLittleFS(buf))
+ return fail(500, {
+ error: `Config server returned an invalid image (${buf.length} bytes)`,
+ });
+
+ return { bytes: hex.encode(buf) };
+ },
+};