@auraindustry/aurajs 0.0.6 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (334) hide show
  1. package/README.md +103 -7
  2. package/benchmarks/perf-thresholds.json +54 -0
  3. package/package.json +4 -7
  4. package/src/asset-pack.mjs +5 -1
  5. package/src/authored-project.mjs +1449 -0
  6. package/src/authored-runtime.mjs +2016 -0
  7. package/src/authoring/avatar-animation-graph.mjs +648 -0
  8. package/src/bin-integrity.mjs +272 -0
  9. package/src/build-contract/assets.mjs +130 -0
  10. package/src/build-contract/capabilities.mjs +116 -0
  11. package/src/build-contract/constants.mjs +6 -0
  12. package/src/build-contract/helpers.mjs +44 -0
  13. package/src/build-contract/web-templates.mjs +5993 -0
  14. package/src/build-contract.mjs +27 -2910
  15. package/src/bundler.mjs +188 -55
  16. package/src/cli.mjs +4825 -1512
  17. package/src/commands/project-authoring.mjs +434 -0
  18. package/src/config.mjs +27 -0
  19. package/src/conformance/cases/app-and-ui-runtime-cases.mjs +3309 -0
  20. package/src/conformance/cases/core-runtime-cases.mjs +1431 -0
  21. package/src/conformance/cases/index.mjs +11 -0
  22. package/src/conformance/cases/scene3d-and-media-cases.mjs +2094 -0
  23. package/src/conformance/cases/systems-and-gameplay-cases.mjs +1776 -0
  24. package/src/conformance/shared.mjs +27 -0
  25. package/src/conformance-runner.mjs +25 -13
  26. package/src/conformance.mjs +619 -4020
  27. package/src/cutscene.mjs +362 -5
  28. package/src/dev-cli-action.mjs +249 -0
  29. package/src/dev-cli-inspect.mjs +92 -0
  30. package/src/dev-cli-state.mjs +80 -0
  31. package/src/external-asset-cache.mjs +587 -0
  32. package/src/external-asset-policy.mjs +217 -0
  33. package/src/external-package-surface.mjs +206 -0
  34. package/src/game-action-runtime.mjs +869 -0
  35. package/src/game-state-runtime.mjs +206 -6
  36. package/src/headless-action.mjs +186 -0
  37. package/src/headless-test/runtime-animation.mjs +1173 -0
  38. package/src/headless-test/runtime-coordinator.mjs +1514 -0
  39. package/src/headless-test/runtime-primitives.mjs +320 -0
  40. package/src/headless-test/runtime-world.mjs +2253 -0
  41. package/src/headless-test.mjs +392 -4298
  42. package/src/host-binary.mjs +342 -14
  43. package/src/icon-discovery.mjs +64 -0
  44. package/src/make-catalog.mjs +109 -0
  45. package/src/make.mjs +197 -0
  46. package/src/package-integrity.mjs +586 -0
  47. package/src/perf-benchmark.mjs +353 -0
  48. package/src/postinstall.mjs +5 -5
  49. package/src/prefabs/index.mjs +34 -0
  50. package/src/prefabs/scene-serialization.mjs +184 -0
  51. package/src/project-importer.mjs +620 -0
  52. package/src/project-registry.mjs +24 -0
  53. package/src/publish-command.mjs +195 -0
  54. package/src/publish-env-example.mjs +83 -0
  55. package/src/publish-validation.mjs +708 -0
  56. package/src/retro/assets/compile.mjs +232 -0
  57. package/src/retro/backend-gba/authoring.mjs +1029 -0
  58. package/src/retro/backend-gba/rom.mjs +363 -0
  59. package/src/retro/backend-gbc/rom.mjs +85 -0
  60. package/src/retro/build.mjs +278 -0
  61. package/src/retro/cli/commands.mjs +292 -0
  62. package/src/retro/cli/templates.mjs +84 -0
  63. package/src/retro/diagnostics/catalog.mjs +110 -0
  64. package/src/retro/diagnostics/emit.mjs +72 -0
  65. package/src/retro/emulator/case-overlay.mjs +64 -0
  66. package/src/retro/emulator/discovery.mjs +158 -0
  67. package/src/retro/emulator/macos-case-overlay.swift +220 -0
  68. package/src/retro/emulator/profiles.mjs +146 -0
  69. package/src/retro/emulator/runner.mjs +289 -0
  70. package/src/retro/frontend/load-project.mjs +98 -0
  71. package/src/retro/index.mjs +30 -0
  72. package/src/retro/ir/build-ir.mjs +108 -0
  73. package/src/retro/runtime-gba/contract.mjs +151 -0
  74. package/src/retro/runtime-gbc/contract.mjs +117 -0
  75. package/src/retro/shared/span.mjs +26 -0
  76. package/src/retro/shared/targets.mjs +64 -0
  77. package/src/retro/validator/check-project.mjs +114 -0
  78. package/src/runtime-hotspot-audit.mjs +707 -0
  79. package/src/scaffold/config.mjs +1000 -0
  80. package/src/scaffold/fs.mjs +56 -0
  81. package/src/scaffold/layout.mjs +318 -0
  82. package/src/scaffold/project-docs.mjs +438 -0
  83. package/src/scaffold.mjs +93 -596
  84. package/src/scene-composition/index.mjs +326 -0
  85. package/src/scene-composition/runtime.mjs +751 -0
  86. package/src/self-hosted-assets.mjs +604 -0
  87. package/src/session-client.mjs +750 -0
  88. package/src/session-native-launcher.mjs +74 -0
  89. package/src/session-protocol.mjs +75 -0
  90. package/src/session-runtime.mjs +321 -0
  91. package/src/session-server.mjs +360 -0
  92. package/src/shader-kits/index.mjs +773 -0
  93. package/src/starter-content-registry.mjs +292 -0
  94. package/src/state-artifacts.mjs +662 -24
  95. package/src/state-dev-reload.mjs +99 -2
  96. package/src/terminal-ui.mjs +245 -0
  97. package/src/web-conformance.mjs +219 -0
  98. package/templates/create/2d/config/gameplay/shooter.config.js +26 -0
  99. package/templates/create/2d/content/gameplay/waves.json +26 -0
  100. package/templates/create/2d/content/registries/.gitkeep +1 -0
  101. package/templates/create/2d/docs/design/.gitkeep +1 -0
  102. package/templates/create/2d/docs/design/loop.md +5 -0
  103. package/templates/create/2d/prefabs/enemies.prefab.js +90 -0
  104. package/templates/create/2d/prefabs/enemy-basic.prefab.js +18 -0
  105. package/templates/create/2d/prefabs/player.prefab.js +36 -0
  106. package/templates/create/2d/prefabs/projectiles.prefab.js +35 -0
  107. package/templates/create/2d/scenes/boot.scene.js +12 -0
  108. package/templates/create/2d/scenes/gameplay.scene.js +230 -0
  109. package/templates/create/2d/scenes/menu.scene.js +9 -0
  110. package/templates/create/2d/src/main.js +6 -185
  111. package/templates/create/2d/src/runtime/app.js +49 -0
  112. package/templates/create/2d/src/runtime/capabilities.js +35 -0
  113. package/templates/create/2d/ui/hud.screen.js +40 -0
  114. package/templates/create/2d/ui/pause.screen.js +149 -0
  115. package/templates/create/2d/ui/settings.screen.js +347 -0
  116. package/templates/create/2d/ui/title.screen.js +13 -0
  117. package/templates/create/2d-adventure/aura.config.json +28 -0
  118. package/templates/create/2d-adventure/config/gameplay/adventure.config.js +14 -0
  119. package/templates/create/2d-adventure/content/gameplay/world.js +46 -0
  120. package/templates/create/2d-adventure/content/registries/.gitkeep +1 -0
  121. package/templates/create/2d-adventure/docs/design/loop.md +5 -0
  122. package/templates/create/2d-adventure/prefabs/player.prefab.js +54 -0
  123. package/templates/create/2d-adventure/prefabs/relic.prefab.js +38 -0
  124. package/templates/create/2d-adventure/prefabs/world.prefab.js +125 -0
  125. package/templates/create/2d-adventure/scenes/gameplay.scene.js +256 -0
  126. package/templates/create/2d-adventure/src/runtime/capabilities.js +34 -0
  127. package/templates/create/2d-adventure/ui/hud.screen.js +60 -0
  128. package/templates/create/2d-survivor/config/gameplay/survivor.config.js +33 -0
  129. package/templates/create/2d-survivor/content/gameplay/spawn-zones.json +29 -0
  130. package/templates/create/2d-survivor/content/registries/.gitkeep +1 -0
  131. package/templates/create/2d-survivor/docs/design/.gitkeep +1 -0
  132. package/templates/create/2d-survivor/docs/design/loop.md +5 -0
  133. package/templates/create/2d-survivor/prefabs/enemies.prefab.js +178 -0
  134. package/templates/create/2d-survivor/prefabs/enemy-swarm.prefab.js +18 -0
  135. package/templates/create/2d-survivor/prefabs/player.prefab.js +42 -0
  136. package/templates/create/2d-survivor/prefabs/projectiles.prefab.js +56 -0
  137. package/templates/create/2d-survivor/scenes/boot.scene.js +12 -0
  138. package/templates/create/2d-survivor/scenes/gameplay.scene.js +314 -0
  139. package/templates/create/2d-survivor/scenes/menu.scene.js +9 -0
  140. package/templates/create/2d-survivor/src/main.js +5 -332
  141. package/templates/create/2d-survivor/src/runtime/app.js +49 -0
  142. package/templates/create/2d-survivor/src/runtime/capabilities.js +35 -0
  143. package/templates/create/2d-survivor/ui/hud.screen.js +45 -0
  144. package/templates/create/2d-survivor/ui/title.screen.js +13 -0
  145. package/templates/create/3d/assets/models/starter-avatar.gltf +184 -0
  146. package/templates/create/3d/config/gameplay/.gitkeep +1 -0
  147. package/templates/create/3d/content/gameplay/checkpoints.json +33 -0
  148. package/templates/create/3d/content/gameplay/course.js +40 -0
  149. package/templates/create/3d/content/registries/.gitkeep +1 -0
  150. package/templates/create/3d/docs/design/.gitkeep +1 -0
  151. package/templates/create/3d/docs/design/loop.md +5 -0
  152. package/templates/create/3d/prefabs/checkpoint.prefab.js +15 -0
  153. package/templates/create/3d/prefabs/player.prefab.js +204 -0
  154. package/templates/create/3d/prefabs/world.prefab.js +112 -0
  155. package/templates/create/3d/scenes/boot.scene.js +12 -0
  156. package/templates/create/3d/scenes/checkpoint.scene.js +9 -0
  157. package/templates/create/3d/scenes/gameplay.scene.js +292 -0
  158. package/templates/create/3d/src/main.js +6 -295
  159. package/templates/create/3d/src/runtime/app.js +49 -0
  160. package/templates/create/3d/src/runtime/capabilities.js +53 -0
  161. package/templates/create/3d/src/runtime/materials.js +34 -0
  162. package/templates/create/3d/src/runtime/state.js +39 -0
  163. package/templates/create/3d/ui/hud.screen.js +75 -0
  164. package/templates/create/3d/ui/pause.screen.js +166 -0
  165. package/templates/create/3d/ui/settings.screen.js +387 -0
  166. package/templates/create/3d-adventure/assets/models/starter-avatar.gltf +184 -0
  167. package/templates/create/3d-adventure/aura.config.json +28 -0
  168. package/templates/create/3d-adventure/config/gameplay/adventure.config.js +9 -0
  169. package/templates/create/3d-adventure/content/gameplay/course.js +62 -0
  170. package/templates/create/3d-adventure/content/registries/.gitkeep +1 -0
  171. package/templates/create/3d-adventure/docs/design/loop.md +5 -0
  172. package/templates/create/3d-adventure/prefabs/player.prefab.js +168 -0
  173. package/templates/create/3d-adventure/prefabs/relic.prefab.js +35 -0
  174. package/templates/create/3d-adventure/prefabs/world.prefab.js +119 -0
  175. package/templates/create/3d-adventure/scenes/gameplay.scene.js +358 -0
  176. package/templates/create/3d-adventure/src/runtime/capabilities.js +56 -0
  177. package/templates/create/3d-adventure/src/runtime/materials.js +39 -0
  178. package/templates/create/3d-adventure/src/runtime/state.js +31 -0
  179. package/templates/create/3d-adventure/ui/hud.screen.js +70 -0
  180. package/templates/create/3d-adventure/ui/pause.screen.js +437 -0
  181. package/templates/create/3d-collectathon/assets/models/starter-avatar.gltf +184 -0
  182. package/templates/create/3d-collectathon/config/gameplay/.gitkeep +1 -0
  183. package/templates/create/3d-collectathon/content/gameplay/collectibles.json +26 -0
  184. package/templates/create/3d-collectathon/content/gameplay/course.js +46 -0
  185. package/templates/create/3d-collectathon/content/registries/.gitkeep +1 -0
  186. package/templates/create/3d-collectathon/docs/design/.gitkeep +1 -0
  187. package/templates/create/3d-collectathon/docs/design/loop.md +5 -0
  188. package/templates/create/3d-collectathon/prefabs/collectible.prefab.js +15 -0
  189. package/templates/create/3d-collectathon/prefabs/player.prefab.js +207 -0
  190. package/templates/create/3d-collectathon/prefabs/world.prefab.js +112 -0
  191. package/templates/create/3d-collectathon/scenes/boot.scene.js +12 -0
  192. package/templates/create/3d-collectathon/scenes/checkpoint.scene.js +9 -0
  193. package/templates/create/3d-collectathon/scenes/gameplay.scene.js +200 -0
  194. package/templates/create/3d-collectathon/src/main.js +5 -355
  195. package/templates/create/3d-collectathon/src/runtime/app.js +49 -0
  196. package/templates/create/3d-collectathon/src/runtime/capabilities.js +53 -0
  197. package/templates/create/3d-collectathon/src/runtime/materials.js +34 -0
  198. package/templates/create/3d-collectathon/src/runtime/state.js +27 -0
  199. package/templates/create/3d-collectathon/ui/hud.screen.js +66 -0
  200. package/templates/create/3d-collectathon/ui/pause.screen.js +13 -0
  201. package/templates/create/blank/config/gameplay/.gitkeep +1 -0
  202. package/templates/create/blank/content/gameplay/.gitkeep +1 -0
  203. package/templates/create/blank/content/registries/.gitkeep +1 -0
  204. package/templates/create/blank/docs/design/.gitkeep +1 -0
  205. package/templates/create/blank/docs/design/loop.md +5 -0
  206. package/templates/create/blank/prefabs/.gitkeep +1 -0
  207. package/templates/create/blank/scenes/.gitkeep +1 -0
  208. package/templates/create/blank/src/runtime/.gitkeep +1 -0
  209. package/templates/create/blank/ui/.gitkeep +1 -0
  210. package/templates/create/deckbuilder-2d/assets/audio/.gitkeep +1 -0
  211. package/templates/create/deckbuilder-2d/assets/fonts/.gitkeep +1 -0
  212. package/templates/create/deckbuilder-2d/assets/sprites/.gitkeep +1 -0
  213. package/templates/create/deckbuilder-2d/assets/starter/README.md +11 -0
  214. package/templates/create/deckbuilder-2d/assets/ui/.gitkeep +1 -0
  215. package/templates/create/deckbuilder-2d/aura.config.json +28 -0
  216. package/templates/create/deckbuilder-2d/config/gameplay/deckbuilder.config.js +26 -0
  217. package/templates/create/deckbuilder-2d/content/cards/guard.card.js +19 -0
  218. package/templates/create/deckbuilder-2d/content/cards/spark.card.js +20 -0
  219. package/templates/create/deckbuilder-2d/content/cards/starter.deck.js +69 -0
  220. package/templates/create/deckbuilder-2d/content/cards/strike.card.js +19 -0
  221. package/templates/create/deckbuilder-2d/content/cards/survey.card.js +20 -0
  222. package/templates/create/deckbuilder-2d/content/encounters/training-battle.encounter.js +14 -0
  223. package/templates/create/deckbuilder-2d/content/encounters/training-battle.js +65 -0
  224. package/templates/create/deckbuilder-2d/content/enemies/training-automaton.enemy.js +48 -0
  225. package/templates/create/deckbuilder-2d/content/gameplay/.gitkeep +1 -0
  226. package/templates/create/deckbuilder-2d/content/registries/cards.registry.js +26 -0
  227. package/templates/create/deckbuilder-2d/content/registries/encounters.registry.js +20 -0
  228. package/templates/create/deckbuilder-2d/content/registries/enemies.registry.js +20 -0
  229. package/templates/create/deckbuilder-2d/content/registries/relics.registry.js +20 -0
  230. package/templates/create/deckbuilder-2d/content/relics/ember-charm.relic.js +18 -0
  231. package/templates/create/deckbuilder-2d/docs/design/loop.md +12 -0
  232. package/templates/create/deckbuilder-2d/prefabs/.gitkeep +1 -0
  233. package/templates/create/deckbuilder-2d/scenes/boot.scene.js +84 -0
  234. package/templates/create/deckbuilder-2d/scenes/gameplay.scene.js +641 -0
  235. package/templates/create/deckbuilder-2d/src/components/.gitkeep +1 -0
  236. package/templates/create/deckbuilder-2d/src/main.js +17 -0
  237. package/templates/create/deckbuilder-2d/src/runtime/capabilities.js +22 -0
  238. package/templates/create/deckbuilder-2d/src/shared/.gitkeep +1 -0
  239. package/templates/create/deckbuilder-2d/src/systems/.gitkeep +1 -0
  240. package/templates/create/deckbuilder-2d/tests/smoke/.gitkeep +1 -0
  241. package/templates/create/deckbuilder-2d/ui/hud.screen.js +80 -0
  242. package/templates/create/deckbuilder-2d/ui/pause.screen.js +146 -0
  243. package/templates/create/deckbuilder-2d/ui/settings.screen.js +342 -0
  244. package/templates/create/local-multiplayer/aura.config.json +40 -0
  245. package/templates/create/local-multiplayer/config/gameplay/local-multiplayer.config.js +26 -0
  246. package/templates/create/local-multiplayer/content/gameplay/room-layout.js +13 -0
  247. package/templates/create/local-multiplayer/content/registries/.gitkeep +1 -0
  248. package/templates/create/local-multiplayer/docs/design/loop.md +14 -0
  249. package/templates/create/local-multiplayer/prefabs/player.prefab.js +99 -0
  250. package/templates/create/local-multiplayer/scenes/boot.scene.js +12 -0
  251. package/templates/create/local-multiplayer/scenes/gameplay.scene.js +443 -0
  252. package/templates/create/local-multiplayer/src/main.js +17 -0
  253. package/templates/create/local-multiplayer/src/runtime/capabilities.js +28 -0
  254. package/templates/create/local-multiplayer/ui/hud.screen.js +60 -0
  255. package/templates/create/shared/src/runtime/project-inspector.js +105 -0
  256. package/templates/create/shared/src/runtime/scene-flow.js +290 -0
  257. package/templates/create/shared/src/runtime/screen-shell.js +222 -0
  258. package/templates/create/shared/src/runtime/ui-forms.js +209 -0
  259. package/templates/create/shared/src/runtime/ui-settings.js +237 -0
  260. package/templates/create/shared/src/runtime/ui-theme.js +352 -0
  261. package/templates/create/shared/src/starter-utils/adventure-objectives.js +102 -0
  262. package/templates/create/shared/src/starter-utils/animation-2d.js +337 -0
  263. package/templates/create/shared/src/starter-utils/avatar-3d.js +404 -0
  264. package/templates/create/shared/src/starter-utils/combat-feedback-2d.js +320 -0
  265. package/templates/create/shared/src/starter-utils/core.js +39 -3
  266. package/templates/create/shared/src/starter-utils/index.js +8 -2
  267. package/templates/create/shared/src/starter-utils/platformer-3d.js +34 -3
  268. package/templates/create/shared/src/starter-utils/triggers.js +662 -0
  269. package/templates/create/shared/src/starter-utils/tween-2d.js +615 -0
  270. package/templates/create/video-cutscene/assets/video/.gitkeep +0 -0
  271. package/templates/create/video-cutscene/aura.config.json +28 -0
  272. package/templates/create/video-cutscene/config/gameplay/.gitkeep +0 -0
  273. package/templates/create/video-cutscene/content/gameplay/.gitkeep +0 -0
  274. package/templates/create/video-cutscene/content/registries/.gitkeep +0 -0
  275. package/templates/create/video-cutscene/docs/design/loop.md +22 -0
  276. package/templates/create/video-cutscene/prefabs/.gitkeep +0 -0
  277. package/templates/create/video-cutscene/scenes/boot.scene.js +11 -0
  278. package/templates/create/video-cutscene/scenes/cutscene.scene.js +113 -0
  279. package/templates/create/video-cutscene/scenes/gameplay.scene.js +50 -0
  280. package/templates/create/video-cutscene/src/main.js +17 -0
  281. package/templates/create/video-cutscene/src/runtime/app.js +52 -0
  282. package/templates/create/video-cutscene/src/runtime/capabilities.js +35 -0
  283. package/templates/create/video-cutscene/src/runtime/state.js +13 -0
  284. package/templates/create/video-cutscene/ui/.gitkeep +0 -0
  285. package/templates/create-bin/play.js +1187 -0
  286. package/templates/make/README.md +46 -0
  287. package/templates/make/catalog.json +51 -0
  288. package/templates/make/component/files/{{MAKE_NAME}}.component.js +20 -0
  289. package/templates/make/component/manifest.json +9 -0
  290. package/templates/make/data/files/{{MAKE_NAME}}.json +14 -0
  291. package/templates/make/data/manifest.json +9 -0
  292. package/templates/make/material/files/{{MAKE_NAME}}.material.json +17 -0
  293. package/templates/make/material/manifest.json +9 -0
  294. package/templates/make/prefab/files/{{MAKE_NAME}}.prefab.js +20 -0
  295. package/templates/make/prefab/manifest.json +9 -0
  296. package/templates/make/scene/files/{{MAKE_NAME}}.scene.js +31 -0
  297. package/templates/make/scene/manifest.json +9 -0
  298. package/templates/make/shader/files/{{MAKE_NAME}}.shader.js +23 -0
  299. package/templates/make/shader/manifest.json +9 -0
  300. package/templates/make/system/files/{{MAKE_NAME}}.system.js +15 -0
  301. package/templates/make/system/manifest.json +9 -0
  302. package/templates/make/ui-screen/files/{{MAKE_NAME}}.screen.js +16 -0
  303. package/templates/make/ui-screen/files/{{MAKE_NAME}}.screen.json +23 -0
  304. package/templates/make/ui-screen/manifest.json +10 -0
  305. package/templates/make-starters/deckbuilder-2d/card/files/{{MAKE_NAME}}.card.js +22 -0
  306. package/templates/make-starters/deckbuilder-2d/card/manifest.json +9 -0
  307. package/templates/make-starters/deckbuilder-2d/catalog.json +34 -0
  308. package/templates/make-starters/deckbuilder-2d/encounter/files/{{MAKE_NAME}}.encounter.js +18 -0
  309. package/templates/make-starters/deckbuilder-2d/encounter/manifest.json +9 -0
  310. package/templates/make-starters/deckbuilder-2d/enemy/files/{{MAKE_NAME}}.enemy.js +28 -0
  311. package/templates/make-starters/deckbuilder-2d/enemy/manifest.json +9 -0
  312. package/templates/make-starters/deckbuilder-2d/relic/files/{{MAKE_NAME}}.relic.js +23 -0
  313. package/templates/make-starters/deckbuilder-2d/relic/manifest.json +9 -0
  314. package/templates/retro/platformer/README.md +10 -0
  315. package/templates/retro/platformer/assets/retro/assets.json +91 -0
  316. package/templates/retro/platformer/aura.config.json +7 -0
  317. package/templates/retro/platformer/package.json +5 -0
  318. package/templates/retro/platformer/src/main.js +40 -0
  319. package/templates/retro/puzzle-grid/README.md +10 -0
  320. package/templates/retro/puzzle-grid/assets/retro/assets.json +90 -0
  321. package/templates/retro/puzzle-grid/aura.config.json +7 -0
  322. package/templates/retro/puzzle-grid/package.json +5 -0
  323. package/templates/retro/puzzle-grid/src/main.js +29 -0
  324. package/templates/retro/tactics-grid/README.md +10 -0
  325. package/templates/retro/tactics-grid/assets/retro/assets.json +90 -0
  326. package/templates/retro/tactics-grid/aura.config.json +7 -0
  327. package/templates/retro/tactics-grid/package.json +5 -0
  328. package/templates/retro/tactics-grid/src/main.js +35 -0
  329. package/templates/retro/topdown-adventure/README.md +10 -0
  330. package/templates/retro/topdown-adventure/assets/retro/assets.json +95 -0
  331. package/templates/retro/topdown-adventure/aura.config.json +7 -0
  332. package/templates/retro/topdown-adventure/package.json +5 -0
  333. package/templates/retro/topdown-adventure/src/main.js +29 -0
  334. package/templates/skills/aurajs/SKILL.md +61 -5
@@ -0,0 +1,587 @@
1
+ import { createHash } from 'node:crypto';
2
+ import {
3
+ copyFileSync,
4
+ cpSync,
5
+ existsSync,
6
+ mkdirSync,
7
+ readFileSync,
8
+ readdirSync,
9
+ rmSync,
10
+ statSync,
11
+ symlinkSync,
12
+ writeFileSync,
13
+ } from 'node:fs';
14
+ import { request as httpRequest } from 'node:http';
15
+ import { request as httpsRequest } from 'node:https';
16
+ import { homedir } from 'node:os';
17
+ import { basename, dirname, join, resolve } from 'node:path';
18
+
19
+ import { SELF_HOSTED_EXTERNAL_ASSETS_CONFIG } from './external-asset-policy.mjs';
20
+ import {
21
+ SELF_HOSTED_ASSETS_SCHEMA,
22
+ SELF_HOSTED_CONFIG_SCHEMA,
23
+ } from './self-hosted-assets.mjs';
24
+
25
+ const EXTERNAL_ASSET_CACHE_ROOT_ENV = 'AURAJS_EXTERNAL_ASSET_CACHE_DIR';
26
+ const LOCAL_HTTP_HOSTS = new Set(['localhost', '127.0.0.1', '::1']);
27
+
28
+ export class ExternalAssetCacheError extends Error {
29
+ constructor(reasonCode, message, details = {}) {
30
+ super(message);
31
+ this.name = 'ExternalAssetCacheError';
32
+ this.reasonCode = typeof reasonCode === 'string' && reasonCode
33
+ ? reasonCode
34
+ : 'external_asset_cache_failed';
35
+ this.details = details && typeof details === 'object' ? details : {};
36
+ }
37
+ }
38
+
39
+ function sha256Buffer(buffer) {
40
+ const hash = createHash('sha256');
41
+ hash.update(buffer);
42
+ return hash.digest('hex');
43
+ }
44
+
45
+ function sha1Buffer(buffer) {
46
+ const hash = createHash('sha1');
47
+ hash.update(buffer);
48
+ return hash.digest('hex');
49
+ }
50
+
51
+ function sha256Text(value) {
52
+ return sha256Buffer(Buffer.from(String(value || ''), 'utf8'));
53
+ }
54
+
55
+ function readJsonFile(path, label) {
56
+ try {
57
+ return JSON.parse(readFileSync(path, 'utf8'));
58
+ } catch (error) {
59
+ throw new ExternalAssetCacheError(
60
+ 'external_asset_json_parse_failed',
61
+ `Unable to parse ${label} at ${path}: ${error instanceof Error ? error.message : String(error)}`,
62
+ { path, label },
63
+ );
64
+ }
65
+ }
66
+
67
+ function readPackageMetadata(projectRoot) {
68
+ const packagePath = resolve(projectRoot, 'package.json');
69
+ if (!existsSync(packagePath)) {
70
+ return {
71
+ name: basename(projectRoot),
72
+ version: '0.0.0',
73
+ };
74
+ }
75
+ const projectPackage = readJsonFile(packagePath, 'package.json');
76
+ return {
77
+ name: typeof projectPackage?.name === 'string' && projectPackage.name.trim()
78
+ ? projectPackage.name.trim()
79
+ : basename(projectRoot),
80
+ version: typeof projectPackage?.version === 'string' && projectPackage.version.trim()
81
+ ? projectPackage.version.trim()
82
+ : '0.0.0',
83
+ };
84
+ }
85
+
86
+ function normalizeSlug(value, fallback = 'cache') {
87
+ const normalized = String(value || '')
88
+ .trim()
89
+ .toLowerCase()
90
+ .replace(/[^a-z0-9._-]+/g, '-')
91
+ .replace(/-+/g, '-')
92
+ .replace(/^-+|-+$/g, '');
93
+ return normalized || fallback;
94
+ }
95
+
96
+ function defaultCacheRoot() {
97
+ return process.env[EXTERNAL_ASSET_CACHE_ROOT_ENV]
98
+ || join(homedir(), '.cache', 'aurajs', 'external-assets');
99
+ }
100
+
101
+ function ensurePublicUrl(rawValue, label) {
102
+ let parsed;
103
+ try {
104
+ parsed = new URL(String(rawValue || '').trim());
105
+ } catch (error) {
106
+ throw new ExternalAssetCacheError(
107
+ 'external_asset_url_invalid',
108
+ `${label} is invalid: ${error instanceof Error ? error.message : String(error)}`,
109
+ { value: rawValue, label },
110
+ );
111
+ }
112
+
113
+ if (parsed.protocol === 'https:') {
114
+ return parsed;
115
+ }
116
+ if (parsed.protocol === 'http:' && LOCAL_HTTP_HOSTS.has(parsed.hostname)) {
117
+ return parsed;
118
+ }
119
+
120
+ throw new ExternalAssetCacheError(
121
+ 'external_asset_url_invalid',
122
+ `${label} must use https://, or http:// only for localhost testing.`,
123
+ { value: rawValue, label },
124
+ );
125
+ }
126
+
127
+ function validateRelativeAssetPath(pathLike) {
128
+ const normalized = String(pathLike || '').replace(/\\/g, '/').trim();
129
+ if (!normalized) {
130
+ throw new ExternalAssetCacheError(
131
+ 'external_asset_manifest_invalid',
132
+ 'External asset manifest entry path must be a non-empty relative path.',
133
+ );
134
+ }
135
+ if (normalized.startsWith('/') || /^[A-Za-z]:\//.test(normalized)) {
136
+ throw new ExternalAssetCacheError(
137
+ 'external_asset_manifest_invalid',
138
+ `External asset path "${normalized}" must be relative.`,
139
+ { path: normalized },
140
+ );
141
+ }
142
+ for (const segment of normalized.split('/')) {
143
+ if (segment === '..') {
144
+ throw new ExternalAssetCacheError(
145
+ 'external_asset_manifest_invalid',
146
+ `External asset path "${normalized}" may not contain "..".`,
147
+ { path: normalized },
148
+ );
149
+ }
150
+ }
151
+ return normalized;
152
+ }
153
+
154
+ function loadExternalAssetsConfig(projectRoot) {
155
+ const configPath = resolve(projectRoot, SELF_HOSTED_EXTERNAL_ASSETS_CONFIG);
156
+ if (!existsSync(configPath)) {
157
+ return null;
158
+ }
159
+
160
+ const config = readJsonFile(configPath, 'aura.external-assets.json');
161
+ if (config?.schema !== SELF_HOSTED_CONFIG_SCHEMA) {
162
+ throw new ExternalAssetCacheError(
163
+ 'external_asset_config_invalid',
164
+ `Expected ${SELF_HOSTED_CONFIG_SCHEMA} in ${configPath}.`,
165
+ { configPath, schema: config?.schema || null },
166
+ );
167
+ }
168
+ if (config?.mode !== 'self-hosted') {
169
+ throw new ExternalAssetCacheError(
170
+ 'external_asset_config_invalid',
171
+ `Unsupported external asset mode "${config?.mode || '<missing>'}" in ${configPath}.`,
172
+ { configPath, mode: config?.mode || null },
173
+ );
174
+ }
175
+ if (typeof config?.assetsManifestUrl !== 'string' || !config.assetsManifestUrl.trim()) {
176
+ throw new ExternalAssetCacheError(
177
+ 'external_asset_config_invalid',
178
+ `${configPath} is missing assetsManifestUrl.`,
179
+ { configPath },
180
+ );
181
+ }
182
+
183
+ ensurePublicUrl(config.assetsManifestUrl, 'assetsManifestUrl');
184
+ return {
185
+ path: configPath,
186
+ value: config,
187
+ };
188
+ }
189
+
190
+ function requestBuffer(urlLike, headers = {}) {
191
+ const url = urlLike instanceof URL ? urlLike : new URL(String(urlLike));
192
+ const requestImpl = url.protocol === 'https:' ? httpsRequest : httpRequest;
193
+
194
+ return new Promise((resolveRequest, rejectRequest) => {
195
+ const request = requestImpl(url, {
196
+ method: 'GET',
197
+ agent: false,
198
+ headers: {
199
+ connection: 'close',
200
+ ...headers,
201
+ },
202
+ }, (response) => {
203
+ const chunks = [];
204
+ response.on('data', (chunk) => chunks.push(Buffer.from(chunk)));
205
+ response.on('end', () => {
206
+ response.socket?.destroy();
207
+ resolveRequest({
208
+ statusCode: response.statusCode ?? 0,
209
+ body: Buffer.concat(chunks),
210
+ });
211
+ });
212
+ });
213
+
214
+ request.on('socket', (socket) => {
215
+ socket.unref();
216
+ });
217
+ request.on('error', rejectRequest);
218
+ request.end();
219
+ });
220
+ }
221
+
222
+ async function fetchJsonWithCache(url, cachedPath) {
223
+ try {
224
+ const response = await requestBuffer(url, {
225
+ accept: 'application/json',
226
+ });
227
+ if (response.statusCode < 200 || response.statusCode >= 300) {
228
+ throw new ExternalAssetCacheError(
229
+ 'external_asset_manifest_fetch_failed',
230
+ `Failed to fetch external asset manifest from ${url}: HTTP ${response.statusCode}.`,
231
+ { url, status: response.statusCode },
232
+ );
233
+ }
234
+ const payload = JSON.parse(response.body.toString('utf8'));
235
+ mkdirSync(dirname(cachedPath), { recursive: true });
236
+ writeFileSync(cachedPath, `${JSON.stringify(payload, null, 2)}\n`, 'utf8');
237
+ return {
238
+ payload,
239
+ source: 'remote',
240
+ fetchWarning: null,
241
+ };
242
+ } catch (error) {
243
+ if (existsSync(cachedPath)) {
244
+ return {
245
+ payload: readJsonFile(cachedPath, 'cached external asset manifest'),
246
+ source: 'cached',
247
+ fetchWarning: error instanceof Error ? error.message : String(error),
248
+ };
249
+ }
250
+ if (error instanceof ExternalAssetCacheError) {
251
+ throw error;
252
+ }
253
+ throw new ExternalAssetCacheError(
254
+ 'external_asset_manifest_fetch_failed',
255
+ `Failed to fetch external asset manifest from ${url}: ${error instanceof Error ? error.message : String(error)}`,
256
+ { url },
257
+ );
258
+ }
259
+ }
260
+
261
+ function validateExternalAssetsManifest(manifest, manifestUrl) {
262
+ if (manifest?.schema !== SELF_HOSTED_ASSETS_SCHEMA) {
263
+ throw new ExternalAssetCacheError(
264
+ 'external_asset_manifest_invalid',
265
+ `Expected ${SELF_HOSTED_ASSETS_SCHEMA} from ${manifestUrl}.`,
266
+ { manifestUrl, schema: manifest?.schema || null },
267
+ );
268
+ }
269
+ if (manifest?.assetMode !== 'sibling') {
270
+ throw new ExternalAssetCacheError(
271
+ 'external_asset_manifest_unsupported',
272
+ `Packaged play/join currently requires self-hosted sibling assets. Received assetMode "${manifest?.assetMode || '<missing>'}" from ${manifestUrl}.`,
273
+ { manifestUrl, assetMode: manifest?.assetMode || null },
274
+ );
275
+ }
276
+ if (manifest?.runtimeResolver !== 'disk') {
277
+ throw new ExternalAssetCacheError(
278
+ 'external_asset_manifest_unsupported',
279
+ `Packaged play/join currently requires runtimeResolver "disk". Received "${manifest?.runtimeResolver || '<missing>'}" from ${manifestUrl}.`,
280
+ { manifestUrl, runtimeResolver: manifest?.runtimeResolver || null },
281
+ );
282
+ }
283
+ if (!Array.isArray(manifest.entries)) {
284
+ throw new ExternalAssetCacheError(
285
+ 'external_asset_manifest_invalid',
286
+ `External asset manifest from ${manifestUrl} is missing entries[].`,
287
+ { manifestUrl },
288
+ );
289
+ }
290
+
291
+ const entries = manifest.entries.map((entry, index) => {
292
+ const path = validateRelativeAssetPath(entry?.path);
293
+ const blobUrl = typeof entry?.blobUrl === 'string' ? entry.blobUrl.trim() : '';
294
+ if (!blobUrl) {
295
+ throw new ExternalAssetCacheError(
296
+ 'external_asset_manifest_invalid',
297
+ `External asset entry "${path}" is missing blobUrl.`,
298
+ { manifestUrl, index, path },
299
+ );
300
+ }
301
+ ensurePublicUrl(blobUrl, `blobUrl for ${path}`);
302
+
303
+ const sha256 = typeof entry?.sha256 === 'string' && entry.sha256.trim()
304
+ ? entry.sha256.trim().toLowerCase()
305
+ : null;
306
+ const sha1 = typeof entry?.sha1 === 'string' && entry.sha1.trim()
307
+ ? entry.sha1.trim().toLowerCase()
308
+ : null;
309
+ if (!sha256 && !sha1) {
310
+ throw new ExternalAssetCacheError(
311
+ 'external_asset_manifest_invalid',
312
+ `External asset entry "${path}" must include sha256 or sha1.`,
313
+ { manifestUrl, index, path },
314
+ );
315
+ }
316
+
317
+ return {
318
+ path,
319
+ blobUrl,
320
+ sizeBytes: Number.isFinite(entry?.sizeBytes) ? entry.sizeBytes : null,
321
+ sha256,
322
+ sha1,
323
+ };
324
+ });
325
+
326
+ return {
327
+ ...manifest,
328
+ entries,
329
+ };
330
+ }
331
+
332
+ function readFileHash(path, algorithm) {
333
+ const hash = createHash(algorithm);
334
+ hash.update(readFileSync(path));
335
+ return hash.digest('hex');
336
+ }
337
+
338
+ function fileMatchesEntry(path, entry) {
339
+ if (!existsSync(path)) return false;
340
+ const stats = statSync(path);
341
+ if (!stats.isFile()) return false;
342
+ if (entry.sizeBytes !== null && stats.size !== entry.sizeBytes) {
343
+ return false;
344
+ }
345
+ if (entry.sha256) {
346
+ return readFileHash(path, 'sha256') === entry.sha256;
347
+ }
348
+ if (entry.sha1) {
349
+ return readFileHash(path, 'sha1') === entry.sha1;
350
+ }
351
+ return false;
352
+ }
353
+
354
+ function walkFiles(root) {
355
+ if (!existsSync(root)) return [];
356
+ const files = [];
357
+ const stack = [root];
358
+ while (stack.length > 0) {
359
+ const current = stack.pop();
360
+ for (const entry of readdirSync(current, { withFileTypes: true })) {
361
+ const fullPath = join(current, entry.name);
362
+ if (entry.isDirectory()) {
363
+ stack.push(fullPath);
364
+ continue;
365
+ }
366
+ files.push(fullPath);
367
+ }
368
+ }
369
+ return files;
370
+ }
371
+
372
+ function removeUnexpectedFiles(root, expectedPaths) {
373
+ for (const filePath of walkFiles(root)) {
374
+ const relativePath = filePath.slice(root.length + 1).replace(/\\/g, '/');
375
+ if (!expectedPaths.has(relativePath)) {
376
+ rmSync(filePath, { force: true });
377
+ }
378
+ }
379
+ }
380
+
381
+ async function downloadEntry(entry, destPath) {
382
+ const response = await requestBuffer(entry.blobUrl);
383
+ if (response.statusCode < 200 || response.statusCode >= 300) {
384
+ throw new ExternalAssetCacheError(
385
+ 'external_asset_download_failed',
386
+ `Failed to download external asset "${entry.path}" from ${entry.blobUrl}: HTTP ${response.statusCode}.`,
387
+ { path: entry.path, url: entry.blobUrl, status: response.statusCode },
388
+ );
389
+ }
390
+
391
+ const buffer = response.body;
392
+ if (entry.sizeBytes !== null && buffer.length !== entry.sizeBytes) {
393
+ throw new ExternalAssetCacheError(
394
+ 'external_asset_hash_mismatch',
395
+ `External asset "${entry.path}" size mismatch: expected ${entry.sizeBytes} bytes, got ${buffer.length}.`,
396
+ { path: entry.path, expectedSizeBytes: entry.sizeBytes, actualSizeBytes: buffer.length },
397
+ );
398
+ }
399
+
400
+ const expectedSha256 = entry.sha256;
401
+ if (expectedSha256 && sha256Buffer(buffer) !== expectedSha256) {
402
+ throw new ExternalAssetCacheError(
403
+ 'external_asset_hash_mismatch',
404
+ `External asset "${entry.path}" failed sha256 validation after download.`,
405
+ { path: entry.path, expectedSha256 },
406
+ );
407
+ }
408
+ if (!expectedSha256 && entry.sha1 && sha1Buffer(buffer) !== entry.sha1) {
409
+ throw new ExternalAssetCacheError(
410
+ 'external_asset_hash_mismatch',
411
+ `External asset "${entry.path}" failed sha1 validation after download.`,
412
+ { path: entry.path, expectedSha1: entry.sha1 },
413
+ );
414
+ }
415
+
416
+ mkdirSync(dirname(destPath), { recursive: true });
417
+ const tempPath = `${destPath}.tmp-${process.pid}-${Date.now()}`;
418
+ writeFileSync(tempPath, buffer);
419
+ try {
420
+ rmSync(destPath, { force: true });
421
+ } catch {}
422
+ copyFileSync(tempPath, destPath);
423
+ rmSync(tempPath, { force: true });
424
+ }
425
+
426
+ async function hydrateAssetFiles(assetRoot, manifest) {
427
+ mkdirSync(assetRoot, { recursive: true });
428
+ removeUnexpectedFiles(assetRoot, new Set(manifest.entries.map((entry) => entry.path)));
429
+
430
+ let downloadedCount = 0;
431
+ let reusedCount = 0;
432
+ for (const entry of manifest.entries) {
433
+ const destPath = resolve(assetRoot, ...entry.path.split('/'));
434
+ if (fileMatchesEntry(destPath, entry)) {
435
+ reusedCount += 1;
436
+ continue;
437
+ }
438
+ await downloadEntry(entry, destPath);
439
+ if (!fileMatchesEntry(destPath, entry)) {
440
+ throw new ExternalAssetCacheError(
441
+ 'external_asset_hash_mismatch',
442
+ `External asset "${entry.path}" failed validation after download was written to cache.`,
443
+ { path: entry.path, destPath },
444
+ );
445
+ }
446
+ downloadedCount += 1;
447
+ }
448
+
449
+ return {
450
+ downloadedCount,
451
+ reusedCount,
452
+ };
453
+ }
454
+
455
+ function resolveNodeModulesRoot(projectRoot) {
456
+ const directNodeModules = resolve(projectRoot, 'node_modules');
457
+ if (existsSync(directNodeModules)) {
458
+ try {
459
+ if (statSync(directNodeModules).isDirectory()) {
460
+ return directNodeModules;
461
+ }
462
+ } catch {}
463
+ }
464
+
465
+ let current = resolve(projectRoot);
466
+ while (true) {
467
+ const parent = dirname(current);
468
+ if (parent === current) {
469
+ return null;
470
+ }
471
+ current = parent;
472
+ if (basename(current) === 'node_modules') {
473
+ return current;
474
+ }
475
+ }
476
+ }
477
+
478
+ function linkOrCopy(sourcePath, destPath, isDirectory) {
479
+ mkdirSync(dirname(destPath), { recursive: true });
480
+ try {
481
+ const linkType = isDirectory
482
+ ? (process.platform === 'win32' ? 'junction' : 'dir')
483
+ : 'file';
484
+ symlinkSync(resolve(sourcePath), destPath, linkType);
485
+ return;
486
+ } catch {}
487
+
488
+ if (isDirectory) {
489
+ cpSync(sourcePath, destPath, {
490
+ recursive: true,
491
+ force: true,
492
+ });
493
+ return;
494
+ }
495
+
496
+ copyFileSync(sourcePath, destPath);
497
+ }
498
+
499
+ function buildRuntimeWorkspace(projectRoot, runtimeRoot, assetRoot) {
500
+ rmSync(runtimeRoot, { recursive: true, force: true });
501
+ mkdirSync(runtimeRoot, { recursive: true });
502
+
503
+ const skippedNames = new Set(['assets', 'build', '.aura', '.logs', 'node_modules']);
504
+ for (const entry of readdirSync(projectRoot, { withFileTypes: true })) {
505
+ if (skippedNames.has(entry.name)) continue;
506
+ const sourcePath = join(projectRoot, entry.name);
507
+ const destPath = join(runtimeRoot, entry.name);
508
+ linkOrCopy(sourcePath, destPath, entry.isDirectory());
509
+ }
510
+
511
+ const nodeModulesRoot = resolveNodeModulesRoot(projectRoot);
512
+ if (nodeModulesRoot) {
513
+ linkOrCopy(nodeModulesRoot, join(runtimeRoot, 'node_modules'), true);
514
+ }
515
+ linkOrCopy(assetRoot, join(runtimeRoot, 'assets'), true);
516
+ }
517
+
518
+ function ensureCacheLayout(projectRoot, config, manifest) {
519
+ const packageMeta = readPackageMetadata(projectRoot);
520
+ const packageSlug = normalizeSlug(packageMeta.name, 'game');
521
+ const versionSlug = normalizeSlug(packageMeta.version, '0.0.0');
522
+ const manifestUrlHash = sha256Text(config.assetsManifestUrl).slice(0, 16);
523
+ const manifestHash = normalizeSlug(
524
+ manifest.sourceManifestHash || sha256Text(JSON.stringify(manifest)),
525
+ 'manifest',
526
+ );
527
+ const cacheBase = resolve(defaultCacheRoot(), packageSlug, versionSlug, manifestUrlHash, manifestHash);
528
+ return {
529
+ packageMeta,
530
+ cacheBase,
531
+ assetRoot: join(cacheBase, 'assets'),
532
+ runtimeRoot: join(cacheBase, 'runtime'),
533
+ cachedManifestPath: join(defaultCacheRoot(), packageSlug, versionSlug, 'manifests', `${manifestUrlHash}.json`),
534
+ };
535
+ }
536
+
537
+ export async function prepareExternalAssetRuntime({
538
+ projectRoot = process.cwd(),
539
+ commandName = 'play',
540
+ stdout = process.stdout,
541
+ } = {}) {
542
+ const configRecord = loadExternalAssetsConfig(projectRoot);
543
+ if (!configRecord) {
544
+ return {
545
+ enabled: false,
546
+ runtimeProjectRoot: projectRoot,
547
+ downloadSummary: null,
548
+ manifestSource: null,
549
+ cacheBase: null,
550
+ };
551
+ }
552
+
553
+ const config = configRecord.value;
554
+ const packageMeta = readPackageMetadata(projectRoot);
555
+ const manifestUrlHash = sha256Text(config.assetsManifestUrl).slice(0, 16);
556
+ const cachedManifestPath = join(
557
+ defaultCacheRoot(),
558
+ normalizeSlug(packageMeta.name, 'game'),
559
+ normalizeSlug(packageMeta.version, '0.0.0'),
560
+ 'manifests',
561
+ `${manifestUrlHash}.json`,
562
+ );
563
+
564
+ const fetchedManifest = await fetchJsonWithCache(config.assetsManifestUrl, cachedManifestPath);
565
+ const manifest = validateExternalAssetsManifest(fetchedManifest.payload, config.assetsManifestUrl);
566
+ const cacheLayout = ensureCacheLayout(projectRoot, config, manifest);
567
+ const downloadSummary = await hydrateAssetFiles(cacheLayout.assetRoot, manifest);
568
+ buildRuntimeWorkspace(projectRoot, cacheLayout.runtimeRoot, cacheLayout.assetRoot);
569
+
570
+ stdout?.write(` Self-hosted assets: using cached runtime workspace for ${commandName}.\n`);
571
+ if (fetchedManifest.source === 'cached') {
572
+ stdout?.write(' External asset manifest: using cached copy because the remote manifest was unavailable.\n');
573
+ }
574
+ stdout?.write(
575
+ ` Asset cache: downloaded=${downloadSummary.downloadedCount} reused=${downloadSummary.reusedCount} root=${cacheLayout.assetRoot}\n`,
576
+ );
577
+
578
+ return {
579
+ enabled: true,
580
+ runtimeProjectRoot: cacheLayout.runtimeRoot,
581
+ downloadSummary,
582
+ manifestSource: fetchedManifest.source,
583
+ manifestFetchWarning: fetchedManifest.fetchWarning,
584
+ cacheBase: cacheLayout.cacheBase,
585
+ assetRoot: cacheLayout.assetRoot,
586
+ };
587
+ }