aiecsjs 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -8,12 +8,89 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
8
8
 
9
9
  ## [Unreleased]
10
10
 
11
- ### Planned for 0.3+
11
+ ### Planned for 0.4+
12
12
 
13
- - Implement ABA-safe `EntityRef` and graduate `getEntityGeneration` / `packEntity` from experimental → stable.
14
13
  - Add `pipeAsync` for async system composition.
15
14
  - Doc-test harness so README code blocks are mechanically verified.
16
15
  - Promote `aiecsjs/relations` and `aiecsjs/worker` (true SAB-shared columns) to `stable`.
16
+ - Document the 8-bit generation wrap caveat in [STABILITY.md](./STABILITY.md): with the
17
+ default `generationBits=8`, a single slot recycled 256 times wraps back to its
18
+ starting generation, briefly re-opening the ABA window. Safe for v0.5 shmup
19
+ workloads (~5000 frame to wrap a single slot at 60 fps × ~1k destroys); high-churn
20
+ pools should set `createWorld({ generationBits: 16 })`. See test
21
+ [tests/ref.test.ts](./tests/ref.test.ts) `generation wrap` describe block.
22
+
23
+ ## [0.3.0] - 2026-05-29
24
+
25
+ ### Added (API)
26
+
27
+ - **`EntityRef<T>`** — ABA-safe entity reference. `refOf(world, eid)` builds one;
28
+ `deref(world, ref)` returns the entity id when still alive (generation match)
29
+ or `null` otherwise; `aliveRef(world, ref)` is the boolean guard form. Phantom
30
+ type `T` lets callers distinguish ref kinds (e.g. `EntityRef<'bullet'>`) without
31
+ runtime cost. Refs are in-memory only — not serializable across worker / disk.
32
+ - **`EntityNotAliveError`** — thrown by `refOf` when the entity is dead or invalid.
33
+ `deref` / `aliveRef` never throw.
34
+
35
+ ### Changed
36
+
37
+ - **`EntityId` now packs index + generation** into a single 32-bit number
38
+ `(generation << indexBits) | index` (default `indexBits=24, generationBits=8`).
39
+ `EntityId` remains opaque per STABILITY contract; the layout is implementation
40
+ detail. **Migration note**: do not compare `EntityId` numbers directly
41
+ (`eid === 42` will break across slot recycles); use
42
+ `getEntityIndex(eid)` for index comparison or `refOf(world, eid).id` for
43
+ identity matching that survives slot reuse.
44
+ - **`getEntityGeneration` / `packEntity` graduate to `stable`** (were `experimental`
45
+ since 0.2.0). Both now return real values. These functions use default 24/8 bit
46
+ layout; for non-default `createWorld({ indexBits, generationBits })`, use
47
+ `EntityRef` and `deref` instead of manual unpacking.
48
+
49
+ ### Fixed
50
+
51
+ - **ABA bug on entity slot recycle**: previously `entityExists` and `isAliveInternal`
52
+ only checked archetype membership; a stale `EntityId` pointing at a recycled slot
53
+ would silently report alive. With packed generation + `deref` generation match,
54
+ stale refs now correctly invalidate.
55
+ - **`destroyEntity` generation wrap mask aligned with `options.generationBits`**
56
+ (was hard-coded `& 0xffff`). The mask now correctly uses
57
+ `state.options.generationMask`, fixing inconsistency for non-default
58
+ `generationBits` values.
59
+
60
+ ### Documentation
61
+
62
+ - `onSet` JSDoc clarifies that `addComponent` does NOT trigger `onSet`, and
63
+ direct writes to column views returned by `getComponent` (e.g. `col.x[idx] = 5`)
64
+ also do NOT trigger `onSet`. Only `setComponent` on an already-present
65
+ component fires the callback. Anti-pattern example included.
66
+
67
+ ### Compatibility
68
+
69
+ - `EntityId` layout change is **not** breaking at the type system level (opaque
70
+ branded number), but consumers who relied on `eid === N` direct comparison
71
+ will need to migrate (see Migration note above).
72
+ - All existing `stable` exports unchanged.
73
+ - `aiecsjs/worker` snapshot wire format unchanged (still uses raw indices).
74
+ - `aiecsjs/serialize` wire format unchanged.
75
+
76
+ ### Build & tooling
77
+
78
+ - `VERSION` constant bumped to `0.3.0`.
79
+
80
+ ## [0.2.1] - 2026-05-28
81
+
82
+ ### Security
83
+
84
+ - **Resolve two Dependabot moderate advisories** on the transitive dev-only graph by upgrading `vitest` 1.6.0 → 4.1.7. Adds `vite` 8.0.14 as a direct devDependency to satisfy vitest 4's peer range (`^6 || ^7 || ^8`). These are dev-only — runtime surface unchanged.
85
+ - [GHSA-67mh-4wv8-2f99](https://github.com/advisories/GHSA-67mh-4wv8-2f99) `esbuild <=0.24.2` CORS development server data leak (fixed in 0.25.0).
86
+ - [GHSA-4w7w-66w2-5vf9](https://github.com/advisories/GHSA-4w7w-66w2-5vf9) `vite <=6.4.1` path traversal in optimized deps `.map` handling (fixed in 6.4.2 / 7.3.2 / 8.0.5).
87
+
88
+ ### Changed
89
+
90
+ - **README opening unified across the ai*js family**: five-badge shields row (npm + CI + License + AI Generated + 繁體中文/English), one-line tagline as blockquote, ecosystem footer linking to the other two packages. Replaces the previous mixed style (text language switcher + 5 ad-hoc badges).
91
+ - **`VERSION` constant bumped to 0.2.1** ([src/version.ts](src/version.ts)) so `world.version` and snapshot meta reflect this release.
92
+
93
+ Runtime surface unchanged. Production bundles are byte-identical to 0.2.0.
17
94
 
18
95
  ## [0.2.0] - 2026-05-28
19
96
 
package/README.md CHANGED
@@ -1,15 +1,15 @@
1
1
  # aiecsjs
2
2
 
3
- [English](README.md) | [繁體中文](README_ZHTW.md)
4
-
3
+ [![npm version](https://img.shields.io/npm/v/aiecsjs.svg)](https://www.npmjs.com/package/aiecsjs)
4
+ [![CI](https://github.com/yshengliao/aiecsjs/actions/workflows/ci.yml/badge.svg)](https://github.com/yshengliao/aiecsjs/actions/workflows/ci.yml)
5
5
  [![License](https://img.shields.io/badge/license-MIT-brightgreen.svg)](LICENSE)
6
- ![AI Generated](https://img.shields.io/badge/AI_Generated-Claude_Code_Opus_4.7_Max-blueviolet.svg)
7
- ![Status](https://img.shields.io/badge/status-experimental-orange.svg)
8
- ![Version](https://img.shields.io/badge/version-0.1.4-blue.svg)
9
- ![Types](https://img.shields.io/badge/types-TypeScript-3178c6.svg)
6
+ [![AI Generated](https://img.shields.io/badge/AI_Generated-Claude_Code_Opus_4.7_Max-blueviolet.svg)](https://www.anthropic.com/claude-code)
7
+ [![繁體中文](https://img.shields.io/badge/lang-繁體中文-red.svg)](README_ZHTW.md)
10
8
 
11
9
  > A TypeScript-first archetype ECS for browser and Node, with SAB-ready snapshot transport and AI-readable documentation.
12
10
 
11
+ Part of the [ai\*js micro-runtime ecosystem](https://github.com/yshengliao) — see also [aifsmjs](https://github.com/yshengliao/aifsmjs) (FSM) and [aibridgejs](https://github.com/yshengliao/aibridgejs) (cross-context RPC).
12
+
13
13
  aiecsjs uses **archetype tables with TypedArray columns** and **bitmask queries** — the same architecture that powers piecs and wolf-ecs at the top of public benchmarks. Its API is **functional and tree-shakable**, composed with `pipe()`. Components support both Structure-of-Arrays (SoA) and Array-of-Structures (AoS) layouts. Entity IDs in 0.x are bare slot indices; internal generation tracks slot reuse but is not encoded in the ID. ABA-safe `EntityRef` is targeted for **0.3+** (deferred from the 0.2 roadmap once the v0.2.0 scope froze on API stability + safety).
14
14
 
15
15
  ```ts
package/README_ZHTW.md CHANGED
@@ -1,15 +1,15 @@
1
1
  # aiecsjs
2
2
 
3
- [English](README.md) | [繁體中文](README_ZHTW.md)
4
-
3
+ [![npm version](https://img.shields.io/npm/v/aiecsjs.svg)](https://www.npmjs.com/package/aiecsjs)
4
+ [![CI](https://github.com/yshengliao/aiecsjs/actions/workflows/ci.yml/badge.svg)](https://github.com/yshengliao/aiecsjs/actions/workflows/ci.yml)
5
5
  [![License](https://img.shields.io/badge/license-MIT-brightgreen.svg)](LICENSE)
6
- ![AI Generated](https://img.shields.io/badge/AI_Generated-Claude_Code_Opus_4.7_Max-blueviolet.svg)
7
- ![Status](https://img.shields.io/badge/status-experimental-orange.svg)
8
- ![Version](https://img.shields.io/badge/version-0.1.4-blue.svg)
9
- ![Types](https://img.shields.io/badge/types-TypeScript-3178c6.svg)
6
+ [![AI Generated](https://img.shields.io/badge/AI_Generated-Claude_Code_Opus_4.7_Max-blueviolet.svg)](https://www.anthropic.com/claude-code)
7
+ [![English](https://img.shields.io/badge/lang-English-blue.svg)](README.md)
10
8
 
11
9
  > 為 TypeScript 而設計的原型式 ECS,支援瀏覽器與 Node,內建 SAB 快照傳輸(snapshot transport)與 AI 可讀文件。
12
10
 
11
+ 隸屬 [ai\*js micro-runtime 生態系](https://github.com/yshengliao) ─ 另見 [aifsmjs](https://github.com/yshengliao/aifsmjs)(FSM)與 [aibridgejs](https://github.com/yshengliao/aibridgejs)(cross-context RPC)。
12
+
13
13
  aiecsjs 採用 **原型表格搭配 TypedArray 欄位** 與 **位元遮罩查詢**,這正是 piecs 與 wolf-ecs 在公開效能評測中名列前茅所採用的架構。API 為 **函式式且可 tree-shake**,以 `pipe()` 組合。元件(Component)同時支援 SoA(結構陣列)與 AoS(結構物件)兩種佈局。0.x 的實體 ID 為純索引值;世代計數在內部追蹤槽位重用,但不編入 ID。具 ABA 安全的 `EntityRef` 預計 **0.3+** 推出(0.2 為求 API 穩定與安全性收尾而延後)。
14
14
 
15
15
  ```ts
package/STABILITY.md CHANGED
@@ -34,8 +34,13 @@ The **root** entry (`aiecsjs`) is the stable core: world, entity, component, que
34
34
  | `destroyEntity` | stable | 0.1.0 | |
35
35
  | `entityExists` | stable | 0.1.0 | |
36
36
  | `getEntityIndex` | stable | 0.1.0 | |
37
- | `getEntityGeneration` | **experimental** | 0.1.0 | Returns 0 in 0.x (generation tracked internally but not encoded in EntityId). Real values arrive with ABA-safe `EntityRef` in **0.3+**. |
38
- | `packEntity` | **experimental** | 0.1.0 | Identity helper in 0.x. Returns the index unchanged. Real packing arrives with `EntityRef` in **0.3+**. |
37
+ | `getEntityGeneration` | stable | 0.3.0 | Returns real generation value packed into EntityId (default 24-bit index, 8-bit generation). For non-default `createWorld({ indexBits, generationBits })`, use `EntityRef` + `deref` instead. |
38
+ | `packEntity` | stable | 0.3.0 | Packs index + generation into an EntityId using default 24/8 bit layout. For non-default bit sizes, use `EntityRef` + `deref` instead. |
39
+ | `refOf` | stable | 0.3.0 | Throws `EntityNotAliveError` for dead entity. |
40
+ | `deref` | stable | 0.3.0 | Returns null for stale / cross-world refs; never throws. |
41
+ | `aliveRef` | stable | 0.3.0 | Boolean guard form of `deref`; never throws. |
42
+ | `EntityRef` (type) | stable | 0.3.0 | In-memory only; not serializable. |
43
+ | `EntityNotAliveError` | stable | 0.3.0 | Thrown only by `refOf`. |
39
44
  | `defineComponent` | stable | 0.1.0 | |
40
45
  | `defineTag` | stable | 0.1.0 | |
41
46
  | `defineObjectComponent` | stable | 0.1.0 | AoS components are main-thread only; not SAB-shareable. |
@@ -130,8 +135,9 @@ Everything under this prefix is **internal**. It exists for the implementation's
130
135
  |---|---|---|
131
136
  | 0.1.x | Core surface (world, entity, component, query, system, loop, commands, observers, serialize) | Initial publish; all marked experimental at the package level but per-export stable where listed. |
132
137
  | 0.2.0 | Safety + alignment | Prototype-pollution hardening, observer `{ signal? }`, `disposeWorld` alias, `getEntityGeneration` / `packEntity` re-labelled experimental, `verify:llms` gate. See [CHANGELOG.md](./CHANGELOG.md#020---2026-05-28). |
133
- | 0.3+ | Relations stabilisation + EntityRef + SAB | `aiecsjs/relations` graduates to stable; ABA-safe `EntityRef` lands and `getEntityGeneration` / `packEntity` start returning real values; `aiecsjs/worker` adopts true shared-memory column aliasing. |
134
- | 0.3.x | Hardening, relations stabilization, multi-threading polish | `aiecsjs/relations` and `aiecsjs/worker` → stable. |
138
+ | 0.3.x | EntityRef + generation packing | ABA-safe; `getEntityGeneration` / `packEntity` → stable. |
139
+ | 0.4+ | Relations stabilisation + true SAB worker | `aiecsjs/relations` and `aiecsjs/worker` → stable. |
140
+ | 0.6+ | Multi-World snapshot diff transport (placeholder) | experimental — design TBD. |
135
141
  | 1.0.0 | API freeze | All `stable` exports frozen for 1.x. |
136
142
 
137
143
  ## How to check stability at runtime
package/STABILITY_ZHTW.md CHANGED
@@ -33,8 +33,13 @@ aiecsjs 遵循 [semver](https://semver.org/)。在 **0.x** 系列內:
33
33
  | `destroyEntity` | stable | 0.1.0 | |
34
34
  | `entityExists` | stable | 0.1.0 | |
35
35
  | `getEntityIndex` | stable | 0.1.0 | |
36
- | `getEntityGeneration` | stable | 0.1.0 | |
37
- | `packEntity` | stable | 0.1.0 | |
36
+ | `getEntityGeneration` | stable | 0.3.0 | 回傳 EntityId 中實際打包的 generation 值(預設 24-bit index、8-bit generation)。若使用非預設 `createWorld({ indexBits, generationBits })`,請改用 `EntityRef` + `deref`。 |
37
+ | `packEntity` | stable | 0.3.0 | 使用預設 24/8 bit 佈局將 index + generation 打包為 EntityId。若使用非預設 bit 大小,請改用 `EntityRef` + `deref`。 |
38
+ | `refOf` | stable | 0.3.0 | entity 不存活時拋出 `EntityNotAliveError`。 |
39
+ | `deref` | stable | 0.3.0 | 對過期或跨 world 的 ref 回傳 null;絕不拋出錯誤。 |
40
+ | `aliveRef` | stable | 0.3.0 | `deref` 的布林 guard 形式;絕不拋出錯誤。 |
41
+ | `EntityRef`(type) | stable | 0.3.0 | 僅限記憶體內使用;不可序列化。 |
42
+ | `EntityNotAliveError` | stable | 0.3.0 | 僅由 `refOf` 拋出。 |
38
43
  | `defineComponent` | stable | 0.1.0 | |
39
44
  | `defineTag` | stable | 0.1.0 | |
40
45
  | `defineObjectComponent` | stable | 0.1.0 | AoS 元件僅限主執行緒;不可跨 SAB 共享。 |
@@ -129,7 +134,9 @@ aiecsjs 遵循 [semver](https://semver.org/)。在 **0.x** 系列內:
129
134
  |---|---|---|
130
135
  | 0.1.x | 核心表面(world、entity、component、query、system、loop、commands、observers、serialize) | 初次發佈;package 整體標 experimental,但各 export 表中列為 stable 者皆穩定。 |
131
136
  | 0.2.0 | 安全與生態對齊 | 原型污染強化、observer `{ signal? }`、`disposeWorld` 別名、`getEntityGeneration` / `packEntity` 改 experimental、`verify:llms` gate。詳見 [CHANGELOG.md](./CHANGELOG.md#020---2026-05-28)。 |
132
- | 0.3+ | Relations 穩定化 + EntityRef + SAB | `aiecsjs/relations` 升為 stable;ABA-safe `EntityRef` 上線,`getEntityGeneration` / `packEntity` 開始回傳真值;`aiecsjs/worker` 採用真正 shared-memory column aliasing。 |
137
+ | 0.3.x | EntityRef + generation packing | ABA-safe;`getEntityGeneration` / `packEntity` → stable。 |
138
+ | 0.4+ | Relations 穩定化 + 真正 SAB worker | `aiecsjs/relations` 與 `aiecsjs/worker` → stable。 |
139
+ | 0.6+ | Multi-World snapshot diff transport(佔位) | experimental — 設計待定。 |
133
140
  | 1.0.0 | API 凍結 | 所有 `stable` 匯出於 1.x 系列凍結。 |
134
141
 
135
142
  ## 在執行時檢查穩定度