@odla-ai/brand 0.4.0 → 0.6.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/index.d.cts CHANGED
@@ -1,7 +1,113 @@
1
- import { P as ProposalKind, a as ProposalStatus, A as AssetKind, b as AssetAnalysis, B as BookStatus, c as BrandTokensSnapshot, d as PaletteStatus, S as Swatch, e as PaletteSource, f as SectionKind, g as SectionStatus } from './index-CRl3IXHB.cjs';
2
- export { h as ASSET_KINDS, i as BOOK_STATUSES, j as BRAND_CHART_TOKENS, k as BRAND_CHAT_TOKENS, l as BRAND_DERIVED_TOKENS, m as BRAND_EMITTED_TOKENS, n as BRAND_NS, o as BRAND_REQUIRED_TOKENS, p as BrandTokens, C as CompileInput, q as CompiledBrandTokens, D as DARK_FLIP_L_MAX, r as DARK_FLIP_L_MIN, s as DEFAULT_ACCENT_SEED, I as ImagerySection, L as LogoSection, M as MapResult, t as PALETTE_SOURCES, u as PALETTE_STATUSES, v as PROPOSAL_KINDS, w as PROPOSAL_STATUSES, x as PaletteSection, R as RenderTokensCssOptions, y as SECTION_KINDS, z as SECTION_STATUSES, E as SWATCH_ROLES, F as SwatchRole, T as TokenWarning, G as TypographySection, V as VoiceSection, H as compileBrandTokens, J as deriveDarkTokens, K as mapPaletteToTokens, N as renderTokensCss } from './index-CRl3IXHB.cjs';
1
+ import { P as ProposalKind, a as ProposalStatus, A as AssetKind, b as AssetAnalysis, B as BookStatus, c as BrandTokensSnapshot, d as PaletteStatus, S as Swatch, e as PaletteSource, f as SectionKind, g as SectionStatus, h as SwatchRole } from './index-r36KQK5n.cjs';
2
+ export { i as ASSET_KINDS, j as BOOK_STATUSES, k as BRAND_CHART_TOKENS, l as BRAND_CHAT_TOKENS, m as BRAND_DERIVED_TOKENS, n as BRAND_EMITTED_TOKENS, o as BRAND_NS, p as BRAND_REQUIRED_TOKENS, q as BrandTokens, C as CompileInput, r as CompiledBrandTokens, D as DARK_FLIP_L_MAX, s as DARK_FLIP_L_MIN, t as DEFAULT_ACCENT_SEED, u as DESIGN_ASSET_KIND, I as ImagerySection, L as LogoSection, M as MapResult, v as PALETTE_SOURCES, w as PALETTE_STATUSES, x as PROPOSAL_KINDS, y as PROPOSAL_STATUSES, z as PaletteSection, R as ROLE_TOKEN, E as RenderTokensCssOptions, F as SECTION_KINDS, G as SECTION_STATUSES, H as SWATCH_ROLES, T as TokenWarning, J as TypographySection, V as VoiceSection, K as compileBrandTokens, N as deriveDarkTokens, O as mapPaletteToTokens, Q as renderTokensCss } from './index-r36KQK5n.cjs';
3
3
  import { ToolHandler, Skill, ToolDef, Persona, Inference, AgentRunInput, ImageBlock, OracleContentBlock } from '@odla-ai/ai';
4
4
 
5
+ /** One entry of the bundle's base64 asset manifest, without its payload. */
6
+ interface DesignBundleAsset {
7
+ /** The manifest key; also the placeholder the template substitutes. */
8
+ uuid: string;
9
+ /** Declared MIME type (`font/woff2`, `image/png`, `text/javascript`, …). */
10
+ mime: string;
11
+ /** Decoded byte length, derived from the base64 payload's length. */
12
+ bytes: number;
13
+ /** Whether the payload is gzipped (the loader inflates it at runtime). */
14
+ compressed: boolean;
15
+ }
16
+ /** A parsed bundle: the islands, split out, with payloads left encoded. */
17
+ interface DesignBundle {
18
+ /** The real document, already JSON-decoded from the template island. */
19
+ template: string;
20
+ /** Manifest entries, payload-free. */
21
+ assets: DesignBundleAsset[];
22
+ /** CDN URLs the design was authored against (their bytes ship inline). */
23
+ externals: string[];
24
+ /** Nested page-bundle uuids (iframe targets); empty for a single page. */
25
+ pageOrder: string[];
26
+ /** The loader's poster SVG, if present — a hand-sized preview of the
27
+ * design that needs no JavaScript to render. */
28
+ thumbnailSvg?: string;
29
+ }
30
+ /** Assets grouped by MIME type — what a digest reports instead of per-file
31
+ * rows, since a bundle carries dozens of font subsets. */
32
+ interface DesignAssetGroup {
33
+ mime: string;
34
+ count: number;
35
+ bytes: number;
36
+ }
37
+ /** One configurable prop the design declares (`data-props` on its logic
38
+ * script): the editor Claude Design renders, its default, and its grouping. */
39
+ interface DesignProp {
40
+ name: string;
41
+ /** Editor kind — `text`, `boolean`, `enum`, … as authored. */
42
+ editor: string;
43
+ /** Allowed values, for `enum` editors. */
44
+ options?: string[];
45
+ /** The declared default, stringified. */
46
+ default?: string;
47
+ /** The design's own grouping label (e.g. "Copy", "Layout"). */
48
+ section?: string;
49
+ /** The TypeScript type the design declares for the prop. */
50
+ tsType?: string;
51
+ }
52
+ /** One heading in document order — the design's information architecture. */
53
+ interface DesignOutlineEntry {
54
+ /** Heading level: 1 for `<h1>` … 6 for `<h6>`. */
55
+ level: number;
56
+ text: string;
57
+ }
58
+ /** A literal color the template's CSS uses, with how often it appears. */
59
+ interface DesignColorUse {
60
+ hex: string;
61
+ count: number;
62
+ }
63
+ /** The `--ui-*` custom properties a design declares, split by theme. A
64
+ * design authored against the @odla-ai/ui contract declares these directly,
65
+ * which is what makes {@link import("./decompile").swatchesFromDesignTokens}
66
+ * possible. */
67
+ interface DesignTokenSets {
68
+ light: Record<string, string>;
69
+ dark: Record<string, string>;
70
+ }
71
+ /**
72
+ * Everything @odla-ai/brand knows about a design without opening its bytes:
73
+ * what it weighs, what it depends on, the design tokens it declares, the
74
+ * props it exposes, and the page outline. Computed deterministically at
75
+ * upload and stored on the asset row.
76
+ */
77
+ interface DesignDigest {
78
+ /** Digest schema marker, so stored digests can be migrated. */
79
+ format: "claude-design-bundle/1";
80
+ /** The document's `<title>`, when it sets one. */
81
+ title?: string;
82
+ /** Byte length of the decoded template document. */
83
+ templateBytes: number;
84
+ /** Total decoded bytes across every manifest asset. */
85
+ assetBytes: number;
86
+ /** Manifest asset count. */
87
+ assetCount: number;
88
+ /** Assets grouped by MIME type, largest group first. */
89
+ assetGroups: DesignAssetGroup[];
90
+ /** CDN URLs the design was built against. */
91
+ externals: string[];
92
+ /** Nested page bundles (0 for a single-document design). */
93
+ pageCount: number;
94
+ /** `--ui-*` declarations, by theme. */
95
+ tokens: DesignTokenSets;
96
+ /** `font-family` values the template names, deduped in first-seen order. */
97
+ fonts: string[];
98
+ /** Literal hex colors in the template's CSS, most-used first. */
99
+ colors: DesignColorUse[];
100
+ /** The design's declared configuration surface. */
101
+ props: DesignProp[];
102
+ /** Headings in document order. */
103
+ outline: DesignOutlineEntry[];
104
+ /** The loader's poster SVG, when small enough to carry. */
105
+ thumbnailSvg?: string;
106
+ /** What was dropped to stay inside the digest caps, for honesty in the
107
+ * UI and in agent-facing output. Empty when nothing was truncated. */
108
+ truncated: string[];
109
+ }
110
+
5
111
  /** Immutable storage snapshot captured by the trusted semantic Brand bridge. */
6
112
  interface BrandSourceAssetSnapshot {
7
113
  assetId: string;
@@ -245,6 +351,10 @@ interface BrandAsset {
245
351
  status: "live" | "deleting" | "deleted";
246
352
  title?: string;
247
353
  analysis?: AssetAnalysis;
354
+ /** Present on `design` assets: the digest computed from the bundle at
355
+ * upload. Deterministic and machine-derived, so it carries no review
356
+ * state — see {@link import("./design/types").DesignDigest}. */
357
+ design?: DesignDigest;
248
358
  analyzedAt?: number;
249
359
  analysisRevision: number;
250
360
  analysisDigest?: string;
@@ -458,8 +568,15 @@ declare function brandRules(): BrandRules;
458
568
 
459
569
  /** Most swatches a single palette may carry. */
460
570
  declare const MAX_SWATCHES = 24;
461
- /** Upload content types the asset pipeline accepts. */
571
+ /** Upload content types the asset pipeline accepts for every kind EXCEPT
572
+ * `design`. Deliberately free of `text/html`: these bytes are handed back to
573
+ * members over signed storage URLs, and an HTML document served from a
574
+ * storage origin is a script-execution surface. */
462
575
  declare const ASSET_CONTENT_TYPES: ReadonlySet<string>;
576
+ /** The only content type a `design` asset may carry. Designs are the one
577
+ * HTML-bearing kind, and they are never served raw — the preview route
578
+ * proxies them under a `sandbox` CSP (see `routes/design-preview.ts`). */
579
+ declare const DESIGN_CONTENT_TYPES: ReadonlySet<string>;
463
580
  /**
464
581
  * Assert `value` is a `#rgb`/`#rrggbb` hex color and normalize it to
465
582
  * lowercase `#rrggbb`. Alpha channels (`#rgba`/`#rrggbbaa`) and every other
@@ -493,17 +610,50 @@ declare function assertSectionContent(kind: string, content: unknown): Record<st
493
610
  */
494
611
  declare function safeFileName(name: unknown): string;
495
612
  /**
496
- * Assert an upload content type is on the {@link ASSET_CONTENT_TYPES}
497
- * allowlist. Normalizes case and strips parameters (`; charset=…`) before
498
- * checking; returns the normalized bare type.
613
+ * Assert an upload content type is allowed FOR ITS KIND, and return the
614
+ * normalized bare type (case-folded, `; charset=…` stripped).
615
+ *
616
+ * The allowlist is per-kind, not global: `design` accepts
617
+ * {@link DESIGN_CONTENT_TYPES} and nothing else, every other kind accepts
618
+ * {@link ASSET_CONTENT_TYPES} and nothing else. The two sets are disjoint on
619
+ * purpose — it must be impossible to store HTML under a kind whose bytes are
620
+ * handed out by signed URL, or to store an image under the kind the preview
621
+ * route serves as a document.
499
622
  */
500
- declare function assertAssetContentType(value: unknown): string;
623
+ declare function assertAssetContentType(value: unknown, kind?: string): string;
501
624
  /**
502
625
  * Validate + normalize an agent's asset analysis: description ≤ 2000 chars,
503
626
  * ≤ 12 dominant colors (each normalized hex), ≤ 24 tags of ≤ 60 chars.
504
627
  */
505
628
  declare function assertAnalysis(value: unknown): AssetAnalysis;
506
629
 
630
+ /**
631
+ * A stored row in the shape it was WRITTEN, ready to verify.
632
+ *
633
+ * The engine stores a `date` as the epoch ms it was given and hands a reader
634
+ * ISO-8601 text back. Brand digests rows that CONTAIN dates — a proposal's
635
+ * `reviewDigest` covers its `createdAt`, and an approval receipt's
636
+ * `receiptDigest` covers its own — so a row read straight out of the store can
637
+ * never match the digest stored beside it. Two production symptoms, both 409:
638
+ * resolving any proposal ("proposal changed since review") and reading a book's
639
+ * tokens after approval.
640
+ *
641
+ * Normalising at the READ is the fix, not tolerating both shapes in the
642
+ * verifier. Tolerance would repair a `safeTime` check and leave the digest
643
+ * failing, because the digest was taken over the number and nothing can change
644
+ * that after the fact.
645
+ *
646
+ * Anything that is not date-shaped text passes through untouched, so a row that
647
+ * never round-tripped verifies exactly as before. `json` attrs are left alone:
648
+ * their contents round-trip as written, which is why an `authorityConsumption`
649
+ * and the `createdAt` beside it disagreed at all.
650
+ */
651
+ declare function rowAsWritten<T>(ns: string, row: T): T;
652
+ /** A stored approval receipt in the shape it was written. */
653
+ declare function receiptAsWritten<T>(row: T): T;
654
+ /** A stored proposal in the shape it was written, so `reviewDigest` matches. */
655
+ declare function proposalAsWritten<T>(row: T): T;
656
+
507
657
  /** Stay materially below the server's whole-guards parser budget. */
508
658
  declare function isBoundedBrandJson(root: unknown, limits?: {
509
659
  maxDepth?: number;
@@ -741,6 +891,8 @@ interface CreateAssetInput {
741
891
  uploadedAuthorityRef: string;
742
892
  audience: string[];
743
893
  title?: string;
894
+ /** `design` kind only: the digest parsed from the uploaded bundle. */
895
+ design?: DesignDigest;
744
896
  now: number;
745
897
  }
746
898
  /**
@@ -763,6 +915,216 @@ declare function finishAssetDeleteOps(assetId: BrandEntityRef): BrandOp[];
763
915
  */
764
916
  declare function recordAnalysisOps(assetId: BrandEntityRef, analysis: unknown, priorRevision: number, analyzedBy: string, analyzedAuthorityRef: string, now: number): Promise<BrandOp[]>;
765
917
 
918
+ /** Longest poster SVG carried into a digest; larger ones are dropped. */
919
+ declare const MAX_THUMBNAIL_CHARS = 16384;
920
+ /**
921
+ * Cheap structural sniff: does this text look like a Claude Design bundle?
922
+ * Checks for the two islands that carry the design itself, so a plain HTML
923
+ * page (or an unrelated file that happens to be HTML) is rejected before any
924
+ * parsing work happens.
925
+ */
926
+ declare function isDesignBundle(html: string): boolean;
927
+ /** Decoded byte length of a base64 payload, without decoding it. */
928
+ declare function base64ByteLength(data: string): number;
929
+ /**
930
+ * The loader's poster: the `<svg>` inside `#__bundler_thumbnail`. It renders
931
+ * with no JavaScript and no blob URLs, so it is the one part of a design that
932
+ * can be shown anywhere. Returns undefined when absent or over
933
+ * {@link MAX_THUMBNAIL_CHARS}.
934
+ */
935
+ declare function extractThumbnailSvg(html: string): string | undefined;
936
+ /** One manifest entry WITH its base64 payload. */
937
+ interface DesignManifestEntry {
938
+ mime: string;
939
+ compressed: boolean;
940
+ /** Base64 payload, gzipped first when `compressed`. */
941
+ data: string;
942
+ }
943
+ /**
944
+ * Read the manifest island's entries INCLUDING their payloads, keyed by uuid.
945
+ *
946
+ * Everything else in this module deliberately leaves payloads encoded and
947
+ * only measures them, because the worker never needs the bytes. This is the
948
+ * one exception, for callers that genuinely write assets out — the CLI's
949
+ * `brand design unpack`. It holds the whole manifest in memory, so use it
950
+ * only where that is affordable.
951
+ */
952
+ declare function readDesignManifest(html: string): Record<string, DesignManifestEntry>;
953
+ /**
954
+ * Parse a Claude Design standalone-HTML export into its parts: the real
955
+ * document (JSON-decoded from the template island), payload-free manifest
956
+ * summaries, the external-resource index, nested page uuids, and the poster
957
+ * SVG.
958
+ *
959
+ * Throws {@link BrandInputError} when the text is not a bundle or an island
960
+ * is malformed — the messages are safe to return to a caller as a 400.
961
+ */
962
+ declare function parseDesignBundle(html: string): DesignBundle;
963
+
964
+ /** One declaration the scanner found, with the selectors it was nested in. */
965
+ interface ScannedDeclaration {
966
+ /** Outermost → innermost selector/at-rule preludes. */
967
+ selectors: string[];
968
+ /** Property name, including the leading `--`. */
969
+ name: string;
970
+ /** Declaration value, trimmed, with comments already removed. */
971
+ value: string;
972
+ }
973
+ /** Remove `/* … *​/` comments so they cannot break declaration splitting. */
974
+ declare function stripCssComments(css: string): string;
975
+ /**
976
+ * Concatenate every `<style>` element's text in document order. Designs ship
977
+ * their theme as a sequence of style blocks (a vendored base tier, then
978
+ * overrides), and the cascade between them is exactly this order.
979
+ */
980
+ declare function styleSheetText(html: string): string;
981
+ /**
982
+ * Walk `css` and yield every custom-property declaration with its enclosing
983
+ * selector stack, in document order. Brace and paren depth are tracked so
984
+ * nested at-rules (`@media { :root { … } }`) and parenthesised values
985
+ * (`color-mix(in srgb, …)`) are handled correctly.
986
+ *
987
+ * Only `--*` declarations are reported; ordinary properties are skipped.
988
+ */
989
+ declare function scanCustomProperties(css: string): ScannedDeclaration[];
990
+
991
+ /** One token that could not become a swatch, and why. */
992
+ interface DesignTokenSkip {
993
+ token: string;
994
+ value: string;
995
+ reason: string;
996
+ }
997
+ /** What {@link swatchesFromDesignTokens} produced. */
998
+ interface DesignDecompilation {
999
+ swatches: Swatch[];
1000
+ /** Tokens present but not literal opaque colours. */
1001
+ skipped: DesignTokenSkip[];
1002
+ /** Roles the design declared no token for at all. */
1003
+ missing: SwatchRole[];
1004
+ }
1005
+ /** Parse one CSS colour value to `#rrggbb`, or null when it is not a literal
1006
+ * opaque colour. Accepts hex and `rgb()`/`rgba()` with alpha exactly 1. */
1007
+ declare function cssColorToHex(value: string): string | null;
1008
+ /**
1009
+ * Read a design's declared `--ui-*` tokens back into brand swatches.
1010
+ *
1011
+ * Reads the LIGHT set: brand palettes are authored light-first and
1012
+ * `deriveDarkTokens` regenerates dark on compile, so importing a design's
1013
+ * dark values would be overwritten anyway. The design's dark tokens stay
1014
+ * visible in the digest for reference.
1015
+ */
1016
+ declare function swatchesFromDesignTokens(tokens: DesignTokenSets): DesignDecompilation;
1017
+
1018
+ /** Most external-resource URLs carried into a digest. */
1019
+ declare const MAX_EXTERNALS = 24;
1020
+ /** Group manifest assets by MIME type, heaviest group first. */
1021
+ declare function groupAssets(bundle: DesignBundle): DesignAssetGroup[];
1022
+ /**
1023
+ * Build the digest for an already-parsed bundle.
1024
+ *
1025
+ * `templateBytes` is measured in UTF-8 bytes, not characters, so it matches
1026
+ * what the CLI writes to disk for a template full of typographic quotes.
1027
+ */
1028
+ declare function digestDesignBundle(bundle: DesignBundle): DesignDigest;
1029
+ /**
1030
+ * Parse a Claude Design standalone-HTML export and digest it in one step.
1031
+ * Throws {@link import("../errors").BrandInputError} when the file is not a
1032
+ * design bundle.
1033
+ */
1034
+ declare function digestDesignHtml(html: string): DesignDigest;
1035
+
1036
+ /** Decode the named and numeric HTML entities that appear in real markup. */
1037
+ declare function decodeEntities(text: string): string;
1038
+ /** Collapse every run of whitespace to a single space and trim. */
1039
+ declare const collapseWhitespace: (text: string) => string;
1040
+ /**
1041
+ * Strip tags and decode entities, yielding the visible text of a markup
1042
+ * fragment. Script and style element contents are dropped whole — a heading
1043
+ * containing an inline `<style>` would otherwise contribute CSS as prose.
1044
+ */
1045
+ declare function htmlToText(fragment: string): string;
1046
+
1047
+ /** Most headings carried into a digest. */
1048
+ declare const MAX_OUTLINE_ENTRIES = 120;
1049
+ /** Longest single heading kept, in characters. */
1050
+ declare const MAX_HEADING_CHARS = 200;
1051
+ /** The document `<title>`, decoded and collapsed; undefined when unset. */
1052
+ declare function extractTitle(html: string): string | undefined;
1053
+ /**
1054
+ * Headings (`<h1>`…`<h6>`) in document order, as level + visible text.
1055
+ *
1056
+ * Empty headings — icon-only or decorative — are skipped rather than emitted
1057
+ * as blanks. The scan stops at {@link MAX_OUTLINE_ENTRIES}; the caller
1058
+ * reports the truncation in the digest.
1059
+ */
1060
+ declare function extractOutline(html: string): {
1061
+ entries: DesignOutlineEntry[];
1062
+ truncated: boolean;
1063
+ };
1064
+
1065
+ /** Most props carried into a digest. */
1066
+ declare const MAX_PROPS = 60;
1067
+ /**
1068
+ * Extract the design's declared props, in declaration order.
1069
+ *
1070
+ * Returns an empty list — never throws — when the design declares none or
1071
+ * the attribute is unparseable: props are a bonus signal, and a design
1072
+ * without them is still perfectly usable.
1073
+ */
1074
+ declare function extractProps(html: string): {
1075
+ props: DesignProp[];
1076
+ truncated: boolean;
1077
+ };
1078
+
1079
+ /** Most typeface families reported. */
1080
+ declare const MAX_FONTS = 16;
1081
+ /** Most distinct literal colours reported. */
1082
+ declare const MAX_COLORS = 24;
1083
+ /**
1084
+ * The typeface families a design uses: the ones it embeds when it embeds
1085
+ * any, otherwise the quoted families its font stacks name, ranked by how
1086
+ * often they appear.
1087
+ */
1088
+ declare function extractFonts(templateHtml: string): string[];
1089
+ /**
1090
+ * Literal `#rrggbb`/`#rgb` colours in the design's CSS, most-used first.
1091
+ *
1092
+ * Complements the token extractor rather than duplicating it: tokens say
1093
+ * what the design DECLARES as its contract, this says what its stylesheets
1094
+ * actually paint with — including one-off colours never promoted to a token.
1095
+ * Function-syntax colours (`rgba()`, `color-mix()`, `oklch()`) are not
1096
+ * counted; they carry alpha or composition that a flat hex tally would
1097
+ * misrepresent.
1098
+ */
1099
+ declare function extractColors(templateHtml: string): DesignColorUse[];
1100
+
1101
+ /**
1102
+ * Substitute every `var(--name[, fallback])` in `value` using `table`,
1103
+ * recursively. An unresolvable reference falls back to its declared fallback
1104
+ * when it has one, and is otherwise left literal so the caller can see that
1105
+ * the value did not resolve.
1106
+ */
1107
+ declare function resolveVarRefs(value: string, table: ReadonlyMap<string, string>, depth?: number): string;
1108
+ /**
1109
+ * Extract the `--ui-*` tokens a design effectively declares, per theme, with
1110
+ * var() chains resolved to their computed text.
1111
+ *
1112
+ * Declarations are read from document-level selectors only (`:root`, `html`,
1113
+ * `[data-theme=…]`, `.ui-invert`); component-scoped custom properties are
1114
+ * ignored. Dark inherits every light token it does not override, mirroring
1115
+ * how theme sheets are written.
1116
+ */
1117
+ declare function extractDesignTokens(templateHtml: string): DesignTokenSets;
1118
+
1119
+ /**
1120
+ * WCAG contrast ratios (2 dp) for a palette's key role pairs, stored
1121
+ * verbatim in the proposal payload so review is numbers, not vibes.
1122
+ *
1123
+ * Every foreground is measured against the palette's own `bg` (white when
1124
+ * it declares none), plus the readability of text placed on `primary`.
1125
+ */
1126
+ declare function contrastReport(swatches: Swatch[]): Record<string, number>;
1127
+
766
1128
  /** An sRGB color with channels as fractions in [0, 1]. */
767
1129
  interface Rgb {
768
1130
  /** Red channel, 0..1. */
@@ -1127,6 +1489,10 @@ interface BrandToolCtx {
1127
1489
  expectedAnalysisRevision: number;
1128
1490
  }): Promise<BrandAsset>;
1129
1491
  readAssetContent(assetId: string): Promise<BrandFetchedBytes>;
1492
+ /** The decoded template document of a `design` asset. Memoized per skill
1493
+ * instance: a bundle is megabytes, and `read_design_source` is designed to
1494
+ * be called repeatedly while an agent ports markup. */
1495
+ readDesignTemplate(assetId: string): Promise<string>;
1130
1496
  resolvePrincipals(ids: string[]): Promise<BrandPrincipalProjection[]>;
1131
1497
  authority(capability: BrandCapability): Promise<BrandCapabilityAuthority>;
1132
1498
  /** Load the scoped book row; throws BrandNotFoundError when missing. */
@@ -1139,7 +1505,7 @@ interface BrandToolCtx {
1139
1505
  * instruction section. */
1140
1506
  declare const BRAND_INSTRUCTIONS: string;
1141
1507
  /**
1142
- * Build the brand Skill: read/asset/palette/book tools scoped to one book,
1508
+ * Build the brand Skill: read/asset/design/palette/book tools scoped to one book,
1143
1509
  * acting as one bot identity, plus {@link BRAND_INSTRUCTIONS}. Attach it to
1144
1510
  * a Persona (or use `createBrandPersona`).
1145
1511
  */
@@ -1290,6 +1656,10 @@ interface BrandRouteOpts {
1290
1656
  * private Brand asset. Callers never provide this URL or receive it back.
1291
1657
  */
1292
1658
  fetchPrivateAsset?: typeof fetch;
1659
+ /** `frame-ancestors` for the design preview response — who may embed a
1660
+ * design. Default `["'self'"]`. Widen only to origins you control: the
1661
+ * preview renders untrusted design HTML. */
1662
+ previewFrameAncestors?: string[];
1293
1663
  /** Upload size cap in bytes (checked against `File.size`). Default 8 MiB. */
1294
1664
  maxUploadBytes?: number;
1295
1665
  /** Serve `GET /books/:id/tokens.css` and `tokens.json` without authorize —
@@ -1313,6 +1683,7 @@ interface BrandRouteCtx {
1313
1683
  maxUploadBytes: number;
1314
1684
  discussionBasePath: string;
1315
1685
  fetchPrivateAsset: typeof fetch;
1686
+ previewFrameAncestors: string[];
1316
1687
  }
1317
1688
 
1318
1689
  /** Freeze the exact OPEN proposal fields a reviewer sees. */
@@ -1530,4 +1901,4 @@ interface CreateBrandIntegrationOptions {
1530
1901
  */
1531
1902
  declare function createBrandIntegration(options?: CreateBrandIntegrationOptions): BrandIntegrationDescriptor;
1532
1903
 
1533
- export { ASSET_CONTENT_TYPES, type AcceptProposalInput, AssetAnalysis, AssetKind, type AttrType, type AudienceChildren, BRAND_AGENT_PROFILE, BRAND_DISCUSSION_REFERENCE_KINDS, BRAND_INSTRUCTIONS, BRAND_RULES, BRAND_SCHEMA, BookStatus, type BrandActor, type BrandAgentBridge, type BrandAgentProfile, type BrandApprovalReceipt, type BrandAsset, type BrandAttrs, type BrandBook, type BrandBotTriggerOpts, type BrandCapabilityAuthority, BrandConflictError, type BrandDb, type BrandDecisionBinding, type BrandDeps, type BrandDiscussionReference, type BrandDiscussionReferenceKind, type BrandDiscussionReferenceTarget, type BrandDiscussionSwatch, type BrandDispatchBody, type BrandDispatchDeps, type BrandEntityRef, type BrandFetchedBytes, type BrandFileRecord, BrandForbiddenError, BrandGoneError, type BrandHumanAuthorityConsumption, BrandInputError, type BrandIntegrationDescriptor, type BrandIntegrationProbe, type BrandLookup, BrandNotFoundError, type BrandOp, type BrandPalette, type BrandPrincipalProjection, type BrandProposal, type BrandProposalProvenance, type BrandProposalReviewSnapshot, type BrandResult, BrandReviewStateChangedError, type BrandRouteCtx, type BrandRouteOpts, type BrandRow, type BrandRule, type BrandRules, type BrandScalar, type BrandSection, type BrandSkillOpts, type BrandSkillSelf, type BrandSourceAssetSnapshot, type BrandStorage, BrandTokensSnapshot, type BrandToolCtx, type BrandTransactGuard, type BrandTransactOptions, type BrandTrigger, type BrandUploadBody, type BrandVisionCapabilities, type BrandVisionSpec, CHART_DELTA_MIN, CHAT_MESSAGE_NS, CSS_NAMED_COLORS, type ContrastKind, type CreateAssetInput, type CreateBookInput, type CreateBrandIntegrationOptions, type CreateBrandPersonaOpts, DEFAULT_BRAND_SYSTEM, type DeriveChartOptions, type DerivePaletteOptions, type Hsl, type IntegrationProvision, type IntegrationSecret, type IntegrationSetting, type LightnessDirection, MAX_SWATCHES, MAX_VIEW_BYTES, type NamedColor, type NearestNamedColor, type Oklab, type Oklch, PICK_TEXT_DEFAULT_CANDIDATES, PaletteSource, PaletteStatus, ProposalKind, ProposalStatus, type ProposePaletteInput, type ProposeSectionInput, RAMP_L_MAX, RAMP_L_MIN, type RejectProposalInput, type ResolvedBrandDeps, type Rgb, SectionKind, SectionStatus, type SerializedAttr, type SerializedEntity, type SerializedLink, type SerializedLinkEnd, type SerializedSchema, Swatch, type UpsertSectionInput, acceptProposalOps, adjustLightnessUntil, analogous, assertAnalysis, assertAssetContentType, assertHex, assertSectionContent, assertSwatches, assetTools, attachedBrandAssetIds, audienceFanoutOps, base64FromBytes, beginAssetDeleteOps, bookForChannel, bookTools, brandAuthorityRef, brandBotTrigger, brandDiscussionReferenceHref, brandDiscussionReferenceId, brandInputFor, brandIntegration, brandJsonDigest, brandRules, brandSkill, canonicalBrandJson, capString, capStringArray, clamp01, clampToGamut, complementary, contrastRatio, createAssetOps, createBookOps, createBrandIntegration, createBrandPersona, createBrandRoutes, deltaEOK, deltaEOKLab, deriveChartColors, derivePalette, dispatchBrandTurn, finishAssetDeleteOps, formatBrandDiscussionReference, hexToOklch, hslToRgb, inSrgbGamut, isBoundedBrandJson, isBrandHumanAuthorityConsumption, linearToSrgb, meetsAA, meetsAAA, monochrome, nearestNamedColor, normalizeHex, oklabToOklch, oklabToRgb, oklchToHex, oklchToOklab, paletteTools, parseBrandDiscussionReference, parseBrandDispatch, parseHex, pickTextOn, proposalReviewSnapshot, proposePaletteOps, proposeSectionOps, readTools, recordAnalysisOps, rejectProposalOps, relativeLuminance, resolveDeps, rgbToHsl, rgbToOklab, rotateHue, safeFileName, sectionKey, splitComplementary, srgbToLinear, supportsBrandVision, tetradic, tintShadeRamp, toHex, triadic, updateBookOps, upsertSectionOps, verifyBrandApprovalReceipt };
1904
+ export { ASSET_CONTENT_TYPES, type AcceptProposalInput, AssetAnalysis, AssetKind, type AttrType, type AudienceChildren, BRAND_AGENT_PROFILE, BRAND_DISCUSSION_REFERENCE_KINDS, BRAND_INSTRUCTIONS, BRAND_RULES, BRAND_SCHEMA, BookStatus, type BrandActor, type BrandAgentBridge, type BrandAgentProfile, type BrandApprovalReceipt, type BrandAsset, type BrandAttrs, type BrandBook, type BrandBotTriggerOpts, type BrandCapabilityAuthority, BrandConflictError, type BrandDb, type BrandDecisionBinding, type BrandDeps, type BrandDiscussionReference, type BrandDiscussionReferenceKind, type BrandDiscussionReferenceTarget, type BrandDiscussionSwatch, type BrandDispatchBody, type BrandDispatchDeps, type BrandEntityRef, type BrandFetchedBytes, type BrandFileRecord, BrandForbiddenError, BrandGoneError, type BrandHumanAuthorityConsumption, BrandInputError, type BrandIntegrationDescriptor, type BrandIntegrationProbe, type BrandLookup, BrandNotFoundError, type BrandOp, type BrandPalette, type BrandPrincipalProjection, type BrandProposal, type BrandProposalProvenance, type BrandProposalReviewSnapshot, type BrandResult, BrandReviewStateChangedError, type BrandRouteCtx, type BrandRouteOpts, type BrandRow, type BrandRule, type BrandRules, type BrandScalar, type BrandSection, type BrandSkillOpts, type BrandSkillSelf, type BrandSourceAssetSnapshot, type BrandStorage, BrandTokensSnapshot, type BrandToolCtx, type BrandTransactGuard, type BrandTransactOptions, type BrandTrigger, type BrandUploadBody, type BrandVisionCapabilities, type BrandVisionSpec, CHART_DELTA_MIN, CHAT_MESSAGE_NS, CSS_NAMED_COLORS, type ContrastKind, type CreateAssetInput, type CreateBookInput, type CreateBrandIntegrationOptions, type CreateBrandPersonaOpts, DEFAULT_BRAND_SYSTEM, DESIGN_CONTENT_TYPES, type DeriveChartOptions, type DerivePaletteOptions, type DesignAssetGroup, type DesignBundle, type DesignBundleAsset, type DesignColorUse, type DesignDecompilation, type DesignDigest, type DesignManifestEntry, type DesignOutlineEntry, type DesignProp, type DesignTokenSets, type DesignTokenSkip, type Hsl, type IntegrationProvision, type IntegrationSecret, type IntegrationSetting, type LightnessDirection, MAX_COLORS, MAX_EXTERNALS, MAX_FONTS, MAX_HEADING_CHARS, MAX_OUTLINE_ENTRIES, MAX_PROPS, MAX_SWATCHES, MAX_THUMBNAIL_CHARS, MAX_VIEW_BYTES, type NamedColor, type NearestNamedColor, type Oklab, type Oklch, PICK_TEXT_DEFAULT_CANDIDATES, PaletteSource, PaletteStatus, ProposalKind, ProposalStatus, type ProposePaletteInput, type ProposeSectionInput, RAMP_L_MAX, RAMP_L_MIN, type RejectProposalInput, type ResolvedBrandDeps, type Rgb, type ScannedDeclaration, SectionKind, SectionStatus, type SerializedAttr, type SerializedEntity, type SerializedLink, type SerializedLinkEnd, type SerializedSchema, Swatch, SwatchRole, type UpsertSectionInput, acceptProposalOps, adjustLightnessUntil, analogous, assertAnalysis, assertAssetContentType, assertHex, assertSectionContent, assertSwatches, assetTools, attachedBrandAssetIds, audienceFanoutOps, base64ByteLength, base64FromBytes, beginAssetDeleteOps, bookForChannel, bookTools, brandAuthorityRef, brandBotTrigger, brandDiscussionReferenceHref, brandDiscussionReferenceId, brandInputFor, brandIntegration, brandJsonDigest, brandRules, brandSkill, canonicalBrandJson, capString, capStringArray, clamp01, clampToGamut, collapseWhitespace, complementary, contrastRatio, contrastReport, createAssetOps, createBookOps, createBrandIntegration, createBrandPersona, createBrandRoutes, cssColorToHex, decodeEntities, deltaEOK, deltaEOKLab, deriveChartColors, derivePalette, digestDesignBundle, digestDesignHtml, dispatchBrandTurn, extractColors, extractDesignTokens, extractFonts, extractOutline, extractProps, extractThumbnailSvg, extractTitle, finishAssetDeleteOps, formatBrandDiscussionReference, groupAssets, hexToOklch, hslToRgb, htmlToText, inSrgbGamut, isBoundedBrandJson, isBrandHumanAuthorityConsumption, isDesignBundle, linearToSrgb, meetsAA, meetsAAA, monochrome, nearestNamedColor, normalizeHex, oklabToOklch, oklabToRgb, oklchToHex, oklchToOklab, paletteTools, parseBrandDiscussionReference, parseBrandDispatch, parseDesignBundle, parseHex, pickTextOn, proposalAsWritten, proposalReviewSnapshot, proposePaletteOps, proposeSectionOps, readDesignManifest, readTools, receiptAsWritten, recordAnalysisOps, rejectProposalOps, relativeLuminance, resolveDeps, resolveVarRefs, rgbToHsl, rgbToOklab, rotateHue, rowAsWritten, safeFileName, scanCustomProperties, sectionKey, splitComplementary, srgbToLinear, stripCssComments, styleSheetText, supportsBrandVision, swatchesFromDesignTokens, tetradic, tintShadeRamp, toHex, triadic, updateBookOps, upsertSectionOps, verifyBrandApprovalReceipt };