@ericchen1990/pano-view 3.5.0 → 3.6.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/dist/data.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/data.ts","../src/data/errors.ts","../../../shared/viewer-config.ts","../src/tile/multires.ts","../src/data/viewer.ts","../src/data/hotspots.ts","../src/data/project.ts"],"sourcesContent":["export { PanoDataError } from \"./data/errors\";\nexport type { PanoDataErrorCode } from \"./data/errors\";\nexport { sceneFromViewerConfig, loadSceneFromJson } from \"./data/viewer\";\nexport type {\n AssetUrlContext,\n AssetUrlResolver,\n JsonRequestOptions,\n SceneFromViewerConfigOptions,\n LoadSceneFromJsonOptions,\n} from \"./data/viewer\";\nexport { parsePanoProject, loadPanoProject } from \"./data/project\";\nexport type {\n PanoProjectDefinition,\n PanoProjectSceneDefinition,\n LoadedPanoProject,\n LoadedProjectScene,\n LoadPanoProjectOptions,\n} from \"./data/project\";\nexport type { ProjectHotspotDefinition } from \"./data/hotspots\";\nexport type {\n ViewerConfig,\n ViewerDocument,\n CubemapViewerConfig,\n SphereViewerConfig,\n} from \"../../../shared/viewer-config\";\n","export type PanoDataErrorCode =\n | \"INVALID_OPTIONS\"\n | \"FETCH_FAILED\"\n | \"HTTP_ERROR\"\n | \"INVALID_JSON\"\n | \"INVALID_CONFIG\"\n | \"UNSUPPORTED_SCHEMA_VERSION\"\n | \"UNSUPPORTED_PROJECTION\"\n | \"INVALID_PROJECT\"\n | \"INVALID_REFERENCE\"\n | \"ABORTED\";\n\nexport class PanoDataError extends Error {\n readonly code: PanoDataErrorCode;\n readonly status?: number;\n readonly sceneId?: string;\n readonly field?: string;\n readonly cause?: unknown;\n constructor(\n code: PanoDataErrorCode,\n message: string,\n details: {\n status?: number;\n sceneId?: string;\n field?: string;\n cause?: unknown;\n } = {}\n ) {\n super(message);\n this.name = \"PanoDataError\";\n this.code = code;\n Object.assign(this, details);\n }\n}\n\nexport function aborted(signal?: AbortSignal | null): void {\n if (signal?.aborted)\n throw new PanoDataError(\"ABORTED\", \"Loading was cancelled\");\n}\n","/** The portable rendering contract shared by the converter and browser viewer. */\nexport type ViewerCubeFace = \"f\" | \"r\" | \"b\" | \"l\" | \"u\" | \"d\";\nexport type CubemapViewerConfig = {\n type: \"tile\";\n multires: { tileSize: number; levels: number[] };\n urlTemplate: string;\n previewUrl: string;\n previewFaceOrder: ViewerCubeFace[];\n};\nexport type SphereViewerConfig = {\n type: \"sphereTile\";\n multires: { tileSize: number; levels: { width: number; height: number }[] };\n urlTemplate: string;\n previewUrl: string;\n indexBase: 0 | 1;\n};\nexport type ViewerConfig = CubemapViewerConfig | SphereViewerConfig;\nexport type ViewerDocument = ViewerConfig & { schemaVersion: 1 };\n\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nexport function requiredString(value: unknown, field: string): string {\n if (typeof value !== \"string\" || !value.trim())\n throw new Error(`${field}: expected a nonempty string`);\n return value;\n}\n\nfunction positive(value: unknown, field: string): number {\n if (typeof value !== \"number\" || !Number.isSafeInteger(value) || value <= 0)\n throw new Error(`${field}: expected a positive safe integer`);\n return value;\n}\n\nexport function validateViewerConfig(value: unknown): ViewerConfig {\n if (!isRecord(value)) throw new Error(\"viewerConfig: expected an object\");\n if (value.type !== \"tile\" && value.type !== \"sphereTile\")\n throw new Error(\"type: expected tile or sphereTile\");\n if (!isRecord(value.multires))\n throw new Error(\"multires: expected an object\");\n const tileSize = positive(value.multires.tileSize, \"multires.tileSize\");\n if (tileSize > 8192) throw new Error(\"multires.tileSize: maximum is 8192\");\n const input = value.multires.levels;\n if (!Array.isArray(input) || input.length === 0 || input.length > 64)\n throw new Error(\"multires.levels: expected 1 to 64 levels\");\n const urlTemplate = requiredString(value.urlTemplate, \"urlTemplate\");\n const previewUrl = requiredString(value.previewUrl, \"previewUrl\");\n if (/%/.test(urlTemplate.replace(/%s|%l|%0*[hxucvywr]/g, \"\")))\n throw new Error(\"urlTemplate: unsupported placeholder\");\n if (value.type === \"tile\") {\n const levels = input.map((level, i) =>\n positive(level, `multires.levels[${i}]`)\n );\n if (levels.some((level, i) => i > 0 && level <= levels[i - 1]!))\n throw new Error(\"multires.levels: face sizes must increase\");\n const order = value.previewFaceOrder;\n if (\n !Array.isArray(order) ||\n order.length !== 6 ||\n ![\"f\", \"r\", \"b\", \"l\", \"u\", \"d\"].every((face) => order.includes(face))\n )\n throw new Error(\"previewFaceOrder: expected six unique cube faces\");\n return {\n type: \"tile\",\n multires: { tileSize, levels },\n urlTemplate,\n previewUrl,\n previewFaceOrder: [...order] as ViewerCubeFace[],\n };\n }\n if (urlTemplate.includes(\"%s\"))\n throw new Error(\"urlTemplate: sphere has no cube face\");\n if (value.indexBase !== 0 && value.indexBase !== 1)\n throw new Error(\"indexBase: expected 0 or 1\");\n const levels = input.map((level: unknown, i) => {\n if (!isRecord(level))\n throw new Error(`multires.levels[${i}]: expected dimensions`);\n const width = positive(level.width, `multires.levels[${i}].width`);\n const height = positive(level.height, `multires.levels[${i}].height`);\n if (Math.abs(width - 2 * height) > 2)\n throw new Error(`multires.levels[${i}]: expected a full 2:1 panorama`);\n return { width, height };\n });\n if (\n levels.some(\n (level, i) =>\n i > 0 &&\n (level.width <= levels[i - 1]!.width ||\n level.height <= levels[i - 1]!.height)\n )\n )\n throw new Error(\"multires.levels: dimensions must increase\");\n return {\n type: \"sphereTile\",\n multires: { tileSize, levels },\n urlTemplate,\n previewUrl,\n indexBase: value.indexBase,\n };\n}\n","import { resolveAssetUrl } from \"../asset-url\";\nimport type {\n TileAddress,\n TileMultiresConfig,\n} from \"./types\";\n\nfunction positiveInteger(value: number, name: string): number {\n if (!Number.isFinite(value) || value <= 0 || !Number.isInteger(value)) {\n throw new Error(`${name} must be a positive integer, received ${String(value)}`);\n }\n return value;\n}\n\nfunction ascendingLevels(levels: number[]): number[] {\n for (let index = 1; index < levels.length; index += 1) {\n if (levels[index]! <= levels[index - 1]!) {\n throw new Error(\"multires face sizes must be strictly ascending\");\n }\n }\n return levels;\n}\n\nexport function parseMultires(\n multires: string | TileMultiresConfig,\n): TileMultiresConfig {\n if (typeof multires !== \"string\") {\n const tileSize = positiveInteger(multires.tileSize, \"multires.tileSize\");\n if (multires.levels.length === 0) {\n throw new Error(\"multires.levels must contain at least one face size\");\n }\n const levels = ascendingLevels(\n multires.levels.map((level, index) =>\n positiveInteger(level, `multires.levels[${index}]`),\n ),\n );\n return { tileSize, levels };\n }\n\n const values = multires.split(\",\").map((part) => Number(part.trim()));\n\n if (values.length < 2 || values.some((value) => !Number.isFinite(value))) {\n throw new Error(\n \"multires must contain a tile size followed by at least one face size\",\n );\n }\n\n const tileSize = positiveInteger(values[0]!, \"multires tile size\");\n const levels = ascendingLevels(\n values.slice(1).map((level, index) =>\n positiveInteger(level, `multires level ${index + 1}`),\n ),\n );\n return { tileSize, levels };\n}\n\nexport const DEFAULT_TILE_URL_TEMPLATE = \"tiles/%s/l%l/%v/l%l_%s_%h_%v.webp\";\n\nexport function buildDefaultTileUrlTemplate(): string {\n return DEFAULT_TILE_URL_TEMPLATE;\n}\n\nexport function resolveRelativeTileUrl(\n baseUrl: string,\n relativePath: string,\n): string {\n return resolveAssetUrl(baseUrl, relativePath);\n}\n\nexport function resolveTemplateUrl(\n template: string,\n address: Pick<TileAddress, \"face\" | \"level\" | \"row\" | \"col\">,\n): string {\n return template\n .replace(/%s/g, address.face)\n .replace(/%l/g, String(address.level))\n .replace(/%(0*)([hxucvywr])/g, (_match, zeroes: string, placeholder: string) => {\n const value = \"hxuc\".includes(placeholder)\n ? address.col\n : address.row;\n return String(value).padStart(zeroes.length + 1, \"0\");\n });\n}\n","import {\n isRecord,\n validateViewerConfig,\n type ViewerConfig,\n} from \"../../../../shared/viewer-config\";\nimport type { TileScene, SphereTileScene } from \"../scenes\";\nimport type { TileAddress } from \"../tile/types\";\nimport type { SphereTileAddress } from \"../sphere-tile/types\";\nimport { resolveTemplateUrl } from \"../tile/multires\";\nimport { PanoDataError, aborted } from \"./errors\";\n\nexport type AssetUrlContext = {\n defaultUrl: string;\n kind: \"tile\" | \"preview\" | \"hotspot\";\n sceneId: string;\n hotspotId?: string;\n};\nexport type AssetUrlResolver = (\n path: string,\n context: AssetUrlContext\n) => string;\nexport type JsonRequestOptions = {\n requestInit?: Pick<RequestInit, \"headers\" | \"credentials\" | \"signal\">;\n};\nexport type SceneFromViewerConfigOptions = {\n id: string;\n baseUrl: string;\n resolveAssetUrl?: AssetUrlResolver;\n};\nexport type LoadSceneFromJsonOptions = Omit<\n SceneFromViewerConfigOptions,\n \"baseUrl\"\n> &\n JsonRequestOptions & { baseUrl?: string };\n\n/** URL resolution is intentionally independent of React and browser globals on the server. */\nexport function documentUrl(input: string): string {\n try {\n const url = new URL(\n input,\n typeof document === \"undefined\" ? undefined : document.baseURI\n );\n if (url.protocol !== \"http:\" && url.protocol !== \"https:\")\n throw new Error(\"Use HTTP(S)\");\n return url.href;\n } catch (cause) {\n throw new PanoDataError(\n \"INVALID_OPTIONS\",\n \"Expected an HTTP(S) URL; Node.js requires an absolute URL\",\n { cause }\n );\n }\n}\n\nexport function directoryUrl(input: string): string {\n const url = new URL(input);\n url.search = \"\";\n url.hash = \"\";\n if (!url.pathname.endsWith(\"/\")) url.pathname += \"/\";\n return url.href;\n}\n\nexport function resolveResource(baseUrl: string, path: string): string {\n try {\n const url = new URL(path, directoryUrl(baseUrl));\n if (![\"http:\", \"https:\", \"blob:\", \"data:\"].includes(url.protocol))\n throw new Error(\"Unsupported resource URL protocol\");\n return url.href;\n } catch (cause) {\n throw new PanoDataError(\n \"INVALID_CONFIG\",\n `Invalid resource path: ${path}`,\n { cause }\n );\n }\n}\n\nexport function mapResource(\n path: string,\n context: AssetUrlContext,\n resolver?: AssetUrlResolver\n): string {\n let result: string;\n try {\n result = resolver ? resolver(path, context) : context.defaultUrl;\n } catch (cause) {\n throw new PanoDataError(\"INVALID_CONFIG\", \"resolveAssetUrl failed\", {\n sceneId: context.sceneId,\n cause,\n });\n }\n if (typeof result !== \"string\" || !result.trim())\n throw new PanoDataError(\n \"INVALID_CONFIG\",\n \"resolveAssetUrl must return a nonempty final URL\",\n { sceneId: context.sceneId }\n );\n // A root path is already final; relative callback results are ambiguous and rejected.\n if (!result.startsWith(\"/\") && !/^(https?:|blob:|data:)/i.test(result))\n throw new PanoDataError(\n \"INVALID_CONFIG\",\n \"resolveAssetUrl must return an absolute URL or a site-root path\",\n { sceneId: context.sceneId }\n );\n return result;\n}\n\nexport function parseConfig(value: unknown): ViewerConfig {\n if (isRecord(value) && value.type !== \"tile\" && value.type !== \"sphereTile\")\n throw new PanoDataError(\n \"UNSUPPORTED_PROJECTION\",\n \"Expected a tile or sphereTile configuration\",\n { field: \"type\" }\n );\n try {\n return validateViewerConfig(value);\n } catch (cause) {\n const message =\n cause instanceof Error ? cause.message : \"Invalid viewer configuration\";\n throw new PanoDataError(\"INVALID_CONFIG\", message, {\n cause,\n field: message.split(\":\")[0],\n });\n }\n}\n\nexport function sceneFromViewerConfig(\n value: unknown,\n options: SceneFromViewerConfigOptions\n): TileScene | SphereTileScene {\n if (\n !options ||\n typeof options.id !== \"string\" ||\n !options.id.trim() ||\n typeof options.baseUrl !== \"string\" ||\n !options.baseUrl.trim()\n )\n throw new PanoDataError(\"INVALID_OPTIONS\", \"id and baseUrl are required\");\n const config = parseConfig(value);\n const baseUrl = directoryUrl(documentUrl(options.baseUrl));\n const resolve = (path: string, kind: \"tile\" | \"preview\") =>\n mapResource(\n path,\n {\n kind,\n sceneId: options.id,\n defaultUrl: resolveResource(baseUrl, path),\n },\n options.resolveAssetUrl\n );\n const previewUrl = resolve(config.previewUrl, \"preview\");\n if (config.type === \"tile\") {\n return {\n ...config,\n id: options.id,\n baseUrl,\n previewUrl,\n ...(options.resolveAssetUrl\n ? {\n resolveTileUrl: (address: TileAddress) =>\n resolve(resolveTemplateUrl(config.urlTemplate, address), \"tile\"),\n }\n : {}),\n };\n }\n return {\n ...config,\n id: options.id,\n baseUrl,\n previewUrl,\n ...(options.resolveAssetUrl\n ? {\n resolveTileUrl: (address: SphereTileAddress) => {\n // Sphere callbacks use logical zero-based addresses; the document controls storage indices.\n const path = resolveTemplateUrl(config.urlTemplate, {\n face: \"f\",\n level: address.level + config.indexBase,\n row: address.row + config.indexBase,\n col: address.col + config.indexBase,\n });\n return resolve(path, \"tile\");\n },\n }\n : {}),\n };\n}\n\nexport async function readJson(\n url: string,\n options: JsonRequestOptions\n): Promise<{ value: unknown; url: string }> {\n const signal = options.requestInit?.signal;\n aborted(signal);\n let response: Response;\n try {\n response = await fetch(url, { ...options.requestInit, method: \"GET\" });\n } catch (cause) {\n aborted(signal);\n throw new PanoDataError(\n \"FETCH_FAILED\",\n \"Could not fetch JSON; check the network and server CORS settings\",\n { cause }\n );\n }\n aborted(signal);\n if (!response.ok)\n throw new PanoDataError(\n \"HTTP_ERROR\",\n `JSON request returned HTTP ${response.status}`,\n { status: response.status }\n );\n try {\n const value: unknown = await response.json();\n aborted(signal);\n return { value, url: response.url || url };\n } catch (cause) {\n aborted(signal);\n throw new PanoDataError(\n \"INVALID_JSON\",\n \"Expected JSON; check for an HTML fallback or login page\",\n { cause }\n );\n }\n}\n\nexport async function loadSceneFromJson(\n url: string,\n options: LoadSceneFromJsonOptions\n): Promise<TileScene | SphereTileScene> {\n if (!options || typeof options.id !== \"string\" || !options.id.trim())\n throw new PanoDataError(\"INVALID_OPTIONS\", \"id is required\");\n const response = await readJson(documentUrl(url), options);\n if (!isRecord(response.value))\n throw new PanoDataError(\n \"INVALID_CONFIG\",\n \"viewer.json must contain an object\"\n );\n if (response.value.schemaVersion !== 1)\n throw new PanoDataError(\n \"UNSUPPORTED_SCHEMA_VERSION\",\n \"Unsupported viewer.json schemaVersion\",\n { field: \"schemaVersion\" }\n );\n return sceneFromViewerConfig(response.value, {\n ...options,\n baseUrl: options.baseUrl ?? new URL(\".\", response.url).href,\n });\n}\n","import { isRecord, requiredString } from \"../../../../shared/viewer-config\";\nimport type { HotspotDefinition } from \"../hotspot/definitions\";\nimport type { HotspotPosition } from \"../hotspot/types\";\nimport { PanoDataError } from \"./errors\";\nimport { mapResource, resolveResource, type AssetUrlResolver } from \"./viewer\";\n\nexport type ProjectHotspotDefinition = HotspotDefinition & {\n action?: { type: \"scene\"; sceneId: string };\n};\n\nconst common = [\n \"label\",\n \"visible\",\n \"interactive\",\n \"pointerEvents\",\n \"cursor\",\n \"renderOrder\",\n \"tooltip\",\n \"tooltipTrigger\",\n \"tooltipPlacement\",\n \"tooltipOffset\",\n \"tooltipAppearance\",\n];\nconst point = [\n \"position\",\n \"width\",\n \"height\",\n \"scale\",\n \"mode\",\n \"distance\",\n \"scaleMode\",\n \"referenceFov\",\n \"rotation\",\n \"opacity\",\n];\nconst fields = {\n image: [\"src\"],\n graphic: [\"graphic\"],\n sequence: [\"src\", \"frameCount\", \"frameDirection\", \"playing\", \"fps\", \"loop\"],\n video: [\n \"src\",\n \"poster\",\n \"playing\",\n \"loop\",\n \"muted\",\n \"volume\",\n \"playsInline\",\n \"preload\",\n \"crossOrigin\",\n ],\n audio: [\n \"src\",\n \"playing\",\n \"loop\",\n \"muted\",\n \"volume\",\n \"pauseWhenHidden\",\n \"range\",\n \"icon\",\n \"playingIcon\",\n \"marker\",\n \"crossOrigin\",\n ],\n text: [\n \"text\",\n \"fontFamily\",\n \"fontSize\",\n \"fontWeight\",\n \"fontStyle\",\n \"color\",\n \"background\",\n \"backgroundOpacity\",\n \"padding\",\n \"align\",\n \"verticalAlign\",\n \"whiteSpace\",\n \"lineHeight\",\n \"borderRadius\",\n \"stroke\",\n \"strokeWidth\",\n ],\n iframe: [\n \"src\",\n \"title\",\n \"sandbox\",\n \"allow\",\n \"referrerPolicy\",\n \"loading\",\n \"pointerPolicy\",\n \"background\",\n ],\n polygon: [\n \"vertices\",\n \"fill\",\n \"fillOpacity\",\n \"stroke\",\n \"strokeWidth\",\n \"strokeOpacity\",\n \"strokeDashSize\",\n \"strokeGapSize\",\n ],\n polyline: [\n \"vertices\",\n \"stroke\",\n \"strokeWidth\",\n \"strokeOpacity\",\n \"strokeDashSize\",\n \"strokeGapSize\",\n ],\n} satisfies Record<HotspotDefinition[\"type\"], string[]>;\nconst booleanFields = new Set([\n \"visible\",\n \"interactive\",\n \"playing\",\n \"loop\",\n \"muted\",\n \"playsInline\",\n \"pauseWhenHidden\",\n \"marker\",\n]);\nconst numberFields = new Set([\n \"renderOrder\",\n \"tooltipOffset\",\n \"width\",\n \"height\",\n \"scale\",\n \"distance\",\n \"referenceFov\",\n \"rotation\",\n \"opacity\",\n \"frameCount\",\n \"fps\",\n \"volume\",\n \"range\",\n \"fontSize\",\n \"backgroundOpacity\",\n \"padding\",\n \"lineHeight\",\n \"borderRadius\",\n \"strokeWidth\",\n \"fillOpacity\",\n \"strokeOpacity\",\n \"strokeDashSize\",\n \"strokeGapSize\",\n]);\nconst positiveFields = new Set([\n \"width\",\n \"height\",\n \"scale\",\n \"distance\",\n \"referenceFov\",\n \"frameCount\",\n \"fps\",\n \"fontSize\",\n \"lineHeight\",\n]);\nconst enums: Record<string, readonly string[]> = {\n pointerEvents: [\"auto\", \"none\"],\n tooltipTrigger: [\"always\", \"hover\", \"click\"],\n tooltipPlacement: [\"top\", \"bottom\", \"left\", \"right\"],\n mode: [\"surface\", \"billboard\"],\n scaleMode: [\"fov\", \"fixed\"],\n frameDirection: [\"horizontal\", \"vertical\"],\n preload: [\"none\", \"metadata\", \"auto\"],\n crossOrigin: [\"\", \"anonymous\", \"use-credentials\"],\n fontStyle: [\"normal\", \"italic\"],\n align: [\"left\", \"center\", \"right\"],\n verticalAlign: [\"top\", \"middle\", \"bottom\"],\n whiteSpace: [\"normal\", \"nowrap\"],\n loading: [\"eager\", \"lazy\"],\n pointerPolicy: [\"hotspot\", \"content\"],\n referrerPolicy: [\n \"\",\n \"no-referrer\",\n \"no-referrer-when-downgrade\",\n \"origin\",\n \"origin-when-cross-origin\",\n \"same-origin\",\n \"strict-origin\",\n \"strict-origin-when-cross-origin\",\n \"unsafe-url\",\n ],\n};\n\nfunction finite(value: unknown, field: string): number {\n if (typeof value !== \"number\" || !Number.isFinite(value))\n throw new Error(`${field}: expected a finite number`);\n return value;\n}\n\nexport function parsePosition(value: unknown, field: string): HotspotPosition {\n if (!isRecord(value)) throw new Error(`${field}: expected yaw and pitch`);\n const yaw = finite(value.yaw, `${field}.yaw`);\n const pitch = finite(value.pitch, `${field}.pitch`);\n if (Math.abs(pitch) > 90)\n throw new Error(`${field}.pitch: expected -90 to 90`);\n return { yaw, pitch };\n}\n\nfunction parseGraphic(value: unknown): Record<string, unknown> {\n if (!isRecord(value)) throw new Error(\"graphic: expected an object\");\n const kind = requiredString(value.kind, \"graphic.kind\");\n if (\n ![\n \"circle\",\n \"triangle\",\n \"diamond\",\n \"star\",\n \"arrow\",\n \"rectangle\",\n \"ring\",\n \"svg\",\n \"path\",\n ].includes(kind)\n )\n throw new Error(\"graphic.kind: unsupported graphic\");\n const result: Record<string, unknown> = { kind };\n for (const key of [\"fill\", \"stroke\"]) {\n if (value[key] !== undefined)\n result[key] = requiredString(value[key], `graphic.${key}`);\n }\n for (const key of [\"strokeWidth\", \"cornerRadius\", \"innerRadius\"]) {\n if (value[key] !== undefined)\n result[key] = finite(value[key], `graphic.${key}`);\n }\n if (kind === \"svg\") result.src = requiredString(value.src, \"graphic.src\");\n if (kind === \"path\") {\n result.path = requiredString(value.path, \"graphic.path\");\n if (!Array.isArray(value.viewBox) || value.viewBox.length !== 4)\n throw new Error(\"graphic.viewBox: expected four numbers\");\n const viewBox = value.viewBox.map((n, i) =>\n finite(n, `graphic.viewBox[${i}]`)\n );\n if (viewBox[2]! <= 0 || viewBox[3]! <= 0)\n throw new Error(\"graphic.viewBox: width and height must be positive\");\n result.viewBox = viewBox;\n }\n return result;\n}\n\nfunction parseTooltip(value: unknown): unknown {\n if (typeof value === \"string\") return value;\n if (!isRecord(value)) throw new Error(\"tooltip: expected text or an object\");\n const result: Record<string, string> = {};\n for (const key of [\"text\", \"image\", \"imageAlt\"]) {\n if (value[key] !== undefined) {\n if (typeof value[key] !== \"string\")\n throw new Error(`tooltip.${key}: expected a string`);\n result[key] = value[key];\n }\n }\n return result;\n}\n\nfunction parseAppearance(value: unknown): Record<string, string | number> {\n if (!isRecord(value))\n throw new Error(\"tooltipAppearance: expected an object\");\n const result: Record<string, string | number> = {};\n for (const key of [\n \"background\",\n \"color\",\n \"border\",\n \"borderRadius\",\n \"shadow\",\n \"padding\",\n \"fontSize\",\n \"fontFamily\",\n \"lineHeight\",\n \"letterSpacing\",\n ]) {\n const item = value[key];\n if (item === undefined) continue;\n if (\n [\"background\", \"color\", \"border\", \"shadow\", \"fontFamily\"].includes(key) &&\n typeof item !== \"string\"\n )\n throw new Error(`tooltipAppearance.${key}: expected a string`);\n if (\n typeof item !== \"string\" &&\n (typeof item !== \"number\" || !Number.isFinite(item))\n )\n throw new Error(\n `tooltipAppearance.${key}: expected a string or finite number`\n );\n result[key] = item;\n }\n return result;\n}\n\nexport function parseHotspot(\n value: unknown,\n sceneId: string,\n field: string\n): ProjectHotspotDefinition {\n try {\n if (!isRecord(value)) throw new Error(\"expected a hotspot object\");\n const type = requiredString(value.type, \"type\");\n if (!Object.prototype.hasOwnProperty.call(fields, type))\n throw new Error(\"type: unsupported hotspot type\");\n const kind = type as HotspotDefinition[\"type\"];\n const result: Record<string, unknown> = {\n type,\n id: requiredString(value.id, \"id\"),\n };\n const isPath = kind === \"polygon\" || kind === \"polyline\";\n const allowed = [...common, ...(isPath ? [] : point), ...fields[kind]];\n for (const key of allowed) {\n const item = value[key];\n if (item === undefined) continue;\n if (key === \"position\") result[key] = parsePosition(item, key);\n else if (key === \"vertices\") {\n if (!Array.isArray(item) || item.length < (kind === \"polygon\" ? 3 : 2))\n throw new Error(\"vertices: not enough points\");\n result[key] = item.map((p, i) => parsePosition(p, `vertices[${i}]`));\n } else if (key === \"graphic\") result[key] = parseGraphic(item);\n else if (key === \"tooltip\") result[key] = parseTooltip(item);\n else if (key === \"tooltipAppearance\") result[key] = parseAppearance(item);\n else if (booleanFields.has(key)) {\n if (typeof item !== \"boolean\")\n throw new Error(`${key}: expected a boolean`);\n result[key] = item;\n } else if (numberFields.has(key)) {\n const n = finite(item, key);\n if (positiveFields.has(key) && n <= 0)\n throw new Error(`${key}: expected a positive number`);\n if (key === \"frameCount\" && !Number.isSafeInteger(n))\n throw new Error(\"frameCount: expected an integer\");\n if (\n [\n \"opacity\",\n \"fillOpacity\",\n \"strokeOpacity\",\n \"volume\",\n \"backgroundOpacity\",\n ].includes(key) &&\n (n < 0 || n > 1)\n )\n throw new Error(`${key}: expected 0 to 1`);\n result[key] = n;\n } else if (key === \"fontWeight\" && typeof item === \"number\")\n result[key] = finite(item, key);\n else if (key === \"src\" && kind === \"audio\" && Array.isArray(item)) {\n if (!item.length) throw new Error(\"src: expected audio sources\");\n result[key] = item.map((src, i) => requiredString(src, `src[${i}]`));\n } else {\n if (typeof item !== \"string\")\n throw new Error(`${key}: expected a string`);\n if (enums[key] && !enums[key].includes(item))\n throw new Error(`${key}: unsupported value`);\n result[key] = item;\n }\n }\n if (!isPath && !result.position) throw new Error(\"position: required\");\n if (isPath && !result.vertices) throw new Error(\"vertices: required\");\n if (\n [\"image\", \"sequence\", \"video\", \"audio\", \"iframe\"].includes(kind) &&\n !(typeof result.src === \"string\"\n ? result.src.trim()\n : Array.isArray(result.src))\n )\n throw new Error(\"src: required\");\n if (kind === \"graphic\" && !result.graphic)\n throw new Error(\"graphic: required\");\n if (kind === \"text\" && typeof result.text !== \"string\")\n throw new Error(\"text: required\");\n if (kind === \"sequence\" && !result.frameCount)\n throw new Error(\"frameCount: required\");\n if (value.action !== undefined) {\n if (!isRecord(value.action) || value.action.type !== \"scene\")\n throw new Error(\"action: expected a scene action\");\n result.action = {\n type: \"scene\",\n sceneId: requiredString(value.action.sceneId, \"action.sceneId\"),\n };\n }\n return result as ProjectHotspotDefinition;\n } catch (cause) {\n const detail = cause instanceof Error ? cause.message : \"Invalid hotspot\";\n throw new PanoDataError(\"INVALID_PROJECT\", `${field}.${detail}`, {\n sceneId,\n field: `${field}.${detail.split(\":\")[0]}`,\n cause,\n });\n }\n}\n\nexport function resolveHotspotAssets(\n hotspot: ProjectHotspotDefinition,\n baseUrl: string,\n sceneId: string,\n resolver?: AssetUrlResolver\n): ProjectHotspotDefinition {\n const resolve = (path: string) =>\n path\n ? mapResource(\n path,\n {\n kind: \"hotspot\",\n sceneId,\n hotspotId: hotspot.id,\n defaultUrl: resolveResource(baseUrl, path),\n },\n resolver\n )\n : path;\n const result = { ...hotspot };\n if (\"src\" in result)\n result.src = Array.isArray(result.src)\n ? result.src.map(resolve)\n : resolve(result.src);\n if (\"poster\" in result && result.poster)\n result.poster = resolve(result.poster);\n if (result.type === \"audio\") {\n if (result.icon) result.icon = resolve(result.icon);\n if (result.playingIcon) result.playingIcon = resolve(result.playingIcon);\n }\n if (result.type === \"graphic\" && result.graphic.kind === \"svg\")\n result.graphic = { ...result.graphic, src: resolve(result.graphic.src) };\n if (typeof result.tooltip === \"object\")\n result.tooltip = {\n ...result.tooltip,\n ...(result.tooltip.image ? { image: resolve(result.tooltip.image) } : {}),\n };\n return result;\n}\n","import {\n isRecord,\n requiredString,\n type ViewerConfig,\n} from \"../../../../shared/viewer-config\";\nimport type { TileScene, SphereTileScene } from \"../scenes\";\nimport type { PanoViewerState } from \"../types\";\nimport { PanoDataError, aborted } from \"./errors\";\nimport {\n parseHotspot,\n parsePosition,\n resolveHotspotAssets,\n type ProjectHotspotDefinition,\n} from \"./hotspots\";\nimport {\n documentUrl,\n directoryUrl,\n readJson,\n parseConfig,\n resolveResource,\n sceneFromViewerConfig,\n loadSceneFromJson,\n type AssetUrlResolver,\n type JsonRequestOptions,\n} from \"./viewer\";\n\nexport type PanoProjectSceneDefinition = {\n id: string;\n title?: string;\n source: (\n | { viewerUrl: string; viewerConfig?: never }\n | { viewerConfig: ViewerConfig; viewerUrl?: never }\n ) & { baseUrl?: string };\n initialView?: Partial<PanoViewerState>;\n hotspots?: ProjectHotspotDefinition[];\n};\nexport type PanoProjectDefinition = {\n schemaVersion: 1;\n title?: string;\n initialSceneId?: string;\n scenes: PanoProjectSceneDefinition[];\n};\nexport type LoadedProjectScene = {\n scene: TileScene | SphereTileScene;\n title?: string;\n initialView?: PanoViewerState;\n hotspots: ProjectHotspotDefinition[];\n};\nexport type LoadedPanoProject = {\n title?: string;\n initialSceneId: string;\n scenes: LoadedProjectScene[];\n};\nexport type LoadPanoProjectOptions = JsonRequestOptions & {\n /** Directory used for project-relative references. Required for object input. */\n baseUrl?: string;\n resolveAssetUrl?: AssetUrlResolver;\n};\n\nfunction optionalString(\n record: Record<string, unknown>,\n key: string\n): string | undefined {\n return record[key] === undefined\n ? undefined\n : requiredString(record[key], key);\n}\n\nexport function parsePanoProject(value: unknown): PanoProjectDefinition {\n if (!isRecord(value))\n throw new PanoDataError(\"INVALID_PROJECT\", \"Expected a project object\");\n if (value.schemaVersion !== 1)\n throw new PanoDataError(\n \"UNSUPPORTED_SCHEMA_VERSION\",\n \"Unsupported project schemaVersion\",\n { field: \"schemaVersion\" }\n );\n try {\n if (!Array.isArray(value.scenes) || !value.scenes.length)\n throw new Error(\"scenes: expected a nonempty array\");\n const ids = new Set<string>();\n const scenes = value.scenes.map(\n (entry: unknown, index): PanoProjectSceneDefinition => {\n let id: string | undefined;\n const field = `scenes[${index}]`;\n try {\n if (!isRecord(entry)) throw new Error(\"expected a scene object\");\n id = requiredString(entry.id, \"id\");\n if (ids.has(id)) throw new Error(\"id: duplicate scene ID\");\n ids.add(id);\n if (!isRecord(entry.source))\n throw new Error(\"source: expected an object\");\n const src = entry.source;\n if (\n (src.viewerUrl !== undefined) ===\n (src.viewerConfig !== undefined)\n )\n throw new Error(\n \"source: provide exactly one of viewerUrl or viewerConfig\"\n );\n const baseUrl = optionalString(src, \"baseUrl\");\n const source: PanoProjectSceneDefinition[\"source\"] =\n src.viewerUrl !== undefined\n ? {\n viewerUrl: requiredString(src.viewerUrl, \"source.viewerUrl\"),\n baseUrl,\n }\n : { viewerConfig: parseConfig(src.viewerConfig), baseUrl };\n let initialView: Partial<PanoViewerState> | undefined;\n if (entry.initialView !== undefined) {\n if (!isRecord(entry.initialView))\n throw new Error(\"initialView: expected an object\");\n const input = entry.initialView;\n const position = parsePosition(\n { yaw: input.yaw ?? 0, pitch: input.pitch ?? 0 },\n \"initialView\"\n );\n const fov = input.fov ?? 75;\n if (\n typeof fov !== \"number\" ||\n !Number.isFinite(fov) ||\n fov <= 0 ||\n fov >= 180\n )\n throw new Error(\n \"initialView.fov: expected a number between 0 and 180\"\n );\n initialView = { ...position, fov };\n }\n if (entry.hotspots !== undefined && !Array.isArray(entry.hotspots))\n throw new Error(\"hotspots: expected an array\");\n const hotspotIds = new Set<string>();\n const hotspots = ((entry.hotspots ?? []) as unknown[]).map(\n (hotspot, i) => {\n const result = parseHotspot(\n hotspot,\n id!,\n `${field}.hotspots[${i}]`\n );\n if (hotspotIds.has(result.id))\n throw new Error(`hotspots[${i}].id: duplicate hotspot ID`);\n hotspotIds.add(result.id);\n return result;\n }\n );\n return {\n id,\n title: optionalString(entry, \"title\"),\n source,\n initialView,\n hotspots,\n };\n } catch (cause) {\n if (cause instanceof PanoDataError && cause.sceneId) throw cause;\n const detail =\n cause instanceof Error ? cause.message : \"Invalid scene\";\n throw new PanoDataError(\n cause instanceof PanoDataError ? cause.code : \"INVALID_PROJECT\",\n `${field}.${detail}`,\n {\n sceneId: id,\n field: `${field}.${\n cause instanceof PanoDataError\n ? `source.viewerConfig.${cause.field ?? \"\"}`\n : detail.split(\":\")[0]\n }`,\n cause,\n }\n );\n }\n }\n );\n const initialSceneId =\n optionalString(value, \"initialSceneId\") ?? scenes[0]!.id;\n if (!ids.has(initialSceneId))\n throw new PanoDataError(\n \"INVALID_REFERENCE\",\n \"initialSceneId: scene does not exist\",\n { field: \"initialSceneId\" }\n );\n for (const [index, scene] of scenes.entries()) {\n for (const [i, hotspot] of (scene.hotspots ?? []).entries()) {\n if (hotspot.action && !ids.has(hotspot.action.sceneId))\n throw new PanoDataError(\n \"INVALID_REFERENCE\",\n \"Hotspot target scene does not exist\",\n {\n sceneId: scene.id,\n field: `scenes[${index}].hotspots[${i}].action.sceneId`,\n }\n );\n }\n }\n return {\n schemaVersion: 1,\n title: optionalString(value, \"title\"),\n initialSceneId,\n scenes,\n };\n } catch (cause) {\n if (cause instanceof PanoDataError) throw cause;\n const message = cause instanceof Error ? cause.message : \"Invalid project\";\n throw new PanoDataError(\"INVALID_PROJECT\", message, {\n cause,\n field: message.split(\":\")[0],\n });\n }\n}\n\nexport async function loadPanoProject(\n source: string | PanoProjectDefinition,\n options: LoadPanoProjectOptions = {}\n): Promise<LoadedPanoProject> {\n aborted(options.requestInit?.signal);\n let definition: PanoProjectDefinition;\n let baseUrl: string;\n if (typeof source === \"string\") {\n const response = await readJson(documentUrl(source), options);\n definition = parsePanoProject(response.value);\n baseUrl = options.baseUrl ?? new URL(\".\", response.url).href;\n } else {\n if (!options.baseUrl)\n throw new PanoDataError(\n \"INVALID_OPTIONS\",\n \"baseUrl is required for project object input\"\n );\n definition = parsePanoProject(source);\n baseUrl = options.baseUrl;\n }\n const root = directoryUrl(documentUrl(baseUrl));\n const controller = new AbortController();\n const signal = options.requestInit?.signal;\n const cancel = () => controller.abort();\n signal?.addEventListener(\"abort\", cancel, { once: true });\n const scenes: LoadedProjectScene[] = new Array(definition.scenes.length);\n let next = 0;\n let failure: PanoDataError | undefined;\n async function worker() {\n while (next < definition.scenes.length && !controller.signal.aborted) {\n const index = next++;\n const item = definition.scenes[index]!;\n try {\n const sourceBase =\n item.source.baseUrl === undefined\n ? undefined\n : resolveResource(root, item.source.baseUrl);\n const sceneOptions = {\n id: item.id,\n resolveAssetUrl: options.resolveAssetUrl,\n };\n const scene =\n item.source.viewerUrl !== undefined\n ? await loadSceneFromJson(\n resolveResource(root, item.source.viewerUrl),\n {\n ...sceneOptions,\n baseUrl: sourceBase,\n requestInit: {\n ...options.requestInit,\n signal: controller.signal,\n },\n }\n )\n : sceneFromViewerConfig(item.source.viewerConfig, {\n ...sceneOptions,\n baseUrl: sourceBase ?? root,\n });\n aborted(controller.signal);\n scenes[index] = {\n scene,\n title: item.title,\n initialView: item.initialView\n ? { yaw: 0, pitch: 0, fov: 75, ...item.initialView }\n : undefined,\n hotspots: item.hotspots!.map((h) =>\n resolveHotspotAssets(h, root, item.id, options.resolveAssetUrl)\n ),\n };\n } catch (cause) {\n if (!failure) {\n const error =\n cause instanceof PanoDataError\n ? cause\n : new PanoDataError(\n \"INVALID_CONFIG\",\n cause instanceof Error\n ? cause.message\n : \"Could not load scene\",\n { cause }\n );\n const field = `scenes[${index}].${\n error.field ??\n (item.source.viewerUrl !== undefined\n ? \"source.viewerUrl\"\n : \"source.viewerConfig\")\n }`;\n failure = new PanoDataError(\n error.code,\n `Scene ${item.id}: ${error.message}`,\n { status: error.status, sceneId: item.id, field, cause: error }\n );\n }\n controller.abort();\n }\n }\n }\n try {\n aborted(signal);\n await Promise.all(\n Array.from({ length: Math.min(4, scenes.length) }, worker)\n );\n aborted(signal);\n if (failure) throw failure;\n return {\n title: definition.title,\n initialSceneId: definition.initialSceneId!,\n scenes,\n };\n } finally {\n signal?.removeEventListener(\"abort\", cancel);\n }\n}\n"],"mappings":"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","names":["levels"]}
1
+ {"version":3,"sources":["../src/data.ts","../src/data/errors.ts","../../../shared/viewer-config.ts","../src/tile/multires.ts","../src/data/viewer.ts","../src/view-limits.ts","../src/data/popups.ts","../../../shared/cursor-assets.ts","../src/data/hotspots.ts","../src/data/project.ts"],"sourcesContent":["export { PanoDataError } from \"./data/errors\";\nexport type { PanoDataErrorCode } from \"./data/errors\";\nexport { sceneFromViewerConfig, loadSceneFromJson } from \"./data/viewer\";\nexport type {\n AssetUrlContext,\n AssetUrlResolver,\n JsonRequestOptions,\n SceneFromViewerConfigOptions,\n LoadSceneFromJsonOptions,\n} from \"./data/viewer\";\nexport { parsePanoProject, loadPanoProject } from \"./data/project\";\nexport type {\n PanoProjectDefinition,\n PanoProjectSceneDefinition,\n LoadedPanoProject,\n LoadedProjectScene,\n LoadPanoProjectOptions,\n} from \"./data/project\";\nexport type { ProjectHotspotDefinition, ProjectHotspotAction, ProjectHotspotTrigger, ProjectCustomHotspotAction, JsonObject, JsonValue } from \"./data/hotspots\";\nexport { resolveHotspotAssets as resolveProjectHotspotAssets } from \"./data/hotspots\";\nexport type {\n ViewerConfig,\n ViewerDocument,\n CubemapViewerConfig,\n SphereViewerConfig,\n} from \"../../../shared/viewer-config\";\n\nexport { resolveProjectPopupAssets } from \"./data/popups\";\nexport type { ProjectPopupDefinition, ProjectPopupBlock, PopupAssetUrlContext, PopupAssetUrlResolver } from \"./data/popups\";\n\nexport type { PanoViewLimits } from \"./view-limits\";\n\nexport { hotspotAction, setHotspotAction, projectHotspotTriggers } from \"./data/hotspots\";\n","export type PanoDataErrorCode =\n | \"INVALID_OPTIONS\"\n | \"FETCH_FAILED\"\n | \"HTTP_ERROR\"\n | \"INVALID_JSON\"\n | \"INVALID_CONFIG\"\n | \"UNSUPPORTED_SCHEMA_VERSION\"\n | \"UNSUPPORTED_PROJECTION\"\n | \"INVALID_PROJECT\"\n | \"INVALID_REFERENCE\"\n | \"ABORTED\";\n\nexport class PanoDataError extends Error {\n readonly code: PanoDataErrorCode;\n readonly status?: number;\n readonly sceneId?: string;\n readonly field?: string;\n readonly cause?: unknown;\n constructor(\n code: PanoDataErrorCode,\n message: string,\n details: {\n status?: number;\n sceneId?: string;\n field?: string;\n cause?: unknown;\n } = {}\n ) {\n super(message);\n this.name = \"PanoDataError\";\n this.code = code;\n Object.assign(this, details);\n }\n}\n\nexport function aborted(signal?: AbortSignal | null): void {\n if (signal?.aborted)\n throw new PanoDataError(\"ABORTED\", \"Loading was cancelled\");\n}\n","/** The portable rendering contract shared by the converter and browser viewer. */\nexport type ViewerCubeFace = \"f\" | \"r\" | \"b\" | \"l\" | \"u\" | \"d\";\nexport type CubemapViewerConfig = {\n type: \"tile\";\n multires: { tileSize: number; levels: number[] };\n urlTemplate: string;\n previewUrl: string;\n previewFaceOrder: ViewerCubeFace[];\n};\nexport type SphereViewerConfig = {\n type: \"sphereTile\";\n multires: { tileSize: number; levels: { width: number; height: number }[] };\n urlTemplate: string;\n previewUrl: string;\n indexBase: 0 | 1;\n};\nexport type ViewerConfig = CubemapViewerConfig | SphereViewerConfig;\nexport type ViewerDocument = ViewerConfig & { schemaVersion: 1 };\n\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nexport function requiredString(value: unknown, field: string): string {\n if (typeof value !== \"string\" || !value.trim())\n throw new Error(`${field}: expected a nonempty string`);\n return value;\n}\n\nfunction positive(value: unknown, field: string): number {\n if (typeof value !== \"number\" || !Number.isSafeInteger(value) || value <= 0)\n throw new Error(`${field}: expected a positive safe integer`);\n return value;\n}\n\nexport function validateViewerConfig(value: unknown): ViewerConfig {\n if (!isRecord(value)) throw new Error(\"viewerConfig: expected an object\");\n if (value.type !== \"tile\" && value.type !== \"sphereTile\")\n throw new Error(\"type: expected tile or sphereTile\");\n if (!isRecord(value.multires))\n throw new Error(\"multires: expected an object\");\n const tileSize = positive(value.multires.tileSize, \"multires.tileSize\");\n if (tileSize > 8192) throw new Error(\"multires.tileSize: maximum is 8192\");\n const input = value.multires.levels;\n if (!Array.isArray(input) || input.length === 0 || input.length > 64)\n throw new Error(\"multires.levels: expected 1 to 64 levels\");\n const urlTemplate = requiredString(value.urlTemplate, \"urlTemplate\");\n const previewUrl = requiredString(value.previewUrl, \"previewUrl\");\n if (/%/.test(urlTemplate.replace(/%s|%l|%0*[hxucvywr]/g, \"\")))\n throw new Error(\"urlTemplate: unsupported placeholder\");\n if (value.type === \"tile\") {\n const levels = input.map((level, i) =>\n positive(level, `multires.levels[${i}]`)\n );\n if (levels.some((level, i) => i > 0 && level <= levels[i - 1]!))\n throw new Error(\"multires.levels: face sizes must increase\");\n const order = value.previewFaceOrder;\n if (\n !Array.isArray(order) ||\n order.length !== 6 ||\n ![\"f\", \"r\", \"b\", \"l\", \"u\", \"d\"].every((face) => order.includes(face))\n )\n throw new Error(\"previewFaceOrder: expected six unique cube faces\");\n return {\n type: \"tile\",\n multires: { tileSize, levels },\n urlTemplate,\n previewUrl,\n previewFaceOrder: [...order] as ViewerCubeFace[],\n };\n }\n if (urlTemplate.includes(\"%s\"))\n throw new Error(\"urlTemplate: sphere has no cube face\");\n if (value.indexBase !== 0 && value.indexBase !== 1)\n throw new Error(\"indexBase: expected 0 or 1\");\n const levels = input.map((level: unknown, i) => {\n if (!isRecord(level))\n throw new Error(`multires.levels[${i}]: expected dimensions`);\n const width = positive(level.width, `multires.levels[${i}].width`);\n const height = positive(level.height, `multires.levels[${i}].height`);\n if (Math.abs(width - 2 * height) > 2)\n throw new Error(`multires.levels[${i}]: expected a full 2:1 panorama`);\n return { width, height };\n });\n if (\n levels.some(\n (level, i) =>\n i > 0 &&\n (level.width <= levels[i - 1]!.width ||\n level.height <= levels[i - 1]!.height)\n )\n )\n throw new Error(\"multires.levels: dimensions must increase\");\n return {\n type: \"sphereTile\",\n multires: { tileSize, levels },\n urlTemplate,\n previewUrl,\n indexBase: value.indexBase,\n };\n}\n","import { resolveAssetUrl } from \"../asset-url\";\nimport type {\n TileAddress,\n TileMultiresConfig,\n} from \"./types\";\n\nfunction positiveInteger(value: number, name: string): number {\n if (!Number.isFinite(value) || value <= 0 || !Number.isInteger(value)) {\n throw new Error(`${name} must be a positive integer, received ${String(value)}`);\n }\n return value;\n}\n\nfunction ascendingLevels(levels: number[]): number[] {\n for (let index = 1; index < levels.length; index += 1) {\n if (levels[index]! <= levels[index - 1]!) {\n throw new Error(\"multires face sizes must be strictly ascending\");\n }\n }\n return levels;\n}\n\nexport function parseMultires(\n multires: string | TileMultiresConfig,\n): TileMultiresConfig {\n if (typeof multires !== \"string\") {\n const tileSize = positiveInteger(multires.tileSize, \"multires.tileSize\");\n if (multires.levels.length === 0) {\n throw new Error(\"multires.levels must contain at least one face size\");\n }\n const levels = ascendingLevels(\n multires.levels.map((level, index) =>\n positiveInteger(level, `multires.levels[${index}]`),\n ),\n );\n return { tileSize, levels };\n }\n\n const values = multires.split(\",\").map((part) => Number(part.trim()));\n\n if (values.length < 2 || values.some((value) => !Number.isFinite(value))) {\n throw new Error(\n \"multires must contain a tile size followed by at least one face size\",\n );\n }\n\n const tileSize = positiveInteger(values[0]!, \"multires tile size\");\n const levels = ascendingLevels(\n values.slice(1).map((level, index) =>\n positiveInteger(level, `multires level ${index + 1}`),\n ),\n );\n return { tileSize, levels };\n}\n\nexport const DEFAULT_TILE_URL_TEMPLATE = \"tiles/%s/l%l/%v/l%l_%s_%h_%v.webp\";\n\nexport function buildDefaultTileUrlTemplate(): string {\n return DEFAULT_TILE_URL_TEMPLATE;\n}\n\nexport function resolveRelativeTileUrl(\n baseUrl: string,\n relativePath: string,\n): string {\n return resolveAssetUrl(baseUrl, relativePath);\n}\n\nexport function resolveTemplateUrl(\n template: string,\n address: Pick<TileAddress, \"face\" | \"level\" | \"row\" | \"col\">,\n): string {\n return template\n .replace(/%s/g, address.face)\n .replace(/%l/g, String(address.level))\n .replace(/%(0*)([hxucvywr])/g, (_match, zeroes: string, placeholder: string) => {\n const value = \"hxuc\".includes(placeholder)\n ? address.col\n : address.row;\n return String(value).padStart(zeroes.length + 1, \"0\");\n });\n}\n","import {\n isRecord,\n validateViewerConfig,\n type ViewerConfig,\n} from \"../../../../shared/viewer-config\";\nimport type { TileScene, SphereTileScene } from \"../scenes\";\nimport type { TileAddress } from \"../tile/types\";\nimport type { SphereTileAddress } from \"../sphere-tile/types\";\nimport { resolveTemplateUrl } from \"../tile/multires\";\nimport { PanoDataError, aborted } from \"./errors\";\n\nexport type AssetUrlContext = {\n defaultUrl: string;\n kind: \"tile\" | \"preview\" | \"hotspot\";\n sceneId: string;\n hotspotId?: string;\n};\nexport type AssetUrlResolver = (\n path: string,\n context: AssetUrlContext\n) => string;\nexport type JsonRequestOptions = {\n requestInit?: Pick<RequestInit, \"headers\" | \"credentials\" | \"signal\">;\n};\nexport type SceneFromViewerConfigOptions = {\n id: string;\n baseUrl: string;\n resolveAssetUrl?: AssetUrlResolver;\n};\nexport type LoadSceneFromJsonOptions = Omit<\n SceneFromViewerConfigOptions,\n \"baseUrl\"\n> &\n JsonRequestOptions & { baseUrl?: string };\n\n/** URL resolution is intentionally independent of React and browser globals on the server. */\nexport function documentUrl(input: string): string {\n try {\n const url = new URL(\n input,\n typeof document === \"undefined\" ? undefined : document.baseURI\n );\n if (url.protocol !== \"http:\" && url.protocol !== \"https:\")\n throw new Error(\"Use HTTP(S)\");\n return url.href;\n } catch (cause) {\n throw new PanoDataError(\n \"INVALID_OPTIONS\",\n \"Expected an HTTP(S) URL; Node.js requires an absolute URL\",\n { cause }\n );\n }\n}\n\nexport function directoryUrl(input: string): string {\n const url = new URL(input);\n url.search = \"\";\n url.hash = \"\";\n if (!url.pathname.endsWith(\"/\")) url.pathname += \"/\";\n return url.href;\n}\n\nexport function resolveResource(baseUrl: string, path: string): string {\n try {\n const url = new URL(path, directoryUrl(baseUrl));\n if (![\"http:\", \"https:\", \"blob:\", \"data:\"].includes(url.protocol))\n throw new Error(\"Unsupported resource URL protocol\");\n return url.href;\n } catch (cause) {\n throw new PanoDataError(\n \"INVALID_CONFIG\",\n `Invalid resource path: ${path}`,\n { cause }\n );\n }\n}\n\nexport function mapResource(\n path: string,\n context: AssetUrlContext,\n resolver?: AssetUrlResolver\n): string {\n let result: string;\n try {\n result = resolver ? resolver(path, context) : context.defaultUrl;\n } catch (cause) {\n throw new PanoDataError(\"INVALID_CONFIG\", \"resolveAssetUrl failed\", {\n sceneId: context.sceneId,\n cause,\n });\n }\n if (typeof result !== \"string\" || !result.trim())\n throw new PanoDataError(\n \"INVALID_CONFIG\",\n \"resolveAssetUrl must return a nonempty final URL\",\n { sceneId: context.sceneId }\n );\n // A root path is already final; relative callback results are ambiguous and rejected.\n if (!result.startsWith(\"/\") && !/^(https?:|blob:|data:)/i.test(result))\n throw new PanoDataError(\n \"INVALID_CONFIG\",\n \"resolveAssetUrl must return an absolute URL or a site-root path\",\n { sceneId: context.sceneId }\n );\n return result;\n}\n\nexport function parseConfig(value: unknown): ViewerConfig {\n if (isRecord(value) && value.type !== \"tile\" && value.type !== \"sphereTile\")\n throw new PanoDataError(\n \"UNSUPPORTED_PROJECTION\",\n \"Expected a tile or sphereTile configuration\",\n { field: \"type\" }\n );\n try {\n return validateViewerConfig(value);\n } catch (cause) {\n const message =\n cause instanceof Error ? cause.message : \"Invalid viewer configuration\";\n throw new PanoDataError(\"INVALID_CONFIG\", message, {\n cause,\n field: message.split(\":\")[0],\n });\n }\n}\n\nexport function sceneFromViewerConfig(\n value: unknown,\n options: SceneFromViewerConfigOptions\n): TileScene | SphereTileScene {\n if (\n !options ||\n typeof options.id !== \"string\" ||\n !options.id.trim() ||\n typeof options.baseUrl !== \"string\" ||\n !options.baseUrl.trim()\n )\n throw new PanoDataError(\"INVALID_OPTIONS\", \"id and baseUrl are required\");\n const config = parseConfig(value);\n const baseUrl = directoryUrl(documentUrl(options.baseUrl));\n const resolve = (path: string, kind: \"tile\" | \"preview\") =>\n mapResource(\n path,\n {\n kind,\n sceneId: options.id,\n defaultUrl: resolveResource(baseUrl, path),\n },\n options.resolveAssetUrl\n );\n const previewUrl = resolve(config.previewUrl, \"preview\");\n if (config.type === \"tile\") {\n return {\n ...config,\n id: options.id,\n baseUrl,\n previewUrl,\n ...(options.resolveAssetUrl\n ? {\n resolveTileUrl: (address: TileAddress) =>\n resolve(resolveTemplateUrl(config.urlTemplate, address), \"tile\"),\n }\n : {}),\n };\n }\n return {\n ...config,\n id: options.id,\n baseUrl,\n previewUrl,\n ...(options.resolveAssetUrl\n ? {\n resolveTileUrl: (address: SphereTileAddress) => {\n // Sphere callbacks use logical zero-based addresses; the document controls storage indices.\n const path = resolveTemplateUrl(config.urlTemplate, {\n face: \"f\",\n level: address.level + config.indexBase,\n row: address.row + config.indexBase,\n col: address.col + config.indexBase,\n });\n return resolve(path, \"tile\");\n },\n }\n : {}),\n };\n}\n\nexport async function readJson(\n url: string,\n options: JsonRequestOptions\n): Promise<{ value: unknown; url: string }> {\n const signal = options.requestInit?.signal;\n aborted(signal);\n let response: Response;\n try {\n response = await fetch(url, { ...options.requestInit, method: \"GET\" });\n } catch (cause) {\n aborted(signal);\n throw new PanoDataError(\n \"FETCH_FAILED\",\n \"Could not fetch JSON; check the network and server CORS settings\",\n { cause }\n );\n }\n aborted(signal);\n if (!response.ok)\n throw new PanoDataError(\n \"HTTP_ERROR\",\n `JSON request returned HTTP ${response.status}`,\n { status: response.status }\n );\n try {\n const value: unknown = await response.json();\n aborted(signal);\n return { value, url: response.url || url };\n } catch (cause) {\n aborted(signal);\n throw new PanoDataError(\n \"INVALID_JSON\",\n \"Expected JSON; check for an HTML fallback or login page\",\n { cause }\n );\n }\n}\n\nexport async function loadSceneFromJson(\n url: string,\n options: LoadSceneFromJsonOptions\n): Promise<TileScene | SphereTileScene> {\n if (!options || typeof options.id !== \"string\" || !options.id.trim())\n throw new PanoDataError(\"INVALID_OPTIONS\", \"id is required\");\n const response = await readJson(documentUrl(url), options);\n if (!isRecord(response.value))\n throw new PanoDataError(\n \"INVALID_CONFIG\",\n \"viewer.json must contain an object\"\n );\n if (response.value.schemaVersion !== 1)\n throw new PanoDataError(\n \"UNSUPPORTED_SCHEMA_VERSION\",\n \"Unsupported viewer.json schemaVersion\",\n { field: \"schemaVersion\" }\n );\n return sceneFromViewerConfig(response.value, {\n ...options,\n baseUrl: options.baseUrl ?? new URL(\".\", response.url).href,\n });\n}\n","/** Camera-center limits in degrees. A yaw min greater than max crosses ±180°. */\nexport type PanoViewLimits = {\n yaw?: { min: number; max: number };\n pitch?: { min: number; max: number };\n fov?: { min: number; max: number };\n};\n\ntype Range = { min: number; max: number };\nexport type ResolvedViewLimits = {\n yaw?: Range;\n pitch: Range;\n fov: Range;\n hardPitch: boolean;\n hardFov: boolean;\n};\n\nexport function parseViewLimits(value: unknown): PanoViewLimits | undefined {\n if (value === undefined) return undefined;\n if (!value || typeof value !== \"object\" || Array.isArray(value))\n throw new Error(\"viewLimits: expected an object\");\n const result: PanoViewLimits = {};\n for (const axis of [\"yaw\", \"pitch\", \"fov\"] as const) {\n const input = (value as Record<string, unknown>)[axis];\n if (input === undefined) continue;\n if (!input || typeof input !== \"object\" || Array.isArray(input))\n throw new Error(`viewLimits.${axis}: expected min and max`);\n const { min, max } = input as Record<string, unknown>;\n const lower = axis === \"yaw\" ? -180 : axis === \"pitch\" ? -90 : 1;\n const upper = axis === \"yaw\" ? 180 : axis === \"pitch\" ? 90 : 179;\n if (typeof min !== \"number\" || typeof max !== \"number\" ||\n !Number.isFinite(min) || !Number.isFinite(max) ||\n min < lower || min > upper || max < lower || max > upper)\n throw new Error(`viewLimits.${axis}: expected finite min and max from ${lower} to ${upper}`);\n if (axis !== \"yaw\" && min > max)\n throw new Error(`viewLimits.${axis}: min must not exceed max`);\n result[axis] = { min, max };\n }\n return result;\n}\n\nexport function resolveViewLimits(\n base: PanoViewLimits | undefined,\n scene: PanoViewLimits | undefined,\n minFov = 30,\n maxFov = 100,\n): ResolvedViewLimits {\n const pitch = scene?.pitch ?? base?.pitch;\n const fov = scene?.fov ?? base?.fov;\n return {\n yaw: scene?.yaw ?? base?.yaw,\n pitch: pitch ?? { min: -90, max: 90 },\n fov: fov ?? { min: minFov, max: maxFov },\n hardPitch: pitch !== undefined,\n hardFov: fov !== undefined,\n };\n}\n\nexport function clampViewAxis(value: number, range: Range): number {\n return Math.max(range.min, Math.min(range.max, value));\n}\n\nexport function normalizeViewYaw(yaw: number): number {\n return ((yaw + 180) % 360 + 360) % 360 - 180;\n}\n\nfunction yawWidth(range: Range | undefined): number {\n if (!range || (range.min === -180 && range.max === 180)) return 360;\n return ((range.max - range.min) % 360 + 360) % 360;\n}\n\n/** Offset in the allowed arc; outside points use the nearest boundary (ties use min). */\nfunction yawOffset(yaw: number, range: Range): number {\n const width = yawWidth(range);\n const offset = ((yaw - range.min) % 360 + 360) % 360;\n if (offset <= width) return offset;\n return offset - width < 360 - offset ? width : 0;\n}\n\nexport function constrainViewYaw(yaw: number, range?: Range): number {\n if (yawWidth(range) === 360) return normalizeViewYaw(yaw);\n return normalizeViewYaw(range!.min + yawOffset(yaw, range!));\n}\n\n/** Clamp relative input before wrapping so a large drag cannot jump across a forbidden arc. */\nexport function applyLimitedYawDelta(yaw: number, delta: number, range?: Range): number {\n const width = yawWidth(range);\n if (width === 360) return normalizeViewYaw(yaw + delta);\n const offset = clampViewAxis(yawOffset(yaw, range!) + delta, { min: 0, max: width });\n return normalizeViewYaw(range!.min + offset);\n}\n\n/** Interpolate inside the allowed arc even when the shorter path leaves it. */\nexport function limitedYawDelta(from: number, to: number, range?: Range, shortestPath = true): number {\n if (yawWidth(range) === 360)\n return shortestPath ? normalizeViewYaw(to - from) : to - from;\n return yawOffset(to, range!) - yawOffset(from, range!);\n}\n","import { isRecord, requiredString } from \"../../../../shared/viewer-config\";\nimport { PanoDataError } from \"./errors\";\nimport { resolveResource } from \"./viewer\";\n\nexport type ProjectPopupBlock = { id: string } & (\n | { type: \"text\"; text: string }\n | { type: \"image\"; src: string; alt?: string }\n | { type: \"video\"; src: string; poster?: string }\n | { type: \"audio\"; src: string }\n);\nexport type ProjectPopupDefinition = {\n id: string;\n title: string;\n blocks: ProjectPopupBlock[];\n};\nexport type PopupAssetUrlContext = {\n defaultUrl: string;\n popupId: string;\n blockId: string;\n field: \"src\" | \"poster\";\n};\nexport type PopupAssetUrlResolver = (path: string, context: PopupAssetUrlContext) => string;\n\nexport function parsePopups(value: unknown, draft = false): ProjectPopupDefinition[] | undefined {\n if (value === undefined) return undefined;\n try {\n if (!Array.isArray(value)) throw new Error(\"popups: expected an array\");\n const ids = new Set<string>();\n const string = (input: unknown, field: string, allowEmpty = false) => {\n if (typeof input !== \"string\" || (!allowEmpty && !input.trim()))\n throw new Error(`${field}: expected a ${allowEmpty ? \"string\" : \"nonempty string\"}`);\n return input;\n };\n return value.map((entry, index) => {\n const field = `popups[${index}]`;\n if (!isRecord(entry)) throw new Error(`${field}: expected an object`);\n const id = requiredString(entry.id, `${field}.id`);\n if (ids.has(id)) throw new Error(`${field}.id: duplicate popup ID`);\n ids.add(id);\n const title = string(entry.title, `${field}.title`, draft);\n if (!Array.isArray(entry.blocks)) throw new Error(`${field}.blocks: expected an array`);\n const blockIds = new Set<string>();\n const blocks = entry.blocks.map((block, i): ProjectPopupBlock => {\n const path = `${field}.blocks[${i}]`;\n if (!isRecord(block)) throw new Error(`${path}: expected an object`);\n const id = requiredString(block.id, `${path}.id`);\n if (blockIds.has(id)) throw new Error(`${path}.id: duplicate block ID`);\n blockIds.add(id);\n if (block.type === \"text\") return { id, type: \"text\", text: string(block.text, `${path}.text`, true) };\n const src = string(block.src, `${path}.src`, draft);\n if (src) resolveResource(\"https://popup.invalid/\", src);\n if (block.type === \"image\") return {\n id, type: \"image\", src,\n ...(block.alt === undefined ? {} : { alt: string(block.alt, `${path}.alt`, true) }),\n };\n if (block.type === \"audio\") return { id, type: \"audio\", src };\n if (block.type === \"video\") {\n const poster = block.poster === undefined ? undefined : string(block.poster, `${path}.poster`, true);\n if (poster) resolveResource(\"https://popup.invalid/\", poster);\n return { id, type: \"video\", src, ...(poster ? { poster } : {}) };\n }\n throw new Error(`${path}.type: unsupported content block`);\n });\n return { id, title, blocks };\n });\n } catch (cause) {\n const message = cause instanceof Error ? cause.message : \"Invalid popup content\";\n throw new PanoDataError(\"INVALID_PROJECT\", message, { field: message.split(\":\")[0], cause });\n }\n}\n\nexport function resolveProjectPopupAssets(\n popup: ProjectPopupDefinition,\n baseUrl: string,\n resolver?: PopupAssetUrlResolver,\n): ProjectPopupDefinition {\n return { ...popup, blocks: popup.blocks.map((block) => {\n if (block.type === \"text\") return { ...block };\n const resolve = (path: string, field: \"src\" | \"poster\") => {\n if (!path) throw new PanoDataError(\"INVALID_PROJECT\", `${popup.id}/${block.id}.${field}: choose a resource`);\n const context = { defaultUrl: resolveResource(baseUrl, path), popupId: popup.id, blockId: block.id, field };\n const result = resolver ? resolver(path, context) : context.defaultUrl;\n if (typeof result !== \"string\" || (!result.startsWith(\"/\") && !/^(https?:|blob:|data:)/i.test(result)))\n throw new PanoDataError(\"INVALID_CONFIG\", \"resolvePopupAssetUrl must return an absolute URL or a site-root path\");\n return result;\n };\n return { ...block, src: resolve(block.src, \"src\"), ...(block.type === \"video\" && block.poster ? { poster: resolve(block.poster, \"poster\") } : {}) };\n }) };\n}\n","/** Resolve image URLs inside CSS cursor values without changing keywords or hotspot coordinates. */\nexport function mapCursorAssets(\n cursor: string,\n resolve: (path: string) => string,\n): string {\n return cursor.replace(\n /url\\(\\s*(?:\"((?:\\\\.|[^\"\\\\])*)\"|'((?:\\\\.|[^'\\\\])*)'|((?:\\\\.|[^)\\\\])*?))\\s*\\)/gi,\n (\n _match,\n double: string | undefined,\n single: string | undefined,\n bare: string | undefined,\n ) => {\n const path = (double ?? single ?? bare ?? \"\").replace(\n /\\\\([\\da-f]{1,6}\\s?|.)/gi,\n (_escape, value: string) =>\n /^[\\da-f]/i.test(value)\n ? String.fromCodePoint(\n Math.min(parseInt(value.trim(), 16), 0x10ffff),\n )\n : value,\n );\n return `url(${JSON.stringify(resolve(path))})`;\n },\n );\n}\n\nexport function cursorImage(cursor: string | undefined): string | undefined {\n let image: string | undefined;\n if (cursor)\n mapCursorAssets(cursor, (path) => {\n image ??= path;\n return path;\n });\n return image;\n}\n\nexport function imageCursor(path: string): string {\n return `url(${JSON.stringify(path)}) 0 0, pointer`;\n}\n","import { mapCursorAssets } from \"../../../../shared/cursor-assets\";\nimport { isRecord, requiredString } from \"../../../../shared/viewer-config\";\nimport type { HotspotDefinition } from \"../hotspot/definitions\";\nimport type { PanoViewerState } from \"../types\";\nimport type { HotspotPosition } from \"../hotspot/types\";\nimport { PanoDataError } from \"./errors\";\nimport { mapResource, resolveResource, type AssetUrlResolver } from \"./viewer\";\n\nexport type JsonValue = null | boolean | number | string | JsonValue[] | JsonObject;\nexport type JsonObject = { [key: string]: JsonValue };\nexport const projectHotspotTriggers = [\"click\", \"pointerenter\", \"pointerleave\"] as const;\nexport type ProjectHotspotTrigger = typeof projectHotspotTriggers[number];\nexport type ProjectCustomHotspotAction = { type: \"custom\"; actionId: string; params?: JsonObject };\nexport function hotspotAction(hotspot: ProjectHotspotDefinition, trigger: ProjectHotspotTrigger) {\n return hotspot.events?.[trigger] ?? (trigger === \"click\" ? hotspot.action : undefined);\n}\nexport function setHotspotAction(hotspot: ProjectHotspotDefinition, trigger: ProjectHotspotTrigger, action?: ProjectHotspotAction): ProjectHotspotDefinition {\n const events = { ...hotspot.events };\n const next: ProjectHotspotDefinition = { ...hotspot, events };\n if (trigger === \"click\") delete next.action;\n if (action) events[trigger] = action;\n else delete events[trigger];\n if (!Object.keys(events).length) delete next.events;\n return next;\n}\nfunction jsonValue(value: unknown, seen = new Set<object>()): JsonValue {\n if (value === null || typeof value === \"string\" || typeof value === \"boolean\") return value;\n if (typeof value === \"number\" && Number.isFinite(value)) return value;\n if (typeof value !== \"object\" || !value || seen.has(value)) throw new Error(\"params: expected JSON data\");\n if (!Array.isArray(value) && Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null) throw new Error(\"params: expected JSON data\");\n seen.add(value);\n const result: JsonValue = Array.isArray(value) ? value.map(item => jsonValue(item, seen)) : Object.fromEntries(Object.entries(value).map(([key, item]) => [key, jsonValue(item, seen)]));\n seen.delete(value);\n return result;\n}\nfunction parseAction(action: unknown): ProjectHotspotAction {\n if (!isRecord(action)) throw new Error(\"action: expected an object\");\n if (action.type === \"scene\") return { type: \"scene\", sceneId: requiredString(action.sceneId, \"action.sceneId\") };\n if (action.type === \"popup\") return { type: \"popup\", popupId: requiredString(action.popupId, \"action.popupId\") };\n if (action.type === \"custom\") {\n if (action.params !== undefined && (!isRecord(action.params) || Array.isArray(action.params))) throw new Error(\"action.params: expected an object\");\n return { type: \"custom\", actionId: requiredString(action.actionId, \"action.actionId\"), ...(action.params === undefined ? {} : { params: jsonValue(action.params) as JsonObject }) };\n }\n if (action.type === \"view\") {\n const position = parsePosition(action.view, \"action.view\");\n const fov = finite((action.view as Record<string, unknown>).fov, \"action.view.fov\");\n if (fov <= 0 || fov >= 180) throw new Error(\"action.view.fov: expected 0 < fov < 180\");\n const duration = action.duration === undefined ? undefined : finite(action.duration, \"action.duration\");\n if (duration !== undefined && duration < 0) throw new Error(\"action.duration: expected a nonnegative number\");\n return { type: \"view\", view: { ...position, fov }, ...(duration === undefined ? {} : { duration }) };\n }\n throw new Error(\"action.type: unsupported action\");\n}\n\nexport type ProjectHotspotAction =\n | ProjectCustomHotspotAction\n | { type: \"scene\"; sceneId: string }\n | { type: \"view\"; view: PanoViewerState; duration?: number }\n | { type: \"popup\"; popupId: string };\n\nexport type ProjectHotspotDefinition = HotspotDefinition & {\n /** Legacy click fallback. events.click takes precedence. */\n action?: ProjectHotspotAction;\n events?: Partial<Record<ProjectHotspotTrigger, ProjectHotspotAction>>;\n};\n\nconst common = [\n \"label\",\n \"visible\",\n \"interactive\",\n \"pointerEvents\",\n \"cursor\",\n \"renderOrder\",\n \"tooltip\",\n \"tooltipTrigger\",\n \"tooltipPlacement\",\n \"tooltipOffset\",\n \"tooltipAppearance\",\n];\nconst point = [\n \"position\",\n \"width\",\n \"height\",\n \"scale\",\n \"mode\",\n \"distance\",\n \"scaleMode\",\n \"referenceFov\",\n \"rotation\",\n \"opacity\",\n];\nconst fields = {\n image: [\"src\"],\n graphic: [\"graphic\"],\n sequence: [\"src\", \"frameCount\", \"frameDirection\", \"playing\", \"fps\", \"loop\"],\n video: [\n \"src\",\n \"poster\",\n \"playing\",\n \"loop\",\n \"muted\",\n \"volume\",\n \"playsInline\",\n \"preload\",\n \"crossOrigin\",\n ],\n audio: [\n \"src\",\n \"format\",\n \"playing\",\n \"loop\",\n \"muted\",\n \"volume\",\n \"pauseWhenHidden\",\n \"range\",\n \"icon\",\n \"playingIcon\",\n \"marker\",\n \"crossOrigin\",\n ],\n text: [\n \"text\",\n \"fontFamily\",\n \"fontSize\",\n \"fontWeight\",\n \"fontStyle\",\n \"color\",\n \"background\",\n \"backgroundOpacity\",\n \"padding\",\n \"align\",\n \"verticalAlign\",\n \"whiteSpace\",\n \"lineHeight\",\n \"borderRadius\",\n \"stroke\",\n \"strokeWidth\",\n ],\n iframe: [\n \"src\",\n \"title\",\n \"sandbox\",\n \"allow\",\n \"referrerPolicy\",\n \"loading\",\n \"pointerPolicy\",\n \"background\",\n ],\n polygon: [\n \"vertices\",\n \"fill\",\n \"fillOpacity\",\n \"stroke\",\n \"strokeWidth\",\n \"strokeOpacity\",\n \"strokeDashSize\",\n \"strokeGapSize\",\n ],\n polyline: [\n \"vertices\",\n \"stroke\",\n \"strokeWidth\",\n \"strokeOpacity\",\n \"strokeDashSize\",\n \"strokeGapSize\",\n ],\n} satisfies Record<HotspotDefinition[\"type\"], string[]>;\nconst booleanFields = new Set([\n \"visible\",\n \"interactive\",\n \"playing\",\n \"loop\",\n \"muted\",\n \"playsInline\",\n \"pauseWhenHidden\",\n \"marker\",\n]);\nconst numberFields = new Set([\n \"renderOrder\",\n \"tooltipOffset\",\n \"width\",\n \"height\",\n \"scale\",\n \"distance\",\n \"referenceFov\",\n \"rotation\",\n \"opacity\",\n \"frameCount\",\n \"fps\",\n \"volume\",\n \"range\",\n \"fontSize\",\n \"backgroundOpacity\",\n \"padding\",\n \"lineHeight\",\n \"borderRadius\",\n \"strokeWidth\",\n \"fillOpacity\",\n \"strokeOpacity\",\n \"strokeDashSize\",\n \"strokeGapSize\",\n]);\nconst positiveFields = new Set([\n \"width\",\n \"height\",\n \"scale\",\n \"distance\",\n \"referenceFov\",\n \"frameCount\",\n \"fps\",\n \"fontSize\",\n \"lineHeight\",\n]);\nconst enums: Record<string, readonly string[]> = {\n pointerEvents: [\"auto\", \"none\"],\n tooltipTrigger: [\"always\", \"hover\", \"click\"],\n tooltipPlacement: [\"top\", \"bottom\", \"left\", \"right\"],\n mode: [\"surface\", \"billboard\"],\n scaleMode: [\"fov\", \"fixed\"],\n frameDirection: [\"horizontal\", \"vertical\"],\n preload: [\"none\", \"metadata\", \"auto\"],\n crossOrigin: [\"\", \"anonymous\", \"use-credentials\"],\n fontStyle: [\"normal\", \"italic\"],\n align: [\"left\", \"center\", \"right\"],\n verticalAlign: [\"top\", \"middle\", \"bottom\"],\n whiteSpace: [\"normal\", \"nowrap\"],\n loading: [\"eager\", \"lazy\"],\n pointerPolicy: [\"hotspot\", \"content\"],\n referrerPolicy: [\n \"\",\n \"no-referrer\",\n \"no-referrer-when-downgrade\",\n \"origin\",\n \"origin-when-cross-origin\",\n \"same-origin\",\n \"strict-origin\",\n \"strict-origin-when-cross-origin\",\n \"unsafe-url\",\n ],\n};\n\nfunction finite(value: unknown, field: string): number {\n if (typeof value !== \"number\" || !Number.isFinite(value))\n throw new Error(`${field}: expected a finite number`);\n return value;\n}\n\nexport function parsePosition(value: unknown, field: string): HotspotPosition {\n if (!isRecord(value)) throw new Error(`${field}: expected yaw and pitch`);\n const yaw = finite(value.yaw, `${field}.yaw`);\n const pitch = finite(value.pitch, `${field}.pitch`);\n if (Math.abs(pitch) > 90)\n throw new Error(`${field}.pitch: expected -90 to 90`);\n return { yaw, pitch };\n}\n\nfunction parseGraphic(value: unknown): Record<string, unknown> {\n if (!isRecord(value)) throw new Error(\"graphic: expected an object\");\n const kind = requiredString(value.kind, \"graphic.kind\");\n if (\n ![\n \"circle\",\n \"triangle\",\n \"diamond\",\n \"star\",\n \"arrow\",\n \"rectangle\",\n \"ring\",\n \"svg\",\n \"path\",\n ].includes(kind)\n )\n throw new Error(\"graphic.kind: unsupported graphic\");\n const result: Record<string, unknown> = { kind };\n for (const key of [\"fill\", \"stroke\"]) {\n if (value[key] !== undefined)\n result[key] = requiredString(value[key], `graphic.${key}`);\n }\n for (const key of [\"strokeWidth\", \"cornerRadius\", \"innerRadius\"]) {\n if (value[key] !== undefined)\n result[key] = finite(value[key], `graphic.${key}`);\n }\n if (kind === \"svg\") result.src = requiredString(value.src, \"graphic.src\");\n if (kind === \"path\") {\n result.path = requiredString(value.path, \"graphic.path\");\n if (!Array.isArray(value.viewBox) || value.viewBox.length !== 4)\n throw new Error(\"graphic.viewBox: expected four numbers\");\n const viewBox = value.viewBox.map((n, i) =>\n finite(n, `graphic.viewBox[${i}]`)\n );\n if (viewBox[2]! <= 0 || viewBox[3]! <= 0)\n throw new Error(\"graphic.viewBox: width and height must be positive\");\n result.viewBox = viewBox;\n }\n return result;\n}\n\nfunction parseTooltip(value: unknown): unknown {\n if (typeof value === \"string\") return value;\n if (!isRecord(value)) throw new Error(\"tooltip: expected text or an object\");\n const result: Record<string, string> = {};\n for (const key of [\"text\", \"image\", \"imageAlt\"]) {\n if (value[key] !== undefined) {\n if (typeof value[key] !== \"string\")\n throw new Error(`tooltip.${key}: expected a string`);\n result[key] = value[key];\n }\n }\n return result;\n}\n\nfunction parseAppearance(value: unknown): Record<string, string | number> {\n if (!isRecord(value))\n throw new Error(\"tooltipAppearance: expected an object\");\n const result: Record<string, string | number> = {};\n for (const key of [\n \"background\",\n \"color\",\n \"border\",\n \"borderRadius\",\n \"shadow\",\n \"padding\",\n \"fontSize\",\n \"fontFamily\",\n \"lineHeight\",\n \"letterSpacing\",\n ]) {\n const item = value[key];\n if (item === undefined) continue;\n if (\n [\"background\", \"color\", \"border\", \"shadow\", \"fontFamily\"].includes(key) &&\n typeof item !== \"string\"\n )\n throw new Error(`tooltipAppearance.${key}: expected a string`);\n if (\n typeof item !== \"string\" &&\n (typeof item !== \"number\" || !Number.isFinite(item))\n )\n throw new Error(\n `tooltipAppearance.${key}: expected a string or finite number`\n );\n result[key] = item;\n }\n return result;\n}\n\nexport function parseHotspot(\n value: unknown,\n sceneId: string,\n field: string\n): ProjectHotspotDefinition {\n try {\n if (!isRecord(value)) throw new Error(\"expected a hotspot object\");\n const type = requiredString(value.type, \"type\");\n if (!Object.prototype.hasOwnProperty.call(fields, type))\n throw new Error(\"type: unsupported hotspot type\");\n const kind = type as HotspotDefinition[\"type\"];\n const result: Record<string, unknown> = {\n type,\n id: requiredString(value.id, \"id\"),\n };\n const isPath = kind === \"polygon\" || kind === \"polyline\";\n const allowed = [...common, ...(isPath ? [] : point), ...fields[kind]];\n for (const key of allowed) {\n const item = value[key];\n if (item === undefined) continue;\n if (key === \"position\") result[key] = parsePosition(item, key);\n else if (key === \"vertices\") {\n if (!Array.isArray(item) || item.length < (kind === \"polygon\" ? 3 : 2))\n throw new Error(\"vertices: not enough points\");\n result[key] = item.map((p, i) => parsePosition(p, `vertices[${i}]`));\n } else if (key === \"graphic\") result[key] = parseGraphic(item);\n else if (key === \"tooltip\") result[key] = parseTooltip(item);\n else if (key === \"tooltipAppearance\") result[key] = parseAppearance(item);\n else if (booleanFields.has(key)) {\n if (typeof item !== \"boolean\")\n throw new Error(`${key}: expected a boolean`);\n result[key] = item;\n } else if (numberFields.has(key)) {\n const n = finite(item, key);\n if (positiveFields.has(key) && n <= 0)\n throw new Error(`${key}: expected a positive number`);\n if (key === \"frameCount\" && !Number.isSafeInteger(n))\n throw new Error(\"frameCount: expected an integer\");\n if (\n [\n \"opacity\",\n \"fillOpacity\",\n \"strokeOpacity\",\n \"volume\",\n \"backgroundOpacity\",\n ].includes(key) &&\n (n < 0 || n > 1)\n )\n throw new Error(`${key}: expected 0 to 1`);\n result[key] = n;\n } else if (key === \"fontWeight\" && typeof item === \"number\")\n result[key] = finite(item, key);\n else if (\n (key === \"src\" || key === \"format\") &&\n kind === \"audio\" &&\n Array.isArray(item)\n ) {\n if (!item.length)\n throw new Error(`${key}: expected audio ${key === \"src\" ? \"sources\" : \"formats\"}`);\n result[key] = item.map((entry, i) => requiredString(entry, `${key}[${i}]`));\n } else {\n if (typeof item !== \"string\")\n throw new Error(`${key}: expected a string`);\n if (enums[key] && !enums[key].includes(item))\n throw new Error(`${key}: unsupported value`);\n result[key] = item;\n }\n }\n if (!isPath && !result.position) throw new Error(\"position: required\");\n if (isPath && !result.vertices) throw new Error(\"vertices: required\");\n if (\n [\"image\", \"sequence\", \"video\", \"audio\", \"iframe\"].includes(kind) &&\n !(typeof result.src === \"string\"\n ? result.src.trim()\n : Array.isArray(result.src))\n )\n throw new Error(\"src: required\");\n if (kind === \"graphic\" && !result.graphic)\n throw new Error(\"graphic: required\");\n if (kind === \"text\" && typeof result.text !== \"string\")\n throw new Error(\"text: required\");\n if (kind === \"sequence\" && !result.frameCount)\n throw new Error(\"frameCount: required\");\n if (value.action !== undefined) result.action = parseAction(value.action);\n if (value.events !== undefined) {\n if (!isRecord(value.events)) throw new Error(\"events: expected an object\");\n const events: Partial<Record<ProjectHotspotTrigger, ProjectHotspotAction>> = {};\n for (const key of Object.keys(value.events)) {\n if (!projectHotspotTriggers.includes(key as ProjectHotspotTrigger)) throw new Error(`events.${key}: unsupported trigger`);\n try { events[key as ProjectHotspotTrigger] = parseAction(value.events[key]); }\n catch (error) { throw new Error(`events.${key}.${error instanceof Error ? error.message : \"invalid action\"}`); }\n }\n result.events = events;\n }\n return result as ProjectHotspotDefinition;\n } catch (cause) {\n const detail = cause instanceof Error ? cause.message : \"Invalid hotspot\";\n throw new PanoDataError(\"INVALID_PROJECT\", `${field}.${detail}`, {\n sceneId,\n field: `${field}.${detail.split(\":\")[0]}`,\n cause,\n });\n }\n}\n\nexport function resolveHotspotAssets(\n hotspot: ProjectHotspotDefinition,\n baseUrl: string,\n sceneId: string,\n resolver?: AssetUrlResolver\n): ProjectHotspotDefinition {\n const resolve = (path: string) =>\n path\n ? mapResource(\n path,\n {\n kind: \"hotspot\",\n sceneId,\n hotspotId: hotspot.id,\n defaultUrl: resolveResource(baseUrl, path),\n },\n resolver\n )\n : path;\n const result = { ...hotspot };\n if (result.cursor) result.cursor = mapCursorAssets(result.cursor, resolve);\n if (result.tooltipAppearance?.background) result.tooltipAppearance = {\n ...result.tooltipAppearance,\n background: mapCursorAssets(result.tooltipAppearance.background, resolve),\n };\n if (\"src\" in result)\n result.src = Array.isArray(result.src)\n ? result.src.map(resolve)\n : resolve(result.src);\n if (\"poster\" in result && result.poster)\n result.poster = resolve(result.poster);\n if (result.type === \"audio\") {\n if (result.icon) result.icon = resolve(result.icon);\n if (result.playingIcon) result.playingIcon = resolve(result.playingIcon);\n }\n if (result.type === \"graphic\" && result.graphic.kind === \"svg\")\n result.graphic = { ...result.graphic, src: resolve(result.graphic.src) };\n if (typeof result.tooltip === \"object\")\n result.tooltip = {\n ...result.tooltip,\n ...(result.tooltip.image ? { image: resolve(result.tooltip.image) } : {}),\n };\n return result;\n}\n","import { parseViewLimits, type PanoViewLimits } from \"../view-limits\";\nimport { parsePopups, resolveProjectPopupAssets, type ProjectPopupDefinition, type PopupAssetUrlResolver } from \"./popups\";\nimport {\n isRecord,\n requiredString,\n type ViewerConfig,\n} from \"../../../../shared/viewer-config\";\nimport type { TileScene, SphereTileScene } from \"../scenes\";\nimport type { PanoViewerState } from \"../types\";\nimport { PanoDataError, aborted } from \"./errors\";\nimport {\n parseHotspot,\n projectHotspotTriggers,\n hotspotAction,\n parsePosition,\n resolveHotspotAssets,\n type ProjectHotspotDefinition,\n} from \"./hotspots\";\nimport {\n documentUrl,\n directoryUrl,\n readJson,\n parseConfig,\n resolveResource,\n sceneFromViewerConfig,\n loadSceneFromJson,\n type AssetUrlResolver,\n type JsonRequestOptions,\n} from \"./viewer\";\n\nexport type PanoProjectSceneDefinition = {\n id: string;\n title?: string;\n source: (\n | { viewerUrl: string; viewerConfig?: never }\n | { viewerConfig: ViewerConfig; viewerUrl?: never }\n ) & { baseUrl?: string };\n initialView?: Partial<PanoViewerState>;\n viewLimits?: PanoViewLimits;\n hotspots?: ProjectHotspotDefinition[];\n};\nexport type PanoProjectDefinition = {\n schemaVersion: 1;\n title?: string;\n initialSceneId?: string;\n scenes: PanoProjectSceneDefinition[];\n popups?: ProjectPopupDefinition[];\n};\nexport type LoadedProjectScene = {\n scene: TileScene | SphereTileScene;\n title?: string;\n initialView?: PanoViewerState;\n hotspots: ProjectHotspotDefinition[];\n};\nexport type LoadedPanoProject = {\n title?: string;\n initialSceneId: string;\n scenes: LoadedProjectScene[];\n popups?: ProjectPopupDefinition[];\n};\nexport type LoadPanoProjectOptions = JsonRequestOptions & {\n /** Directory used for project-relative references. Required for object input. */\n baseUrl?: string;\n resolveAssetUrl?: AssetUrlResolver;\n resolvePopupAssetUrl?: PopupAssetUrlResolver;\n};\n\nfunction optionalString(\n record: Record<string, unknown>,\n key: string\n): string | undefined {\n return record[key] === undefined\n ? undefined\n : requiredString(record[key], key);\n}\n\n/** Drafts permit empty scenes and unfinished popup titles/media; loading and export always validate strictly. */\nexport function parsePanoProject(value: unknown, options: { draft?: boolean } = {}): PanoProjectDefinition {\n if (!isRecord(value))\n throw new PanoDataError(\"INVALID_PROJECT\", \"Expected a project object\");\n if (value.schemaVersion !== 1)\n throw new PanoDataError(\n \"UNSUPPORTED_SCHEMA_VERSION\",\n \"Unsupported project schemaVersion\",\n { field: \"schemaVersion\" }\n );\n try {\n const popups = parsePopups(value.popups, options.draft);\n if (!Array.isArray(value.scenes) || (!options.draft && !value.scenes.length))\n throw new Error(\"scenes: expected a nonempty array\");\n const ids = new Set<string>();\n const scenes = value.scenes.map(\n (entry: unknown, index): PanoProjectSceneDefinition => {\n let id: string | undefined;\n const field = `scenes[${index}]`;\n try {\n if (!isRecord(entry)) throw new Error(\"expected a scene object\");\n id = requiredString(entry.id, \"id\");\n if (ids.has(id)) throw new Error(\"id: duplicate scene ID\");\n ids.add(id);\n if (!isRecord(entry.source))\n throw new Error(\"source: expected an object\");\n const src = entry.source;\n if (\n (src.viewerUrl !== undefined) ===\n (src.viewerConfig !== undefined)\n )\n throw new Error(\n \"source: provide exactly one of viewerUrl or viewerConfig\"\n );\n const baseUrl = optionalString(src, \"baseUrl\");\n const source: PanoProjectSceneDefinition[\"source\"] =\n src.viewerUrl !== undefined\n ? {\n viewerUrl: requiredString(src.viewerUrl, \"source.viewerUrl\"),\n baseUrl,\n }\n : { viewerConfig: parseConfig(src.viewerConfig), baseUrl };\n const viewLimits = parseViewLimits(entry.viewLimits);\n let initialView: Partial<PanoViewerState> | undefined;\n if (entry.initialView !== undefined) {\n if (!isRecord(entry.initialView))\n throw new Error(\"initialView: expected an object\");\n const input = entry.initialView;\n const position = parsePosition(\n { yaw: input.yaw ?? 0, pitch: input.pitch ?? 0 },\n \"initialView\"\n );\n const fov = input.fov ?? 75;\n if (\n typeof fov !== \"number\" ||\n !Number.isFinite(fov) ||\n fov <= 0 ||\n fov >= 180\n )\n throw new Error(\n \"initialView.fov: expected a number between 0 and 180\"\n );\n initialView = { ...position, fov };\n }\n if (entry.hotspots !== undefined && !Array.isArray(entry.hotspots))\n throw new Error(\"hotspots: expected an array\");\n const hotspotIds = new Set<string>();\n const hotspots = ((entry.hotspots ?? []) as unknown[]).map(\n (hotspot, i) => {\n const result = parseHotspot(\n hotspot,\n id!,\n `${field}.hotspots[${i}]`\n );\n if (hotspotIds.has(result.id))\n throw new Error(`hotspots[${i}].id: duplicate hotspot ID`);\n hotspotIds.add(result.id);\n return result;\n }\n );\n return {\n id,\n title: optionalString(entry, \"title\"),\n source,\n initialView,\n ...(viewLimits === undefined ? {} : { viewLimits }),\n hotspots,\n };\n } catch (cause) {\n if (cause instanceof PanoDataError && cause.sceneId) throw cause;\n const detail =\n cause instanceof Error ? cause.message : \"Invalid scene\";\n throw new PanoDataError(\n cause instanceof PanoDataError ? cause.code : \"INVALID_PROJECT\",\n `${field}.${detail}`,\n {\n sceneId: id,\n field: `${field}.${\n cause instanceof PanoDataError\n ? `source.viewerConfig.${cause.field ?? \"\"}`\n : detail.split(\":\")[0]\n }`,\n cause,\n }\n );\n }\n }\n );\n const initialSceneId =\n optionalString(value, \"initialSceneId\") ?? scenes[0]?.id;\n if (initialSceneId !== undefined && !ids.has(initialSceneId))\n throw new PanoDataError(\n \"INVALID_REFERENCE\",\n \"initialSceneId: scene does not exist\",\n { field: \"initialSceneId\" }\n );\n for (const [index, scene] of scenes.entries()) {\n for (const [i, hotspot] of (scene.hotspots ?? []).entries()) {\n for (const trigger of projectHotspotTriggers) {\n const action = hotspotAction(hotspot, trigger);\n if (action?.type === \"popup\" && !popups?.some((popup) => popup.id === action.popupId))\n throw new PanoDataError(\"INVALID_REFERENCE\", \"Hotspot target popup does not exist\", {\n sceneId: scene.id, field: `scenes[${index}].hotspots[${i}].${hotspot.events?.[trigger] ? `events.${trigger}` : \"action\"}.popupId`,\n });\n if (action?.type === \"scene\" && !ids.has(action.sceneId))\n throw new PanoDataError(\n \"INVALID_REFERENCE\",\n \"Hotspot target scene does not exist\",\n {\n sceneId: scene.id,\n field: `scenes[${index}].hotspots[${i}].${hotspot.events?.[trigger] ? `events.${trigger}` : \"action\"}.sceneId`,\n }\n );\n }\n }\n }\n return {\n schemaVersion: 1,\n title: optionalString(value, \"title\"),\n initialSceneId,\n scenes,\n ...(popups === undefined ? {} : { popups }),\n };\n } catch (cause) {\n if (cause instanceof PanoDataError) throw cause;\n const message = cause instanceof Error ? cause.message : \"Invalid project\";\n throw new PanoDataError(\"INVALID_PROJECT\", message, {\n cause,\n field: message.split(\":\")[0],\n });\n }\n}\n\nexport async function loadPanoProject(\n source: string | PanoProjectDefinition,\n options: LoadPanoProjectOptions = {}\n): Promise<LoadedPanoProject> {\n aborted(options.requestInit?.signal);\n let definition: PanoProjectDefinition;\n let baseUrl: string;\n if (typeof source === \"string\") {\n const response = await readJson(documentUrl(source), options);\n definition = parsePanoProject(response.value);\n baseUrl = options.baseUrl ?? new URL(\".\", response.url).href;\n } else {\n if (!options.baseUrl)\n throw new PanoDataError(\n \"INVALID_OPTIONS\",\n \"baseUrl is required for project object input\"\n );\n definition = parsePanoProject(source);\n baseUrl = options.baseUrl;\n }\n const root = directoryUrl(documentUrl(baseUrl));\n const controller = new AbortController();\n const signal = options.requestInit?.signal;\n const cancel = () => controller.abort();\n signal?.addEventListener(\"abort\", cancel, { once: true });\n const scenes: LoadedProjectScene[] = new Array(definition.scenes.length);\n let next = 0;\n let failure: PanoDataError | undefined;\n async function worker() {\n while (next < definition.scenes.length && !controller.signal.aborted) {\n const index = next++;\n const item = definition.scenes[index]!;\n try {\n const sourceBase =\n item.source.baseUrl === undefined\n ? undefined\n : resolveResource(root, item.source.baseUrl);\n const sceneOptions = {\n id: item.id,\n resolveAssetUrl: options.resolveAssetUrl,\n };\n const scene =\n item.source.viewerUrl !== undefined\n ? await loadSceneFromJson(\n resolveResource(root, item.source.viewerUrl),\n {\n ...sceneOptions,\n baseUrl: sourceBase,\n requestInit: {\n ...options.requestInit,\n signal: controller.signal,\n },\n }\n )\n : sceneFromViewerConfig(item.source.viewerConfig, {\n ...sceneOptions,\n baseUrl: sourceBase ?? root,\n });\n aborted(controller.signal);\n if (item.viewLimits !== undefined) scene.viewLimits = item.viewLimits;\n scenes[index] = {\n scene,\n title: item.title,\n initialView: item.initialView\n ? { yaw: 0, pitch: 0, fov: 75, ...item.initialView }\n : undefined,\n hotspots: item.hotspots!.map((h) =>\n resolveHotspotAssets(h, root, item.id, options.resolveAssetUrl)\n ),\n };\n } catch (cause) {\n if (!failure) {\n const error =\n cause instanceof PanoDataError\n ? cause\n : new PanoDataError(\n \"INVALID_CONFIG\",\n cause instanceof Error\n ? cause.message\n : \"Could not load scene\",\n { cause }\n );\n const field = `scenes[${index}].${\n error.field ??\n (item.source.viewerUrl !== undefined\n ? \"source.viewerUrl\"\n : \"source.viewerConfig\")\n }`;\n failure = new PanoDataError(\n error.code,\n `Scene ${item.id}: ${error.message}`,\n { status: error.status, sceneId: item.id, field, cause: error }\n );\n }\n controller.abort();\n }\n }\n }\n try {\n aborted(signal);\n await Promise.all(\n Array.from({ length: Math.min(4, scenes.length) }, worker)\n );\n aborted(signal);\n if (failure) throw failure;\n return {\n title: definition.title,\n initialSceneId: definition.initialSceneId!,\n scenes,\n ...(definition.popups === undefined ? {} : { popups: definition.popups.map((popup) => resolveProjectPopupAssets(popup, root, options.resolvePopupAssetUrl)) }),\n };\n } finally {\n signal?.removeEventListener(\"abort\", cancel);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACYO,IAAM,gBAAN,cAA4B,MAAM;AAAA,EAMvC,YACE,MACA,SACA,UAKI,CAAC,GACL;AACA,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,OAAO;AACZ,WAAO,OAAO,MAAM,OAAO;AAAA,EAC7B;AACF;AAEO,SAAS,QAAQ,QAAmC;AACzD,MAAI,QAAQ;AACV,UAAM,IAAI,cAAc,WAAW,uBAAuB;AAC9D;;;ACnBO,SAAS,SAAS,OAAkD;AACzE,SAAO,UAAU,QAAQ,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAEO,SAAS,eAAe,OAAgB,OAAuB;AACpE,MAAI,OAAO,UAAU,YAAY,CAAC,MAAM,KAAK;AAC3C,UAAM,IAAI,MAAM,GAAG,KAAK,8BAA8B;AACxD,SAAO;AACT;AAEA,SAAS,SAAS,OAAgB,OAAuB;AACvD,MAAI,OAAO,UAAU,YAAY,CAAC,OAAO,cAAc,KAAK,KAAK,SAAS;AACxE,UAAM,IAAI,MAAM,GAAG,KAAK,oCAAoC;AAC9D,SAAO;AACT;AAEO,SAAS,qBAAqB,OAA8B;AACjE,MAAI,CAAC,SAAS,KAAK,EAAG,OAAM,IAAI,MAAM,kCAAkC;AACxE,MAAI,MAAM,SAAS,UAAU,MAAM,SAAS;AAC1C,UAAM,IAAI,MAAM,mCAAmC;AACrD,MAAI,CAAC,SAAS,MAAM,QAAQ;AAC1B,UAAM,IAAI,MAAM,8BAA8B;AAChD,QAAM,WAAW,SAAS,MAAM,SAAS,UAAU,mBAAmB;AACtE,MAAI,WAAW,KAAM,OAAM,IAAI,MAAM,oCAAoC;AACzE,QAAM,QAAQ,MAAM,SAAS;AAC7B,MAAI,CAAC,MAAM,QAAQ,KAAK,KAAK,MAAM,WAAW,KAAK,MAAM,SAAS;AAChE,UAAM,IAAI,MAAM,0CAA0C;AAC5D,QAAM,cAAc,eAAe,MAAM,aAAa,aAAa;AACnE,QAAM,aAAa,eAAe,MAAM,YAAY,YAAY;AAChE,MAAI,IAAI,KAAK,YAAY,QAAQ,wBAAwB,EAAE,CAAC;AAC1D,UAAM,IAAI,MAAM,sCAAsC;AACxD,MAAI,MAAM,SAAS,QAAQ;AACzB,UAAMA,UAAS,MAAM;AAAA,MAAI,CAAC,OAAO,MAC/B,SAAS,OAAO,mBAAmB,CAAC,GAAG;AAAA,IACzC;AACA,QAAIA,QAAO,KAAK,CAAC,OAAO,MAAM,IAAI,KAAK,SAASA,QAAO,IAAI,CAAC,CAAE;AAC5D,YAAM,IAAI,MAAM,2CAA2C;AAC7D,UAAM,QAAQ,MAAM;AACpB,QACE,CAAC,MAAM,QAAQ,KAAK,KACpB,MAAM,WAAW,KACjB,CAAC,CAAC,KAAK,KAAK,KAAK,KAAK,KAAK,GAAG,EAAE,MAAM,CAAC,SAAS,MAAM,SAAS,IAAI,CAAC;AAEpE,YAAM,IAAI,MAAM,kDAAkD;AACpE,WAAO;AAAA,MACL,MAAM;AAAA,MACN,UAAU,EAAE,UAAU,QAAAA,QAAO;AAAA,MAC7B;AAAA,MACA;AAAA,MACA,kBAAkB,CAAC,GAAG,KAAK;AAAA,IAC7B;AAAA,EACF;AACA,MAAI,YAAY,SAAS,IAAI;AAC3B,UAAM,IAAI,MAAM,sCAAsC;AACxD,MAAI,MAAM,cAAc,KAAK,MAAM,cAAc;AAC/C,UAAM,IAAI,MAAM,4BAA4B;AAC9C,QAAM,SAAS,MAAM,IAAI,CAAC,OAAgB,MAAM;AAC9C,QAAI,CAAC,SAAS,KAAK;AACjB,YAAM,IAAI,MAAM,mBAAmB,CAAC,wBAAwB;AAC9D,UAAM,QAAQ,SAAS,MAAM,OAAO,mBAAmB,CAAC,SAAS;AACjE,UAAM,SAAS,SAAS,MAAM,QAAQ,mBAAmB,CAAC,UAAU;AACpE,QAAI,KAAK,IAAI,QAAQ,IAAI,MAAM,IAAI;AACjC,YAAM,IAAI,MAAM,mBAAmB,CAAC,iCAAiC;AACvE,WAAO,EAAE,OAAO,OAAO;AAAA,EACzB,CAAC;AACD,MACE,OAAO;AAAA,IACL,CAAC,OAAO,MACN,IAAI,MACH,MAAM,SAAS,OAAO,IAAI,CAAC,EAAG,SAC7B,MAAM,UAAU,OAAO,IAAI,CAAC,EAAG;AAAA,EACrC;AAEA,UAAM,IAAI,MAAM,2CAA2C;AAC7D,SAAO;AAAA,IACL,MAAM;AAAA,IACN,UAAU,EAAE,UAAU,OAAO;AAAA,IAC7B;AAAA,IACA;AAAA,IACA,WAAW,MAAM;AAAA,EACnB;AACF;;;AChCO,SAAS,mBACd,UACA,SACQ;AACR,SAAO,SACJ,QAAQ,OAAO,QAAQ,IAAI,EAC3B,QAAQ,OAAO,OAAO,QAAQ,KAAK,CAAC,EACpC,QAAQ,sBAAsB,CAAC,QAAQ,QAAgB,gBAAwB;AAC9E,UAAM,QAAQ,OAAO,SAAS,WAAW,IACrC,QAAQ,MACR,QAAQ;AACZ,WAAO,OAAO,KAAK,EAAE,SAAS,OAAO,SAAS,GAAG,GAAG;AAAA,EACtD,CAAC;AACL;;;AC7CO,SAAS,YAAY,OAAuB;AACjD,MAAI;AACF,UAAM,MAAM,IAAI;AAAA,MACd;AAAA,MACA,OAAO,aAAa,cAAc,SAAY,SAAS;AAAA,IACzD;AACA,QAAI,IAAI,aAAa,WAAW,IAAI,aAAa;AAC/C,YAAM,IAAI,MAAM,aAAa;AAC/B,WAAO,IAAI;AAAA,EACb,SAAS,OAAO;AACd,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,MACA,EAAE,MAAM;AAAA,IACV;AAAA,EACF;AACF;AAEO,SAAS,aAAa,OAAuB;AAClD,QAAM,MAAM,IAAI,IAAI,KAAK;AACzB,MAAI,SAAS;AACb,MAAI,OAAO;AACX,MAAI,CAAC,IAAI,SAAS,SAAS,GAAG,EAAG,KAAI,YAAY;AACjD,SAAO,IAAI;AACb;AAEO,SAAS,gBAAgB,SAAiB,MAAsB;AACrE,MAAI;AACF,UAAM,MAAM,IAAI,IAAI,MAAM,aAAa,OAAO,CAAC;AAC/C,QAAI,CAAC,CAAC,SAAS,UAAU,SAAS,OAAO,EAAE,SAAS,IAAI,QAAQ;AAC9D,YAAM,IAAI,MAAM,mCAAmC;AACrD,WAAO,IAAI;AAAA,EACb,SAAS,OAAO;AACd,UAAM,IAAI;AAAA,MACR;AAAA,MACA,0BAA0B,IAAI;AAAA,MAC9B,EAAE,MAAM;AAAA,IACV;AAAA,EACF;AACF;AAEO,SAAS,YACd,MACA,SACA,UACQ;AACR,MAAI;AACJ,MAAI;AACF,aAAS,WAAW,SAAS,MAAM,OAAO,IAAI,QAAQ;AAAA,EACxD,SAAS,OAAO;AACd,UAAM,IAAI,cAAc,kBAAkB,0BAA0B;AAAA,MAClE,SAAS,QAAQ;AAAA,MACjB;AAAA,IACF,CAAC;AAAA,EACH;AACA,MAAI,OAAO,WAAW,YAAY,CAAC,OAAO,KAAK;AAC7C,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,MACA,EAAE,SAAS,QAAQ,QAAQ;AAAA,IAC7B;AAEF,MAAI,CAAC,OAAO,WAAW,GAAG,KAAK,CAAC,0BAA0B,KAAK,MAAM;AACnE,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,MACA,EAAE,SAAS,QAAQ,QAAQ;AAAA,IAC7B;AACF,SAAO;AACT;AAEO,SAAS,YAAY,OAA8B;AACxD,MAAI,SAAS,KAAK,KAAK,MAAM,SAAS,UAAU,MAAM,SAAS;AAC7D,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,MACA,EAAE,OAAO,OAAO;AAAA,IAClB;AACF,MAAI;AACF,WAAO,qBAAqB,KAAK;AAAA,EACnC,SAAS,OAAO;AACd,UAAM,UACJ,iBAAiB,QAAQ,MAAM,UAAU;AAC3C,UAAM,IAAI,cAAc,kBAAkB,SAAS;AAAA,MACjD;AAAA,MACA,OAAO,QAAQ,MAAM,GAAG,EAAE,CAAC;AAAA,IAC7B,CAAC;AAAA,EACH;AACF;AAEO,SAAS,sBACd,OACA,SAC6B;AAC7B,MACE,CAAC,WACD,OAAO,QAAQ,OAAO,YACtB,CAAC,QAAQ,GAAG,KAAK,KACjB,OAAO,QAAQ,YAAY,YAC3B,CAAC,QAAQ,QAAQ,KAAK;AAEtB,UAAM,IAAI,cAAc,mBAAmB,6BAA6B;AAC1E,QAAM,SAAS,YAAY,KAAK;AAChC,QAAM,UAAU,aAAa,YAAY,QAAQ,OAAO,CAAC;AACzD,QAAM,UAAU,CAAC,MAAc,SAC7B;AAAA,IACE;AAAA,IACA;AAAA,MACE;AAAA,MACA,SAAS,QAAQ;AAAA,MACjB,YAAY,gBAAgB,SAAS,IAAI;AAAA,IAC3C;AAAA,IACA,QAAQ;AAAA,EACV;AACF,QAAM,aAAa,QAAQ,OAAO,YAAY,SAAS;AACvD,MAAI,OAAO,SAAS,QAAQ;AAC1B,WAAO;AAAA,MACL,GAAG;AAAA,MACH,IAAI,QAAQ;AAAA,MACZ;AAAA,MACA;AAAA,MACA,GAAI,QAAQ,kBACR;AAAA,QACE,gBAAgB,CAAC,YACf,QAAQ,mBAAmB,OAAO,aAAa,OAAO,GAAG,MAAM;AAAA,MACnE,IACA,CAAC;AAAA,IACP;AAAA,EACF;AACA,SAAO;AAAA,IACL,GAAG;AAAA,IACH,IAAI,QAAQ;AAAA,IACZ;AAAA,IACA;AAAA,IACA,GAAI,QAAQ,kBACR;AAAA,MACE,gBAAgB,CAAC,YAA+B;AAE9C,cAAM,OAAO,mBAAmB,OAAO,aAAa;AAAA,UAClD,MAAM;AAAA,UACN,OAAO,QAAQ,QAAQ,OAAO;AAAA,UAC9B,KAAK,QAAQ,MAAM,OAAO;AAAA,UAC1B,KAAK,QAAQ,MAAM,OAAO;AAAA,QAC5B,CAAC;AACD,eAAO,QAAQ,MAAM,MAAM;AAAA,MAC7B;AAAA,IACF,IACA,CAAC;AAAA,EACP;AACF;AAEA,eAAsB,SACpB,KACA,SAC0C;AAC1C,QAAM,SAAS,QAAQ,aAAa;AACpC,UAAQ,MAAM;AACd,MAAI;AACJ,MAAI;AACF,eAAW,MAAM,MAAM,KAAK,EAAE,GAAG,QAAQ,aAAa,QAAQ,MAAM,CAAC;AAAA,EACvE,SAAS,OAAO;AACd,YAAQ,MAAM;AACd,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,MACA,EAAE,MAAM;AAAA,IACV;AAAA,EACF;AACA,UAAQ,MAAM;AACd,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI;AAAA,MACR;AAAA,MACA,8BAA8B,SAAS,MAAM;AAAA,MAC7C,EAAE,QAAQ,SAAS,OAAO;AAAA,IAC5B;AACF,MAAI;AACF,UAAM,QAAiB,MAAM,SAAS,KAAK;AAC3C,YAAQ,MAAM;AACd,WAAO,EAAE,OAAO,KAAK,SAAS,OAAO,IAAI;AAAA,EAC3C,SAAS,OAAO;AACd,YAAQ,MAAM;AACd,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,MACA,EAAE,MAAM;AAAA,IACV;AAAA,EACF;AACF;AAEA,eAAsB,kBACpB,KACA,SACsC;AACtC,MAAI,CAAC,WAAW,OAAO,QAAQ,OAAO,YAAY,CAAC,QAAQ,GAAG,KAAK;AACjE,UAAM,IAAI,cAAc,mBAAmB,gBAAgB;AAC7D,QAAM,WAAW,MAAM,SAAS,YAAY,GAAG,GAAG,OAAO;AACzD,MAAI,CAAC,SAAS,SAAS,KAAK;AAC1B,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,IACF;AACF,MAAI,SAAS,MAAM,kBAAkB;AACnC,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,MACA,EAAE,OAAO,gBAAgB;AAAA,IAC3B;AACF,SAAO,sBAAsB,SAAS,OAAO;AAAA,IAC3C,GAAG;AAAA,IACH,SAAS,QAAQ,WAAW,IAAI,IAAI,KAAK,SAAS,GAAG,EAAE;AAAA,EACzD,CAAC;AACH;;;ACvOO,SAAS,gBAAgB,OAA4C;AAC1E,MAAI,UAAU,OAAW,QAAO;AAChC,MAAI,CAAC,SAAS,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK;AAC5D,UAAM,IAAI,MAAM,gCAAgC;AAClD,QAAM,SAAyB,CAAC;AAChC,aAAW,QAAQ,CAAC,OAAO,SAAS,KAAK,GAAY;AACnD,UAAM,QAAS,MAAkC,IAAI;AACrD,QAAI,UAAU,OAAW;AACzB,QAAI,CAAC,SAAS,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK;AAC5D,YAAM,IAAI,MAAM,cAAc,IAAI,wBAAwB;AAC5D,UAAM,EAAE,KAAK,IAAI,IAAI;AACrB,UAAM,QAAQ,SAAS,QAAQ,OAAO,SAAS,UAAU,MAAM;AAC/D,UAAM,QAAQ,SAAS,QAAQ,MAAM,SAAS,UAAU,KAAK;AAC7D,QAAI,OAAO,QAAQ,YAAY,OAAO,QAAQ,YAC1C,CAAC,OAAO,SAAS,GAAG,KAAK,CAAC,OAAO,SAAS,GAAG,KAC7C,MAAM,SAAS,MAAM,SAAS,MAAM,SAAS,MAAM;AACrD,YAAM,IAAI,MAAM,cAAc,IAAI,sCAAsC,KAAK,OAAO,KAAK,EAAE;AAC7F,QAAI,SAAS,SAAS,MAAM;AAC1B,YAAM,IAAI,MAAM,cAAc,IAAI,2BAA2B;AAC/D,WAAO,IAAI,IAAI,EAAE,KAAK,IAAI;AAAA,EAC5B;AACA,SAAO;AACT;;;ACfO,SAAS,YAAY,OAAgB,QAAQ,OAA6C;AAC/F,MAAI,UAAU,OAAW,QAAO;AAChC,MAAI;AACF,QAAI,CAAC,MAAM,QAAQ,KAAK,EAAG,OAAM,IAAI,MAAM,2BAA2B;AACtE,UAAM,MAAM,oBAAI,IAAY;AAC5B,UAAM,SAAS,CAAC,OAAgB,OAAe,aAAa,UAAU;AACpE,UAAI,OAAO,UAAU,YAAa,CAAC,cAAc,CAAC,MAAM,KAAK;AAC3D,cAAM,IAAI,MAAM,GAAG,KAAK,gBAAgB,aAAa,WAAW,iBAAiB,EAAE;AACrF,aAAO;AAAA,IACT;AACA,WAAO,MAAM,IAAI,CAAC,OAAO,UAAU;AACjC,YAAM,QAAQ,UAAU,KAAK;AAC7B,UAAI,CAAC,SAAS,KAAK,EAAG,OAAM,IAAI,MAAM,GAAG,KAAK,sBAAsB;AACpE,YAAM,KAAK,eAAe,MAAM,IAAI,GAAG,KAAK,KAAK;AACjD,UAAI,IAAI,IAAI,EAAE,EAAG,OAAM,IAAI,MAAM,GAAG,KAAK,yBAAyB;AAClE,UAAI,IAAI,EAAE;AACV,YAAM,QAAQ,OAAO,MAAM,OAAO,GAAG,KAAK,UAAU,KAAK;AACzD,UAAI,CAAC,MAAM,QAAQ,MAAM,MAAM,EAAG,OAAM,IAAI,MAAM,GAAG,KAAK,4BAA4B;AACtF,YAAM,WAAW,oBAAI,IAAY;AACjC,YAAM,SAAS,MAAM,OAAO,IAAI,CAAC,OAAO,MAAyB;AAC/D,cAAM,OAAO,GAAG,KAAK,WAAW,CAAC;AACjC,YAAI,CAAC,SAAS,KAAK,EAAG,OAAM,IAAI,MAAM,GAAG,IAAI,sBAAsB;AACnE,cAAMC,MAAK,eAAe,MAAM,IAAI,GAAG,IAAI,KAAK;AAChD,YAAI,SAAS,IAAIA,GAAE,EAAG,OAAM,IAAI,MAAM,GAAG,IAAI,yBAAyB;AACtE,iBAAS,IAAIA,GAAE;AACf,YAAI,MAAM,SAAS,OAAQ,QAAO,EAAE,IAAAA,KAAI,MAAM,QAAQ,MAAM,OAAO,MAAM,MAAM,GAAG,IAAI,SAAS,IAAI,EAAE;AACrG,cAAM,MAAM,OAAO,MAAM,KAAK,GAAG,IAAI,QAAQ,KAAK;AAClD,YAAI,IAAK,iBAAgB,0BAA0B,GAAG;AACtD,YAAI,MAAM,SAAS,QAAS,QAAO;AAAA,UACjC,IAAAA;AAAA,UAAI,MAAM;AAAA,UAAS;AAAA,UACnB,GAAI,MAAM,QAAQ,SAAY,CAAC,IAAI,EAAE,KAAK,OAAO,MAAM,KAAK,GAAG,IAAI,QAAQ,IAAI,EAAE;AAAA,QACnF;AACA,YAAI,MAAM,SAAS,QAAS,QAAO,EAAE,IAAAA,KAAI,MAAM,SAAS,IAAI;AAC5D,YAAI,MAAM,SAAS,SAAS;AAC1B,gBAAM,SAAS,MAAM,WAAW,SAAY,SAAY,OAAO,MAAM,QAAQ,GAAG,IAAI,WAAW,IAAI;AACnG,cAAI,OAAQ,iBAAgB,0BAA0B,MAAM;AAC5D,iBAAO,EAAE,IAAAA,KAAI,MAAM,SAAS,KAAK,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC,EAAG;AAAA,QACjE;AACA,cAAM,IAAI,MAAM,GAAG,IAAI,kCAAkC;AAAA,MAC3D,CAAC;AACD,aAAO,EAAE,IAAI,OAAO,OAAO;AAAA,IAC7B,CAAC;AAAA,EACH,SAAS,OAAO;AACd,UAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU;AACzD,UAAM,IAAI,cAAc,mBAAmB,SAAS,EAAE,OAAO,QAAQ,MAAM,GAAG,EAAE,CAAC,GAAG,MAAM,CAAC;AAAA,EAC7F;AACF;AAEO,SAAS,0BACd,OACA,SACA,UACwB;AACxB,SAAO,EAAE,GAAG,OAAO,QAAQ,MAAM,OAAO,IAAI,CAAC,UAAU;AACrD,QAAI,MAAM,SAAS,OAAQ,QAAO,EAAE,GAAG,MAAM;AAC7C,UAAM,UAAU,CAAC,MAAc,UAA4B;AACzD,UAAI,CAAC,KAAM,OAAM,IAAI,cAAc,mBAAmB,GAAG,MAAM,EAAE,IAAI,MAAM,EAAE,IAAI,KAAK,qBAAqB;AAC3G,YAAM,UAAU,EAAE,YAAY,gBAAgB,SAAS,IAAI,GAAG,SAAS,MAAM,IAAI,SAAS,MAAM,IAAI,MAAM;AAC1G,YAAM,SAAS,WAAW,SAAS,MAAM,OAAO,IAAI,QAAQ;AAC5D,UAAI,OAAO,WAAW,YAAa,CAAC,OAAO,WAAW,GAAG,KAAK,CAAC,0BAA0B,KAAK,MAAM;AAClG,cAAM,IAAI,cAAc,kBAAkB,sEAAsE;AAClH,aAAO;AAAA,IACT;AACA,WAAO,EAAE,GAAG,OAAO,KAAK,QAAQ,MAAM,KAAK,KAAK,GAAG,GAAI,MAAM,SAAS,WAAW,MAAM,SAAS,EAAE,QAAQ,QAAQ,MAAM,QAAQ,QAAQ,EAAE,IAAI,CAAC,EAAG;AAAA,EACpJ,CAAC,EAAE;AACL;;;ACvFO,SAAS,gBACd,QACA,SACQ;AACR,SAAO,OAAO;AAAA,IACZ;AAAA,IACA,CACE,QACA,QACA,QACA,SACG;AACH,YAAM,QAAQ,UAAU,UAAU,QAAQ,IAAI;AAAA,QAC5C;AAAA,QACA,CAAC,SAAS,UACR,YAAY,KAAK,KAAK,IAClB,OAAO;AAAA,UACL,KAAK,IAAI,SAAS,MAAM,KAAK,GAAG,EAAE,GAAG,OAAQ;AAAA,QAC/C,IACA;AAAA,MACR;AACA,aAAO,OAAO,KAAK,UAAU,QAAQ,IAAI,CAAC,CAAC;AAAA,IAC7C;AAAA,EACF;AACF;;;ACfO,IAAM,yBAAyB,CAAC,SAAS,gBAAgB,cAAc;AAGvE,SAAS,cAAc,SAAmC,SAAgC;AAC/F,SAAO,QAAQ,SAAS,OAAO,MAAM,YAAY,UAAU,QAAQ,SAAS;AAC9E;AACO,SAAS,iBAAiB,SAAmC,SAAgC,QAAyD;AAC3J,QAAM,SAAS,EAAE,GAAG,QAAQ,OAAO;AACnC,QAAM,OAAiC,EAAE,GAAG,SAAS,OAAO;AAC5D,MAAI,YAAY,QAAS,QAAO,KAAK;AACrC,MAAI,OAAQ,QAAO,OAAO,IAAI;AAAA,MACzB,QAAO,OAAO,OAAO;AAC1B,MAAI,CAAC,OAAO,KAAK,MAAM,EAAE,OAAQ,QAAO,KAAK;AAC7C,SAAO;AACT;AACA,SAAS,UAAU,OAAgB,OAAO,oBAAI,IAAY,GAAc;AACtE,MAAI,UAAU,QAAQ,OAAO,UAAU,YAAY,OAAO,UAAU,UAAW,QAAO;AACtF,MAAI,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,EAAG,QAAO;AAChE,MAAI,OAAO,UAAU,YAAY,CAAC,SAAS,KAAK,IAAI,KAAK,EAAG,OAAM,IAAI,MAAM,4BAA4B;AACxG,MAAI,CAAC,MAAM,QAAQ,KAAK,KAAK,OAAO,eAAe,KAAK,MAAM,OAAO,aAAa,OAAO,eAAe,KAAK,MAAM,KAAM,OAAM,IAAI,MAAM,4BAA4B;AACrK,OAAK,IAAI,KAAK;AACd,QAAM,SAAoB,MAAM,QAAQ,KAAK,IAAI,MAAM,IAAI,UAAQ,UAAU,MAAM,IAAI,CAAC,IAAI,OAAO,YAAY,OAAO,QAAQ,KAAK,EAAE,IAAI,CAAC,CAAC,KAAK,IAAI,MAAM,CAAC,KAAK,UAAU,MAAM,IAAI,CAAC,CAAC,CAAC;AACvL,OAAK,OAAO,KAAK;AACjB,SAAO;AACT;AACA,SAAS,YAAY,QAAuC;AAC1D,MAAI,CAAC,SAAS,MAAM,EAAG,OAAM,IAAI,MAAM,4BAA4B;AACnE,MAAI,OAAO,SAAS,QAAS,QAAO,EAAE,MAAM,SAAS,SAAS,eAAe,OAAO,SAAS,gBAAgB,EAAE;AAC/G,MAAI,OAAO,SAAS,QAAS,QAAO,EAAE,MAAM,SAAS,SAAS,eAAe,OAAO,SAAS,gBAAgB,EAAE;AAC/G,MAAI,OAAO,SAAS,UAAU;AAC5B,QAAI,OAAO,WAAW,WAAc,CAAC,SAAS,OAAO,MAAM,KAAK,MAAM,QAAQ,OAAO,MAAM,GAAI,OAAM,IAAI,MAAM,mCAAmC;AAClJ,WAAO,EAAE,MAAM,UAAU,UAAU,eAAe,OAAO,UAAU,iBAAiB,GAAG,GAAI,OAAO,WAAW,SAAY,CAAC,IAAI,EAAE,QAAQ,UAAU,OAAO,MAAM,EAAgB,EAAG;AAAA,EACpL;AACA,MAAI,OAAO,SAAS,QAAQ;AAC1B,UAAM,WAAW,cAAc,OAAO,MAAM,aAAa;AACzD,UAAM,MAAM,OAAQ,OAAO,KAAiC,KAAK,iBAAiB;AAClF,QAAI,OAAO,KAAK,OAAO,IAAK,OAAM,IAAI,MAAM,yCAAyC;AACrF,UAAM,WAAW,OAAO,aAAa,SAAY,SAAY,OAAO,OAAO,UAAU,iBAAiB;AACtG,QAAI,aAAa,UAAa,WAAW,EAAG,OAAM,IAAI,MAAM,gDAAgD;AAC5G,WAAO,EAAE,MAAM,QAAQ,MAAM,EAAE,GAAG,UAAU,IAAI,GAAG,GAAI,aAAa,SAAY,CAAC,IAAI,EAAE,SAAS,EAAG;AAAA,EACrG;AACA,QAAM,IAAI,MAAM,iCAAiC;AACnD;AAcA,IAAM,SAAS;AAAA,EACb;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AACA,IAAM,QAAQ;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AACA,IAAM,SAAS;AAAA,EACb,OAAO,CAAC,KAAK;AAAA,EACb,SAAS,CAAC,SAAS;AAAA,EACnB,UAAU,CAAC,OAAO,cAAc,kBAAkB,WAAW,OAAO,MAAM;AAAA,EAC1E,OAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,OAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,MAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,QAAQ;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,SAAS;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,UAAU;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AACA,IAAM,gBAAgB,oBAAI,IAAI;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AACD,IAAM,eAAe,oBAAI,IAAI;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AACD,IAAM,iBAAiB,oBAAI,IAAI;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AACD,IAAM,QAA2C;AAAA,EAC/C,eAAe,CAAC,QAAQ,MAAM;AAAA,EAC9B,gBAAgB,CAAC,UAAU,SAAS,OAAO;AAAA,EAC3C,kBAAkB,CAAC,OAAO,UAAU,QAAQ,OAAO;AAAA,EACnD,MAAM,CAAC,WAAW,WAAW;AAAA,EAC7B,WAAW,CAAC,OAAO,OAAO;AAAA,EAC1B,gBAAgB,CAAC,cAAc,UAAU;AAAA,EACzC,SAAS,CAAC,QAAQ,YAAY,MAAM;AAAA,EACpC,aAAa,CAAC,IAAI,aAAa,iBAAiB;AAAA,EAChD,WAAW,CAAC,UAAU,QAAQ;AAAA,EAC9B,OAAO,CAAC,QAAQ,UAAU,OAAO;AAAA,EACjC,eAAe,CAAC,OAAO,UAAU,QAAQ;AAAA,EACzC,YAAY,CAAC,UAAU,QAAQ;AAAA,EAC/B,SAAS,CAAC,SAAS,MAAM;AAAA,EACzB,eAAe,CAAC,WAAW,SAAS;AAAA,EACpC,gBAAgB;AAAA,IACd;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,OAAO,OAAgB,OAAuB;AACrD,MAAI,OAAO,UAAU,YAAY,CAAC,OAAO,SAAS,KAAK;AACrD,UAAM,IAAI,MAAM,GAAG,KAAK,4BAA4B;AACtD,SAAO;AACT;AAEO,SAAS,cAAc,OAAgB,OAAgC;AAC5E,MAAI,CAAC,SAAS,KAAK,EAAG,OAAM,IAAI,MAAM,GAAG,KAAK,0BAA0B;AACxE,QAAM,MAAM,OAAO,MAAM,KAAK,GAAG,KAAK,MAAM;AAC5C,QAAM,QAAQ,OAAO,MAAM,OAAO,GAAG,KAAK,QAAQ;AAClD,MAAI,KAAK,IAAI,KAAK,IAAI;AACpB,UAAM,IAAI,MAAM,GAAG,KAAK,4BAA4B;AACtD,SAAO,EAAE,KAAK,MAAM;AACtB;AAEA,SAAS,aAAa,OAAyC;AAC7D,MAAI,CAAC,SAAS,KAAK,EAAG,OAAM,IAAI,MAAM,6BAA6B;AACnE,QAAM,OAAO,eAAe,MAAM,MAAM,cAAc;AACtD,MACE,CAAC;AAAA,IACC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,SAAS,IAAI;AAEf,UAAM,IAAI,MAAM,mCAAmC;AACrD,QAAM,SAAkC,EAAE,KAAK;AAC/C,aAAW,OAAO,CAAC,QAAQ,QAAQ,GAAG;AACpC,QAAI,MAAM,GAAG,MAAM;AACjB,aAAO,GAAG,IAAI,eAAe,MAAM,GAAG,GAAG,WAAW,GAAG,EAAE;AAAA,EAC7D;AACA,aAAW,OAAO,CAAC,eAAe,gBAAgB,aAAa,GAAG;AAChE,QAAI,MAAM,GAAG,MAAM;AACjB,aAAO,GAAG,IAAI,OAAO,MAAM,GAAG,GAAG,WAAW,GAAG,EAAE;AAAA,EACrD;AACA,MAAI,SAAS,MAAO,QAAO,MAAM,eAAe,MAAM,KAAK,aAAa;AACxE,MAAI,SAAS,QAAQ;AACnB,WAAO,OAAO,eAAe,MAAM,MAAM,cAAc;AACvD,QAAI,CAAC,MAAM,QAAQ,MAAM,OAAO,KAAK,MAAM,QAAQ,WAAW;AAC5D,YAAM,IAAI,MAAM,wCAAwC;AAC1D,UAAM,UAAU,MAAM,QAAQ;AAAA,MAAI,CAAC,GAAG,MACpC,OAAO,GAAG,mBAAmB,CAAC,GAAG;AAAA,IACnC;AACA,QAAI,QAAQ,CAAC,KAAM,KAAK,QAAQ,CAAC,KAAM;AACrC,YAAM,IAAI,MAAM,oDAAoD;AACtE,WAAO,UAAU;AAAA,EACnB;AACA,SAAO;AACT;AAEA,SAAS,aAAa,OAAyB;AAC7C,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,MAAI,CAAC,SAAS,KAAK,EAAG,OAAM,IAAI,MAAM,qCAAqC;AAC3E,QAAM,SAAiC,CAAC;AACxC,aAAW,OAAO,CAAC,QAAQ,SAAS,UAAU,GAAG;AAC/C,QAAI,MAAM,GAAG,MAAM,QAAW;AAC5B,UAAI,OAAO,MAAM,GAAG,MAAM;AACxB,cAAM,IAAI,MAAM,WAAW,GAAG,qBAAqB;AACrD,aAAO,GAAG,IAAI,MAAM,GAAG;AAAA,IACzB;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,gBAAgB,OAAiD;AACxE,MAAI,CAAC,SAAS,KAAK;AACjB,UAAM,IAAI,MAAM,uCAAuC;AACzD,QAAM,SAA0C,CAAC;AACjD,aAAW,OAAO;AAAA,IAChB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAAG;AACD,UAAM,OAAO,MAAM,GAAG;AACtB,QAAI,SAAS,OAAW;AACxB,QACE,CAAC,cAAc,SAAS,UAAU,UAAU,YAAY,EAAE,SAAS,GAAG,KACtE,OAAO,SAAS;AAEhB,YAAM,IAAI,MAAM,qBAAqB,GAAG,qBAAqB;AAC/D,QACE,OAAO,SAAS,aACf,OAAO,SAAS,YAAY,CAAC,OAAO,SAAS,IAAI;AAElD,YAAM,IAAI;AAAA,QACR,qBAAqB,GAAG;AAAA,MAC1B;AACF,WAAO,GAAG,IAAI;AAAA,EAChB;AACA,SAAO;AACT;AAEO,SAAS,aACd,OACA,SACA,OAC0B;AAC1B,MAAI;AACF,QAAI,CAAC,SAAS,KAAK,EAAG,OAAM,IAAI,MAAM,2BAA2B;AACjE,UAAM,OAAO,eAAe,MAAM,MAAM,MAAM;AAC9C,QAAI,CAAC,OAAO,UAAU,eAAe,KAAK,QAAQ,IAAI;AACpD,YAAM,IAAI,MAAM,gCAAgC;AAClD,UAAM,OAAO;AACb,UAAM,SAAkC;AAAA,MACtC;AAAA,MACA,IAAI,eAAe,MAAM,IAAI,IAAI;AAAA,IACnC;AACA,UAAM,SAAS,SAAS,aAAa,SAAS;AAC9C,UAAM,UAAU,CAAC,GAAG,QAAQ,GAAI,SAAS,CAAC,IAAI,OAAQ,GAAG,OAAO,IAAI,CAAC;AACrE,eAAW,OAAO,SAAS;AACzB,YAAM,OAAO,MAAM,GAAG;AACtB,UAAI,SAAS,OAAW;AACxB,UAAI,QAAQ,WAAY,QAAO,GAAG,IAAI,cAAc,MAAM,GAAG;AAAA,eACpD,QAAQ,YAAY;AAC3B,YAAI,CAAC,MAAM,QAAQ,IAAI,KAAK,KAAK,UAAU,SAAS,YAAY,IAAI;AAClE,gBAAM,IAAI,MAAM,6BAA6B;AAC/C,eAAO,GAAG,IAAI,KAAK,IAAI,CAAC,GAAG,MAAM,cAAc,GAAG,YAAY,CAAC,GAAG,CAAC;AAAA,MACrE,WAAW,QAAQ,UAAW,QAAO,GAAG,IAAI,aAAa,IAAI;AAAA,eACpD,QAAQ,UAAW,QAAO,GAAG,IAAI,aAAa,IAAI;AAAA,eAClD,QAAQ,oBAAqB,QAAO,GAAG,IAAI,gBAAgB,IAAI;AAAA,eAC/D,cAAc,IAAI,GAAG,GAAG;AAC/B,YAAI,OAAO,SAAS;AAClB,gBAAM,IAAI,MAAM,GAAG,GAAG,sBAAsB;AAC9C,eAAO,GAAG,IAAI;AAAA,MAChB,WAAW,aAAa,IAAI,GAAG,GAAG;AAChC,cAAM,IAAI,OAAO,MAAM,GAAG;AAC1B,YAAI,eAAe,IAAI,GAAG,KAAK,KAAK;AAClC,gBAAM,IAAI,MAAM,GAAG,GAAG,8BAA8B;AACtD,YAAI,QAAQ,gBAAgB,CAAC,OAAO,cAAc,CAAC;AACjD,gBAAM,IAAI,MAAM,iCAAiC;AACnD,YACE;AAAA,UACE;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF,EAAE,SAAS,GAAG,MACb,IAAI,KAAK,IAAI;AAEd,gBAAM,IAAI,MAAM,GAAG,GAAG,mBAAmB;AAC3C,eAAO,GAAG,IAAI;AAAA,MAChB,WAAW,QAAQ,gBAAgB,OAAO,SAAS;AACjD,eAAO,GAAG,IAAI,OAAO,MAAM,GAAG;AAAA,gBAE7B,QAAQ,SAAS,QAAQ,aAC1B,SAAS,WACT,MAAM,QAAQ,IAAI,GAClB;AACA,YAAI,CAAC,KAAK;AACR,gBAAM,IAAI,MAAM,GAAG,GAAG,oBAAoB,QAAQ,QAAQ,YAAY,SAAS,EAAE;AACnF,eAAO,GAAG,IAAI,KAAK,IAAI,CAAC,OAAO,MAAM,eAAe,OAAO,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC;AAAA,MAC5E,OAAO;AACL,YAAI,OAAO,SAAS;AAClB,gBAAM,IAAI,MAAM,GAAG,GAAG,qBAAqB;AAC7C,YAAI,MAAM,GAAG,KAAK,CAAC,MAAM,GAAG,EAAE,SAAS,IAAI;AACzC,gBAAM,IAAI,MAAM,GAAG,GAAG,qBAAqB;AAC7C,eAAO,GAAG,IAAI;AAAA,MAChB;AAAA,IACF;AACA,QAAI,CAAC,UAAU,CAAC,OAAO,SAAU,OAAM,IAAI,MAAM,oBAAoB;AACrE,QAAI,UAAU,CAAC,OAAO,SAAU,OAAM,IAAI,MAAM,oBAAoB;AACpE,QACE,CAAC,SAAS,YAAY,SAAS,SAAS,QAAQ,EAAE,SAAS,IAAI,KAC/D,EAAE,OAAO,OAAO,QAAQ,WACpB,OAAO,IAAI,KAAK,IAChB,MAAM,QAAQ,OAAO,GAAG;AAE5B,YAAM,IAAI,MAAM,eAAe;AACjC,QAAI,SAAS,aAAa,CAAC,OAAO;AAChC,YAAM,IAAI,MAAM,mBAAmB;AACrC,QAAI,SAAS,UAAU,OAAO,OAAO,SAAS;AAC5C,YAAM,IAAI,MAAM,gBAAgB;AAClC,QAAI,SAAS,cAAc,CAAC,OAAO;AACjC,YAAM,IAAI,MAAM,sBAAsB;AACxC,QAAI,MAAM,WAAW,OAAW,QAAO,SAAS,YAAY,MAAM,MAAM;AACxE,QAAI,MAAM,WAAW,QAAW;AAC9B,UAAI,CAAC,SAAS,MAAM,MAAM,EAAG,OAAM,IAAI,MAAM,4BAA4B;AACzE,YAAM,SAAuE,CAAC;AAC9E,iBAAW,OAAO,OAAO,KAAK,MAAM,MAAM,GAAG;AAC3C,YAAI,CAAC,uBAAuB,SAAS,GAA4B,EAAG,OAAM,IAAI,MAAM,UAAU,GAAG,uBAAuB;AACxH,YAAI;AAAE,iBAAO,GAA4B,IAAI,YAAY,MAAM,OAAO,GAAG,CAAC;AAAA,QAAG,SACtE,OAAO;AAAE,gBAAM,IAAI,MAAM,UAAU,GAAG,IAAI,iBAAiB,QAAQ,MAAM,UAAU,gBAAgB,EAAE;AAAA,QAAG;AAAA,MACjH;AACA,aAAO,SAAS;AAAA,IAClB;AACA,WAAO;AAAA,EACT,SAAS,OAAO;AACd,UAAM,SAAS,iBAAiB,QAAQ,MAAM,UAAU;AACxD,UAAM,IAAI,cAAc,mBAAmB,GAAG,KAAK,IAAI,MAAM,IAAI;AAAA,MAC/D;AAAA,MACA,OAAO,GAAG,KAAK,IAAI,OAAO,MAAM,GAAG,EAAE,CAAC,CAAC;AAAA,MACvC;AAAA,IACF,CAAC;AAAA,EACH;AACF;AAEO,SAAS,qBACd,SACA,SACA,SACA,UAC0B;AAC1B,QAAM,UAAU,CAAC,SACf,OACI;AAAA,IACE;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN;AAAA,MACA,WAAW,QAAQ;AAAA,MACnB,YAAY,gBAAgB,SAAS,IAAI;AAAA,IAC3C;AAAA,IACA;AAAA,EACF,IACA;AACN,QAAM,SAAS,EAAE,GAAG,QAAQ;AAC5B,MAAI,OAAO,OAAQ,QAAO,SAAS,gBAAgB,OAAO,QAAQ,OAAO;AACzE,MAAI,OAAO,mBAAmB,WAAY,QAAO,oBAAoB;AAAA,IACnE,GAAG,OAAO;AAAA,IACV,YAAY,gBAAgB,OAAO,kBAAkB,YAAY,OAAO;AAAA,EAC1E;AACA,MAAI,SAAS;AACX,WAAO,MAAM,MAAM,QAAQ,OAAO,GAAG,IACjC,OAAO,IAAI,IAAI,OAAO,IACtB,QAAQ,OAAO,GAAG;AACxB,MAAI,YAAY,UAAU,OAAO;AAC/B,WAAO,SAAS,QAAQ,OAAO,MAAM;AACvC,MAAI,OAAO,SAAS,SAAS;AAC3B,QAAI,OAAO,KAAM,QAAO,OAAO,QAAQ,OAAO,IAAI;AAClD,QAAI,OAAO,YAAa,QAAO,cAAc,QAAQ,OAAO,WAAW;AAAA,EACzE;AACA,MAAI,OAAO,SAAS,aAAa,OAAO,QAAQ,SAAS;AACvD,WAAO,UAAU,EAAE,GAAG,OAAO,SAAS,KAAK,QAAQ,OAAO,QAAQ,GAAG,EAAE;AACzE,MAAI,OAAO,OAAO,YAAY;AAC5B,WAAO,UAAU;AAAA,MACf,GAAG,OAAO;AAAA,MACV,GAAI,OAAO,QAAQ,QAAQ,EAAE,OAAO,QAAQ,OAAO,QAAQ,KAAK,EAAE,IAAI,CAAC;AAAA,IACzE;AACF,SAAO;AACT;;;AC3aA,SAAS,eACP,QACA,KACoB;AACpB,SAAO,OAAO,GAAG,MAAM,SACnB,SACA,eAAe,OAAO,GAAG,GAAG,GAAG;AACrC;AAGO,SAAS,iBAAiB,OAAgB,UAA+B,CAAC,GAA0B;AACzG,MAAI,CAAC,SAAS,KAAK;AACjB,UAAM,IAAI,cAAc,mBAAmB,2BAA2B;AACxE,MAAI,MAAM,kBAAkB;AAC1B,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,MACA,EAAE,OAAO,gBAAgB;AAAA,IAC3B;AACF,MAAI;AACF,UAAM,SAAS,YAAY,MAAM,QAAQ,QAAQ,KAAK;AACtD,QAAI,CAAC,MAAM,QAAQ,MAAM,MAAM,KAAM,CAAC,QAAQ,SAAS,CAAC,MAAM,OAAO;AACnE,YAAM,IAAI,MAAM,mCAAmC;AACrD,UAAM,MAAM,oBAAI,IAAY;AAC5B,UAAM,SAAS,MAAM,OAAO;AAAA,MAC1B,CAAC,OAAgB,UAAsC;AACrD,YAAI;AACJ,cAAM,QAAQ,UAAU,KAAK;AAC7B,YAAI;AACF,cAAI,CAAC,SAAS,KAAK,EAAG,OAAM,IAAI,MAAM,yBAAyB;AAC/D,eAAK,eAAe,MAAM,IAAI,IAAI;AAClC,cAAI,IAAI,IAAI,EAAE,EAAG,OAAM,IAAI,MAAM,wBAAwB;AACzD,cAAI,IAAI,EAAE;AACV,cAAI,CAAC,SAAS,MAAM,MAAM;AACxB,kBAAM,IAAI,MAAM,4BAA4B;AAC9C,gBAAM,MAAM,MAAM;AAClB,cACG,IAAI,cAAc,YAClB,IAAI,iBAAiB;AAEtB,kBAAM,IAAI;AAAA,cACR;AAAA,YACF;AACF,gBAAM,UAAU,eAAe,KAAK,SAAS;AAC7C,gBAAM,SACJ,IAAI,cAAc,SACd;AAAA,YACE,WAAW,eAAe,IAAI,WAAW,kBAAkB;AAAA,YAC3D;AAAA,UACF,IACA,EAAE,cAAc,YAAY,IAAI,YAAY,GAAG,QAAQ;AAC7D,gBAAM,aAAa,gBAAgB,MAAM,UAAU;AACnD,cAAI;AACJ,cAAI,MAAM,gBAAgB,QAAW;AACnC,gBAAI,CAAC,SAAS,MAAM,WAAW;AAC7B,oBAAM,IAAI,MAAM,iCAAiC;AACnD,kBAAM,QAAQ,MAAM;AACpB,kBAAM,WAAW;AAAA,cACf,EAAE,KAAK,MAAM,OAAO,GAAG,OAAO,MAAM,SAAS,EAAE;AAAA,cAC/C;AAAA,YACF;AACA,kBAAM,MAAM,MAAM,OAAO;AACzB,gBACE,OAAO,QAAQ,YACf,CAAC,OAAO,SAAS,GAAG,KACpB,OAAO,KACP,OAAO;AAEP,oBAAM,IAAI;AAAA,gBACR;AAAA,cACF;AACF,0BAAc,EAAE,GAAG,UAAU,IAAI;AAAA,UACnC;AACA,cAAI,MAAM,aAAa,UAAa,CAAC,MAAM,QAAQ,MAAM,QAAQ;AAC/D,kBAAM,IAAI,MAAM,6BAA6B;AAC/C,gBAAM,aAAa,oBAAI,IAAY;AACnC,gBAAM,YAAa,MAAM,YAAY,CAAC,GAAiB;AAAA,YACrD,CAAC,SAAS,MAAM;AACd,oBAAM,SAAS;AAAA,gBACb;AAAA,gBACA;AAAA,gBACA,GAAG,KAAK,aAAa,CAAC;AAAA,cACxB;AACA,kBAAI,WAAW,IAAI,OAAO,EAAE;AAC1B,sBAAM,IAAI,MAAM,YAAY,CAAC,4BAA4B;AAC3D,yBAAW,IAAI,OAAO,EAAE;AACxB,qBAAO;AAAA,YACT;AAAA,UACF;AACA,iBAAO;AAAA,YACL;AAAA,YACA,OAAO,eAAe,OAAO,OAAO;AAAA,YACpC;AAAA,YACA;AAAA,YACA,GAAI,eAAe,SAAY,CAAC,IAAI,EAAE,WAAW;AAAA,YACjD;AAAA,UACF;AAAA,QACF,SAAS,OAAO;AACd,cAAI,iBAAiB,iBAAiB,MAAM,QAAS,OAAM;AAC3D,gBAAM,SACJ,iBAAiB,QAAQ,MAAM,UAAU;AAC3C,gBAAM,IAAI;AAAA,YACR,iBAAiB,gBAAgB,MAAM,OAAO;AAAA,YAC9C,GAAG,KAAK,IAAI,MAAM;AAAA,YAClB;AAAA,cACE,SAAS;AAAA,cACT,OAAO,GAAG,KAAK,IACb,iBAAiB,gBACb,uBAAuB,MAAM,SAAS,EAAE,KACxC,OAAO,MAAM,GAAG,EAAE,CAAC,CACzB;AAAA,cACA;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AACA,UAAM,iBACJ,eAAe,OAAO,gBAAgB,KAAK,OAAO,CAAC,GAAG;AACxD,QAAI,mBAAmB,UAAa,CAAC,IAAI,IAAI,cAAc;AACzD,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,QACA,EAAE,OAAO,iBAAiB;AAAA,MAC5B;AACF,eAAW,CAAC,OAAO,KAAK,KAAK,OAAO,QAAQ,GAAG;AAC7C,iBAAW,CAAC,GAAG,OAAO,MAAM,MAAM,YAAY,CAAC,GAAG,QAAQ,GAAG;AAC3D,mBAAW,WAAW,wBAAwB;AAC5C,gBAAM,SAAS,cAAc,SAAS,OAAO;AAC7C,cAAI,QAAQ,SAAS,WAAW,CAAC,QAAQ,KAAK,CAAC,UAAU,MAAM,OAAO,OAAO,OAAO;AAClF,kBAAM,IAAI,cAAc,qBAAqB,uCAAuC;AAAA,cAClF,SAAS,MAAM;AAAA,cAAI,OAAO,UAAU,KAAK,cAAc,CAAC,KAAK,QAAQ,SAAS,OAAO,IAAI,UAAU,OAAO,KAAK,QAAQ;AAAA,YACzH,CAAC;AACH,cAAI,QAAQ,SAAS,WAAW,CAAC,IAAI,IAAI,OAAO,OAAO;AACrD,kBAAM,IAAI;AAAA,cACR;AAAA,cACA;AAAA,cACA;AAAA,gBACE,SAAS,MAAM;AAAA,gBACf,OAAO,UAAU,KAAK,cAAc,CAAC,KAAK,QAAQ,SAAS,OAAO,IAAI,UAAU,OAAO,KAAK,QAAQ;AAAA,cACtG;AAAA,YACF;AAAA,QACJ;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,MACL,eAAe;AAAA,MACf,OAAO,eAAe,OAAO,OAAO;AAAA,MACpC;AAAA,MACA;AAAA,MACA,GAAI,WAAW,SAAY,CAAC,IAAI,EAAE,OAAO;AAAA,IAC3C;AAAA,EACF,SAAS,OAAO;AACd,QAAI,iBAAiB,cAAe,OAAM;AAC1C,UAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU;AACzD,UAAM,IAAI,cAAc,mBAAmB,SAAS;AAAA,MAClD;AAAA,MACA,OAAO,QAAQ,MAAM,GAAG,EAAE,CAAC;AAAA,IAC7B,CAAC;AAAA,EACH;AACF;AAEA,eAAsB,gBACpB,QACA,UAAkC,CAAC,GACP;AAC5B,UAAQ,QAAQ,aAAa,MAAM;AACnC,MAAI;AACJ,MAAI;AACJ,MAAI,OAAO,WAAW,UAAU;AAC9B,UAAM,WAAW,MAAM,SAAS,YAAY,MAAM,GAAG,OAAO;AAC5D,iBAAa,iBAAiB,SAAS,KAAK;AAC5C,cAAU,QAAQ,WAAW,IAAI,IAAI,KAAK,SAAS,GAAG,EAAE;AAAA,EAC1D,OAAO;AACL,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,MACF;AACF,iBAAa,iBAAiB,MAAM;AACpC,cAAU,QAAQ;AAAA,EACpB;AACA,QAAM,OAAO,aAAa,YAAY,OAAO,CAAC;AAC9C,QAAM,aAAa,IAAI,gBAAgB;AACvC,QAAM,SAAS,QAAQ,aAAa;AACpC,QAAM,SAAS,MAAM,WAAW,MAAM;AACtC,UAAQ,iBAAiB,SAAS,QAAQ,EAAE,MAAM,KAAK,CAAC;AACxD,QAAM,SAA+B,IAAI,MAAM,WAAW,OAAO,MAAM;AACvE,MAAI,OAAO;AACX,MAAI;AACJ,iBAAe,SAAS;AACtB,WAAO,OAAO,WAAW,OAAO,UAAU,CAAC,WAAW,OAAO,SAAS;AACpE,YAAM,QAAQ;AACd,YAAM,OAAO,WAAW,OAAO,KAAK;AACpC,UAAI;AACF,cAAM,aACJ,KAAK,OAAO,YAAY,SACpB,SACA,gBAAgB,MAAM,KAAK,OAAO,OAAO;AAC/C,cAAM,eAAe;AAAA,UACnB,IAAI,KAAK;AAAA,UACT,iBAAiB,QAAQ;AAAA,QAC3B;AACA,cAAM,QACJ,KAAK,OAAO,cAAc,SACtB,MAAM;AAAA,UACJ,gBAAgB,MAAM,KAAK,OAAO,SAAS;AAAA,UAC3C;AAAA,YACE,GAAG;AAAA,YACH,SAAS;AAAA,YACT,aAAa;AAAA,cACX,GAAG,QAAQ;AAAA,cACX,QAAQ,WAAW;AAAA,YACrB;AAAA,UACF;AAAA,QACF,IACA,sBAAsB,KAAK,OAAO,cAAc;AAAA,UAC9C,GAAG;AAAA,UACH,SAAS,cAAc;AAAA,QACzB,CAAC;AACP,gBAAQ,WAAW,MAAM;AACzB,YAAI,KAAK,eAAe,OAAW,OAAM,aAAa,KAAK;AAC3D,eAAO,KAAK,IAAI;AAAA,UACd;AAAA,UACA,OAAO,KAAK;AAAA,UACZ,aAAa,KAAK,cACd,EAAE,KAAK,GAAG,OAAO,GAAG,KAAK,IAAI,GAAG,KAAK,YAAY,IACjD;AAAA,UACJ,UAAU,KAAK,SAAU;AAAA,YAAI,CAAC,MAC5B,qBAAqB,GAAG,MAAM,KAAK,IAAI,QAAQ,eAAe;AAAA,UAChE;AAAA,QACF;AAAA,MACF,SAAS,OAAO;AACd,YAAI,CAAC,SAAS;AACZ,gBAAM,QACJ,iBAAiB,gBACb,QACA,IAAI;AAAA,YACF;AAAA,YACA,iBAAiB,QACb,MAAM,UACN;AAAA,YACJ,EAAE,MAAM;AAAA,UACV;AACN,gBAAM,QAAQ,UAAU,KAAK,KAC3B,MAAM,UACL,KAAK,OAAO,cAAc,SACvB,qBACA,sBACN;AACA,oBAAU,IAAI;AAAA,YACZ,MAAM;AAAA,YACN,SAAS,KAAK,EAAE,KAAK,MAAM,OAAO;AAAA,YAClC,EAAE,QAAQ,MAAM,QAAQ,SAAS,KAAK,IAAI,OAAO,OAAO,MAAM;AAAA,UAChE;AAAA,QACF;AACA,mBAAW,MAAM;AAAA,MACnB;AAAA,IACF;AAAA,EACF;AACA,MAAI;AACF,YAAQ,MAAM;AACd,UAAM,QAAQ;AAAA,MACZ,MAAM,KAAK,EAAE,QAAQ,KAAK,IAAI,GAAG,OAAO,MAAM,EAAE,GAAG,MAAM;AAAA,IAC3D;AACA,YAAQ,MAAM;AACd,QAAI,QAAS,OAAM;AACnB,WAAO;AAAA,MACL,OAAO,WAAW;AAAA,MAClB,gBAAgB,WAAW;AAAA,MAC3B;AAAA,MACA,GAAI,WAAW,WAAW,SAAY,CAAC,IAAI,EAAE,QAAQ,WAAW,OAAO,IAAI,CAAC,UAAU,0BAA0B,OAAO,MAAM,QAAQ,oBAAoB,CAAC,EAAE;AAAA,IAC9J;AAAA,EACF,UAAE;AACA,YAAQ,oBAAoB,SAAS,MAAM;AAAA,EAC7C;AACF;","names":["levels","id"]}
package/dist/data.d.mts CHANGED
@@ -45,6 +45,22 @@ type ViewerDocument = ViewerConfig & {
45
45
  schemaVersion: 1;
46
46
  };
47
47
 
48
+ /** Camera-center limits in degrees. A yaw min greater than max crosses ±180°. */
49
+ type PanoViewLimits = {
50
+ yaw?: {
51
+ min: number;
52
+ max: number;
53
+ };
54
+ pitch?: {
55
+ min: number;
56
+ max: number;
57
+ };
58
+ fov?: {
59
+ min: number;
60
+ max: number;
61
+ };
62
+ };
63
+
48
64
  type CubeFaceCode = "f" | "r" | "b" | "l" | "u" | "d";
49
65
  type TileAddress = {
50
66
  face: CubeFaceCode;
@@ -179,11 +195,14 @@ type SphereTileProps = {
179
195
  onLevelChange?: (level: number) => void;
180
196
  };
181
197
 
182
- type TileScene = Omit<TileProps, "loadMode" | "visible" | "onReady" | "onPreviewError" | "onLoadProgress" | "onTileError" | "onLevelChange"> & {
198
+ type SceneViewOptions = {
199
+ viewLimits?: PanoViewLimits;
200
+ };
201
+ type TileScene = Omit<TileProps, "loadMode" | "visible" | "onReady" | "onPreviewError" | "onLoadProgress" | "onTileError" | "onLevelChange"> & SceneViewOptions & {
183
202
  id: string;
184
203
  type: "tile";
185
204
  };
186
- type SphereTileScene = Omit<SphereTileProps, "loadMode" | "visible" | "onReady" | "onPreviewError" | "onLoadProgress" | "onTileError" | "onLevelChange"> & {
205
+ type SphereTileScene = Omit<SphereTileProps, "loadMode" | "visible" | "onReady" | "onPreviewError" | "onLoadProgress" | "onTileError" | "onLevelChange"> & SceneViewOptions & {
187
206
  id: string;
188
207
  type: "sphereTile";
189
208
  };
@@ -209,6 +228,37 @@ type LoadSceneFromJsonOptions = Omit<SceneFromViewerConfigOptions, "baseUrl"> &
209
228
  declare function sceneFromViewerConfig(value: unknown, options: SceneFromViewerConfigOptions): TileScene | SphereTileScene;
210
229
  declare function loadSceneFromJson(url: string, options: LoadSceneFromJsonOptions): Promise<TileScene | SphereTileScene>;
211
230
 
231
+ type ProjectPopupBlock = {
232
+ id: string;
233
+ } & ({
234
+ type: "text";
235
+ text: string;
236
+ } | {
237
+ type: "image";
238
+ src: string;
239
+ alt?: string;
240
+ } | {
241
+ type: "video";
242
+ src: string;
243
+ poster?: string;
244
+ } | {
245
+ type: "audio";
246
+ src: string;
247
+ });
248
+ type ProjectPopupDefinition = {
249
+ id: string;
250
+ title: string;
251
+ blocks: ProjectPopupBlock[];
252
+ };
253
+ type PopupAssetUrlContext = {
254
+ defaultUrl: string;
255
+ popupId: string;
256
+ blockId: string;
257
+ field: "src" | "poster";
258
+ };
259
+ type PopupAssetUrlResolver = (path: string, context: PopupAssetUrlContext) => string;
260
+ declare function resolveProjectPopupAssets(popup: ProjectPopupDefinition, baseUrl: string, resolver?: PopupAssetUrlResolver): ProjectPopupDefinition;
261
+
212
262
  type HotspotPosition = {
213
263
  /** Horizontal panorama angle in degrees. Positive values look right. */
214
264
  yaw: number;
@@ -398,6 +448,7 @@ type VideoHotspotDefinition = PointHotspotDefinitionBase & {
398
448
  type AudioHotspotDefinition = PointHotspotDefinitionBase & {
399
449
  type: "audio";
400
450
  src: string | string[];
451
+ format?: string | string[];
401
452
  playing?: boolean;
402
453
  loop?: boolean;
403
454
  muted?: boolean;
@@ -449,12 +500,36 @@ type PointHotspotDefinition = ImageHotspotDefinition | GraphicHotspotDefinition
449
500
  /** A serializable, discriminated hotspot collection item. */
450
501
  type HotspotDefinition = PointHotspotDefinition | PolygonHotspotDefinition | PolylineHotspotDefinition;
451
502
 
503
+ type JsonValue = null | boolean | number | string | JsonValue[] | JsonObject;
504
+ type JsonObject = {
505
+ [key: string]: JsonValue;
506
+ };
507
+ declare const projectHotspotTriggers: readonly ["click", "pointerenter", "pointerleave"];
508
+ type ProjectHotspotTrigger = typeof projectHotspotTriggers[number];
509
+ type ProjectCustomHotspotAction = {
510
+ type: "custom";
511
+ actionId: string;
512
+ params?: JsonObject;
513
+ };
514
+ declare function hotspotAction(hotspot: ProjectHotspotDefinition, trigger: ProjectHotspotTrigger): ProjectHotspotAction | undefined;
515
+ declare function setHotspotAction(hotspot: ProjectHotspotDefinition, trigger: ProjectHotspotTrigger, action?: ProjectHotspotAction): ProjectHotspotDefinition;
516
+ type ProjectHotspotAction = ProjectCustomHotspotAction | {
517
+ type: "scene";
518
+ sceneId: string;
519
+ } | {
520
+ type: "view";
521
+ view: PanoViewerState;
522
+ duration?: number;
523
+ } | {
524
+ type: "popup";
525
+ popupId: string;
526
+ };
452
527
  type ProjectHotspotDefinition = HotspotDefinition & {
453
- action?: {
454
- type: "scene";
455
- sceneId: string;
456
- };
528
+ /** Legacy click fallback. events.click takes precedence. */
529
+ action?: ProjectHotspotAction;
530
+ events?: Partial<Record<ProjectHotspotTrigger, ProjectHotspotAction>>;
457
531
  };
532
+ declare function resolveHotspotAssets(hotspot: ProjectHotspotDefinition, baseUrl: string, sceneId: string, resolver?: AssetUrlResolver): ProjectHotspotDefinition;
458
533
 
459
534
  type PanoProjectSceneDefinition = {
460
535
  id: string;
@@ -469,6 +544,7 @@ type PanoProjectSceneDefinition = {
469
544
  baseUrl?: string;
470
545
  };
471
546
  initialView?: Partial<PanoViewerState>;
547
+ viewLimits?: PanoViewLimits;
472
548
  hotspots?: ProjectHotspotDefinition[];
473
549
  };
474
550
  type PanoProjectDefinition = {
@@ -476,6 +552,7 @@ type PanoProjectDefinition = {
476
552
  title?: string;
477
553
  initialSceneId?: string;
478
554
  scenes: PanoProjectSceneDefinition[];
555
+ popups?: ProjectPopupDefinition[];
479
556
  };
480
557
  type LoadedProjectScene = {
481
558
  scene: TileScene | SphereTileScene;
@@ -487,13 +564,18 @@ type LoadedPanoProject = {
487
564
  title?: string;
488
565
  initialSceneId: string;
489
566
  scenes: LoadedProjectScene[];
567
+ popups?: ProjectPopupDefinition[];
490
568
  };
491
569
  type LoadPanoProjectOptions = JsonRequestOptions & {
492
570
  /** Directory used for project-relative references. Required for object input. */
493
571
  baseUrl?: string;
494
572
  resolveAssetUrl?: AssetUrlResolver;
573
+ resolvePopupAssetUrl?: PopupAssetUrlResolver;
495
574
  };
496
- declare function parsePanoProject(value: unknown): PanoProjectDefinition;
575
+ /** Drafts permit empty scenes and unfinished popup titles/media; loading and export always validate strictly. */
576
+ declare function parsePanoProject(value: unknown, options?: {
577
+ draft?: boolean;
578
+ }): PanoProjectDefinition;
497
579
  declare function loadPanoProject(source: string | PanoProjectDefinition, options?: LoadPanoProjectOptions): Promise<LoadedPanoProject>;
498
580
 
499
- export { type AssetUrlContext, type AssetUrlResolver, type CubemapViewerConfig, type JsonRequestOptions, type LoadPanoProjectOptions, type LoadSceneFromJsonOptions, type LoadedPanoProject, type LoadedProjectScene, PanoDataError, type PanoDataErrorCode, type PanoProjectDefinition, type PanoProjectSceneDefinition, type ProjectHotspotDefinition, type SceneFromViewerConfigOptions, type SphereViewerConfig, type ViewerConfig, type ViewerDocument, loadPanoProject, loadSceneFromJson, parsePanoProject, sceneFromViewerConfig };
581
+ export { type AssetUrlContext, type AssetUrlResolver, type CubemapViewerConfig, type JsonObject, type JsonRequestOptions, type JsonValue, type LoadPanoProjectOptions, type LoadSceneFromJsonOptions, type LoadedPanoProject, type LoadedProjectScene, PanoDataError, type PanoDataErrorCode, type PanoProjectDefinition, type PanoProjectSceneDefinition, type PanoViewLimits, type PopupAssetUrlContext, type PopupAssetUrlResolver, type ProjectCustomHotspotAction, type ProjectHotspotAction, type ProjectHotspotDefinition, type ProjectHotspotTrigger, type ProjectPopupBlock, type ProjectPopupDefinition, type SceneFromViewerConfigOptions, type SphereViewerConfig, type ViewerConfig, type ViewerDocument, hotspotAction, loadPanoProject, loadSceneFromJson, parsePanoProject, projectHotspotTriggers, resolveHotspotAssets as resolveProjectHotspotAssets, resolveProjectPopupAssets, sceneFromViewerConfig, setHotspotAction };