@odla-ai/brand 0.3.0 → 0.5.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.ts 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.js';
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.js';
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.js';
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.js';
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,11 +610,17 @@ 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.
@@ -534,6 +657,15 @@ interface BrandDiscussionReferenceTarget {
534
657
  bookId: string;
535
658
  resourceId?: string;
536
659
  }
660
+ /** Bounded color projection shared with Discussion people and agents. */
661
+ interface BrandDiscussionSwatch {
662
+ /** Semantic role used by the Brand token compiler. */
663
+ role: string;
664
+ /** Normalized opaque sRGB color (`#rrggbb`). */
665
+ hex: string;
666
+ /** Optional product-authored color name. */
667
+ name?: string;
668
+ }
537
669
  /** Product-owned projection returned to Discussion typeahead and exact lookup. */
538
670
  interface BrandDiscussionReference {
539
671
  /** Canonical Brand kind used in stored Discussion ref markup. */
@@ -552,6 +684,8 @@ interface BrandDiscussionReference {
552
684
  destination: string;
553
685
  /** Same-origin native link; navigation is not mutation authority. */
554
686
  href: string;
687
+ /** Present only for a validated Brand palette, capped by Brand's swatch limit. */
688
+ swatches?: BrandDiscussionSwatch[];
555
689
  }
556
690
  /** Durable ref id: a book id, or `bookId/resourceId` for a child resource. */
557
691
  declare function brandDiscussionReferenceId(target: BrandDiscussionReferenceTarget): string;
@@ -730,6 +864,8 @@ interface CreateAssetInput {
730
864
  uploadedAuthorityRef: string;
731
865
  audience: string[];
732
866
  title?: string;
867
+ /** `design` kind only: the digest parsed from the uploaded bundle. */
868
+ design?: DesignDigest;
733
869
  now: number;
734
870
  }
735
871
  /**
@@ -752,6 +888,216 @@ declare function finishAssetDeleteOps(assetId: BrandEntityRef): BrandOp[];
752
888
  */
753
889
  declare function recordAnalysisOps(assetId: BrandEntityRef, analysis: unknown, priorRevision: number, analyzedBy: string, analyzedAuthorityRef: string, now: number): Promise<BrandOp[]>;
754
890
 
891
+ /** Longest poster SVG carried into a digest; larger ones are dropped. */
892
+ declare const MAX_THUMBNAIL_CHARS = 16384;
893
+ /**
894
+ * Cheap structural sniff: does this text look like a Claude Design bundle?
895
+ * Checks for the two islands that carry the design itself, so a plain HTML
896
+ * page (or an unrelated file that happens to be HTML) is rejected before any
897
+ * parsing work happens.
898
+ */
899
+ declare function isDesignBundle(html: string): boolean;
900
+ /** Decoded byte length of a base64 payload, without decoding it. */
901
+ declare function base64ByteLength(data: string): number;
902
+ /**
903
+ * The loader's poster: the `<svg>` inside `#__bundler_thumbnail`. It renders
904
+ * with no JavaScript and no blob URLs, so it is the one part of a design that
905
+ * can be shown anywhere. Returns undefined when absent or over
906
+ * {@link MAX_THUMBNAIL_CHARS}.
907
+ */
908
+ declare function extractThumbnailSvg(html: string): string | undefined;
909
+ /** One manifest entry WITH its base64 payload. */
910
+ interface DesignManifestEntry {
911
+ mime: string;
912
+ compressed: boolean;
913
+ /** Base64 payload, gzipped first when `compressed`. */
914
+ data: string;
915
+ }
916
+ /**
917
+ * Read the manifest island's entries INCLUDING their payloads, keyed by uuid.
918
+ *
919
+ * Everything else in this module deliberately leaves payloads encoded and
920
+ * only measures them, because the worker never needs the bytes. This is the
921
+ * one exception, for callers that genuinely write assets out — the CLI's
922
+ * `brand design unpack`. It holds the whole manifest in memory, so use it
923
+ * only where that is affordable.
924
+ */
925
+ declare function readDesignManifest(html: string): Record<string, DesignManifestEntry>;
926
+ /**
927
+ * Parse a Claude Design standalone-HTML export into its parts: the real
928
+ * document (JSON-decoded from the template island), payload-free manifest
929
+ * summaries, the external-resource index, nested page uuids, and the poster
930
+ * SVG.
931
+ *
932
+ * Throws {@link BrandInputError} when the text is not a bundle or an island
933
+ * is malformed — the messages are safe to return to a caller as a 400.
934
+ */
935
+ declare function parseDesignBundle(html: string): DesignBundle;
936
+
937
+ /** One declaration the scanner found, with the selectors it was nested in. */
938
+ interface ScannedDeclaration {
939
+ /** Outermost → innermost selector/at-rule preludes. */
940
+ selectors: string[];
941
+ /** Property name, including the leading `--`. */
942
+ name: string;
943
+ /** Declaration value, trimmed, with comments already removed. */
944
+ value: string;
945
+ }
946
+ /** Remove `/* … *​/` comments so they cannot break declaration splitting. */
947
+ declare function stripCssComments(css: string): string;
948
+ /**
949
+ * Concatenate every `<style>` element's text in document order. Designs ship
950
+ * their theme as a sequence of style blocks (a vendored base tier, then
951
+ * overrides), and the cascade between them is exactly this order.
952
+ */
953
+ declare function styleSheetText(html: string): string;
954
+ /**
955
+ * Walk `css` and yield every custom-property declaration with its enclosing
956
+ * selector stack, in document order. Brace and paren depth are tracked so
957
+ * nested at-rules (`@media { :root { … } }`) and parenthesised values
958
+ * (`color-mix(in srgb, …)`) are handled correctly.
959
+ *
960
+ * Only `--*` declarations are reported; ordinary properties are skipped.
961
+ */
962
+ declare function scanCustomProperties(css: string): ScannedDeclaration[];
963
+
964
+ /** One token that could not become a swatch, and why. */
965
+ interface DesignTokenSkip {
966
+ token: string;
967
+ value: string;
968
+ reason: string;
969
+ }
970
+ /** What {@link swatchesFromDesignTokens} produced. */
971
+ interface DesignDecompilation {
972
+ swatches: Swatch[];
973
+ /** Tokens present but not literal opaque colours. */
974
+ skipped: DesignTokenSkip[];
975
+ /** Roles the design declared no token for at all. */
976
+ missing: SwatchRole[];
977
+ }
978
+ /** Parse one CSS colour value to `#rrggbb`, or null when it is not a literal
979
+ * opaque colour. Accepts hex and `rgb()`/`rgba()` with alpha exactly 1. */
980
+ declare function cssColorToHex(value: string): string | null;
981
+ /**
982
+ * Read a design's declared `--ui-*` tokens back into brand swatches.
983
+ *
984
+ * Reads the LIGHT set: brand palettes are authored light-first and
985
+ * `deriveDarkTokens` regenerates dark on compile, so importing a design's
986
+ * dark values would be overwritten anyway. The design's dark tokens stay
987
+ * visible in the digest for reference.
988
+ */
989
+ declare function swatchesFromDesignTokens(tokens: DesignTokenSets): DesignDecompilation;
990
+
991
+ /** Most external-resource URLs carried into a digest. */
992
+ declare const MAX_EXTERNALS = 24;
993
+ /** Group manifest assets by MIME type, heaviest group first. */
994
+ declare function groupAssets(bundle: DesignBundle): DesignAssetGroup[];
995
+ /**
996
+ * Build the digest for an already-parsed bundle.
997
+ *
998
+ * `templateBytes` is measured in UTF-8 bytes, not characters, so it matches
999
+ * what the CLI writes to disk for a template full of typographic quotes.
1000
+ */
1001
+ declare function digestDesignBundle(bundle: DesignBundle): DesignDigest;
1002
+ /**
1003
+ * Parse a Claude Design standalone-HTML export and digest it in one step.
1004
+ * Throws {@link import("../errors").BrandInputError} when the file is not a
1005
+ * design bundle.
1006
+ */
1007
+ declare function digestDesignHtml(html: string): DesignDigest;
1008
+
1009
+ /** Decode the named and numeric HTML entities that appear in real markup. */
1010
+ declare function decodeEntities(text: string): string;
1011
+ /** Collapse every run of whitespace to a single space and trim. */
1012
+ declare const collapseWhitespace: (text: string) => string;
1013
+ /**
1014
+ * Strip tags and decode entities, yielding the visible text of a markup
1015
+ * fragment. Script and style element contents are dropped whole — a heading
1016
+ * containing an inline `<style>` would otherwise contribute CSS as prose.
1017
+ */
1018
+ declare function htmlToText(fragment: string): string;
1019
+
1020
+ /** Most headings carried into a digest. */
1021
+ declare const MAX_OUTLINE_ENTRIES = 120;
1022
+ /** Longest single heading kept, in characters. */
1023
+ declare const MAX_HEADING_CHARS = 200;
1024
+ /** The document `<title>`, decoded and collapsed; undefined when unset. */
1025
+ declare function extractTitle(html: string): string | undefined;
1026
+ /**
1027
+ * Headings (`<h1>`…`<h6>`) in document order, as level + visible text.
1028
+ *
1029
+ * Empty headings — icon-only or decorative — are skipped rather than emitted
1030
+ * as blanks. The scan stops at {@link MAX_OUTLINE_ENTRIES}; the caller
1031
+ * reports the truncation in the digest.
1032
+ */
1033
+ declare function extractOutline(html: string): {
1034
+ entries: DesignOutlineEntry[];
1035
+ truncated: boolean;
1036
+ };
1037
+
1038
+ /** Most props carried into a digest. */
1039
+ declare const MAX_PROPS = 60;
1040
+ /**
1041
+ * Extract the design's declared props, in declaration order.
1042
+ *
1043
+ * Returns an empty list — never throws — when the design declares none or
1044
+ * the attribute is unparseable: props are a bonus signal, and a design
1045
+ * without them is still perfectly usable.
1046
+ */
1047
+ declare function extractProps(html: string): {
1048
+ props: DesignProp[];
1049
+ truncated: boolean;
1050
+ };
1051
+
1052
+ /** Most typeface families reported. */
1053
+ declare const MAX_FONTS = 16;
1054
+ /** Most distinct literal colours reported. */
1055
+ declare const MAX_COLORS = 24;
1056
+ /**
1057
+ * The typeface families a design uses: the ones it embeds when it embeds
1058
+ * any, otherwise the quoted families its font stacks name, ranked by how
1059
+ * often they appear.
1060
+ */
1061
+ declare function extractFonts(templateHtml: string): string[];
1062
+ /**
1063
+ * Literal `#rrggbb`/`#rgb` colours in the design's CSS, most-used first.
1064
+ *
1065
+ * Complements the token extractor rather than duplicating it: tokens say
1066
+ * what the design DECLARES as its contract, this says what its stylesheets
1067
+ * actually paint with — including one-off colours never promoted to a token.
1068
+ * Function-syntax colours (`rgba()`, `color-mix()`, `oklch()`) are not
1069
+ * counted; they carry alpha or composition that a flat hex tally would
1070
+ * misrepresent.
1071
+ */
1072
+ declare function extractColors(templateHtml: string): DesignColorUse[];
1073
+
1074
+ /**
1075
+ * Substitute every `var(--name[, fallback])` in `value` using `table`,
1076
+ * recursively. An unresolvable reference falls back to its declared fallback
1077
+ * when it has one, and is otherwise left literal so the caller can see that
1078
+ * the value did not resolve.
1079
+ */
1080
+ declare function resolveVarRefs(value: string, table: ReadonlyMap<string, string>, depth?: number): string;
1081
+ /**
1082
+ * Extract the `--ui-*` tokens a design effectively declares, per theme, with
1083
+ * var() chains resolved to their computed text.
1084
+ *
1085
+ * Declarations are read from document-level selectors only (`:root`, `html`,
1086
+ * `[data-theme=…]`, `.ui-invert`); component-scoped custom properties are
1087
+ * ignored. Dark inherits every light token it does not override, mirroring
1088
+ * how theme sheets are written.
1089
+ */
1090
+ declare function extractDesignTokens(templateHtml: string): DesignTokenSets;
1091
+
1092
+ /**
1093
+ * WCAG contrast ratios (2 dp) for a palette's key role pairs, stored
1094
+ * verbatim in the proposal payload so review is numbers, not vibes.
1095
+ *
1096
+ * Every foreground is measured against the palette's own `bg` (white when
1097
+ * it declares none), plus the readability of text placed on `primary`.
1098
+ */
1099
+ declare function contrastReport(swatches: Swatch[]): Record<string, number>;
1100
+
755
1101
  /** An sRGB color with channels as fractions in [0, 1]. */
756
1102
  interface Rgb {
757
1103
  /** Red channel, 0..1. */
@@ -1116,6 +1462,10 @@ interface BrandToolCtx {
1116
1462
  expectedAnalysisRevision: number;
1117
1463
  }): Promise<BrandAsset>;
1118
1464
  readAssetContent(assetId: string): Promise<BrandFetchedBytes>;
1465
+ /** The decoded template document of a `design` asset. Memoized per skill
1466
+ * instance: a bundle is megabytes, and `read_design_source` is designed to
1467
+ * be called repeatedly while an agent ports markup. */
1468
+ readDesignTemplate(assetId: string): Promise<string>;
1119
1469
  resolvePrincipals(ids: string[]): Promise<BrandPrincipalProjection[]>;
1120
1470
  authority(capability: BrandCapability): Promise<BrandCapabilityAuthority>;
1121
1471
  /** Load the scoped book row; throws BrandNotFoundError when missing. */
@@ -1128,7 +1478,7 @@ interface BrandToolCtx {
1128
1478
  * instruction section. */
1129
1479
  declare const BRAND_INSTRUCTIONS: string;
1130
1480
  /**
1131
- * Build the brand Skill: read/asset/palette/book tools scoped to one book,
1481
+ * Build the brand Skill: read/asset/design/palette/book tools scoped to one book,
1132
1482
  * acting as one bot identity, plus {@link BRAND_INSTRUCTIONS}. Attach it to
1133
1483
  * a Persona (or use `createBrandPersona`).
1134
1484
  */
@@ -1274,6 +1624,15 @@ interface BrandRouteOpts {
1274
1624
  basePath?: string;
1275
1625
  /** Native UI mount used by returned Discussion deep links. Default "/". */
1276
1626
  discussionBasePath?: string;
1627
+ /**
1628
+ * Product-owned fetch used only for a short-lived URL minted from a linked
1629
+ * private Brand asset. Callers never provide this URL or receive it back.
1630
+ */
1631
+ fetchPrivateAsset?: typeof fetch;
1632
+ /** `frame-ancestors` for the design preview response — who may embed a
1633
+ * design. Default `["'self'"]`. Widen only to origins you control: the
1634
+ * preview renders untrusted design HTML. */
1635
+ previewFrameAncestors?: string[];
1277
1636
  /** Upload size cap in bytes (checked against `File.size`). Default 8 MiB. */
1278
1637
  maxUploadBytes?: number;
1279
1638
  /** Serve `GET /books/:id/tokens.css` and `tokens.json` without authorize —
@@ -1296,6 +1655,8 @@ interface BrandRouteCtx {
1296
1655
  newId: () => string;
1297
1656
  maxUploadBytes: number;
1298
1657
  discussionBasePath: string;
1658
+ fetchPrivateAsset: typeof fetch;
1659
+ previewFrameAncestors: string[];
1299
1660
  }
1300
1661
 
1301
1662
  /** Freeze the exact OPEN proposal fields a reviewer sees. */
@@ -1513,4 +1874,4 @@ interface CreateBrandIntegrationOptions {
1513
1874
  */
1514
1875
  declare function createBrandIntegration(options?: CreateBrandIntegrationOptions): BrandIntegrationDescriptor;
1515
1876
 
1516
- 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 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 };
1877
+ 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, proposalReviewSnapshot, proposePaletteOps, proposeSectionOps, readDesignManifest, readTools, recordAnalysisOps, rejectProposalOps, relativeLuminance, resolveDeps, resolveVarRefs, rgbToHsl, rgbToOklab, rotateHue, safeFileName, scanCustomProperties, sectionKey, splitComplementary, srgbToLinear, stripCssComments, styleSheetText, supportsBrandVision, swatchesFromDesignTokens, tetradic, tintShadeRamp, toHex, triadic, updateBookOps, upsertSectionOps, verifyBrandApprovalReceipt };