From f9ecfdb319f11ee1a9391f6d2f774dc445b96827 Mon Sep 17 00:00:00 2001 From: Karthik Ganeshram Date: Tue, 30 Sep 2025 14:15:05 +0200 Subject: [PATCH] fix handling of KV set and throw wrapped errors Signed-off-by: Karthik Ganeshram --- packages/spin-kv/package-lock.json | 4 ++-- packages/spin-kv/package.json | 2 +- packages/spin-kv/src/index.ts | 22 ++++++++++++++++++++-- packages/spin-kv/tsconfig.json | 4 ++-- test/test-app/src/index.ts | 3 ++- test/test-app/src/test.ts | 14 ++++++++++++++ test/test-app/tsconfig.json | 4 ++-- 7 files changed, 43 insertions(+), 10 deletions(-) diff --git a/packages/spin-kv/package-lock.json b/packages/spin-kv/package-lock.json index 145d1c80..9969e6d5 100644 --- a/packages/spin-kv/package-lock.json +++ b/packages/spin-kv/package-lock.json @@ -1,12 +1,12 @@ { "name": "@spinframework/spin-kv", - "version": "1.0.0", + "version": "1.0.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@spinframework/spin-kv", - "version": "1.0.0", + "version": "1.0.1", "license": " Apache-2.0 WITH LLVM-exception", "devDependencies": { "typescript": "^5.7.3" diff --git a/packages/spin-kv/package.json b/packages/spin-kv/package.json index 23fe72ca..9e91089e 100644 --- a/packages/spin-kv/package.json +++ b/packages/spin-kv/package.json @@ -1,6 +1,6 @@ { "name": "@spinframework/spin-kv", - "version": "1.0.0", + "version": "1.0.1", "description": "", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/spin-kv/src/index.ts b/packages/spin-kv/src/index.ts index ad06e1ea..733017b9 100644 --- a/packages/spin-kv/src/index.ts +++ b/packages/spin-kv/src/index.ts @@ -59,6 +59,8 @@ function createKvStore(store: spinKv.Store): Store { if (!(value instanceof Uint8Array)) { if (typeof value === 'string') { value = encoder.encode(value); + } else if (value instanceof ArrayBuffer) { + value = new Uint8Array(value); } else if (typeof value === 'object') { value = encoder.encode(JSON.stringify(value)); } @@ -90,7 +92,15 @@ function createKvStore(store: spinKv.Store): Store { * @returns {Store} The key-value store object. */ export function open(label: string): Store { - return createKvStore(spinKv.Store.open(label)); + try { + return createKvStore(spinKv.Store.open(label)); + } catch (error: any) { + // Wrapping the Spin KV error in a plain JS Error prevents cyclic object issues + // that occur if the original ComponentError is thrown or spread directly. + const e = new Error(error); + (e as any).payload = error.payload ?? { tag: 'unknown', val: String(error) }; + throw e; + } } /** @@ -98,5 +108,13 @@ export function open(label: string): Store { * @returns {Store} The default key-value store object. */ export function openDefault(): Store { - return createKvStore(spinKv.Store.open('default')); + try { + return createKvStore(spinKv.Store.open('default')); + } catch (error: any) { + // Wrapping the Spin KV error in a plain JS Error prevents cyclic object issues + // that occur if the original ComponentError is thrown or spread directly. + const e = new Error(error); + (e as any).payload = error.payload ?? { tag: 'unknown', val: String(error) }; + throw e; + } } diff --git a/packages/spin-kv/tsconfig.json b/packages/spin-kv/tsconfig.json index 64294b71..8f225c48 100644 --- a/packages/spin-kv/tsconfig.json +++ b/packages/spin-kv/tsconfig.json @@ -1,12 +1,12 @@ { "compilerOptions": { "target": "ES2020", - "module": "ES2020", + "module": "nodenext", "lib": [ "ES2020", "WebWorker" ], - "moduleResolution": "node", + "moduleResolution": "nodenext", "declaration": true, "outDir": "dist", "strict": true, diff --git a/test/test-app/src/index.ts b/test/test-app/src/index.ts index 92929a6d..058f7caf 100644 --- a/test/test-app/src/index.ts +++ b/test/test-app/src/index.ts @@ -1,5 +1,5 @@ import { AutoRouter } from "itty-router" -import { headersTest, health, kvTest, kvTestUint8Array, outboundHttp, statusTest, stream, streamTest, testFunctionality } from "./test"; +import { headersTest, health, kvTest, kvTestArrayBuffer, kvTestUint8Array, outboundHttp, statusTest, stream, streamTest, testFunctionality } from "./test"; let router = AutoRouter() @@ -9,6 +9,7 @@ router.get("/statusTest", statusTest) router.get("/headersTest", headersTest) router.get("/outboundHttp", outboundHttp) router.get("/kvTest", kvTest) +router.get("/kvTestArrayBuffer", kvTestArrayBuffer) router.get("/kvTestUint8Array", kvTestUint8Array) router.get("/streamTest", streamTest) router.get("/testFunctionality", testFunctionality) diff --git a/test/test-app/src/test.ts b/test/test-app/src/test.ts index 8ecd4654..6ae41bfc 100644 --- a/test/test-app/src/test.ts +++ b/test/test-app/src/test.ts @@ -46,6 +46,18 @@ function kvTest(req: Request) { return new Response("failed", { status: 500 }) } +function kvTestArrayBuffer(req: Request) { + let store = Kv.openDefault() + + let arr = new Uint8Array([1, 2, 3]) + store.set("arr", arr.buffer) + let ret = store.get("arr") + if (ret == null || !isEqualBytes(new Uint8Array(ret), arr)) { + return new Response("failed", { status: 500 }) + } + return new Response("success", { status: 200 }) +} + function kvTestUint8Array(req: Request) { let store = Kv.openDefault() @@ -87,6 +99,7 @@ async function testFunctionality(req: Request) { { name: "headersTest", validate: (resp: Response) => resp.status === 200 && resp.headers.get("Content-Type") === "text/html" }, { name: "outboundHttp", validate: (resp: Response) => resp.status === 200 }, { name: "kvTest", validate: (resp: Response) => resp.status === 200 }, + { name: "kvTestArrayBuffer", validate: (resp: Response) => resp.status === 200 }, { name: "kvTestUint8Array", validate: (resp: Response) => resp.status === 200 }, { name: "streamTest", validate: (resp: Response) => resp.status === 200 }, ]; @@ -112,6 +125,7 @@ export { statusTest, outboundHttp, kvTest, + kvTestArrayBuffer, kvTestUint8Array, streamTest } \ No newline at end of file diff --git a/test/test-app/tsconfig.json b/test/test-app/tsconfig.json index 6ddbfed4..6769ce9e 100644 --- a/test/test-app/tsconfig.json +++ b/test/test-app/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "outDir": "./dist/", "noImplicitAny": true, - "module": "es6", + "module": "nodenext", "target": "es2020", "jsx": "react", "skipLibCheck": true, @@ -13,6 +13,6 @@ "allowJs": true, "strict": true, "noImplicitReturns": true, - "moduleResolution": "node" + "moduleResolution": "nodenext" } } \ No newline at end of file