# Scalar bundled-asset registry _(no submodules)_ ## Purpose The assets module owns the in-package bundled Scalar runtime that ships with the package — a small self-contained JS bootstrap and a tiny companion stylesheet — plus the asset-URL resolver consumed by the handler factory. Air-gapped hosts toggle `assetMode = "bundled"` and the shell loads JS / CSS from `/assets/.`; hosts on the public internet toggle `assetMode = "cdn"` and the shell loads the upstream `@scalar/api-reference` bundle from JSDelivr. Either way the shell embeds the bootstrap config block at render time so the runtime target is fixed at handler construction. ## Features - `SCALAR_ASSETS` — frozen registry keyed by logical asset name, every entry carrying its bytes, MIME type, and an FNV-1a-32 cache-busting hash. - `hashedAssetPath(name)` — formats the `..` filename embedded in the rendered shell. - `resolveAsset(filename)` — reverse lookup tolerating stale hashes (rolling deploy) and missing-hash bare filenames. - `resolveAssetUrl({ mode, cdnUrl, uiEndpoint, probe })` — returns the Scalar runtime URL the shell should embed. `bundled` + missing asset raises `OPENAPI_UI_SCALAR.ASSETS_MISSING`. - `defaultBundledAssetProbe` — checks the in-package registry is non-empty (default behaviour); tests inject a stub to simulate the stripped-bundle case. ## Usage: Basic ```ts import { resolveAssetUrl } from "@suaveplan/api-openapi-ui-scalar/assets"; const runtime = resolveAssetUrl({ mode: "cdn", cdnUrl: "https://cdn.jsdelivr.net/npm/@scalar/api-reference", uiEndpoint: "/docs/ui/scalar", }); console.log(runtime.url); ``` ## Usage: Advanced ```ts import { resolveAssetUrl, type BundledAssetProbe, } from "@suaveplan/api-openapi-ui-scalar/assets"; const stubbedProbe: BundledAssetProbe = { hasBundle: () => false }; // Simulate the air-gapped "asset stripped from dist" failure case — // `resolveAssetUrl` throws OPENAPI_UI_SCALAR.ASSETS_MISSING. try { resolveAssetUrl({ mode: "bundled", cdnUrl: "", uiEndpoint: "/docs/ui/scalar", probe: stubbedProbe, }); } catch (err) { console.error("bundled asset is missing", err); } ``` ## API Reference - `ScalarAsset` interface — `{ name, content, contentType, hash }`. - `SCALAR_ASSETS` `ReadonlyMap` — frozen registry. - `fnv1a32(input)` — 8-char hex FNV-1a-32 of the asset bytes. - `hashedAssetPath(name)` — throws `ASSET_NOT_REGISTERED` when missing. - `resolveAsset(filename)` — returns the asset entry or throws `ASSET_NOT_REGISTERED`. - `resolveAssetUrl(input)` — returns `{ mode, url }`; throws `ASSETS_MISSING` in bundled mode without a bundle. - `listScalarAssetNames()` — listing of registered names for tests. ## Implementation Notes The bundled JS bootstrap is intentionally minimal — it parses the `