@forgeax/engine-ecs 0.0.0-dev.8d955ade1c79

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.
Files changed (383) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +278 -0
  3. package/dist/.tsbuildinfo +1 -0
  4. package/dist/__fixtures__/field-shape-fixture.d.ts +16 -0
  5. package/dist/__fixtures__/field-shape-fixture.d.ts.map +1 -0
  6. package/dist/__tests__/__fixtures__/inspect-scripts.snapshot.d.ts +3 -0
  7. package/dist/__tests__/__fixtures__/inspect-scripts.snapshot.d.ts.map +1 -0
  8. package/dist/__tests__/archetype.unit.test.d.ts +2 -0
  9. package/dist/__tests__/archetype.unit.test.d.ts.map +1 -0
  10. package/dist/__tests__/array-handle-element.test-d.d.ts +2 -0
  11. package/dist/__tests__/array-handle-element.test-d.d.ts.map +1 -0
  12. package/dist/__tests__/buffer-array-vocab.test-d.d.ts +2 -0
  13. package/dist/__tests__/buffer-array-vocab.test-d.d.ts.map +1 -0
  14. package/dist/__tests__/buffer-field-input-widen.unit.test.d.ts +2 -0
  15. package/dist/__tests__/buffer-field-input-widen.unit.test.d.ts.map +1 -0
  16. package/dist/__tests__/buffer-pool.test-d.d.ts +2 -0
  17. package/dist/__tests__/buffer-pool.test-d.d.ts.map +1 -0
  18. package/dist/__tests__/change-detection.unit.test.d.ts +2 -0
  19. package/dist/__tests__/change-detection.unit.test.d.ts.map +1 -0
  20. package/dist/__tests__/command-buffer.test.d.ts +2 -0
  21. package/dist/__tests__/command-buffer.test.d.ts.map +1 -0
  22. package/dist/__tests__/commands-deferred.unit.test.d.ts +2 -0
  23. package/dist/__tests__/commands-deferred.unit.test.d.ts.map +1 -0
  24. package/dist/__tests__/component-catalog.test.d.ts +2 -0
  25. package/dist/__tests__/component-catalog.test.d.ts.map +1 -0
  26. package/dist/__tests__/component-definition-identity.unit.test.d.ts +2 -0
  27. package/dist/__tests__/component-definition-identity.unit.test.d.ts.map +1 -0
  28. package/dist/__tests__/component-nan-preflight.unit.test.d.ts +2 -0
  29. package/dist/__tests__/component-nan-preflight.unit.test.d.ts.map +1 -0
  30. package/dist/__tests__/component-schema.test-d.d.ts +2 -0
  31. package/dist/__tests__/component-schema.test-d.d.ts.map +1 -0
  32. package/dist/__tests__/component-schema.test.d.ts +2 -0
  33. package/dist/__tests__/component-schema.test.d.ts.map +1 -0
  34. package/dist/__tests__/define-component-options.test-d.d.ts +2 -0
  35. package/dist/__tests__/define-component-options.test-d.d.ts.map +1 -0
  36. package/dist/__tests__/deprecated-vocab-rejection.unit.test.d.ts +2 -0
  37. package/dist/__tests__/deprecated-vocab-rejection.unit.test.d.ts.map +1 -0
  38. package/dist/__tests__/despawn-all.unit.test.d.ts +2 -0
  39. package/dist/__tests__/despawn-all.unit.test.d.ts.map +1 -0
  40. package/dist/__tests__/ecs-core-reduction.characterization.test.d.ts +2 -0
  41. package/dist/__tests__/ecs-core-reduction.characterization.test.d.ts.map +1 -0
  42. package/dist/__tests__/ecs-core-reduction.perf.test.d.ts +2 -0
  43. package/dist/__tests__/ecs-core-reduction.perf.test.d.ts.map +1 -0
  44. package/dist/__tests__/ecs-error-code-31.test-d.d.ts +2 -0
  45. package/dist/__tests__/ecs-error-code-31.test-d.d.ts.map +1 -0
  46. package/dist/__tests__/entity-disabling.unit.test.d.ts +2 -0
  47. package/dist/__tests__/entity-disabling.unit.test.d.ts.map +1 -0
  48. package/dist/__tests__/entity-handle-codec-parity.unit.test.d.ts +2 -0
  49. package/dist/__tests__/entity-handle-codec-parity.unit.test.d.ts.map +1 -0
  50. package/dist/__tests__/errors.unit.test.d.ts +2 -0
  51. package/dist/__tests__/errors.unit.test.d.ts.map +1 -0
  52. package/dist/__tests__/execution-conflict-boundary.unit.test.d.ts +2 -0
  53. package/dist/__tests__/execution-conflict-boundary.unit.test.d.ts.map +1 -0
  54. package/dist/__tests__/execution-shared-storage.unit.test.d.ts +2 -0
  55. package/dist/__tests__/execution-shared-storage.unit.test.d.ts.map +1 -0
  56. package/dist/__tests__/externalization-portable-value.unit.test.d.ts +2 -0
  57. package/dist/__tests__/externalization-portable-value.unit.test.d.ts.map +1 -0
  58. package/dist/__tests__/externalization-projection.unit.test.d.ts +2 -0
  59. package/dist/__tests__/externalization-projection.unit.test.d.ts.map +1 -0
  60. package/dist/__tests__/externalization-render-read-lease.test-d.d.ts +2 -0
  61. package/dist/__tests__/externalization-render-read-lease.test-d.d.ts.map +1 -0
  62. package/dist/__tests__/externalization-render-read-lease.unit.test.d.ts +2 -0
  63. package/dist/__tests__/externalization-render-read-lease.unit.test.d.ts.map +1 -0
  64. package/dist/__tests__/externalization-root-surface.unit.test.d.ts +2 -0
  65. package/dist/__tests__/externalization-root-surface.unit.test.d.ts.map +1 -0
  66. package/dist/__tests__/field-enum-labels-reflection.test.d.ts +2 -0
  67. package/dist/__tests__/field-enum-labels-reflection.test.d.ts.map +1 -0
  68. package/dist/__tests__/field-shape-fixture.test.d.ts +2 -0
  69. package/dist/__tests__/field-shape-fixture.test.d.ts.map +1 -0
  70. package/dist/__tests__/field-transient-reflection.test.d.ts +2 -0
  71. package/dist/__tests__/field-transient-reflection.test.d.ts.map +1 -0
  72. package/dist/__tests__/field-value-type.test-d.d.ts +2 -0
  73. package/dist/__tests__/field-value-type.test-d.d.ts.map +1 -0
  74. package/dist/__tests__/fixed-update.unit.test.d.ts +2 -0
  75. package/dist/__tests__/fixed-update.unit.test.d.ts.map +1 -0
  76. package/dist/__tests__/handle.test-d.d.ts +2 -0
  77. package/dist/__tests__/handle.test-d.d.ts.map +1 -0
  78. package/dist/__tests__/hierarchy.unit.test.d.ts +2 -0
  79. package/dist/__tests__/hierarchy.unit.test.d.ts.map +1 -0
  80. package/dist/__tests__/managed-array-vocab.test-d.d.ts +2 -0
  81. package/dist/__tests__/managed-array-vocab.test-d.d.ts.map +1 -0
  82. package/dist/__tests__/minimal-example.test-d.d.ts +2 -0
  83. package/dist/__tests__/minimal-example.test-d.d.ts.map +1 -0
  84. package/dist/__tests__/name-read-types.test-d.d.ts +2 -0
  85. package/dist/__tests__/name-read-types.test-d.d.ts.map +1 -0
  86. package/dist/__tests__/plugin-service.test.d.ts +2 -0
  87. package/dist/__tests__/plugin-service.test.d.ts.map +1 -0
  88. package/dist/__tests__/query-combinations.unit.test.d.ts +2 -0
  89. package/dist/__tests__/query-combinations.unit.test.d.ts.map +1 -0
  90. package/dist/__tests__/query-light-extract-flat-column-ratio.perf.test.d.ts +2 -0
  91. package/dist/__tests__/query-light-extract-flat-column-ratio.perf.test.d.ts.map +1 -0
  92. package/dist/__tests__/query-storage-trends.perf.test.d.ts +2 -0
  93. package/dist/__tests__/query-storage-trends.perf.test.d.ts.map +1 -0
  94. package/dist/__tests__/query-trs-flat-column-ratio.perf.test.d.ts +2 -0
  95. package/dist/__tests__/query-trs-flat-column-ratio.perf.test.d.ts.map +1 -0
  96. package/dist/__tests__/query.unit.test.d.ts +2 -0
  97. package/dist/__tests__/query.unit.test.d.ts.map +1 -0
  98. package/dist/__tests__/relationship-index.perf.test.d.ts +2 -0
  99. package/dist/__tests__/relationship-index.perf.test.d.ts.map +1 -0
  100. package/dist/__tests__/relationship-index.test.d.ts +2 -0
  101. package/dist/__tests__/relationship-index.test.d.ts.map +1 -0
  102. package/dist/__tests__/scalar-field-type-owner.test-d.d.ts +2 -0
  103. package/dist/__tests__/scalar-field-type-owner.test-d.d.ts.map +1 -0
  104. package/dist/__tests__/schedule-determinism.unit.test.d.ts +2 -0
  105. package/dist/__tests__/schedule-determinism.unit.test.d.ts.map +1 -0
  106. package/dist/__tests__/schedule-inspection.unit.test.d.ts +2 -0
  107. package/dist/__tests__/schedule-inspection.unit.test.d.ts.map +1 -0
  108. package/dist/__tests__/schedule-scope-error.unit.test.d.ts +2 -0
  109. package/dist/__tests__/schedule-scope-error.unit.test.d.ts.map +1 -0
  110. package/dist/__tests__/schedule-token.unit.test.d.ts +2 -0
  111. package/dist/__tests__/schedule-token.unit.test.d.ts.map +1 -0
  112. package/dist/__tests__/schema-vocab.test-d.d.ts +2 -0
  113. package/dist/__tests__/schema-vocab.test-d.d.ts.map +1 -0
  114. package/dist/__tests__/serialization.unit.test.d.ts +2 -0
  115. package/dist/__tests__/serialization.unit.test.d.ts.map +1 -0
  116. package/dist/__tests__/shared-kernel-eligibility.test-d.d.ts +2 -0
  117. package/dist/__tests__/shared-kernel-eligibility.test-d.d.ts.map +1 -0
  118. package/dist/__tests__/shared-kernel-eligibility.unit.test.d.ts +2 -0
  119. package/dist/__tests__/shared-kernel-eligibility.unit.test.d.ts.map +1 -0
  120. package/dist/__tests__/shared-ref-store.unit.test.d.ts +2 -0
  121. package/dist/__tests__/shared-ref-store.unit.test.d.ts.map +1 -0
  122. package/dist/__tests__/sparse-tag.unit.test.d.ts +2 -0
  123. package/dist/__tests__/sparse-tag.unit.test.d.ts.map +1 -0
  124. package/dist/__tests__/spawn-field-error.test-d.d.ts +2 -0
  125. package/dist/__tests__/spawn-field-error.test-d.d.ts.map +1 -0
  126. package/dist/__tests__/stale-error.test-d.d.ts +2 -0
  127. package/dist/__tests__/stale-error.test-d.d.ts.map +1 -0
  128. package/dist/__tests__/string-view-symmetry.test-d.d.ts +2 -0
  129. package/dist/__tests__/string-view-symmetry.test-d.d.ts.map +1 -0
  130. package/dist/__tests__/string-vocab.test-d.d.ts +2 -0
  131. package/dist/__tests__/string-vocab.test-d.d.ts.map +1 -0
  132. package/dist/__tests__/structure-epoch-boundaries.unit.test.d.ts +2 -0
  133. package/dist/__tests__/structure-epoch-boundaries.unit.test.d.ts.map +1 -0
  134. package/dist/__tests__/structure-epoch.unit.test.d.ts +2 -0
  135. package/dist/__tests__/structure-epoch.unit.test.d.ts.map +1 -0
  136. package/dist/__tests__/table-archetype-mapping.unit.test.d.ts +2 -0
  137. package/dist/__tests__/table-archetype-mapping.unit.test.d.ts.map +1 -0
  138. package/dist/__tests__/time.unit.test.d.ts +2 -0
  139. package/dist/__tests__/time.unit.test.d.ts.map +1 -0
  140. package/dist/__tests__/types.test-d.d.ts +2 -0
  141. package/dist/__tests__/types.test-d.d.ts.map +1 -0
  142. package/dist/__tests__/unique-ref-store.unit.test.d.ts +2 -0
  143. package/dist/__tests__/unique-ref-store.unit.test.d.ts.map +1 -0
  144. package/dist/__tests__/utils/handle-numeric.d.ts +14 -0
  145. package/dist/__tests__/utils/handle-numeric.d.ts.map +1 -0
  146. package/dist/__tests__/validation-root-surface.unit.test.d.ts +2 -0
  147. package/dist/__tests__/validation-root-surface.unit.test.d.ts.map +1 -0
  148. package/dist/__tests__/visibility-atomic-write.unit.test.d.ts +2 -0
  149. package/dist/__tests__/visibility-atomic-write.unit.test.d.ts.map +1 -0
  150. package/dist/__tests__/world-change-journal.unit.test.d.ts +2 -0
  151. package/dist/__tests__/world-change-journal.unit.test.d.ts.map +1 -0
  152. package/dist/__tests__/world-characterization.unit.test.d.ts +2 -0
  153. package/dist/__tests__/world-characterization.unit.test.d.ts.map +1 -0
  154. package/dist/__tests__/world-consumer-inference.test-d.d.ts +2 -0
  155. package/dist/__tests__/world-consumer-inference.test-d.d.ts.map +1 -0
  156. package/dist/__tests__/world-health.contract.test.d.ts +2 -0
  157. package/dist/__tests__/world-health.contract.test.d.ts.map +1 -0
  158. package/dist/__tests__/world-inspection.test.d.ts +2 -0
  159. package/dist/__tests__/world-inspection.test.d.ts.map +1 -0
  160. package/dist/__tests__/world-internal-identity.unit.test.d.ts +2 -0
  161. package/dist/__tests__/world-internal-identity.unit.test.d.ts.map +1 -0
  162. package/dist/__tests__/world-managed-roundtrip.unit.test.d.ts +2 -0
  163. package/dist/__tests__/world-managed-roundtrip.unit.test.d.ts.map +1 -0
  164. package/dist/__tests__/world-scheduling.m4.test.d.ts +2 -0
  165. package/dist/__tests__/world-scheduling.m4.test.d.ts.map +1 -0
  166. package/dist/__tests__/world-unique-roundtrip.unit.test.d.ts +2 -0
  167. package/dist/__tests__/world-unique-roundtrip.unit.test.d.ts.map +1 -0
  168. package/dist/__tests__/world.test-d.d.ts +2 -0
  169. package/dist/__tests__/world.test-d.d.ts.map +1 -0
  170. package/dist/buffer-pool.d.ts +109 -0
  171. package/dist/buffer-pool.d.ts.map +1 -0
  172. package/dist/commands.d.ts +93 -0
  173. package/dist/commands.d.ts.map +1 -0
  174. package/dist/component-default-fallback.d.ts +88 -0
  175. package/dist/component-default-fallback.d.ts.map +1 -0
  176. package/dist/component-schema.d.ts +34 -0
  177. package/dist/component-schema.d.ts.map +1 -0
  178. package/dist/component-value-validate.d.ts +29 -0
  179. package/dist/component-value-validate.d.ts.map +1 -0
  180. package/dist/component.d.ts +581 -0
  181. package/dist/component.d.ts.map +1 -0
  182. package/dist/entity-handle.d.ts +68 -0
  183. package/dist/entity-handle.d.ts.map +1 -0
  184. package/dist/entity.d.ts +86 -0
  185. package/dist/entity.d.ts.map +1 -0
  186. package/dist/errors/query-and-component-errors.d.ts +132 -0
  187. package/dist/errors/query-and-component-errors.d.ts.map +1 -0
  188. package/dist/errors/relationship-errors.d.ts +112 -0
  189. package/dist/errors/relationship-errors.d.ts.map +1 -0
  190. package/dist/errors/sprite-and-shared-errors.d.ts +107 -0
  191. package/dist/errors/sprite-and-shared-errors.d.ts.map +1 -0
  192. package/dist/errors/validation-errors.d.ts +229 -0
  193. package/dist/errors/validation-errors.d.ts.map +1 -0
  194. package/dist/errors.d.ts +763 -0
  195. package/dist/errors.d.ts.map +1 -0
  196. package/dist/execution/shared-kernel.d.ts +106 -0
  197. package/dist/execution/shared-kernel.d.ts.map +1 -0
  198. package/dist/externalization/index.d.ts +31 -0
  199. package/dist/externalization/index.d.ts.map +1 -0
  200. package/dist/externalization/index.mjs +298 -0
  201. package/dist/externalization/index.mjs.map +1 -0
  202. package/dist/index.d.ts +261 -0
  203. package/dist/index.d.ts.map +1 -0
  204. package/dist/index.mjs +7422 -0
  205. package/dist/index.mjs.map +1 -0
  206. package/dist/internal.mjs +479 -0
  207. package/dist/internal.mjs.map +1 -0
  208. package/dist/plugin-service.d.ts +11 -0
  209. package/dist/plugin-service.d.ts.map +1 -0
  210. package/dist/projection/index.d.ts +103 -0
  211. package/dist/projection/index.d.ts.map +1 -0
  212. package/dist/projection/index.mjs +615 -0
  213. package/dist/projection/index.mjs.map +1 -0
  214. package/dist/query/query.d.ts +58 -0
  215. package/dist/query/query.d.ts.map +1 -0
  216. package/dist/relationship-index.d.ts +81 -0
  217. package/dist/relationship-index.d.ts.map +1 -0
  218. package/dist/resource.d.ts +70 -0
  219. package/dist/resource.d.ts.map +1 -0
  220. package/dist/schedule-token.d.ts +16 -0
  221. package/dist/schedule-token.d.ts.map +1 -0
  222. package/dist/schedule.d.ts +271 -0
  223. package/dist/schedule.d.ts.map +1 -0
  224. package/dist/shared-ref-store.d.ts +144 -0
  225. package/dist/shared-ref-store.d.ts.map +1 -0
  226. package/dist/shared.d.ts +3 -0
  227. package/dist/shared.d.ts.map +1 -0
  228. package/dist/shared.mjs +364 -0
  229. package/dist/shared.mjs.map +1 -0
  230. package/dist/storage/archetype-graph.d.ts +54 -0
  231. package/dist/storage/archetype-graph.d.ts.map +1 -0
  232. package/dist/storage/archetype.d.ts +23 -0
  233. package/dist/storage/archetype.d.ts.map +1 -0
  234. package/dist/storage/change-detection.d.ts +40 -0
  235. package/dist/storage/change-detection.d.ts.map +1 -0
  236. package/dist/storage/column.d.ts +111 -0
  237. package/dist/storage/column.d.ts.map +1 -0
  238. package/dist/storage/table.d.ts +29 -0
  239. package/dist/storage/table.d.ts.map +1 -0
  240. package/dist/time.d.ts +57 -0
  241. package/dist/time.d.ts.map +1 -0
  242. package/dist/unique-ref-store.d.ts +105 -0
  243. package/dist/unique-ref-store.d.ts.map +1 -0
  244. package/dist/world-change-journal.d.ts +34 -0
  245. package/dist/world-change-journal.d.ts.map +1 -0
  246. package/dist/world-component-access.d.ts +265 -0
  247. package/dist/world-component-access.d.ts.map +1 -0
  248. package/dist/world-component-storage.d.ts +282 -0
  249. package/dist/world-component-storage.d.ts.map +1 -0
  250. package/dist/world-core.d.ts +39 -0
  251. package/dist/world-core.d.ts.map +1 -0
  252. package/dist/world-entity-lifecycle.d.ts +30 -0
  253. package/dist/world-entity-lifecycle.d.ts.map +1 -0
  254. package/dist/world-internal.d.ts +14 -0
  255. package/dist/world-internal.d.ts.map +1 -0
  256. package/dist/world-scheduling.d.ts +30 -0
  257. package/dist/world-scheduling.d.ts.map +1 -0
  258. package/dist/world.d.ts +620 -0
  259. package/dist/world.d.ts.map +1 -0
  260. package/package.json +77 -0
  261. package/src/__fixtures__/field-shape-fixture.ts +30 -0
  262. package/src/__tests__/__fixtures__/inspect-scripts.snapshot.ts +2 -0
  263. package/src/__tests__/archetype.unit.test.ts +1837 -0
  264. package/src/__tests__/array-handle-element.test-d.ts +34 -0
  265. package/src/__tests__/buffer-array-vocab.test-d.ts +53 -0
  266. package/src/__tests__/buffer-field-input-widen.unit.test.ts +99 -0
  267. package/src/__tests__/buffer-pool.test-d.ts +32 -0
  268. package/src/__tests__/change-detection.unit.test.ts +86 -0
  269. package/src/__tests__/command-buffer.test.ts +179 -0
  270. package/src/__tests__/commands-deferred.unit.test.ts +68 -0
  271. package/src/__tests__/component-catalog.test.ts +59 -0
  272. package/src/__tests__/component-definition-identity.unit.test.ts +24 -0
  273. package/src/__tests__/component-nan-preflight.unit.test.ts +186 -0
  274. package/src/__tests__/component-schema.test-d.ts +119 -0
  275. package/src/__tests__/component-schema.test.ts +55 -0
  276. package/src/__tests__/define-component-options.test-d.ts +35 -0
  277. package/src/__tests__/deprecated-vocab-rejection.unit.test.ts +59 -0
  278. package/src/__tests__/despawn-all.unit.test.ts +17 -0
  279. package/src/__tests__/ecs-core-reduction.characterization.test.ts +130 -0
  280. package/src/__tests__/ecs-core-reduction.perf.test.ts +260 -0
  281. package/src/__tests__/ecs-error-code-31.test-d.ts +42 -0
  282. package/src/__tests__/entity-disabling.unit.test.ts +37 -0
  283. package/src/__tests__/entity-handle-codec-parity.unit.test.ts +126 -0
  284. package/src/__tests__/errors.unit.test.ts +1456 -0
  285. package/src/__tests__/execution-conflict-boundary.unit.test.ts +123 -0
  286. package/src/__tests__/execution-shared-storage.unit.test.ts +40 -0
  287. package/src/__tests__/externalization-portable-value.unit.test.ts +275 -0
  288. package/src/__tests__/externalization-projection.unit.test.ts +325 -0
  289. package/src/__tests__/externalization-render-read-lease.test-d.ts +30 -0
  290. package/src/__tests__/externalization-render-read-lease.unit.test.ts +79 -0
  291. package/src/__tests__/externalization-root-surface.unit.test.ts +33 -0
  292. package/src/__tests__/field-enum-labels-reflection.test.ts +66 -0
  293. package/src/__tests__/field-shape-fixture.test.ts +61 -0
  294. package/src/__tests__/field-transient-reflection.test.ts +59 -0
  295. package/src/__tests__/field-value-type.test-d.ts +57 -0
  296. package/src/__tests__/fixed-update.unit.test.ts +78 -0
  297. package/src/__tests__/handle.test-d.ts +86 -0
  298. package/src/__tests__/hierarchy.unit.test.ts +2534 -0
  299. package/src/__tests__/managed-array-vocab.test-d.ts +137 -0
  300. package/src/__tests__/minimal-example.test-d.ts +42 -0
  301. package/src/__tests__/name-read-types.test-d.ts +72 -0
  302. package/src/__tests__/plugin-service.test.ts +13 -0
  303. package/src/__tests__/query-combinations.unit.test.ts +42 -0
  304. package/src/__tests__/query-light-extract-flat-column-ratio.perf.test.ts +252 -0
  305. package/src/__tests__/query-storage-trends.perf.test.ts +104 -0
  306. package/src/__tests__/query-trs-flat-column-ratio.perf.test.ts +194 -0
  307. package/src/__tests__/query.unit.test.ts +196 -0
  308. package/src/__tests__/relationship-index.perf.test.ts +126 -0
  309. package/src/__tests__/relationship-index.test.ts +70 -0
  310. package/src/__tests__/scalar-field-type-owner.test-d.ts +71 -0
  311. package/src/__tests__/schedule-determinism.unit.test.ts +36 -0
  312. package/src/__tests__/schedule-inspection.unit.test.ts +81 -0
  313. package/src/__tests__/schedule-scope-error.unit.test.ts +63 -0
  314. package/src/__tests__/schedule-token.unit.test.ts +54 -0
  315. package/src/__tests__/schema-vocab.test-d.ts +103 -0
  316. package/src/__tests__/serialization.unit.test.ts +2740 -0
  317. package/src/__tests__/shared-kernel-eligibility.test-d.ts +18 -0
  318. package/src/__tests__/shared-kernel-eligibility.unit.test.ts +78 -0
  319. package/src/__tests__/shared-ref-store.unit.test.ts +646 -0
  320. package/src/__tests__/sparse-tag.unit.test.ts +201 -0
  321. package/src/__tests__/spawn-field-error.test-d.ts +41 -0
  322. package/src/__tests__/stale-error.test-d.ts +208 -0
  323. package/src/__tests__/string-view-symmetry.test-d.ts +26 -0
  324. package/src/__tests__/string-vocab.test-d.ts +49 -0
  325. package/src/__tests__/structure-epoch-boundaries.unit.test.ts +39 -0
  326. package/src/__tests__/structure-epoch.unit.test.ts +48 -0
  327. package/src/__tests__/table-archetype-mapping.unit.test.ts +78 -0
  328. package/src/__tests__/time.unit.test.ts +79 -0
  329. package/src/__tests__/types.test-d.ts +38 -0
  330. package/src/__tests__/unique-ref-store.unit.test.ts +348 -0
  331. package/src/__tests__/utils/handle-numeric.ts +30 -0
  332. package/src/__tests__/validation-root-surface.unit.test.ts +15 -0
  333. package/src/__tests__/visibility-atomic-write.unit.test.ts +82 -0
  334. package/src/__tests__/world-change-journal.unit.test.ts +97 -0
  335. package/src/__tests__/world-characterization.unit.test.ts +408 -0
  336. package/src/__tests__/world-consumer-inference.test-d.ts +16 -0
  337. package/src/__tests__/world-health.contract.test.ts +87 -0
  338. package/src/__tests__/world-inspection.test.ts +37 -0
  339. package/src/__tests__/world-internal-identity.unit.test.ts +17 -0
  340. package/src/__tests__/world-managed-roundtrip.unit.test.ts +98 -0
  341. package/src/__tests__/world-scheduling.m4.test.ts +52 -0
  342. package/src/__tests__/world-unique-roundtrip.unit.test.ts +357 -0
  343. package/src/__tests__/world.test-d.ts +156 -0
  344. package/src/buffer-pool.ts +357 -0
  345. package/src/commands.ts +644 -0
  346. package/src/component-default-fallback.ts +236 -0
  347. package/src/component-schema.ts +92 -0
  348. package/src/component-value-validate.ts +135 -0
  349. package/src/component.ts +1268 -0
  350. package/src/entity-handle.ts +104 -0
  351. package/src/entity.ts +140 -0
  352. package/src/errors/query-and-component-errors.ts +200 -0
  353. package/src/errors/relationship-errors.ts +198 -0
  354. package/src/errors/sprite-and-shared-errors.ts +231 -0
  355. package/src/errors/validation-errors.ts +506 -0
  356. package/src/errors.ts +1464 -0
  357. package/src/execution/shared-kernel.ts +392 -0
  358. package/src/externalization/index.ts +170 -0
  359. package/src/index.ts +414 -0
  360. package/src/plugin-service.ts +35 -0
  361. package/src/projection/index.ts +318 -0
  362. package/src/query/query.ts +606 -0
  363. package/src/relationship-index.ts +175 -0
  364. package/src/resource.ts +106 -0
  365. package/src/schedule-token.ts +40 -0
  366. package/src/schedule.ts +846 -0
  367. package/src/shared-ref-store.ts +418 -0
  368. package/src/shared.ts +23 -0
  369. package/src/storage/archetype-graph.ts +166 -0
  370. package/src/storage/archetype.ts +78 -0
  371. package/src/storage/change-detection.ts +231 -0
  372. package/src/storage/column.ts +247 -0
  373. package/src/storage/table.ts +153 -0
  374. package/src/time.ts +122 -0
  375. package/src/unique-ref-store.ts +278 -0
  376. package/src/world-change-journal.ts +84 -0
  377. package/src/world-component-access.ts +1421 -0
  378. package/src/world-component-storage.ts +1178 -0
  379. package/src/world-core.ts +74 -0
  380. package/src/world-entity-lifecycle.ts +539 -0
  381. package/src/world-internal.ts +75 -0
  382. package/src/world-scheduling.ts +499 -0
  383. package/src/world.ts +1399 -0
@@ -0,0 +1,236 @@
1
+ // @forgeax/engine-ecs - Layer-3 default-value SSOT helper (feat-20260517-
2
+ // spawn-default-fallback / M1).
3
+ //
4
+ // AI users: this file is the SINGLE PHYSICAL LOCATION of the layer-3
5
+ // `typeDefault(fieldType)` table. Three runtime paths consume it (D-2
6
+ // / plan-strategy §2.1 / AC-05):
7
+ //
8
+ // - `world.spawn(...)` (M2 — t9)
9
+ // - `world.addComponent(...)` (M2 — t9, ComponentData<S> shared)
10
+ //
11
+ // Two-layer split (D-3 / plan-strategy §2.2 — DELIBERATELY NOT MERGED):
12
+ //
13
+ // layer-3 (this file)
14
+ // "raw value fallback" — fills missing schema fields with the
15
+ // spawn-data raw shape: 0 / false / ENTITY_NULL_RAW / [] / 0 (slot
16
+ // id placeholder). The output is the input shape `world.spawn`
17
+ // receives (`Partial<ShapeOf<S>>` -> `Record<string, unknown>` with
18
+ // all schema keys present).
19
+ //
20
+ // layer-4 (silent fallback inside writeRow / write{Buffer,Array,
21
+ // UniqueRef}Field)
22
+ // "column-store value fallback" — when raw === 0 hits a managed-
23
+ // family arm (string / unique<T> / buffer / buffer<N> / array<T> for
24
+ // T != entity), the column store routes 0 to "empty slot" semantics
25
+ // (UniqueRefStore handle 0 / BufferPool slot 0 / array slot
26
+ // length === 0). The two layers are NEVER merged — layer-3 stays
27
+ // pure / unaware of column physics; layer-4 stays inside writeRow
28
+ // where the column instance is in scope.
29
+ //
30
+ // The 14-vocab x default-value table (AC-06 closed table, grep-gate t2
31
+ // keyword "layer-3 typeDefault table"):
32
+ //
33
+ // ScalarFieldType (11 arms):
34
+ // f32 / f64 / i32 / u32 / i16 / u16 / i8 / u8 -> 0
35
+ // bool -> false
36
+ // enum / ref (legacy scalar) -> 0
37
+ //
38
+ // SchemaVocabKeyword (8 arms; one "buffer" + one "buffer<N>"; one
39
+ // "ref<T>" + one "handle<T>"; one "entity" + one "string"; two array
40
+ // variants — array<T,N> / array<T> — collapse to two table arms:
41
+ // 'string' -> 0 (uniqueRefs handle slot;
42
+ // resolved payload '' on read)
43
+ // 'entity' -> ENTITY_NULL_RAW (NULL_ENTITY u32
44
+ // = 0xffffffff)
45
+ // 'array<entity>' -> [] (THE ONLY array<T> arm with []
46
+ // — entity[] runtime shape is a
47
+ // JS array of Entity, not a
48
+ // BufferPool slot id)
49
+ // 'array<T>' (T != entity) -> 0 (BufferPool slot id; layer-4
50
+ // writeArrayField bottoms out to
51
+ // empty slot — D-2 asymmetric;
52
+ // SceneAsset byte-equivalence,
53
+ // OOS-6 letter)
54
+ // 'array<T, N>' (any T) -> 0 (inline stride-N column,
55
+ // feat-20260602; fallback writes the
56
+ // zeroed row, not a slot id)
57
+ // 'buffer' -> 0 (BufferPool slot id; variable
58
+ // byte capacity)
59
+ // 'buffer<N>' -> 0 (inline stride-N u8 column,
60
+ // feat-20260602; fallback writes the
61
+ // zeroed row, not a slot id)
62
+ // 'unique<T>' -> 0 (UniqueRefStore handle slot)
63
+ // 'handle<T>' -> 0 (unmanaged handle phantom u32;
64
+ // schema-level nullable -> NULL
65
+ // sentinel 0)
66
+ //
67
+ // Brand-class semantics (AC-10 / requirements §A-3 reframe round 2):
68
+ // `handle<T>` and `ref<T>` are SCHEMA-LEVEL nullable. Spawn `data: {}`
69
+ // is legal; layer-3 fills 0 (NULL sentinel for unmanaged handles) /
70
+ // 0 (uniqueRefs handle slot, '' payload). SceneAsset.instantiate
71
+ // produces byte-equivalent column state.
72
+ //
73
+ // Anchors:
74
+ // - requirements §AC-05 (helper SSOT) + §AC-06 (closed 14-vocab table)
75
+ // + §AC-09 (SceneAsset byte-equiv) + §AC-10 (brand-class nullable)
76
+ // - plan-strategy §2.1 (helper file location decision)
77
+ // §2.2 (two-layer split JSDoc declaration)
78
+ // §2.3 (array<T> T!=entity asymmetric raw 0)
79
+ // §3.1 (helper node in component graph)
80
+ // §8.2 (naming rules: fillComponentDefaults / typeDefault)
81
+ // §8.4 (head JSDoc as discovery anchor)
82
+
83
+ import type { Component, ComponentSchema } from './component';
84
+ import { componentSchema } from './component';
85
+ import { componentDefinition } from './component-schema';
86
+ import { ENTITY_NULL_RAW } from './entity-handle';
87
+ import { SpawnDataUnknownFieldError } from './errors';
88
+
89
+ /**
90
+ * Layer-3 silent default for a single schema field type. Returned when
91
+ * the spawn-data raw input (layer 1) and the owner definition defaults
92
+ * map (layer 2) both omit a known schema field.
93
+ *
94
+ * Pure function — runs once per missing field per (component, spawn /
95
+ * instantiate) call. No `BufferPool` / `UniqueRefStore` / `World`
96
+ * dependency: the helper hands back raw column-shape values (u32 / bool
97
+ * / number array literal); the layer-4 silent fallback inside
98
+ * `writeRow` / `write{Buffer,Array,UniqueRef}Field` turns raw `0` into
99
+ * the live column-store value (unique-ref handle 0 / BufferPool slot
100
+ * id 0 / array slot length 0).
101
+ *
102
+ * Mapping is the same closed table the head-JSDoc table documents.
103
+ *
104
+ * @internal — helper-private; AI users call `fillComponentDefaults`.
105
+ */
106
+ function typeDefault(fieldType: string): unknown {
107
+ // bool is the only scalar arm with a non-zero default.
108
+ if (fieldType === 'bool') return false;
109
+ // 'entity' uses the runtime NULL_ENTITY sentinel (0xffffffff).
110
+ if (fieldType === 'entity') return ENTITY_NULL_RAW;
111
+ // 'array<entity>' is the only array<T> arm whose layer-3 default is a
112
+ // JS array literal — entity[] runtime shape is a JS Array<Entity>,
113
+ // not a BufferPool slot id (D-2 asymmetric pivot).
114
+ if (fieldType === 'array<entity>') return [];
115
+ // every other vocab keyword (incl. 'string' / 'unique<T>' / 'handle<T>'
116
+ // / 'buffer' / 'buffer<N>' / 'array<T>' (T!=entity) / 'array<T, N>')
117
+ // and every remaining ScalarFieldType (f* / i* / u* / enum / ref)
118
+ // defaults to numeric 0 at the spawn-data raw surface. Layer-4
119
+ // silent fallback inside writeRow turns 0 into the empty-slot
120
+ // shape on the column-store side when applicable.
121
+ return 0;
122
+ }
123
+
124
+ /**
125
+ * Fill missing schema fields on a partial spawn-data raw with their
126
+ * layer-2 / layer-3 defaults. Public surface used by:
127
+ *
128
+ * - `World.spawn` (writeRow entry, M2)
129
+ * - `World.addComponent` (writeRow entry, M2)
130
+ *
131
+ * Resolution order (matches scene-instance-container.ts JSDoc):
132
+ *
133
+ * layer 1 — explicit raw value (caller passed `data[field] = v`).
134
+ * Carrier: the raw input itself; not handled by this
135
+ * helper — copied through the `if (key in raw)` branch.
136
+ * SceneAsset.instantiate additionally remaps `entity` /
137
+ * `array<entity>` LocalEntityId values BEFORE handing the raw
138
+ * to the helper (the entity-remap layer is NOT this
139
+ * helper's responsibility).
140
+ *
141
+ * layer 2 — owner definition defaults (declared via
142
+ * `defineComponent(name, schema, { defaults })`). Layer-2
143
+ * defaults beat layer-3.
144
+ *
145
+ * layer 3 — `typeDefault(fieldType)` (this file's private dispatch).
146
+ *
147
+ * Returns a fresh `Record<string, unknown>` carrying every schema
148
+ * field. The output is column-shape raw — the caller's writeRow path
149
+ * walks it field-by-field and applies layer-4 silent fallback when a
150
+ * raw `0` lands on a managed-family arm.
151
+ *
152
+ * Pure: no World / store side effect. Thread-safety irrelevant (single-
153
+ * thread JS engine), but the helper allocates one `Object.create(null)`
154
+ * per call so repeated invocations cannot share a mutable record.
155
+ *
156
+ * @param token Component token (name + schema + optional defaults).
157
+ * @param raw Partial spawn-data raw — caller's `Partial<ShapeOf<S>>`.
158
+ * Keys not present in the schema are passed through
159
+ * unchanged (the spawn write path will emit a write-time
160
+ * error if applicable; helper does not validate keys).
161
+ * @returns Record with every schema field populated by layer-1 /
162
+ * layer-2 / layer-3 defaults in that order.
163
+ */
164
+ export function fillComponentDefaults<S extends ComponentSchema>(
165
+ token: Component<string, S>,
166
+ raw: Partial<Record<string, unknown>> | undefined,
167
+ ): Record<string, unknown> {
168
+ const schema = componentSchema(token) as Record<string, string>;
169
+ const layer2 = componentDefinition(token).defaults;
170
+ const out: Record<string, unknown> = Object.create(null);
171
+ const rawObj = (raw as Record<string, unknown> | undefined) ?? undefined;
172
+ for (const fieldName of Object.keys(schema)) {
173
+ const fieldType = schema[fieldName];
174
+ if (fieldType === undefined) continue;
175
+ // layer 1 — explicit raw value (caller may pass undefined to mean
176
+ // "use default"; mirror the existing scene-instance-container
177
+ // behaviour where the gate is `fieldName in raw`).
178
+ if (rawObj !== undefined && fieldName in rawObj) {
179
+ out[fieldName] = rawObj[fieldName];
180
+ continue;
181
+ }
182
+ // layer 2 — component-level defaults map.
183
+ if (layer2 !== undefined && fieldName in layer2) {
184
+ out[fieldName] = layer2[fieldName];
185
+ continue;
186
+ }
187
+ // layer 3 — TS type defaults (silent — no error code).
188
+ out[fieldName] = typeDefault(fieldType);
189
+ }
190
+ return out;
191
+ }
192
+
193
+ // Re-export the private dispatch for unit-test introspection (t1
194
+ // keyword pin — every vocab arm gets a one-liner it() block). The
195
+ // helper-private arity is preserved at callers via the
196
+ // `fillComponentDefaults` boundary.
197
+ export { typeDefault };
198
+
199
+ /**
200
+ * Validate that every key in `raw` is a declared schema field on `token`.
201
+ *
202
+ * Returned as a `SpawnDataUnknownFieldError` on the FIRST offending key
203
+ * (deterministic for AI users; subsequent unknown keys surface on the next
204
+ * spawn after the first is fixed). Pre-fix the unknown key was silently
205
+ * dropped inside `fillComponentDefaults` (which iterates only schema keys),
206
+ * routing typos like `MeshRenderer { material }` (singular legacy field name)
207
+ * into the empty-default path and producing invisible / mid-grey entities
208
+ * downstream.
209
+ *
210
+ * Pure: no World / store side effect; allocates no closure on the hot path
211
+ * (early-returns null when raw is undefined / empty).
212
+ *
213
+ * Call order at every spawn / addComponent / SceneAsset.instantiate /
214
+ * Commands.spawn site: validate FIRST, then `fillComponentDefaults`. The
215
+ * split keeps `fillComponentDefaults` pure (charter P3 SSOT — a fill helper
216
+ * never validates) while every layer-1 raw key reaches one validator gate.
217
+ *
218
+ * @param token Component token (name + schema).
219
+ * @param raw Caller's `Partial<ShapeOf<S>>` — raw spawn payload.
220
+ * @returns `null` on success; `SpawnDataUnknownFieldError` on the first
221
+ * key not declared in `componentSchema(token)`.
222
+ */
223
+ export function validateComponentDataKeys<S extends ComponentSchema>(
224
+ token: Component<string, S>,
225
+ raw: Partial<Record<string, unknown>> | undefined,
226
+ ): SpawnDataUnknownFieldError | null {
227
+ if (raw === undefined) return null;
228
+ const schema = componentSchema(token) as Record<string, unknown>;
229
+ const rawObj = raw as Record<string, unknown>;
230
+ for (const fieldName of Object.keys(rawObj)) {
231
+ if (!(fieldName in schema)) {
232
+ return new SpawnDataUnknownFieldError(token.name, fieldName, Object.keys(schema));
233
+ }
234
+ }
235
+ return null;
236
+ }
@@ -0,0 +1,92 @@
1
+ import type { Component, FieldReflection, SchemaFieldType } from './component';
2
+
3
+ /** The complete storage placement vocabulary owned by ECS schema. */
4
+ export type ComponentStorageKind = 'table' | 'sparse';
5
+
6
+ /** The stable public facts needed to describe a component schema offline. */
7
+ export interface ComponentSchemaDefinition {
8
+ readonly name: string;
9
+ readonly fields: Readonly<Record<string, SchemaFieldType>>;
10
+ readonly storage: ComponentStorageKind;
11
+ }
12
+
13
+ /**
14
+ * Serialization facts owned beside schema registration, not carried by the
15
+ * public component token. Queries and storage only need the token's schema
16
+ * vocabulary; domain validation and lifecycle belong to their owners.
17
+ */
18
+ export interface ComponentPolicy {
19
+ readonly transient: boolean;
20
+ readonly meta: Record<string, unknown>;
21
+ }
22
+
23
+ /** Immutable schema reflection plus non-token policy projection. */
24
+ export interface ComponentDefinition {
25
+ readonly fields: Readonly<Record<string, FieldReflection>>;
26
+ readonly defaults: Readonly<Record<string, unknown>> | undefined;
27
+ readonly policy: ComponentPolicy;
28
+ }
29
+
30
+ // Component tokens can cross independently bundled ECS entry points. Share
31
+ // the owner registry through globalThis rather than attaching a hidden symbol
32
+ // to each token; `Reflect.ownKeys(token)` must remain exactly the three public
33
+ // facts name/fields/storage.
34
+ const COMPONENT_REGISTRY = Symbol.for('forgeax.ecs.componentRegistry');
35
+ interface ComponentRegistry {
36
+ readonly definitions: WeakMap<object, ComponentDefinition>;
37
+ }
38
+ const globalSymbols = globalThis as typeof globalThis & { [key: symbol]: unknown };
39
+ const definitions =
40
+ (globalSymbols[COMPONENT_REGISTRY] as ComponentRegistry | undefined) ??
41
+ (() => {
42
+ const registry: ComponentRegistry = { definitions: new WeakMap<object, ComponentDefinition>() };
43
+ globalSymbols[COMPONENT_REGISTRY] = registry;
44
+ return registry;
45
+ })();
46
+
47
+ export function registerComponentDefinition(
48
+ component: Component,
49
+ definition: ComponentDefinition,
50
+ ): void {
51
+ definitions.definitions.set(component, definition);
52
+ }
53
+
54
+ /** Read the definition-time schema/policy projection for a component token. */
55
+ export function componentDefinition(component: Component): ComponentDefinition {
56
+ const definition = definitions.definitions.get(component);
57
+ if (definition === undefined) {
58
+ throw new Error(`Component definition missing for '${component.name}'.`);
59
+ }
60
+ return definition;
61
+ }
62
+
63
+ /**
64
+ * Freeze a schema value recursively. Component descriptors are authored data,
65
+ * so nested defaults and enum label maps must not become mutation channels.
66
+ */
67
+ export function deepFreeze<T>(value: T): Readonly<T> {
68
+ if (value === null || (typeof value !== 'object' && typeof value !== 'function')) {
69
+ return value as Readonly<T>;
70
+ }
71
+ // Non-empty TypedArrays reject Object.freeze and their indexed elements
72
+ // remain writable even when the wrapper is frozen. Treat binary views as
73
+ // immutable leaf projections; the authored descriptor around them is still
74
+ // recursively frozen by this function.
75
+ if (ArrayBuffer.isView(value) || value instanceof ArrayBuffer) {
76
+ return value as Readonly<T>;
77
+ }
78
+ const object = value as object;
79
+ for (const key of Reflect.ownKeys(object)) {
80
+ const child = (object as Record<PropertyKey, unknown>)[key];
81
+ if (child !== null && (typeof child === 'object' || typeof child === 'function')) {
82
+ deepFreeze(child);
83
+ }
84
+ }
85
+ return Object.freeze(value) as Readonly<T>;
86
+ }
87
+
88
+ export function assertComponentStorage(value: string): asserts value is ComponentStorageKind {
89
+ if (value !== 'table' && value !== 'sparse') {
90
+ throw new Error(`Unsupported component storage '${value}'. Expected 'table' or 'sparse'.`);
91
+ }
92
+ }
@@ -0,0 +1,135 @@
1
+ // feat-20260713-mount-override-component-add-and-shared-ref-round M2 / w9 —
2
+ // P3 shared-field value gate.
3
+ //
4
+ // `validateComponentDataKeys` (component-default-fallback.ts) checks that every
5
+ // key in a spawn / addComponent / set payload is a declared schema field. It
6
+ // does NOT check value TYPES. A `shared<T>` scalar / `array<shared<T>>` element
7
+ // must be a resolved numeric Handle; a raw GUID string / `{ guid }` / `{ kind }`
8
+ // object (the pre-resolution shape a sidecar hands an AI user) was silently
9
+ // coerced to the all-zero sentinel by the column packer
10
+ // (`typed[i] = typeof val === 'number' ? val : 0`) / scalar write path, so a
11
+ // mis-bound reference read back as `0` / `[0,0,0,0]` and rendered blank with no
12
+ // error.
13
+ //
14
+ // This module closes that value-type gap. It is a pure validator (no World /
15
+ // store side effect) invoked at all three write entries (spawn / addComponent /
16
+ // set) BEFORE any archetype mutation, mirroring the validate-first ordering of
17
+ // `validateComponentDataKeys`. §2.5: it depends only on the schema field-type
18
+ // SHAPE (`shared<...>` / `array<shared<...>>`), never on any GUID / asset
19
+ // concretion — the GUID domain stays sealed in assets-runtime; ecs only sees a
20
+ // numeric handle vs a non-handle.
21
+
22
+ import type { Component, ComponentSchema } from './component';
23
+ import { componentSchema } from './component';
24
+ import { componentDefinition } from './component-schema';
25
+ import { ManagedArrayInvalidValueError, SharedFieldInvalidValueError } from './errors';
26
+
27
+ /** A resolved shared handle is a plain number (the branded Handle bit pattern). */
28
+ function isNumericHandle(v: unknown): boolean {
29
+ return typeof v === 'number';
30
+ }
31
+
32
+ /** `shared<T>` scalar field type. */
33
+ function isSharedScalarType(fieldType: string): boolean {
34
+ return fieldType.startsWith('shared<') && fieldType.endsWith('>');
35
+ }
36
+
37
+ /**
38
+ * `array<shared<T>>` / `array<shared<T>, N>` field type. The inner element type
39
+ * is a `shared<...>` template; we test the array wrapper and the `shared<`
40
+ * infix rather than fully re-parsing (parseManagedArraySchema owns the strict
41
+ * grammar — here we only need the coarse "is this an array of shared refs"
42
+ * discriminant).
43
+ */
44
+ function isSharedArrayType(fieldType: string): boolean {
45
+ if (!fieldType.startsWith('array<') || !fieldType.endsWith('>')) return false;
46
+ const inner = fieldType.slice(6, -1);
47
+ const head = inner.indexOf(',') === -1 ? inner : inner.slice(0, inner.indexOf(',')).trim();
48
+ return head.startsWith('shared<') && head.endsWith('>');
49
+ }
50
+
51
+ function isArrayPayload(value: unknown): boolean {
52
+ if (Array.isArray(value)) return true;
53
+ // DataView and ArrayBuffer are views/buffers without an element `length`;
54
+ // the storage writer cannot interpret them as a managed array payload.
55
+ return ArrayBuffer.isView(value) && typeof (value as { length?: unknown }).length === 'number';
56
+ }
57
+
58
+ /**
59
+ * Validate the outer value shape for every managed `array<T>` field present in
60
+ * a write payload. This is deliberately a preflight-only check: element
61
+ * coercion remains owned by the column writer, while arbitrary objects are
62
+ * rejected before any row, buffer slot, retain, or epoch mutation can occur.
63
+ */
64
+ export function validateManagedArrayValues<S extends ComponentSchema>(
65
+ token: Component<string, S>,
66
+ raw: Partial<Record<string, unknown>> | undefined,
67
+ ): ManagedArrayInvalidValueError | null {
68
+ if (raw === undefined) return null;
69
+ const fields = componentDefinition(token).fields as Readonly<
70
+ Record<string, { readonly type: string; readonly arrayMeta?: unknown }>
71
+ >;
72
+ const rawObj = raw as Record<string, unknown>;
73
+ for (const fieldName of Object.keys(rawObj)) {
74
+ const reflection = fields[fieldName];
75
+ if (reflection?.arrayMeta === undefined) continue;
76
+ const value = rawObj[fieldName];
77
+ // `fillComponentDefaults` deliberately uses numeric zero as the layer-3
78
+ // raw sentinel for every non-entity array vocabulary. The column writer
79
+ // owns translating that sentinel into an empty variable slot or a
80
+ // zero-filled fixed row, so it must pass this preflight just like an
81
+ // omitted/null value. Other scalar/object values remain invalid.
82
+ if (value === 0) continue;
83
+ if (value === undefined || value === null || isArrayPayload(value)) continue;
84
+ return new ManagedArrayInvalidValueError(token.name, fieldName, reflection.type, value);
85
+ }
86
+ return null;
87
+ }
88
+
89
+ /**
90
+ * Validate that every `shared<T>` scalar / `array<shared<T>>` element present in
91
+ * `raw` is a resolved numeric Handle. Returns the FIRST offending field's
92
+ * `SharedFieldInvalidValueError` (deterministic for AI users), or `null` on
93
+ * success.
94
+ *
95
+ * Pure: no World / store side effect. Only fields PRESENT in `raw` are checked
96
+ * (an omitted shared field takes its schema default — a numeric sentinel — via
97
+ * `fillComponentDefaults`, so it is never a non-handle). `undefined` / `null`
98
+ * values are treated as "omitted" (the write path routes them to the sentinel
99
+ * intentionally); only a concrete non-numeric value (string / object) is a
100
+ * mis-bound GUID and fails fast.
101
+ *
102
+ * @param token Component token (name + schema).
103
+ * @param raw Caller's raw payload (spawn / addComponent / set value).
104
+ * @returns `null` on success; `SharedFieldInvalidValueError` on the first
105
+ * shared field bound to a non-handle value.
106
+ */
107
+ export function validateSharedFieldValues<S extends ComponentSchema>(
108
+ token: Component<string, S>,
109
+ raw: Partial<Record<string, unknown>> | undefined,
110
+ ): SharedFieldInvalidValueError | null {
111
+ if (raw === undefined) return null;
112
+ const schema = componentSchema(token) as Record<string, string>;
113
+ const rawObj = raw as Record<string, unknown>;
114
+ for (const fieldName of Object.keys(rawObj)) {
115
+ const fieldType = schema[fieldName];
116
+ if (fieldType === undefined) continue; // key validation owns unknown keys.
117
+ const value = rawObj[fieldName];
118
+ if (value === undefined || value === null) continue; // omitted -> sentinel default.
119
+ if (isSharedScalarType(fieldType)) {
120
+ if (!isNumericHandle(value)) {
121
+ return new SharedFieldInvalidValueError(token.name, fieldName, fieldType, value);
122
+ }
123
+ } else if (isSharedArrayType(fieldType)) {
124
+ if (!Array.isArray(value)) continue; // non-array raw for an array field: write path no-ops.
125
+ for (let i = 0; i < value.length; i++) {
126
+ const el = value[i];
127
+ if (el === undefined || el === null) continue;
128
+ if (!isNumericHandle(el)) {
129
+ return new SharedFieldInvalidValueError(token.name, fieldName, fieldType, el, i);
130
+ }
131
+ }
132
+ }
133
+ }
134
+ return null;
135
+ }