| |
| |
| |
|
|
| import { |
| isValidGenAttrCachedRunPayload, |
| parseGenAttrCachedRunPayload, |
| type GenAttrCachedRun, |
| } from '../../shared/storage/genAttributeRunCache'; |
| import { GEN_ATTRIBUTE_BUNDLED_DEMOS } from './genAttributeBundledDemoManifest.generated'; |
|
|
| const BASE = 'assets/demos/causal_flow/'; |
|
|
| function baseUrl(): URL { |
| return new URL(BASE, window.location.href); |
| } |
|
|
| function isSafeDemoSlug(s: string): boolean { |
| if (s.length === 0 || s.length > 512) return false; |
| if (s.includes('..') || s.includes('/') || s.includes('\\')) return false; |
| return true; |
| } |
|
|
| const payloadCache = new Map<string, GenAttrCachedRun>(); |
| const payloadInflight = new Map<string, Promise<GenAttrCachedRun | undefined>>(); |
|
|
| export type BundledDemoListEntry = { id: string; label: string; featuredStyle?: string }; |
|
|
| |
| export function getBundledGenAttributeDemoList(): readonly BundledDemoListEntry[] { |
| return GEN_ATTRIBUTE_BUNDLED_DEMOS.map(({ slug, label, featured }) => ({ |
| id: slug, |
| label, |
| ...(featured ? { featuredStyle: featured } : {}), |
| })); |
| } |
|
|
| |
| export function getBundledGenAttributeDemoLabel(slug: string): string { |
| const s = slug.trim(); |
| const hit = GEN_ATTRIBUTE_BUNDLED_DEMOS.find((d) => d.slug === s); |
| return hit?.label ?? s; |
| } |
|
|
| |
| |
| |
| export async function fetchBundledGenAttributeDemoBySlug( |
| slug: string |
| ): Promise<GenAttrCachedRun | undefined> { |
| const s = slug.trim(); |
| if (!s || !isSafeDemoSlug(s)) return undefined; |
| const hit = payloadCache.get(s); |
| if (hit) return hit; |
| let inflight = payloadInflight.get(s); |
| if (!inflight) { |
| inflight = (async (): Promise<GenAttrCachedRun | undefined> => { |
| const fileUrl = new URL(`${encodeURIComponent(s)}.json`, baseUrl()); |
| const r = await fetch(fileUrl); |
| if (!r.ok) return undefined; |
| const raw: unknown = await r.json(); |
| const parsed = parseGenAttrCachedRunPayload(raw, `bundled demo slug=${s}`); |
| if (!parsed) return undefined; |
| payloadCache.set(s, parsed); |
| return parsed; |
| })().finally(() => { |
| payloadInflight.delete(s); |
| }); |
| payloadInflight.set(s, inflight); |
| } |
| return inflight; |
| } |
|
|
| export function isGenAttrRunPayloadValidForUi(rec: GenAttrCachedRun | undefined): boolean { |
| return rec != null && isValidGenAttrCachedRunPayload(rec); |
| } |
|
|