Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 <entity>/<id>` / `ownership denied for <entity>/<id>`). 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<string>`); 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
Expand Down
12 changes: 6 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down Expand Up @@ -74,7 +74,7 @@
}
},
"dependencies": {
"@laboverwire/stitch-wasm": "^0.3.0"
"@laboverwire/stitch-wasm": "^0.4.0"
},
"peerDependencies": {
"react": "^19.0.0",
Expand Down
18 changes: 18 additions & 0 deletions tests/integration/smoke.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down