From f99604ba6c9eaf39d6f749841f84519511c9df43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabr=C3=ADcio=20Bracht?= Date: Sat, 29 Aug 2026 20:38:12 -0300 Subject: [PATCH] release 0.6.1 --- CHANGELOG.md | 10 ++++++++++ package-lock.json | 12 ++++++------ package.json | 4 ++-- tests/integration/smoke.test.ts | 18 ++++++++++++++++++ 4 files changed, 36 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 600d4c4..5b92bf4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,16 @@ - _Nothing yet._ +## 0.6.1 + +### Fixed + +- **`create()` now rejects and rolls back the optimistic local row when the broker refuses an online insert.** On a live connection, a broker `Conflict` (409) or `Ownership` (403) response previously swallowed the error and resolved `create()` with an id, leaving a phantom local row. As of `@laboverwire/stitch-wasm` 0.4.0 the optimistic write is rolled back (memory + persistence + offline queue) and the promise rejects, carrying the stringified error (`conflict for /` / `ownership denied for /`). This makes `create()` usable for exclusive-key claims that must distinguish a win from a loss. Behavior change: code that treats `create()` as infallible should add a `.catch`. + +### Changed + +- Raised the `@laboverwire/stitch-wasm` floor to `^0.4.0`, which implements the create-conflict rollback above. Additive to the wrapper's own API; no `@laboverwire/stitch` type or signature changes. The create binding the adapter calls is unchanged (`create(entity, scopeId, data, tag?) => Promise`); only its rejection behavior on a live-connection 409/403 differs. A create without an `id` still returns a fresh UUID. + ## 0.6.0 ### Added diff --git a/package-lock.json b/package-lock.json index b821ffe..bf1dc17 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,15 @@ { "name": "@laboverwire/stitch", - "version": "0.5.1", + "version": "0.6.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@laboverwire/stitch", - "version": "0.5.1", + "version": "0.6.1", "license": "Apache-2.0", "dependencies": { - "@laboverwire/stitch-wasm": "^0.3.0" + "@laboverwire/stitch-wasm": "^0.4.0" }, "devDependencies": { "@eslint/js": "^10.0.1", @@ -1031,9 +1031,9 @@ } }, "node_modules/@laboverwire/stitch-wasm": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@laboverwire/stitch-wasm/-/stitch-wasm-0.3.0.tgz", - "integrity": "sha512-DVzBdR+8+hUeRa7opRAnoMnWzmsattFpnZVMr0qqJVazL48LISuHz4AqD4DbS2gF0UD6wx3LsAnXaWOPXK0lBg==", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@laboverwire/stitch-wasm/-/stitch-wasm-0.4.0.tgz", + "integrity": "sha512-eTJ4ocOPLTmnlvb7fILhpNpy+L8lEKCPfbAeA2NI94EJPdbGmujLtm6V4zg/KOV33Wqefx9lcoHY7i2fKosOtg==", "license": "Apache-2.0" }, "node_modules/@napi-rs/lzma-linux-x64-gnu": { diff --git a/package.json b/package.json index 6a69167..33c9e27 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@laboverwire/stitch", - "version": "0.6.0", + "version": "0.6.1", "description": "Reactive state synchronization library bridging an in-memory store, IndexedDB persistence, and MQTT-based remote sync.", "license": "Apache-2.0", "author": "LabOverWire", @@ -74,7 +74,7 @@ } }, "dependencies": { - "@laboverwire/stitch-wasm": "^0.3.0" + "@laboverwire/stitch-wasm": "^0.4.0" }, "peerDependencies": { "react": "^19.0.0", diff --git a/tests/integration/smoke.test.ts b/tests/integration/smoke.test.ts index 8738d04..da8ce62 100644 --- a/tests/integration/smoke.test.ts +++ b/tests/integration/smoke.test.ts @@ -40,6 +40,24 @@ describe('smoke: core store operations', () => { store.destroy(); }); + it('create generates a fresh id when none supplied and honors an explicit id', async () => { + const store = createStore(projectTaskConfig()); + await store.initialize(); + + const generatedId = await store.create('project', '', { name: 'P1' }); + expect(generatedId).toMatch( + /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i + ); + expect(store.read('project', generatedId)).toMatchObject({ id: generatedId, name: 'P1' }); + + const suppliedId = 'project-fixed-id'; + const returnedId = await store.create('project', '', { id: suppliedId, name: 'P2' }); + expect(returnedId).toBe(suppliedId); + expect(store.read('project', suppliedId)).toMatchObject({ id: suppliedId, name: 'P2' }); + + store.destroy(); + }); + it('persistent store survives destroy + rehydrate', async () => { const dbName = uniqueDbName(); const config = projectTaskConfig();