@forgeax/engine-assets-runtime 0.1.3 → 0.1.6

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 (313) hide show
  1. package/README.md +442 -175
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/__tests__/aabb.unit.test.d.ts +2 -0
  4. package/dist/__tests__/aabb.unit.test.d.ts.map +1 -0
  5. package/dist/__tests__/artifact-integrity.unit.test.d.ts +2 -0
  6. package/dist/__tests__/artifact-integrity.unit.test.d.ts.map +1 -0
  7. package/dist/__tests__/artifact-io.unit.test.d.ts +2 -0
  8. package/dist/__tests__/artifact-io.unit.test.d.ts.map +1 -0
  9. package/dist/__tests__/asset-evidence-sdk.integration.test.d.ts +2 -0
  10. package/dist/__tests__/asset-evidence-sdk.integration.test.d.ts.map +1 -0
  11. package/dist/__tests__/asset-evidence.unit.test.d.ts +2 -0
  12. package/dist/__tests__/asset-evidence.unit.test.d.ts.map +1 -0
  13. package/dist/__tests__/asset-kind.unit.test.d.ts +2 -0
  14. package/dist/__tests__/asset-kind.unit.test.d.ts.map +1 -0
  15. package/dist/__tests__/asset-registry-catalog-reconcile.integration.test.d.ts +2 -0
  16. package/dist/__tests__/asset-registry-catalog-reconcile.integration.test.d.ts.map +1 -0
  17. package/dist/__tests__/asset-registry-catalog-reconcile.unit.test.d.ts +2 -0
  18. package/dist/__tests__/asset-registry-catalog-reconcile.unit.test.d.ts.map +1 -0
  19. package/dist/__tests__/asset-registry-catalog.unit.test.d.ts +2 -0
  20. package/dist/__tests__/asset-registry-catalog.unit.test.d.ts.map +1 -0
  21. package/dist/__tests__/asset-registry.pack-cache.test.d.ts +2 -0
  22. package/dist/__tests__/asset-registry.pack-cache.test.d.ts.map +1 -0
  23. package/dist/__tests__/asset-registry.unit.test.d.ts +2 -0
  24. package/dist/__tests__/asset-registry.unit.test.d.ts.map +1 -0
  25. package/dist/__tests__/asset-runtime-error-code-owner.test-d.d.ts +2 -0
  26. package/dist/__tests__/asset-runtime-error-code-owner.test-d.d.ts.map +1 -0
  27. package/dist/__tests__/catalog-replica.unit.test.d.ts +2 -0
  28. package/dist/__tests__/catalog-replica.unit.test.d.ts.map +1 -0
  29. package/dist/__tests__/catalog-source-v2.unit.test.d.ts +2 -0
  30. package/dist/__tests__/catalog-source-v2.unit.test.d.ts.map +1 -0
  31. package/dist/__tests__/catalog-source.unit.test.d.ts +2 -0
  32. package/dist/__tests__/catalog-source.unit.test.d.ts.map +1 -0
  33. package/dist/__tests__/catalog-subscription-order.unit.test.d.ts +2 -0
  34. package/dist/__tests__/catalog-subscription-order.unit.test.d.ts.map +1 -0
  35. package/dist/__tests__/catalog-subscription.unit.test.d.ts +2 -0
  36. package/dist/__tests__/catalog-subscription.unit.test.d.ts.map +1 -0
  37. package/dist/__tests__/decode-image-bytes-pass-through.test.d.ts +2 -0
  38. package/dist/__tests__/decode-image-bytes-pass-through.test.d.ts.map +1 -0
  39. package/dist/__tests__/decode-image-bytes.browser.test.d.ts +2 -0
  40. package/dist/__tests__/decode-image-bytes.browser.test.d.ts.map +1 -0
  41. package/dist/__tests__/decode-image-bytes.test-d.d.ts +2 -0
  42. package/dist/__tests__/decode-image-bytes.test-d.d.ts.map +1 -0
  43. package/dist/__tests__/decode-image-bytes.test.d.ts +2 -0
  44. package/dist/__tests__/decode-image-bytes.test.d.ts.map +1 -0
  45. package/dist/__tests__/dynamic-texture-store.unit.test.d.ts +2 -0
  46. package/dist/__tests__/dynamic-texture-store.unit.test.d.ts.map +1 -0
  47. package/dist/__tests__/errors-asset.unit.test.d.ts +2 -0
  48. package/dist/__tests__/errors-asset.unit.test.d.ts.map +1 -0
  49. package/dist/__tests__/inline-pack-loaders.unit.test.d.ts +2 -0
  50. package/dist/__tests__/inline-pack-loaders.unit.test.d.ts.map +1 -0
  51. package/dist/__tests__/instantiate-context.unit.test.d.ts +2 -0
  52. package/dist/__tests__/instantiate-context.unit.test.d.ts.map +1 -0
  53. package/dist/__tests__/instantiate-publication-fence.unit.test.d.ts +2 -0
  54. package/dist/__tests__/instantiate-publication-fence.unit.test.d.ts.map +1 -0
  55. package/dist/__tests__/instantiate.unit.test.d.ts +2 -0
  56. package/dist/__tests__/instantiate.unit.test.d.ts.map +1 -0
  57. package/dist/__tests__/loader-input-contract.unit.test.d.ts +2 -0
  58. package/dist/__tests__/loader-input-contract.unit.test.d.ts.map +1 -0
  59. package/dist/__tests__/loader-registry.unit.test.d.ts +2 -0
  60. package/dist/__tests__/loader-registry.unit.test.d.ts.map +1 -0
  61. package/dist/__tests__/material-dependency-invalidation.unit.test.d.ts +2 -0
  62. package/dist/__tests__/material-dependency-invalidation.unit.test.d.ts.map +1 -0
  63. package/dist/__tests__/material-generation-cache.unit.test.d.ts +2 -0
  64. package/dist/__tests__/material-generation-cache.unit.test.d.ts.map +1 -0
  65. package/dist/__tests__/material-load-consumer.test-d.d.ts +2 -0
  66. package/dist/__tests__/material-load-consumer.test-d.d.ts.map +1 -0
  67. package/dist/__tests__/material-ready.integration.test.d.ts +2 -0
  68. package/dist/__tests__/material-ready.integration.test.d.ts.map +1 -0
  69. package/dist/__tests__/material-stale-generation.unit.test.d.ts +2 -0
  70. package/dist/__tests__/material-stale-generation.unit.test.d.ts.map +1 -0
  71. package/dist/__tests__/mesh-bin-morph-v3.test.d.ts +2 -0
  72. package/dist/__tests__/mesh-bin-morph-v3.test.d.ts.map +1 -0
  73. package/dist/__tests__/mesh-bin.unit.test.d.ts +2 -0
  74. package/dist/__tests__/mesh-bin.unit.test.d.ts.map +1 -0
  75. package/dist/__tests__/mipmap-generator.unit.test.d.ts +2 -0
  76. package/dist/__tests__/mipmap-generator.unit.test.d.ts.map +1 -0
  77. package/dist/__tests__/pack-artifact-transcode-model-owner.test.d.ts +2 -0
  78. package/dist/__tests__/pack-artifact-transcode-model-owner.test.d.ts.map +1 -0
  79. package/dist/__tests__/pack-basis-load.integration.test.d.ts +2 -0
  80. package/dist/__tests__/pack-basis-load.integration.test.d.ts.map +1 -0
  81. package/dist/__tests__/payload-validate.unit.test.d.ts +2 -0
  82. package/dist/__tests__/payload-validate.unit.test.d.ts.map +1 -0
  83. package/dist/__tests__/plugin.test.d.ts +2 -0
  84. package/dist/__tests__/plugin.test.d.ts.map +1 -0
  85. package/dist/__tests__/registry-concurrency.bench.test.d.ts +2 -0
  86. package/dist/__tests__/registry-concurrency.bench.test.d.ts.map +1 -0
  87. package/dist/__tests__/registry-failure-retry.integration.test.d.ts +2 -0
  88. package/dist/__tests__/registry-failure-retry.integration.test.d.ts.map +1 -0
  89. package/dist/__tests__/registry-load-graph.integration.test.d.ts +2 -0
  90. package/dist/__tests__/registry-load-graph.integration.test.d.ts.map +1 -0
  91. package/dist/__tests__/registry-load-state.unit.test.d.ts +2 -0
  92. package/dist/__tests__/registry-load-state.unit.test.d.ts.map +1 -0
  93. package/dist/__tests__/registry-package-cache.unit.test.d.ts +2 -0
  94. package/dist/__tests__/registry-package-cache.unit.test.d.ts.map +1 -0
  95. package/dist/__tests__/registry-public-ready.unit.test.d.ts +2 -0
  96. package/dist/__tests__/registry-public-ready.unit.test.d.ts.map +1 -0
  97. package/dist/__tests__/resolve-asset-handle.unit.test.d.ts +2 -0
  98. package/dist/__tests__/resolve-asset-handle.unit.test.d.ts.map +1 -0
  99. package/dist/__tests__/scene-handle-fields.unit.test.d.ts +2 -0
  100. package/dist/__tests__/scene-handle-fields.unit.test.d.ts.map +1 -0
  101. package/dist/__tests__/scene-payload.unit.test.d.ts +2 -0
  102. package/dist/__tests__/scene-payload.unit.test.d.ts.map +1 -0
  103. package/dist/__tests__/scene-publication-fence.test.d.ts +2 -0
  104. package/dist/__tests__/scene-publication-fence.test.d.ts.map +1 -0
  105. package/dist/__tests__/scriptable-pack-public-surface.test-d.d.ts +2 -0
  106. package/dist/__tests__/scriptable-pack-public-surface.test-d.d.ts.map +1 -0
  107. package/dist/__tests__/static-rig.integration.test.d.ts +2 -0
  108. package/dist/__tests__/static-rig.integration.test.d.ts.map +1 -0
  109. package/dist/__tests__/validate-material.unit.test.d.ts +2 -0
  110. package/dist/__tests__/validate-material.unit.test.d.ts.map +1 -0
  111. package/dist/__tests__/video-pack-loader.integration.test.d.ts +2 -0
  112. package/dist/__tests__/video-pack-loader.integration.test.d.ts.map +1 -0
  113. package/dist/aabb.d.ts +3 -0
  114. package/dist/aabb.d.ts.map +1 -0
  115. package/dist/asset-registry.d.ts +552 -0
  116. package/dist/asset-registry.d.ts.map +1 -0
  117. package/dist/builtin-asset-registry.d.ts +22 -0
  118. package/dist/builtin-asset-registry.d.ts.map +1 -0
  119. package/dist/catalog-source.d.ts +2 -1
  120. package/dist/catalog-source.d.ts.map +1 -1
  121. package/dist/decode-image-bytes.d.ts +57 -0
  122. package/dist/decode-image-bytes.d.ts.map +1 -0
  123. package/dist/dynamic-texture-store.d.ts +89 -0
  124. package/dist/dynamic-texture-store.d.ts.map +1 -0
  125. package/dist/errors/asset.d.ts +201 -0
  126. package/dist/errors/asset.d.ts.map +1 -0
  127. package/dist/handles.d.ts +141 -0
  128. package/dist/handles.d.ts.map +1 -0
  129. package/dist/image-error.d.ts +6 -0
  130. package/dist/image-error.d.ts.map +1 -0
  131. package/dist/index.d.ts +32 -3
  132. package/dist/index.d.ts.map +1 -1
  133. package/dist/index.mjs +7218 -114
  134. package/dist/index.mjs.map +1 -1
  135. package/dist/internal.d.ts +2 -1
  136. package/dist/internal.d.ts.map +1 -1
  137. package/dist/internal.mjs +317 -3
  138. package/dist/internal.mjs.map +1 -1
  139. package/dist/loader-registry.d.ts +63 -0
  140. package/dist/loader-registry.d.ts.map +1 -0
  141. package/dist/loaders/inline-pack.d.ts +72 -0
  142. package/dist/loaders/inline-pack.d.ts.map +1 -0
  143. package/dist/loaders/mesh-bin.d.ts +21 -0
  144. package/dist/loaders/mesh-bin.d.ts.map +1 -0
  145. package/dist/loaders/pack-artifact.d.ts +20 -0
  146. package/dist/loaders/pack-artifact.d.ts.map +1 -0
  147. package/dist/material/dependency-graph.d.ts +9 -0
  148. package/dist/material/dependency-graph.d.ts.map +1 -0
  149. package/dist/material/generation-cache.d.ts +24 -0
  150. package/dist/material/generation-cache.d.ts.map +1 -0
  151. package/dist/material/inspection.d.ts +24 -0
  152. package/dist/material/inspection.d.ts.map +1 -0
  153. package/dist/material/loader.d.ts +59 -0
  154. package/dist/material/loader.d.ts.map +1 -0
  155. package/dist/material/runtime-shader.d.ts +14 -0
  156. package/dist/material/runtime-shader.d.ts.map +1 -0
  157. package/dist/mesh-bin.d.ts +3 -0
  158. package/dist/mesh-bin.d.ts.map +1 -0
  159. package/dist/mipmap-generator.d.ts +132 -0
  160. package/dist/mipmap-generator.d.ts.map +1 -0
  161. package/dist/payload-validate.d.ts +60 -0
  162. package/dist/payload-validate.d.ts.map +1 -0
  163. package/dist/plugin.d.ts +16 -0
  164. package/dist/plugin.d.ts.map +1 -0
  165. package/dist/registry/artifact-io.d.ts +16 -0
  166. package/dist/registry/artifact-io.d.ts.map +1 -0
  167. package/dist/registry/asset-evidence.d.ts +13 -0
  168. package/dist/registry/asset-evidence.d.ts.map +1 -0
  169. package/dist/registry/catalog-state.d.ts +47 -0
  170. package/dist/registry/catalog-state.d.ts.map +1 -0
  171. package/dist/registry/catalog.d.ts +48 -0
  172. package/dist/registry/catalog.d.ts.map +1 -0
  173. package/dist/registry/instantiate.d.ts +153 -0
  174. package/dist/registry/instantiate.d.ts.map +1 -0
  175. package/dist/registry/load-by-guid.d.ts +247 -0
  176. package/dist/registry/load-by-guid.d.ts.map +1 -0
  177. package/dist/registry/load-state.d.ts +26 -0
  178. package/dist/registry/load-state.d.ts.map +1 -0
  179. package/dist/registry/runtime-projection.d.ts +16 -0
  180. package/dist/registry/runtime-projection.d.ts.map +1 -0
  181. package/dist/registry/scene-publication-fence.d.ts +38 -0
  182. package/dist/registry/scene-publication-fence.d.ts.map +1 -0
  183. package/dist/registry/validate-material.d.ts +77 -0
  184. package/dist/registry/validate-material.d.ts.map +1 -0
  185. package/dist/resolve-asset-handle.d.ts +43 -0
  186. package/dist/resolve-asset-handle.d.ts.map +1 -0
  187. package/dist/resolve-tileset-runtime.d.ts +23 -0
  188. package/dist/resolve-tileset-runtime.d.ts.map +1 -0
  189. package/dist/scene-handle-fields.d.ts +88 -0
  190. package/dist/scene-handle-fields.d.ts.map +1 -0
  191. package/dist/scene-payload.d.ts +15 -0
  192. package/dist/scene-payload.d.ts.map +1 -0
  193. package/dist/wire-default-loaders.d.ts +29 -0
  194. package/dist/wire-default-loaders.d.ts.map +1 -0
  195. package/package.json +22 -9
  196. package/src/__tests__/aabb.unit.test.ts +97 -0
  197. package/src/__tests__/artifact-integrity.unit.test.ts +99 -0
  198. package/src/__tests__/artifact-io.unit.test.ts +127 -0
  199. package/src/__tests__/asset-evidence-sdk.integration.test.ts +32 -0
  200. package/src/__tests__/asset-evidence.unit.test.ts +32 -0
  201. package/src/__tests__/{asset-kind.test.ts → asset-kind.unit.test.ts} +1 -1
  202. package/src/__tests__/asset-registry-catalog-reconcile.integration.test.ts +74 -0
  203. package/src/__tests__/asset-registry-catalog-reconcile.unit.test.ts +89 -0
  204. package/src/__tests__/asset-registry-catalog.unit.test.ts +170 -0
  205. package/src/__tests__/asset-registry.pack-cache.test.ts +96 -0
  206. package/src/__tests__/asset-registry.unit.test.ts +511 -0
  207. package/src/__tests__/asset-runtime-error-code-owner.test-d.ts +63 -0
  208. package/src/__tests__/catalog-replica.unit.test.ts +196 -0
  209. package/src/__tests__/catalog-source-v2.unit.test.ts +158 -0
  210. package/src/__tests__/catalog-source.unit.test.ts +126 -0
  211. package/src/__tests__/catalog-subscription-order.unit.test.ts +65 -0
  212. package/src/__tests__/catalog-subscription.unit.test.ts +28 -0
  213. package/src/__tests__/decode-image-bytes-pass-through.test.ts +34 -0
  214. package/src/__tests__/decode-image-bytes.browser.test.ts +102 -0
  215. package/src/__tests__/decode-image-bytes.test-d.ts +108 -0
  216. package/src/__tests__/decode-image-bytes.test.ts +90 -0
  217. package/src/__tests__/decode-image-mime-owner.test.ts +2 -5
  218. package/src/__tests__/dynamic-texture-store.unit.test.ts +115 -0
  219. package/src/__tests__/errors-asset.unit.test.ts +92 -0
  220. package/src/__tests__/inline-pack-loaders.unit.test.ts +548 -0
  221. package/src/__tests__/instantiate-context.unit.test.ts +65 -0
  222. package/src/__tests__/instantiate-publication-fence.unit.test.ts +158 -0
  223. package/src/__tests__/instantiate.unit.test.ts +684 -0
  224. package/src/__tests__/loader-input-contract.unit.test.ts +89 -0
  225. package/src/__tests__/loader-registry.unit.test.ts +101 -0
  226. package/src/__tests__/material-dependency-invalidation.unit.test.ts +14 -0
  227. package/src/__tests__/material-generation-cache.unit.test.ts +46 -0
  228. package/src/__tests__/material-load-consumer.test-d.ts +42 -0
  229. package/src/__tests__/material-ready.integration.test.ts +492 -0
  230. package/src/__tests__/material-stale-generation.unit.test.ts +152 -0
  231. package/src/__tests__/mesh-bin-morph-v3.test.ts +22 -0
  232. package/src/__tests__/mesh-bin.unit.test.ts +152 -0
  233. package/src/__tests__/mipmap-generator.unit.test.ts +202 -0
  234. package/src/__tests__/pack-artifact-transcode-model-owner.test.ts +32 -0
  235. package/src/__tests__/pack-basis-load.integration.test.ts +168 -0
  236. package/src/__tests__/payload-validate.unit.test.ts +285 -0
  237. package/src/__tests__/plugin.test.ts +55 -0
  238. package/src/__tests__/registry-concurrency.bench.test.ts +40 -0
  239. package/src/__tests__/registry-failure-retry.integration.test.ts +69 -0
  240. package/src/__tests__/registry-load-graph.integration.test.ts +246 -0
  241. package/src/__tests__/registry-load-state.unit.test.ts +35 -0
  242. package/src/__tests__/registry-package-cache.unit.test.ts +53 -0
  243. package/src/__tests__/registry-public-ready.unit.test.ts +38 -0
  244. package/src/__tests__/resolve-asset-handle.unit.test.ts +238 -0
  245. package/src/__tests__/scene-handle-fields.unit.test.ts +129 -0
  246. package/src/__tests__/scene-payload.unit.test.ts +151 -0
  247. package/src/__tests__/scene-publication-fence.test.ts +129 -0
  248. package/src/__tests__/scriptable-pack-public-surface.test-d.ts +16 -0
  249. package/src/__tests__/static-rig.integration.test.ts +8 -0
  250. package/src/__tests__/validate-material.unit.test.ts +359 -0
  251. package/src/__tests__/video-pack-loader.integration.test.ts +83 -0
  252. package/src/aabb.ts +107 -0
  253. package/src/asset-registry.ts +2040 -0
  254. package/src/builtin-asset-registry.ts +164 -0
  255. package/src/catalog-source.ts +14 -70
  256. package/src/decode-image-bytes.ts +126 -0
  257. package/src/dynamic-texture-store.ts +234 -0
  258. package/src/errors/asset.ts +347 -0
  259. package/src/handles.ts +180 -0
  260. package/src/image-error.ts +45 -0
  261. package/src/index.ts +177 -19
  262. package/src/internal.ts +2 -0
  263. package/src/loader-registry.ts +157 -0
  264. package/src/loaders/inline-pack.ts +837 -0
  265. package/src/loaders/mesh-bin.ts +304 -0
  266. package/src/loaders/pack-artifact.ts +665 -0
  267. package/src/material/dependency-graph.ts +46 -0
  268. package/src/material/generation-cache.ts +177 -0
  269. package/src/material/inspection.ts +46 -0
  270. package/src/material/loader.ts +326 -0
  271. package/src/material/runtime-shader.ts +133 -0
  272. package/src/mesh-bin.ts +5 -0
  273. package/src/mipmap-generator.ts +450 -0
  274. package/src/payload-validate.ts +573 -0
  275. package/src/plugin.ts +48 -0
  276. package/src/registry/artifact-io.ts +259 -0
  277. package/src/registry/asset-evidence.ts +51 -0
  278. package/src/registry/catalog-state.ts +409 -0
  279. package/src/registry/catalog.ts +369 -0
  280. package/src/registry/instantiate.ts +1056 -0
  281. package/src/registry/load-by-guid.ts +1657 -0
  282. package/src/registry/load-state.ts +115 -0
  283. package/src/registry/runtime-projection.ts +63 -0
  284. package/src/registry/scene-publication-fence.ts +256 -0
  285. package/src/registry/validate-material.ts +386 -0
  286. package/src/resolve-asset-handle.ts +147 -0
  287. package/src/resolve-tileset-runtime.ts +72 -0
  288. package/src/scene-handle-fields.ts +221 -0
  289. package/src/scene-payload.ts +207 -0
  290. package/src/wire-default-loaders.ts +79 -0
  291. package/dist/__tests__/asset-graph-red.integration.test.d.ts +0 -2
  292. package/dist/__tests__/asset-graph-red.integration.test.d.ts.map +0 -1
  293. package/dist/__tests__/asset-kind.test.d.ts +0 -2
  294. package/dist/__tests__/asset-kind.test.d.ts.map +0 -1
  295. package/dist/__tests__/asset-registry-core.integration.test.d.ts +0 -2
  296. package/dist/__tests__/asset-registry-core.integration.test.d.ts.map +0 -1
  297. package/dist/__tests__/asset-registry-public-api.test-d.d.ts +0 -2
  298. package/dist/__tests__/asset-registry-public-api.test-d.d.ts.map +0 -1
  299. package/dist/__tests__/asset-runtime-core-lifecycle.integration.test.d.ts +0 -2
  300. package/dist/__tests__/asset-runtime-core-lifecycle.integration.test.d.ts.map +0 -1
  301. package/dist/__tests__/asset-runtime-snapshot.unit.test.d.ts +0 -2
  302. package/dist/__tests__/asset-runtime-snapshot.unit.test.d.ts.map +0 -1
  303. package/dist/__tests__/catalog-session-red.unit.test.d.ts +0 -2
  304. package/dist/__tests__/catalog-session-red.unit.test.d.ts.map +0 -1
  305. package/dist/__tests__/registry-lifecycle-red.integration.test.d.ts +0 -2
  306. package/dist/__tests__/registry-lifecycle-red.integration.test.d.ts.map +0 -1
  307. package/src/__tests__/asset-graph-red.integration.test.ts +0 -113
  308. package/src/__tests__/asset-registry-core.integration.test.ts +0 -161
  309. package/src/__tests__/asset-registry-public-api.test-d.ts +0 -31
  310. package/src/__tests__/asset-runtime-core-lifecycle.integration.test.ts +0 -79
  311. package/src/__tests__/asset-runtime-snapshot.unit.test.ts +0 -23
  312. package/src/__tests__/catalog-session-red.unit.test.ts +0 -276
  313. package/src/__tests__/registry-lifecycle-red.integration.test.ts +0 -80
@@ -0,0 +1,23 @@
1
+ import type { World } from '@forgeax/engine-ecs';
2
+ import type { Asset, Handle, Result, TextureAsset } from '@forgeax/engine-types';
3
+ export type TilesetRuntimeErrorCode = 'tileset-atlas-not-found' | 'tileset-atlas-stale' | 'tileset-atlas-kind-mismatch';
4
+ export interface TilesetRuntimeError {
5
+ readonly code: TilesetRuntimeErrorCode;
6
+ readonly expected: string;
7
+ readonly hint: string;
8
+ readonly detail: {
9
+ readonly guid: string;
10
+ readonly actualKind?: string;
11
+ };
12
+ }
13
+ export interface ResolvedTilesetRuntime {
14
+ readonly guid: string;
15
+ readonly payload: TextureAsset;
16
+ readonly handle: Handle<'TextureAsset', 'shared'>;
17
+ }
18
+ export type TilesetAtlasLookup = Asset | {
19
+ readonly code: 'stale';
20
+ } | undefined;
21
+ /** Project one durable atlas GUID into the current World at the tilemap owner. */
22
+ export declare function resolveTilesetRuntime(world: World, guid: string, lookup: (guid: string) => TilesetAtlasLookup): Result<ResolvedTilesetRuntime, TilesetRuntimeError>;
23
+ //# sourceMappingURL=resolve-tileset-runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve-tileset-runtime.d.ts","sourceRoot":"","sources":["../src/resolve-tileset-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAGjF,MAAM,MAAM,uBAAuB,GAC/B,yBAAyB,GACzB,qBAAqB,GACrB,6BAA6B,CAAC;AAElC,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,uBAAuB,CAAC;IACvC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE;QACf,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;KAC9B,CAAC;CACH;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,cAAc,EAAE,QAAQ,CAAC,CAAC;CACnD;AAED,MAAM,MAAM,kBAAkB,GAAG,KAAK,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;CAAE,GAAG,SAAS,CAAC;AAEhF,kFAAkF;AAClF,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,kBAAkB,GAC3C,MAAM,CAAC,sBAAsB,EAAE,mBAAmB,CAAC,CAuCrD"}
@@ -0,0 +1,88 @@
1
+ import type { Component } from '@forgeax/engine-ecs';
2
+ import type { MountOverride } from '@forgeax/engine-types';
3
+ /**
4
+ * A single handle-field reference extracted from a SceneAsset entity.
5
+ *
6
+ * `entityLocalId` is the `node.localId`; `componentName` and `fieldName`
7
+ * identify the schema field whose `fieldType` starts with `shared\<` or
8
+ * `array\<shared\<`. `guidString` is the raw GUID string value from the
9
+ * entity's component data (NOT a parsed `AssetGuid` — callers parse or
10
+ * resolve as needed).
11
+ *
12
+ * `arrayIndex` is `undefined` for plain `handle<T>` fields; for
13
+ * `array<handle<T>>` fields it is the 0-based index into the array.
14
+ */
15
+ export interface SceneHandleFieldEntry {
16
+ readonly entityLocalId: number;
17
+ readonly componentName: string;
18
+ readonly fieldName: string;
19
+ readonly guidString: string;
20
+ /** 0-based index for `array<handle<T>>` elements; `undefined` for plain `handle<T>` fields. */
21
+ readonly arrayIndex?: number;
22
+ }
23
+ /**
24
+ * Shape of a single entity passed to {@link extractSceneEntityHandleGuids}.
25
+ *
26
+ * Compatible with both `SceneEntity` (from `@forgeax/engine-types`, where
27
+ * `components` is `Partial<ComponentValuesMap>`) and test-side plain objects.
28
+ */
29
+ interface SceneEntityLike {
30
+ readonly localId: number;
31
+ readonly components: Record<string, Record<string, unknown>>;
32
+ }
33
+ /**
34
+ * Walk every `SceneEntityLike` in `entities` and extract all GUID strings
35
+ * bound to schema fields with `handle<...>` or `array<handle<...>>` fieldType.
36
+ *
37
+ * Unknown component names (absent from the supplied World-local catalog) are
38
+ * silently skipped — the ecs layer's `additionalProperties` check will catch
39
+ * unknowns at spawn time if appropriate.
40
+ *
41
+ * Values that are already numbers (resolved Handles) or non-strings are
42
+ * skipped (they are not GUID refs).
43
+ *
44
+ * @internal Shared by {@link AssetRegistry._resolveSceneGuids} and
45
+ * `buildSceneChildContext` as the entity-walk fallback used when the structured
46
+ * `envelope.refs` edges are unavailable or carry no per-entity detail.
47
+ */
48
+ export declare function extractSceneEntityHandleGuids(components: ReadonlyMap<string, Component>, entities: ReadonlyArray<SceneEntityLike>): SceneHandleFieldEntry[];
49
+ /**
50
+ * One handle-field GUID reference extracted from a {@link MountOverride}'s value
51
+ * (feat-20260713 M3 / w12). Mirrors {@link SceneHandleFieldEntry} but keys on the
52
+ * override's array index (there is no entity `localId` — an override targets a
53
+ * mount member by its own `localId`, resolved by the ecs apply loop, not here).
54
+ *
55
+ * `fieldName` is the schema field the GUID binds to: the override's own `field`
56
+ * for the patch form, or a key of the component-add value map for the add form.
57
+ */
58
+ export interface MountOverrideHandleFieldEntry {
59
+ /** 0-based index into the `overrides[]` array passed to the extractor. */
60
+ readonly overrideIndex: number;
61
+ readonly componentName: string;
62
+ readonly fieldName: string;
63
+ readonly guidString: string;
64
+ /** 0-based index for `array<shared<T>>` elements; `undefined` for scalar `shared<T>`. */
65
+ readonly arrayIndex?: number;
66
+ }
67
+ /**
68
+ * Walk `overrides` and extract every GUID string bound to a `shared<...>` /
69
+ * `array<shared<...>>` schema field inside each override's value (feat-20260713
70
+ * M3 / w12, plan-strategy D-2). This is the apply-side counterpart to
71
+ * {@link extractSceneEntityHandleGuids}: it feeds `resolveMountsRec`'s
72
+ * GUID→handle down-drill so a `mounts[].overrides[].value` carrying a raw GUID
73
+ * (e.g. an `AnimationPlayer.clips` clip GUID) resolves to a live handle before
74
+ * the ecs apply loop, which only ever sees numeric handles (D-2: the GUID domain
75
+ * stays sealed in assets-runtime).
76
+ *
77
+ * The `{comp, field?, value}` discriminant is normalized to `(fieldName, value)`
78
+ * pairs: the patch form (`field` present) yields one pair; the component-add form
79
+ * (`field` absent, `value` is a per-field map) yields one pair per value key.
80
+ * Field type is judged from the supplied catalog token schema, the same
81
+ * schema SSOT the entity walk uses. Unknown components / non-shared fields /
82
+ * non-string (already-resolved number) values are skipped (D-8 number pass-through).
83
+ *
84
+ * @internal Shared identification core; resolution lives in `resolveMountsRec`.
85
+ */
86
+ export declare function extractMountOverrideHandleGuids(components: ReadonlyMap<string, Component>, overrides: ReadonlyArray<MountOverride>): MountOverrideHandleFieldEntry[];
87
+ export {};
88
+ //# sourceMappingURL=scene-handle-fields.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scene-handle-fields.d.ts","sourceRoot":"","sources":["../src/scene-handle-fields.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAErD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE3D;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,+FAA+F;IAC/F,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED;;;;;GAKG;AACH,UAAU,eAAe;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAC9D;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,6BAA6B,CAC3C,UAAU,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,CAAC,EAC1C,QAAQ,EAAE,aAAa,CAAC,eAAe,CAAC,GACvC,qBAAqB,EAAE,CAmCzB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,6BAA6B;IAC5C,0EAA0E;IAC1E,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,yFAAyF;IACzF,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,+BAA+B,CAC7C,UAAU,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,CAAC,EAC1C,SAAS,EAAE,aAAa,CAAC,aAAa,CAAC,GACtC,6BAA6B,EAAE,CAwBjC"}
@@ -0,0 +1,15 @@
1
+ import type { SceneAsset } from '@forgeax/engine-types';
2
+ /**
3
+ * Structured error returned by parseScenePayload when a refs index is
4
+ * out of bounds (F-2 / AC-02).
5
+ */
6
+ interface ParseSceneError {
7
+ readonly localId: number;
8
+ readonly component: string;
9
+ readonly field: string;
10
+ readonly index: number;
11
+ readonly refsLength: number;
12
+ }
13
+ export declare function parseScenePayload(payload: Record<string, unknown>, refs?: string[]): SceneAsset | ParseSceneError | undefined;
14
+ export {};
15
+ //# sourceMappingURL=scene-payload.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scene-payload.d.ts","sourceRoot":"","sources":["../src/scene-payload.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAEV,UAAU,EAGX,MAAM,uBAAuB,CAAC;AAG/B;;;GAGG;AACH,UAAU,eAAe;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAsBD,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,IAAI,CAAC,EAAE,MAAM,EAAE,GACd,UAAU,GAAG,eAAe,GAAG,SAAS,CAoG1C"}
@@ -0,0 +1,29 @@
1
+ import type { Loader } from '@forgeax/engine-types';
2
+ import { LoaderRegistry } from './loader-registry';
3
+ /**
4
+ * Wire the engine's default loader set (16 ordinary kinds plus UI) plus any
5
+ * `extraLoaders` onto `registry` in
6
+ * one call. Returns the same `registry` for chaining (so `wireDefaultLoaders(new
7
+ * LoaderRegistry())` is a one-expression wired registry). The `extraLoaders` are
8
+ * appended after the defaults and must use kinds outside the ordinary set.
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * import { LoaderRegistry, wireDefaultLoaders } from '@forgeax/engine-assets-runtime';
13
+ * const loaders = wireDefaultLoaders(new LoaderRegistry());
14
+ * // loaders.get('mesh') / .get('texture') / .get('font') / .get('video') are
15
+ * // non-undefined; all ordinary Asset kinds share this same owner table.
16
+ * ```
17
+ */
18
+ export declare function wireDefaultLoaders(registry: LoaderRegistry, extraLoaders?: readonly Loader[]): LoaderRegistry;
19
+ /**
20
+ * Convenience factory: a fresh `LoaderRegistry` pre-wired with the default
21
+ * loader set (plus any `extraLoaders`). The production assembly point
22
+ * (`createRenderer`) and tests pass the result into `new LoaderRegistry()` (D-7
23
+ * constructor-injection; loaders always wired at construction -- used by
24
+ * `AssetRegistry` internally via `createDefaultLoaderRegistry(extraLoaders)` and
25
+ * by host code / tests independently) -- no setter / no illegal intermediate
26
+ * state).
27
+ */
28
+ export declare function createDefaultLoaderRegistry(extraLoaders?: readonly Loader[]): LoaderRegistry;
29
+ //# sourceMappingURL=wire-default-loaders.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wire-default-loaders.d.ts","sourceRoot":"","sources":["../src/wire-default-loaders.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAEpD,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAanD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,cAAc,EACxB,YAAY,GAAE,SAAS,MAAM,EAAO,GACnC,cAAc,CAahB;AAED;;;;;;;;GAQG;AACH,wBAAgB,2BAA2B,CAAC,YAAY,GAAE,SAAS,MAAM,EAAO,GAAG,cAAc,CAEhG"}
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@forgeax/engine-assets-runtime",
3
- "version": "0.1.3",
3
+ "version": "0.1.6",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
7
7
  "sideEffects": false,
8
- "description": "Single-scope Catalog, Pack, typed decoder, dependency graph, and terminal lifecycle for forgeax-engine.",
8
+ "description": "Asset registry, loader registry, GUID resolution, and default loader wiring for forgeax-engine (Tier 2.1 -- extracted from @forgeax/engine-runtime).",
9
9
  "exports": {
10
10
  ".": {
11
11
  "types": "./dist/index.d.ts",
@@ -26,7 +26,23 @@
26
26
  "LICENSE"
27
27
  ],
28
28
  "dependencies": {
29
- "@forgeax/engine-types": "0.1.3"
29
+ "@forgeax/engine-codec": "0.1.6",
30
+ "@forgeax/engine-ecs": "0.1.6",
31
+ "@forgeax/engine-geometry": "0.1.6",
32
+ "@forgeax/engine-graphics-extras": "0.1.6",
33
+ "@forgeax/engine-image": "0.1.6",
34
+ "@forgeax/engine-pack": "0.1.6",
35
+ "@forgeax/engine-plugin": "0.1.6",
36
+ "@forgeax/engine-rhi": "0.1.6",
37
+ "@forgeax/engine-scene": "0.1.6",
38
+ "@forgeax/engine-shader": "0.1.6",
39
+ "@forgeax/engine-types": "0.1.6",
40
+ "@forgeax/engine-ui": "0.1.6",
41
+ "@webgpu/types": "^0.1.71"
42
+ },
43
+ "devDependencies": {
44
+ "@forgeax/engine-skinning": "0.1.6",
45
+ "@webgpu/types": "^0.1.71"
30
46
  },
31
47
  "forgeax": {
32
48
  "metrics": {
@@ -40,9 +56,8 @@
40
56
  "reason": "asset registry / loader library, no runtime canvas; fps reported by hello-* apps that consume it"
41
57
  },
42
58
  "bench": {
43
- "enabled": true,
44
- "reportSchema": "asset-runtime-core",
45
- "reportPath": "report/assets-runtime-core.json"
59
+ "enabled": false,
60
+ "reason": "asset catalogue + load pipeline run at asset-load time, not per-frame; no CI micro-benchmark warranted"
46
61
  },
47
62
  "gate": {
48
63
  "enabled": false,
@@ -56,8 +71,6 @@
56
71
  },
57
72
  "scripts": {
58
73
  "build": "tsup",
59
- "test": "vitest run",
60
- "bench:asset-runtime-baseline": "node ../../scripts/metrics/asset-runtime-baseline.mjs",
61
- "bench:asset-runtime-core": "node ../../scripts/metrics/asset-runtime-bench.mjs"
74
+ "test": "vitest run"
62
75
  }
63
76
  }
@@ -0,0 +1,97 @@
1
+ // @forgeax/engine-assets-runtime -- withMeshAabb / computeAABB coverage
2
+ // (fix issue #709: assets-runtime src entered the coverage pool via the
3
+ // package's own tests importing `../` relative paths -> src; before this the
4
+ // module was only exercised through the compiled dist by runtime-project
5
+ // tests, which are excluded from the coverage denominator).
6
+
7
+ import type { MeshAsset } from '@forgeax/engine-types';
8
+ import { describe, expect, it } from 'vitest';
9
+ import { withMeshAabb } from '../aabb';
10
+
11
+ const EMPTY_BOX = [Infinity, Infinity, Infinity, -Infinity, -Infinity, -Infinity];
12
+
13
+ function meshWith(position: Float32Array | ArrayBuffer | undefined): MeshAsset {
14
+ return {
15
+ kind: 'mesh',
16
+ vertices: new Float32Array(0),
17
+ attributes: position === undefined ? {} : { position },
18
+ submeshes: [
19
+ { indexOffset: 0, indexCount: 0, vertexCount: 0, topology: 'triangle-list', materialSlot: 0 },
20
+ ],
21
+ materialSlots: [{ slotName: 'Default' }],
22
+ } as MeshAsset;
23
+ }
24
+
25
+ describe('withMeshAabb', () => {
26
+ it('computes [min, max] over every (x, y, z) triple of the position attribute', () => {
27
+ const position = Float32Array.of(
28
+ -1,
29
+ -2,
30
+ -3, //
31
+ 4,
32
+ 5,
33
+ 6, //
34
+ 0,
35
+ 0,
36
+ 0,
37
+ );
38
+ const out = withMeshAabb(meshWith(position));
39
+ expect(Array.from(out.aabb as Float32Array)).toEqual([-1, -2, -3, 4, 5, 6]);
40
+ });
41
+
42
+ it('handles a single-vertex mesh (min === max === that vertex)', () => {
43
+ const out = withMeshAabb(meshWith(Float32Array.of(7, 8, 9)));
44
+ expect(Array.from(out.aabb as Float32Array)).toEqual([7, 8, 9, 7, 8, 9]);
45
+ });
46
+
47
+ it('re-wraps an ArrayBuffer position buffer as Float32Array', () => {
48
+ const buf = Float32Array.of(1, 1, 1, 2, 3, 4).buffer;
49
+ const out = withMeshAabb(meshWith(buf));
50
+ expect(Array.from(out.aabb as Float32Array)).toEqual([1, 1, 1, 2, 3, 4]);
51
+ });
52
+
53
+ it('returns the inverted-infinity empty box when position is absent', () => {
54
+ const out = withMeshAabb(meshWith(undefined));
55
+ expect(Array.from(out.aabb as Float32Array)).toEqual(EMPTY_BOX);
56
+ });
57
+
58
+ it('returns the empty box when position has fewer than 3 floats', () => {
59
+ const out = withMeshAabb(meshWith(Float32Array.of(1, 2)));
60
+ expect(Array.from(out.aabb as Float32Array)).toEqual(EMPTY_BOX);
61
+ });
62
+
63
+ it('returns the empty box for a Uint16Array position (treated as absent)', () => {
64
+ const mesh = {
65
+ kind: 'mesh',
66
+ vertices: new Float32Array(0),
67
+ attributes: { position: Uint16Array.of(1, 2, 3) },
68
+ submeshes: [{ indexOffset: 0, indexCount: 0, vertexCount: 0, topology: 'triangle-list' }],
69
+ } as unknown as MeshAsset;
70
+ const out = withMeshAabb(mesh);
71
+ expect(Array.from(out.aabb as Float32Array)).toEqual(EMPTY_BOX);
72
+ });
73
+
74
+ it('preserves a packed AABB when the binary path omits position attributes', () => {
75
+ const mesh = {
76
+ ...meshWith(undefined),
77
+ aabb: Float32Array.of(-2, 0, -1, 3, 4, 5),
78
+ };
79
+ const out = withMeshAabb(mesh);
80
+ expect(Array.from(out.aabb as Float32Array)).toEqual([-2, 0, -1, 3, 4, 5]);
81
+ });
82
+
83
+ it('mutates the mesh in place when it is extensible (returns same reference)', () => {
84
+ const mesh = meshWith(Float32Array.of(0, 0, 0, 1, 1, 1));
85
+ const out = withMeshAabb(mesh);
86
+ expect(out).toBe(mesh);
87
+ expect(mesh.aabb).toBeInstanceOf(Float32Array);
88
+ });
89
+
90
+ it('returns a shallow copy carrying the aabb when the mesh is frozen', () => {
91
+ const mesh = Object.freeze(meshWith(Float32Array.of(0, 0, 0, 2, 2, 2)));
92
+ const out = withMeshAabb(mesh);
93
+ expect(out).not.toBe(mesh);
94
+ expect(Array.from(out.aabb as Float32Array)).toEqual([0, 0, 0, 2, 2, 2]);
95
+ expect(mesh.aabb).toBeUndefined();
96
+ });
97
+ });
@@ -0,0 +1,99 @@
1
+ import type { ArtifactDescriptor } from '@forgeax/engine-types';
2
+ import { describe, expect, it, vi } from 'vitest';
3
+ import { readArtifact } from '../registry/artifact-io';
4
+
5
+ const GUID = '22222222-2222-4222-8222-222222222222';
6
+
7
+ describe('artifact integrity and outer encoding', () => {
8
+ it('rejects an artifact without a durable media type', async () => {
9
+ const fetcher = vi.fn().mockResolvedValue(new Response(Uint8Array.of(1)));
10
+ const result = await readArtifact(
11
+ {
12
+ packageUrl: 'https://example.test/pkg.pack.json',
13
+ guid: GUID,
14
+ artifactKey: 'payload',
15
+ descriptor: {
16
+ path: 'payload.bin',
17
+ mediaType: '',
18
+ },
19
+ },
20
+ fetcher,
21
+ );
22
+
23
+ expect(result.ok).toBe(false);
24
+ expect(fetcher).not.toHaveBeenCalled();
25
+ if (!result.ok) expect(result.error.code).toBe('asset-artifact-media-unsupported');
26
+ });
27
+
28
+ it('checks byte length and integrity after outer decoding', async () => {
29
+ const descriptor: ArtifactDescriptor = {
30
+ path: 'payload.bin',
31
+ mediaType: 'application/octet-stream',
32
+ contentEncoding: 'identity',
33
+ byteLength: 3,
34
+ integrity: {
35
+ algorithm: 'sha256',
36
+ digest: 'sha256-of-decoded-bytes',
37
+ },
38
+ };
39
+ const result = await readArtifact(
40
+ {
41
+ packageUrl: 'https://example.test/pkg.pack.json',
42
+ guid: GUID,
43
+ artifactKey: 'payload',
44
+ descriptor,
45
+ },
46
+ vi.fn().mockResolvedValue(new Response(Uint8Array.of(1, 2, 3))),
47
+ );
48
+
49
+ expect(result.ok).toBe(false);
50
+ if (!result.ok) {
51
+ expect(result.error.code).toBe('asset-artifact-integrity-mismatch');
52
+ expect(result.error.expected).toContain('sha256');
53
+ expect(result.error.detail.observed).toBeTruthy();
54
+ }
55
+ });
56
+
57
+ it('reports a same-sized published artifact with the wrong digest as an integrity mismatch', async () => {
58
+ const result = await readArtifact(
59
+ {
60
+ packageUrl: 'https://example.test/pkg.pack.json',
61
+ guid: GUID,
62
+ artifactKey: 'shader',
63
+ descriptor: {
64
+ path: 'shader.wgsl',
65
+ mediaType: 'text/wgsl',
66
+ byteLength: 4,
67
+ integrity: { algorithm: 'sha256', digest: 'sha256:published-digest' },
68
+ },
69
+ },
70
+ vi.fn().mockResolvedValue(new Response(Uint8Array.of(1, 2, 3, 4))),
71
+ );
72
+
73
+ expect(result).toMatchObject({
74
+ ok: false,
75
+ error: { code: 'asset-artifact-integrity-mismatch' },
76
+ });
77
+ });
78
+
79
+ it('does not pass asset codec names to the outer decoder', async () => {
80
+ const fetcher = vi.fn().mockResolvedValue(new Response(Uint8Array.of(7, 8)));
81
+ const result = await readArtifact(
82
+ {
83
+ packageUrl: 'https://example.test/pkg.pack.json',
84
+ guid: GUID,
85
+ artifactKey: 'texture',
86
+ descriptor: {
87
+ path: 'texture.data',
88
+ mediaType: 'image/ktx2',
89
+ assetCodec: { name: 'basis', profile: 'etc1s' },
90
+ contentEncoding: 'identity',
91
+ },
92
+ },
93
+ fetcher,
94
+ );
95
+
96
+ expect(result).toEqual({ ok: true, value: Uint8Array.of(7, 8) });
97
+ expect(fetcher).toHaveBeenCalledTimes(1);
98
+ });
99
+ });
@@ -0,0 +1,127 @@
1
+ import type { ArtifactDescriptor } from '@forgeax/engine-types';
2
+ import { describe, expect, it, vi } from 'vitest';
3
+ import { readArtifact } from '../registry/artifact-io';
4
+
5
+ const GUID = '11111111-1111-4111-8111-111111111111';
6
+
7
+ function descriptor(path: string, changes: Partial<ArtifactDescriptor> = {}): ArtifactDescriptor {
8
+ return { path, mediaType: 'application/octet-stream', ...changes };
9
+ }
10
+
11
+ function response(bytes: Uint8Array, ok = true): Response {
12
+ const body = new ArrayBuffer(bytes.byteLength);
13
+ new Uint8Array(body).set(bytes);
14
+ return new Response(body, { status: ok ? 200 : 404 });
15
+ }
16
+
17
+ describe('artifact I/O', () => {
18
+ it('rejects an empty media type before fetching artifact bytes', async () => {
19
+ const fetcher = vi.fn();
20
+ const result = await readArtifact(
21
+ {
22
+ packageUrl: 'https://example.test/packages/main.pack.json',
23
+ guid: GUID,
24
+ artifactKey: 'source',
25
+ descriptor: descriptor('payload.bin', { mediaType: '' }),
26
+ },
27
+ fetcher,
28
+ );
29
+
30
+ expect(result.ok).toBe(false);
31
+ expect(fetcher).not.toHaveBeenCalled();
32
+ if (!result.ok) expect(result.error.code).toBe('asset-artifact-media-unsupported');
33
+ });
34
+
35
+ it.each([
36
+ '../outside.bin',
37
+ '%2e%2e/outside.bin',
38
+ '%252e%252e/outside.bin',
39
+ '/absolute.bin',
40
+ 'https://evil.example/outside.bin',
41
+ '..\\outside.bin',
42
+ ])('rejects unsafe locator %s before reading', async (path) => {
43
+ const fetcher = vi.fn();
44
+ const result = await readArtifact(
45
+ {
46
+ packageUrl: 'https://example.test/packages/main.pack.json',
47
+ guid: GUID,
48
+ artifactKey: 'source',
49
+ descriptor: descriptor(path),
50
+ },
51
+ fetcher,
52
+ );
53
+
54
+ expect(result.ok).toBe(false);
55
+ expect(fetcher).not.toHaveBeenCalled();
56
+ if (!result.ok) {
57
+ expect(result.error.code).toBe('asset-artifact-path-invalid');
58
+ expect(result.error.detail.guid).toBe(GUID);
59
+ expect(result.error.detail.artifactKey).toBe('source');
60
+ expect(result.error.hint).toContain('package-relative');
61
+ }
62
+ });
63
+
64
+ it('reads a normalized package-relative artifact and preserves asset codec metadata as data', async () => {
65
+ const fetcher = vi.fn().mockResolvedValue(response(Uint8Array.of(1, 2, 3)));
66
+ const result = await readArtifact(
67
+ {
68
+ packageUrl: 'https://example.test/packages/main.pack.json',
69
+ guid: GUID,
70
+ artifactKey: 'source',
71
+ descriptor: descriptor('./payload.bin', {
72
+ mediaType: 'image/ktx2',
73
+ assetCodec: { name: 'basis', profile: 'uastc' },
74
+ contentEncoding: 'identity',
75
+ }),
76
+ },
77
+ fetcher,
78
+ );
79
+
80
+ expect(result).toEqual({ ok: true, value: Uint8Array.of(1, 2, 3) });
81
+ expect(fetcher).toHaveBeenCalledWith('https://example.test/packages/payload.bin');
82
+ });
83
+
84
+ it('returns structured missing, encoding, and integrity failures', async () => {
85
+ const missing = await readArtifact(
86
+ {
87
+ packageUrl: 'https://example.test/main.pack.json',
88
+ guid: GUID,
89
+ artifactKey: 'source',
90
+ descriptor: descriptor('missing.bin'),
91
+ },
92
+ vi.fn().mockResolvedValue(response(new Uint8Array(), false)),
93
+ );
94
+ expect(missing.ok).toBe(false);
95
+ if (!missing.ok) expect(missing.error.code).toBe('asset-artifact-missing');
96
+
97
+ const unsupported = await readArtifact(
98
+ {
99
+ packageUrl: 'https://example.test/main.pack.json',
100
+ guid: GUID,
101
+ artifactKey: 'source',
102
+ descriptor: descriptor('payload.bin', { contentEncoding: 'brotli' as never }),
103
+ },
104
+ vi.fn(),
105
+ );
106
+ expect(unsupported.ok).toBe(false);
107
+ if (!unsupported.ok) expect(unsupported.error.code).toBe('asset-artifact-encoding-unsupported');
108
+
109
+ const integrity = await readArtifact(
110
+ {
111
+ packageUrl: 'https://example.test/main.pack.json',
112
+ guid: GUID,
113
+ artifactKey: 'source',
114
+ descriptor: descriptor('payload.bin', {
115
+ integrity: { algorithm: 'sha256', digest: 'not-the-digest' },
116
+ }),
117
+ },
118
+ vi.fn().mockResolvedValue(response(Uint8Array.of(1, 2, 3))),
119
+ );
120
+ expect(integrity.ok).toBe(false);
121
+ if (!integrity.ok) {
122
+ expect(integrity.error.code).toBe('asset-artifact-integrity-mismatch');
123
+ expect(integrity.error.detail.guid).toBe(GUID);
124
+ expect(integrity.error.detail.artifactKey).toBe('source');
125
+ }
126
+ });
127
+ });
@@ -0,0 +1,32 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { createRuntimeAssetEvidenceAdapter } from '../registry/asset-evidence.js';
3
+
4
+ const guid = '11111111-1111-4111-8111-111111111111';
5
+
6
+ describe('AssetEvidence SDK integration', () => {
7
+ it('uses the same projector shape for inspect and verifyByGuid', async () => {
8
+ const adapter = createRuntimeAssetEvidenceAdapter({
9
+ evidence: async () => ({
10
+ guid,
11
+ source: { origin: 'sourceMeta', inputFingerprint: 'fp-1' },
12
+ locator: { packageUrl: '/assets/config.pack.json' },
13
+ receipt: {
14
+ guid,
15
+ origin: 'sourceMeta',
16
+ status: 'succeeded',
17
+ inputFingerprint: 'fp-1',
18
+ outputDigest: 'digest-1',
19
+ },
20
+ packageVerification: { status: 'passed', digest: 'digest-1' },
21
+ artifacts: {},
22
+ runtime: { status: 'ready' },
23
+ }),
24
+ });
25
+
26
+ const inspected = await adapter.inspect(guid);
27
+ const verified = await adapter.verifyByGuid(guid);
28
+ expect(inspected.ok).toBe(true);
29
+ expect(verified.ok).toBe(true);
30
+ expect(inspected).toEqual(verified);
31
+ });
32
+ });
@@ -0,0 +1,32 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { createRuntimeAssetEvidenceAdapter } from '../registry/asset-evidence.js';
3
+
4
+ const guid = '11111111-1111-4111-8111-111111111111';
5
+
6
+ describe('runtime AssetEvidence adapter', () => {
7
+ it('uses injected runtime state and leaves missing capability explicit', async () => {
8
+ const adapter = createRuntimeAssetEvidenceAdapter({
9
+ evidence: async (requestedGuid) => ({
10
+ guid: requestedGuid,
11
+ source: { origin: 'sourceMeta', inputFingerprint: 'fp-1' },
12
+ locator: { packageUrl: '/assets/data.pack.json' },
13
+ receipt: {
14
+ guid: requestedGuid,
15
+ origin: 'sourceMeta',
16
+ status: 'succeeded',
17
+ inputFingerprint: 'fp-1',
18
+ outputDigest: 'digest-1',
19
+ },
20
+ packageVerification: { status: 'passed', digest: 'digest-1' },
21
+ artifacts: {},
22
+ }),
23
+ });
24
+
25
+ const result = await adapter.verifyByGuid(guid);
26
+ expect(result.ok).toBe(true);
27
+ if (!result.ok) return;
28
+ expect(result.value.guid).toBe(guid);
29
+ expect(result.value.runtime.status).toBe('unknown');
30
+ expect(result.value.cook.freshness).toBe('current');
31
+ });
32
+ });
@@ -1,6 +1,6 @@
1
1
  import type { AssetKindPayload } from '@forgeax/engine-types';
2
2
  import { describe, expect, it } from 'vitest';
3
- import { defineAssetKind } from '../asset-kind.js';
3
+ import { defineAssetKind } from '../index.js';
4
4
 
5
5
  describe('defineAssetKind', () => {
6
6
  it('freezes the runtime kind witness while preserving its payload type', () => {