@auraindustry/aurajs 0.0.7 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +98 -2
- package/benchmarks/perf-thresholds.json +54 -0
- package/package.json +4 -7
- package/src/asset-pack.mjs +8 -1
- package/src/authored-project.mjs +1449 -0
- package/src/authored-runtime.mjs +2016 -0
- package/src/authoring/avatar-animation-graph.mjs +648 -0
- package/src/bin-integrity.mjs +272 -0
- package/src/build-contract/assets.mjs +130 -0
- package/src/build-contract/capabilities.mjs +116 -0
- package/src/build-contract/constants.mjs +6 -0
- package/src/build-contract/helpers.mjs +44 -0
- package/src/build-contract/web-templates.mjs +5993 -0
- package/src/build-contract.mjs +27 -2910
- package/src/bundler.mjs +188 -55
- package/src/cli.mjs +4840 -1512
- package/src/commands/project-authoring.mjs +454 -0
- package/src/config.mjs +44 -0
- package/src/conformance/cases/app-and-ui-runtime-cases.mjs +3309 -0
- package/src/conformance/cases/core-runtime-cases.mjs +1431 -0
- package/src/conformance/cases/index.mjs +11 -0
- package/src/conformance/cases/scene3d-and-media-cases.mjs +2094 -0
- package/src/conformance/cases/systems-and-gameplay-cases.mjs +1776 -0
- package/src/conformance/shared.mjs +27 -0
- package/src/conformance-runner.mjs +25 -13
- package/src/conformance.mjs +619 -4020
- package/src/cutscene.mjs +362 -5
- package/src/dev-cli-action.mjs +249 -0
- package/src/dev-cli-inspect.mjs +92 -0
- package/src/dev-cli-state.mjs +80 -0
- package/src/external-asset-cache.mjs +587 -0
- package/src/external-asset-policy.mjs +217 -0
- package/src/external-package-surface.mjs +206 -0
- package/src/game-action-runtime.mjs +869 -0
- package/src/game-state-runtime.mjs +206 -6
- package/src/headless-action.mjs +186 -0
- package/src/headless-test/runtime-animation.mjs +1173 -0
- package/src/headless-test/runtime-coordinator.mjs +1514 -0
- package/src/headless-test/runtime-primitives.mjs +320 -0
- package/src/headless-test/runtime-world.mjs +2253 -0
- package/src/headless-test.mjs +392 -4298
- package/src/host-binary.mjs +342 -14
- package/src/icon-discovery.mjs +64 -0
- package/src/make-catalog.mjs +109 -0
- package/src/make.mjs +197 -0
- package/src/package-integrity.mjs +586 -0
- package/src/perf-benchmark.mjs +353 -0
- package/src/postinstall.mjs +5 -5
- package/src/prefabs/index.mjs +34 -0
- package/src/prefabs/scene-serialization.mjs +184 -0
- package/src/project-importer.mjs +620 -0
- package/src/project-registry.mjs +24 -0
- package/src/publish-command.mjs +195 -0
- package/src/publish-env-example.mjs +83 -0
- package/src/publish-validation.mjs +708 -0
- package/src/retro/assets/compile.mjs +232 -0
- package/src/retro/backend-gba/authoring.mjs +1029 -0
- package/src/retro/backend-gba/rom.mjs +363 -0
- package/src/retro/backend-gbc/rom.mjs +85 -0
- package/src/retro/build.mjs +278 -0
- package/src/retro/cli/commands.mjs +292 -0
- package/src/retro/cli/templates.mjs +84 -0
- package/src/retro/diagnostics/catalog.mjs +110 -0
- package/src/retro/diagnostics/emit.mjs +72 -0
- package/src/retro/emulator/case-overlay.mjs +64 -0
- package/src/retro/emulator/discovery.mjs +158 -0
- package/src/retro/emulator/macos-case-overlay.swift +220 -0
- package/src/retro/emulator/profiles.mjs +146 -0
- package/src/retro/emulator/runner.mjs +289 -0
- package/src/retro/frontend/load-project.mjs +98 -0
- package/src/retro/index.mjs +30 -0
- package/src/retro/ir/build-ir.mjs +108 -0
- package/src/retro/runtime-gba/contract.mjs +151 -0
- package/src/retro/runtime-gbc/contract.mjs +117 -0
- package/src/retro/shared/span.mjs +26 -0
- package/src/retro/shared/targets.mjs +64 -0
- package/src/retro/validator/check-project.mjs +114 -0
- package/src/runtime-hotspot-audit.mjs +707 -0
- package/src/scaffold/config.mjs +1000 -0
- package/src/scaffold/fs.mjs +56 -0
- package/src/scaffold/layout.mjs +318 -0
- package/src/scaffold/project-docs.mjs +439 -0
- package/src/scaffold.mjs +93 -596
- package/src/scene-composition/index.mjs +326 -0
- package/src/scene-composition/runtime.mjs +751 -0
- package/src/self-hosted-assets.mjs +604 -0
- package/src/session-client.mjs +750 -0
- package/src/session-native-launcher.mjs +74 -0
- package/src/session-protocol.mjs +75 -0
- package/src/session-runtime.mjs +321 -0
- package/src/session-server.mjs +360 -0
- package/src/shader-kits/index.mjs +773 -0
- package/src/starter-content-registry.mjs +292 -0
- package/src/state-artifacts.mjs +662 -24
- package/src/state-dev-reload.mjs +99 -2
- package/src/terminal-ui.mjs +245 -0
- package/src/web-conformance.mjs +219 -0
- package/templates/create/2d/config/gameplay/shooter.config.js +26 -0
- package/templates/create/2d/content/gameplay/waves.json +26 -0
- package/templates/create/2d/content/registries/.gitkeep +1 -0
- package/templates/create/2d/docs/design/.gitkeep +1 -0
- package/templates/create/2d/docs/design/loop.md +5 -0
- package/templates/create/2d/prefabs/enemies.prefab.js +90 -0
- package/templates/create/2d/prefabs/enemy-basic.prefab.js +18 -0
- package/templates/create/2d/prefabs/player.prefab.js +36 -0
- package/templates/create/2d/prefabs/projectiles.prefab.js +35 -0
- package/templates/create/2d/scenes/boot.scene.js +12 -0
- package/templates/create/2d/scenes/gameplay.scene.js +230 -0
- package/templates/create/2d/scenes/menu.scene.js +9 -0
- package/templates/create/2d/src/main.js +6 -185
- package/templates/create/2d/src/runtime/app.js +49 -0
- package/templates/create/2d/src/runtime/capabilities.js +35 -0
- package/templates/create/2d/ui/hud.screen.js +40 -0
- package/templates/create/2d/ui/pause.screen.js +149 -0
- package/templates/create/2d/ui/settings.screen.js +347 -0
- package/templates/create/2d/ui/title.screen.js +13 -0
- package/templates/create/2d-adventure/aura.config.json +28 -0
- package/templates/create/2d-adventure/config/gameplay/adventure.config.js +14 -0
- package/templates/create/2d-adventure/content/gameplay/world.js +46 -0
- package/templates/create/2d-adventure/content/registries/.gitkeep +1 -0
- package/templates/create/2d-adventure/docs/design/loop.md +5 -0
- package/templates/create/2d-adventure/prefabs/player.prefab.js +54 -0
- package/templates/create/2d-adventure/prefabs/relic.prefab.js +38 -0
- package/templates/create/2d-adventure/prefabs/world.prefab.js +125 -0
- package/templates/create/2d-adventure/scenes/gameplay.scene.js +256 -0
- package/templates/create/2d-adventure/src/runtime/capabilities.js +34 -0
- package/templates/create/2d-adventure/ui/hud.screen.js +60 -0
- package/templates/create/2d-survivor/config/gameplay/survivor.config.js +33 -0
- package/templates/create/2d-survivor/content/gameplay/spawn-zones.json +29 -0
- package/templates/create/2d-survivor/content/registries/.gitkeep +1 -0
- package/templates/create/2d-survivor/docs/design/.gitkeep +1 -0
- package/templates/create/2d-survivor/docs/design/loop.md +5 -0
- package/templates/create/2d-survivor/prefabs/enemies.prefab.js +178 -0
- package/templates/create/2d-survivor/prefabs/enemy-swarm.prefab.js +18 -0
- package/templates/create/2d-survivor/prefabs/player.prefab.js +42 -0
- package/templates/create/2d-survivor/prefabs/projectiles.prefab.js +56 -0
- package/templates/create/2d-survivor/scenes/boot.scene.js +12 -0
- package/templates/create/2d-survivor/scenes/gameplay.scene.js +314 -0
- package/templates/create/2d-survivor/scenes/menu.scene.js +9 -0
- package/templates/create/2d-survivor/src/main.js +5 -332
- package/templates/create/2d-survivor/src/runtime/app.js +49 -0
- package/templates/create/2d-survivor/src/runtime/capabilities.js +35 -0
- package/templates/create/2d-survivor/ui/hud.screen.js +45 -0
- package/templates/create/2d-survivor/ui/title.screen.js +13 -0
- package/templates/create/3d/assets/models/starter-avatar.gltf +184 -0
- package/templates/create/3d/config/gameplay/.gitkeep +1 -0
- package/templates/create/3d/content/gameplay/checkpoints.json +33 -0
- package/templates/create/3d/content/gameplay/course.js +40 -0
- package/templates/create/3d/content/registries/.gitkeep +1 -0
- package/templates/create/3d/docs/design/.gitkeep +1 -0
- package/templates/create/3d/docs/design/loop.md +5 -0
- package/templates/create/3d/prefabs/checkpoint.prefab.js +15 -0
- package/templates/create/3d/prefabs/player.prefab.js +204 -0
- package/templates/create/3d/prefabs/world.prefab.js +112 -0
- package/templates/create/3d/scenes/boot.scene.js +12 -0
- package/templates/create/3d/scenes/checkpoint.scene.js +9 -0
- package/templates/create/3d/scenes/gameplay.scene.js +292 -0
- package/templates/create/3d/src/main.js +6 -295
- package/templates/create/3d/src/runtime/app.js +49 -0
- package/templates/create/3d/src/runtime/capabilities.js +53 -0
- package/templates/create/3d/src/runtime/materials.js +34 -0
- package/templates/create/3d/src/runtime/state.js +39 -0
- package/templates/create/3d/ui/hud.screen.js +75 -0
- package/templates/create/3d/ui/pause.screen.js +166 -0
- package/templates/create/3d/ui/settings.screen.js +387 -0
- package/templates/create/3d-adventure/assets/models/starter-avatar.gltf +184 -0
- package/templates/create/3d-adventure/aura.config.json +28 -0
- package/templates/create/3d-adventure/config/gameplay/adventure.config.js +9 -0
- package/templates/create/3d-adventure/content/gameplay/course.js +62 -0
- package/templates/create/3d-adventure/content/registries/.gitkeep +1 -0
- package/templates/create/3d-adventure/docs/design/loop.md +5 -0
- package/templates/create/3d-adventure/prefabs/player.prefab.js +168 -0
- package/templates/create/3d-adventure/prefabs/relic.prefab.js +35 -0
- package/templates/create/3d-adventure/prefabs/world.prefab.js +119 -0
- package/templates/create/3d-adventure/scenes/gameplay.scene.js +358 -0
- package/templates/create/3d-adventure/src/runtime/capabilities.js +56 -0
- package/templates/create/3d-adventure/src/runtime/materials.js +39 -0
- package/templates/create/3d-adventure/src/runtime/state.js +31 -0
- package/templates/create/3d-adventure/ui/hud.screen.js +70 -0
- package/templates/create/3d-adventure/ui/pause.screen.js +437 -0
- package/templates/create/3d-collectathon/assets/models/starter-avatar.gltf +184 -0
- package/templates/create/3d-collectathon/config/gameplay/.gitkeep +1 -0
- package/templates/create/3d-collectathon/content/gameplay/collectibles.json +26 -0
- package/templates/create/3d-collectathon/content/gameplay/course.js +46 -0
- package/templates/create/3d-collectathon/content/registries/.gitkeep +1 -0
- package/templates/create/3d-collectathon/docs/design/.gitkeep +1 -0
- package/templates/create/3d-collectathon/docs/design/loop.md +5 -0
- package/templates/create/3d-collectathon/prefabs/collectible.prefab.js +15 -0
- package/templates/create/3d-collectathon/prefabs/player.prefab.js +207 -0
- package/templates/create/3d-collectathon/prefabs/world.prefab.js +112 -0
- package/templates/create/3d-collectathon/scenes/boot.scene.js +12 -0
- package/templates/create/3d-collectathon/scenes/checkpoint.scene.js +9 -0
- package/templates/create/3d-collectathon/scenes/gameplay.scene.js +200 -0
- package/templates/create/3d-collectathon/src/main.js +5 -355
- package/templates/create/3d-collectathon/src/runtime/app.js +49 -0
- package/templates/create/3d-collectathon/src/runtime/capabilities.js +53 -0
- package/templates/create/3d-collectathon/src/runtime/materials.js +34 -0
- package/templates/create/3d-collectathon/src/runtime/state.js +27 -0
- package/templates/create/3d-collectathon/ui/hud.screen.js +66 -0
- package/templates/create/3d-collectathon/ui/pause.screen.js +13 -0
- package/templates/create/blank/config/gameplay/.gitkeep +1 -0
- package/templates/create/blank/content/gameplay/.gitkeep +1 -0
- package/templates/create/blank/content/registries/.gitkeep +1 -0
- package/templates/create/blank/docs/design/.gitkeep +1 -0
- package/templates/create/blank/docs/design/loop.md +5 -0
- package/templates/create/blank/prefabs/.gitkeep +1 -0
- package/templates/create/blank/scenes/.gitkeep +1 -0
- package/templates/create/blank/src/runtime/.gitkeep +1 -0
- package/templates/create/blank/ui/.gitkeep +1 -0
- package/templates/create/deckbuilder-2d/assets/audio/.gitkeep +1 -0
- package/templates/create/deckbuilder-2d/assets/fonts/.gitkeep +1 -0
- package/templates/create/deckbuilder-2d/assets/sprites/.gitkeep +1 -0
- package/templates/create/deckbuilder-2d/assets/starter/README.md +11 -0
- package/templates/create/deckbuilder-2d/assets/ui/.gitkeep +1 -0
- package/templates/create/deckbuilder-2d/aura.config.json +28 -0
- package/templates/create/deckbuilder-2d/config/gameplay/deckbuilder.config.js +26 -0
- package/templates/create/deckbuilder-2d/content/cards/guard.card.js +19 -0
- package/templates/create/deckbuilder-2d/content/cards/spark.card.js +20 -0
- package/templates/create/deckbuilder-2d/content/cards/starter.deck.js +69 -0
- package/templates/create/deckbuilder-2d/content/cards/strike.card.js +19 -0
- package/templates/create/deckbuilder-2d/content/cards/survey.card.js +20 -0
- package/templates/create/deckbuilder-2d/content/encounters/training-battle.encounter.js +14 -0
- package/templates/create/deckbuilder-2d/content/encounters/training-battle.js +65 -0
- package/templates/create/deckbuilder-2d/content/enemies/training-automaton.enemy.js +48 -0
- package/templates/create/deckbuilder-2d/content/gameplay/.gitkeep +1 -0
- package/templates/create/deckbuilder-2d/content/registries/cards.registry.js +26 -0
- package/templates/create/deckbuilder-2d/content/registries/encounters.registry.js +20 -0
- package/templates/create/deckbuilder-2d/content/registries/enemies.registry.js +20 -0
- package/templates/create/deckbuilder-2d/content/registries/relics.registry.js +20 -0
- package/templates/create/deckbuilder-2d/content/relics/ember-charm.relic.js +18 -0
- package/templates/create/deckbuilder-2d/docs/design/loop.md +12 -0
- package/templates/create/deckbuilder-2d/prefabs/.gitkeep +1 -0
- package/templates/create/deckbuilder-2d/scenes/boot.scene.js +84 -0
- package/templates/create/deckbuilder-2d/scenes/gameplay.scene.js +641 -0
- package/templates/create/deckbuilder-2d/src/components/.gitkeep +1 -0
- package/templates/create/deckbuilder-2d/src/main.js +17 -0
- package/templates/create/deckbuilder-2d/src/runtime/capabilities.js +22 -0
- package/templates/create/deckbuilder-2d/src/shared/.gitkeep +1 -0
- package/templates/create/deckbuilder-2d/src/systems/.gitkeep +1 -0
- package/templates/create/deckbuilder-2d/tests/smoke/.gitkeep +1 -0
- package/templates/create/deckbuilder-2d/ui/hud.screen.js +80 -0
- package/templates/create/deckbuilder-2d/ui/pause.screen.js +146 -0
- package/templates/create/deckbuilder-2d/ui/settings.screen.js +342 -0
- package/templates/create/local-multiplayer/aura.config.json +41 -0
- package/templates/create/local-multiplayer/config/gameplay/local-multiplayer.config.js +26 -0
- package/templates/create/local-multiplayer/content/gameplay/room-layout.js +13 -0
- package/templates/create/local-multiplayer/content/registries/.gitkeep +1 -0
- package/templates/create/local-multiplayer/docs/design/loop.md +16 -0
- package/templates/create/local-multiplayer/prefabs/player.prefab.js +99 -0
- package/templates/create/local-multiplayer/scenes/boot.scene.js +12 -0
- package/templates/create/local-multiplayer/scenes/gameplay.scene.js +472 -0
- package/templates/create/local-multiplayer/src/main.js +17 -0
- package/templates/create/local-multiplayer/src/runtime/capabilities.js +28 -0
- package/templates/create/local-multiplayer/ui/hud.screen.js +65 -0
- package/templates/create/shared/src/runtime/project-inspector.js +105 -0
- package/templates/create/shared/src/runtime/scene-flow.js +290 -0
- package/templates/create/shared/src/runtime/screen-shell.js +222 -0
- package/templates/create/shared/src/runtime/ui-forms.js +209 -0
- package/templates/create/shared/src/runtime/ui-settings.js +237 -0
- package/templates/create/shared/src/runtime/ui-theme.js +352 -0
- package/templates/create/shared/src/starter-utils/adventure-objectives.js +102 -0
- package/templates/create/shared/src/starter-utils/animation-2d.js +337 -0
- package/templates/create/shared/src/starter-utils/avatar-3d.js +404 -0
- package/templates/create/shared/src/starter-utils/combat-feedback-2d.js +320 -0
- package/templates/create/shared/src/starter-utils/core.js +39 -3
- package/templates/create/shared/src/starter-utils/index.js +8 -2
- package/templates/create/shared/src/starter-utils/platformer-3d.js +34 -3
- package/templates/create/shared/src/starter-utils/triggers.js +662 -0
- package/templates/create/shared/src/starter-utils/tween-2d.js +615 -0
- package/templates/create/video-cutscene/assets/video/.gitkeep +0 -0
- package/templates/create/video-cutscene/aura.config.json +28 -0
- package/templates/create/video-cutscene/config/gameplay/.gitkeep +0 -0
- package/templates/create/video-cutscene/content/gameplay/.gitkeep +0 -0
- package/templates/create/video-cutscene/content/registries/.gitkeep +0 -0
- package/templates/create/video-cutscene/docs/design/loop.md +22 -0
- package/templates/create/video-cutscene/prefabs/.gitkeep +0 -0
- package/templates/create/video-cutscene/scenes/boot.scene.js +11 -0
- package/templates/create/video-cutscene/scenes/cutscene.scene.js +113 -0
- package/templates/create/video-cutscene/scenes/gameplay.scene.js +50 -0
- package/templates/create/video-cutscene/src/main.js +17 -0
- package/templates/create/video-cutscene/src/runtime/app.js +52 -0
- package/templates/create/video-cutscene/src/runtime/capabilities.js +35 -0
- package/templates/create/video-cutscene/src/runtime/state.js +13 -0
- package/templates/create/video-cutscene/ui/.gitkeep +0 -0
- package/templates/create-bin/play.js +1192 -0
- package/templates/make/README.md +46 -0
- package/templates/make/catalog.json +51 -0
- package/templates/make/component/files/{{MAKE_NAME}}.component.js +20 -0
- package/templates/make/component/manifest.json +9 -0
- package/templates/make/data/files/{{MAKE_NAME}}.json +14 -0
- package/templates/make/data/manifest.json +9 -0
- package/templates/make/material/files/{{MAKE_NAME}}.material.json +17 -0
- package/templates/make/material/manifest.json +9 -0
- package/templates/make/prefab/files/{{MAKE_NAME}}.prefab.js +20 -0
- package/templates/make/prefab/manifest.json +9 -0
- package/templates/make/scene/files/{{MAKE_NAME}}.scene.js +31 -0
- package/templates/make/scene/manifest.json +9 -0
- package/templates/make/shader/files/{{MAKE_NAME}}.shader.js +23 -0
- package/templates/make/shader/manifest.json +9 -0
- package/templates/make/system/files/{{MAKE_NAME}}.system.js +15 -0
- package/templates/make/system/manifest.json +9 -0
- package/templates/make/ui-screen/files/{{MAKE_NAME}}.screen.js +16 -0
- package/templates/make/ui-screen/files/{{MAKE_NAME}}.screen.json +23 -0
- package/templates/make/ui-screen/manifest.json +10 -0
- package/templates/make-starters/deckbuilder-2d/card/files/{{MAKE_NAME}}.card.js +22 -0
- package/templates/make-starters/deckbuilder-2d/card/manifest.json +9 -0
- package/templates/make-starters/deckbuilder-2d/catalog.json +34 -0
- package/templates/make-starters/deckbuilder-2d/encounter/files/{{MAKE_NAME}}.encounter.js +18 -0
- package/templates/make-starters/deckbuilder-2d/encounter/manifest.json +9 -0
- package/templates/make-starters/deckbuilder-2d/enemy/files/{{MAKE_NAME}}.enemy.js +28 -0
- package/templates/make-starters/deckbuilder-2d/enemy/manifest.json +9 -0
- package/templates/make-starters/deckbuilder-2d/relic/files/{{MAKE_NAME}}.relic.js +23 -0
- package/templates/make-starters/deckbuilder-2d/relic/manifest.json +9 -0
- package/templates/retro/platformer/README.md +10 -0
- package/templates/retro/platformer/assets/retro/assets.json +91 -0
- package/templates/retro/platformer/aura.config.json +7 -0
- package/templates/retro/platformer/package.json +5 -0
- package/templates/retro/platformer/src/main.js +40 -0
- package/templates/retro/puzzle-grid/README.md +10 -0
- package/templates/retro/puzzle-grid/assets/retro/assets.json +90 -0
- package/templates/retro/puzzle-grid/aura.config.json +7 -0
- package/templates/retro/puzzle-grid/package.json +5 -0
- package/templates/retro/puzzle-grid/src/main.js +29 -0
- package/templates/retro/tactics-grid/README.md +10 -0
- package/templates/retro/tactics-grid/assets/retro/assets.json +90 -0
- package/templates/retro/tactics-grid/aura.config.json +7 -0
- package/templates/retro/tactics-grid/package.json +5 -0
- package/templates/retro/tactics-grid/src/main.js +35 -0
- package/templates/retro/topdown-adventure/README.md +10 -0
- package/templates/retro/topdown-adventure/assets/retro/assets.json +95 -0
- package/templates/retro/topdown-adventure/aura.config.json +7 -0
- package/templates/retro/topdown-adventure/package.json +5 -0
- package/templates/retro/topdown-adventure/src/main.js +29 -0
- package/templates/skills/aurajs/SKILL.md +61 -5
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
3
|
+
import { dirname, join, resolve } from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
|
|
6
|
+
export const DEFAULT_AURAJS_PACKAGE_ROOT = dirname(fileURLToPath(new URL('../package.json', import.meta.url)));
|
|
7
|
+
export const EXACT_SEMVER_PATTERN = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
|
|
8
|
+
|
|
9
|
+
export class ProjectBinIntegrityError extends Error {
|
|
10
|
+
constructor(reasonCode, message, details = {}) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.name = 'ProjectBinIntegrityError';
|
|
13
|
+
this.reasonCode = typeof reasonCode === 'string' && reasonCode.length > 0
|
|
14
|
+
? reasonCode
|
|
15
|
+
: 'project_bin_integrity_failed';
|
|
16
|
+
this.details = details && typeof details === 'object' ? details : {};
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function normalizeRelativePath(pathLike) {
|
|
21
|
+
return String(pathLike || '')
|
|
22
|
+
.trim()
|
|
23
|
+
.replace(/^[.][\\/]/, '')
|
|
24
|
+
.replaceAll('\\', '/');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function normalizeText(value) {
|
|
28
|
+
return String(value || '').replace(/\r\n?/g, '\n');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function sha256Text(value) {
|
|
32
|
+
return createHash('sha256').update(normalizeText(value)).digest('hex');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function readJsonFile(path) {
|
|
36
|
+
return JSON.parse(readFileSync(path, 'utf8'));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function listRelativeFiles(root, current = root, acc = []) {
|
|
40
|
+
for (const entry of readdirSync(current, { withFileTypes: true })) {
|
|
41
|
+
const fullPath = join(current, entry.name);
|
|
42
|
+
if (entry.isDirectory()) {
|
|
43
|
+
listRelativeFiles(root, fullPath, acc);
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if (entry.isFile()) {
|
|
47
|
+
acc.push(normalizeRelativePath(fullPath.slice(root.length + 1)));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return acc;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function isExactSemver(value) {
|
|
54
|
+
return EXACT_SEMVER_PATTERN.test(String(value || '').trim());
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function resolveProjectBinEntries(projectPackage, packageName = null) {
|
|
58
|
+
const normalizedPackageName = typeof packageName === 'string' && packageName.trim().length > 0
|
|
59
|
+
? packageName.trim()
|
|
60
|
+
: (typeof projectPackage?.name === 'string' && projectPackage.name.trim().length > 0
|
|
61
|
+
? projectPackage.name.trim()
|
|
62
|
+
: null);
|
|
63
|
+
|
|
64
|
+
if (typeof projectPackage?.bin === 'string' && projectPackage.bin.trim().length > 0) {
|
|
65
|
+
return [{
|
|
66
|
+
name: normalizedPackageName?.split('/').pop() || normalizedPackageName || 'game',
|
|
67
|
+
relativePath: normalizeRelativePath(projectPackage.bin.trim()),
|
|
68
|
+
}];
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return Object.entries(projectPackage?.bin || {})
|
|
72
|
+
.filter(([, value]) => typeof value === 'string' && value.trim().length > 0)
|
|
73
|
+
.map(([name, value]) => ({
|
|
74
|
+
name,
|
|
75
|
+
relativePath: normalizeRelativePath(value.trim()),
|
|
76
|
+
}));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function assertProjectBinIntegrity(
|
|
80
|
+
{
|
|
81
|
+
projectRoot,
|
|
82
|
+
projectPackage = null,
|
|
83
|
+
packageName = null,
|
|
84
|
+
aurajsPackageRoot = DEFAULT_AURAJS_PACKAGE_ROOT,
|
|
85
|
+
expectedAurajsVersion = null,
|
|
86
|
+
enforceExactAurajsDependency = true,
|
|
87
|
+
} = {},
|
|
88
|
+
) {
|
|
89
|
+
const resolvedProjectRoot = resolve(projectRoot || process.cwd());
|
|
90
|
+
const packagePath = resolve(resolvedProjectRoot, 'package.json');
|
|
91
|
+
if (!existsSync(packagePath)) {
|
|
92
|
+
throw new ProjectBinIntegrityError(
|
|
93
|
+
'project_package_json_missing',
|
|
94
|
+
'Project bin integrity check requires a package.json in the current project root.',
|
|
95
|
+
{ packagePath },
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const resolvedProjectPackage = projectPackage || readJsonFile(packagePath);
|
|
100
|
+
const resolvedPackageName = typeof packageName === 'string' && packageName.trim().length > 0
|
|
101
|
+
? packageName.trim()
|
|
102
|
+
: (typeof resolvedProjectPackage?.name === 'string' && resolvedProjectPackage.name.trim().length > 0
|
|
103
|
+
? resolvedProjectPackage.name.trim()
|
|
104
|
+
: null);
|
|
105
|
+
|
|
106
|
+
const dependencySpec = String(resolvedProjectPackage?.dependencies?.['@auraindustry/aurajs'] || '').trim();
|
|
107
|
+
if (!dependencySpec) {
|
|
108
|
+
throw new ProjectBinIntegrityError(
|
|
109
|
+
'project_aurajs_dependency_missing',
|
|
110
|
+
'Published AuraJS games must depend on @auraindustry/aurajs.',
|
|
111
|
+
{ packagePath },
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (enforceExactAurajsDependency && !isExactSemver(dependencySpec)) {
|
|
116
|
+
throw new ProjectBinIntegrityError(
|
|
117
|
+
'project_aurajs_dependency_unpinned',
|
|
118
|
+
'Published AuraJS games must pin @auraindustry/aurajs to an exact version.',
|
|
119
|
+
{
|
|
120
|
+
dependencySpec,
|
|
121
|
+
packagePath,
|
|
122
|
+
},
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (expectedAurajsVersion && dependencySpec !== expectedAurajsVersion) {
|
|
127
|
+
throw new ProjectBinIntegrityError(
|
|
128
|
+
'project_aurajs_dependency_version_mismatch',
|
|
129
|
+
`Expected @auraindustry/aurajs version ${expectedAurajsVersion}, found ${dependencySpec}.`,
|
|
130
|
+
{
|
|
131
|
+
dependencySpec,
|
|
132
|
+
expectedAurajsVersion,
|
|
133
|
+
packagePath,
|
|
134
|
+
},
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const aurajsPackageJsonPath = resolve(aurajsPackageRoot, 'package.json');
|
|
139
|
+
if (!existsSync(aurajsPackageJsonPath)) {
|
|
140
|
+
throw new ProjectBinIntegrityError(
|
|
141
|
+
'project_aurajs_package_missing',
|
|
142
|
+
'Could not resolve the canonical @auraindustry/aurajs package used for bin verification.',
|
|
143
|
+
{ aurajsPackageJsonPath },
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const aurajsPackage = readJsonFile(aurajsPackageJsonPath);
|
|
148
|
+
const resolvedAurajsVersion = String(aurajsPackage?.version || '').trim();
|
|
149
|
+
if (expectedAurajsVersion && resolvedAurajsVersion !== expectedAurajsVersion) {
|
|
150
|
+
throw new ProjectBinIntegrityError(
|
|
151
|
+
'project_aurajs_resolved_version_mismatch',
|
|
152
|
+
`Resolved @auraindustry/aurajs ${resolvedAurajsVersion || '<missing>'}, expected ${expectedAurajsVersion}.`,
|
|
153
|
+
{
|
|
154
|
+
resolvedAurajsVersion,
|
|
155
|
+
expectedAurajsVersion,
|
|
156
|
+
aurajsPackageJsonPath,
|
|
157
|
+
},
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const templatePath = resolve(aurajsPackageRoot, 'templates', 'create-bin', 'play.js');
|
|
162
|
+
if (!existsSync(templatePath)) {
|
|
163
|
+
throw new ProjectBinIntegrityError(
|
|
164
|
+
'project_play_template_missing',
|
|
165
|
+
'Could not find the canonical AuraJS play.js template for bin verification.',
|
|
166
|
+
{ templatePath },
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const canonicalTemplate = normalizeText(readFileSync(templatePath, 'utf8'));
|
|
171
|
+
const canonicalTemplateHash = sha256Text(canonicalTemplate);
|
|
172
|
+
|
|
173
|
+
const binEntries = resolveProjectBinEntries(resolvedProjectPackage, resolvedPackageName);
|
|
174
|
+
if (binEntries.length === 0) {
|
|
175
|
+
throw new ProjectBinIntegrityError(
|
|
176
|
+
'project_bin_missing',
|
|
177
|
+
'Published AuraJS games must declare a generated wrapper entrypoint in package.json -> bin.',
|
|
178
|
+
{ packagePath },
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
for (const entry of binEntries) {
|
|
183
|
+
if (!entry.relativePath.startsWith('bin/')) {
|
|
184
|
+
throw new ProjectBinIntegrityError(
|
|
185
|
+
'project_bin_path_outside_bin_dir',
|
|
186
|
+
`Bin target "${entry.relativePath}" must live under bin/.`,
|
|
187
|
+
{ entry },
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const binDir = resolve(resolvedProjectRoot, 'bin');
|
|
193
|
+
if (!existsSync(binDir)) {
|
|
194
|
+
throw new ProjectBinIntegrityError(
|
|
195
|
+
'project_bin_dir_missing',
|
|
196
|
+
'Published AuraJS games must include a bin/ directory.',
|
|
197
|
+
{ binDir },
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const actualBinFiles = listRelativeFiles(binDir).map((relativePath) => normalizeRelativePath(join('bin', relativePath)));
|
|
202
|
+
const declaredBinPaths = [...new Set(binEntries.map((entry) => entry.relativePath))];
|
|
203
|
+
const declaredBinSet = new Set(declaredBinPaths);
|
|
204
|
+
const unexpectedFiles = actualBinFiles.filter((relativePath) => !declaredBinSet.has(relativePath));
|
|
205
|
+
if (unexpectedFiles.length > 0) {
|
|
206
|
+
throw new ProjectBinIntegrityError(
|
|
207
|
+
'project_bin_unexpected_file',
|
|
208
|
+
`Published AuraJS games may not ship extra bin/ files: ${unexpectedFiles.join(', ')}`,
|
|
209
|
+
{
|
|
210
|
+
declaredBinPaths,
|
|
211
|
+
unexpectedFiles,
|
|
212
|
+
},
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const verifiedFiles = [];
|
|
217
|
+
for (const relativePath of declaredBinPaths) {
|
|
218
|
+
const absolutePath = resolve(resolvedProjectRoot, relativePath);
|
|
219
|
+
if (!existsSync(absolutePath)) {
|
|
220
|
+
throw new ProjectBinIntegrityError(
|
|
221
|
+
'project_bin_target_missing',
|
|
222
|
+
`Bin target "${relativePath}" is missing from the project root.`,
|
|
223
|
+
{
|
|
224
|
+
relativePath,
|
|
225
|
+
absolutePath,
|
|
226
|
+
},
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const fileContent = normalizeText(readFileSync(absolutePath, 'utf8'));
|
|
231
|
+
const fileHash = sha256Text(fileContent);
|
|
232
|
+
if (fileContent !== canonicalTemplate) {
|
|
233
|
+
throw new ProjectBinIntegrityError(
|
|
234
|
+
'project_bin_template_modified',
|
|
235
|
+
`Bin target "${relativePath}" does not match the canonical AuraJS play.js template.`,
|
|
236
|
+
{
|
|
237
|
+
relativePath,
|
|
238
|
+
absolutePath,
|
|
239
|
+
expectedTemplatePath: templatePath,
|
|
240
|
+
expectedTemplateHash: canonicalTemplateHash,
|
|
241
|
+
actualHash: fileHash,
|
|
242
|
+
},
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
verifiedFiles.push({
|
|
247
|
+
relativePath,
|
|
248
|
+
absolutePath,
|
|
249
|
+
hash: fileHash,
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
return {
|
|
254
|
+
reasonCode: 'project_bin_integrity_ok',
|
|
255
|
+
projectRoot: resolvedProjectRoot,
|
|
256
|
+
packagePath,
|
|
257
|
+
packageName: resolvedPackageName,
|
|
258
|
+
aurajsDependency: {
|
|
259
|
+
spec: dependencySpec,
|
|
260
|
+
resolvedVersion: resolvedAurajsVersion,
|
|
261
|
+
packageRoot: aurajsPackageRoot,
|
|
262
|
+
templatePath,
|
|
263
|
+
templateHash: canonicalTemplateHash,
|
|
264
|
+
},
|
|
265
|
+
bin: {
|
|
266
|
+
entries: binEntries,
|
|
267
|
+
declaredFiles: declaredBinPaths,
|
|
268
|
+
actualFiles: actualBinFiles,
|
|
269
|
+
verifiedFiles,
|
|
270
|
+
},
|
|
271
|
+
};
|
|
272
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import {
|
|
2
|
+
copyFileSync,
|
|
3
|
+
existsSync,
|
|
4
|
+
mkdirSync,
|
|
5
|
+
readdirSync,
|
|
6
|
+
readFileSync,
|
|
7
|
+
rmSync,
|
|
8
|
+
statSync,
|
|
9
|
+
} from 'node:fs';
|
|
10
|
+
import { extname, relative, resolve } from 'node:path';
|
|
11
|
+
|
|
12
|
+
import { sha256, toPosix } from './helpers.mjs';
|
|
13
|
+
|
|
14
|
+
export function emitWebAssets({ projectRoot, outRoot }) {
|
|
15
|
+
const sourceRoot = resolve(projectRoot, 'assets');
|
|
16
|
+
const assetsOutRoot = resolve(outRoot, 'assets');
|
|
17
|
+
rmSync(assetsOutRoot, { recursive: true, force: true });
|
|
18
|
+
mkdirSync(assetsOutRoot, { recursive: true });
|
|
19
|
+
|
|
20
|
+
const sourceFiles = collectFiles(sourceRoot);
|
|
21
|
+
const entries = [];
|
|
22
|
+
for (const sourcePath of sourceFiles) {
|
|
23
|
+
const sourceRelative = toPosix(relative(sourceRoot, sourcePath));
|
|
24
|
+
const sourceBytes = readFileSync(sourcePath);
|
|
25
|
+
const contentHash = sha256(sourceBytes);
|
|
26
|
+
const relativeHash = sha256(Buffer.from(sourceRelative, 'utf8')).slice(0, 8);
|
|
27
|
+
const extension = extname(sourceRelative).toLowerCase();
|
|
28
|
+
const stemSource = extension.length > 0
|
|
29
|
+
? sourceRelative.slice(0, sourceRelative.length - extension.length)
|
|
30
|
+
: sourceRelative;
|
|
31
|
+
const stem = sanitizeAssetStem(stemSource);
|
|
32
|
+
const outputName = `${stem}.${relativeHash}.${contentHash.slice(0, 12)}${extension}`;
|
|
33
|
+
const outputPath = resolve(assetsOutRoot, outputName);
|
|
34
|
+
|
|
35
|
+
copyFileSync(sourcePath, outputPath);
|
|
36
|
+
entries.push({
|
|
37
|
+
path: `assets/${outputName}`,
|
|
38
|
+
sourcePath: sourceRelative,
|
|
39
|
+
bytes: sourceBytes.length,
|
|
40
|
+
sha256: contentHash,
|
|
41
|
+
mediaType: mediaTypeForExtension(extension),
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
entries.sort((a, b) => a.path.localeCompare(b.path));
|
|
46
|
+
removeUnexpectedFiles(assetsOutRoot, new Set(entries.map((entry) => entry.path.slice('assets/'.length))));
|
|
47
|
+
return { entries, assetsOutRoot };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function collectFiles(rootPath) {
|
|
51
|
+
if (!existsSync(rootPath)) {
|
|
52
|
+
return [];
|
|
53
|
+
}
|
|
54
|
+
const output = [];
|
|
55
|
+
walkFiles(rootPath, output);
|
|
56
|
+
output.sort((a, b) => toPosix(a).localeCompare(toPosix(b)));
|
|
57
|
+
return output;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function walkFiles(dirPath, output) {
|
|
61
|
+
const names = readdirSync(dirPath).sort((a, b) => a.localeCompare(b));
|
|
62
|
+
for (const name of names) {
|
|
63
|
+
const fullPath = resolve(dirPath, name);
|
|
64
|
+
const stat = statSync(fullPath);
|
|
65
|
+
if (stat.isDirectory()) {
|
|
66
|
+
walkFiles(fullPath, output);
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
output.push(fullPath);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function sanitizeAssetStem(value) {
|
|
74
|
+
const normalized = String(value || '')
|
|
75
|
+
.replace(/[\\/]+/g, '-')
|
|
76
|
+
.replace(/[^A-Za-z0-9._-]+/g, '-')
|
|
77
|
+
.replace(/-+/g, '-')
|
|
78
|
+
.replace(/^[-._]+|[-._]+$/g, '');
|
|
79
|
+
return normalized.length > 0 ? normalized : 'asset';
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function mediaTypeForExtension(extension) {
|
|
83
|
+
switch (extension) {
|
|
84
|
+
case '.png':
|
|
85
|
+
return 'image/png';
|
|
86
|
+
case '.jpg':
|
|
87
|
+
case '.jpeg':
|
|
88
|
+
return 'image/jpeg';
|
|
89
|
+
case '.gif':
|
|
90
|
+
return 'image/gif';
|
|
91
|
+
case '.webp':
|
|
92
|
+
return 'image/webp';
|
|
93
|
+
case '.wav':
|
|
94
|
+
return 'audio/wav';
|
|
95
|
+
case '.ogg':
|
|
96
|
+
return 'audio/ogg';
|
|
97
|
+
case '.mp3':
|
|
98
|
+
return 'audio/mpeg';
|
|
99
|
+
case '.mp4':
|
|
100
|
+
return 'video/mp4';
|
|
101
|
+
case '.ttf':
|
|
102
|
+
return 'font/ttf';
|
|
103
|
+
case '.otf':
|
|
104
|
+
return 'font/otf';
|
|
105
|
+
case '.woff':
|
|
106
|
+
return 'font/woff';
|
|
107
|
+
case '.woff2':
|
|
108
|
+
return 'font/woff2';
|
|
109
|
+
case '.json':
|
|
110
|
+
return 'application/json';
|
|
111
|
+
case '.txt':
|
|
112
|
+
case '.md':
|
|
113
|
+
case '.csv':
|
|
114
|
+
return 'text/plain; charset=utf-8';
|
|
115
|
+
default:
|
|
116
|
+
return 'application/octet-stream';
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function removeUnexpectedFiles(rootPath, allowedNames) {
|
|
121
|
+
if (!existsSync(rootPath)) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
for (const name of readdirSync(rootPath)) {
|
|
125
|
+
if (allowedNames.has(name)) {
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
rmSync(resolve(rootPath, name), { recursive: true, force: true });
|
|
129
|
+
}
|
|
130
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
PROJECT_CAPABILITY_DECLARATION_FILE,
|
|
6
|
+
WEB_CAPABILITY_DECLARATION_SCHEMA,
|
|
7
|
+
WEB_RUNTIME_CONFIG_SCHEMA,
|
|
8
|
+
} from './constants.mjs';
|
|
9
|
+
import { normalizePositiveInt } from './helpers.mjs';
|
|
10
|
+
|
|
11
|
+
export function buildRuntimeConfig(options = {}) {
|
|
12
|
+
const windowConfig = options.windowConfig && typeof options.windowConfig === 'object'
|
|
13
|
+
? options.windowConfig
|
|
14
|
+
: {};
|
|
15
|
+
const modules = options.modules && typeof options.modules === 'object'
|
|
16
|
+
? options.modules
|
|
17
|
+
: {};
|
|
18
|
+
const capabilityDeclaration = normalizeWebCapabilityDeclaration(
|
|
19
|
+
options.capabilityDeclaration,
|
|
20
|
+
normalizeOptionalModules(modules),
|
|
21
|
+
options.capabilityDeclaration && typeof options.capabilityDeclaration === 'object'
|
|
22
|
+
? options.capabilityDeclaration.source || null
|
|
23
|
+
: null,
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
return {
|
|
27
|
+
schema: WEB_RUNTIME_CONFIG_SCHEMA,
|
|
28
|
+
schemaVersion: '1.0.0',
|
|
29
|
+
canvas: {
|
|
30
|
+
id: 'aura-canvas',
|
|
31
|
+
resizeMode: 'fit-container',
|
|
32
|
+
width: normalizePositiveInt(windowConfig.width, 1280),
|
|
33
|
+
height: normalizePositiveInt(windowConfig.height, 720),
|
|
34
|
+
devicePixelRatioMode: 'clamped',
|
|
35
|
+
},
|
|
36
|
+
loop: {
|
|
37
|
+
tickMode: 'raf',
|
|
38
|
+
maxDeltaMs: 50,
|
|
39
|
+
},
|
|
40
|
+
modules: {
|
|
41
|
+
physics: modules.physics === true,
|
|
42
|
+
network: modules.network === true,
|
|
43
|
+
multiplayer: modules.multiplayer === true,
|
|
44
|
+
},
|
|
45
|
+
capabilities: capabilityDeclaration,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function normalizeRequiredApis(entries) {
|
|
50
|
+
if (!Array.isArray(entries)) {
|
|
51
|
+
return [];
|
|
52
|
+
}
|
|
53
|
+
return [...new Set(entries
|
|
54
|
+
.filter((entry) => typeof entry === 'string')
|
|
55
|
+
.map((entry) => entry.trim())
|
|
56
|
+
.filter(Boolean))]
|
|
57
|
+
.sort((a, b) => a.localeCompare(b));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function normalizeOptionalModules(modules) {
|
|
61
|
+
const source = modules && typeof modules === 'object' ? modules : {};
|
|
62
|
+
return {
|
|
63
|
+
physics: source.physics === true,
|
|
64
|
+
network: source.network === true || source.net === true,
|
|
65
|
+
multiplayer: source.multiplayer === true,
|
|
66
|
+
steam: source.steam === true,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function normalizeWebCapabilityDeclaration(value, baseModules = {}, source = null) {
|
|
71
|
+
const declaration = value && typeof value === 'object' && !Array.isArray(value)
|
|
72
|
+
? value
|
|
73
|
+
: {};
|
|
74
|
+
if (
|
|
75
|
+
declaration.schema != null
|
|
76
|
+
&& declaration.schema !== 'aurajs.create-capabilities.v1'
|
|
77
|
+
&& declaration.schema !== 'aurajs.capability-declaration.v1'
|
|
78
|
+
&& declaration.schema !== WEB_CAPABILITY_DECLARATION_SCHEMA
|
|
79
|
+
) {
|
|
80
|
+
throw new Error(
|
|
81
|
+
`${source || 'Capability declaration'} must use `
|
|
82
|
+
+ '`aurajs.create-capabilities.v1`, `aurajs.capability-declaration.v1`, '
|
|
83
|
+
+ `or \`${WEB_CAPABILITY_DECLARATION_SCHEMA}\`.`,
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const declaredModules = normalizeOptionalModules(declaration.optionalModules);
|
|
88
|
+
return {
|
|
89
|
+
schema: WEB_CAPABILITY_DECLARATION_SCHEMA,
|
|
90
|
+
source,
|
|
91
|
+
requiredApis: normalizeRequiredApis(declaration.requiredApis),
|
|
92
|
+
optionalModules: {
|
|
93
|
+
physics: baseModules.physics || declaredModules.physics,
|
|
94
|
+
network: baseModules.network || declaredModules.network,
|
|
95
|
+
multiplayer: baseModules.multiplayer || declaredModules.multiplayer,
|
|
96
|
+
steam: baseModules.steam || declaredModules.steam,
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function readProjectCapabilityDeclaration({ projectRoot, modules }) {
|
|
102
|
+
const declarationPath = resolve(projectRoot, PROJECT_CAPABILITY_DECLARATION_FILE);
|
|
103
|
+
const baseModules = normalizeOptionalModules(modules);
|
|
104
|
+
if (!existsSync(declarationPath)) {
|
|
105
|
+
return normalizeWebCapabilityDeclaration({}, baseModules, null);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
let parsed;
|
|
109
|
+
try {
|
|
110
|
+
parsed = JSON.parse(readFileSync(declarationPath, 'utf8'));
|
|
111
|
+
} catch (error) {
|
|
112
|
+
throw new Error(`Failed to parse ${PROJECT_CAPABILITY_DECLARATION_FILE}: ${error.message}`);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return normalizeWebCapabilityDeclaration(parsed, baseModules, PROJECT_CAPABILITY_DECLARATION_FILE);
|
|
116
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export const BUILD_MANIFEST_SCHEMA = 'aurajs.build-manifest.v1';
|
|
2
|
+
export const WEB_BUILD_MANIFEST_SCHEMA = 'aurajs.web-build-manifest.v1';
|
|
3
|
+
export const WEB_RUNTIME_CONFIG_SCHEMA = 'aurajs.web-runtime-config.v1';
|
|
4
|
+
export const WEB_CAPABILITY_DECLARATION_SCHEMA = 'aurajs.web-capability-declaration.v1';
|
|
5
|
+
|
|
6
|
+
export const PROJECT_CAPABILITY_DECLARATION_FILE = 'aura.capabilities.json';
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { writeFileSync } from 'node:fs';
|
|
3
|
+
import { relative, resolve, sep } from 'node:path';
|
|
4
|
+
|
|
5
|
+
export function resolveRequiredPath(pathLike, fieldName) {
|
|
6
|
+
if (typeof pathLike !== 'string' || pathLike.length === 0) {
|
|
7
|
+
throw new Error(`build contract requires a non-empty "${fieldName}" path.`);
|
|
8
|
+
}
|
|
9
|
+
return resolve(pathLike);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function normalizeAssetMode(value) {
|
|
13
|
+
if (value !== 'embed' && value !== 'sibling') {
|
|
14
|
+
throw new Error(`unsupported asset mode "${value}" for build contract.`);
|
|
15
|
+
}
|
|
16
|
+
return value;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function toPosix(input) {
|
|
20
|
+
return input.split(sep).join('/');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function resolveOptionalRelative(outRoot, pathLike) {
|
|
24
|
+
if (typeof pathLike !== 'string' || pathLike.length === 0) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
return toPosix(relative(outRoot, resolve(pathLike)));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function normalizePositiveInt(value, fallback) {
|
|
31
|
+
if (!Number.isFinite(value)) {
|
|
32
|
+
return fallback;
|
|
33
|
+
}
|
|
34
|
+
const normalized = Math.floor(value);
|
|
35
|
+
return normalized > 0 ? normalized : fallback;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function writeCanonicalJsonFile(path, value) {
|
|
39
|
+
writeFileSync(path, `${JSON.stringify(value, null, 2)}\n`, 'utf8');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function sha256(value) {
|
|
43
|
+
return createHash('sha256').update(value).digest('hex');
|
|
44
|
+
}
|