@odla-ai/brand 0.7.2 → 0.8.1
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.cjs +136 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -1
- package/dist/index.d.ts +13 -1
- package/dist/index.js +138 -20
- package/dist/index.js.map +1 -1
- package/package.json +4 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
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-r6SGidYT.cjs';
|
|
2
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-r6SGidYT.cjs';
|
|
3
3
|
import { ToolHandler, Skill, ToolDef, Persona, Inference, AgentRunInput, ImageBlock, OracleContentBlock } from '@odla-ai/ai';
|
|
4
|
+
import { PromotionAdapterResult } from '@odla-ai/promotion';
|
|
4
5
|
|
|
5
6
|
/** One entry of the bundle's base64 asset manifest, without its payload. */
|
|
6
7
|
interface DesignBundleAsset {
|
|
@@ -1901,4 +1902,15 @@ interface CreateBrandIntegrationOptions {
|
|
|
1901
1902
|
*/
|
|
1902
1903
|
declare function createBrandIntegration(options?: CreateBrandIntegrationOptions): BrandIntegrationDescriptor;
|
|
1903
1904
|
|
|
1904
|
-
|
|
1905
|
+
/** Stable adapter identity bound into Brand artifact provenance. */
|
|
1906
|
+
declare const BRAND_PROMOTION_ADAPTER = "@odla-ai/brand/v1";
|
|
1907
|
+
/** Approved Brand rows required to export one bounded promotion selection. */
|
|
1908
|
+
interface BrandPromotionInput {
|
|
1909
|
+
book: BrandBook;
|
|
1910
|
+
sections: readonly BrandSection[];
|
|
1911
|
+
palettes: readonly BrandPalette[];
|
|
1912
|
+
}
|
|
1913
|
+
/** Export only human-approved, provider-independent Brand state. */
|
|
1914
|
+
declare function exportBrandPromotion(input: BrandPromotionInput): PromotionAdapterResult;
|
|
1915
|
+
|
|
1916
|
+
export { ASSET_CONTENT_TYPES, type AcceptProposalInput, AssetAnalysis, AssetKind, type AttrType, type AudienceChildren, BRAND_AGENT_PROFILE, BRAND_DISCUSSION_REFERENCE_KINDS, BRAND_INSTRUCTIONS, BRAND_PROMOTION_ADAPTER, 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 BrandPromotionInput, 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, exportBrandPromotion, 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 };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
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-r6SGidYT.js';
|
|
2
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-r6SGidYT.js';
|
|
3
3
|
import { ToolHandler, Skill, ToolDef, Persona, Inference, AgentRunInput, ImageBlock, OracleContentBlock } from '@odla-ai/ai';
|
|
4
|
+
import { PromotionAdapterResult } from '@odla-ai/promotion';
|
|
4
5
|
|
|
5
6
|
/** One entry of the bundle's base64 asset manifest, without its payload. */
|
|
6
7
|
interface DesignBundleAsset {
|
|
@@ -1901,4 +1902,15 @@ interface CreateBrandIntegrationOptions {
|
|
|
1901
1902
|
*/
|
|
1902
1903
|
declare function createBrandIntegration(options?: CreateBrandIntegrationOptions): BrandIntegrationDescriptor;
|
|
1903
1904
|
|
|
1904
|
-
|
|
1905
|
+
/** Stable adapter identity bound into Brand artifact provenance. */
|
|
1906
|
+
declare const BRAND_PROMOTION_ADAPTER = "@odla-ai/brand/v1";
|
|
1907
|
+
/** Approved Brand rows required to export one bounded promotion selection. */
|
|
1908
|
+
interface BrandPromotionInput {
|
|
1909
|
+
book: BrandBook;
|
|
1910
|
+
sections: readonly BrandSection[];
|
|
1911
|
+
palettes: readonly BrandPalette[];
|
|
1912
|
+
}
|
|
1913
|
+
/** Export only human-approved, provider-independent Brand state. */
|
|
1914
|
+
declare function exportBrandPromotion(input: BrandPromotionInput): PromotionAdapterResult;
|
|
1915
|
+
|
|
1916
|
+
export { ASSET_CONTENT_TYPES, type AcceptProposalInput, AssetAnalysis, AssetKind, type AttrType, type AudienceChildren, BRAND_AGENT_PROFILE, BRAND_DISCUSSION_REFERENCE_KINDS, BRAND_INSTRUCTIONS, BRAND_PROMOTION_ADAPTER, 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 BrandPromotionInput, 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, exportBrandPromotion, 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 };
|
package/dist/index.js
CHANGED
|
@@ -708,14 +708,14 @@ var SNAPSHOT_REQUIRED = [
|
|
|
708
708
|
];
|
|
709
709
|
function validSnapshotShape(value) {
|
|
710
710
|
if (!record3(value) || !exactKeys(value, SNAPSHOT_REQUIRED)) return false;
|
|
711
|
-
const
|
|
712
|
-
return boundedString(value.id) && boundedString(value.bookId) && typeof value.kind === "string" && PROPOSAL_KINDS.includes(value.kind) && value.status === "open" && record3(value.payload) && boundedString(value.rationale, 2e3) && record3(
|
|
711
|
+
const provenance2 = value.provenance;
|
|
712
|
+
return boundedString(value.id) && boundedString(value.bookId) && typeof value.kind === "string" && PROPOSAL_KINDS.includes(value.kind) && value.status === "open" && record3(value.payload) && boundedString(value.rationale, 2e3) && record3(provenance2) && exactKeys(provenance2, [
|
|
713
713
|
"sourceAssetId",
|
|
714
714
|
"sourceAsset",
|
|
715
715
|
"messageId",
|
|
716
716
|
"turnId",
|
|
717
717
|
"taintLabels"
|
|
718
|
-
]) && (
|
|
718
|
+
]) && (provenance2.sourceAssetId === null || boundedString(provenance2.sourceAssetId)) && (provenance2.sourceAsset === null || record3(provenance2.sourceAsset) && exactKeys(provenance2.sourceAsset, [
|
|
719
719
|
"assetId",
|
|
720
720
|
"contentDigest",
|
|
721
721
|
"objectEtag",
|
|
@@ -724,7 +724,7 @@ function validSnapshotShape(value) {
|
|
|
724
724
|
"contentType",
|
|
725
725
|
"analysisRevision",
|
|
726
726
|
"analysisDigest"
|
|
727
|
-
]) && boundedString(
|
|
727
|
+
]) && boundedString(provenance2.sourceAsset.assetId) && typeof provenance2.sourceAsset.contentDigest === "string" && DIGEST.test(provenance2.sourceAsset.contentDigest) && boundedString(provenance2.sourceAsset.objectEtag) && Number.isSafeInteger(provenance2.sourceAsset.objectSize) && provenance2.sourceAsset.objectSize > 0 && typeof provenance2.sourceAsset.pathDigest === "string" && DIGEST.test(provenance2.sourceAsset.pathDigest) && (provenance2.sourceAsset.contentType === null || boundedString(provenance2.sourceAsset.contentType, 160)) && (provenance2.sourceAsset.analysisRevision === null || Number.isSafeInteger(provenance2.sourceAsset.analysisRevision) && provenance2.sourceAsset.analysisRevision >= 0) && (provenance2.sourceAsset.analysisDigest === null || typeof provenance2.sourceAsset.analysisDigest === "string" && DIGEST.test(provenance2.sourceAsset.analysisDigest))) && (provenance2.sourceAssetId === null && provenance2.sourceAsset === null || provenance2.sourceAssetId !== null && provenance2.sourceAsset !== null && provenance2.sourceAsset.assetId === provenance2.sourceAssetId) && (provenance2.messageId === null || boundedString(provenance2.messageId)) && (provenance2.turnId === null || boundedString(provenance2.turnId)) && Array.isArray(provenance2.taintLabels) && provenance2.taintLabels.length <= 16 && provenance2.taintLabels.every((label) => boundedString(label, 120)) && new Set(provenance2.taintLabels).size === provenance2.taintLabels.length && typeof value.reviewDigest === "string" && DIGEST.test(value.reviewDigest) && Array.isArray(value.audience) && value.audience.length > 0 && value.audience.length <= 100 && value.audience.every((id) => boundedString(id)) && new Set(value.audience).size === value.audience.length && boundedString(value.createdBy) && boundedString(value.createdAuthorityRef) && safeTime(value.createdAt);
|
|
728
728
|
}
|
|
729
729
|
var CONSUMPTION_REQUIRED = [
|
|
730
730
|
"id",
|
|
@@ -1794,6 +1794,13 @@ function contrastReport(swatches) {
|
|
|
1794
1794
|
return report;
|
|
1795
1795
|
}
|
|
1796
1796
|
|
|
1797
|
+
// src/link-shape.ts
|
|
1798
|
+
function hasExactOneLink(value, expectedId) {
|
|
1799
|
+
if (Array.isArray(value))
|
|
1800
|
+
return value.length === 1 && value[0]?.id === expectedId;
|
|
1801
|
+
return typeof value === "object" && value !== null && value.id === expectedId;
|
|
1802
|
+
}
|
|
1803
|
+
|
|
1797
1804
|
// src/skill/asset-tools.ts
|
|
1798
1805
|
var MAX_VIEW_BYTES = 4718592;
|
|
1799
1806
|
var IMAGE_TYPES = /* @__PURE__ */ new Set(["image/png", "image/jpeg", "image/gif", "image/webp"]);
|
|
@@ -1836,7 +1843,7 @@ function assetTools(ctx) {
|
|
|
1836
1843
|
}
|
|
1837
1844
|
});
|
|
1838
1845
|
const row = (res[BRAND_NS.asset] ?? [])[0];
|
|
1839
|
-
if (!row || row.status !== "live" || row.deletedAt || !
|
|
1846
|
+
if (!row || row.status !== "live" || row.deletedAt || !hasExactOneLink(row.book, book.id)) throw new BrandNotFoundError(`asset ${assetId}`);
|
|
1840
1847
|
return row;
|
|
1841
1848
|
};
|
|
1842
1849
|
const viewAsset = {
|
|
@@ -1924,7 +1931,7 @@ async function proposalSourceAssetId(ctx, book, value) {
|
|
|
1924
1931
|
});
|
|
1925
1932
|
const rows = result[BRAND_NS.asset] ?? [];
|
|
1926
1933
|
const asset = rows.length === 1 ? rows[0] : void 0;
|
|
1927
|
-
if (!asset || asset.id !== sourceAssetId || asset.bookId !== book.id || asset.status !== "live" || asset.deletedAt !== void 0 || !
|
|
1934
|
+
if (!asset || asset.id !== sourceAssetId || asset.bookId !== book.id || asset.status !== "live" || asset.deletedAt !== void 0 || !hasExactOneLink(asset.book, book.id)) throw new BrandInputError(
|
|
1928
1935
|
"sourceAssetId must be a live asset in this brand book"
|
|
1929
1936
|
);
|
|
1930
1937
|
return sourceAssetId;
|
|
@@ -2366,7 +2373,7 @@ function readTools(ctx) {
|
|
|
2366
2373
|
book: {}
|
|
2367
2374
|
}
|
|
2368
2375
|
});
|
|
2369
|
-
const linked = (rows) => rows.filter((row) => row.bookId === authorizedBook.id &&
|
|
2376
|
+
const linked = (rows) => rows.filter((row) => row.bookId === authorizedBook.id && hasExactOneLink(row.book, authorizedBook.id));
|
|
2370
2377
|
const sections = linked(
|
|
2371
2378
|
res[BRAND_NS.section] ?? []
|
|
2372
2379
|
);
|
|
@@ -2416,7 +2423,7 @@ function readTools(ctx) {
|
|
|
2416
2423
|
book: {}
|
|
2417
2424
|
}
|
|
2418
2425
|
});
|
|
2419
|
-
const rows = (res[BRAND_NS.asset] ?? []).filter((asset) => asset.bookId === ctx.bookId &&
|
|
2426
|
+
const rows = (res[BRAND_NS.asset] ?? []).filter((asset) => asset.bookId === ctx.bookId && hasExactOneLink(asset.book, ctx.bookId));
|
|
2420
2427
|
if (rows.length === 0) {
|
|
2421
2428
|
return { content: input.kind ? `(no ${String(input.kind)} assets uploaded yet)` : "(no assets uploaded yet)" };
|
|
2422
2429
|
}
|
|
@@ -2545,7 +2552,7 @@ async function linkedAsset(ctx, book, assetId, allowDeleting = false) {
|
|
|
2545
2552
|
});
|
|
2546
2553
|
const row = rowAsWritten(BRAND_NS.asset, (result[BRAND_NS.asset] ?? [])[0]);
|
|
2547
2554
|
const links = row?.book;
|
|
2548
|
-
if (!row || row.bookId !== book.id || !
|
|
2555
|
+
if (!row || row.bookId !== book.id || !hasExactOneLink(links, book.id) || row.status !== "live" && !(allowDeleting && row.status === "deleting")) throw new BrandNotFoundError(`asset ${assetId}`);
|
|
2549
2556
|
return row;
|
|
2550
2557
|
}
|
|
2551
2558
|
|
|
@@ -2748,7 +2755,7 @@ async function handleAssetsRoot(ctx, req, bookId) {
|
|
|
2748
2755
|
});
|
|
2749
2756
|
const assets = (result[BRAND_NS.asset] ?? []).filter((value) => {
|
|
2750
2757
|
const row = value;
|
|
2751
|
-
return row.bookId === book.id &&
|
|
2758
|
+
return row.bookId === book.id && hasExactOneLink(row.book, book.id);
|
|
2752
2759
|
});
|
|
2753
2760
|
return json({ assets });
|
|
2754
2761
|
}
|
|
@@ -3234,7 +3241,7 @@ async function proposalReceiptByMutation(ctx, mutationKey) {
|
|
|
3234
3241
|
}
|
|
3235
3242
|
});
|
|
3236
3243
|
const row = (result[BRAND_NS.approvalReceipt] ?? [])[0];
|
|
3237
|
-
if (!row || !
|
|
3244
|
+
if (!row || !hasExactOneLink(row.book, row.bookId)) return void 0;
|
|
3238
3245
|
const { book: _book, ...receipt2 } = row;
|
|
3239
3246
|
return receiptAsWritten(receipt2);
|
|
3240
3247
|
}
|
|
@@ -3269,7 +3276,7 @@ async function receipt(ctx, id, actionDigest, expected) {
|
|
|
3269
3276
|
}
|
|
3270
3277
|
});
|
|
3271
3278
|
const row = (result[BRAND_NS.approvalReceipt] ?? [])[0];
|
|
3272
|
-
if (!row || row.actionDigest !== actionDigest || row.resolution !== "accepted" || row.bookId !== expected.bookId || row.reviewedProposal.bookId !== expected.bookId || row.reviewedProposal.kind !== expected.kind || !
|
|
3279
|
+
if (!row || row.actionDigest !== actionDigest || row.resolution !== "accepted" || row.bookId !== expected.bookId || row.reviewedProposal.bookId !== expected.bookId || row.reviewedProposal.kind !== expected.kind || !hasExactOneLink(row.book, expected.bookId) || expected.paletteId !== void 0 && row.paletteId !== expected.paletteId || expected.proposalId !== void 0 && row.proposalId !== expected.proposalId || expected.content !== void 0 && canonicalBrandJson(row.reviewedProposal.payload.content) !== canonicalBrandJson(expected.content)) throw new BrandConflictError(`approval receipt ${id} is invalid`);
|
|
3273
3280
|
const { book: _book, ...stored } = row;
|
|
3274
3281
|
const unhydrated = receiptAsWritten(stored);
|
|
3275
3282
|
if (!await verifyBrandApprovalReceipt(unhydrated))
|
|
@@ -3285,7 +3292,7 @@ async function activePalette(ctx, book) {
|
|
|
3285
3292
|
}
|
|
3286
3293
|
});
|
|
3287
3294
|
const palette = (result[BRAND_NS.palette] ?? [])[0];
|
|
3288
|
-
if (!palette || palette.bookId !== book.id || palette.status !== "active" || !palette.proposalId || !palette.approvalReceiptId || !palette.approvalActionDigest || !
|
|
3295
|
+
if (!palette || palette.bookId !== book.id || palette.status !== "active" || !palette.proposalId || !palette.approvalReceiptId || !palette.approvalActionDigest || !hasExactOneLink(palette.book, book.id)) throw new BrandConflictError(
|
|
3289
3296
|
"active palette is missing valid approval provenance"
|
|
3290
3297
|
);
|
|
3291
3298
|
const approval = await receipt(
|
|
@@ -3334,7 +3341,7 @@ async function approvedTypography(ctx, book) {
|
|
|
3334
3341
|
});
|
|
3335
3342
|
const section = (result[BRAND_NS.section] ?? [])[0];
|
|
3336
3343
|
if (!section || section.status !== "approved") return {};
|
|
3337
|
-
if (section.bookId !== book.id || section.kind !== "typography" || !section.approvalReceiptId || !section.approvalActionDigest || !
|
|
3344
|
+
if (section.bookId !== book.id || section.kind !== "typography" || !section.approvalReceiptId || !section.approvalActionDigest || !hasExactOneLink(section.book, book.id)) throw new BrandConflictError(
|
|
3338
3345
|
"approved typography is missing valid approval provenance"
|
|
3339
3346
|
);
|
|
3340
3347
|
assertSectionContent("typography", section.content);
|
|
@@ -3375,7 +3382,7 @@ async function proposalDecisionState(ctx, req, book, proposal, resolution, recei
|
|
|
3375
3382
|
}
|
|
3376
3383
|
});
|
|
3377
3384
|
sourceAsset = (result[BRAND_NS.asset] ?? [])[0];
|
|
3378
|
-
if (!sourceAsset || sourceAsset.id !== source.assetId || sourceAsset.bookId !== book.id || sourceAsset.status !== "live" || sourceAsset.deletedAt !== void 0 || sourceAsset.contentDigest !== source.contentDigest || sourceAsset.size !== source.objectSize || sourceAsset.contentType !== source.contentType || await brandJsonDigest({ appId: ctx.appId, path: sourceAsset.path }) !== source.pathDigest || sourceAsset.analysisRevision !== source.analysisRevision || (sourceAsset.analysisDigest ?? null) !== source.analysisDigest || !
|
|
3385
|
+
if (!sourceAsset || sourceAsset.id !== source.assetId || sourceAsset.bookId !== book.id || sourceAsset.status !== "live" || sourceAsset.deletedAt !== void 0 || sourceAsset.contentDigest !== source.contentDigest || sourceAsset.size !== source.objectSize || sourceAsset.contentType !== source.contentType || await brandJsonDigest({ appId: ctx.appId, path: sourceAsset.path }) !== source.pathDigest || sourceAsset.analysisRevision !== source.analysisRevision || (sourceAsset.analysisDigest ?? null) !== source.analysisDigest || !hasExactOneLink(sourceAsset.book, book.id)) throw new BrandConflictError(
|
|
3379
3386
|
"source asset changed since the proposal was reviewed"
|
|
3380
3387
|
);
|
|
3381
3388
|
if (!await ctx.verifySourceAssetSnapshot({
|
|
@@ -3559,7 +3566,7 @@ async function handleProposalResolution(ctx, req, bookId, proposalId) {
|
|
|
3559
3566
|
}
|
|
3560
3567
|
});
|
|
3561
3568
|
const proposal = proposalAsWritten((result[BRAND_NS.proposal] ?? [])[0]);
|
|
3562
|
-
if (!proposal || proposal.bookId !== book.id || !
|
|
3569
|
+
if (!proposal || proposal.bookId !== book.id || !hasExactOneLink(proposal.book, book.id)) throw new BrandNotFoundError(`proposal ${proposalId}`);
|
|
3563
3570
|
const current = proposalReviewSnapshot(proposal);
|
|
3564
3571
|
const { reviewDigest, ...unsignedReview } = current;
|
|
3565
3572
|
if (await brandJsonDigest(unsignedReview) !== reviewDigest || canonicalBrandJson(current) !== canonicalBrandJson(reviewed)) throw new BrandConflictError("proposal changed since review");
|
|
@@ -3703,7 +3710,7 @@ async function acceptedReceipt(db, bookId, receiptId, actionDigest) {
|
|
|
3703
3710
|
}
|
|
3704
3711
|
});
|
|
3705
3712
|
const receipt2 = (result[BRAND_NS.approvalReceipt] ?? [])[0];
|
|
3706
|
-
if (!receipt2 || receipt2.resolution !== "accepted" || receipt2.actionDigest !== actionDigest || !
|
|
3713
|
+
if (!receipt2 || receipt2.resolution !== "accepted" || receipt2.actionDigest !== actionDigest || !hasExactOneLink(receipt2.book, bookId)) return missing(bookId);
|
|
3707
3714
|
const { book: _book, ...stored } = receipt2;
|
|
3708
3715
|
const unhydrated = receiptAsWritten(stored);
|
|
3709
3716
|
if (!await verifyBrandApprovalReceipt(unhydrated)) return missing(bookId);
|
|
@@ -3719,7 +3726,7 @@ async function approvedCache(db, book) {
|
|
|
3719
3726
|
}
|
|
3720
3727
|
});
|
|
3721
3728
|
const palette = (paletteResult[BRAND_NS.palette] ?? [])[0];
|
|
3722
|
-
if (!palette || palette.status !== "active" || palette.approvalReceiptId !== cache.paletteReceiptId || palette.approvalActionDigest !== cache.paletteActionDigest || !
|
|
3729
|
+
if (!palette || palette.status !== "active" || palette.approvalReceiptId !== cache.paletteReceiptId || palette.approvalActionDigest !== cache.paletteActionDigest || !hasExactOneLink(palette.book, book.id)) return missing(book.id);
|
|
3723
3730
|
await acceptedReceipt(
|
|
3724
3731
|
db,
|
|
3725
3732
|
book.id,
|
|
@@ -3737,7 +3744,7 @@ async function approvedCache(db, book) {
|
|
|
3737
3744
|
});
|
|
3738
3745
|
const typography = (sectionResult[BRAND_NS.section] ?? [])[0];
|
|
3739
3746
|
if (hasTypeId) {
|
|
3740
|
-
if (!typography || typography.bookId !== book.id || typography.kind !== "typography" || typography.status !== "approved" || typography.approvalReceiptId !== cache.typographyReceiptId || typography.approvalActionDigest !== cache.typographyActionDigest || !
|
|
3747
|
+
if (!typography || typography.bookId !== book.id || typography.kind !== "typography" || typography.status !== "approved" || typography.approvalReceiptId !== cache.typographyReceiptId || typography.approvalActionDigest !== cache.typographyActionDigest || !hasExactOneLink(typography.book, book.id)) return missing(book.id);
|
|
3741
3748
|
await acceptedReceipt(
|
|
3742
3749
|
db,
|
|
3743
3750
|
book.id,
|
|
@@ -4142,7 +4149,7 @@ async function attachedBrandAssetIds(db, book, row) {
|
|
|
4142
4149
|
const rows = result[BRAND_NS.asset] ?? [];
|
|
4143
4150
|
if (rows.length !== 1) return null;
|
|
4144
4151
|
const asset = rows[0];
|
|
4145
|
-
return asset.id === id && asset.bookId === book.id && asset.status === "live" && asset.deletedAt === void 0 &&
|
|
4152
|
+
return asset.id === id && asset.bookId === book.id && asset.status === "live" && asset.deletedAt === void 0 && hasExactOneLink(asset.book, book.id) ? id : null;
|
|
4146
4153
|
}));
|
|
4147
4154
|
return assets.filter((id) => id !== null);
|
|
4148
4155
|
}
|
|
@@ -4365,6 +4372,115 @@ function createBrandIntegration(options = {}) {
|
|
|
4365
4372
|
probes: [{ path: `${basePath}/books`, expectedStatus: 401 }]
|
|
4366
4373
|
};
|
|
4367
4374
|
}
|
|
4375
|
+
|
|
4376
|
+
// src/promotion.ts
|
|
4377
|
+
import {
|
|
4378
|
+
canonicalPromotionValue
|
|
4379
|
+
} from "@odla-ai/promotion";
|
|
4380
|
+
var BRAND_PROMOTION_ADAPTER = "@odla-ai/brand/v1";
|
|
4381
|
+
var provenance = (sourceIds, receiptDigests = []) => ({
|
|
4382
|
+
adapter: BRAND_PROMOTION_ADAPTER,
|
|
4383
|
+
sourceIds: [...sourceIds].sort(),
|
|
4384
|
+
receiptDigests: [...receiptDigests].sort()
|
|
4385
|
+
});
|
|
4386
|
+
var exclusions = (book) => [
|
|
4387
|
+
{
|
|
4388
|
+
kind: "brand.runtime",
|
|
4389
|
+
id: book.slug,
|
|
4390
|
+
reason: "environment_local",
|
|
4391
|
+
paths: [`${BRAND_NS.book}.ownerId`, `${BRAND_NS.book}.memberIds`, `${BRAND_NS.book}.channelId`, `${BRAND_NS.book}.*At`],
|
|
4392
|
+
detail: "Ownership, roster, channel, and timestamps remain local to the target environment."
|
|
4393
|
+
},
|
|
4394
|
+
{
|
|
4395
|
+
kind: "brand.drafts",
|
|
4396
|
+
id: book.slug,
|
|
4397
|
+
reason: "draft_state",
|
|
4398
|
+
paths: [`${BRAND_NS.proposal}.*`, `${BRAND_NS.section}[status=draft]`],
|
|
4399
|
+
detail: "Open proposals and unapproved sections are review state, not published brand content."
|
|
4400
|
+
},
|
|
4401
|
+
{
|
|
4402
|
+
kind: "brand.assets",
|
|
4403
|
+
id: book.slug,
|
|
4404
|
+
reason: "provider_identity",
|
|
4405
|
+
paths: [`${BRAND_NS.asset}.storageObjectId`, `${BRAND_NS.asset}.path`, `${BRAND_NS.asset}.*AuthorityRef`],
|
|
4406
|
+
detail: "Stored files and provider object identities require a separate asset-transfer contract."
|
|
4407
|
+
},
|
|
4408
|
+
{
|
|
4409
|
+
kind: "brand.authority",
|
|
4410
|
+
id: book.slug,
|
|
4411
|
+
reason: "authority_history",
|
|
4412
|
+
paths: [`${BRAND_NS.approvalReceipt}.*`, `${BRAND_NS.palette}.audience`],
|
|
4413
|
+
detail: "Authority rows stay immutable in their source environment; artifacts retain only receipt digests and ids."
|
|
4414
|
+
}
|
|
4415
|
+
];
|
|
4416
|
+
function exportBrandPromotion(input) {
|
|
4417
|
+
const { book } = input;
|
|
4418
|
+
if (book.status !== "active") throw new TypeError(`brand book ${book.slug} is not active`);
|
|
4419
|
+
const revision = `brand:${book.slug}:${book.activationRevision}`;
|
|
4420
|
+
const artifacts = [];
|
|
4421
|
+
if (book.tokens) {
|
|
4422
|
+
const {
|
|
4423
|
+
compiledAt: _compiledAt,
|
|
4424
|
+
paletteReceiptId,
|
|
4425
|
+
paletteActionDigest,
|
|
4426
|
+
typographyReceiptId,
|
|
4427
|
+
typographyActionDigest,
|
|
4428
|
+
sourceDigest,
|
|
4429
|
+
...stableTokens
|
|
4430
|
+
} = book.tokens;
|
|
4431
|
+
artifacts.push({
|
|
4432
|
+
kind: "brand.tokens",
|
|
4433
|
+
id: book.slug,
|
|
4434
|
+
sourceRevision: revision,
|
|
4435
|
+
provenance: provenance(
|
|
4436
|
+
[book.id, book.tokens.paletteId, paletteReceiptId, typographyReceiptId].filter((value) => Boolean(value)),
|
|
4437
|
+
[sourceDigest, paletteActionDigest, typographyActionDigest].filter((value) => Boolean(value))
|
|
4438
|
+
),
|
|
4439
|
+
content: canonicalPromotionValue({ bookSlug: book.slug, tokens: stableTokens })
|
|
4440
|
+
});
|
|
4441
|
+
}
|
|
4442
|
+
for (const section of input.sections.filter((row) => row.bookId === book.id && row.status === "approved")) {
|
|
4443
|
+
if (!section.approvalReceiptId || !section.approvalActionDigest) {
|
|
4444
|
+
throw new TypeError(`approved brand section ${section.key} lacks approval provenance`);
|
|
4445
|
+
}
|
|
4446
|
+
artifacts.push({
|
|
4447
|
+
kind: "brand.section",
|
|
4448
|
+
id: `${book.slug}/${section.kind}`,
|
|
4449
|
+
sourceRevision: revision,
|
|
4450
|
+
provenance: provenance([book.id, section.id, section.approvalReceiptId], [section.approvalActionDigest]),
|
|
4451
|
+
content: canonicalPromotionValue({ bookSlug: book.slug, kind: section.kind, content: section.content })
|
|
4452
|
+
});
|
|
4453
|
+
}
|
|
4454
|
+
const activePalette2 = input.palettes.find((row) => row.bookId === book.id && row.id === book.activePaletteId && row.status === "active");
|
|
4455
|
+
if (book.activePaletteId && !activePalette2) throw new TypeError(`active palette ${book.activePaletteId} is unavailable`);
|
|
4456
|
+
if (activePalette2) {
|
|
4457
|
+
artifacts.push({
|
|
4458
|
+
kind: "brand.palette",
|
|
4459
|
+
id: `${book.slug}/${activePalette2.id}`,
|
|
4460
|
+
sourceRevision: revision,
|
|
4461
|
+
provenance: provenance([book.id, activePalette2.id, activePalette2.proposalId, activePalette2.approvalReceiptId], [activePalette2.approvalActionDigest]),
|
|
4462
|
+
content: canonicalPromotionValue({
|
|
4463
|
+
bookSlug: book.slug,
|
|
4464
|
+
name: activePalette2.name,
|
|
4465
|
+
swatches: activePalette2.swatches,
|
|
4466
|
+
source: activePalette2.source,
|
|
4467
|
+
...activePalette2.seedHex ? { seedHex: activePalette2.seedHex } : {},
|
|
4468
|
+
...activePalette2.rationale ? { rationale: activePalette2.rationale } : {}
|
|
4469
|
+
})
|
|
4470
|
+
});
|
|
4471
|
+
}
|
|
4472
|
+
return {
|
|
4473
|
+
adapter: BRAND_PROMOTION_ADAPTER,
|
|
4474
|
+
artifacts,
|
|
4475
|
+
exclusions: exclusions(book),
|
|
4476
|
+
preconditions: [{
|
|
4477
|
+
code: "brand.schema",
|
|
4478
|
+
path: "services.brand.schemaVersion",
|
|
4479
|
+
expected: 1,
|
|
4480
|
+
detail: "The target must expose the Brand v1 approved-content schema."
|
|
4481
|
+
}]
|
|
4482
|
+
};
|
|
4483
|
+
}
|
|
4368
4484
|
export {
|
|
4369
4485
|
ASSET_CONTENT_TYPES,
|
|
4370
4486
|
ASSET_KINDS,
|
|
@@ -4377,6 +4493,7 @@ export {
|
|
|
4377
4493
|
BRAND_EMITTED_TOKENS,
|
|
4378
4494
|
BRAND_INSTRUCTIONS,
|
|
4379
4495
|
BRAND_NS,
|
|
4496
|
+
BRAND_PROMOTION_ADAPTER,
|
|
4380
4497
|
BRAND_REQUIRED_TOKENS,
|
|
4381
4498
|
BRAND_RULES,
|
|
4382
4499
|
BRAND_SCHEMA,
|
|
@@ -4465,6 +4582,7 @@ export {
|
|
|
4465
4582
|
digestDesignBundle,
|
|
4466
4583
|
digestDesignHtml,
|
|
4467
4584
|
dispatchBrandTurn,
|
|
4585
|
+
exportBrandPromotion,
|
|
4468
4586
|
extractColors,
|
|
4469
4587
|
extractDesignTokens,
|
|
4470
4588
|
extractFonts,
|