@odla-ai/brand 0.8.4 → 0.8.5

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.js CHANGED
@@ -61,6 +61,7 @@ var BRAND_NS = {
61
61
  palette: "brand_palette",
62
62
  proposal: "brand_proposal",
63
63
  approvalReceipt: "brand_approval_receipt",
64
+ activationReceipt: "brand_activation_receipt",
64
65
  asset: "brand_asset"
65
66
  };
66
67
  var BOOK_STATUSES = ["draft", "active", "archived"];
@@ -185,6 +186,8 @@ var BRAND_SCHEMA = {
185
186
  activationRevision: a("number"),
186
187
  tokens: opt("json"),
187
188
  // maps + complete palette/typography receipt provenance
189
+ activationReceiptId: opt("string"),
190
+ activationActionDigest: opt("string"),
188
191
  summary: opt("string"),
189
192
  createdAt: idx("date"),
190
193
  updatedAt: idx("date")
@@ -279,6 +282,23 @@ var BRAND_SCHEMA = {
279
282
  receiptDigest: idx("string")
280
283
  }
281
284
  },
285
+ [BRAND_NS.activationReceipt]: {
286
+ attrs: {
287
+ id: uniq("string"),
288
+ version: a("number"),
289
+ mutationKey: uniq("string"),
290
+ bookId: idx("string"),
291
+ reviewedBook: a("json"),
292
+ actionDigest: idx("string"),
293
+ approvedBy: idx("string"),
294
+ approvedByKind: a("string"),
295
+ authorityRef: idx("string"),
296
+ authorityCapability: a("string"),
297
+ authorityConsumption: a("json"),
298
+ createdAt: idx("date"),
299
+ receiptDigest: idx("string")
300
+ }
301
+ },
282
302
  [BRAND_NS.asset]: {
283
303
  attrs: {
284
304
  id: uniq("string"),
@@ -333,6 +353,10 @@ var BRAND_SCHEMA = {
333
353
  forward: { on: BRAND_NS.approvalReceipt, has: "one", label: "book" },
334
354
  reverse: { on: BRAND_NS.book, has: "many", label: "approvalReceipts" }
335
355
  },
356
+ brandActivationReceiptBook: {
357
+ forward: { on: BRAND_NS.activationReceipt, has: "one", label: "book" },
358
+ reverse: { on: BRAND_NS.book, has: "many", label: "activationReceipts" }
359
+ },
336
360
  brandAssetBook: {
337
361
  forward: { on: BRAND_NS.asset, has: "one", label: "book" },
338
362
  reverse: { on: BRAND_NS.book, has: "many", label: "assets" }
@@ -374,6 +398,15 @@ function receiptAsWritten(row) {
374
398
  for (const key of systemAttrs) delete out[key];
375
399
  return out;
376
400
  }
401
+ function activationReceiptAsWritten(row) {
402
+ const normalized = rowAsWritten(BRAND_NS.activationReceipt, row);
403
+ if (!record(normalized)) return normalized;
404
+ const systemAttrs = Object.keys(normalized).filter((key) => key.startsWith("$"));
405
+ if (systemAttrs.length === 0) return normalized;
406
+ const out = { ...normalized };
407
+ for (const key of systemAttrs) delete out[key];
408
+ return out;
409
+ }
377
410
  function proposalAsWritten(row) {
378
411
  return rowAsWritten(BRAND_NS.proposal, row);
379
412
  }
@@ -445,6 +478,12 @@ var BRAND_RULES = {
445
478
  update: "false",
446
479
  delete: "false"
447
480
  },
481
+ [BRAND_NS.activationReceipt]: {
482
+ view: CURRENT_BOOK_MEMBER,
483
+ create: "false",
484
+ update: "false",
485
+ delete: "false"
486
+ },
448
487
  [BRAND_NS.asset]: {
449
488
  view: CURRENT_BOOK_MEMBER,
450
489
  create: "false",
@@ -686,15 +725,106 @@ async function brandJsonDigest(value) {
686
725
  return `sha256:${[...new Uint8Array(bytes)].map((byte) => byte.toString(16).padStart(2, "0")).join("")}`;
687
726
  }
688
727
 
689
- // src/review.ts
728
+ // src/activation-review.ts
690
729
  var DIGEST = /^sha256:[0-9a-f]{64}$/;
691
- var record3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value) && (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null);
692
- var exactKeys = (value, required, optional = []) => {
693
- const allowed = /* @__PURE__ */ new Set([...required, ...optional]);
730
+ var record3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
731
+ var exactKeys = (value, required) => {
732
+ const allowed = new Set(required);
694
733
  return required.every((key) => Object.hasOwn(value, key)) && Object.keys(value).every((key) => allowed.has(key));
695
734
  };
696
735
  var boundedString = (value, max = 200) => typeof value === "string" && value.length > 0 && value.length <= max;
697
736
  var safeTime = (value) => Number.isSafeInteger(value) && value >= 0;
737
+ var SNAPSHOT_KEYS = [
738
+ "version",
739
+ "bookId",
740
+ "slug",
741
+ "status",
742
+ "bookVersion",
743
+ "activationRevision",
744
+ "activePaletteId",
745
+ "memberIdsDigest",
746
+ "tokensSourceDigest",
747
+ "paletteReceiptId",
748
+ "paletteActionDigest",
749
+ "typographyReceiptId",
750
+ "typographyActionDigest",
751
+ "approvedSectionKeys",
752
+ "promotionDigest"
753
+ ];
754
+ function validSnapshot(value) {
755
+ if (!record3(value) || !exactKeys(value, SNAPSHOT_KEYS)) return false;
756
+ const sectionKeys = value.approvedSectionKeys;
757
+ return value.version === 1 && boundedString(value.bookId) && boundedString(value.slug) && value.status === "draft" && Number.isSafeInteger(value.bookVersion) && value.bookVersion > 0 && Number.isSafeInteger(value.activationRevision) && value.activationRevision > 0 && boundedString(value.activePaletteId) && typeof value.memberIdsDigest === "string" && DIGEST.test(value.memberIdsDigest) && typeof value.tokensSourceDigest === "string" && DIGEST.test(value.tokensSourceDigest) && boundedString(value.paletteReceiptId) && typeof value.paletteActionDigest === "string" && DIGEST.test(value.paletteActionDigest) && boundedString(value.typographyReceiptId) && typeof value.typographyActionDigest === "string" && DIGEST.test(value.typographyActionDigest) && Array.isArray(sectionKeys) && sectionKeys.length > 0 && sectionKeys.length <= 5 && sectionKeys.every((key) => boundedString(key)) && new Set(sectionKeys).size === sectionKeys.length && [...sectionKeys].sort().every((key, index) => key === sectionKeys[index]) && typeof value.promotionDigest === "string" && DIGEST.test(value.promotionDigest);
758
+ }
759
+ var CONSUMPTION_KEYS = [
760
+ "id",
761
+ "grantId",
762
+ "grantVersion",
763
+ "useNumber",
764
+ "actorPrincipalId",
765
+ "actorKind",
766
+ "credentialId",
767
+ "credentialKind",
768
+ "appId",
769
+ "appIncarnation",
770
+ "capability",
771
+ "projectCapability",
772
+ "effect",
773
+ "actionDigest",
774
+ "resourceDigest",
775
+ "constraintEvidence",
776
+ "consumptionIdempotencyKey",
777
+ "requestDigest",
778
+ "consumedAt"
779
+ ];
780
+ function validConsumption(value) {
781
+ return record3(value) && exactKeys(value, CONSUMPTION_KEYS) && boundedString(value.id) && boundedString(value.grantId) && Number.isSafeInteger(value.grantVersion) && value.grantVersion > 0 && Number.isSafeInteger(value.useNumber) && value.useNumber > 0 && boundedString(value.actorPrincipalId) && value.actorKind === "human" && boundedString(value.credentialId) && value.credentialKind === "clerk" && boundedString(value.appId) && typeof value.appIncarnation === "string" && /^[a-f0-9]{32}$/.test(value.appIncarnation) && value.capability === "brand.book.activate" && value.projectCapability === "brand.approve" && value.effect === "external" && typeof value.actionDigest === "string" && DIGEST.test(value.actionDigest) && typeof value.resourceDigest === "string" && DIGEST.test(value.resourceDigest) && record3(value.constraintEvidence) && boundedString(value.consumptionIdempotencyKey) && typeof value.requestDigest === "string" && DIGEST.test(value.requestDigest) && safeTime(value.consumedAt);
782
+ }
783
+ var RECEIPT_KEYS = [
784
+ "version",
785
+ "id",
786
+ "mutationKey",
787
+ "bookId",
788
+ "reviewedBook",
789
+ "actionDigest",
790
+ "approvedBy",
791
+ "approvedByKind",
792
+ "authorityRef",
793
+ "authorityCapability",
794
+ "authorityConsumption",
795
+ "createdAt",
796
+ "receiptDigest"
797
+ ];
798
+ async function verifyBrandActivationReceipt(receipt2) {
799
+ try {
800
+ if (!isBoundedBrandJson(receipt2, { maxDepth: 12, maxNodes: 1e3, maxBytes: 32 * 1024 }) || !record3(receipt2) || !exactKeys(receipt2, RECEIPT_KEYS)) return false;
801
+ if (receipt2.version !== 1 || !boundedString(receipt2.id) || !boundedString(receipt2.mutationKey) || !boundedString(receipt2.bookId) || !validSnapshot(receipt2.reviewedBook) || typeof receipt2.actionDigest !== "string" || !DIGEST.test(receipt2.actionDigest) || !boundedString(receipt2.approvedBy) || receipt2.approvedByKind !== "human" || !boundedString(receipt2.authorityRef) || receipt2.authorityCapability !== "brand.approve" || !validConsumption(receipt2.authorityConsumption) || !safeTime(receipt2.createdAt) || typeof receipt2.receiptDigest !== "string" || !DIGEST.test(receipt2.receiptDigest)) return false;
802
+ const reviewed = receipt2.reviewedBook;
803
+ const authority = receipt2.authorityConsumption;
804
+ if (reviewed.bookId !== receipt2.bookId || authority.actorPrincipalId !== receipt2.approvedBy || authority.actionDigest !== receipt2.actionDigest || authority.consumptionIdempotencyKey !== receipt2.mutationKey || receipt2.authorityRef !== `authority:${authority.grantId}:v${authority.grantVersion}` || authority.consumedAt > receipt2.createdAt || await brandJsonDigest({ bookId: receipt2.bookId }) !== authority.resourceDigest) return false;
805
+ const expectedAction = await brandJsonDigest({
806
+ version: 1,
807
+ reviewedBook: reviewed,
808
+ intendedStatus: "active",
809
+ activationReceiptId: receipt2.id
810
+ });
811
+ if (expectedAction !== receipt2.actionDigest) return false;
812
+ const { receiptDigest, ...immutable } = receipt2;
813
+ return await brandJsonDigest(immutable) === receiptDigest;
814
+ } catch {
815
+ return false;
816
+ }
817
+ }
818
+
819
+ // src/review.ts
820
+ var DIGEST2 = /^sha256:[0-9a-f]{64}$/;
821
+ var record4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value) && (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null);
822
+ var exactKeys2 = (value, required, optional = []) => {
823
+ const allowed = /* @__PURE__ */ new Set([...required, ...optional]);
824
+ return required.every((key) => Object.hasOwn(value, key)) && Object.keys(value).every((key) => allowed.has(key));
825
+ };
826
+ var boundedString2 = (value, max = 200) => typeof value === "string" && value.length > 0 && value.length <= max;
827
+ var safeTime2 = (value) => Number.isSafeInteger(value) && value >= 0;
698
828
  function brandAuthorityRef(consumption) {
699
829
  return `authority:${consumption.grantId}:v${consumption.grantVersion}`;
700
830
  }
@@ -713,15 +843,15 @@ var SNAPSHOT_REQUIRED = [
713
843
  "createdAt"
714
844
  ];
715
845
  function validSnapshotShape(value) {
716
- if (!record3(value) || !exactKeys(value, SNAPSHOT_REQUIRED)) return false;
846
+ if (!record4(value) || !exactKeys2(value, SNAPSHOT_REQUIRED)) return false;
717
847
  const provenance2 = value.provenance;
718
- 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, [
848
+ return boundedString2(value.id) && boundedString2(value.bookId) && typeof value.kind === "string" && PROPOSAL_KINDS.includes(value.kind) && value.status === "open" && record4(value.payload) && boundedString2(value.rationale, 2e3) && record4(provenance2) && exactKeys2(provenance2, [
719
849
  "sourceAssetId",
720
850
  "sourceAsset",
721
851
  "messageId",
722
852
  "turnId",
723
853
  "taintLabels"
724
- ]) && (provenance2.sourceAssetId === null || boundedString(provenance2.sourceAssetId)) && (provenance2.sourceAsset === null || record3(provenance2.sourceAsset) && exactKeys(provenance2.sourceAsset, [
854
+ ]) && (provenance2.sourceAssetId === null || boundedString2(provenance2.sourceAssetId)) && (provenance2.sourceAsset === null || record4(provenance2.sourceAsset) && exactKeys2(provenance2.sourceAsset, [
725
855
  "assetId",
726
856
  "contentDigest",
727
857
  "objectEtag",
@@ -730,7 +860,7 @@ function validSnapshotShape(value) {
730
860
  "contentType",
731
861
  "analysisRevision",
732
862
  "analysisDigest"
733
- ]) && 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);
863
+ ]) && boundedString2(provenance2.sourceAsset.assetId) && typeof provenance2.sourceAsset.contentDigest === "string" && DIGEST2.test(provenance2.sourceAsset.contentDigest) && boundedString2(provenance2.sourceAsset.objectEtag) && Number.isSafeInteger(provenance2.sourceAsset.objectSize) && provenance2.sourceAsset.objectSize > 0 && typeof provenance2.sourceAsset.pathDigest === "string" && DIGEST2.test(provenance2.sourceAsset.pathDigest) && (provenance2.sourceAsset.contentType === null || boundedString2(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" && DIGEST2.test(provenance2.sourceAsset.analysisDigest))) && (provenance2.sourceAssetId === null && provenance2.sourceAsset === null || provenance2.sourceAssetId !== null && provenance2.sourceAsset !== null && provenance2.sourceAsset.assetId === provenance2.sourceAssetId) && (provenance2.messageId === null || boundedString2(provenance2.messageId)) && (provenance2.turnId === null || boundedString2(provenance2.turnId)) && Array.isArray(provenance2.taintLabels) && provenance2.taintLabels.length <= 16 && provenance2.taintLabels.every((label) => boundedString2(label, 120)) && new Set(provenance2.taintLabels).size === provenance2.taintLabels.length && typeof value.reviewDigest === "string" && DIGEST2.test(value.reviewDigest) && Array.isArray(value.audience) && value.audience.length > 0 && value.audience.length <= 100 && value.audience.every((id) => boundedString2(id)) && new Set(value.audience).size === value.audience.length && boundedString2(value.createdBy) && boundedString2(value.createdAuthorityRef) && safeTime2(value.createdAt);
734
864
  }
735
865
  var CONSUMPTION_REQUIRED = [
736
866
  "id",
@@ -754,8 +884,8 @@ var CONSUMPTION_REQUIRED = [
754
884
  "consumedAt"
755
885
  ];
756
886
  function isBrandHumanAuthorityConsumption(value) {
757
- if (!record3(value) || !exactKeys(value, CONSUMPTION_REQUIRED)) return false;
758
- return boundedString(value.id) && boundedString(value.grantId) && Number.isSafeInteger(value.grantVersion) && value.grantVersion > 0 && Number.isSafeInteger(value.useNumber) && value.useNumber > 0 && boundedString(value.actorPrincipalId) && value.actorKind === "human" && boundedString(value.credentialId) && value.credentialKind === "clerk" && boundedString(value.appId) && typeof value.appIncarnation === "string" && /^[a-f0-9]{32}$/.test(value.appIncarnation) && value.capability === "brand.proposal.resolve" && value.projectCapability === "brand.approve" && value.effect === "internal" && typeof value.actionDigest === "string" && DIGEST.test(value.actionDigest) && typeof value.resourceDigest === "string" && DIGEST.test(value.resourceDigest) && record3(value.constraintEvidence) && boundedString(value.consumptionIdempotencyKey) && typeof value.requestDigest === "string" && DIGEST.test(value.requestDigest) && safeTime(value.consumedAt);
887
+ if (!record4(value) || !exactKeys2(value, CONSUMPTION_REQUIRED)) return false;
888
+ return boundedString2(value.id) && boundedString2(value.grantId) && Number.isSafeInteger(value.grantVersion) && value.grantVersion > 0 && Number.isSafeInteger(value.useNumber) && value.useNumber > 0 && boundedString2(value.actorPrincipalId) && value.actorKind === "human" && boundedString2(value.credentialId) && value.credentialKind === "clerk" && boundedString2(value.appId) && typeof value.appIncarnation === "string" && /^[a-f0-9]{32}$/.test(value.appIncarnation) && (value.capability === "brand.proposal.resolve" || value.capability === "brand.book.activate") && value.projectCapability === "brand.approve" && (value.effect === "internal" || value.effect === "external") && typeof value.actionDigest === "string" && DIGEST2.test(value.actionDigest) && typeof value.resourceDigest === "string" && DIGEST2.test(value.resourceDigest) && record4(value.constraintEvidence) && boundedString2(value.consumptionIdempotencyKey) && typeof value.requestDigest === "string" && DIGEST2.test(value.requestDigest) && safeTime2(value.consumedAt);
759
889
  }
760
890
  var RECEIPT_REQUIRED = [
761
891
  "version",
@@ -781,10 +911,10 @@ async function verifyBrandApprovalReceipt(receipt2) {
781
911
  try {
782
912
  if (!isBoundedBrandJson(receipt2, { maxDepth: 14, maxNodes: 2500, maxBytes: 48 * 1024 }))
783
913
  return false;
784
- if (!record3(receipt2) || !exactKeys(receipt2, RECEIPT_REQUIRED, ["paletteId", "resolutionNote"]))
914
+ if (!record4(receipt2) || !exactKeys2(receipt2, RECEIPT_REQUIRED, ["paletteId", "resolutionNote"]))
785
915
  return false;
786
916
  const binding = receipt2.decisionBinding;
787
- if (receipt2.version !== 1 || !boundedString(receipt2.id) || !boundedString(receipt2.mutationKey) || !boundedString(receipt2.bookId) || !boundedString(receipt2.proposalId) || receipt2.resolution !== "accepted" && receipt2.resolution !== "rejected" || !validSnapshotShape(receipt2.reviewedProposal) || typeof receipt2.actionDigest !== "string" || !DIGEST.test(receipt2.actionDigest) || !record3(binding) || !exactKeys(binding, [
917
+ if (receipt2.version !== 1 || !boundedString2(receipt2.id) || !boundedString2(receipt2.mutationKey) || !boundedString2(receipt2.bookId) || !boundedString2(receipt2.proposalId) || receipt2.resolution !== "accepted" && receipt2.resolution !== "rejected" || !validSnapshotShape(receipt2.reviewedProposal) || typeof receipt2.actionDigest !== "string" || !DIGEST2.test(receipt2.actionDigest) || !record4(binding) || !exactKeys2(binding, [
788
918
  "version",
789
919
  "bookVersion",
790
920
  "activationRevision",
@@ -794,10 +924,10 @@ async function verifyBrandApprovalReceipt(receipt2) {
794
924
  "typographyDigest",
795
925
  "sourceAssetDigest",
796
926
  "effectDigest"
797
- ]) || binding.version !== 1 || !Number.isSafeInteger(binding.bookVersion) || binding.bookVersion < 1 || !Number.isSafeInteger(binding.activationRevision) || binding.activationRevision < 0 || binding.activePaletteId !== null && !boundedString(binding.activePaletteId) || typeof binding.memberIdsDigest !== "string" || !DIGEST.test(binding.memberIdsDigest) || binding.activePaletteDigest !== null && (typeof binding.activePaletteDigest !== "string" || !DIGEST.test(binding.activePaletteDigest)) || binding.typographyDigest !== null && (typeof binding.typographyDigest !== "string" || !DIGEST.test(binding.typographyDigest)) || binding.sourceAssetDigest !== null && (typeof binding.sourceAssetDigest !== "string" || !DIGEST.test(binding.sourceAssetDigest)) || typeof binding.effectDigest !== "string" || !DIGEST.test(binding.effectDigest) || !boundedString(receipt2.approvedBy) || receipt2.approvedByKind !== "human" || !boundedString(receipt2.appliedBy) || receipt2.appliedByKind !== "human" || !boundedString(receipt2.authorityRef) || receipt2.authorityCapability !== "brand.approve" || !isBrandHumanAuthorityConsumption(receipt2.authorityConsumption) || !safeTime(receipt2.createdAt) || typeof receipt2.receiptDigest !== "string" || !DIGEST.test(receipt2.receiptDigest) || receipt2.paletteId !== void 0 && !boundedString(receipt2.paletteId) || receipt2.resolutionNote !== void 0 && !boundedString(receipt2.resolutionNote, 1e3)) return false;
927
+ ]) || binding.version !== 1 || !Number.isSafeInteger(binding.bookVersion) || binding.bookVersion < 1 || !Number.isSafeInteger(binding.activationRevision) || binding.activationRevision < 0 || binding.activePaletteId !== null && !boundedString2(binding.activePaletteId) || typeof binding.memberIdsDigest !== "string" || !DIGEST2.test(binding.memberIdsDigest) || binding.activePaletteDigest !== null && (typeof binding.activePaletteDigest !== "string" || !DIGEST2.test(binding.activePaletteDigest)) || binding.typographyDigest !== null && (typeof binding.typographyDigest !== "string" || !DIGEST2.test(binding.typographyDigest)) || binding.sourceAssetDigest !== null && (typeof binding.sourceAssetDigest !== "string" || !DIGEST2.test(binding.sourceAssetDigest)) || typeof binding.effectDigest !== "string" || !DIGEST2.test(binding.effectDigest) || !boundedString2(receipt2.approvedBy) || receipt2.approvedByKind !== "human" || !boundedString2(receipt2.appliedBy) || receipt2.appliedByKind !== "human" || !boundedString2(receipt2.authorityRef) || receipt2.authorityCapability !== "brand.approve" || !isBrandHumanAuthorityConsumption(receipt2.authorityConsumption) || !safeTime2(receipt2.createdAt) || typeof receipt2.receiptDigest !== "string" || !DIGEST2.test(receipt2.receiptDigest) || receipt2.paletteId !== void 0 && !boundedString2(receipt2.paletteId) || receipt2.resolutionNote !== void 0 && !boundedString2(receipt2.resolutionNote, 1e3)) return false;
798
928
  const reviewed = receipt2.reviewedProposal;
799
929
  const authority = receipt2.authorityConsumption;
800
- if (reviewed.id !== receipt2.proposalId || reviewed.bookId !== receipt2.bookId || receipt2.approvedBy !== receipt2.appliedBy || authority.actorPrincipalId !== receipt2.approvedBy || authority.actionDigest !== receipt2.actionDigest || authority.consumptionIdempotencyKey !== receipt2.mutationKey || receipt2.authorityRef !== brandAuthorityRef(authority) || authority.consumedAt > receipt2.createdAt || receipt2.resolution === "rejected" && receipt2.paletteId !== void 0 || receipt2.resolution === "accepted" && reviewed.kind === "palette" && !receipt2.paletteId || reviewed.kind !== "palette" && receipt2.paletteId !== void 0) return false;
930
+ if (authority.capability !== "brand.proposal.resolve" || authority.effect !== "internal" || reviewed.id !== receipt2.proposalId || reviewed.bookId !== receipt2.bookId || receipt2.approvedBy !== receipt2.appliedBy || authority.actorPrincipalId !== receipt2.approvedBy || authority.actionDigest !== receipt2.actionDigest || authority.consumptionIdempotencyKey !== receipt2.mutationKey || receipt2.authorityRef !== brandAuthorityRef(authority) || authority.consumedAt > receipt2.createdAt || receipt2.resolution === "rejected" && receipt2.paletteId !== void 0 || receipt2.resolution === "accepted" && reviewed.kind === "palette" && !receipt2.paletteId || reviewed.kind !== "palette" && receipt2.paletteId !== void 0) return false;
801
931
  const { reviewDigest, ...unsignedReview } = reviewed;
802
932
  if (await brandJsonDigest(unsignedReview) !== reviewDigest) return false;
803
933
  const expectedAction = await brandJsonDigest({
@@ -2685,14 +2815,14 @@ async function uploadAsset(ctx, req, bookId) {
2685
2815
  "internal",
2686
2816
  book.id
2687
2817
  );
2688
- const record7 = await ctx.db.storage.upload(
2818
+ const record9 = await ctx.db.storage.upload(
2689
2819
  path,
2690
2820
  file,
2691
2821
  contentType,
2692
2822
  { private: true }
2693
2823
  );
2694
- if (record7.path !== path) {
2695
- await ctx.db.storage.delete(record7.path);
2824
+ if (record9.path !== path) {
2825
+ await ctx.db.storage.delete(record9.path);
2696
2826
  throw new BrandConflictError(
2697
2827
  "private storage returned an unexpected asset path"
2698
2828
  );
@@ -2711,11 +2841,11 @@ async function uploadAsset(ctx, req, bookId) {
2711
2841
  id,
2712
2842
  bookId: book.id,
2713
2843
  kind,
2714
- path: record7.path,
2715
- storageObjectId: record7.id,
2844
+ path: record9.path,
2845
+ storageObjectId: record9.id,
2716
2846
  contentDigest: await contentDigest(file),
2717
2847
  contentType,
2718
- size: record7.size,
2848
+ size: record9.size,
2719
2849
  uploadedBy: ctx.actor.id,
2720
2850
  uploadedAuthorityRef: authority.authorityRef,
2721
2851
  audience: book.memberIds,
@@ -2742,7 +2872,7 @@ async function uploadAsset(ctx, req, bookId) {
2742
2872
  asPrincipalKind: "human"
2743
2873
  });
2744
2874
  } catch (error) {
2745
- await ctx.db.storage.delete(record7.path);
2875
+ await ctx.db.storage.delete(record9.path);
2746
2876
  throw error;
2747
2877
  }
2748
2878
  return json(await linkedAsset(ctx, book, id), 201);
@@ -3009,7 +3139,7 @@ async function handleDesignDigest(ctx, req, bookId, assetId) {
3009
3139
  }
3010
3140
 
3011
3141
  // src/routes/proposal-input.ts
3012
- var SNAPSHOT_KEYS = [
3142
+ var SNAPSHOT_KEYS2 = [
3013
3143
  "audience",
3014
3144
  "bookId",
3015
3145
  "createdAt",
@@ -3023,7 +3153,7 @@ var SNAPSHOT_KEYS = [
3023
3153
  "reviewDigest",
3024
3154
  "status"
3025
3155
  ];
3026
- var record4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
3156
+ var record5 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
3027
3157
  function parseProposalResolutionRequest(body, bookId, proposalId) {
3028
3158
  const allowed = /* @__PURE__ */ new Set([
3029
3159
  "mutationId",
@@ -3067,13 +3197,13 @@ function proposalReviewSnapshot(proposal) {
3067
3197
  function parseReviewedProposal(value, bookId, proposalId) {
3068
3198
  if (!isBoundedBrandJson(value, { maxDepth: 12, maxNodes: 1500, maxBytes: 32 * 1024 }))
3069
3199
  throw new BrandInputError('"reviewedProposal" is too deeply nested, complex, or large');
3070
- if (!record4(value)) throw new BrandInputError('"reviewedProposal" must be an object');
3200
+ if (!record5(value)) throw new BrandInputError('"reviewedProposal" must be an object');
3071
3201
  const keys = Object.keys(value).sort();
3072
- if (keys.length !== SNAPSHOT_KEYS.length || !SNAPSHOT_KEYS.every((key, index) => key === keys[index])) throw new BrandInputError('"reviewedProposal" has an invalid shape');
3202
+ if (keys.length !== SNAPSHOT_KEYS2.length || !SNAPSHOT_KEYS2.every((key, index) => key === keys[index])) throw new BrandInputError('"reviewedProposal" has an invalid shape');
3073
3203
  if (value.id !== proposalId || value.bookId !== bookId || value.status !== "open")
3074
3204
  throw new BrandInputError('"reviewedProposal" must identify this open proposal');
3075
- if (typeof value.kind !== "string" || !PROPOSAL_KINDS.includes(value.kind) || !record4(value.payload) || typeof value.rationale !== "string" || !Array.isArray(value.audience) || value.audience.length < 1 || value.audience.length > 100 || value.audience.some((id) => typeof id !== "string" || id.length < 1 || id.length > 200) || new Set(value.audience).size !== value.audience.length || typeof value.createdBy !== "string" || value.createdBy.length < 1 || value.createdBy.length > 200 || typeof value.createdAuthorityRef !== "string" || value.createdAuthorityRef.length < 1 || value.createdAuthorityRef.length > 200 || !Number.isSafeInteger(value.createdAt) || value.createdAt < 0 || typeof value.reviewDigest !== "string" || !/^sha256:[0-9a-f]{64}$/.test(value.reviewDigest)) throw new BrandInputError('"reviewedProposal" has invalid fields');
3076
- if (!record4(value.provenance) || Object.keys(value.provenance).sort().join(",") !== "messageId,sourceAsset,sourceAssetId,taintLabels,turnId" || value.provenance.sourceAssetId !== null && (typeof value.provenance.sourceAssetId !== "string" || value.provenance.sourceAssetId.length < 1 || value.provenance.sourceAssetId.length > 200) || value.provenance.sourceAsset !== null && (!record4(value.provenance.sourceAsset) || Object.keys(value.provenance.sourceAsset).sort().join(",") !== "analysisDigest,analysisRevision,assetId,contentDigest,contentType,objectEtag,objectSize,pathDigest" || typeof value.provenance.sourceAsset.assetId !== "string" || value.provenance.sourceAsset.assetId.length < 1 || value.provenance.sourceAsset.assetId.length > 200 || typeof value.provenance.sourceAsset.objectEtag !== "string" || value.provenance.sourceAsset.objectEtag.length < 1 || value.provenance.sourceAsset.objectEtag.length > 200 || !Number.isSafeInteger(value.provenance.sourceAsset.objectSize) || value.provenance.sourceAsset.objectSize < 1 || typeof value.provenance.sourceAsset.pathDigest !== "string" || !/^sha256:[0-9a-f]{64}$/.test(value.provenance.sourceAsset.pathDigest) || value.provenance.sourceAsset.contentType !== null && (typeof value.provenance.sourceAsset.contentType !== "string" || value.provenance.sourceAsset.contentType.length < 1 || value.provenance.sourceAsset.contentType.length > 160) || typeof value.provenance.sourceAsset.contentDigest !== "string" || !/^sha256:[0-9a-f]{64}$/.test(value.provenance.sourceAsset.contentDigest) || value.provenance.sourceAsset.analysisRevision !== null && (!Number.isSafeInteger(value.provenance.sourceAsset.analysisRevision) || value.provenance.sourceAsset.analysisRevision < 0) || value.provenance.sourceAsset.analysisDigest !== null && (typeof value.provenance.sourceAsset.analysisDigest !== "string" || !/^sha256:[0-9a-f]{64}$/.test(
3205
+ if (typeof value.kind !== "string" || !PROPOSAL_KINDS.includes(value.kind) || !record5(value.payload) || typeof value.rationale !== "string" || !Array.isArray(value.audience) || value.audience.length < 1 || value.audience.length > 100 || value.audience.some((id) => typeof id !== "string" || id.length < 1 || id.length > 200) || new Set(value.audience).size !== value.audience.length || typeof value.createdBy !== "string" || value.createdBy.length < 1 || value.createdBy.length > 200 || typeof value.createdAuthorityRef !== "string" || value.createdAuthorityRef.length < 1 || value.createdAuthorityRef.length > 200 || !Number.isSafeInteger(value.createdAt) || value.createdAt < 0 || typeof value.reviewDigest !== "string" || !/^sha256:[0-9a-f]{64}$/.test(value.reviewDigest)) throw new BrandInputError('"reviewedProposal" has invalid fields');
3206
+ if (!record5(value.provenance) || Object.keys(value.provenance).sort().join(",") !== "messageId,sourceAsset,sourceAssetId,taintLabels,turnId" || value.provenance.sourceAssetId !== null && (typeof value.provenance.sourceAssetId !== "string" || value.provenance.sourceAssetId.length < 1 || value.provenance.sourceAssetId.length > 200) || value.provenance.sourceAsset !== null && (!record5(value.provenance.sourceAsset) || Object.keys(value.provenance.sourceAsset).sort().join(",") !== "analysisDigest,analysisRevision,assetId,contentDigest,contentType,objectEtag,objectSize,pathDigest" || typeof value.provenance.sourceAsset.assetId !== "string" || value.provenance.sourceAsset.assetId.length < 1 || value.provenance.sourceAsset.assetId.length > 200 || typeof value.provenance.sourceAsset.objectEtag !== "string" || value.provenance.sourceAsset.objectEtag.length < 1 || value.provenance.sourceAsset.objectEtag.length > 200 || !Number.isSafeInteger(value.provenance.sourceAsset.objectSize) || value.provenance.sourceAsset.objectSize < 1 || typeof value.provenance.sourceAsset.pathDigest !== "string" || !/^sha256:[0-9a-f]{64}$/.test(value.provenance.sourceAsset.pathDigest) || value.provenance.sourceAsset.contentType !== null && (typeof value.provenance.sourceAsset.contentType !== "string" || value.provenance.sourceAsset.contentType.length < 1 || value.provenance.sourceAsset.contentType.length > 160) || typeof value.provenance.sourceAsset.contentDigest !== "string" || !/^sha256:[0-9a-f]{64}$/.test(value.provenance.sourceAsset.contentDigest) || value.provenance.sourceAsset.analysisRevision !== null && (!Number.isSafeInteger(value.provenance.sourceAsset.analysisRevision) || value.provenance.sourceAsset.analysisRevision < 0) || value.provenance.sourceAsset.analysisDigest !== null && (typeof value.provenance.sourceAsset.analysisDigest !== "string" || !/^sha256:[0-9a-f]{64}$/.test(
3077
3207
  value.provenance.sourceAsset.analysisDigest
3078
3208
  )) || value.provenance.sourceAsset.assetId !== value.provenance.sourceAssetId) || value.provenance.sourceAssetId === null !== (value.provenance.sourceAsset === null) || value.provenance.messageId !== null && (typeof value.provenance.messageId !== "string" || value.provenance.messageId.length < 1 || value.provenance.messageId.length > 200) || value.provenance.turnId !== null && (typeof value.provenance.turnId !== "string" || value.provenance.turnId.length < 1 || value.provenance.turnId.length > 200) || !Array.isArray(value.provenance.taintLabels) || value.provenance.taintLabels.length > 16 || value.provenance.taintLabels.some((label) => typeof label !== "string" || label.length < 1 || label.length > 120) || new Set(value.provenance.taintLabels).size !== value.provenance.taintLabels.length) throw new BrandInputError('"reviewedProposal.provenance" is invalid');
3079
3209
  return value;
@@ -3150,11 +3280,11 @@ async function proposalDecisionOps(input) {
3150
3280
  input.approvedTypography?.approvalReceiptId,
3151
3281
  input.approvedTypography?.approvalActionDigest
3152
3282
  );
3153
- const bookOp = ops.find(
3283
+ const bookOp2 = ops.find(
3154
3284
  (op) => op.t === "update" && op.ns === BRAND_NS.book && op.id === input.book.id
3155
3285
  );
3156
- if (!bookOp || bookOp.t !== "update") throw new Error("book activation op missing");
3157
- Object.assign(bookOp.attrs, {
3286
+ if (!bookOp2 || bookOp2.t !== "update") throw new Error("book activation op missing");
3287
+ Object.assign(bookOp2.attrs, {
3158
3288
  version: input.book.version + 1,
3159
3289
  activationRevision: input.book.activationRevision + 1,
3160
3290
  tokens
@@ -3206,13 +3336,13 @@ async function proposalDecisionOps(input) {
3206
3336
  }
3207
3337
  ];
3208
3338
  if (input.proposal.kind === "typography" && input.priorPalette) {
3209
- const bookOp = ops.find(
3339
+ const bookOp2 = ops.find(
3210
3340
  (op) => op.t === "update" && op.ns === BRAND_NS.book && op.id === input.book.id
3211
3341
  );
3212
- if (bookOp?.t === "update") {
3342
+ if (bookOp2?.t === "update") {
3213
3343
  if (!input.priorPalette.approvalReceiptId || !input.priorPalette.approvalActionDigest)
3214
3344
  throw new BrandInputError("active palette is missing approval provenance");
3215
- bookOp.attrs.tokens = await tokenSnapshot(
3345
+ bookOp2.attrs.tokens = await tokenSnapshot(
3216
3346
  input.priorPalette.swatches,
3217
3347
  content,
3218
3348
  input,
@@ -3225,6 +3355,19 @@ async function proposalDecisionOps(input) {
3225
3355
  }
3226
3356
  }
3227
3357
  }
3358
+ const bookOp = ops.find(
3359
+ (candidate) => candidate.t === "update" && candidate.ns === BRAND_NS.book && candidate.id === input.book.id
3360
+ );
3361
+ if (!bookOp || bookOp.t !== "update") throw new Error("book approval op missing");
3362
+ bookOp.attrs.status = "draft";
3363
+ if (input.book.activationReceiptId || input.book.activationActionDigest) {
3364
+ ops.push({
3365
+ t: "retract",
3366
+ ns: BRAND_NS.book,
3367
+ id: input.book.id,
3368
+ attrs: ["activationReceiptId", "activationActionDigest"]
3369
+ });
3370
+ }
3228
3371
  stampProposal(ops, input);
3229
3372
  return ops;
3230
3373
  }
@@ -3264,7 +3407,7 @@ async function consumeProposalAuthority(ctx, req, bookId, proposalId, actionDige
3264
3407
  consumptionIdempotencyKey: mutationKey
3265
3408
  });
3266
3409
  const resourceDigest = await brandJsonDigest({ bookId, proposalId });
3267
- if (!isBrandHumanAuthorityConsumption(authority) || authority.actorPrincipalId !== ctx.actor.id || authority.appId !== ctx.appId || authority.actionDigest !== actionDigest || authority.resourceDigest !== resourceDigest || authority.consumptionIdempotencyKey !== mutationKey) throw new BrandForbiddenError(
3410
+ if (!isBrandHumanAuthorityConsumption(authority) || authority.capability !== "brand.proposal.resolve" || authority.projectCapability !== "brand.approve" || authority.effect !== "internal" || authority.actorPrincipalId !== ctx.actor.id || authority.appId !== ctx.appId || authority.actionDigest !== actionDigest || authority.resourceDigest !== resourceDigest || authority.consumptionIdempotencyKey !== mutationKey) throw new BrandForbiddenError(
3268
3411
  "a verified human-exact brand approval is required"
3269
3412
  );
3270
3413
  return authority;
@@ -3528,9 +3671,9 @@ async function proposalDecisionState(ctx, req, book, proposal, resolution, recei
3528
3671
  }
3529
3672
 
3530
3673
  // src/routes/proposals.ts
3531
- var record5 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
3674
+ var record6 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
3532
3675
  var sameStrings2 = (left, right) => left.length === right.length && left.every((value, index) => value === right[index]);
3533
- var guardFailure2 = (error) => record5(error) && error.code === "transact_guard_failed";
3676
+ var guardFailure2 = (error) => record6(error) && error.code === "transact_guard_failed";
3534
3677
  async function handleProposalResolution(ctx, req, bookId, proposalId) {
3535
3678
  if (req.method !== "POST") return methodNotAllowed();
3536
3679
  const book = await loadMemberBook(ctx.db, bookId, ctx.actor.id);
@@ -3710,7 +3853,7 @@ async function handleProposalResolution(ctx, req, bookId, proposalId) {
3710
3853
  }
3711
3854
 
3712
3855
  // src/routes/tokens.ts
3713
- var record6 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
3856
+ var record7 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
3714
3857
  var missing = (bookId) => {
3715
3858
  throw new BrandNotFoundError(`compiled tokens for brand book ${bookId}`);
3716
3859
  };
@@ -3730,7 +3873,7 @@ async function acceptedReceipt(db, bookId, receiptId, actionDigest) {
3730
3873
  }
3731
3874
  async function approvedCache(db, book) {
3732
3875
  const cache = book.tokens;
3733
- if (!cache || !record6(cache.light) || !record6(cache.dark) || !book.activePaletteId || cache.paletteId !== book.activePaletteId || !cache.paletteReceiptId || !cache.paletteActionDigest || !cache.sourceDigest) return missing(book.id);
3876
+ if (!cache || !record7(cache.light) || !record7(cache.dark) || !book.activePaletteId || cache.paletteId !== book.activePaletteId || !cache.paletteReceiptId || !cache.paletteActionDigest || !cache.sourceDigest) return missing(book.id);
3734
3877
  const paletteResult = await db.query({
3735
3878
  [BRAND_NS.palette]: {
3736
3879
  $: { where: { id: cache.paletteId, bookId: book.id } },
@@ -4075,6 +4218,413 @@ async function handleBrandDiscussionReferences(ctx, req, url) {
4075
4218
  });
4076
4219
  }
4077
4220
 
4221
+ // src/promotion.ts
4222
+ import {
4223
+ canonicalPromotionValue
4224
+ } from "@odla-ai/promotion";
4225
+ var BRAND_PROMOTION_ADAPTER = "@odla-ai/brand/v1";
4226
+ var provenance = (book, sourceIds, receiptDigests = []) => ({
4227
+ adapter: BRAND_PROMOTION_ADAPTER,
4228
+ sourceIds: [
4229
+ ...sourceIds,
4230
+ ...book.activationReceiptId ? [book.activationReceiptId] : []
4231
+ ].sort(),
4232
+ receiptDigests: [
4233
+ ...receiptDigests,
4234
+ ...book.activationActionDigest ? [book.activationActionDigest] : []
4235
+ ].sort()
4236
+ });
4237
+ var exclusions = (book) => [
4238
+ {
4239
+ kind: "brand.runtime",
4240
+ id: book.slug,
4241
+ reason: "environment_local",
4242
+ paths: [`${BRAND_NS.book}.ownerId`, `${BRAND_NS.book}.memberIds`, `${BRAND_NS.book}.channelId`, `${BRAND_NS.book}.*At`],
4243
+ detail: "Ownership, roster, channel, and timestamps remain local to the target environment."
4244
+ },
4245
+ {
4246
+ kind: "brand.drafts",
4247
+ id: book.slug,
4248
+ reason: "draft_state",
4249
+ paths: [`${BRAND_NS.proposal}.*`, `${BRAND_NS.section}[status=draft]`],
4250
+ detail: "Open proposals and unapproved sections are review state, not published brand content."
4251
+ },
4252
+ {
4253
+ kind: "brand.assets",
4254
+ id: book.slug,
4255
+ reason: "provider_identity",
4256
+ paths: [`${BRAND_NS.asset}.storageObjectId`, `${BRAND_NS.asset}.path`, `${BRAND_NS.asset}.*AuthorityRef`],
4257
+ detail: "Stored files and provider object identities require a separate asset-transfer contract."
4258
+ },
4259
+ {
4260
+ kind: "brand.authority",
4261
+ id: book.slug,
4262
+ reason: "authority_history",
4263
+ paths: [
4264
+ `${BRAND_NS.approvalReceipt}.*`,
4265
+ `${BRAND_NS.activationReceipt}.*`,
4266
+ `${BRAND_NS.palette}.audience`
4267
+ ],
4268
+ detail: "Authority rows stay immutable in their source environment; artifacts retain only receipt digests and ids."
4269
+ }
4270
+ ];
4271
+ function buildBrandPromotion(input) {
4272
+ const { book } = input;
4273
+ const revision = `brand:${book.slug}:${book.activationRevision}`;
4274
+ const artifacts = [];
4275
+ if (book.tokens) {
4276
+ const {
4277
+ compiledAt: _compiledAt,
4278
+ paletteReceiptId,
4279
+ paletteActionDigest,
4280
+ typographyReceiptId,
4281
+ typographyActionDigest,
4282
+ sourceDigest,
4283
+ ...stableTokens
4284
+ } = book.tokens;
4285
+ artifacts.push({
4286
+ kind: "brand.tokens",
4287
+ id: book.slug,
4288
+ sourceRevision: revision,
4289
+ provenance: provenance(
4290
+ book,
4291
+ [book.id, book.tokens.paletteId, paletteReceiptId, typographyReceiptId].filter((value) => Boolean(value)),
4292
+ [sourceDigest, paletteActionDigest, typographyActionDigest].filter((value) => Boolean(value))
4293
+ ),
4294
+ content: canonicalPromotionValue({ bookSlug: book.slug, tokens: stableTokens })
4295
+ });
4296
+ }
4297
+ for (const section of input.sections.filter((row) => row.bookId === book.id && row.status === "approved")) {
4298
+ if (!section.approvalReceiptId || !section.approvalActionDigest) {
4299
+ throw new TypeError(`approved brand section ${section.key} lacks approval provenance`);
4300
+ }
4301
+ artifacts.push({
4302
+ kind: "brand.section",
4303
+ id: `${book.slug}/${section.kind}`,
4304
+ sourceRevision: revision,
4305
+ provenance: provenance(book, [book.id, section.id, section.approvalReceiptId], [section.approvalActionDigest]),
4306
+ content: canonicalPromotionValue({ bookSlug: book.slug, kind: section.kind, content: section.content })
4307
+ });
4308
+ }
4309
+ const activePalette2 = input.palettes.find((row) => row.bookId === book.id && row.id === book.activePaletteId && row.status === "active");
4310
+ if (book.activePaletteId && !activePalette2) throw new TypeError(`active palette ${book.activePaletteId} is unavailable`);
4311
+ if (activePalette2) {
4312
+ artifacts.push({
4313
+ kind: "brand.palette",
4314
+ id: `${book.slug}/${activePalette2.id}`,
4315
+ sourceRevision: revision,
4316
+ provenance: provenance(book, [book.id, activePalette2.id, activePalette2.proposalId, activePalette2.approvalReceiptId], [activePalette2.approvalActionDigest]),
4317
+ content: canonicalPromotionValue({
4318
+ bookSlug: book.slug,
4319
+ name: activePalette2.name,
4320
+ swatches: activePalette2.swatches,
4321
+ source: activePalette2.source,
4322
+ ...activePalette2.seedHex ? { seedHex: activePalette2.seedHex } : {},
4323
+ ...activePalette2.rationale ? { rationale: activePalette2.rationale } : {}
4324
+ })
4325
+ });
4326
+ }
4327
+ return {
4328
+ adapter: BRAND_PROMOTION_ADAPTER,
4329
+ artifacts,
4330
+ exclusions: exclusions(book),
4331
+ preconditions: [{
4332
+ code: "brand.schema",
4333
+ path: "services.brand.schemaVersion",
4334
+ expected: 1,
4335
+ detail: "The target must expose the Brand v1 approved-content schema."
4336
+ }]
4337
+ };
4338
+ }
4339
+ function exportBrandPromotionCandidate(input) {
4340
+ if (input.book.status !== "draft")
4341
+ throw new TypeError(`brand book ${input.book.slug} is not draft`);
4342
+ return buildBrandPromotion({
4343
+ ...input,
4344
+ book: { ...input.book, status: "active" }
4345
+ });
4346
+ }
4347
+ function exportBrandPromotion(input) {
4348
+ const { book } = input;
4349
+ if (book.status !== "active") throw new TypeError(`brand book ${book.slug} is not active`);
4350
+ if (!book.activationReceiptId || !book.activationActionDigest)
4351
+ throw new TypeError(`active brand book ${book.slug} lacks activation provenance`);
4352
+ return buildBrandPromotion(input);
4353
+ }
4354
+
4355
+ // src/routes/activation-state.ts
4356
+ async function activationReceiptByMutation(ctx, mutationKey) {
4357
+ const result = await ctx.db.query({
4358
+ [BRAND_NS.activationReceipt]: {
4359
+ $: { where: { mutationKey } },
4360
+ book: {}
4361
+ }
4362
+ });
4363
+ const row = (result[BRAND_NS.activationReceipt] ?? [])[0];
4364
+ if (!row || !hasExactOneLink(row.book, row.bookId)) return void 0;
4365
+ const { book: _book, ...receipt2 } = row;
4366
+ return activationReceiptAsWritten(receipt2);
4367
+ }
4368
+ async function approvalReceipt(ctx, bookId, receiptId) {
4369
+ const result = await ctx.db.query({
4370
+ [BRAND_NS.approvalReceipt]: {
4371
+ $: { where: { id: receiptId, bookId } },
4372
+ book: {}
4373
+ }
4374
+ });
4375
+ const row = (result[BRAND_NS.approvalReceipt] ?? [])[0];
4376
+ if (!row || !hasExactOneLink(row.book, bookId))
4377
+ throw new BrandInputError(`approval receipt ${receiptId} is unavailable`);
4378
+ const { book: _book, ...stored } = row;
4379
+ const receipt2 = receiptAsWritten(stored);
4380
+ if (!await verifyBrandApprovalReceipt(receipt2))
4381
+ throw new BrandInputError(`approval receipt ${receiptId} is invalid`);
4382
+ return receipt2;
4383
+ }
4384
+ async function activationState(ctx, book) {
4385
+ if (book.status !== "draft")
4386
+ throw new BrandConflictError(`brand book ${book.slug} is already ${book.status}`);
4387
+ const tokens = book.tokens;
4388
+ if (!book.activePaletteId || !tokens || tokens.paletteId !== book.activePaletteId || !tokens.paletteReceiptId || !tokens.paletteActionDigest || !tokens.typographyReceiptId || !tokens.typographyActionDigest) throw new BrandInputError(
4389
+ "brand book activation requires approved palette and typography tokens"
4390
+ );
4391
+ const result = await ctx.db.query({
4392
+ [BRAND_NS.section]: { $: { where: { bookId: book.id } }, book: {} },
4393
+ [BRAND_NS.palette]: { $: { where: { bookId: book.id } }, book: {} }
4394
+ });
4395
+ const sections = (result[BRAND_NS.section] ?? []).map((row) => rowAsWritten(BRAND_NS.section, row));
4396
+ const palettes = (result[BRAND_NS.palette] ?? []).map((row) => rowAsWritten(BRAND_NS.palette, row));
4397
+ const activePalette2 = palettes.find((row) => row.id === book.activePaletteId && row.status === "active");
4398
+ const typography = sections.find((row) => row.kind === "typography" && row.status === "approved");
4399
+ if (!activePalette2 || activePalette2.approvalReceiptId !== tokens.paletteReceiptId || activePalette2.approvalActionDigest !== tokens.paletteActionDigest) throw new BrandInputError("active palette does not match compiled token provenance");
4400
+ if (!typography || typography.approvalReceiptId !== tokens.typographyReceiptId || typography.approvalActionDigest !== tokens.typographyActionDigest) throw new BrandInputError("approved typography does not match compiled token provenance");
4401
+ const [paletteReceipt, typographyReceipt] = await Promise.all([
4402
+ approvalReceipt(ctx, book.id, tokens.paletteReceiptId),
4403
+ approvalReceipt(ctx, book.id, tokens.typographyReceiptId)
4404
+ ]);
4405
+ if (paletteReceipt.resolution !== "accepted" || paletteReceipt.actionDigest !== tokens.paletteActionDigest || typographyReceipt.resolution !== "accepted" || typographyReceipt.actionDigest !== tokens.typographyActionDigest) throw new BrandInputError("compiled tokens are not backed by accepted approvals");
4406
+ const candidateBook = { ...book, status: "draft" };
4407
+ delete candidateBook.activationReceiptId;
4408
+ delete candidateBook.activationActionDigest;
4409
+ const promotion = exportBrandPromotionCandidate({ book: candidateBook, sections, palettes });
4410
+ const approved = sections.filter((row) => row.status === "approved").sort((left, right) => left.key.localeCompare(right.key));
4411
+ const reviewed = {
4412
+ version: 1,
4413
+ bookId: book.id,
4414
+ slug: book.slug,
4415
+ status: "draft",
4416
+ bookVersion: book.version,
4417
+ activationRevision: book.activationRevision,
4418
+ activePaletteId: book.activePaletteId,
4419
+ memberIdsDigest: await brandJsonDigest(book.memberIds),
4420
+ tokensSourceDigest: tokens.sourceDigest,
4421
+ paletteReceiptId: tokens.paletteReceiptId,
4422
+ paletteActionDigest: tokens.paletteActionDigest,
4423
+ typographyReceiptId: tokens.typographyReceiptId,
4424
+ typographyActionDigest: tokens.typographyActionDigest,
4425
+ approvedSectionKeys: approved.map((row) => row.key),
4426
+ promotionDigest: await brandJsonDigest(promotion)
4427
+ };
4428
+ return {
4429
+ reviewed,
4430
+ sections,
4431
+ palettes,
4432
+ guards: [
4433
+ {
4434
+ ns: BRAND_NS.book,
4435
+ id: book.id,
4436
+ exists: true,
4437
+ equals: {
4438
+ version: book.version,
4439
+ status: "draft",
4440
+ activationRevision: book.activationRevision,
4441
+ activePaletteId: book.activePaletteId,
4442
+ memberIds: book.memberIds,
4443
+ tokens: book.tokens
4444
+ }
4445
+ },
4446
+ {
4447
+ ns: BRAND_NS.palette,
4448
+ id: activePalette2.id,
4449
+ exists: true,
4450
+ equals: {
4451
+ status: "active",
4452
+ approvalReceiptId: activePalette2.approvalReceiptId,
4453
+ approvalActionDigest: activePalette2.approvalActionDigest,
4454
+ swatches: activePalette2.swatches
4455
+ }
4456
+ },
4457
+ ...approved.map((row) => ({
4458
+ ns: BRAND_NS.section,
4459
+ id: row.id,
4460
+ exists: true,
4461
+ equals: {
4462
+ status: "approved",
4463
+ content: row.content,
4464
+ approvalReceiptId: row.approvalReceiptId,
4465
+ approvalActionDigest: row.approvalActionDigest
4466
+ }
4467
+ })),
4468
+ ...[paletteReceipt, typographyReceipt].map((row) => ({
4469
+ ns: BRAND_NS.approvalReceipt,
4470
+ id: row.id,
4471
+ exists: true,
4472
+ equals: { receiptDigest: row.receiptDigest }
4473
+ }))
4474
+ ]
4475
+ };
4476
+ }
4477
+
4478
+ // src/routes/activation.ts
4479
+ var record8 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
4480
+ var guardFailure3 = (error) => record8(error) && error.code === "transact_guard_failed";
4481
+ async function activationMutationKey(bookId, mutationId) {
4482
+ const digest2 = await brandJsonDigest({ version: 1, bookId, mutationId });
4483
+ return `brand:book-activation:v1:${digest2.slice("sha256:".length)}`;
4484
+ }
4485
+ async function consumeActivationAuthority(ctx, req, bookId, actionDigest, mutationKey) {
4486
+ const authority = await ctx.consumeHumanExact({
4487
+ req,
4488
+ actor: ctx.actor,
4489
+ appId: ctx.appId,
4490
+ capability: "brand.book.activate",
4491
+ projectCapability: "brand.approve",
4492
+ effect: "external",
4493
+ resource: { bookId },
4494
+ actionDigest,
4495
+ consumptionIdempotencyKey: mutationKey
4496
+ });
4497
+ if (!authority || authority.capability !== "brand.book.activate" || authority.projectCapability !== "brand.approve" || authority.effect !== "external" || authority.actorKind !== "human" || authority.credentialKind !== "clerk" || authority.actorPrincipalId !== ctx.actor.id || authority.appId !== ctx.appId || authority.actionDigest !== actionDigest || authority.resourceDigest !== await brandJsonDigest({ bookId }) || authority.consumptionIdempotencyKey !== mutationKey) throw new BrandForbiddenError("a verified human-exact Brand activation is required");
4498
+ return authority;
4499
+ }
4500
+ async function handleBookActivation(ctx, req, bookId) {
4501
+ const book = await loadMemberBook(ctx.db, bookId, ctx.actor.id);
4502
+ if (ctx.actor.kind !== "human")
4503
+ throw new BrandForbiddenError("only a directly authenticated human can activate a brand book");
4504
+ if (req.method === "GET") {
4505
+ if (book.status === "active") return json({ status: "active", book });
4506
+ const state2 = await activationState(ctx, book);
4507
+ return json({ status: "draft", reviewedBook: state2.reviewed });
4508
+ }
4509
+ if (req.method !== "POST") return methodNotAllowed();
4510
+ const body = await readJson(req);
4511
+ if (!record8(body.reviewedBook))
4512
+ throw new BrandInputError('"reviewedBook" is required');
4513
+ const reviewed = body.reviewedBook;
4514
+ const mutationId = capString(str(body, "mutationId"), "mutationId", 200);
4515
+ const mutationKey = await activationMutationKey(bookId, mutationId);
4516
+ const stable = (await brandJsonDigest({ mutationKey })).slice(7);
4517
+ const receiptId = `brand-activation-${stable.slice(0, 32)}`;
4518
+ const existing = await activationReceiptByMutation(ctx, mutationKey);
4519
+ if (existing) {
4520
+ if (!await verifyBrandActivationReceipt(existing) || canonicalBrandJson(existing.reviewedBook) !== canonicalBrandJson(reviewed)) throw new BrandConflictError("mutationId was used for another activation");
4521
+ const replayed = await consumeActivationAuthority(
4522
+ ctx,
4523
+ req,
4524
+ bookId,
4525
+ existing.actionDigest,
4526
+ mutationKey
4527
+ );
4528
+ if (canonicalBrandJson(replayed) !== canonicalBrandJson(existing.authorityConsumption))
4529
+ throw new BrandConflictError("central activation receipt changed");
4530
+ if (book.status !== "active" || book.activationReceiptId !== existing.id || book.activationActionDigest !== existing.actionDigest) throw new BrandConflictError("activated Brand revision is no longer current");
4531
+ const result = await ctx.db.query({
4532
+ [BRAND_NS.section]: { $: { where: { bookId } } },
4533
+ [BRAND_NS.palette]: { $: { where: { bookId } } }
4534
+ });
4535
+ const promotion2 = exportBrandPromotion({
4536
+ book,
4537
+ sections: result[BRAND_NS.section] ?? [],
4538
+ palettes: result[BRAND_NS.palette] ?? []
4539
+ });
4540
+ return json({ receipt: existing, promotion: promotion2, promotionDigest: await brandJsonDigest(promotion2), duplicate: true });
4541
+ }
4542
+ const state = await activationState(ctx, book);
4543
+ if (canonicalBrandJson(state.reviewed) !== canonicalBrandJson(reviewed))
4544
+ throw new BrandConflictError("brand book changed since activation review");
4545
+ const actionDigest = await brandJsonDigest({
4546
+ version: 1,
4547
+ reviewedBook: state.reviewed,
4548
+ intendedStatus: "active",
4549
+ activationReceiptId: receiptId
4550
+ });
4551
+ const authority = await consumeActivationAuthority(
4552
+ ctx,
4553
+ req,
4554
+ bookId,
4555
+ actionDigest,
4556
+ mutationKey
4557
+ );
4558
+ const receiptBase = {
4559
+ version: 1,
4560
+ id: receiptId,
4561
+ mutationKey,
4562
+ bookId,
4563
+ reviewedBook: state.reviewed,
4564
+ actionDigest,
4565
+ approvedBy: ctx.actor.id,
4566
+ approvedByKind: "human",
4567
+ authorityRef: brandAuthorityRef(authority),
4568
+ authorityCapability: "brand.approve",
4569
+ authorityConsumption: authority,
4570
+ createdAt: authority.consumedAt
4571
+ };
4572
+ const receipt2 = {
4573
+ ...receiptBase,
4574
+ receiptDigest: await brandJsonDigest(receiptBase)
4575
+ };
4576
+ try {
4577
+ const tx = await ctx.db.transact([
4578
+ {
4579
+ t: "update",
4580
+ ns: BRAND_NS.book,
4581
+ id: bookId,
4582
+ attrs: {
4583
+ status: "active",
4584
+ version: book.version + 1,
4585
+ activationReceiptId: receipt2.id,
4586
+ activationActionDigest: receipt2.actionDigest,
4587
+ updatedAt: authority.consumedAt
4588
+ }
4589
+ },
4590
+ { t: "update", ns: BRAND_NS.activationReceipt, id: receipt2.id, attrs: receipt2 },
4591
+ { t: "link", ns: BRAND_NS.activationReceipt, id: receipt2.id, label: "book", target: bookId }
4592
+ ], {
4593
+ mutationId: mutationKey,
4594
+ guards: [
4595
+ ...state.guards,
4596
+ { ns: BRAND_NS.activationReceipt, id: receipt2.id, exists: false }
4597
+ ],
4598
+ asUser: ctx.actor.id,
4599
+ ...ctx.actor.email ? { asEmail: ctx.actor.email } : {},
4600
+ asPrincipalKind: "human"
4601
+ });
4602
+ if (tx.duplicate) throw new BrandConflictError("activation replay was not observable");
4603
+ } catch (error) {
4604
+ if (guardFailure3(error)) throw new BrandReviewStateChangedError();
4605
+ throw error;
4606
+ }
4607
+ const activeBook = {
4608
+ ...book,
4609
+ status: "active",
4610
+ version: book.version + 1,
4611
+ activationReceiptId: receipt2.id,
4612
+ activationActionDigest: receipt2.actionDigest,
4613
+ updatedAt: authority.consumedAt
4614
+ };
4615
+ const promotion = exportBrandPromotion({
4616
+ book: activeBook,
4617
+ sections: state.sections,
4618
+ palettes: state.palettes
4619
+ });
4620
+ return json({
4621
+ receipt: receipt2,
4622
+ promotion,
4623
+ promotionDigest: await brandJsonDigest(promotion),
4624
+ duplicate: false
4625
+ });
4626
+ }
4627
+
4078
4628
  // src/routes/index.ts
4079
4629
  var tokensFile = (seg) => seg.length === 3 && seg[0] === "books" && (seg[2] === "tokens.css" || seg[2] === "tokens.json") ? seg[2] : null;
4080
4630
  async function route(ctx, req, url, seg) {
@@ -4085,6 +4635,7 @@ async function route(ctx, req, url, seg) {
4085
4635
  if (seg.length === 1) return handleBooksRoot(ctx, req);
4086
4636
  if (seg.length === 2) return handleBookItem(ctx, req, id);
4087
4637
  if (seg.length === 3 && sub === "members") return handleBookMembers(ctx, req, id);
4638
+ if (seg.length === 3 && sub === "activate") return handleBookActivation(ctx, req, id);
4088
4639
  if (sub === "assets") {
4089
4640
  if (seg.length === 3) return handleAssetsRoot(ctx, req, id);
4090
4641
  if (seg.length === 4) return handleAssetItem(ctx, req, id, subId);
@@ -4344,7 +4895,7 @@ var brandIntegration = {
4344
4895
  agentProfile: BRAND_AGENT_PROFILE,
4345
4896
  provision: {
4346
4897
  human: [
4347
- "Configure direct Clerk human approval through authorizeCapability + consumeHumanExact; delegated, machine, and agent principals must not resolve proposals.",
4898
+ "Configure direct Clerk human approval through authorizeCapability + consumeHumanExact; delegated, machine, and agent principals must not resolve proposals or activate books.",
4348
4899
  'Choose the trigger mode: one global mention-gated bot (brandBotTrigger({ mention: "@brand" }), no channels) or per-book channel-scoped bots (channels: [book.channelId], no mention).',
4349
4900
  "Pick a model where supportsBrandVision(catalog[model]) is true for in-conversation asset viewing; secure dispatch never falls back to signed or persistent asset URLs.",
4350
4901
  "Decide whether compiled tokens are public (publicTokens serves tokens.css/tokens.json unauthenticated)."
@@ -4358,9 +4909,10 @@ var brandIntegration = {
4358
4909
  "Provision private file signing and verifySourceAssetSnapshot; never expose an admin credential or persistent asset URL to the agent."
4359
4910
  ],
4360
4911
  doctor: [
4361
- "All six brand_* namespaces have rules installed; raw browser/agent writes are denied and child reads use current linked-book membership.",
4912
+ "All seven brand_* namespaces have rules installed; raw browser/agent writes are denied and child reads use current linked-book membership.",
4362
4913
  "The agent runtime matches BRAND_AGENT_PROFILE: brand.read/edit only, semantic operations only, no raw brand_* or file access.",
4363
4914
  "Proposal decisions consume a direct-human exact brand.approve authority use and persist one guarded brand_approval_receipt.",
4915
+ "Book activation consumes a direct-human exact external brand.approve authority use and persists one guarded brand_activation_receipt before promotion export opens.",
4364
4916
  "Private source assets are signed briefly and verifySourceAssetSnapshot revalidates path, ETag, size, content type, and digest before approval.",
4365
4917
  "brand_book.id/slug, brand_section.key, and the other mirrored id attrs are unique.",
4366
4918
  "Each registered trigger's agent id is present in its target books' memberIds rosters.",
@@ -4384,115 +4936,6 @@ function createBrandIntegration(options = {}) {
4384
4936
  probes: [{ path: `${basePath}/books`, expectedStatus: 401 }]
4385
4937
  };
4386
4938
  }
4387
-
4388
- // src/promotion.ts
4389
- import {
4390
- canonicalPromotionValue
4391
- } from "@odla-ai/promotion";
4392
- var BRAND_PROMOTION_ADAPTER = "@odla-ai/brand/v1";
4393
- var provenance = (sourceIds, receiptDigests = []) => ({
4394
- adapter: BRAND_PROMOTION_ADAPTER,
4395
- sourceIds: [...sourceIds].sort(),
4396
- receiptDigests: [...receiptDigests].sort()
4397
- });
4398
- var exclusions = (book) => [
4399
- {
4400
- kind: "brand.runtime",
4401
- id: book.slug,
4402
- reason: "environment_local",
4403
- paths: [`${BRAND_NS.book}.ownerId`, `${BRAND_NS.book}.memberIds`, `${BRAND_NS.book}.channelId`, `${BRAND_NS.book}.*At`],
4404
- detail: "Ownership, roster, channel, and timestamps remain local to the target environment."
4405
- },
4406
- {
4407
- kind: "brand.drafts",
4408
- id: book.slug,
4409
- reason: "draft_state",
4410
- paths: [`${BRAND_NS.proposal}.*`, `${BRAND_NS.section}[status=draft]`],
4411
- detail: "Open proposals and unapproved sections are review state, not published brand content."
4412
- },
4413
- {
4414
- kind: "brand.assets",
4415
- id: book.slug,
4416
- reason: "provider_identity",
4417
- paths: [`${BRAND_NS.asset}.storageObjectId`, `${BRAND_NS.asset}.path`, `${BRAND_NS.asset}.*AuthorityRef`],
4418
- detail: "Stored files and provider object identities require a separate asset-transfer contract."
4419
- },
4420
- {
4421
- kind: "brand.authority",
4422
- id: book.slug,
4423
- reason: "authority_history",
4424
- paths: [`${BRAND_NS.approvalReceipt}.*`, `${BRAND_NS.palette}.audience`],
4425
- detail: "Authority rows stay immutable in their source environment; artifacts retain only receipt digests and ids."
4426
- }
4427
- ];
4428
- function exportBrandPromotion(input) {
4429
- const { book } = input;
4430
- if (book.status !== "active") throw new TypeError(`brand book ${book.slug} is not active`);
4431
- const revision = `brand:${book.slug}:${book.activationRevision}`;
4432
- const artifacts = [];
4433
- if (book.tokens) {
4434
- const {
4435
- compiledAt: _compiledAt,
4436
- paletteReceiptId,
4437
- paletteActionDigest,
4438
- typographyReceiptId,
4439
- typographyActionDigest,
4440
- sourceDigest,
4441
- ...stableTokens
4442
- } = book.tokens;
4443
- artifacts.push({
4444
- kind: "brand.tokens",
4445
- id: book.slug,
4446
- sourceRevision: revision,
4447
- provenance: provenance(
4448
- [book.id, book.tokens.paletteId, paletteReceiptId, typographyReceiptId].filter((value) => Boolean(value)),
4449
- [sourceDigest, paletteActionDigest, typographyActionDigest].filter((value) => Boolean(value))
4450
- ),
4451
- content: canonicalPromotionValue({ bookSlug: book.slug, tokens: stableTokens })
4452
- });
4453
- }
4454
- for (const section of input.sections.filter((row) => row.bookId === book.id && row.status === "approved")) {
4455
- if (!section.approvalReceiptId || !section.approvalActionDigest) {
4456
- throw new TypeError(`approved brand section ${section.key} lacks approval provenance`);
4457
- }
4458
- artifacts.push({
4459
- kind: "brand.section",
4460
- id: `${book.slug}/${section.kind}`,
4461
- sourceRevision: revision,
4462
- provenance: provenance([book.id, section.id, section.approvalReceiptId], [section.approvalActionDigest]),
4463
- content: canonicalPromotionValue({ bookSlug: book.slug, kind: section.kind, content: section.content })
4464
- });
4465
- }
4466
- const activePalette2 = input.palettes.find((row) => row.bookId === book.id && row.id === book.activePaletteId && row.status === "active");
4467
- if (book.activePaletteId && !activePalette2) throw new TypeError(`active palette ${book.activePaletteId} is unavailable`);
4468
- if (activePalette2) {
4469
- artifacts.push({
4470
- kind: "brand.palette",
4471
- id: `${book.slug}/${activePalette2.id}`,
4472
- sourceRevision: revision,
4473
- provenance: provenance([book.id, activePalette2.id, activePalette2.proposalId, activePalette2.approvalReceiptId], [activePalette2.approvalActionDigest]),
4474
- content: canonicalPromotionValue({
4475
- bookSlug: book.slug,
4476
- name: activePalette2.name,
4477
- swatches: activePalette2.swatches,
4478
- source: activePalette2.source,
4479
- ...activePalette2.seedHex ? { seedHex: activePalette2.seedHex } : {},
4480
- ...activePalette2.rationale ? { rationale: activePalette2.rationale } : {}
4481
- })
4482
- });
4483
- }
4484
- return {
4485
- adapter: BRAND_PROMOTION_ADAPTER,
4486
- artifacts,
4487
- exclusions: exclusions(book),
4488
- preconditions: [{
4489
- code: "brand.schema",
4490
- path: "services.brand.schemaVersion",
4491
- expected: 1,
4492
- detail: "The target must expose the Brand v1 approved-content schema."
4493
- }]
4494
- };
4495
- }
4496
4939
  export {
4497
4940
  ASSET_CONTENT_TYPES,
4498
4941
  ASSET_KINDS,
@@ -4545,6 +4988,7 @@ export {
4545
4988
  SECTION_STATUSES,
4546
4989
  SWATCH_ROLES,
4547
4990
  acceptProposalOps,
4991
+ activationReceiptAsWritten,
4548
4992
  adjustLightnessUntil,
4549
4993
  analogous,
4550
4994
  assertAnalysis,
@@ -4661,6 +5105,7 @@ export {
4661
5105
  triadic,
4662
5106
  updateBookOps,
4663
5107
  upsertSectionOps,
5108
+ verifyBrandActivationReceipt,
4664
5109
  verifyBrandApprovalReceipt
4665
5110
  };
4666
5111
  //# sourceMappingURL=index.js.map