diff --git a/package.json b/package.json index 9133fb572..b66d4e213 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "data-monorepo", - "version": "0.10.28", + "version": "0.10.29", "private": true, "engines": { "node": ">=24" diff --git a/packages/data-ai/.claude-plugin/plugin.json b/packages/data-ai/.claude-plugin/plugin.json index 39e6f46f3..7af26a8fe 100644 --- a/packages/data-ai/.claude-plugin/plugin.json +++ b/packages/data-ai/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "adobe-data-ai", - "version": "0.10.28", + "version": "0.10.29", "description": "Architecture skills for @adobe/data — data-oriented modelling, archetype iteration, hot-path performance, and related conventions.", "author": { "name": "Adobe" diff --git a/packages/data-ai/package.json b/packages/data-ai/package.json index 95920a247..685c91027 100644 --- a/packages/data-ai/package.json +++ b/packages/data-ai/package.json @@ -1,6 +1,6 @@ { "name": "@adobe/data-ai", - "version": "0.10.28", + "version": "0.10.29", "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/package.json b/packages/data-gpu/package.json index a4125eaa2..af8db8d9c 100644 --- a/packages/data-gpu/package.json +++ b/packages/data-gpu/package.json @@ -1,6 +1,6 @@ { "name": "@adobe/data-gpu", - "version": "0.10.28", + "version": "0.10.29", "description": "Adobe data WebGPU plugins and types for graphics and compute", "type": "module", "private": false, diff --git a/packages/data-lit/package.json b/packages/data-lit/package.json index 2c1ff4e3e..187eb04a9 100644 --- a/packages/data-lit/package.json +++ b/packages/data-lit/package.json @@ -1,6 +1,6 @@ { "name": "@adobe/data-lit", - "version": "0.10.28", + "version": "0.10.29", "description": "Adobe data Lit bindings - hooks, elements, decorators", "type": "module", "private": false, diff --git a/packages/data-persistence/package.json b/packages/data-persistence/package.json index 1a4e27426..96135ce49 100644 --- a/packages/data-persistence/package.json +++ b/packages/data-persistence/package.json @@ -1,6 +1,6 @@ { "name": "@adobe/data-persistence", - "version": "0.10.28", + "version": "0.10.29", "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/package.json b/packages/data-react/package.json index 04fb8429f..b460d1727 100644 --- a/packages/data-react/package.json +++ b/packages/data-react/package.json @@ -1,6 +1,6 @@ { "name": "@adobe/data-react", - "version": "0.10.28", + "version": "0.10.29", "description": "Adobe data React bindings — hooks and context for ECS database", "type": "module", "private": false, diff --git a/packages/data-rpc/package.json b/packages/data-rpc/package.json index e57f869f8..a2fe2b64b 100644 --- a/packages/data-rpc/package.json +++ b/packages/data-rpc/package.json @@ -1,6 +1,6 @@ { "name": "@adobe/data-rpc", - "version": "0.10.28", + "version": "0.10.29", "description": "Schema-driven, bidirectional projection of @adobe/data async data services across a boundary (iframe / MessagePort / Worker). Only Data crosses the wire.", "type": "module", "sideEffects": false, diff --git a/packages/data-solid/package.json b/packages/data-solid/package.json index ec8a5bc5b..de7cea231 100644 --- a/packages/data-solid/package.json +++ b/packages/data-solid/package.json @@ -1,6 +1,6 @@ { "name": "@adobe/data-solid", - "version": "0.10.28", + "version": "0.10.29", "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 a8154106d..ffcd3c6b3 100644 --- a/packages/data-sync/package.json +++ b/packages/data-sync/package.json @@ -1,6 +1,6 @@ { "name": "@adobe/data-sync", - "version": "0.10.28", + "version": "0.10.29", "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-testing/package.json b/packages/data-testing/package.json index f0b3f85be..feab752fe 100644 --- a/packages/data-testing/package.json +++ b/packages/data-testing/package.json @@ -1,6 +1,6 @@ { "name": "@adobe/data-testing", - "version": "0.10.28", + "version": "0.10.29", "description": "Conformance-testing utilities (Match + Conformance runners) for @adobe/data ECS features", "type": "module", "sideEffects": false, diff --git a/packages/data/package.json b/packages/data/package.json index 7debeb71e..928b09e04 100644 --- a/packages/data/package.json +++ b/packages/data/package.json @@ -1,6 +1,6 @@ { "name": "@adobe/data", - "version": "0.10.28", + "version": "0.10.29", "description": "Adobe data oriented programming library", "type": "module", "sideEffects": false, diff --git a/packages/data/src/ecs/store/core/core.ts b/packages/data/src/ecs/store/core/core.ts index 9dfc0045e..05eab3ac9 100644 --- a/packages/data/src/ecs/store/core/core.ts +++ b/packages/data/src/ecs/store/core/core.ts @@ -15,7 +15,10 @@ import { PersistenceScope, ToDataOptions } from "../../persistence-scope.js"; // stays a real column (see the Archetype interface) but is never part of a read. export type EntityValues = { readonly [K in StringKeyof]: (C & OptionalComponents)[K] } export type EntityReadValues = { readonly [K in StringKeyof as string extends K ? never : K]?: (C & OptionalComponents)[K] } -export type EntityUpdateValues = Partial>; +// `undefined` removes the component (the entity migrates to the archetype +// without it), so every value admits it explicitly — under +// `exactOptionalPropertyTypes` an optional key alone would not. +export type EntityUpdateValues = { [K in keyof Omit]?: C[K] | undefined }; export type ArchetypeQueryOptions = { exclude?: readonly StringKeyof[]; diff --git a/packages/data/tsconfig.json b/packages/data/tsconfig.json index 958a848e1..205b39279 100644 --- a/packages/data/tsconfig.json +++ b/packages/data/tsconfig.json @@ -3,6 +3,9 @@ "references": [ { "path": "./src" + }, + { + "path": "./type-tests/exact-optional" } ] } diff --git a/packages/data/type-tests/exact-optional/tsconfig.json b/packages/data/type-tests/exact-optional/tsconfig.json new file mode 100644 index 000000000..c548794e9 --- /dev/null +++ b/packages/data/type-tests/exact-optional/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig-base.json", + "compilerOptions": { + "rootDir": ".", + "noEmit": true, + "tsBuildInfoFile": "../../dist/type-tests/exact-optional.tsbuildinfo", + "exactOptionalPropertyTypes": true + }, + "include": ["**/*.ts"], + "references": [{ "path": "../../src" }] +} diff --git a/packages/data/type-tests/exact-optional/update-removes-component.type-test.ts b/packages/data/type-tests/exact-optional/update-removes-component.type-test.ts new file mode 100644 index 000000000..40c8c3380 --- /dev/null +++ b/packages/data/type-tests/exact-optional/update-removes-component.type-test.ts @@ -0,0 +1,30 @@ +// © 2026 Adobe. MIT License. See /LICENSE for details. + +import { Database } from "../../src/ecs/index.js"; + +/** + * Compile-time tests under `exactOptionalPropertyTypes`: `update(entity, { c: undefined })` + * removes component `c`, so it must type-check without a cast even when `c` is required. + */ + +const db = Database.create(Database.Plugin.create({ + components: { + parent: { type: "number" }, + label: { type: "string" }, + }, + archetypes: { + Child: ["parent", "label"], + }, + transactions: { + sever(t, entity: number) { + t.update(entity, { parent: undefined }); + }, + relabel(t, { entity, label }: { entity: number; label: string }) { + t.update(entity, { label }); + // @ts-expect-error a removal does not widen the value type + t.update(entity, { label: 1 }); + }, + }, +})); + +db.transactions.sever(0);