@pipelex/mthds-form 0.29.0 → 0.31.0
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/brand/index.d.ts +21 -104
- package/dist/brand/index.js +9 -382
- package/dist/brand/index.js.map +1 -1
- package/dist/{chunk-ZX52CQJ4.js → chunk-2UCH4AAO.js} +3 -3
- package/dist/{chunk-ZX52CQJ4.js.map → chunk-2UCH4AAO.js.map} +1 -1
- package/dist/{chunk-RHX7LQRL.js → chunk-ENK5QTUK.js} +390 -128
- package/dist/chunk-ENK5QTUK.js.map +1 -0
- package/dist/{chunk-ZB4RYUKV.js → chunk-HVWE3TTC.js} +3 -3
- package/dist/{chunk-ZB4RYUKV.js.map → chunk-HVWE3TTC.js.map} +1 -1
- package/dist/chunk-UZNRJWN5.js +721 -0
- package/dist/chunk-UZNRJWN5.js.map +1 -0
- package/dist/{chunk-IBBAJXIO.js → chunk-XVGAQ4RK.js} +4 -4
- package/dist/{chunk-IBBAJXIO.js.map → chunk-XVGAQ4RK.js.map} +1 -1
- package/dist/core/derive.js +2 -2
- package/dist/core/gate.js +3 -3
- package/dist/core/index.js +12 -12
- package/dist/core/values.js +3 -3
- package/dist/generative/index.d.ts +474 -79
- package/dist/generative/index.js +1261 -512
- package/dist/generative/index.js.map +1 -1
- package/dist/layout-design.mthds +133 -6
- package/dist/react/index.d.ts +24 -6
- package/dist/react/index.js +7 -7
- package/dist/styles-BoXPBjF4.d.ts +258 -0
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/dist/chunk-QFX332LE.js +0 -22
- package/dist/chunk-QFX332LE.js.map +0 -1
- package/dist/chunk-RHX7LQRL.js.map +0 -1
- package/dist/manifest-DUeAWeqa.d.ts +0 -17
package/dist/brand/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/brand/contract.ts","../../src/brand/tokens.ts","../../src/brand/stated.ts","../../src/brand/provenance.ts","../../src/brand/compile.ts","../../src/brand/assemble.ts","../../src/brand/seed-roles.ts"],"names":["z","description"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * The brand contract, as data: which token of a brand's `tokens.json` sets\n * which custom property, and what that property paints.\n *\n * It is the theme contract seen from the other side. `src/styles/theme.css`\n * states it as a working default and `docs/theming.md` in prose; this is the\n * same list as a table a build can read, and a brand is exactly these tokens\n * and no others - the validator refuses a file that adds one, because a token\n * nothing consumes is a value with no way to be looked at.\n *\n * The colour and radius rows are not a second list kept beside `theme.css`:\n * they are held to it, by `__tests__/contract.test.ts` over the source and by\n * `scripts/assert-bundle.mjs` over the build. The two typography rows are the\n * exception, and on purpose. `--font-sans` and `--font-mono` are the names of\n * Tailwind's own theme variables, which the prebuilt sheet already declares,\n * so `theme.css` does not define them: it is unlayered, and a value there\n * would override the typeface of every host that loads it. The stock\n * typeface is therefore the host's own, and only a brand's scope sets these\n * two. See docs/brand.md.\n */\n\nexport type ContractTokenType = 'color' | 'dimension' | 'fontFamily';\n\nexport interface ContractToken {\n /** The DTCG token id, `color.background`. */\n id: string;\n /** The custom property it sets, `--background`. */\n variable: string;\n type: ContractTokenType;\n /** What the property paints, in the words a producer is told. */\n paints: string;\n}\n\n/** The colour tokens, in the order `theme.css` states them. */\nexport const COLOR_TOKEN_NAMES = [\n 'background',\n 'foreground',\n 'card',\n 'card-foreground',\n 'popover',\n 'popover-foreground',\n 'primary',\n 'primary-foreground',\n 'secondary',\n 'secondary-foreground',\n 'muted',\n 'muted-foreground',\n 'accent',\n 'accent-foreground',\n 'destructive',\n 'destructive-foreground',\n 'border',\n 'input',\n 'ring',\n] as const;\n\nexport type ColorTokenName = (typeof COLOR_TOKEN_NAMES)[number];\n\nexport function isColorTokenName(name: string): name is ColorTokenName {\n return (COLOR_TOKEN_NAMES as readonly string[]).includes(name);\n}\n\nconst COLOR_PAINTS: Record<ColorTokenName, string> = {\n background: 'The page canvas.',\n foreground: 'Text on the canvas.',\n card: \"A raised surface on the canvas: the rail's panel, a list's rows. May be translucent.\",\n 'card-foreground': 'Text on a card.',\n popover: \"A floating surface: a select's menu, a tooltip. Opaque.\",\n 'popover-foreground': 'Text on a popover.',\n primary: 'The accent: the run button, a selected pill, a section number, a highlight.',\n 'primary-foreground': 'Text on the accent.',\n secondary: 'A quiet filled surface: a secondary button, an unselected segment.',\n 'secondary-foreground': 'Text on a secondary surface.',\n muted: \"A subdued fill: a table's header band, an inactive tab strip.\",\n 'muted-foreground':\n \"Secondary text: descriptions, hints, a summary row's label. Most of the text on the page that is not a heading or a value.\",\n accent: 'A hover fill: a menu item under the pointer.',\n 'accent-foreground': 'Text on an accent fill.',\n destructive: 'The error colour: an invalid mark, a remove button.',\n 'destructive-foreground': 'Text on the destructive colour.',\n border: 'The hairline: every border and divider.',\n input:\n \"The control surface, a field's own fill - a step off the canvas, so fields read as one family.\",\n ring: 'The focus ring.',\n};\n\nexport const BRAND_CONTRACT: readonly ContractToken[] = [\n ...COLOR_TOKEN_NAMES.map((name): ContractToken => ({\n id: `color.${name}`,\n variable: `--${name}`,\n type: 'color',\n paints: COLOR_PAINTS[name],\n })),\n {\n id: 'radius.base',\n variable: '--radius',\n type: 'dimension',\n paints: 'The corner radius of a control; cards take one and a half of it.',\n },\n {\n id: 'font.sans',\n variable: '--font-sans',\n type: 'fontFamily',\n paints: 'The typeface of everything on the page.',\n },\n {\n id: 'font.mono',\n variable: '--font-mono',\n type: 'fontFamily',\n paints: 'Tags, numbers, the receipt.',\n },\n];\n\n/**\n * The pairs that must clear WCAG AA in both modes, as they render: the canvas\n * opaque, the ink blended over it by its alpha.\n */\nexport const CONTRAST_PAIRS: readonly {\n foreground: ColorTokenName;\n background: ColorTokenName;\n}[] = [\n { foreground: 'foreground', background: 'background' },\n { foreground: 'muted-foreground', background: 'background' },\n];\n\n/** The minimum contrast ratio those pairs must reach: WCAG 2 AA for normal text. */\nexport const MIN_CONTRAST = 4.5;\n\nconst byId = new Map(BRAND_CONTRACT.map((token) => [token.id, token]));\n\n/** The custom property a token sets, or a loud failure for a token the contract does not name. */\nexport function contractVariable(id: string): string {\n const token = byId.get(id);\n if (!token) throw new Error(`The brand contract has no token ${id}.`);\n return token.variable;\n}\n","import { z } from 'zod';\nimport {\n COLOR_TOKEN_NAMES,\n type ColorTokenName,\n CONTRAST_PAIRS,\n isColorTokenName,\n MIN_CONTRAST,\n} from './contract';\n\n/**\n * A brand's `tokens.json`, validated against the contract.\n *\n * The file is standard DTCG (the Design Tokens Community Group format, 2025.10),\n * and DTCG is looser than the contract in every direction that matters here: it\n * accepts any token, any colour space, a string colour, and a mode of any name.\n * Each of those is a way for a producer's file to be wrong and a page to be\n * painted anyway. So this holds the contract's own rules - exactly its tokens,\n * object colours in sRGB whose hex agrees with their components, aliases only\n * to contract tokens and never in a cycle, a description on every token, `dark`\n * the only mode and stated on every colour object (an alias may stand for both\n * modes), the contrast pairs in both modes - and a file it accepts is one the\n * compiler can only render. Every problem is named by its path, all at once,\n * so a producer's repair round is handed the whole list.\n */\n\nconst component = z.number().min(0).max(1);\n\nexport const srgbColorSchema = z.strictObject({\n colorSpace: z.literal('srgb'),\n components: z.tuple([component, component, component]),\n alpha: z.number().min(0).max(1),\n hex: z\n .string()\n .regex(/^#[0-9a-f]{6}$/i, 'a hex colour is #rrggbb')\n .optional(),\n});\n\nexport type SrgbColor = z.infer<typeof srgbColorSchema>;\n\nconst colorAliasSchema = z\n .string()\n .regex(/^\\{color\\.[a-z][a-z-]*\\}$/, 'an alias is \"{color.<name>}\"');\n\nconst colorValueSchema = z.union([srgbColorSchema, colorAliasSchema]);\n\nexport type ColorValue = z.infer<typeof colorValueSchema>;\n\nconst description = z.string().min(1, 'every token carries a $description');\n\n/**\n * A C0 control or DEL. Written as a test on the code point rather than a\n * character class, since that range is what a regex may not spell\n * (`no-control-regex`).\n */\nexport function isControlCharacter(char: string): boolean {\n const code = char.codePointAt(0)!;\n return code < 0x20 || code === 0x7f;\n}\n\nconst colorTokenSchema = z\n .strictObject({\n $value: colorValueSchema,\n $description: description,\n $extensions: z\n .strictObject({\n mode: z.strictObject({ dark: colorValueSchema }),\n })\n .optional(),\n })\n .refine((token) => token.$extensions !== undefined || typeof token.$value === 'string', {\n message: 'a colour carries $extensions.mode.dark; only an alias may stand for both modes',\n path: ['$extensions'],\n });\n\nexport type ColorToken = z.infer<typeof colorTokenSchema>;\n\nconst dimensionTokenSchema = z.strictObject({\n $value: z.strictObject({ value: z.number().min(0), unit: z.enum(['rem', 'px']) }),\n $description: description,\n});\n\nexport type DimensionToken = z.infer<typeof dimensionTokenSchema>;\n\nconst fontFamilyTokenSchema = z.strictObject({\n $value: z\n .array(\n z\n .string()\n .min(1)\n // A face's name never holds one, and a form feed ends a CSS string.\n .refine((name) => ![...name].some(isControlCharacter), {\n message: 'a family name holds no control characters',\n }),\n )\n .min(1),\n $description: description,\n});\n\nexport type FontFamilyToken = z.infer<typeof fontFamilyTokenSchema>;\n\n/** The token file, typed: the contract's groups and tokens, nothing else. */\nexport interface BrandTokens {\n color: { $type: 'color' } & Record<ColorTokenName, ColorToken>;\n radius: { $type: 'dimension'; base: DimensionToken };\n font: { $type: 'fontFamily'; sans: FontFamilyToken; mono: FontFamilyToken };\n}\n\nconst brandTokensSchema = z.strictObject({\n color: z.strictObject({\n $type: z.literal('color'),\n ...Object.fromEntries(COLOR_TOKEN_NAMES.map((name) => [name, colorTokenSchema])),\n }),\n radius: z.strictObject({ $type: z.literal('dimension'), base: dimensionTokenSchema }),\n font: z.strictObject({\n $type: z.literal('fontFamily'),\n sans: fontFamilyTokenSchema,\n mono: fontFamilyTokenSchema,\n }),\n});\n\nexport type TokensValidation =\n { ok: true; tokens: BrandTokens } | { ok: false; problems: string[] };\n\nexport type ColorMode = 'light' | 'dark';\n\n/** The name an alias points at, or null for a colour object. */\nexport function aliasTarget(value: ColorValue): string | null {\n return typeof value === 'string' ? value.slice('{color.'.length, -1) : null;\n}\n\n/** A token's dark value: what it states, or - for an alias that states none - the same alias. */\nexport function darkValue(token: ColorToken): ColorValue {\n return token.$extensions?.mode.dark ?? token.$value;\n}\n\n/** A token's value in a mode. */\nexport function modeValue(token: ColorToken, mode: ColorMode): ColorValue {\n return mode === 'light' ? token.$value : darkValue(token);\n}\n\n/** `#rrggbb` for a colour, its alpha dropped: each channel the byte the compiler writes. */\nexport function colorHex(color: SrgbColor): string {\n return `#${color.components\n .map((channel) =>\n Math.round(channel * 255)\n .toString(16)\n .padStart(2, '0'),\n )\n .join('')}`;\n}\n\n/**\n * Whether a colour compiles to the hex. The hex is what a brand ships for the\n * colour, so any slack here would let a stated accent ship as its neighbour.\n */\nexport function colorIsHex(color: SrgbColor, hex: string): boolean {\n return colorHex(color) === hex.toLowerCase();\n}\n\n/**\n * A colour as the compiler writes it: each channel the byte a hex or `rgb()`\n * carries, the alpha to the three decimals `rgb()` is given, and opaque once it\n * rounds to 1. A page renders this colour, not the components it was produced\n * as, so contrast is measured on it: a grey that passes at full precision can\n * round below the bar.\n */\nexport function asWritten(color: SrgbColor): SrgbColor {\n const alpha = Number(Math.min(color.alpha, 1).toFixed(3));\n return {\n colorSpace: 'srgb',\n components: color.components.map((channel) => Math.round(channel * 255) / 255) as [\n number,\n number,\n number,\n ],\n alpha,\n };\n}\n\nfunction checkHexAgreement(name: string, mode: ColorMode, value: ColorValue, problems: string[]) {\n if (typeof value === 'string' || !value.hex) return;\n if (!colorIsHex(value, value.hex)) {\n problems.push(\n `color.${name} (${mode}): hex ${value.hex} does not agree with components [${value.components.join(', ')}]`,\n );\n }\n}\n\nfunction checkAliases(tokens: BrandTokens, mode: ColorMode, problems: string[]) {\n for (const name of COLOR_TOKEN_NAMES) {\n const seen = new Set<string>([name]);\n let current: ColorTokenName = name;\n for (;;) {\n const target = aliasTarget(modeValue(tokens.color[current], mode));\n if (target === null) break;\n if (!isColorTokenName(target)) {\n problems.push(\n `color.${name} (${mode}): aliases {color.${target}}, which the contract has no token for`,\n );\n break;\n }\n if (seen.has(target)) {\n problems.push(`color.${name} (${mode}): alias cycle through {color.${target}}`);\n break;\n }\n seen.add(target);\n current = target;\n }\n }\n}\n\n/** The colour a token resolves to in a mode, through its aliases; null when a chain is broken. */\nexport function resolveColor(\n tokens: BrandTokens,\n name: ColorTokenName,\n mode: ColorMode,\n): SrgbColor | null {\n const seen = new Set<string>();\n let current: ColorTokenName = name;\n for (;;) {\n if (seen.has(current)) return null;\n seen.add(current);\n const value = modeValue(tokens.color[current], mode);\n const target = aliasTarget(value);\n if (target === null) return value as SrgbColor;\n if (!isColorTokenName(target)) return null;\n current = target;\n }\n}\n\nfunction luminance(color: SrgbColor): number {\n const [r, g, b] = color.components.map((channel) =>\n channel <= 0.04045 ? channel / 12.92 : ((channel + 0.055) / 1.055) ** 2.4,\n ) as [number, number, number];\n return 0.2126 * r + 0.7152 * g + 0.0722 * b;\n}\n\n/** WCAG 2 contrast ratio between two colours, taken as opaque. */\nexport function contrastRatio(a: SrgbColor, b: SrgbColor): number {\n const la = luminance(a);\n const lb = luminance(b);\n const [light, dark] = la > lb ? [la, lb] : [lb, la];\n return (light + 0.05) / (dark + 0.05);\n}\n\n/** A colour as it renders over an opaque one: the two blended by its alpha, as a browser does. */\nexport function composite(color: SrgbColor, over: SrgbColor): SrgbColor {\n const components = color.components.map(\n (channel, index) => channel * color.alpha + over.components[index]! * (1 - color.alpha),\n ) as [number, number, number];\n return { colorSpace: 'srgb', components, alpha: 1 };\n}\n\n/**\n * Each contrast pair as it renders. The canvas must be opaque, since a\n * translucent one shows whatever the host paints beneath it and its contrast is\n * nobody's to promise; the ink is blended over it, so a translucent ink is\n * measured at the strength it actually has, and a transparent one fails. Both\n * are measured as the compiler writes them, which is what renders.\n */\nfunction checkContrast(tokens: BrandTokens, mode: ColorMode, problems: string[]) {\n for (const pair of CONTRAST_PAIRS) {\n const foreground = resolveColor(tokens, pair.foreground, mode);\n const background = resolveColor(tokens, pair.background, mode);\n if (!foreground || !background) continue;\n if (background.alpha < 1) {\n problems.push(\n `color.${pair.background} (${mode}): alpha ${background.alpha}, but text is measured against it, so it must be opaque (alpha 1)`,\n );\n continue;\n }\n const canvas = asWritten(background);\n const ratio = contrastRatio(composite(asWritten(foreground), canvas), canvas);\n if (ratio < MIN_CONTRAST) {\n problems.push(\n `color.${pair.foreground} on color.${pair.background} (${mode}): contrast ${ratio.toFixed(2)}, expected ${MIN_CONTRAST} (WCAG AA)`,\n );\n }\n }\n}\n\n/** Every problem with the file at once, so a producer's repair round sees the whole list. */\nexport function validateBrandTokens(doc: unknown): TokensValidation {\n const parsed = brandTokensSchema.safeParse(doc);\n if (!parsed.success) {\n return {\n ok: false,\n problems: parsed.error.issues.map((issue) => {\n const where = issue.path.map(String).join('.') || '(root)';\n return `${where}: ${issue.message}`;\n }),\n };\n }\n const tokens = parsed.data as unknown as BrandTokens;\n const problems: string[] = [];\n for (const name of COLOR_TOKEN_NAMES) {\n const token = tokens.color[name];\n checkHexAgreement(name, 'light', token.$value, problems);\n checkHexAgreement(name, 'dark', darkValue(token), problems);\n }\n checkAliases(tokens, 'light', problems);\n checkAliases(tokens, 'dark', problems);\n // Contrast is read through the aliases, so it is only meaningful once every\n // chain resolves.\n if (problems.length === 0) {\n checkContrast(tokens, 'light', problems);\n checkContrast(tokens, 'dark', problems);\n }\n return problems.length === 0 ? { ok: true, tokens } : { ok: false, problems };\n}\n","import { z } from 'zod';\nimport { type BrandManifest, httpUrl } from './manifest';\nimport { type BrandTokens, colorHex, colorIsHex, resolveColor } from './tokens';\n\n/**\n * What a person states beside a site's URL: the things a site does not show and\n * no reading can supply. The accent of a site with no button, per mode when its\n * dark canvas needs another, and the logo for a canvas the site draws none for.\n *\n * A stated fact outranks every reading, which whatever runs a producer tells\n * it, outside this package. Here the brand is held to honour it\n * (`statedFactProblems`), and the provenance records it.\n */\n\nconst statedHex = z.string().regex(/^#[0-9a-f]{6}$/i, 'a stated accent is #rrggbb');\n\nexport const statedFactsSchema = z.strictObject({\n /** The accent per mode, `#rrggbb`: what `color.primary` resolves to in that mode. */\n accent: z\n .strictObject({\n light: statedHex.optional(),\n dark: statedHex.optional(),\n })\n .optional(),\n /**\n * The logo for a canvas: `logo.onLight` or `logo.onDark` in the manifest,\n * which the brand must carry exactly, so it obeys the manifest's rule (http\n * or https) or no brand could ever honour it.\n */\n logo: z\n .strictObject({\n onLight: httpUrl.optional(),\n onDark: httpUrl.optional(),\n })\n .optional(),\n});\n\nexport type StatedFacts = z.infer<typeof statedFactsSchema>;\n\n/**\n * Where the brand does not carry what the person stated, in the words a repair\n * round is told. Only the modes and canvases that were stated are checked.\n */\nexport function statedFactProblems(\n stated: StatedFacts | undefined,\n manifest: BrandManifest,\n tokens: BrandTokens,\n): string[] {\n if (!stated) return [];\n const problems: string[] = [];\n for (const mode of ['light', 'dark'] as const) {\n const accent = stated.accent?.[mode];\n if (!accent) continue;\n const primary = resolveColor(tokens, 'primary', mode);\n if (!primary) continue;\n if (!colorIsHex(primary, accent)) {\n problems.push(\n `tokens.json: color.primary (${mode}) resolves to ${colorHex(primary)}, but the accent for ${mode} mode was stated as ${accent}`,\n );\n }\n // A hex carries no alpha, so the components alone would let a primary\n // nobody can see honour the accent: a stated accent is an opaque colour.\n if (primary.alpha < 1) {\n problems.push(\n `tokens.json: color.primary (${mode}) has alpha ${primary.alpha}, but the accent for ${mode} mode was stated as the opaque ${accent}, so it must be opaque (alpha 1)`,\n );\n }\n }\n for (const canvas of ['onLight', 'onDark'] as const) {\n const url = stated.logo?.[canvas];\n if (url && manifest.logo[canvas] !== url) {\n problems.push(\n `brand.json: logo.${canvas} is ${manifest.logo[canvas]}, but the logo for that canvas was stated as ${url}`,\n );\n }\n }\n return problems;\n}\n","import { z } from 'zod';\nimport { statedFactsSchema } from './stated';\n\n/**\n * A brand's `provenance.json`: who produced it, on which model, from which\n * contract and which facts.\n *\n * A brand follows the rules a captured layout follows: produced by a pass,\n * committed with its provenance, and titled by what made it and by nothing\n * else. The provenance is a record, so it is never rewritten to make a check\n * pass. A brand's directory is named by `brandProducerId`, the same recipe a\n * layout fixture's id uses, so the tree and the record cannot disagree about\n * who made a brand.\n */\n\n/** How a brand came to be. */\nexport const BRAND_PRODUCERS = [\n /** The producer method, run on the hosted API. */\n 'pipelex-method',\n /** A Claude Code subagent in a fresh context, given the contract and the facts and nothing else. */\n 'claude-code-subagent',\n /** A Claude Code session reading the site and writing the files by hand. */\n 'claude-code-session',\n] as const;\n\nexport type BrandProducer = (typeof BRAND_PRODUCERS)[number];\n\n/** The first twelve hex digits of a SHA-256: how the provenance names a text it was produced from. */\nconst hash12 = z.string().regex(/^[0-9a-f]{12}$/, 'twelve hex digits');\n\nexport const brandProvenanceSchema = z\n .strictObject({\n producer: z.enum(BRAND_PRODUCERS),\n /** The model id: the one the method ran with, or the Claude Code model behind the session. */\n model: z.string().min(1),\n /** The day it was produced, `YYYY-MM-DD`. */\n date: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/),\n /** The contract brief it was produced from, as the producer recorded its path. */\n brief: z.string().min(1),\n /** The first twelve hex digits of the SHA-256 of the contract brief at the time. */\n contractHash: hash12,\n /** The creative seed handed over with the brief, verbatim, when one was. */\n seed: z.string().min(1).optional(),\n /** What the person stated beside the URL, when they did. */\n stated: statedFactsSchema.optional(),\n /** Where the site facts came from: a file, or a sentence for a brand read by hand. */\n siteFacts: z.string().min(1).optional(),\n /**\n * The first twelve hex digits of the SHA-256 of the file `siteFacts`\n * names, its bytes as the producer read them. A path alone cannot say\n * whether the facts behind it moved since the brand was produced; whatever\n * re-reads them hashes the file again, and a mismatch makes the brand\n * stale, never invalid. The schema refuses one beside no `siteFacts`,\n * but it cannot tell a path from a sentence: a brand read by hand records\n * none by the producer's own rule, and a hash recorded beside a sentence\n * anyway is caught where it is judged, since the sentence names no file.\n */\n siteFactsHash: hash12.optional(),\n /** How many repair rounds the producer ran before the files validated. */\n rounds: z.number().int().min(0).optional(),\n })\n .refine(\n (provenance) => provenance.siteFactsHash === undefined || provenance.siteFacts !== undefined,\n {\n path: ['siteFactsHash'],\n message: 'no siteFacts names the file it hashes',\n },\n );\n\nexport type BrandProvenance = z.infer<typeof brandProvenanceSchema>;\n\n/** The id a brand's directory is named by: `producer--model[--seeded]`. */\nexport function brandProducerId(\n provenance: Pick<BrandProvenance, 'producer' | 'model' | 'seed'>,\n): string {\n return [provenance.producer, provenance.model, provenance.seed ? 'seeded' : null]\n .filter((part): part is string => part !== null)\n .join('--');\n}\n\n/**\n * The scope class a brand's stylesheet sets its tokens on: `brand-<brand>-<producerId>`,\n * with every character outside `[a-z0-9-]` replaced, because a model id\n * carries dots and a dot ends a class selector.\n *\n * The replacement folds: `claude-4.8-opus` and `claude-4-8-opus` share a\n * scope, and so do two ids that differ only in case. A set of brands loaded on\n * one page must therefore check its scopes are distinct, or the later\n * stylesheet silently takes the earlier brand's place.\n */\nexport function brandScope(brand: string, producerId: string): string {\n return `brand-${brand}-${producerId}`.toLowerCase().replace(/[^a-z0-9-]/g, '-');\n}\n","import { BRAND_CONTRACT, COLOR_TOKEN_NAMES, type ColorTokenName } from './contract';\nimport {\n aliasTarget,\n asWritten,\n type BrandTokens,\n colorHex,\n type ColorValue,\n isControlCharacter,\n modeValue,\n type SrgbColor,\n} from './tokens';\n\n/**\n * A validated `tokens.json` in, the brand's stylesheet out.\n *\n * What comes out is exactly the contract, scoped: a `.<scope>` block setting\n * every custom property the contract names, and a `.dark .<scope>` block\n * restating every colour with its dark value. The `.dark` ancestor is the\n * package's own dark-mode convention (`theme.css`, the `dark` variant), so a\n * branded page inside a dark pane picks its dark values up with nothing else\n * to wire.\n *\n * The scope block also sets `font-family: var(--font-sans)`. Tailwind's\n * preflight resolves the page's typeface once, at `<html>`, so a scope that\n * only set `--font-sans` lower in the tree would change no text; declaring the\n * family where the scope is makes the brand's typeface reach everything under\n * it - the produced page and the plain form alike - while a page with no brand\n * keeps the host's own typeface untouched.\n *\n * The contract is closed - a fixed set of tokens, colours in sRGB only, one\n * length, two font stacks - so compiling a file the validator accepted is this\n * function and no dependency. It takes the file as `validateBrandTokens`\n * returned it; anything else is the caller's mistake, and `assembleBrand` is\n * the route that cannot make it. The output stays comparable with what a\n * standard DTCG tool writes for the same file: `__tests__/terrazzo.test.ts`\n * compiles every committed brand through Terrazzo and compares the\n * declarations.\n */\nexport function compileBrand(tokens: BrandTokens, scope: string): string {\n if (!/^[a-z][a-z0-9-]*$/.test(scope)) {\n throw new Error(`compileBrand: \"${scope}\" is not a scope class (see brandScope).`);\n }\n const light: string[] = [];\n const dark: string[] = [];\n for (const name of COLOR_TOKEN_NAMES) {\n const token = tokens.color[name];\n light.push(...declaration(token.$description, `--${name}`, colorCss(name, token.$value)));\n dark.push(\n ...declaration(token.$description, `--${name}`, colorCss(name, modeValue(token, 'dark'))),\n );\n }\n const radius = tokens.radius.base;\n light.push(\n ...declaration(radius.$description, '--radius', `${radius.$value.value}${radius.$value.unit}`),\n );\n for (const key of ['sans', 'mono'] as const) {\n const font = tokens.font[key];\n light.push(...declaration(font.$description, `--font-${key}`, fontStack(font.$value)));\n }\n light.push(\n ' /* The typeface reaches the text here, where the scope is; see compileBrand. */',\n ' font-family: var(--font-sans);',\n );\n return [`.${scope} {`, ...light, '}', '', `.dark .${scope} {`, ...dark, '}', ''].join('\\n');\n}\n\n/** Every custom property a compiled brand sets on its scope, in contract order. */\nexport const BRAND_VARIABLES: readonly string[] = BRAND_CONTRACT.map((token) => token.variable);\n\nfunction declaration(description: string, property: string, value: string): string[] {\n return [` /* ${commentText(description)} */`, ` ${property}: ${value};`];\n}\n\n/**\n * A description as comment text: one line, and nothing that could close the\n * comment, nor the `<style>` element of a host that inlines the stylesheet.\n */\nfunction commentText(text: string): string {\n return text.replace(/\\s+/g, ' ').replace(/\\*\\//g, '* /').replace(/<\\//g, '< /').trim();\n}\n\nfunction colorCss(name: ColorTokenName, value: ColorValue): string {\n const target = aliasTarget(value);\n if (target !== null) {\n // The validator has already refused an alias outside the contract; a\n // stray one here would write a reference to a property nothing sets.\n if (!(COLOR_TOKEN_NAMES as readonly string[]).includes(target)) {\n throw new Error(`compileBrand: color.${name} aliases {color.${target}}.`);\n }\n return `var(--${target})`;\n }\n return srgbCss(value as SrgbColor);\n}\n\n/**\n * An opaque colour as its hex, a translucent one as `rgb()` with its alpha,\n * both as `asWritten` rounds them, which is the colour the validator measured.\n */\nfunction srgbCss(color: SrgbColor): string {\n const { alpha } = asWritten(color);\n if (alpha >= 1) return colorHex(color);\n const [r, g, b] = color.components.map((channel) => Math.round(channel * 255));\n return `rgb(${r} ${g} ${b} / ${alpha})`;\n}\n\n/**\n * The family names CSS reads as keywords rather than as a face's name, which\n * must therefore stay unquoted: quoting `sans-serif` names a font called\n * \"sans-serif\" and loses the generic fallback.\n */\nconst KEYWORD_FAMILIES = new Set([\n 'serif',\n 'sans-serif',\n 'monospace',\n 'cursive',\n 'fantasy',\n 'system-ui',\n 'ui-serif',\n 'ui-sans-serif',\n 'ui-monospace',\n 'ui-rounded',\n 'emoji',\n 'math',\n 'fangsong',\n '-apple-system',\n 'blinkmacsystemfont',\n]);\n\nfunction fontStack(families: readonly string[]): string {\n return families\n .map((family) => (KEYWORD_FAMILIES.has(family.toLowerCase()) ? family : cssString(family)))\n .join(', ');\n}\n\n/**\n * A produced name as a CSS string that cannot end early. The quote and the\n * backslash are escaped; a control character (a form feed ends a string) and\n * `<` (which could close the `<style>` element of a host that inlines the\n * stylesheet) are written as their code points.\n */\nfunction cssString(text: string): string {\n const escaped = [...text.replace(/[\\\\']/g, '\\\\$&')]\n .map((char) =>\n char === '<' || char === '>' || isControlCharacter(char)\n ? `\\\\${char.codePointAt(0)!.toString(16)} `\n : char,\n )\n .join('');\n return `'${escaped}'`;\n}\n","import { compileBrand } from './compile';\nimport { type BrandManifest, brandManifestSchema } from './manifest';\nimport {\n type BrandProvenance,\n brandProducerId,\n brandProvenanceSchema,\n brandScope,\n} from './provenance';\nimport { statedFactProblems } from './stated';\nimport { type BrandTokens, validateBrandTokens } from './tokens';\n\n/**\n * One brand's three files in - the manifest, the tokens, the provenance - and\n * either the brand, validated and compiled, or every problem with it.\n *\n * This is the verdict on whether a brand is VALID under the contract as it is\n * now: the manifest, the tokens with their contrast, and the facts the person\n * stated. It is a hard verdict, and a brand that fails it is not compiled.\n * Whether a brand was produced against the current brief, and from the facts\n * its recording holds now, is a different question and never a reason to\n * refuse one - an older brand stays a valid brand - so the provenance's\n * contract hash and facts hash are recorded here and judged by the producer,\n * not by this function.\n *\n * The problems come in the order a producer would want to be told: the\n * manifest and the provenance first, because they are cheap and their errors\n * exact, then the tokens, then the stated facts, which can only be checked\n * against files that parsed. Each names the file and the path.\n */\n\nexport interface BrandSource {\n /** The brand's directory name: `pipelex`. */\n brand: string;\n /** The producer's directory name under it: `pipelex-method--claude-4.8-opus`. */\n producerId: string;\n manifest: unknown;\n tokens: unknown;\n provenance: unknown;\n}\n\nexport interface AssembledBrand extends BrandProvenance {\n brand: string;\n producerId: string;\n manifest: BrandManifest;\n tokens: BrandTokens;\n /** The class a page root carries; the stylesheet is scoped to it. */\n scope: string;\n /** The compiled stylesheet. */\n css: string;\n}\n\nexport type AssembleResult =\n { ok: true; brand: AssembledBrand } | { ok: false; problems: string[] };\n\nfunction issues(file: string, error: { issues: { path: PropertyKey[]; message: string }[] }) {\n return error.issues.map((issue) => {\n const where = issue.path.map(String).join('.') || '(root)';\n return `${file}: ${where}: ${issue.message}`;\n });\n}\n\nexport function assembleBrand(source: BrandSource): AssembleResult {\n const problems: string[] = [];\n const manifest = brandManifestSchema.safeParse(source.manifest);\n if (!manifest.success) problems.push(...issues('brand.json', manifest.error));\n const provenance = brandProvenanceSchema.safeParse(source.provenance);\n if (!provenance.success) problems.push(...issues('provenance.json', provenance.error));\n else {\n const expected = brandProducerId(provenance.data);\n if (expected !== source.producerId) {\n problems.push(\n `provenance.json: names producer ${expected}, but the brand is filed as ${source.producerId}`,\n );\n }\n }\n const tokens = validateBrandTokens(source.tokens);\n if (!tokens.ok) problems.push(...tokens.problems.map((problem) => `tokens.json: ${problem}`));\n if (!manifest.success || !provenance.success || !tokens.ok) return { ok: false, problems };\n problems.push(...statedFactProblems(provenance.data.stated, manifest.data, tokens.tokens));\n if (problems.length > 0) return { ok: false, problems };\n const scope = brandScope(source.brand, source.producerId);\n return {\n ok: true,\n brand: {\n ...provenance.data,\n brand: source.brand,\n producerId: source.producerId,\n manifest: manifest.data,\n tokens: tokens.tokens,\n scope,\n css: compileBrand(tokens.tokens, scope),\n },\n };\n}\n","import { MIN_CONTRAST } from './contract';\nimport { colorHex, contrastRatio, type SrgbColor } from './tokens';\n\n/**\n * Up to three seed colours in, the colour roles a page paints with out.\n *\n * A team brands its pages with at most three colours, each optional, each a\n * `#rrggbb` a person picked: the button colour (`action`), the accent\n * (`accent`) and the header band (`header`). A person picks a colour for how\n * it looks, never for how text reads on it, so nothing here assumes a seed is\n * readable. What this derives is everything a page needs around the seeds,\n * with every text role readable by construction:\n *\n * - **Fills are the seeds, exactly.** `action`, `accent` and `header` come\n * back as they were given, in lower case, so the button and the band are the\n * colours the person chose.\n * - **Text on a fill is pure black or pure white**, whichever contrasts more\n * (`onAction`, `onHeader`). One of the two reaches at least 4.58:1 on any\n * colour, so every label clears WCAG AA. Only the two extremes carry that\n * guarantee: a warm near-black or an off-white falls below 4.5:1 on some\n * mid-tone, so no other colour is ever returned for text.\n * - **The accent as text is ink** (`accentInk`): the accent darkened on a\n * light page or lightened on a dark one, keeping its hue and saturation,\n * just until it reads at 4.5:1 on the page and on the pale accent fill, the\n * two backgrounds a host draws accent text on. An accent that already reads\n * is its own ink.\n * - **The pale accent fill** (`accentFill`) is the accent laid over the page\n * at a low strength: a pale tint on a light page, a deep one on a dark page.\n *\n * **An unset seed produces no role.** The roles a seed paints are present\n * when it is set and absent when it is not, so a host keeps its own token for\n * whatever the team left unset: the team's colours where it chose some, and\n * the host's palette everywhere else. The one seed that reaches further is the\n * button colour, which the accent follows when the accent is unset, so a red\n * button never sits beside links in another hue. With no seed at all, there\n * is no colour role to return.\n *\n * The page colour is an argument because every text role is measured against\n * it: a host renders a light and a dark theme, and it calls this once per\n * theme with that theme's page colour and that theme's seeds. Which seeds a\n * theme uses is the host's to decide; `resolveDarkSeeds` is the rule for a\n * dark set that falls back, colour by colour, to the light one.\n *\n * It returns roles, never custom property names: each host maps the roles onto\n * its own tokens. See docs/brand.md § \"Three seed colours\".\n */\n\n/**\n * The contrast a control's outline needs against what surrounds it: WCAG 2's\n * level for a user interface component (1.4.11). A button colour below it\n * against the page is a button whose shape is hard to see.\n */\nexport const MIN_CONTROL_CONTRAST = 3;\n\n/**\n * How strongly the accent is laid over the page to make the pale accent fill:\n * the same order as a control's `bg-primary/10` and `bg-primary/15` tints.\n */\nconst ACCENT_FILL_STRENGTH = 0.12;\n\n/**\n * How many halvings the searches below run. Thirty-two pins a lightness far\n * below the step a byte can express, so the result is the first colour that\n * reads, to the byte.\n */\nconst SEARCH_STEPS = 32;\n\n/**\n * Up to three seed colours, each `#rrggbb` in any case, or unset. `null` and\n * `undefined` both mean unset, so a host can pass a team's stored colours as\n * they arrive.\n */\nexport interface BrandSeeds {\n /** The button colour: the run button, every main button, the selected state of a pill. */\n action?: string | null;\n /** The accent: links, the active tab, the upload area on hover, progress. */\n accent?: string | null;\n /** The band across the top of the page, behind the logo. */\n header?: string | null;\n}\n\n/** Text on a fill: only the two colours that read on every fill. */\nexport type TextOnFill = '#000000' | '#ffffff';\n\n/** The button colour's roles, present when the button colour is set. */\ninterface ActionRoles {\n /** The button colour, as a fill. Never text. */\n action: string;\n /** Text and icons on the button colour. */\n onAction: TextOnFill;\n}\n\n/** The accent's roles, present when the accent or the button colour it follows is set. */\ninterface AccentRoles {\n /** The accent, as a fill: an active tab's underline, a progress bar. Never text. */\n accent: string;\n /** A pale accent fill (deep on a dark page), behind accent ink: a pill, a badge. */\n accentFill: string;\n /** The accent as text, reading at 4.5:1 or more on the page and on `accentFill`. */\n accentInk: string;\n}\n\n/** The header band's roles, present when the header is set. */\ninterface HeaderRoles {\n /** The header band, as a fill. */\n header: string;\n /** Text on the header band: the back link, a wordmark. */\n onHeader: TextOnFill;\n}\n\n/** A group of roles that is either all there or not there at all. */\ntype Absent<Roles> = { [Role in keyof Roles]?: never };\n\n/**\n * The colours a page paints with, each `#rrggbb` in lower case. The roles come\n * in groups, each present whole or absent whole: checking one role of a group\n * (`roles.action !== undefined`) narrows the rest of it.\n */\nexport type BrandRoles = (ActionRoles | Absent<ActionRoles>) &\n (AccentRoles | Absent<AccentRoles>) &\n (HeaderRoles | Absent<HeaderRoles>);\n\n/**\n * The roles a page paints with, from up to three seeds and the colour of the\n * page they render on. Throws when a seed or the page is not a `#rrggbb`\n * colour: a host validates what a person typed before it reaches here.\n */\nexport function deriveBrandRoles(seeds: BrandSeeds | null | undefined, page: string): BrandRoles {\n const canvas = parseHex(page, 'The page colour');\n const action = seeds?.action == null ? null : parseHex(seeds.action, 'The action seed');\n // An unset accent follows the button colour, and is unset too when that is.\n const accent = seeds?.accent == null ? action : parseHex(seeds.accent, 'The accent seed');\n const header = seeds?.header == null ? null : parseHex(seeds.header, 'The header seed');\n\n const actionRoles: ActionRoles | Absent<ActionRoles> =\n action === null ? {} : { action: colorHex(action), onAction: textOn(action) };\n const accentRoles: AccentRoles | Absent<AccentRoles> =\n accent === null ? {} : accentRolesOf(accent, canvas);\n const headerRoles: HeaderRoles | Absent<HeaderRoles> =\n header === null ? {} : { header: colorHex(header), onHeader: textOn(header) };\n return { ...actionRoles, ...accentRoles, ...headerRoles };\n}\n\n/** The accent as a fill, its pale fill on the page, and its ink on both. */\nfunction accentRolesOf(accent: SrgbColor, canvas: SrgbColor): AccentRoles {\n // The way accent text moves is the way text on the page moves: toward\n // whichever of black and white reads better there, which always reaches\n // 4.58:1 on the page itself, so the ink's search always has an end.\n const extreme = textOn(canvas) === '#000000' ? BLACK : WHITE;\n const accentFill = paleFill(accent, canvas, extreme);\n const accentInk = inkFor(accent, [canvas, accentFill], extreme);\n return {\n accent: colorHex(accent),\n accentFill: colorHex(accentFill),\n accentInk: colorHex(accentInk),\n };\n}\n\n/**\n * Whether the button colour sits below 3:1 against the page, so a button may\n * be hard to see in that theme. Only a colour the person set is judged: with\n * no button colour the button is the host's own, and the answer is `false`.\n */\nexport function isActionFaint(seeds: BrandSeeds | null | undefined, page: string): boolean {\n const canvas = parseHex(page, 'The page colour');\n if (seeds?.action == null) return false;\n return contrastRatio(parseHex(seeds.action, 'The action seed'), canvas) < MIN_CONTROL_CONTRAST;\n}\n\n/**\n * Whether the accent had to be darkened or lightened to become ink on the\n * page, so links read in a shade of it rather than in the colour itself. Only\n * a colour the person set is judged, and the accent counts as set when it\n * follows a button colour the person set: with neither, the answer is `false`.\n */\nexport function isAccentAdjusted(seeds: BrandSeeds | null | undefined, page: string): boolean {\n const roles = deriveBrandRoles(seeds, page);\n return roles.accentInk !== undefined && roles.accentInk !== roles.accent;\n}\n\n/**\n * The seeds a dark theme uses: each dark colour where one is set, and the\n * light one where it is not. Colour by colour, before the accent follows the\n * button colour in `deriveBrandRoles`, so a light accent the person set\n * outranks a dark button colour the accent would otherwise follow. A colour\n * set in neither stays unset. Either set may be absent.\n */\nexport function resolveDarkSeeds(\n colors: BrandSeeds | null | undefined,\n darkColors: BrandSeeds | null | undefined,\n): BrandSeeds {\n return {\n action: darkColors?.action ?? colors?.action ?? null,\n accent: darkColors?.accent ?? colors?.accent ?? null,\n header: darkColors?.header ?? colors?.header ?? null,\n };\n}\n\n/** Pure black or pure white, whichever reads better on a `#rrggbb` fill. */\nexport function readableTextOn(fill: string): TextOnFill {\n return textOn(parseHex(fill, 'The fill'));\n}\n\nconst BLACK: SrgbColor = { colorSpace: 'srgb', components: [0, 0, 0], alpha: 1 };\nconst WHITE: SrgbColor = { colorSpace: 'srgb', components: [1, 1, 1], alpha: 1 };\n\n/** Ties go to black: on a colour where both measure the same, either clears 4.58:1. */\nfunction textOn(fill: SrgbColor): TextOnFill {\n return contrastRatio(BLACK, fill) >= contrastRatio(WHITE, fill) ? '#000000' : '#ffffff';\n}\n\nfunction parseHex(value: string, what: string): SrgbColor {\n if (typeof value !== 'string' || !/^#[0-9a-f]{6}$/i.test(value)) {\n throw new Error(`${what} must be a #rrggbb colour, not ${JSON.stringify(value)}.`);\n }\n const channel = (at: number) => parseInt(value.slice(at, at + 2), 16) / 255;\n return { colorSpace: 'srgb', components: [channel(1), channel(3), channel(5)], alpha: 1 };\n}\n\n/**\n * A colour as a hex can carry it, each channel rounded to its byte. Every\n * contrast below is measured on this, the colour a page renders, never on the\n * unrounded value a search produced, so a colour that clears the bar by a\n * rounding error is never returned.\n */\nfunction snapped(components: readonly number[]): SrgbColor {\n const [r, g, b] = components.map(\n (channel) => Math.round(Math.min(1, Math.max(0, channel)) * 255) / 255,\n ) as [number, number, number];\n return { colorSpace: 'srgb', components: [r, g, b], alpha: 1 };\n}\n\n/**\n * The accent laid over the page at `ACCENT_FILL_STRENGTH`. On a page near the\n * middle of the lightness scale, a fill that strong can leave even black or\n * white below 4.5:1, and then no ink would read on it; the fill moves back\n * toward the page until the extreme reads again. On a page a person would\n * actually use, light or dark, that never happens.\n */\nfunction paleFill(accent: SrgbColor, page: SrgbColor, extreme: SrgbColor): SrgbColor {\n const at = (strength: number) =>\n snapped(\n page.components.map(\n (channel, index) => channel + (accent.components[index]! - channel) * strength,\n ),\n );\n const nominal = at(ACCENT_FILL_STRENGTH);\n if (contrastRatio(extreme, nominal) >= MIN_CONTRAST) return nominal;\n // At strength 0 the fill is the page, on which the extreme reads.\n let enough = 0;\n let short = ACCENT_FILL_STRENGTH;\n for (let step = 0; step < SEARCH_STEPS; step++) {\n const middle = (enough + short) / 2;\n if (contrastRatio(extreme, at(middle)) >= MIN_CONTRAST) enough = middle;\n else short = middle;\n }\n return at(enough);\n}\n\n/**\n * The accent as text on every background given: the accent itself if it\n * reads, otherwise the accent with its lightness moved toward the extreme\n * (black or white) just until it does. Hue and saturation are kept, so a pale\n * yellow becomes a gold rather than a grey.\n *\n * The search halves the lightness between a value known to fall short and one\n * known to read, and only ever returns the one known to read, measured as a\n * hex - so the result reads whatever the rounding does. The extreme itself\n * reads on the page by the choice of direction and on the fill by\n * `paleFill`'s construction, so the search starts with an answer.\n */\nfunction inkFor(\n accent: SrgbColor,\n backgrounds: readonly SrgbColor[],\n extreme: SrgbColor,\n): SrgbColor {\n const reads = (color: SrgbColor) =>\n backgrounds.every((background) => contrastRatio(color, background) >= MIN_CONTRAST);\n if (reads(accent)) return accent;\n const [hue, saturation, lightness] = toHsl(accent.components);\n const at = (value: number) => snapped(fromHsl(hue, saturation, value));\n let short = lightness;\n let enough = extreme === BLACK ? 0 : 1;\n for (let step = 0; step < SEARCH_STEPS; step++) {\n const middle = (short + enough) / 2;\n if (reads(at(middle))) enough = middle;\n else short = middle;\n }\n return at(enough);\n}\n\n/** sRGB components to hue (degrees), saturation and lightness, each of the last two in 0..1. */\nfunction toHsl(components: readonly number[]): [number, number, number] {\n const [r, g, b] = components as [number, number, number];\n const max = Math.max(r, g, b);\n const min = Math.min(r, g, b);\n const lightness = (max + min) / 2;\n const chroma = max - min;\n if (chroma === 0) return [0, 0, lightness];\n const saturation = chroma / (1 - Math.abs(2 * lightness - 1));\n const sector =\n max === r\n ? ((g - b) / chroma + 6) % 6\n : max === g\n ? (b - r) / chroma + 2\n : (r - g) / chroma + 4;\n return [sector * 60, Math.min(1, saturation), lightness];\n}\n\n/**\n * Hue, saturation and lightness back to sRGB components. Lightness 0 is black\n * and lightness 1 is white whatever the hue, which is what lets the ink's\n * search end on an extreme.\n */\nfunction fromHsl(hue: number, saturation: number, lightness: number): [number, number, number] {\n const chroma = (1 - Math.abs(2 * lightness - 1)) * saturation;\n const sector = hue / 60;\n const second = chroma * (1 - Math.abs((sector % 2) - 1));\n const [r, g, b]: [number, number, number] =\n sector < 1\n ? [chroma, second, 0]\n : sector < 2\n ? [second, chroma, 0]\n : sector < 3\n ? [0, chroma, second]\n : sector < 4\n ? [0, second, chroma]\n : sector < 5\n ? [second, 0, chroma]\n : [chroma, 0, second];\n const offset = lightness - chroma / 2;\n return [r + offset, g + offset, b + offset];\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/brand/stated.ts","../../src/brand/provenance.ts","../../src/brand/compile.ts","../../src/brand/assemble.ts"],"names":["z"],"mappings":"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","file":"index.js","sourcesContent":["import { z } from 'zod';\nimport { type BrandManifest, httpUrl } from './manifest';\nimport { type BrandTokens, colorHex, colorIsHex, resolveColor } from './tokens';\n\n/**\n * What a person states beside a site's URL: the things a site does not show and\n * no reading can supply. The accent of a site with no button, per mode when its\n * dark canvas needs another, and the logo for a canvas the site draws none for.\n *\n * A stated fact outranks every reading, which whatever runs a producer tells\n * it, outside this package. Here the brand is held to honour it\n * (`statedFactProblems`), and the provenance records it.\n */\n\nconst statedHex = z.string().regex(/^#[0-9a-f]{6}$/i, 'a stated accent is #rrggbb');\n\nexport const statedFactsSchema = z.strictObject({\n /** The accent per mode, `#rrggbb`: what `color.primary` resolves to in that mode. */\n accent: z\n .strictObject({\n light: statedHex.optional(),\n dark: statedHex.optional(),\n })\n .optional(),\n /**\n * The logo for a canvas: `logo.onLight` or `logo.onDark` in the manifest,\n * which the brand must carry exactly. It is held to the http(s) half of the\n * manifest's logo rule, so a manifest can always carry it; the manifest's\n * other half, a root-relative path, names a file on the host serving the\n * page, which means nothing as a fact stated beside another site's URL.\n */\n logo: z\n .strictObject({\n onLight: httpUrl.optional(),\n onDark: httpUrl.optional(),\n })\n .optional(),\n});\n\nexport type StatedFacts = z.infer<typeof statedFactsSchema>;\n\n/**\n * Where the brand does not carry what the person stated, in the words a repair\n * round is told. Only the modes and canvases that were stated are checked.\n */\nexport function statedFactProblems(\n stated: StatedFacts | undefined,\n manifest: BrandManifest,\n tokens: BrandTokens,\n): string[] {\n if (!stated) return [];\n const problems: string[] = [];\n for (const mode of ['light', 'dark'] as const) {\n const accent = stated.accent?.[mode];\n if (!accent) continue;\n const primary = resolveColor(tokens, 'primary', mode);\n if (!primary) continue;\n if (!colorIsHex(primary, accent)) {\n problems.push(\n `tokens.json: color.primary (${mode}) resolves to ${colorHex(primary)}, but the accent for ${mode} mode was stated as ${accent}`,\n );\n }\n // A hex carries no alpha, so the components alone would let a primary\n // nobody can see honour the accent: a stated accent is an opaque colour.\n if (primary.alpha < 1) {\n problems.push(\n `tokens.json: color.primary (${mode}) has alpha ${primary.alpha}, but the accent for ${mode} mode was stated as the opaque ${accent}, so it must be opaque (alpha 1)`,\n );\n }\n }\n for (const canvas of ['onLight', 'onDark'] as const) {\n const url = stated.logo?.[canvas];\n if (url && manifest.logo[canvas] !== url) {\n problems.push(\n `brand.json: logo.${canvas} is ${manifest.logo[canvas]}, but the logo for that canvas was stated as ${url}`,\n );\n }\n }\n return problems;\n}\n","import { z } from 'zod';\nimport { statedFactsSchema } from './stated';\n\n/**\n * A brand's `provenance.json`: who produced it, on which model, from which\n * contract and which facts.\n *\n * A brand follows the rules a captured layout follows: produced by a pass,\n * committed with its provenance, and titled by what made it and by nothing\n * else. The provenance is a record, so it is never rewritten to make a check\n * pass. A brand's directory is named by `brandProducerId`, the same recipe a\n * layout fixture's id uses, so the tree and the record cannot disagree about\n * who made a brand.\n */\n\n/** How a brand came to be. */\nexport const BRAND_PRODUCERS = [\n /** The producer method, run on the hosted API. */\n 'pipelex-method',\n /** A Claude Code subagent in a fresh context, given the contract and the facts and nothing else. */\n 'claude-code-subagent',\n /** A Claude Code session reading the site and writing the files by hand. */\n 'claude-code-session',\n] as const;\n\nexport type BrandProducer = (typeof BRAND_PRODUCERS)[number];\n\n/** The first twelve hex digits of a SHA-256: how the provenance names a text it was produced from. */\nconst hash12 = z.string().regex(/^[0-9a-f]{12}$/, 'twelve hex digits');\n\nexport const brandProvenanceSchema = z\n .strictObject({\n producer: z.enum(BRAND_PRODUCERS),\n /** The model id: the one the method ran with, or the Claude Code model behind the session. */\n model: z.string().min(1),\n /** The day it was produced, `YYYY-MM-DD`. */\n date: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/),\n /** The contract brief it was produced from, as the producer recorded its path. */\n brief: z.string().min(1),\n /** The first twelve hex digits of the SHA-256 of the contract brief at the time. */\n contractHash: hash12,\n /** The creative seed handed over with the brief, verbatim, when one was. */\n seed: z.string().min(1).optional(),\n /** What the person stated beside the URL, when they did. */\n stated: statedFactsSchema.optional(),\n /** Where the site facts came from: a file, or a sentence for a brand read by hand. */\n siteFacts: z.string().min(1).optional(),\n /**\n * The first twelve hex digits of the SHA-256 of the file `siteFacts`\n * names, its bytes as the producer read them. A path alone cannot say\n * whether the facts behind it moved since the brand was produced; whatever\n * re-reads them hashes the file again, and a mismatch makes the brand\n * stale, never invalid. The schema refuses one beside no `siteFacts`,\n * but it cannot tell a path from a sentence: a brand read by hand records\n * none by the producer's own rule, and a hash recorded beside a sentence\n * anyway is caught where it is judged, since the sentence names no file.\n */\n siteFactsHash: hash12.optional(),\n /** How many repair rounds the producer ran before the files validated. */\n rounds: z.number().int().min(0).optional(),\n })\n .refine(\n (provenance) => provenance.siteFactsHash === undefined || provenance.siteFacts !== undefined,\n {\n path: ['siteFactsHash'],\n message: 'no siteFacts names the file it hashes',\n },\n );\n\nexport type BrandProvenance = z.infer<typeof brandProvenanceSchema>;\n\n/** The id a brand's directory is named by: `producer--model[--seeded]`. */\nexport function brandProducerId(\n provenance: Pick<BrandProvenance, 'producer' | 'model' | 'seed'>,\n): string {\n return [provenance.producer, provenance.model, provenance.seed ? 'seeded' : null]\n .filter((part): part is string => part !== null)\n .join('--');\n}\n\n/**\n * The scope class a brand's stylesheet sets its tokens on: `brand-<brand>-<producerId>`,\n * with every character outside `[a-z0-9-]` replaced, because a model id\n * carries dots and a dot ends a class selector.\n *\n * The replacement folds: `claude-4.8-opus` and `claude-4-8-opus` share a\n * scope, and so do two ids that differ only in case. A set of brands loaded on\n * one page must therefore check its scopes are distinct, or the later\n * stylesheet silently takes the earlier brand's place.\n */\nexport function brandScope(brand: string, producerId: string): string {\n return `brand-${brand}-${producerId}`.toLowerCase().replace(/[^a-z0-9-]/g, '-');\n}\n","import { BRAND_CONTRACT, COLOR_TOKEN_NAMES, type ColorTokenName } from './contract';\nimport {\n aliasTarget,\n asWritten,\n type BrandTokens,\n colorHex,\n type ColorValue,\n isControlCharacter,\n modeValue,\n type SrgbColor,\n} from './tokens';\n\n/**\n * A validated `tokens.json` in, the brand's stylesheet out.\n *\n * What comes out is exactly the contract, scoped: a `.<scope>` block setting\n * every custom property the contract names, and a `.dark .<scope>` block\n * restating every colour with its dark value. The `.dark` ancestor is the\n * package's own dark-mode convention (`theme.css`, the `dark` variant), so a\n * branded page inside a dark pane picks its dark values up with nothing else\n * to wire.\n *\n * The scope block also sets `font-family: var(--font-sans)`. Tailwind's\n * preflight resolves the page's typeface once, at `<html>`, so a scope that\n * only set `--font-sans` lower in the tree would change no text; declaring the\n * family where the scope is makes the brand's typeface reach everything under\n * it - the produced page and the plain form alike - while a page with no brand\n * keeps the host's own typeface untouched.\n *\n * The contract is closed - a fixed set of tokens, colours in sRGB only, one\n * length, two font stacks - so compiling a file the validator accepted is this\n * function and no dependency. It takes the file as `validateBrandTokens`\n * returned it; anything else is the caller's mistake, and `assembleBrand` is\n * the route that cannot make it. The output stays comparable with what a\n * standard DTCG tool writes for the same file: `__tests__/terrazzo.test.ts`\n * compiles every committed brand through Terrazzo and compares the\n * declarations.\n */\nexport function compileBrand(tokens: BrandTokens, scope: string): string {\n if (!/^[a-z][a-z0-9-]*$/.test(scope)) {\n throw new Error(`compileBrand: \"${scope}\" is not a scope class (see brandScope).`);\n }\n const light: string[] = [];\n const dark: string[] = [];\n for (const name of COLOR_TOKEN_NAMES) {\n const token = tokens.color[name];\n light.push(...declaration(token.$description, `--${name}`, colorCss(name, token.$value)));\n dark.push(\n ...declaration(token.$description, `--${name}`, colorCss(name, modeValue(token, 'dark'))),\n );\n }\n const radius = tokens.radius.base;\n light.push(\n ...declaration(radius.$description, '--radius', `${radius.$value.value}${radius.$value.unit}`),\n );\n for (const key of ['sans', 'mono'] as const) {\n const font = tokens.font[key];\n light.push(...declaration(font.$description, `--font-${key}`, fontStack(font.$value)));\n }\n light.push(\n ' /* The typeface reaches the text here, where the scope is; see compileBrand. */',\n ' font-family: var(--font-sans);',\n );\n return [`.${scope} {`, ...light, '}', '', `.dark .${scope} {`, ...dark, '}', ''].join('\\n');\n}\n\n/** Every custom property a compiled brand sets on its scope, in contract order. */\nexport const BRAND_VARIABLES: readonly string[] = BRAND_CONTRACT.map((token) => token.variable);\n\nfunction declaration(description: string, property: string, value: string): string[] {\n return [` /* ${commentText(description)} */`, ` ${property}: ${value};`];\n}\n\n/**\n * A description as comment text: one line, and nothing that could close the\n * comment, nor the `<style>` element of a host that inlines the stylesheet.\n */\nfunction commentText(text: string): string {\n return text.replace(/\\s+/g, ' ').replace(/\\*\\//g, '* /').replace(/<\\//g, '< /').trim();\n}\n\nfunction colorCss(name: ColorTokenName, value: ColorValue): string {\n const target = aliasTarget(value);\n if (target !== null) {\n // The validator has already refused an alias outside the contract; a\n // stray one here would write a reference to a property nothing sets.\n if (!(COLOR_TOKEN_NAMES as readonly string[]).includes(target)) {\n throw new Error(`compileBrand: color.${name} aliases {color.${target}}.`);\n }\n return `var(--${target})`;\n }\n return srgbCss(value as SrgbColor);\n}\n\n/**\n * An opaque colour as its hex, a translucent one as `rgb()` with its alpha,\n * both as `asWritten` rounds them, which is the colour the validator measured.\n */\nfunction srgbCss(color: SrgbColor): string {\n const { alpha } = asWritten(color);\n if (alpha >= 1) return colorHex(color);\n const [r, g, b] = color.components.map((channel) => Math.round(channel * 255));\n return `rgb(${r} ${g} ${b} / ${alpha})`;\n}\n\n/**\n * The family names CSS reads as keywords rather than as a face's name, which\n * must therefore stay unquoted: quoting `sans-serif` names a font called\n * \"sans-serif\" and loses the generic fallback.\n */\nconst KEYWORD_FAMILIES = new Set([\n 'serif',\n 'sans-serif',\n 'monospace',\n 'cursive',\n 'fantasy',\n 'system-ui',\n 'ui-serif',\n 'ui-sans-serif',\n 'ui-monospace',\n 'ui-rounded',\n 'emoji',\n 'math',\n 'fangsong',\n '-apple-system',\n 'blinkmacsystemfont',\n]);\n\nfunction fontStack(families: readonly string[]): string {\n return families\n .map((family) => (KEYWORD_FAMILIES.has(family.toLowerCase()) ? family : cssString(family)))\n .join(', ');\n}\n\n/**\n * A produced name as a CSS string that cannot end early. The quote and the\n * backslash are escaped; a control character (a form feed ends a string) and\n * `<` (which could close the `<style>` element of a host that inlines the\n * stylesheet) are written as their code points.\n */\nfunction cssString(text: string): string {\n const escaped = [...text.replace(/[\\\\']/g, '\\\\$&')]\n .map((char) =>\n char === '<' || char === '>' || isControlCharacter(char)\n ? `\\\\${char.codePointAt(0)!.toString(16)} `\n : char,\n )\n .join('');\n return `'${escaped}'`;\n}\n","import { compileBrand } from './compile';\nimport { type BrandManifest, brandManifestSchema } from './manifest';\nimport {\n type BrandProvenance,\n brandProducerId,\n brandProvenanceSchema,\n brandScope,\n} from './provenance';\nimport { statedFactProblems } from './stated';\nimport { type BrandTokens, validateBrandTokens } from './tokens';\n\n/**\n * One brand's three files in - the manifest, the tokens, the provenance - and\n * either the brand, validated and compiled, or every problem with it.\n *\n * This is the verdict on whether a brand is VALID under the contract as it is\n * now: the manifest, the tokens with their contrast, and the facts the person\n * stated. It is a hard verdict, and a brand that fails it is not compiled.\n * Whether a brand was produced against the current brief, and from the facts\n * its recording holds now, is a different question and never a reason to\n * refuse one - an older brand stays a valid brand - so the provenance's\n * contract hash and facts hash are recorded here and judged by the producer,\n * not by this function.\n *\n * The problems come in the order a producer would want to be told: the\n * manifest and the provenance first, because they are cheap and their errors\n * exact, then the tokens, then the stated facts, which can only be checked\n * against files that parsed. Each names the file and the path.\n */\n\nexport interface BrandSource {\n /** The brand's directory name: `pipelex`. */\n brand: string;\n /** The producer's directory name under it: `pipelex-method--claude-4.8-opus`. */\n producerId: string;\n manifest: unknown;\n tokens: unknown;\n provenance: unknown;\n}\n\nexport interface AssembledBrand extends BrandProvenance {\n brand: string;\n producerId: string;\n manifest: BrandManifest;\n tokens: BrandTokens;\n /** The class a page root carries; the stylesheet is scoped to it. */\n scope: string;\n /** The compiled stylesheet. */\n css: string;\n}\n\nexport type AssembleResult =\n { ok: true; brand: AssembledBrand } | { ok: false; problems: string[] };\n\nfunction issues(file: string, error: { issues: { path: PropertyKey[]; message: string }[] }) {\n return error.issues.map((issue) => {\n const where = issue.path.map(String).join('.') || '(root)';\n return `${file}: ${where}: ${issue.message}`;\n });\n}\n\nexport function assembleBrand(source: BrandSource): AssembleResult {\n const problems: string[] = [];\n const manifest = brandManifestSchema.safeParse(source.manifest);\n if (!manifest.success) problems.push(...issues('brand.json', manifest.error));\n const provenance = brandProvenanceSchema.safeParse(source.provenance);\n if (!provenance.success) problems.push(...issues('provenance.json', provenance.error));\n else {\n const expected = brandProducerId(provenance.data);\n if (expected !== source.producerId) {\n problems.push(\n `provenance.json: names producer ${expected}, but the brand is filed as ${source.producerId}`,\n );\n }\n }\n const tokens = validateBrandTokens(source.tokens);\n if (!tokens.ok) problems.push(...tokens.problems.map((problem) => `tokens.json: ${problem}`));\n if (!manifest.success || !provenance.success || !tokens.ok) return { ok: false, problems };\n problems.push(...statedFactProblems(provenance.data.stated, manifest.data, tokens.tokens));\n if (problems.length > 0) return { ok: false, problems };\n const scope = brandScope(source.brand, source.producerId);\n return {\n ok: true,\n brand: {\n ...provenance.data,\n brand: source.brand,\n producerId: source.producerId,\n manifest: manifest.data,\n tokens: tokens.tokens,\n scope,\n css: compileBrand(tokens.tokens, scope),\n },\n };\n}\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { buildRunFields } from './chunk-ZB4RYUKV.js';
|
|
2
1
|
import { inflateAllInputs, deflateAllInputs, isWrappedForm } from './chunk-E6BIXJ6C.js';
|
|
3
2
|
import { isFilled, isOptionalStructure, optionalStructureOpen } from './chunk-XO5OENNF.js';
|
|
3
|
+
import { buildRunFields } from './chunk-HVWE3TTC.js';
|
|
4
4
|
import { isOptionalInput, isPluralInput } from './chunk-WYH56SOZ.js';
|
|
5
5
|
import { ownProp } from './chunk-V3OV2XQT.js';
|
|
6
6
|
|
|
@@ -210,5 +210,5 @@ function setValueAtPath(root, path, value) {
|
|
|
210
210
|
}
|
|
211
211
|
|
|
212
212
|
export { apiInputsFromRunValues, fieldsForContract, inputDataFromWorkingMemory, outputsFromPipeOutput, rjsfDataFromRunValues, runValuesFromInputs, runValuesFromStore, sameRunValues, setValueAtPath, storeInputDataFromRunValues };
|
|
213
|
-
//# sourceMappingURL=chunk-
|
|
214
|
-
//# sourceMappingURL=chunk-
|
|
213
|
+
//# sourceMappingURL=chunk-2UCH4AAO.js.map
|
|
214
|
+
//# sourceMappingURL=chunk-2UCH4AAO.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/values.ts"],"names":[],"mappings":"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","file":"chunk-ZX52CQJ4.js","sourcesContent":["/**\n * Bridges the `MethodRunner`'s field values to the rest of the host.\n *\n * The method-store keeps inputs in the *simplified* format and runs send the\n * *full* RJSF form shape - both already handled by `inflate/deflateAllInputs`.\n * The only gap is that a few field controls use a friendlier value than RJSF: a\n * scalar is the bare scalar where the full shape is the content model its\n * concept declares (`{ text }`, `{ number }`, `{ yes_no }`), and a file is\n * `{ url, filename }`. `fromRjsf`/`toRjsf` translate just those, so store\n * reads/writes and run payloads stay byte-for-byte compatible with the proven\n * playground path.\n *\n * Which property a scalar wraps into is NOT decided here - it arrives on the\n * descriptor as `contentKey`, derived from the contract by `buildRunFields`.\n *\n * Pure module - no React, unit-tested.\n */\nimport type { PipeInputFormDescriptor } from 'mthds/protocol';\n\nimport type { RunField } from './descriptor';\nimport { buildRunFields } from './derive';\nimport { ownProp } from './own-property';\nimport { isFilled, isOptionalStructure, optionalStructureOpen } from './readiness';\nimport { isOptionalInput, isPluralInput } from './contracts';\nimport { deflateAllInputs, inflateAllInputs, isWrappedForm } from './wire-format';\nimport type { PipeIOContract, PipeInputContract } from './contracts';\n\ntype Dict = Record<string, unknown>;\ntype InputSchemas = Record<string, PipeInputContract>;\n\n// ─── RJSF full shape ↔ RunField value ──────────────────────────────────────\n\n/**\n * Put a scalar back inside the content model its concept declares:\n * `\"hi\"` → `{ text: \"hi\" }`, `2` → `{ number: 2 }`, `false` → `{ yes_no: false }`.\n *\n * The property name comes from the DESCRIPTOR (`contentKey`, stamped by\n * `buildRunFields` - the only reader of JSON Schema). This module holds no\n * taxonomy of its own, which is the point: the version that did held a list of\n * concepts that wrap, `native.Number` was missing from it, and every run\n * carrying a number was rejected by the gate against `NumberContent`.\n *\n * A field with no `contentKey` keeps its value plain. That is not an oversight\n * either - a child property of a structured concept, or a custom concept whose\n * schema is a bare string, IS its value, and wrapping it double-nests it\n * (`{ text: { text } }`) into a payload no schema accepts.\n */\nfunction wrapContent(field: RunField, value: unknown): unknown {\n return field.contentKey === undefined ? value : { [field.contentKey]: value };\n}\n\n/**\n * The inverse. A value that is already bare passes through untouched: persisted\n * `inputData` predates the number and yes/no wrappers, and an inputs.json\n * written by hand or by an agent says `2`, not `{number: 2}`.\n */\nfunction unwrapContent(field: RunField, value: unknown): unknown {\n const key = field.contentKey;\n if (key === undefined || !value || typeof value !== 'object' || Array.isArray(value))\n return value;\n return ownProp(value as Record<string, unknown>, key);\n}\n\n/** How deep a nested `{ text: … }` / `{ content: … }` chain we bother unwrapping. */\nconst MAX_UNWRAP_DEPTH = 8;\n\n/**\n * Pull a plain string out of whatever the store hands a text field.\n *\n * Persisted `inputData` carries historical corruptions - a double-wrapped\n * `{ text: { text } }`, a `{ concept, content }` envelope that was never\n * deflated - and the old fallback ran `String()` over them, which renders the\n * literal `\"[object Object]\"` into the textarea. That is worse than showing\n * nothing: it looks exactly like content the user typed, and one keystroke\n * later it is content the user typed. So unwrap the envelopes we know, and give\n * up with `undefined` (an empty field) rather than displaying garbage.\n *\n * Genuine primitives still stringify - a number or a boolean in a text slot is\n * a value, not a wrapper.\n *\n * The envelope names here are the HISTORICAL corruptions, not the wrapper key:\n * the declared wrapper is stripped by `unwrapContent` first, off the field's\n * `contentKey`, exactly as the number and boolean paths do. A text wrapper\n * whose property is not literally `text` would otherwise read back empty - and\n * one save later, BE empty.\n */\nfunction textFromStored(value: unknown, depth = 0): string | undefined {\n if (value == null) return undefined;\n if (typeof value === 'string') return value;\n if (typeof value === 'number' || typeof value === 'boolean') return String(value);\n if (typeof value !== 'object' || depth >= MAX_UNWRAP_DEPTH) return undefined;\n const envelope = value as { text?: unknown; content?: unknown };\n if ('text' in envelope) return textFromStored(envelope.text, depth + 1);\n if ('content' in envelope) return textFromStored(envelope.content, depth + 1);\n return undefined;\n}\n\n/** RJSF full form value → the runner's field value. */\nfunction fromRjsf(field: RunField, value: unknown): unknown {\n switch (field.kind) {\n case 'text':\n case 'prose':\n return textFromStored(unwrapContent(field, value));\n case 'number': {\n // The control holds `number | undefined`. A numeric STRING is tolerated\n // because that is what a hand-written inputs.json tends to carry; anything\n // else empties the field rather than feeding NaN to a number input.\n const raw = unwrapContent(field, value);\n if (typeof raw === 'number') return Number.isFinite(raw) ? raw : undefined;\n if (typeof raw === 'string' && raw.trim() !== '') {\n const parsed = Number(raw);\n return Number.isFinite(parsed) ? parsed : undefined;\n }\n return undefined;\n }\n case 'boolean': {\n // Strictly a real boolean, deliberately: pipelex declares `YesNoContent.\n // yes_no` with `strict=True` precisely to refuse \"yes\"/1/\"true\", and\n // coercing here would smuggle back in what the runtime closed off.\n const raw = unwrapContent(field, value);\n return typeof raw === 'boolean' ? raw : undefined;\n }\n case 'unknown':\n // The escape hatch is a raw-JSON textarea, so a structured value belongs\n // there as JSON - `String(value)` would have shown \"[object Object]\" and\n // thrown the actual value away.\n if (typeof value === 'string') return value;\n if (value == null) return undefined;\n if (typeof value === 'object') {\n try {\n return JSON.stringify(value, null, 2);\n } catch {\n return undefined;\n }\n }\n return String(value);\n case 'document':\n case 'image': {\n if (value && typeof value === 'object') {\n const o = value as { url?: unknown; filename?: unknown };\n return o.url\n ? { url: String(o.url), filename: o.filename as string | undefined }\n : undefined;\n }\n return typeof value === 'string' && value ? { url: value } : undefined;\n }\n case 'object': {\n // An optional structure the store holds no object for - absent, or the\n // `null` a stored run writes for a structure it went without - stays\n // CLOSED. Materializing a shell of `undefined` children here reopened it:\n // `optionalStructureOpen` reads any plain object as open, so a run reloaded\n // from the store showed every structure it had left out as opened and\n // blank. A required structure has no closed state, and keeps its shell.\n if (isOptionalStructure(field) && !optionalStructureOpen(value)) return undefined;\n const obj = (value && typeof value === 'object' ? value : {}) as Dict;\n const out: Dict = {};\n for (const child of field.fields) out[child.name] = fromRjsf(child, ownProp(obj, child.name));\n return out;\n }\n case 'list': {\n const arr = Array.isArray(value) ? value : [];\n return arr.map((item) => fromRjsf(field.item, item));\n }\n default:\n return value;\n }\n}\n\n/**\n * The runner's field value → RJSF full form value (what runs/store expect).\n *\n * `collapseEmpty` is what a SINGULAR slot does and a LIST ITEM must not: an\n * untouched structure in a singular slot is absent, but an item exists only\n * because the user added it, so adding IS the touch. Only the structure case\n * reads the flag.\n */\nfunction toRjsf(field: RunField, value: unknown, collapseEmpty = true): unknown {\n switch (field.kind) {\n case 'text':\n case 'prose':\n return wrapContent(field, typeof value === 'string' ? value : '');\n case 'number':\n // An untouched number stays ABSENT rather than becoming an empty wrapper.\n // The gate then does the right thing on both counts: it prunes an absent\n // optional input, and it reports a required one as missing by name -\n // where `{number: undefined}` would read as a malformed value instead.\n return typeof value === 'number' && Number.isFinite(value)\n ? wrapContent(field, value)\n : undefined;\n case 'boolean':\n // `false` is a value, not an absence - hence the type test rather than a\n // truthiness one.\n return typeof value === 'boolean' ? wrapContent(field, value) : undefined;\n case 'unknown':\n return typeof value === 'string' ? value : '';\n case 'document':\n case 'image': {\n const url = value && typeof value === 'object' ? (value as { url?: unknown }).url : value;\n const filename =\n value && typeof value === 'object' ? (value as { filename?: unknown }).filename : undefined;\n return { url: url ? String(url) : '', ...(filename ? { filename } : {}) };\n }\n case 'object': {\n const obj = (value && typeof value === 'object' ? value : {}) as Dict;\n const out: Dict = {};\n for (const child of field.fields) out[child.name] = toRjsf(child, ownProp(obj, child.name));\n // A structure nobody put anything into stays ABSENT, exactly as an\n // untouched number does above - it does NOT become a shell of empty\n // children. Materializing that shell made an OPTIONAL structured input\n // unrunnable whenever its concept declared a required child: readiness\n // ignored the input (correctly - the method said it may be omitted), Run\n // lit up, and the gate then judged an object the kernel had invented\n // against the concept's full schema and rejected the run for a child the\n // user was never asked to fill.\n //\n // Emptiness is `isFilled`, the SAME predicate readiness and the wire\n // payload use, so the three cannot disagree about whether this input is\n // there. Which also says what the touch is NOT: opening the optional\n // disclosure is local view state the value never sees, so a section\n // opened and left blank collapses exactly like one never opened. What\n // keeps a structure is a VALUE in it - and then the whole shell survives,\n // empty children and all, so a required child left blank still fails, and\n // loudly.\n return collapseEmpty && !isFilled(out) ? undefined : out;\n }\n case 'list': {\n const arr = Array.isArray(value) ? value : [];\n // An item is NEVER absent: it is in the array because the user added it,\n // and `ListField`'s \"Add\" seeds an object item with `{}`. Letting it\n // collapse the way an untouched singular slot does put `undefined` in the\n // array, which ajv rejects as `must be object` - blocking an empty item\n // the item schema allowed, and turning a required-child complaint into a\n // type error that names nothing the user can act on.\n return arr.map((item) => toRjsf(field.item, item, false));\n }\n default:\n return value;\n }\n}\n\n// ─── Store ↔ RunField values ──────────────────────────────────────────────\n\n/** Seed the runner's form values from the method-store's simplified inputData. */\nexport function runValuesFromStore(\n inputData: Dict | undefined,\n fields: RunField[],\n inputSchemas: InputSchemas,\n): Dict {\n const full = inflateAllInputs(inputData ?? {}, inputSchemas);\n const out: Dict = {};\n for (const field of fields) out[field.name] = fromRjsf(field, ownProp(full, field.name));\n return out;\n}\n\n/**\n * The runner's form values in **schema shape** - the same shape an RJSF panel\n * holds, and therefore the shape `gate.ts` validates against the per-input\n * JSON Schemas.\n *\n * Deliberately stops short of `deflateAllInputs`: deflation is the STORE's\n * compact form, and ajv validates the full one.\n */\nexport function rjsfDataFromRunValues(values: Dict, fields: RunField[]): Dict {\n const full: Dict = {};\n for (const field of fields) full[field.name] = toRjsf(field, ownProp(values, field.name));\n return full;\n}\n\n/** Convert the runner's form values back to the store's simplified inputData. */\nexport function storeInputDataFromRunValues(\n values: Dict,\n fields: RunField[],\n inputSchemas: InputSchemas,\n): Dict {\n return deflateAllInputs(rjsfDataFromRunValues(values, fields), inputSchemas);\n}\n\n/**\n * Build the `{ concept, content }` map a run expects from the form values.\n *\n * The two ways a method says \"this may be nothing\" land differently on the wire,\n * and both matter:\n * - an **optional (`?`)** input left blank is OMITTED, so the runtime records a\n * real absence the method can branch on - sending `{ text: \"\" }` would look\n * like the caller supplied an empty string;\n * - a **plural (`[]`)** input keeps its key, because a plural slot is never\n * absent - its empty form IS the empty list, and the runtime requires the key.\n * When that list is EMPTY it is sent BARE, without the envelope: the envelope\n * is the runtime's \"explicit form\", which bypasses the top-down shaper and\n * hands the value to the bottom-up factory, and that factory types a list from\n * its first item - so an empty list there raises \"Cannot create Stuff from\n * empty list in content\". The bare form keeps the shaper, which reads the\n * DECLARED concept and builds the empty list correctly. (pipelex/#1096 makes\n * the envelope agree; the bare form runs today and stays correct after.)\n */\nexport function apiInputsFromRunValues(\n values: Dict,\n fields: RunField[],\n inputSchemas: InputSchemas,\n): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const field of fields) {\n const schema = ownProp(inputSchemas, field.name);\n if (!schema) continue;\n const value = ownProp(values, field.name);\n if (isOptionalInput(schema) && !isFilled(value)) continue;\n if (isPluralInput(schema) && !isFilled(value)) {\n out[field.name] = [];\n continue;\n }\n out[field.name] = { concept: schema.concept_ref, content: toRjsf(field, value) };\n }\n return out;\n}\n\n/**\n * The form values a set of run inputs stands for: the inverse of\n * `apiInputsFromRunValues`, for inputs saved from a form (an example) and\n * handed back to one.\n *\n * Each input is read as a run sends it, `{ concept, content }`, or as its bare\n * content (the empty plural `[]`), and its content is turned back into the\n * control's own shape. Only an object naming its concept is read as that\n * envelope: a structure sent bare may well have a property called `content`. An input the inputs do not hold is left empty, and an\n * optional structure they do not hold stays closed: the inputs are the whole\n * run, so an input they left out was left out of the run too. An input no\n * field takes is ignored.\n */\nexport function runValuesFromInputs(inputs: Readonly<Dict> | undefined, fields: RunField[]): Dict {\n const out: Dict = {};\n for (const field of fields) {\n const entry = ownProp(inputs ?? {}, field.name);\n const content = isWrappedForm(entry) ? entry.content : entry;\n out[field.name] = fromRjsf(field, content);\n }\n return out;\n}\n\n/**\n * Whether two sets of form values send the same run.\n *\n * Compared in the shape a run takes, so the differences a run cannot see do\n * not count: a text typed and then erased is the blank it started as, and an\n * optional structure opened and left empty is the closed one it was. What\n * \"Fill with an example\" asks before replacing is the work a person did, and\n * a value that sends nothing is no work to lose.\n */\nexport function sameRunValues(a: Dict, b: Dict, fields: RunField[]): boolean {\n return (\n JSON.stringify(rjsfDataFromRunValues(a, fields)) ===\n JSON.stringify(rjsfDataFromRunValues(b, fields))\n );\n}\n\n// ─── Pipe output → result entries ────────────────────────────────────────────\n\n/** One named output pulled out of a run's working memory, ready to render. */\nexport interface OutputEntry {\n /** The output variable key (mono). */\n key: string;\n conceptRef?: string;\n value: unknown;\n}\n\n/**\n * The slice of a serialized pipe output this module actually reads. Structural\n * on purpose: the SDK's `DictPipeOutput` is the host's wire type, and the kernel\n * must not depend on `@pipelex/sdk` - the guard below verifies the shape at\n * runtime anyway.\n */\ninterface PipeOutputWithWorkingMemory {\n working_memory: {\n root: Record<string, unknown>;\n aliases?: Record<string, string>;\n };\n}\n\nfunction hasWorkingMemoryRoot(value: unknown): value is PipeOutputWithWorkingMemory {\n return (\n !!value &&\n typeof value === 'object' &&\n 'working_memory' in value &&\n !!(value as { working_memory?: { root?: unknown } }).working_memory &&\n typeof (value as { working_memory: { root?: unknown } }).working_memory.root === 'object'\n );\n}\n\n/** The concept code of a working-memory entry (`{concept}` may be obj/str/absent). */\nfunction entryConceptRef(data: unknown): string | undefined {\n if (!data || typeof data !== 'object') return undefined;\n const raw = (data as { concept?: unknown; concept_code?: unknown }).concept;\n if (raw && typeof raw === 'object')\n return (\n ((raw as { concept_code?: string }).concept_code ?? (raw as { code?: string }).code) ||\n undefined\n );\n if (typeof raw === 'string') return raw;\n return (data as { concept_code?: string }).concept_code || undefined;\n}\n\n/**\n * Split a run's pipe output into the main result and any intermediate outputs,\n * excluding the inputs. The main output's identity comes from the working\n * memory's `main_stuff` alias (the authoritative pointer to the output variable)\n * - so its label is the REAL stuff name, not a positional guess. Falls back to\n * the last produced stuff only when the alias is absent.\n */\nexport function outputsFromPipeOutput(\n pipeOutput: unknown,\n inputKeys: string[],\n): { main: OutputEntry; intermediates: OutputEntry[] } | null {\n if (!hasWorkingMemoryRoot(pipeOutput)) return null;\n const wm = pipeOutput.working_memory as {\n root: Record<string, unknown>;\n aliases?: Record<string, string>;\n };\n const entries = Object.entries(wm.root).filter(([key]) => !inputKeys.includes(key));\n if (entries.length === 0) return null;\n\n const toEntry = ([key, data]: [string, unknown]): OutputEntry => ({\n key,\n conceptRef: entryConceptRef(data),\n value: (data as { content?: unknown })?.content ?? data,\n });\n\n // The real main-output name: `aliases.main_stuff` → its root key.\n const mainKey = wm.aliases?.['main_stuff'];\n const mainEntry: [string, unknown] =\n mainKey && Object.prototype.hasOwnProperty.call(wm.root, mainKey)\n ? [mainKey, wm.root[mainKey]]\n : entries[entries.length - 1]!;\n const intermediates = entries.filter(([key]) => key !== mainEntry[0]).map(toEntry);\n\n return { main: toEntry(mainEntry), intermediates };\n}\n\n/**\n * Recover the inputs a run was executed with from its working memory. The run's\n * `working_memory.root` holds every named stuff - inputs AND outputs - keyed by\n * variable name; we pull the entries whose keys are declared inputs and deflate\n * their `content` (the full form shape) back into the store's simplified\n * `inputData`. Lets the runner repopulate the form for a past/shared run - the\n * inputs that produced the result. Returns `null` when no inputs are present.\n */\nexport function inputDataFromWorkingMemory(\n workingMemory: unknown,\n inputSchemas: InputSchemas,\n): Dict | null {\n const root = (workingMemory as { root?: Record<string, unknown> } | null | undefined)?.root;\n if (!root || typeof root !== 'object') return null;\n const full: Dict = {};\n let found = false;\n for (const key of Object.keys(inputSchemas)) {\n const entry = ownProp(root, key);\n if (entry && typeof entry === 'object' && 'content' in entry) {\n full[key] = (entry as { content: unknown }).content;\n found = true;\n }\n }\n if (!found) return null;\n return deflateAllInputs(full, inputSchemas);\n}\n\n/**\n * Field descriptors for a method's main pipe - the wire descriptor mapped over\n * the contract, or `[]` while either artifact has not arrived yet. The\n * descriptor comes back from `validate` beside `pipe_io_contracts` when the\n * request opts in with `views: [\"input_form\"]`; `getPipeInputForm` is the\n * lookup that matches `getPipeIOContract`.\n */\nexport function fieldsForContract(\n contract: PipeIOContract | undefined,\n descriptor: PipeInputFormDescriptor | undefined,\n): RunField[] {\n return contract?.inputs && descriptor ? buildRunFields(descriptor, contract.inputs) : [];\n}\n\n/**\n * Immutably set a value at a dotted/indexed path (`a.0.b`). Used to write an\n * uploaded file's URL back to a field anywhere in the (possibly nested) tree.\n */\nexport function setValueAtPath(root: Dict, path: string[], value: unknown): Dict {\n const head = path[0];\n if (head === undefined) return root;\n const rest = path.slice(1);\n if (rest.length === 0) return { ...root, [head]: value };\n\n const nextSeg = rest[0] as string;\n const child = root[head];\n if (/^\\d+$/.test(nextSeg)) {\n const arr = Array.isArray(child) ? child.slice() : [];\n const idx = Number(nextSeg);\n arr[idx] =\n rest.length === 1 ? value : setValueAtPath((arr[idx] as Dict) ?? {}, rest.slice(1), value);\n return { ...root, [head]: arr };\n }\n return { ...root, [head]: setValueAtPath((child as Dict) ?? {}, rest, value) };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/core/values.ts"],"names":[],"mappings":"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","file":"chunk-2UCH4AAO.js","sourcesContent":["/**\n * Bridges the `MethodRunner`'s field values to the rest of the host.\n *\n * The method-store keeps inputs in the *simplified* format and runs send the\n * *full* RJSF form shape - both already handled by `inflate/deflateAllInputs`.\n * The only gap is that a few field controls use a friendlier value than RJSF: a\n * scalar is the bare scalar where the full shape is the content model its\n * concept declares (`{ text }`, `{ number }`, `{ yes_no }`), and a file is\n * `{ url, filename }`. `fromRjsf`/`toRjsf` translate just those, so store\n * reads/writes and run payloads stay byte-for-byte compatible with the proven\n * playground path.\n *\n * Which property a scalar wraps into is NOT decided here - it arrives on the\n * descriptor as `contentKey`, derived from the contract by `buildRunFields`.\n *\n * Pure module - no React, unit-tested.\n */\nimport type { PipeInputFormDescriptor } from 'mthds/protocol';\n\nimport type { RunField } from './descriptor';\nimport { buildRunFields } from './derive';\nimport { ownProp } from './own-property';\nimport { isFilled, isOptionalStructure, optionalStructureOpen } from './readiness';\nimport { isOptionalInput, isPluralInput } from './contracts';\nimport { deflateAllInputs, inflateAllInputs, isWrappedForm } from './wire-format';\nimport type { PipeIOContract, PipeInputContract } from './contracts';\n\ntype Dict = Record<string, unknown>;\ntype InputSchemas = Record<string, PipeInputContract>;\n\n// ─── RJSF full shape ↔ RunField value ──────────────────────────────────────\n\n/**\n * Put a scalar back inside the content model its concept declares:\n * `\"hi\"` → `{ text: \"hi\" }`, `2` → `{ number: 2 }`, `false` → `{ yes_no: false }`.\n *\n * The property name comes from the DESCRIPTOR (`contentKey`, stamped by\n * `buildRunFields` - the only reader of JSON Schema). This module holds no\n * taxonomy of its own, which is the point: the version that did held a list of\n * concepts that wrap, `native.Number` was missing from it, and every run\n * carrying a number was rejected by the gate against `NumberContent`.\n *\n * A field with no `contentKey` keeps its value plain. That is not an oversight\n * either - a child property of a structured concept, or a custom concept whose\n * schema is a bare string, IS its value, and wrapping it double-nests it\n * (`{ text: { text } }`) into a payload no schema accepts.\n */\nfunction wrapContent(field: RunField, value: unknown): unknown {\n return field.contentKey === undefined ? value : { [field.contentKey]: value };\n}\n\n/**\n * The inverse. A value that is already bare passes through untouched: persisted\n * `inputData` predates the number and yes/no wrappers, and an inputs.json\n * written by hand or by an agent says `2`, not `{number: 2}`.\n */\nfunction unwrapContent(field: RunField, value: unknown): unknown {\n const key = field.contentKey;\n if (key === undefined || !value || typeof value !== 'object' || Array.isArray(value))\n return value;\n return ownProp(value as Record<string, unknown>, key);\n}\n\n/** How deep a nested `{ text: … }` / `{ content: … }` chain we bother unwrapping. */\nconst MAX_UNWRAP_DEPTH = 8;\n\n/**\n * Pull a plain string out of whatever the store hands a text field.\n *\n * Persisted `inputData` carries historical corruptions - a double-wrapped\n * `{ text: { text } }`, a `{ concept, content }` envelope that was never\n * deflated - and the old fallback ran `String()` over them, which renders the\n * literal `\"[object Object]\"` into the textarea. That is worse than showing\n * nothing: it looks exactly like content the user typed, and one keystroke\n * later it is content the user typed. So unwrap the envelopes we know, and give\n * up with `undefined` (an empty field) rather than displaying garbage.\n *\n * Genuine primitives still stringify - a number or a boolean in a text slot is\n * a value, not a wrapper.\n *\n * The envelope names here are the HISTORICAL corruptions, not the wrapper key:\n * the declared wrapper is stripped by `unwrapContent` first, off the field's\n * `contentKey`, exactly as the number and boolean paths do. A text wrapper\n * whose property is not literally `text` would otherwise read back empty - and\n * one save later, BE empty.\n */\nfunction textFromStored(value: unknown, depth = 0): string | undefined {\n if (value == null) return undefined;\n if (typeof value === 'string') return value;\n if (typeof value === 'number' || typeof value === 'boolean') return String(value);\n if (typeof value !== 'object' || depth >= MAX_UNWRAP_DEPTH) return undefined;\n const envelope = value as { text?: unknown; content?: unknown };\n if ('text' in envelope) return textFromStored(envelope.text, depth + 1);\n if ('content' in envelope) return textFromStored(envelope.content, depth + 1);\n return undefined;\n}\n\n/** RJSF full form value → the runner's field value. */\nfunction fromRjsf(field: RunField, value: unknown): unknown {\n switch (field.kind) {\n case 'text':\n case 'prose':\n return textFromStored(unwrapContent(field, value));\n case 'number': {\n // The control holds `number | undefined`. A numeric STRING is tolerated\n // because that is what a hand-written inputs.json tends to carry; anything\n // else empties the field rather than feeding NaN to a number input.\n const raw = unwrapContent(field, value);\n if (typeof raw === 'number') return Number.isFinite(raw) ? raw : undefined;\n if (typeof raw === 'string' && raw.trim() !== '') {\n const parsed = Number(raw);\n return Number.isFinite(parsed) ? parsed : undefined;\n }\n return undefined;\n }\n case 'boolean': {\n // Strictly a real boolean, deliberately: pipelex declares `YesNoContent.\n // yes_no` with `strict=True` precisely to refuse \"yes\"/1/\"true\", and\n // coercing here would smuggle back in what the runtime closed off.\n const raw = unwrapContent(field, value);\n return typeof raw === 'boolean' ? raw : undefined;\n }\n case 'unknown':\n // The escape hatch is a raw-JSON textarea, so a structured value belongs\n // there as JSON - `String(value)` would have shown \"[object Object]\" and\n // thrown the actual value away.\n if (typeof value === 'string') return value;\n if (value == null) return undefined;\n if (typeof value === 'object') {\n try {\n return JSON.stringify(value, null, 2);\n } catch {\n return undefined;\n }\n }\n return String(value);\n case 'document':\n case 'image': {\n if (value && typeof value === 'object') {\n const o = value as { url?: unknown; filename?: unknown };\n return o.url\n ? { url: String(o.url), filename: o.filename as string | undefined }\n : undefined;\n }\n return typeof value === 'string' && value ? { url: value } : undefined;\n }\n case 'object': {\n // An optional structure the store holds no object for - absent, or the\n // `null` a stored run writes for a structure it went without - stays\n // CLOSED. Materializing a shell of `undefined` children here reopened it:\n // `optionalStructureOpen` reads any plain object as open, so a run reloaded\n // from the store showed every structure it had left out as opened and\n // blank. A required structure has no closed state, and keeps its shell.\n if (isOptionalStructure(field) && !optionalStructureOpen(value)) return undefined;\n const obj = (value && typeof value === 'object' ? value : {}) as Dict;\n const out: Dict = {};\n for (const child of field.fields) out[child.name] = fromRjsf(child, ownProp(obj, child.name));\n return out;\n }\n case 'list': {\n const arr = Array.isArray(value) ? value : [];\n return arr.map((item) => fromRjsf(field.item, item));\n }\n default:\n return value;\n }\n}\n\n/**\n * The runner's field value → RJSF full form value (what runs/store expect).\n *\n * `collapseEmpty` is what a SINGULAR slot does and a LIST ITEM must not: an\n * untouched structure in a singular slot is absent, but an item exists only\n * because the user added it, so adding IS the touch. Only the structure case\n * reads the flag.\n */\nfunction toRjsf(field: RunField, value: unknown, collapseEmpty = true): unknown {\n switch (field.kind) {\n case 'text':\n case 'prose':\n return wrapContent(field, typeof value === 'string' ? value : '');\n case 'number':\n // An untouched number stays ABSENT rather than becoming an empty wrapper.\n // The gate then does the right thing on both counts: it prunes an absent\n // optional input, and it reports a required one as missing by name -\n // where `{number: undefined}` would read as a malformed value instead.\n return typeof value === 'number' && Number.isFinite(value)\n ? wrapContent(field, value)\n : undefined;\n case 'boolean':\n // `false` is a value, not an absence - hence the type test rather than a\n // truthiness one.\n return typeof value === 'boolean' ? wrapContent(field, value) : undefined;\n case 'unknown':\n return typeof value === 'string' ? value : '';\n case 'document':\n case 'image': {\n const url = value && typeof value === 'object' ? (value as { url?: unknown }).url : value;\n const filename =\n value && typeof value === 'object' ? (value as { filename?: unknown }).filename : undefined;\n return { url: url ? String(url) : '', ...(filename ? { filename } : {}) };\n }\n case 'object': {\n const obj = (value && typeof value === 'object' ? value : {}) as Dict;\n const out: Dict = {};\n for (const child of field.fields) out[child.name] = toRjsf(child, ownProp(obj, child.name));\n // A structure nobody put anything into stays ABSENT, exactly as an\n // untouched number does above - it does NOT become a shell of empty\n // children. Materializing that shell made an OPTIONAL structured input\n // unrunnable whenever its concept declared a required child: readiness\n // ignored the input (correctly - the method said it may be omitted), Run\n // lit up, and the gate then judged an object the kernel had invented\n // against the concept's full schema and rejected the run for a child the\n // user was never asked to fill.\n //\n // Emptiness is `isFilled`, the SAME predicate readiness and the wire\n // payload use, so the three cannot disagree about whether this input is\n // there. Which also says what the touch is NOT: opening the optional\n // disclosure is local view state the value never sees, so a section\n // opened and left blank collapses exactly like one never opened. What\n // keeps a structure is a VALUE in it - and then the whole shell survives,\n // empty children and all, so a required child left blank still fails, and\n // loudly.\n return collapseEmpty && !isFilled(out) ? undefined : out;\n }\n case 'list': {\n const arr = Array.isArray(value) ? value : [];\n // An item is NEVER absent: it is in the array because the user added it,\n // and `ListField`'s \"Add\" seeds an object item with `{}`. Letting it\n // collapse the way an untouched singular slot does put `undefined` in the\n // array, which ajv rejects as `must be object` - blocking an empty item\n // the item schema allowed, and turning a required-child complaint into a\n // type error that names nothing the user can act on.\n return arr.map((item) => toRjsf(field.item, item, false));\n }\n default:\n return value;\n }\n}\n\n// ─── Store ↔ RunField values ──────────────────────────────────────────────\n\n/** Seed the runner's form values from the method-store's simplified inputData. */\nexport function runValuesFromStore(\n inputData: Dict | undefined,\n fields: RunField[],\n inputSchemas: InputSchemas,\n): Dict {\n const full = inflateAllInputs(inputData ?? {}, inputSchemas);\n const out: Dict = {};\n for (const field of fields) out[field.name] = fromRjsf(field, ownProp(full, field.name));\n return out;\n}\n\n/**\n * The runner's form values in **schema shape** - the same shape an RJSF panel\n * holds, and therefore the shape `gate.ts` validates against the per-input\n * JSON Schemas.\n *\n * Deliberately stops short of `deflateAllInputs`: deflation is the STORE's\n * compact form, and ajv validates the full one.\n */\nexport function rjsfDataFromRunValues(values: Dict, fields: RunField[]): Dict {\n const full: Dict = {};\n for (const field of fields) full[field.name] = toRjsf(field, ownProp(values, field.name));\n return full;\n}\n\n/** Convert the runner's form values back to the store's simplified inputData. */\nexport function storeInputDataFromRunValues(\n values: Dict,\n fields: RunField[],\n inputSchemas: InputSchemas,\n): Dict {\n return deflateAllInputs(rjsfDataFromRunValues(values, fields), inputSchemas);\n}\n\n/**\n * Build the `{ concept, content }` map a run expects from the form values.\n *\n * The two ways a method says \"this may be nothing\" land differently on the wire,\n * and both matter:\n * - an **optional (`?`)** input left blank is OMITTED, so the runtime records a\n * real absence the method can branch on - sending `{ text: \"\" }` would look\n * like the caller supplied an empty string;\n * - a **plural (`[]`)** input keeps its key, because a plural slot is never\n * absent - its empty form IS the empty list, and the runtime requires the key.\n * When that list is EMPTY it is sent BARE, without the envelope: the envelope\n * is the runtime's \"explicit form\", which bypasses the top-down shaper and\n * hands the value to the bottom-up factory, and that factory types a list from\n * its first item - so an empty list there raises \"Cannot create Stuff from\n * empty list in content\". The bare form keeps the shaper, which reads the\n * DECLARED concept and builds the empty list correctly. (pipelex/#1096 makes\n * the envelope agree; the bare form runs today and stays correct after.)\n */\nexport function apiInputsFromRunValues(\n values: Dict,\n fields: RunField[],\n inputSchemas: InputSchemas,\n): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const field of fields) {\n const schema = ownProp(inputSchemas, field.name);\n if (!schema) continue;\n const value = ownProp(values, field.name);\n if (isOptionalInput(schema) && !isFilled(value)) continue;\n if (isPluralInput(schema) && !isFilled(value)) {\n out[field.name] = [];\n continue;\n }\n out[field.name] = { concept: schema.concept_ref, content: toRjsf(field, value) };\n }\n return out;\n}\n\n/**\n * The form values a set of run inputs stands for: the inverse of\n * `apiInputsFromRunValues`, for inputs saved from a form (an example) and\n * handed back to one.\n *\n * Each input is read as a run sends it, `{ concept, content }`, or as its bare\n * content (the empty plural `[]`), and its content is turned back into the\n * control's own shape. Only an object naming its concept is read as that\n * envelope: a structure sent bare may well have a property called `content`. An input the inputs do not hold is left empty, and an\n * optional structure they do not hold stays closed: the inputs are the whole\n * run, so an input they left out was left out of the run too. An input no\n * field takes is ignored.\n */\nexport function runValuesFromInputs(inputs: Readonly<Dict> | undefined, fields: RunField[]): Dict {\n const out: Dict = {};\n for (const field of fields) {\n const entry = ownProp(inputs ?? {}, field.name);\n const content = isWrappedForm(entry) ? entry.content : entry;\n out[field.name] = fromRjsf(field, content);\n }\n return out;\n}\n\n/**\n * Whether two sets of form values send the same run.\n *\n * Compared in the shape a run takes, so the differences a run cannot see do\n * not count: a text typed and then erased is the blank it started as, and an\n * optional structure opened and left empty is the closed one it was. What\n * \"Fill with an example\" asks before replacing is the work a person did, and\n * a value that sends nothing is no work to lose.\n */\nexport function sameRunValues(a: Dict, b: Dict, fields: RunField[]): boolean {\n return (\n JSON.stringify(rjsfDataFromRunValues(a, fields)) ===\n JSON.stringify(rjsfDataFromRunValues(b, fields))\n );\n}\n\n// ─── Pipe output → result entries ────────────────────────────────────────────\n\n/** One named output pulled out of a run's working memory, ready to render. */\nexport interface OutputEntry {\n /** The output variable key (mono). */\n key: string;\n conceptRef?: string;\n value: unknown;\n}\n\n/**\n * The slice of a serialized pipe output this module actually reads. Structural\n * on purpose: the SDK's `DictPipeOutput` is the host's wire type, and the kernel\n * must not depend on `@pipelex/sdk` - the guard below verifies the shape at\n * runtime anyway.\n */\ninterface PipeOutputWithWorkingMemory {\n working_memory: {\n root: Record<string, unknown>;\n aliases?: Record<string, string>;\n };\n}\n\nfunction hasWorkingMemoryRoot(value: unknown): value is PipeOutputWithWorkingMemory {\n return (\n !!value &&\n typeof value === 'object' &&\n 'working_memory' in value &&\n !!(value as { working_memory?: { root?: unknown } }).working_memory &&\n typeof (value as { working_memory: { root?: unknown } }).working_memory.root === 'object'\n );\n}\n\n/** The concept code of a working-memory entry (`{concept}` may be obj/str/absent). */\nfunction entryConceptRef(data: unknown): string | undefined {\n if (!data || typeof data !== 'object') return undefined;\n const raw = (data as { concept?: unknown; concept_code?: unknown }).concept;\n if (raw && typeof raw === 'object')\n return (\n ((raw as { concept_code?: string }).concept_code ?? (raw as { code?: string }).code) ||\n undefined\n );\n if (typeof raw === 'string') return raw;\n return (data as { concept_code?: string }).concept_code || undefined;\n}\n\n/**\n * Split a run's pipe output into the main result and any intermediate outputs,\n * excluding the inputs. The main output's identity comes from the working\n * memory's `main_stuff` alias (the authoritative pointer to the output variable)\n * - so its label is the REAL stuff name, not a positional guess. Falls back to\n * the last produced stuff only when the alias is absent.\n */\nexport function outputsFromPipeOutput(\n pipeOutput: unknown,\n inputKeys: string[],\n): { main: OutputEntry; intermediates: OutputEntry[] } | null {\n if (!hasWorkingMemoryRoot(pipeOutput)) return null;\n const wm = pipeOutput.working_memory as {\n root: Record<string, unknown>;\n aliases?: Record<string, string>;\n };\n const entries = Object.entries(wm.root).filter(([key]) => !inputKeys.includes(key));\n if (entries.length === 0) return null;\n\n const toEntry = ([key, data]: [string, unknown]): OutputEntry => ({\n key,\n conceptRef: entryConceptRef(data),\n value: (data as { content?: unknown })?.content ?? data,\n });\n\n // The real main-output name: `aliases.main_stuff` → its root key.\n const mainKey = wm.aliases?.['main_stuff'];\n const mainEntry: [string, unknown] =\n mainKey && Object.prototype.hasOwnProperty.call(wm.root, mainKey)\n ? [mainKey, wm.root[mainKey]]\n : entries[entries.length - 1]!;\n const intermediates = entries.filter(([key]) => key !== mainEntry[0]).map(toEntry);\n\n return { main: toEntry(mainEntry), intermediates };\n}\n\n/**\n * Recover the inputs a run was executed with from its working memory. The run's\n * `working_memory.root` holds every named stuff - inputs AND outputs - keyed by\n * variable name; we pull the entries whose keys are declared inputs and deflate\n * their `content` (the full form shape) back into the store's simplified\n * `inputData`. Lets the runner repopulate the form for a past/shared run - the\n * inputs that produced the result. Returns `null` when no inputs are present.\n */\nexport function inputDataFromWorkingMemory(\n workingMemory: unknown,\n inputSchemas: InputSchemas,\n): Dict | null {\n const root = (workingMemory as { root?: Record<string, unknown> } | null | undefined)?.root;\n if (!root || typeof root !== 'object') return null;\n const full: Dict = {};\n let found = false;\n for (const key of Object.keys(inputSchemas)) {\n const entry = ownProp(root, key);\n if (entry && typeof entry === 'object' && 'content' in entry) {\n full[key] = (entry as { content: unknown }).content;\n found = true;\n }\n }\n if (!found) return null;\n return deflateAllInputs(full, inputSchemas);\n}\n\n/**\n * Field descriptors for a method's main pipe - the wire descriptor mapped over\n * the contract, or `[]` while either artifact has not arrived yet. The\n * descriptor comes back from `validate` beside `pipe_io_contracts` when the\n * request opts in with `views: [\"input_form\"]`; `getPipeInputForm` is the\n * lookup that matches `getPipeIOContract`.\n */\nexport function fieldsForContract(\n contract: PipeIOContract | undefined,\n descriptor: PipeInputFormDescriptor | undefined,\n): RunField[] {\n return contract?.inputs && descriptor ? buildRunFields(descriptor, contract.inputs) : [];\n}\n\n/**\n * Immutably set a value at a dotted/indexed path (`a.0.b`). Used to write an\n * uploaded file's URL back to a field anywhere in the (possibly nested) tree.\n */\nexport function setValueAtPath(root: Dict, path: string[], value: unknown): Dict {\n const head = path[0];\n if (head === undefined) return root;\n const rest = path.slice(1);\n if (rest.length === 0) return { ...root, [head]: value };\n\n const nextSeg = rest[0] as string;\n const child = root[head];\n if (/^\\d+$/.test(nextSeg)) {\n const arr = Array.isArray(child) ? child.slice() : [];\n const idx = Number(nextSeg);\n arr[idx] =\n rest.length === 1 ? value : setValueAtPath((arr[idx] as Dict) ?? {}, rest.slice(1), value);\n return { ...root, [head]: arr };\n }\n return { ...root, [head]: setValueAtPath((child as Dict) ?? {}, rest, value) };\n}\n"]}
|