diff --git a/apps/tangle-cloud/src/blueprintApps/manifest.ts b/apps/tangle-cloud/src/blueprintApps/manifest.ts index 0691658d4..895081d7c 100644 --- a/apps/tangle-cloud/src/blueprintApps/manifest.ts +++ b/apps/tangle-cloud/src/blueprintApps/manifest.ts @@ -377,9 +377,15 @@ export function buildBlueprintManifestFromMetadata( }); manifest.externalApp = externalAppParsed.externalApp; + // Declarative tier is unlocked at the URI-bound trust level + // (`verified-uri`) or stronger. The stricter `productionReady` gate + // (IPFS + signed attestation) is kept for `metadataVerified` below, + // which controls iframe/externalApp embedding — that needs payload + // attestation, not just URI binding. const allowDeclarativeTier = manifestRoot !== null && - blueprint.metadataVerification?.productionReady === true; + (blueprint.metadataVerification?.productionReady === true || + blueprint.metadataVerification?.status === 'verified-uri'); const trustedExternalApp = manifest.externalApp?.trust === 'trusted' ? manifest.externalApp diff --git a/apps/tangle-cloud/src/blueprintApps/registry.ts b/apps/tangle-cloud/src/blueprintApps/registry.ts index 1bb2d0f22..f25cca04f 100644 --- a/apps/tangle-cloud/src/blueprintApps/registry.ts +++ b/apps/tangle-cloud/src/blueprintApps/registry.ts @@ -1,11 +1,31 @@ import { resolveBlueprintAppView } from './resolver'; import type { BlueprintAppEntry } from './types'; +/** + * Per-network blueprintId → curated-entry slug bindings. + * + * The upstream `BlueprintAppEntry` type only carries a single `blueprintId`, + * but in practice one curated app (e.g. the sandbox) maps to multiple + * on-chain IDs across networks and across retries (Base Sepolia currently + * has the sandbox registered at ids 0, 1, and 2). This map is the single + * source of truth for those bindings — `getBlueprintAppByBlueprintId` + * consults it first. + * + * Update this when: + * - re-registering a curated app on a new network + * - landing a brand new curated entry that ships with a known id + */ +const CURATED_BLUEPRINT_ID_TO_SLUG: ReadonlyMap = new Map([ + // Base Sepolia (chainId 84532) — see deployments/base-sepolia/blueprints.tsv + [0n, 'sandbox'], + [1n, 'sandbox'], + [2n, 'sandbox'], +]); + const entries = [ { slug: 'trading', canonicalSlug: 'trading', - blueprintId: 1n, publisher: { label: 'Tangle Labs', visibility: 'first-party', @@ -198,9 +218,11 @@ export function getBlueprintAppByCanonicalSlug( export function getBlueprintAppByBlueprintId( blueprintId: bigint, ): BlueprintAppEntry | null { - for (const entry of blueprintAppEntries) { - if (entry.blueprintId === blueprintId) { - return entry; + const mappedSlug = CURATED_BLUEPRINT_ID_TO_SLUG.get(blueprintId); + if (mappedSlug) { + const mapped = blueprintAppRegistry.get(mappedSlug); + if (mapped) { + return mapped; } } diff --git a/apps/tangle-cloud/src/components/Header.tsx b/apps/tangle-cloud/src/components/Header.tsx index d4628e891..2ce210c05 100644 --- a/apps/tangle-cloud/src/components/Header.tsx +++ b/apps/tangle-cloud/src/components/Header.tsx @@ -53,7 +53,7 @@ export default function Header({ return (
= ({ isExpandedByDefault, onExpandedChange }) => { <>