src/cli/commands/bootstrap
declarative-hex-worlds / src/cli/commands/bootstrap
src/cli/commands/bootstrap
src/cli/commands/bootstrap/ — the bootstrap CLI command + its runtime
asset-bootstrap implementation.
Remarks
Bootstrap is a CLI-domain capability (reachable only from src/cli/), not a
runtime-library domain — the umbrella does not re-export it. The published
npm tarball does NOT ship KayKit GLTF binaries; consumers run the CLI
bootstrap subcommand (or call bootstrapKayKitAssets directly via the
./bootstrap subpath) after install to materialize the asset tree under
their app's asset root. Two source modes are supported:
{ kind: 'github' }— downloads the upstream GitHub tarball viahttps(CC0 FREE edition only).{ kind: 'zip', path }— extracts a user-supplied zip on disk (works for both FREE and the EXTRA edition purchased on itch.io).
Both modes mirror only the .gltf + .bin + texture files (unless
includeSourceFormats is set), preserving the upstream Assets/gltf/
directory structure under
<out>/addons/kaykit_medieval_hexagon_pack/Assets/gltf/. A
.bootstrap.json integrity sidecar is written alongside, recording per-file
SHA-256 hashes plus provenance. verifyBootstrap re-hashes a
bootstrapped tree and reports drift.
Interfaces
BootstrapFileEntry
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/core.ts:154
Per-file entry in the integrity sidecar.
Properties
bytes
readonlybytes:number
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/core.ts:160
Byte length of the file at fetch time.
path
readonlypath:string
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/core.ts:156
POSIX path relative to <out>/addons/kaykit_medieval_hexagon_pack/.
sha256
readonlysha256:string
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/core.ts:158
SHA-256 hash of the file's contents, lowercase hex.
BootstrapKayKitAssetsOptions
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/core.ts:95
Inputs to bootstrapKayKitAssets.
Properties
edition?
readonlyoptionaledition?:"free"|"extra"
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/core.ts:104
Pack edition (default free). extra requires source.kind === 'zip'.
fetchedAt?
readonlyoptionalfetchedAt?:string
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/core.ts:125
Reproducible timestamp written into the integrity sidecar. Default
new Date().toISOString().
force?
readonlyoptionalforce?:boolean
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/core.ts:110
When true, the destination is wiped before mirroring. When false (default), an existing non-empty target throws unless its sidecar matches the requested edition.
githubSource?
readonlyoptionalgithubSource?:object
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/core.ts:143
GitHub archive source for the pack (RFC0-10). Defaults to the KayKit
Medieval Hexagon repo. Pass a pack descriptor's github to fetch a different
pack's archive. Only used when source.kind === 'github'.
archiveUrlTemplate
readonlyarchiveUrlTemplate:string
defaultRef
readonlydefaultRef:string
owner
readonlyowner:string
repo
readonlyrepo:string
includeSourceFormats?
readonlyoptionalincludeSourceFormats?:boolean
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/core.ts:115
Include .fbx, .fbx(unity), .obj, .mtl files. Default false —
only .gltf, .bin, and PNG textures are mirrored.
layout?
readonlyoptionallayout?:KayKitUpstreamLayout
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/core.ts:137
Target upstream layout (RFC0-10). Defaults to the edition-derived KayKit
Medieval Hexagon layout. Pass a characterPackLayout(...) to bootstrap a
character pack (Adventurers/Skeletons) instead. When set, detection and
mirroring use THIS layout rather than the medieval-hexagon detection list.
libraryVersion?
readonlyoptionallibraryVersion?:string
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/core.ts:130
Override for the integrity sidecar's libraryVersion field. Defaults to
the value resolved from the closest package.json.
out
readonlyout:string
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/core.ts:102
Consumer's asset root. The bootstrap step writes
<out>/addons/kaykit_medieval_hexagon_pack/... under this folder.
outRoot?
readonlyoptionaloutRoot?:string
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/core.ts:120
Optional jail root for out resolution. Defaults to process.cwd().
The bootstrap function refuses to write outside this root.
source
readonlysource:BootstrapKayKitAssetsSource
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/core.ts:97
Where to fetch the upstream source tree from.
BootstrapPackOptions
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/pack-bootstrap.ts:51
Options for bootstrapPack.
Properties
fetchedAt?
readonlyoptionalfetchedAt?:string
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/pack-bootstrap.ts:65
Reproducible sidecar timestamp (tests).
force?
readonlyoptionalforce?:boolean
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/pack-bootstrap.ts:63
Overwrite an existing non-empty target.
libraryVersion?
readonlyoptionallibraryVersion?:string
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/pack-bootstrap.ts:67
Sidecar library-version override (tests).
outRoot?
readonlyoptionaloutRoot?:string
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/pack-bootstrap.ts:59
Jail root for path resolution (defaults to cwd inside core).
rawAssetsRoot
readonlyrawAssetsRoot:string
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/pack-bootstrap.ts:57
Gitignored raw-assets ROOT. The pack materializes into
<rawAssetsRoot>/<packId>/ — the id subdir is appended internally so the
write location always matches resolveDefaultPackKit/assertPackPresent.
ref?
readonlyoptionalref?:string
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/pack-bootstrap.ts:61
Git ref to fetch (defaults to the descriptor's default ref).
BootstrapResult
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/core.ts:185
Return value of bootstrapKayKitAssets.
Properties
edition
readonlyedition:"free"|"extra"
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/core.ts:187
Pack edition that was bootstrapped.
fileCount
readonlyfileCount:number
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/core.ts:191
Total number of files written (gltf + bin + textures + any extras).
integritySidecar
readonlyintegritySidecar:string
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/core.ts:195
Absolute path of the integrity sidecar.
outRoot
readonlyoutRoot:string
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/core.ts:189
Absolute path of the bootstrap target root.
totalBytes
readonlytotalBytes:number
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/core.ts:193
Sum of BootstrapFileEntry.bytes.
BootstrapSidecar
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/core.ts:167
Integrity sidecar serialized as .bootstrap.json inside each bootstrap
target.
Properties
edition
readonlyedition:"free"|"extra"
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/core.ts:171
Pack edition this target was bootstrapped for.
fetchedAt
readonlyfetchedAt:string
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/core.ts:177
ISO-8601 timestamp at which the bootstrap was performed.
files
readonlyfiles: readonlyBootstrapFileEntry[]
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/core.ts:179
Sorted list of every mirrored file plus its SHA-256.
libraryVersion
readonlylibraryVersion:string
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/core.ts:173
Library version that produced this bootstrap.
schemaVersion
readonlyschemaVersion:"1.0.0"
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/core.ts:169
Sidecar schema version.
sourceUrl
readonlysourceUrl:string
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/core.ts:175
Provenance URL (https://...) or file:// URL for zip-sourced bootstraps.
BootstrapVerificationReport
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/core.ts:201
Verification report returned by verifyBootstrap.
Properties
drift
readonlydrift: readonlystring[]
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/core.ts:205
Human-readable descriptions of any drift discovered.
ok
readonlyok:boolean
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/core.ts:203
True when every recorded file matches its expected hash and length.
sidecarPath
readonlysidecarPath:string
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/core.ts:207
Sidecar that was checked.
PackResolution
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/pack-bootstrap.ts:104
A pack's default-resolution status against a raw-assets root.
Properties
dir
readonlydir:string
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/pack-bootstrap.ts:108
Absolute directory the pack resolves to (whether or not it's present).
id
readonlyid:"medieval-hexagon"|"adventurers"|"skeletons"
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/pack-bootstrap.ts:106
Pack id.
present
readonlypresent:boolean
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/pack-bootstrap.ts:110
True when the pack is materialized there.
Type Aliases
BootstrapKayKitAssetsSource
BootstrapKayKitAssetsSource = {
commit?:string;kind:"github"; } | {kind:"zip";path:string; }
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/core.ts:78
Source descriptor for BootstrapKayKitAssetsOptions. Discriminates between fetching from the upstream GitHub repo and extracting a locally cached zip archive.
Union Members
Type Literal
{ commit?: string; kind: "github"; }
commit?
readonlyoptionalcommit?:string
Optional git ref (commit / tag / branch). Defaults to KAYKIT_FREE_GITHUB_DEFAULT_REF.
kind
readonlykind:"github"
Source kind discriminator selecting the upstream-GitHub tarball path.
Type Literal
{ kind: "zip"; path: string; }
kind
readonlykind:"zip"
Source kind discriminator selecting the local-zip extraction path.
path
readonlypath:string
Filesystem path of the locally cached pack zip.
PackCategory
PackCategory = typeof
PACK_CATEGORIES[number]
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/registry.ts:38
Gameplay category a pack fills.
PackDescriptor
PackDescriptor =
z.infer<typeofpackDescriptorSchema>
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/registry.ts:75
A downloadable-pack descriptor.
PackGithubSource
PackGithubSource =
z.infer<typeofpackGithubSourceSchema>
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/registry.ts:55
Upstream GitHub source descriptor.
PackId
PackId = typeof
PACK_IDS[number]
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/registry.ts:25
One of the recognized downloadable pack ids.
PackRole
PackRole = typeof
PACK_ROLES[number]
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/registry.ts:30
Asset role a pack contributes (tiles vs models).
Variables
KAYKIT_BOOTSTRAP_GLTF_RELATIVE
constKAYKIT_BOOTSTRAP_GLTF_RELATIVE:string=BOOTSTRAP_PATHS.gltfRelative
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/target.ts:14
Sub-folder under the consumer's asset root holding the mirrored GLTF tree. Empty string means GLTFs land directly in the asset root (flat layout).
KAYKIT_BOOTSTRAP_SIDECAR
constKAYKIT_BOOTSTRAP_SIDECAR:string=BOOTSTRAP_PATHS.sidecarFileName
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/target.ts:24
Filename of the integrity sidecar written into each bootstrap target.
KAYKIT_BOOTSTRAP_TEXTURE_RELATIVE
constKAYKIT_BOOTSTRAP_TEXTURE_RELATIVE:string=BOOTSTRAP_PATHS.textureRelative
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/target.ts:19
Sub-folder under the consumer's asset root holding mirrored shared textures.
KAYKIT_FREE_GITHUB_DEFAULT_REF
constKAYKIT_FREE_GITHUB_DEFAULT_REF:string=KAYKIT_SOURCE.github.defaultRef
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/core.ts:71
Default git ref the bootstrap CLI fetches when no --commit is supplied.
KAYKIT_FREE_GITHUB_OWNER
constKAYKIT_FREE_GITHUB_OWNER:string=KAYKIT_SOURCE.github.owner
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/core.ts:60
Canonical GitHub organization holding the FREE edition source tree.
KAYKIT_FREE_GITHUB_REPO
constKAYKIT_FREE_GITHUB_REPO:string=KAYKIT_SOURCE.github.repo
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/core.ts:66
Canonical GitHub repository name for the FREE edition (the repo at
KayKit-Game-Assets/KayKit-Medieval-Hexagon-Pack-1.0).
PACK_CATEGORIES
constPACK_CATEGORIES: readonly ["terrain","playable","enemy"]
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/registry.ts:36
Gameplay category a pack fills — drives default source composition (terrain board vs playable units vs enemies) so three packs compose into a full game.
PACK_IDS
constPACK_IDS: readonly ["medieval-hexagon","adventurers","skeletons"]
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/registry.ts:23
A stable pack identifier used by the CLI (bootstrap --pack <id>) and resolution.
PACK_REGISTRY
constPACK_REGISTRY:Readonly<Record<PackId,PackDescriptor>>
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/registry.ts:86
The three first-class downloadable CC0 packs. Together they are a full game from defaults: a hex tile board, playable characters, and enemies. GitHub reports these repos as NOASSERTION (no machine-readable LICENSE), but KayKit's itch.io pages license the packs CC0; the attribution is a courtesy credit.
PACK_ROLES
constPACK_ROLES: readonly ["tile","model"]
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/registry.ts:28
How a pack's assets map into an AssetSource role.
packDescriptorSchema
constpackDescriptorSchema:ZodObject<{attribution:ZodString;category:ZodEnum<{enemy:"enemy";playable:"playable";terrain:"terrain"; }>;displayName:ZodString;github:ZodObject<{archiveUrlTemplate:ZodString;defaultRef:ZodString;owner:ZodString;repo:ZodString; },$strip>;id:ZodEnum<{adventurers:"adventurers";medieval-hexagon:"medieval-hexagon";skeletons:"skeletons"; }>;packFolder:ZodString;role:ZodEnum<{model:"model";tile:"tile"; }>; },$strip>
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/registry.ts:58
A single downloadable-pack descriptor.
packGithubSourceSchema
constpackGithubSourceSchema:ZodObject<{archiveUrlTemplate:ZodString;defaultRef:ZodString;owner:ZodString;repo:ZodString; },$strip>
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/registry.ts:41
Upstream GitHub source for a pack's CC0 archive.
Functions
assertPackPresent()
assertPackPresent(
id,rawAssetsRoot):string
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/pack-bootstrap.ts:132
Assert a pack is materialized at <rawAssetsRoot>/<packId>, or throw a clear
error naming the pack + the exact command to fetch it. This is the
"absent → clear error" half of default source resolution (RFC0-10).
Parameters
id
string
rawAssetsRoot
string
Returns
string
bootstrapKayKitAssets()
bootstrapKayKitAssets(
options):Promise<BootstrapResult>
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/core.ts:218
Materialize the KayKit asset tree under the consumer's asset root.
Parameters
options
Returns
Promise<BootstrapResult>
bootstrapPack()
bootstrapPack(
id,options):Promise<BootstrapResult>
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/pack-bootstrap.ts:76
Fetch a registered pack by id from its upstream GitHub archive into
<rawAssetsRoot>/<packId>/. Throws a clear error for an unknown pack id (via
packDescriptor). The per-pack subdir is computed here (not caller-chosen)
so the fetched pack is always locatable by the default-source resolvers.
Parameters
id
string
options
Returns
Promise<BootstrapResult>
detectDefaultBootstrapOut()
detectDefaultBootstrapOut():
string
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/index.ts:141
Default --out heuristic. Prefers existing models (flat bootstrap
default), then public/models (Vite / Next.js public dir convention), then
falls back to models. Cosmetic only: every call still routes through
safeResolveOutput.
Returns
string
formatBytes()
formatBytes(
value):string
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/index.ts:170
Parameters
value
number
Returns
string
isPackId()
isPackId(
value): value is "medieval-hexagon" | "adventurers" | "skeletons"
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/registry.ts:132
True if value names a registered pack (proto-safe — used on external input).
Parameters
value
string
Returns
value is "medieval-hexagon" | "adventurers" | "skeletons"
isPackMaterialized()
isPackMaterialized(
id,rawAssetsRoot):boolean
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/pack-bootstrap.ts:99
Whether a pack is materialized at <rawAssetsRoot>/<packId> (sidecar present).
Validates the id at runtime (not just by the PackId type) so an external
caller passing an unknown/hostile id gets a clear error, never a stray path.
Parameters
id
string
rawAssetsRoot
string
Returns
boolean
kayKitFreeGithubTarballUrl()
kayKitFreeGithubTarballUrl(
commit?):string
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/core.ts:349
Format the canonical GitHub source-archive zip URL for a given ref (or
main when unset). GitHub serves a stable, never-changing archive at
/archive/refs/heads/<ref>.zip, so bootstrap downloads it and feeds the
exact same local-zip extraction flow as a user-supplied archive — no tarball
decompression and no git dependency.
Parameters
commit?
string
Returns
string
layoutForPack()
layoutForPack(
descriptor):KayKitUpstreamLayout
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/pack-bootstrap.ts:32
Resolve the upstream layout for a pack descriptor. terrain packs use the
medieval-hexagon layout (FREE edition); playable/enemy character packs use
the flat character-pack layout keyed by the descriptor's addons/ folder.
Parameters
descriptor
attribution
string = ...
Attribution string (CC0 — no attribution required, but credited by courtesy).
category
"enemy" | "terrain" | "playable" = ...
Gameplay category the pack fills.
displayName
string = ...
Human-facing name for CLI listings + docs.
github
{ archiveUrlTemplate: string; defaultRef: string; owner: string; repo: string; } = packGithubSourceSchema
Upstream GitHub source.
github.archiveUrlTemplate
string = ...
Archive-URL template with {owner}/{repo}/{ref} placeholders. Kept per
descriptor (not global) so a pack hosted differently can override it.
github.defaultRef
string = ...
Default git ref fetched when none is supplied.
github.owner
string = ...
GitHub owner/org.
github.repo
string = ...
Repository name.
id
"medieval-hexagon" | "adventurers" | "skeletons" = ...
Stable pack id.
packFolder
string = ...
Upstream addons/<packFolder>/ directory name the pack publishes under.
role
"tile" | "model" = ...
Asset role the pack contributes.
Returns
listPackDescriptors()
listPackDescriptors(): readonly
object[]
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/registry.ts:149
Every pack descriptor, in registry order.
Returns
readonly object[]
packArchiveUrl()
packArchiveUrl(
descriptor,ref?):string
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/registry.ts:154
Format a pack's upstream archive URL for a given ref (or its default ref).
Parameters
descriptor
attribution
string = ...
Attribution string (CC0 — no attribution required, but credited by courtesy).
category
"enemy" | "terrain" | "playable" = ...
Gameplay category the pack fills.
displayName
string = ...
Human-facing name for CLI listings + docs.
github
{ archiveUrlTemplate: string; defaultRef: string; owner: string; repo: string; } = packGithubSourceSchema
Upstream GitHub source.
github.archiveUrlTemplate
string = ...
Archive-URL template with {owner}/{repo}/{ref} placeholders. Kept per
descriptor (not global) so a pack hosted differently can override it.
github.defaultRef
string = ...
Default git ref fetched when none is supplied.
github.owner
string = ...
GitHub owner/org.
github.repo
string = ...
Repository name.
id
"medieval-hexagon" | "adventurers" | "skeletons" = ...
Stable pack id.
packFolder
string = ...
Upstream addons/<packFolder>/ directory name the pack publishes under.
role
"tile" | "model" = ...
Asset role the pack contributes.
ref?
string
Returns
string
packDescriptor()
packDescriptor(
id):object
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/registry.ts:141
Look up a pack descriptor by id, or throw a clear error listing the valid ids.
Uses Object.hasOwn so an id equal to an Object.prototype member can't
return an inherited value.
Parameters
id
string
Returns
attribution
attribution:
string
Attribution string (CC0 — no attribution required, but credited by courtesy).
category
category:
"enemy"|"terrain"|"playable"
Gameplay category the pack fills.
displayName
displayName:
string
Human-facing name for CLI listings + docs.
github
github:
object=packGithubSourceSchema
Upstream GitHub source.
github.archiveUrlTemplate
archiveUrlTemplate:
string
Archive-URL template with {owner}/{repo}/{ref} placeholders. Kept per
descriptor (not global) so a pack hosted differently can override it.
github.defaultRef
defaultRef:
string
Default git ref fetched when none is supplied.
github.owner
owner:
string
GitHub owner/org.
github.repo
repo:
string
Repository name.
id
id:
"medieval-hexagon"|"adventurers"|"skeletons"
Stable pack id.
packFolder
packFolder:
string
Upstream addons/<packFolder>/ directory name the pack publishes under.
role
role:
"tile"|"model"
Asset role the pack contributes.
packDir()
packDir(
rawAssetsRoot,id):string
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/pack-bootstrap.ts:46
The single source of truth for where a pack lives under a raw-assets root:
<rawAssetsRoot>/<packId>/. bootstrapPack WRITES here and the default-source
resolvers READ here, so a pack fetched by the CLI is always found by
resolveDefaultPackKit/assertPackPresent — the convention can't diverge.
Uses the validated descriptor.id (never a raw caller string) in the join.
Parameters
rawAssetsRoot
string
id
string
Returns
string
printBootstrapResult()
printBootstrapResult(
result):void
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/index.ts:152
Parameters
result
Returns
void
printBootstrapVerifyReport()
printBootstrapVerifyReport(
report):void
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/index.ts:159
Parameters
report
Returns
void
registeredPackClassifiers()
registeredPackClassifiers(): readonly
PlacementClassifier[]
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/pack-bootstrap.ts:157
The recognized-pack PlacementClassifiers (RFC0-TAGb): one per registered
pack, mapping each pack's registry category to its default gameplay classifiers
(Adventurers → playable, Skeletons → enemy/random-encounter; terrain packs
contribute none). Compose these ON TOP of DEFAULT_PLACEMENT_CLASSIFIERS so a
placement sourced from a recognized pack is auto-classified:
const classifiers = [...DEFAULT_PLACEMENT_CLASSIFIERS, ...registeredPackClassifiers()];
classifyPlacement(placement, classifiers);Returns
readonly PlacementClassifier[]
resolveBootstrapGltfRoot()
resolveBootstrapGltfRoot(
assetRoot):string
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/target.ts:30
Resolve the absolute path to a bootstrap target's GLTF tree root. With the flat layout (gltfRelative = ""), this is the asset root itself.
Parameters
assetRoot
string
Returns
string
resolveBootstrapSidecarPath()
resolveBootstrapSidecarPath(
assetRoot):string
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/target.ts:40
Resolve the absolute path to a bootstrap target's integrity sidecar.
Parameters
assetRoot
string
Returns
string
resolveDefaultPackKit()
resolveDefaultPackKit(
rawAssetsRoot): readonlyPackResolution[]
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/pack-bootstrap.ts:119
Resolve every registered pack against a raw-assets root, reporting which are
present and which are missing. An app composes its default game from the
present packs; assertPackPresent turns a missing required pack into a
clear, actionable error. Convention: each pack lives at <root>/<packId>/.
Parameters
rawAssetsRoot
string
Returns
readonly PackResolution[]
runBootstrap()
runBootstrap(
parsed,edition):Promise<void>
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/index.ts:61
Parameters
parsed
ParsedArgs
edition
"free" | "extra"
Returns
Promise<void>
verifyBootstrap()
verifyBootstrap(
outRoot):Promise<BootstrapVerificationReport>
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/core.ts:299
Re-hash every file recorded in an integrity sidecar and report drift.
Parameters
outRoot
string
Returns
Promise<BootstrapVerificationReport>
zipEntryEscapesRoot()
zipEntryEscapesRoot(
entryPath):boolean
Defined in: packages/declarative-hex-worlds/src/cli/commands/bootstrap/core.ts:917
True when a zip entry name is unsafe to extract — it would escape the destination directory, or is malformed in a way that makes containment platform-dependent (zip-slip, CWE-22).
Parameters
entryPath
string
Returns
boolean
Remarks
Judged entirely on the RAW entry name, never on a join()-ed path. That is the
whole point: join() normalizes both escape shapes back INSIDE the target, so a
post-join() test silently passes them.
join('/root', '/etc/passwd')is'/root/etc/passwd'— a leading separator is treated as root-relative, soisAbsolute()on the joined path can never fire. A Windows drive prefix (C:\...) is matched explicitly, sinceisAbsolute()is platform-dependent and returns false for it on POSIX.- A backslash is a legal filename character on POSIX but a SEPARATOR on Windows,
so
join()/relative()on POSIX seea\..\..\etcas one opaque segment and find no traversal — while the same archive extracted on Windows escapes. Splitting the raw name on BOTH separators makes the verdict independent of where extraction runs. The zip spec (APPNOTE 4.4.17) mandates forward slashes, so a backslash is malformed regardless.
Traversal is detected per SEGMENT, not with a startsWith('..') prefix test —
the latter also rejects legitimate names that merely begin with two dots
(..foo/x, .../x, ...), which an asset pack may legally contain.
A .. segment is rejected even when it would resolve back inside the root
(a/../b). Deliberate: it matches yauzl's rule exactly, so the two layers agree
on what a valid entry name is rather than subtly diverging.
yauzl's own validateFileName already refuses every one of these before an
entry event fires, so in practice this is defense in depth. It is exported so
its contract can be tested directly — an end-to-end assertion cannot distinguish
this guard working from yauzl covering for it.
References
characterPackLayout
Re-exports characterPackLayout
detectKayKitLayout
Re-exports detectKayKitLayout
detectLayoutFrom
Re-exports detectLayoutFrom
expectedTexturePaths
Re-exports expectedTexturePaths
KAYKIT_MEDIEVAL_EXTRA_LAYOUT
Re-exports KAYKIT_MEDIEVAL_EXTRA_LAYOUT
KAYKIT_MEDIEVAL_FREE_LAYOUT
Re-exports KAYKIT_MEDIEVAL_FREE_LAYOUT
KAYKIT_UPSTREAM_LAYOUTS
Re-exports KAYKIT_UPSTREAM_LAYOUTS
kayKitLayoutForEdition
Re-exports kayKitLayoutForEdition
KayKitUpstreamLayout
Re-exports KayKitUpstreamLayout
