UNPKG

everything-dev

Version:

A consolidated product package for building Module Federation apps with oRPC APIs.

1 lines • 32.3 kB
{"version":3,"file":"manifest.mjs","names":[],"sources":["../../../src/services/platform/manifest.ts"],"sourcesContent":["/**\n * The platform release manifest (ADR 0034) — one module, the whole release\n * contract: schema, composer, inventory, registry slot, resolution, and the\n * compat check. One composer feeds both publish homes (FastKV pointer slot +\n * in-image staging); the image digest is deliberately absent — it derives from\n * the tags at deploy preflight. The homes' one known divergence is the compat\n * floor: publisher-side (previous release) in FastKV, own version — failing\n * closed — in the image, which cannot read the registry inside the build.\n */\nimport { createHash } from \"node:crypto\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join, relative } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { Context, Layer } from \"effect\";\nimport {\n SHARED_DEP_SPECS,\n type SharedDependencyConfig,\n shareConfigFor,\n} from \"every-plugin/shared-deps-spec\";\nimport { glob } from \"glob\";\nimport { z } from \"zod\";\nimport { getExtendsRef, parseBosRef } from \"../../utils/bos-ref\";\nimport { compareSemver, satisfiesConstraint } from \"../../utils/semver\";\nimport { fetchRegistryKey, fetchRegistryKeyOrNull } from \"../registry/fastkv\";\nimport { fetchParentConfig } from \"../resolution/init-source\";\nimport { AGENT_SYNC_GLOBS, FRAMEWORK_OWNED_SYNC_FILES } from \"../scaffold/ownership\";\n\nexport const PlatformReleaseManifestSchema = z.object({\n schemaVersion: z.literal(1),\n kind: z.literal(\"everything-dev/platform-manifest\"),\n frameworkVersion: z.string().min(1),\n everyPluginVersion: z.string().min(1),\n /** The serving build's repo HEAD (full sha) — omitted when the compose\n * context has no git (regression image builds, build-arg-less builds). */\n gitSha: z.string().min(7).optional(),\n image: z.object({\n ref: z.string().min(1),\n tags: z.array(z.string().min(1)),\n }),\n catalog: z.record(z.string(), z.string()),\n sharedDeps: z.record(\n z.string(),\n z.object({\n version: z.string(),\n requiredVersion: z.union([z.string(), z.boolean()]),\n singleton: z.boolean(),\n eager: z.boolean(),\n strictVersion: z.boolean(),\n shareScope: z.string(),\n }),\n ),\n templateInventory: z.array(\n z.object({\n path: z.string(),\n sha256: z.string().regex(/^[0-9a-f]{64}$/),\n }),\n ),\n compat: z.object({ minChild: z.string().min(1) }),\n /**\n * The release's own slot-pin map (ADR 0034 amendment — release-scoped\n * extends inheritance): each entry records the immutable version-manifest\n * pointer the release published for a config slot (dotted config path, e.g.\n * `app.auth`, `app.auth.ui`, `plugins.votes.ui`) — the son of the store, so\n * children pinned to this release can re-point inherited slots at THESE\n * bytes instead of the parent's live config whenever the parent publishes.\n * Optional: releases composed before the field carry no slots, and old\n * readers strip unknown keys.\n */\n slots: z\n .record(\n z.string(),\n z.object({\n base: z.string().min(1),\n pin: z.object({\n manifest: z.string().min(1),\n integrity: z.string().min(1),\n }),\n }),\n )\n .optional(),\n});\nexport type PlatformReleaseManifest = z.infer<typeof PlatformReleaseManifestSchema>;\n\n/** One recorded release slot (see {@link PlatformReleaseManifestSchema.slots}). */\nexport interface ReleaseSlotRecord {\n base: string;\n pin: { manifest: string; integrity: string };\n}\n\nexport interface TemplateInventoryEntry {\n path: string;\n sha256: string;\n}\n\nexport function getPlatformManifestKey(accountId: string, gatewayId: string): string {\n return `apps/${accountId}/${gatewayId}/platform.json`;\n}\n\n/** The immutable per-release slot (#573): one key per released framework\n * version, written once, never mutated — a divergent republish is a burned\n * version and fails loud. `platform.json` remains the moving pointer; slot-\n * first resolution (#574) reads slots directly. */\nexport function getPlatformVersionSlotKey(\n accountId: string,\n gatewayId: string,\n version: string,\n): string {\n return `apps/${accountId}/${gatewayId}/platform-versions/${version}.json`;\n}\n\n/**\n * The template-source file set a release inventory hashes: the ownership\n * inventory's static paths, the agent-sync globs, and the per-plugin template\n * scaffolding (`plugins/_template/*` — the sources of the per-plugin sync\n * patterns). Files absent from the release source are skipped, mirroring\n * sync's transitional tolerance.\n */\nconst TEMPLATE_SCAFFOLD_SOURCES = [\n \"plugins/_template/rspack.config.js\",\n \"plugins/_template/tsconfig.json\",\n \"plugins/_template/tests/types.d.ts\",\n];\n\nfunction templateSourcePaths(sourceDir: string): string[] {\n const paths = new Set<string>([...FRAMEWORK_OWNED_SYNC_FILES, ...TEMPLATE_SCAFFOLD_SOURCES]);\n for (const match of glob.sync(AGENT_SYNC_GLOBS, {\n cwd: sourceDir,\n nodir: true,\n dot: true,\n ignore: [\"**/node_modules/**\", \"**/.git/**\", \"**/dist/**\", \"**/.bos/**\"],\n })) {\n paths.add(relative(sourceDir, join(sourceDir, match)));\n }\n return [...paths].sort();\n}\n\nexport function computeTemplateInventory(sourceDir: string): TemplateInventoryEntry[] {\n const inventory: TemplateInventoryEntry[] = [];\n for (const relativeFilePath of templateSourcePaths(sourceDir)) {\n const fullPath = join(sourceDir, relativeFilePath);\n if (!existsSync(fullPath)) continue;\n try {\n const content = readFileSync(fullPath);\n inventory.push({\n path: relativeFilePath,\n sha256: createHash(\"sha256\").update(content).digest(\"hex\"),\n });\n } catch {\n // unreadable at compose time → not part of the release inventory\n }\n }\n return inventory.sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0));\n}\n\nexport function composeSharedDepsFromCatalog(\n catalog: Record<string, string>,\n): Record<string, SharedDependencyConfig> {\n const deps: Record<string, SharedDependencyConfig> = {};\n for (const spec of SHARED_DEP_SPECS) {\n const version = catalog[spec.name];\n if (!version) continue;\n deps[spec.name] = { version, ...shareConfigFor(spec, version) };\n }\n return deps;\n}\n\nexport interface ComposePlatformReleaseManifestInputs {\n frameworkVersion: string;\n everyPluginVersion: string;\n gitSha?: string;\n imageRef: string;\n catalog: Record<string, string>;\n templateInventory: TemplateInventoryEntry[];\n compatMinChild: string;\n /** The release's own slot-pin map — sorted here so identical payloads\n * compose identical manifest bytes across machines (the burned-version\n * guard compares serialized bytes). */\n slots?: Record<string, ReleaseSlotRecord>;\n}\n\nexport function composePlatformReleaseManifest(\n inputs: ComposePlatformReleaseManifestInputs,\n): PlatformReleaseManifest {\n // The manifest carries only the derivable tag — the exact version tag the\n // tag scheme pushes for semver releases (ADR 0021). Sha-tags are git facts\n // an image build cannot see; derivation (`ref@v<version>` → digest) keys off\n // the version tag so both publish homes stay byte-identical without any\n // build-context plumbing.\n const semver = parseSemver(inputs.frameworkVersion.trim());\n const tags = semver\n ? [\n `v${semver.major}.${semver.minor}.${semver.patch}${semver.prerelease ? `-${semver.prerelease}` : \"\"}`,\n ]\n : [];\n const slots = inputs.slots\n ? Object.fromEntries(Object.entries(inputs.slots).sort(([a], [b]) => (a < b ? -1 : 1)))\n : undefined;\n return PlatformReleaseManifestSchema.parse({\n schemaVersion: 1,\n kind: \"everything-dev/platform-manifest\",\n frameworkVersion: inputs.frameworkVersion,\n everyPluginVersion: inputs.everyPluginVersion,\n ...(inputs.gitSha ? { gitSha: inputs.gitSha } : {}),\n image: { ref: inputs.imageRef, tags },\n catalog: inputs.catalog,\n sharedDeps: composeSharedDepsFromCatalog(inputs.catalog),\n templateInventory: inputs.templateInventory,\n compat: { minChild: inputs.compatMinChild },\n ...(slots ? { slots } : {}),\n });\n}\n\n/** The one serializer for both publish homes — byte-identical by construction. */\nexport function serializePlatformReleaseManifest(manifest: PlatformReleaseManifest): string {\n return JSON.stringify(manifest);\n}\n\n/**\n * The in-image copy (ADR 0034 pt 1): generated inside the docker build at\n * `packages/everything-dev/dist/platform-manifest.json`. Resolved relative to\n * this module — the compiled layout is `<pkg>/dist/services/platform/manifest.mjs`\n * (two directory levels up = `<pkg>/dist/`), the source layout is\n * `<pkg>/src/services/platform/manifest.ts` (four levels up = the pnpm parent\n * dir, then `<pkg>/dist/`). Both candidates are tried; absent or unparsable →\n * null.\n */\nexport function readInImagePlatformManifest(): PlatformReleaseManifest | null {\n const moduleFile = fileURLToPath(import.meta.url);\n const candidates = [\n join(moduleFile, \"..\", \"..\", \"platform-manifest.json\"),\n join(moduleFile, \"..\", \"..\", \"..\", \"..\", \"dist\", \"platform-manifest.json\"),\n ];\n for (const path of candidates) {\n try {\n return PlatformReleaseManifestSchema.parse(JSON.parse(readFileSync(path, \"utf-8\")));\n } catch {\n // try the next layout candidate\n }\n }\n return null;\n}\n\nfunction parseSemver(\n version: string,\n): { major: number; minor: number; patch: number; prerelease?: string } | null {\n const match = /^(\\d+)\\.(\\d+)\\.(\\d+)(?:-([0-9A-Za-z.-]+))?$/.exec(version.trim());\n if (!match) return null;\n return {\n major: Number(match[1]),\n minor: Number(match[2]),\n patch: Number(match[3]),\n ...(match[4] ? { prerelease: match[4] } : {}),\n };\n}\n\nexport interface PlatformCompatSubject {\n /** The child's recorded platform pin / installed framework version. */\n platformVersion?: string;\n catalog: Record<string, string>;\n}\n\nexport interface PlatformCompatViolation {\n kind: \"minChild\" | \"shared-dep\";\n name?: string;\n message: string;\n}\n\n/**\n * The additive compat gate (ADR 0034 pt 5): the child's framework version must\n * sit inside the release's compat window, and strict singletons must agree\n * exactly with the release's pins. A sibling of the federation check — never\n * a relaxation of it.\n */\nexport function checkPlatformCompat(\n manifest: PlatformReleaseManifest,\n subject: PlatformCompatSubject,\n): PlatformCompatViolation[] {\n const violations: PlatformCompatViolation[] = [];\n\n if (subject.platformVersion) {\n if (compareSemver(subject.platformVersion, manifest.compat.minChild) < 0) {\n violations.push({\n kind: \"minChild\",\n message: `platform ${subject.platformVersion} is older than this release's compat floor ${manifest.compat.minChild}`,\n });\n }\n if (compareSemver(subject.platformVersion, manifest.frameworkVersion) > 0) {\n violations.push({\n kind: \"minChild\",\n message: `platform ${subject.platformVersion} is newer than this release ${manifest.frameworkVersion}`,\n });\n }\n }\n\n for (const [name, pin] of Object.entries(manifest.sharedDeps)) {\n const childVersion = subject.catalog[name];\n if (pin.strictVersion) {\n if (!childVersion) {\n violations.push({\n kind: \"shared-dep\",\n name,\n message: `strict singleton \"${name}\" is missing from the child catalog (release pins ${pin.version})`,\n });\n continue;\n }\n if (childVersion !== pin.version) {\n violations.push({\n kind: \"shared-dep\",\n name,\n message: `strict singleton \"${name}\" is ${childVersion}, the release pins ${pin.version}`,\n });\n }\n continue;\n }\n if (typeof pin.requiredVersion === \"string\" && childVersion) {\n if (!satisfiesConstraint(childVersion, pin.requiredVersion)) {\n violations.push({\n kind: \"shared-dep\",\n name,\n message: `\"${name}\" is ${childVersion}, which does not satisfy the release range ${pin.requiredVersion}`,\n });\n }\n }\n }\n\n return violations;\n}\n\n/**\n * Resolution (ADR 0034 pt 3): one authored `platform` pin in, one resolved\n * manifest out. Absent pin = latest via extends (nearest chain manifest);\n * explicit pins match exactly or fail loud. The `.bos/platform-manifest.json`\n * cache carries offline dev; network failure with no usable cache → null\n * (today's behavior). All I/O is injectable — the test seam.\n */\nexport interface ResolvedPlatformManifest {\n manifest: PlatformReleaseManifest;\n source: { account: string; gateway: string };\n fromCache: boolean;\n /** Where the resolved bytes came from (#574): an immutable version slot\n * (an exact pin's target) or the moving `platform.json` pointer (unpinned\n * \"latest\" resolution). */\n provenance: \"slot\" | \"pointer\";\n}\n\nexport interface PlatformManifestCache {\n schemaVersion: 1;\n kind: \"everything-dev/platform-manifest-cache\";\n resolvedAt: string;\n source: { account: string; gateway: string };\n manifest: PlatformReleaseManifest;\n provenance?: \"slot\" | \"pointer\";\n}\n\n/**\n * How long a cached resolution may stand in for a live fetch. The cache\n * exists for offline dev ONLY (#574) — never stale-pin grace: slot-first\n * resolution makes old pins resolvable forever from immutable slots, so a\n * cache can no longer be the reason a pin resolves. Without a freshness\n * bound a registry outage (or a cache written before the parent's latest\n * publish) silently serves a months-old release manifest — pins derive\n * from it and the mismatch can take an hour to diagnose. Past the TTL the\n * cache is refused: pin-less resolution degrades to \"no manifest\"; pinned\n * resolution fails loud with the slot key named.\n */\nexport const PLATFORM_MANIFEST_CACHE_TTL_MS = 24 * 60 * 60_000;\n\nexport interface ResolvePlatformManifestOptions {\n configDir: string;\n localConfig: Record<string, unknown>;\n fetchManifest?: (account: string, gateway: string) => Promise<PlatformReleaseManifest | null>;\n /** The immutable version-slot read (#574) — an exact pin's target. Throws\n * on read failure (distinct from a clean absent-slot null). */\n fetchSlot?: (account: string, gateway: string, version: string) => Promise<unknown>;\n fetchParent?: (account: string, gateway: string) => Promise<Record<string, unknown> | null>;\n cacheRead?: () => PlatformManifestCache | null;\n cacheWrite?: (cached: PlatformManifestCache) => void;\n /** injectable clock for the cache-freshness check (test seam) */\n now?: () => number;\n /** injectable freshness bound (test seam); defaults to {@link PLATFORM_MANIFEST_CACHE_TTL_MS} */\n cacheTtlMs?: number;\n}\n\nconst CACHE_DIR = \".bos\";\nconst CACHE_FILE = \"platform-manifest.json\";\n\n/**\n * A cached resolution stands in for a live fetch only while it is fresh:\n * `resolvedAt` inside the TTL, and parseable (a cache with an unparseable\n * timestamp is treated as stale — never trusted).\n */\nfunction isFresh(cached: PlatformManifestCache, opts: ResolvePlatformManifestOptions): boolean {\n const now = (opts.now ?? Date.now)();\n const ttl = opts.cacheTtlMs ?? PLATFORM_MANIFEST_CACHE_TTL_MS;\n const resolvedAt = Date.parse(cached.resolvedAt);\n if (Number.isNaN(resolvedAt)) return false;\n return now - resolvedAt <= ttl;\n}\n\nfunction defaultCachePath(configDir: string): string {\n return join(configDir, CACHE_DIR, CACHE_FILE);\n}\n\nfunction defaultCacheRead(configDir: string): PlatformManifestCache | null {\n try {\n const raw = JSON.parse(\n readFileSync(defaultCachePath(configDir), \"utf-8\"),\n ) as PlatformManifestCache;\n return raw?.kind === \"everything-dev/platform-manifest-cache\" ? raw : null;\n } catch {\n return null;\n }\n}\n\nfunction defaultCacheWrite(configDir: string, cached: PlatformManifestCache): void {\n try {\n mkdirSync(join(configDir, CACHE_DIR), { recursive: true });\n writeFileSync(defaultCachePath(configDir), `${JSON.stringify(cached, null, 2)}\\n`);\n } catch {\n // cache writes never fail the resolution\n }\n}\n\nfunction defaultFetchManifest(\n account: string,\n gateway: string,\n): Promise<PlatformReleaseManifest | null> {\n return (async () => {\n const raw = await fetchRegistryKeyOrNull<unknown>(account, gateway, \"platform.json\");\n if (!raw) return null;\n return PlatformReleaseManifestSchema.parse(raw);\n })();\n}\n\nfunction defaultFetchSlot(account: string, gateway: string, version: string): Promise<unknown> {\n // NOT the OrNull variant: a read failure must stay distinguishable from a\n // clean absent-slot — the resolver fails loud with the slot key on a\n // failure and treats null as absence.\n return fetchRegistryKey<unknown>(account, gateway, `platform-versions/${version}.json`);\n}\n\nfunction defaultFetchParent(\n account: string,\n gateway: string,\n): Promise<Record<string, unknown> | null> {\n return fetchParentConfig(account, gateway)\n .then((config) => config as Record<string, unknown>)\n .catch(() => null);\n}\n\nexport interface ExtendsChainNode {\n account: string;\n gateway: string;\n}\n\nexport interface ExtendsChainWalk {\n /** child → root, nearest first — `chain[0]` is the local extends target */\n chain: ExtendsChainNode[];\n /** the most rootward `repository` seen — parent configs override the child's */\n repository?: string;\n /** set when the walk revisits a node — a pathological extends chain */\n circularAt?: string;\n}\n\n/**\n * The ONE extends-chain walk (child → root via FastKV parent configs): both\n * `resolvePlatformManifest` and the upgrade source resolution used to carry\n * their own `fetchParentConfig` loops; this is the shared implementation.\n * A fetch failure (throw or null) stops the walk — the chain gathered so far\n * is still returned.\n */\nexport async function walkExtendsChain(input: {\n localConfig: Record<string, unknown>;\n localRepository?: string;\n fetchParent?: (account: string, gateway: string) => Promise<Record<string, unknown> | null>;\n}): Promise<ExtendsChainWalk> {\n const fetchParent = input.fetchParent ?? defaultFetchParent;\n const chain: ExtendsChainNode[] = [];\n let repository = input.localRepository;\n\n const startsRef = getExtendsRef(input.localConfig);\n let cursor: ExtendsChainNode | null =\n typeof startsRef === \"string\" && startsRef.startsWith(\"bos://\")\n ? (parseBosRef(startsRef) ?? null)\n : null;\n const visited = new Set<string>();\n let circularAt: string | undefined;\n\n while (cursor) {\n const ref = `bos://${cursor.account}/${cursor.gateway}`;\n if (visited.has(ref)) {\n circularAt = ref;\n break;\n }\n visited.add(ref);\n chain.push(cursor);\n\n const parentConfig = await fetchParent(cursor.account, cursor.gateway);\n if (!parentConfig) break;\n if (typeof parentConfig.repository === \"string\" && parentConfig.repository) {\n repository = parentConfig.repository;\n }\n const nextRef = getExtendsRef(parentConfig);\n cursor =\n typeof nextRef === \"string\" && nextRef.startsWith(\"bos://\")\n ? (parseBosRef(nextRef) ?? null)\n : null;\n }\n\n return {\n chain,\n ...(repository !== undefined ? { repository } : {}),\n ...(circularAt ? { circularAt } : {}),\n };\n}\n\nexport async function resolvePlatformManifest(\n opts: ResolvePlatformManifestOptions,\n): Promise<ResolvedPlatformManifest | null> {\n const fetchManifest =\n opts.fetchManifest ?? ((a: string, g: string) => defaultFetchManifest(a, g));\n const fetchSlot =\n opts.fetchSlot ?? ((a: string, g: string, v: string) => defaultFetchSlot(a, g, v));\n const cacheRead = opts.cacheRead ?? (() => defaultCacheRead(opts.configDir));\n const cacheWrite = opts.cacheWrite ?? ((cached) => defaultCacheWrite(opts.configDir, cached));\n\n const { chain } = await walkExtendsChain({\n localConfig: opts.localConfig,\n ...(opts.fetchParent ? { fetchParent: opts.fetchParent } : {}),\n });\n\n const writeCache = (\n manifest: PlatformReleaseManifest,\n source: { account: string; gateway: string },\n provenance: \"slot\" | \"pointer\",\n ) => {\n const cached: PlatformManifestCache = {\n schemaVersion: 1,\n kind: \"everything-dev/platform-manifest-cache\",\n resolvedAt: new Date().toISOString(),\n source,\n manifest,\n provenance,\n };\n cacheWrite(cached);\n return { manifest, source, fromCache: false, provenance };\n };\n\n const pin = typeof opts.localConfig.platform === \"string\" ? opts.localConfig.platform : undefined;\n\n // Slot-first pin resolution (#574): an exact pin targets the immutable\n // `platform-versions/<pin>.json` slot, scanning the extends chain — a root\n // release never strands a child pin, because slots are immutable and the\n // pointer only moves forward (the #546 stale-pin class is dead). The\n // pointer serves only unpinned (\"latest\") resolution.\n if (pin) {\n for (const node of chain) {\n const slotKey = getPlatformVersionSlotKey(node.account, node.gateway, pin);\n let raw: unknown;\n try {\n raw = await fetchSlot(node.account, node.gateway, pin);\n } catch (error) {\n // Slot read failure: the offline cache may stand in (an offline-dev\n // aid, not stale-pin grace — same pin match required) — otherwise\n // fail with the slot key named.\n const cached = cacheRead();\n if (cached && cached.manifest.frameworkVersion === pin && isFresh(cached, opts)) {\n return {\n manifest: cached.manifest,\n source: cached.source,\n fromCache: true,\n provenance: cached.provenance ?? \"slot\",\n };\n }\n throw new Error(\n `platform pin ${pin}: the version slot read failed (${slotKey}): ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n if (raw) {\n const manifest = PlatformReleaseManifestSchema.parse(raw);\n return writeCache(manifest, node, \"slot\");\n }\n }\n // Slot miss across the chain — the pin names a release whose manifest\n // leg never published (the npm-version-exists / manifest-not-published\n // race, #568). The old \"pin not found, publish the release or clear the\n // pin\" dead path is gone: slots are immutable, so this state means the\n // release deploy must be re-run.\n throw new Error(\n `platform pin ${pin}: no version slot in the extends chain` +\n `${chain.length > 0 ? ` (${chain.map((n) => `bos://${n.account}/${n.gateway}`).join(\" → \")})` : \"\"} — ` +\n `the release's manifest leg never published it; re-run the release deploy (or \\`bos upgrade\\` to re-pin)`,\n );\n }\n\n for (const node of chain) {\n const manifest = await fetchManifest(node.account, node.gateway);\n if (!manifest) continue;\n return writeCache(manifest, node, \"pointer\");\n }\n\n const cached = cacheRead();\n if (cached && isFresh(cached, opts)) {\n return {\n manifest: cached.manifest,\n source: cached.source,\n fromCache: true,\n provenance: cached.provenance ?? \"pointer\",\n };\n }\n return null;\n}\n\n/**\n * The platform release manifest as a Context.Service: the same \"module is\n * the implementation, the tag is the seam\" shape as FastKVRegistryService —\n * CLI handlers `yield*` the tag; pure and standalone callers keep using the\n * plain functions. Tests provide `Layer.succeed` fakes instead of module\n * mocks.\n */\nexport class PlatformManifestService extends Context.Service<\n PlatformManifestService,\n {\n resolvePlatformManifest: typeof resolvePlatformManifest;\n composePlatformReleaseManifest: typeof composePlatformReleaseManifest;\n checkPlatformCompat: typeof checkPlatformCompat;\n readInImagePlatformManifest: typeof readInImagePlatformManifest;\n }\n>()(\"everything-dev/platform/manifest\") {\n static readonly Live = Layer.succeed(\n this,\n this.of({\n resolvePlatformManifest,\n composePlatformReleaseManifest,\n checkPlatformCompat,\n readInImagePlatformManifest,\n }),\n );\n}\n"],"mappings":"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"}