diff --git a/package.json b/package.json index 8fca18c..0084254 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "data-monorepo", - "version": "0.9.77", + "version": "0.9.78", "private": true, "scripts": { "build": "pnpm -r run build", diff --git a/packages/data-ai/package.json b/packages/data-ai/package.json index 62ae893..fea6230 100644 --- a/packages/data-ai/package.json +++ b/packages/data-ai/package.json @@ -1,6 +1,6 @@ { "name": "@adobe/data-ai", - "version": "0.9.77", + "version": "0.9.78", "description": "Cross-agent architecture skills for @adobe/data — installable as a Claude Code plugin or copied into any Agent-Skills-compatible agent (Cursor, Codex).", "type": "module", "private": false, diff --git a/packages/data-gpu-samples/package.json b/packages/data-gpu-samples/package.json index 0ff406f..207f4c1 100644 --- a/packages/data-gpu-samples/package.json +++ b/packages/data-gpu-samples/package.json @@ -1,6 +1,6 @@ { "name": "data-gpu-samples", - "version": "0.9.77", + "version": "0.9.78", "description": "WebGPU samples built on @adobe/data-gpu", "type": "module", "private": true, diff --git a/packages/data-gpu/package.json b/packages/data-gpu/package.json index 55970c6..6c70f43 100644 --- a/packages/data-gpu/package.json +++ b/packages/data-gpu/package.json @@ -1,6 +1,6 @@ { "name": "@adobe/data-gpu", - "version": "0.9.77", + "version": "0.9.78", "description": "Adobe data WebGPU plugins and types for graphics and compute", "type": "module", "private": false, diff --git a/packages/data-lit-tictactoe/package.json b/packages/data-lit-tictactoe/package.json index 548033b..860a58c 100644 --- a/packages/data-lit-tictactoe/package.json +++ b/packages/data-lit-tictactoe/package.json @@ -1,6 +1,6 @@ { "name": "data-lit-tictactoe", - "version": "0.9.77", + "version": "0.9.78", "description": "Tic-Tac-Toe sample - Lit web components with @adobe/data-lit and AgenticService", "type": "module", "private": true, diff --git a/packages/data-lit-todo/package.json b/packages/data-lit-todo/package.json index 4e95861..935046e 100644 --- a/packages/data-lit-todo/package.json +++ b/packages/data-lit-todo/package.json @@ -1,6 +1,6 @@ { "name": "data-lit-todo", - "version": "0.9.77", + "version": "0.9.78", "description": "Todo sample app demonstrating @adobe/data with Lit", "type": "module", "private": true, diff --git a/packages/data-lit/package.json b/packages/data-lit/package.json index 9d37f8f..516f87e 100644 --- a/packages/data-lit/package.json +++ b/packages/data-lit/package.json @@ -1,6 +1,6 @@ { "name": "@adobe/data-lit", - "version": "0.9.77", + "version": "0.9.78", "description": "Adobe data Lit bindings - hooks, elements, decorators", "type": "module", "private": false, diff --git a/packages/data-p2p-tictactoe/package.json b/packages/data-p2p-tictactoe/package.json index 5f51b65..3eaf551 100644 --- a/packages/data-p2p-tictactoe/package.json +++ b/packages/data-p2p-tictactoe/package.json @@ -1,6 +1,6 @@ { "name": "data-p2p-tictactoe", - "version": "0.9.77", + "version": "0.9.78", "description": "Serverless P2P tic-tac-toe — WebRTC DataChannel + @adobe/data-sync", "type": "module", "private": true, diff --git a/packages/data-persistence/package.json b/packages/data-persistence/package.json index 4d1089d..28f8671 100644 --- a/packages/data-persistence/package.json +++ b/packages/data-persistence/package.json @@ -1,6 +1,6 @@ { "name": "@adobe/data-persistence", - "version": "0.9.77", + "version": "0.9.78", "description": "Worker-based incremental persistence layer for @adobe/data ECS over OPFS (browser) and node:fs (server).", "type": "module", "sideEffects": false, diff --git a/packages/data-react-hello/package.json b/packages/data-react-hello/package.json index a9e977f..64fcead 100644 --- a/packages/data-react-hello/package.json +++ b/packages/data-react-hello/package.json @@ -1,6 +1,6 @@ { "name": "data-react-hello", - "version": "0.9.77", + "version": "0.9.78", "description": "Hello World sample - click counter using @adobe/data-react", "type": "module", "private": true, diff --git a/packages/data-react-pixie/package.json b/packages/data-react-pixie/package.json index d0369ae..433cd9a 100644 --- a/packages/data-react-pixie/package.json +++ b/packages/data-react-pixie/package.json @@ -1,6 +1,6 @@ { "name": "data-react-pixie", - "version": "0.9.77", + "version": "0.9.78", "description": "PixiJS React sample - ECS sprites (bunny, fox) with @adobe/data-react", "type": "module", "private": true, diff --git a/packages/data-react/package.json b/packages/data-react/package.json index 610c124..519137d 100644 --- a/packages/data-react/package.json +++ b/packages/data-react/package.json @@ -1,6 +1,6 @@ { "name": "@adobe/data-react", - "version": "0.9.77", + "version": "0.9.78", "description": "Adobe data React bindings — hooks and context for ECS database", "type": "module", "private": false, diff --git a/packages/data-solid-dashboard/package.json b/packages/data-solid-dashboard/package.json index 5b0750b..09f8b16 100644 --- a/packages/data-solid-dashboard/package.json +++ b/packages/data-solid-dashboard/package.json @@ -1,6 +1,6 @@ { "name": "data-solid-dashboard", - "version": "0.9.77", + "version": "0.9.78", "description": "Mini dashboard sample — multiple components sharing one @adobe/data ECS database with SolidJS", "type": "module", "private": true, diff --git a/packages/data-solid/package.json b/packages/data-solid/package.json index f244b72..4d70b0c 100644 --- a/packages/data-solid/package.json +++ b/packages/data-solid/package.json @@ -1,6 +1,6 @@ { "name": "@adobe/data-solid", - "version": "0.9.77", + "version": "0.9.78", "description": "Adobe data SolidJS bindings — context and provider for ECS database", "type": "module", "private": false, diff --git a/packages/data-sync/package.json b/packages/data-sync/package.json index 6439e28..6778635 100644 --- a/packages/data-sync/package.json +++ b/packages/data-sync/package.json @@ -1,6 +1,6 @@ { "name": "@adobe/data-sync", - "version": "0.9.77", + "version": "0.9.78", "description": "Multi-user real-time synchronisation for @adobe/data ECS — server, client, and in-process loopback.", "type": "module", "sideEffects": false, diff --git a/packages/data/package.json b/packages/data/package.json index 343ab2c..d856124 100644 --- a/packages/data/package.json +++ b/packages/data/package.json @@ -1,6 +1,6 @@ { "name": "@adobe/data", - "version": "0.9.77", + "version": "0.9.78", "description": "Adobe data oriented programming library", "type": "module", "sideEffects": false, diff --git a/packages/data/src/ecs/store/core/create-core.ts b/packages/data/src/ecs/store/core/create-core.ts index ff3d2c3..ef94f1b 100644 --- a/packages/data/src/ecs/store/core/create-core.ts +++ b/packages/data/src/ecs/store/core/create-core.ts @@ -259,6 +259,19 @@ export function createCore(newComponentSchemas: NC) return; } Object.assign(componentSchemas, data.componentSchemas); + // The non-persistent (negative-ID) space is never captured by + // toData, so a load must revert it to defaults rather than leak the + // loading store's pre-load live values across the load. Clear it the + // same way reset() does; the persistent side below is fully + // overwritten by the restore, so only the nonPersistent rows need + // clearing here. The store layer re-seeds nonPersistent resource + // defaults afterward (its rowCount === 0 re-init guard). + nonPersistentLocationTable.reset(); + for (const archetype of archetypes) { + if (archetype.components.has("nonPersistent")) { + archetype.rowCount = 0; + } + } persistentLocationTable.fromData(data.entityLocationTableData); for (const { componentNames, data: archetypeData } of data.archetypesData) { // Recreating the archetype reserves its id and leaves it diff --git a/packages/data/src/ecs/store/public/create-store.test.ts b/packages/data/src/ecs/store/public/create-store.test.ts index 6a70045..bf85008 100644 --- a/packages/data/src/ecs/store/public/create-store.test.ts +++ b/packages/data/src/ecs/store/public/create-store.test.ts @@ -689,6 +689,60 @@ describe("createStore", () => { expect((newStore.resources as any).score).toBe(0); }); + it("reverts a nonPersistent resource to its default when loading into a populated (non-fresh) store", () => { + const schema = { + components: {}, + resources: { + score: { default: 0 as number, nonPersistent: true }, + persistentScore: { default: 0 as number }, + }, + archetypes: {}, + } as const; + + // Save a snapshot from a source store. + const source = createStore(schema as any); + (source.resources as any).persistentScore = 123; + const snapshot = source.toData(true); + + // Load into a store that ALREADY holds non-default state — the + // same-instance Save-As -> Load path. The nonPersistent resource + // is never captured by toData, so the only correct post-load value + // is its default. Leaving the pre-load live value in place would + // leak it across the load (the stale-blob-URL bug). This must match + // reset()'s treatment of the nonPersistent space. + const target = createStore(schema as any); + (target.resources as any).score = 999; + (target.resources as any).persistentScore = 456; + target.fromData(snapshot); + + expect((target.resources as any).score).toBe(0); + expect((target.resources as any).persistentScore).toBe(123); + }); + + it("clears a nonPersistent entity present before the load when loading into a populated store", () => { + const selectionSchema = { type: "boolean", default: false } as const satisfies Schema; + const makeStore = () => createStore({ + components: { selection: selectionSchema }, + resources: {}, + archetypes: {}, + }); + + const source = makeStore(); + const snapshot = source.toData(true); + + // Target holds a nonPersistent entity (negative-ID space) before the + // load. fromData must clear it — the nonPersistent space is never + // serialized, so a load resets it exactly as reset() would. + const target = makeStore(); + const selectionArchetype = target.ensureArchetype(["id", "selection", "nonPersistent"]); + const selectionEntity = selectionArchetype.insert({ selection: true, nonPersistent: true }); + expect(target.read(selectionEntity)).not.toBeNull(); + + target.fromData(snapshot); + + expect(target.read(selectionEntity)).toBeNull(); + }); + it("preserves archetype ids across serialization when a nonPersistent archetype precedes a persistent one", () => { const selectionSchema = { type: "boolean", default: false } as const satisfies Schema; const positionScalarSchema = { type: "number", default: 0 } as const satisfies Schema;