Files
Momento/memento-note/lib/interactive-demo/schema.ts
Antigravity 80ccc1f6de
All checks were successful
CI / Lint, Unit Tests & Build (push) Successful in 7m14s
CI / Deploy production (on server) (push) Successful in 1m25s
feat: dashboard Second Brain, essai 7 jours et vérification e-mail
Rendre le dashboard actionnable (inbox, peek, carte mentale), aligner la facturation sur l’essai 7 jours, et bloquer le login e-mail tant que l’adresse n’est pas confirmée.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-30 07:19:36 +00:00

137 lines
3.5 KiB
TypeScript

import { z } from 'zod'
import {
ANNOTATION_KINDS,
CHART_TYPES,
INTENT_IDS,
INTERACTIVE_DEMO_CAPS,
INTERACTIVE_DEMO_SCHEMA_VERSION,
PANEL_TYPES,
PATTERN_IDS,
SCOPE_IDS,
TRANSITIONS,
} from './constants'
const intentSchema = z.enum(INTENT_IDS).optional()
const patternSchema = z.enum(PATTERN_IDS)
const scopeSchema = z.enum(SCOPE_IDS)
const revealSchema = z.object({
ids: z.array(z.string().min(1)).min(1),
scope: scopeSchema,
})
const annotationSchema = z.object({
kind: z.enum(ANNOTATION_KINDS),
targetIds: z.array(z.string().min(1)).min(1),
scope: scopeSchema,
text: z.string().optional(),
intent: intentSchema,
})
const stepSchema = z.object({
id: z.string().min(1),
speak: z.string().min(1),
pattern: patternSchema.optional(),
pointTo: z.array(z.string().min(1)).optional(),
reveal: z.array(revealSchema).optional(),
annotate: z
.array(annotationSchema)
.max(INTERACTIVE_DEMO_CAPS.maxAnnotationsPerStep)
.optional(),
})
const svgNodeSchema = z.object({
id: z.string().min(1),
label: z.string().optional(),
intent: intentSchema,
})
const svgEdgeSchema = z.object({
id: z.string().min(1),
from: z.string().min(1),
to: z.string().min(1),
style: z.enum(['solid', 'dashed']).optional(),
weight: z.number().min(0).max(5).optional(),
intent: intentSchema,
})
const svgScenePayloadSchema = z.object({
nodes: z.array(svgNodeSchema).min(1),
edges: z.array(svgEdgeSchema).optional(),
})
const chartSeriesSchema = z.object({
id: z.string().min(1),
label: z.string().optional(),
values: z.array(z.number()),
intent: intentSchema,
})
const chartPayloadSchema = z.object({
chartType: z.enum(CHART_TYPES),
series: z.array(chartSeriesSchema).min(1),
})
const heatmapPayloadSchema = z.object({
rows: z.number().int().positive().max(50),
cols: z.number().int().positive().max(50),
values: z.array(z.array(z.number())),
triangular: z.enum(['lower', 'upper', 'none']).optional(),
rowLabels: z.array(z.string()).optional(),
colLabels: z.array(z.string()).optional(),
})
const panelSchema = z.discriminatedUnion('type', [
z.object({
id: z.string().min(1),
type: z.literal('svg-scene'),
payload: svgScenePayloadSchema,
}),
z.object({
id: z.string().min(1),
type: z.literal('chart'),
payload: chartPayloadSchema,
}),
z.object({
id: z.string().min(1),
type: z.literal('heatmap-matrix'),
payload: heatmapPayloadSchema,
}),
])
const sceneSchema = z.object({
id: z.string().min(1).optional(),
panels: z
.array(panelSchema)
.min(1)
.max(INTERACTIVE_DEMO_CAPS.maxPanelsPerScene),
})
const actSchema = z.object({
id: z.string().min(1),
title: z.string().min(1),
scene: sceneSchema.optional(),
transition: z.enum(TRANSITIONS).optional(),
pattern: patternSchema.optional(),
steps: z.array(stepSchema).min(1).max(INTERACTIVE_DEMO_CAPS.maxStepsPerAct),
})
/** Loose BCP-47: primary tag + optional subtags (fr, en, zh-Hans, pt-BR). */
const langSchema = z
.string()
.regex(/^[a-zA-Z]{2,3}(-[a-zA-Z0-9]{2,8})*$/, 'Invalid BCP-47 language tag')
export const interactiveDemoV1Schema = z.object({
schemaVersion: z.literal(INTERACTIVE_DEMO_SCHEMA_VERSION),
id: z.string().min(1),
lang: langSchema,
disclaimer: z.string().optional(),
scene: sceneSchema,
acts: z.array(actSchema).min(1).max(INTERACTIVE_DEMO_CAPS.maxActs),
})
export type InteractiveDemoV1Parsed = z.infer<typeof interactiveDemoV1Schema>
/** Re-export allowlists for callers that need them at runtime. */
export { PANEL_TYPES, PATTERN_IDS }