@odla-ai/brand 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +101 -50
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +28 -1
- package/dist/index.d.ts +28 -1
- package/dist/index.js +101 -50
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -153,11 +153,13 @@ __export(src_exports, {
|
|
|
153
153
|
parseDesignBundle: () => parseDesignBundle,
|
|
154
154
|
parseHex: () => parseHex,
|
|
155
155
|
pickTextOn: () => pickTextOn,
|
|
156
|
+
proposalAsWritten: () => proposalAsWritten,
|
|
156
157
|
proposalReviewSnapshot: () => proposalReviewSnapshot,
|
|
157
158
|
proposePaletteOps: () => proposePaletteOps,
|
|
158
159
|
proposeSectionOps: () => proposeSectionOps,
|
|
159
160
|
readDesignManifest: () => readDesignManifest,
|
|
160
161
|
readTools: () => readTools,
|
|
162
|
+
receiptAsWritten: () => receiptAsWritten,
|
|
161
163
|
recordAnalysisOps: () => recordAnalysisOps,
|
|
162
164
|
rejectProposalOps: () => rejectProposalOps,
|
|
163
165
|
relativeLuminance: () => relativeLuminance,
|
|
@@ -167,6 +169,7 @@ __export(src_exports, {
|
|
|
167
169
|
rgbToHsl: () => rgbToHsl,
|
|
168
170
|
rgbToOklab: () => rgbToOklab,
|
|
169
171
|
rotateHue: () => rotateHue,
|
|
172
|
+
rowAsWritten: () => rowAsWritten,
|
|
170
173
|
safeFileName: () => safeFileName,
|
|
171
174
|
scanCustomProperties: () => scanCustomProperties,
|
|
172
175
|
sectionKey: () => sectionKey,
|
|
@@ -286,24 +289,6 @@ var BrandReviewStateChangedError = class extends BrandConflictError {
|
|
|
286
289
|
}
|
|
287
290
|
};
|
|
288
291
|
|
|
289
|
-
// src/deps.ts
|
|
290
|
-
async function defaultFetchBytes(url) {
|
|
291
|
-
const res = await fetch(url);
|
|
292
|
-
if (!res.ok) throw new Error(`asset fetch failed: ${res.status} for ${url}`);
|
|
293
|
-
return {
|
|
294
|
-
bytes: new Uint8Array(await res.arrayBuffer()),
|
|
295
|
-
contentType: res.headers.get("content-type") ?? "application/octet-stream"
|
|
296
|
-
};
|
|
297
|
-
}
|
|
298
|
-
function resolveDeps(deps) {
|
|
299
|
-
return {
|
|
300
|
-
db: deps.db,
|
|
301
|
-
now: deps.now ?? Date.now,
|
|
302
|
-
newId: deps.newId ?? (() => crypto.randomUUID()),
|
|
303
|
-
fetchBytes: deps.fetchBytes ?? defaultFetchBytes
|
|
304
|
-
};
|
|
305
|
-
}
|
|
306
|
-
|
|
307
292
|
// src/schema.ts
|
|
308
293
|
var a = (type, o = {}) => ({
|
|
309
294
|
type,
|
|
@@ -490,6 +475,70 @@ var BRAND_SCHEMA = {
|
|
|
490
475
|
}
|
|
491
476
|
};
|
|
492
477
|
|
|
478
|
+
// src/read-shape.ts
|
|
479
|
+
var record = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
480
|
+
var DATE_FIELDS = /* @__PURE__ */ new Map();
|
|
481
|
+
for (const [ns, entity] of Object.entries(BRAND_SCHEMA.entities))
|
|
482
|
+
DATE_FIELDS.set(
|
|
483
|
+
ns,
|
|
484
|
+
new Set(
|
|
485
|
+
Object.entries(entity.attrs).filter(([, attr]) => attr.type === "date").map(([label]) => label)
|
|
486
|
+
)
|
|
487
|
+
);
|
|
488
|
+
function rowAsWritten(ns, row) {
|
|
489
|
+
const dates = DATE_FIELDS.get(ns);
|
|
490
|
+
if (!dates?.size || !record(row)) return row;
|
|
491
|
+
let changed = false;
|
|
492
|
+
const out = { ...row };
|
|
493
|
+
for (const field of dates) {
|
|
494
|
+
const value = out[field];
|
|
495
|
+
if (typeof value !== "string") continue;
|
|
496
|
+
const parsed = Date.parse(value);
|
|
497
|
+
if (!Number.isSafeInteger(parsed) || parsed < 0) continue;
|
|
498
|
+
out[field] = parsed;
|
|
499
|
+
changed = true;
|
|
500
|
+
}
|
|
501
|
+
return changed ? out : row;
|
|
502
|
+
}
|
|
503
|
+
function receiptAsWritten(row) {
|
|
504
|
+
return rowAsWritten(BRAND_NS.approvalReceipt, row);
|
|
505
|
+
}
|
|
506
|
+
function proposalAsWritten(row) {
|
|
507
|
+
return rowAsWritten(BRAND_NS.proposal, row);
|
|
508
|
+
}
|
|
509
|
+
function resultAsWritten(result) {
|
|
510
|
+
const out = { ...result };
|
|
511
|
+
for (const [ns, rows] of Object.entries(out)) {
|
|
512
|
+
if (Array.isArray(rows)) out[ns] = rows.map((row) => rowAsWritten(ns, row));
|
|
513
|
+
}
|
|
514
|
+
return out;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
// src/deps.ts
|
|
518
|
+
async function defaultFetchBytes(url) {
|
|
519
|
+
const res = await fetch(url);
|
|
520
|
+
if (!res.ok) throw new Error(`asset fetch failed: ${res.status} for ${url}`);
|
|
521
|
+
return {
|
|
522
|
+
bytes: new Uint8Array(await res.arrayBuffer()),
|
|
523
|
+
contentType: res.headers.get("content-type") ?? "application/octet-stream"
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
function readingAsWritten(db) {
|
|
527
|
+
return {
|
|
528
|
+
query: async (q) => resultAsWritten(await db.query(q)),
|
|
529
|
+
transact: (ops, opts) => db.transact(ops, opts),
|
|
530
|
+
storage: db.storage
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
function resolveDeps(deps) {
|
|
534
|
+
return {
|
|
535
|
+
db: readingAsWritten(deps.db),
|
|
536
|
+
now: deps.now ?? Date.now,
|
|
537
|
+
newId: deps.newId ?? (() => crypto.randomUUID()),
|
|
538
|
+
fetchBytes: deps.fetchBytes ?? defaultFetchBytes
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
|
|
493
542
|
// src/rules.ts
|
|
494
543
|
var CURRENT_BOOK_MEMBER = "ref('book.memberIds').exists(members, auth.id in members)";
|
|
495
544
|
var BRAND_RULES = {
|
|
@@ -691,7 +740,7 @@ function assertAnalysis(value) {
|
|
|
691
740
|
}
|
|
692
741
|
|
|
693
742
|
// src/review-json.ts
|
|
694
|
-
var
|
|
743
|
+
var record2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value) && (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null);
|
|
695
744
|
function isBoundedBrandJson(root, limits = {}) {
|
|
696
745
|
const maxDepth = limits.maxDepth ?? 12;
|
|
697
746
|
const maxNodes = limits.maxNodes ?? 2048;
|
|
@@ -715,7 +764,7 @@ function isBoundedBrandJson(root, limits = {}) {
|
|
|
715
764
|
if (Array.isArray(value)) {
|
|
716
765
|
for (const child of value)
|
|
717
766
|
stack.push({ value: child, depth: depth + 1 });
|
|
718
|
-
} else if (
|
|
767
|
+
} else if (record2(value)) {
|
|
719
768
|
for (const child of Object.values(value))
|
|
720
769
|
stack.push({ value: child, depth: depth + 1 });
|
|
721
770
|
} else {
|
|
@@ -752,7 +801,7 @@ async function brandJsonDigest(value) {
|
|
|
752
801
|
|
|
753
802
|
// src/review.ts
|
|
754
803
|
var DIGEST = /^sha256:[0-9a-f]{64}$/;
|
|
755
|
-
var
|
|
804
|
+
var record3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value) && (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null);
|
|
756
805
|
var exactKeys = (value, required, optional = []) => {
|
|
757
806
|
const allowed = /* @__PURE__ */ new Set([...required, ...optional]);
|
|
758
807
|
return required.every((key) => Object.hasOwn(value, key)) && Object.keys(value).every((key) => allowed.has(key));
|
|
@@ -777,15 +826,15 @@ var SNAPSHOT_REQUIRED = [
|
|
|
777
826
|
"createdAt"
|
|
778
827
|
];
|
|
779
828
|
function validSnapshotShape(value) {
|
|
780
|
-
if (!
|
|
829
|
+
if (!record3(value) || !exactKeys(value, SNAPSHOT_REQUIRED)) return false;
|
|
781
830
|
const provenance = value.provenance;
|
|
782
|
-
return boundedString(value.id) && boundedString(value.bookId) && typeof value.kind === "string" && PROPOSAL_KINDS.includes(value.kind) && value.status === "open" &&
|
|
831
|
+
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(provenance) && exactKeys(provenance, [
|
|
783
832
|
"sourceAssetId",
|
|
784
833
|
"sourceAsset",
|
|
785
834
|
"messageId",
|
|
786
835
|
"turnId",
|
|
787
836
|
"taintLabels"
|
|
788
|
-
]) && (provenance.sourceAssetId === null || boundedString(provenance.sourceAssetId)) && (provenance.sourceAsset === null ||
|
|
837
|
+
]) && (provenance.sourceAssetId === null || boundedString(provenance.sourceAssetId)) && (provenance.sourceAsset === null || record3(provenance.sourceAsset) && exactKeys(provenance.sourceAsset, [
|
|
789
838
|
"assetId",
|
|
790
839
|
"contentDigest",
|
|
791
840
|
"objectEtag",
|
|
@@ -818,8 +867,8 @@ var CONSUMPTION_REQUIRED = [
|
|
|
818
867
|
"consumedAt"
|
|
819
868
|
];
|
|
820
869
|
function isBrandHumanAuthorityConsumption(value) {
|
|
821
|
-
if (!
|
|
822
|
-
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) &&
|
|
870
|
+
if (!record3(value) || !exactKeys(value, CONSUMPTION_REQUIRED)) return false;
|
|
871
|
+
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);
|
|
823
872
|
}
|
|
824
873
|
var RECEIPT_REQUIRED = [
|
|
825
874
|
"version",
|
|
@@ -845,10 +894,10 @@ async function verifyBrandApprovalReceipt(receipt2) {
|
|
|
845
894
|
try {
|
|
846
895
|
if (!isBoundedBrandJson(receipt2, { maxDepth: 14, maxNodes: 2500, maxBytes: 48 * 1024 }))
|
|
847
896
|
return false;
|
|
848
|
-
if (!
|
|
897
|
+
if (!record3(receipt2) || !exactKeys(receipt2, RECEIPT_REQUIRED, ["paletteId", "resolutionNote"]))
|
|
849
898
|
return false;
|
|
850
899
|
const binding = receipt2.decisionBinding;
|
|
851
|
-
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) || !
|
|
900
|
+
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, [
|
|
852
901
|
"version",
|
|
853
902
|
"bookVersion",
|
|
854
903
|
"activationRevision",
|
|
@@ -3568,7 +3617,7 @@ async function linkedAsset(ctx, book, assetId, allowDeleting = false) {
|
|
|
3568
3617
|
book: {}
|
|
3569
3618
|
}
|
|
3570
3619
|
});
|
|
3571
|
-
const row = (result[BRAND_NS.asset] ?? [])[0];
|
|
3620
|
+
const row = rowAsWritten(BRAND_NS.asset, (result[BRAND_NS.asset] ?? [])[0]);
|
|
3572
3621
|
const links = row?.book;
|
|
3573
3622
|
if (!row || row.bookId !== book.id || !Array.isArray(links) || links.length !== 1 || links[0]?.id !== book.id || row.status !== "live" && !(allowDeleting && row.status === "deleting")) throw new BrandNotFoundError(`asset ${assetId}`);
|
|
3574
3623
|
return row;
|
|
@@ -3642,7 +3691,7 @@ async function loadBook(db, bookId) {
|
|
|
3642
3691
|
const res = await db.query({ [BRAND_NS.book]: { $: { where: { id: bookId } } } });
|
|
3643
3692
|
const row = (res[BRAND_NS.book] ?? [])[0];
|
|
3644
3693
|
if (!row) throw new BrandNotFoundError(`brand book ${bookId}`);
|
|
3645
|
-
return row;
|
|
3694
|
+
return rowAsWritten(BRAND_NS.book, row);
|
|
3646
3695
|
}
|
|
3647
3696
|
async function loadMemberBook(db, bookId, actorId) {
|
|
3648
3697
|
const book = await loadBook(db, bookId);
|
|
@@ -3697,14 +3746,14 @@ async function uploadAsset(ctx, req, bookId) {
|
|
|
3697
3746
|
"internal",
|
|
3698
3747
|
book.id
|
|
3699
3748
|
);
|
|
3700
|
-
const
|
|
3749
|
+
const record7 = await ctx.db.storage.upload(
|
|
3701
3750
|
path,
|
|
3702
3751
|
file,
|
|
3703
3752
|
contentType,
|
|
3704
3753
|
{ private: true }
|
|
3705
3754
|
);
|
|
3706
|
-
if (
|
|
3707
|
-
await ctx.db.storage.delete(
|
|
3755
|
+
if (record7.path !== path) {
|
|
3756
|
+
await ctx.db.storage.delete(record7.path);
|
|
3708
3757
|
throw new BrandConflictError(
|
|
3709
3758
|
"private storage returned an unexpected asset path"
|
|
3710
3759
|
);
|
|
@@ -3723,11 +3772,11 @@ async function uploadAsset(ctx, req, bookId) {
|
|
|
3723
3772
|
id,
|
|
3724
3773
|
bookId: book.id,
|
|
3725
3774
|
kind,
|
|
3726
|
-
path:
|
|
3727
|
-
storageObjectId:
|
|
3775
|
+
path: record7.path,
|
|
3776
|
+
storageObjectId: record7.id,
|
|
3728
3777
|
contentDigest: await contentDigest(file),
|
|
3729
3778
|
contentType,
|
|
3730
|
-
size:
|
|
3779
|
+
size: record7.size,
|
|
3731
3780
|
uploadedBy: ctx.actor.id,
|
|
3732
3781
|
uploadedAuthorityRef: authority.authorityRef,
|
|
3733
3782
|
audience: book.memberIds,
|
|
@@ -3754,7 +3803,7 @@ async function uploadAsset(ctx, req, bookId) {
|
|
|
3754
3803
|
asPrincipalKind: "human"
|
|
3755
3804
|
});
|
|
3756
3805
|
} catch (error) {
|
|
3757
|
-
await ctx.db.storage.delete(
|
|
3806
|
+
await ctx.db.storage.delete(record7.path);
|
|
3758
3807
|
throw error;
|
|
3759
3808
|
}
|
|
3760
3809
|
return json(await linkedAsset(ctx, book, id), 201);
|
|
@@ -3869,7 +3918,7 @@ async function handleAssetItem(ctx, req, bookId, assetId) {
|
|
|
3869
3918
|
async function handleBooksRoot(ctx, req) {
|
|
3870
3919
|
if (req.method === "GET") {
|
|
3871
3920
|
const res = await ctx.db.query({ [BRAND_NS.book]: { $: { order: { createdAt: "asc" } } } });
|
|
3872
|
-
const books = (res[BRAND_NS.book] ?? []).filter(
|
|
3921
|
+
const books = (res[BRAND_NS.book] ?? []).map((b) => rowAsWritten(BRAND_NS.book, b)).filter(
|
|
3873
3922
|
(b) => isMember(b, ctx.actor.id)
|
|
3874
3923
|
);
|
|
3875
3924
|
return json({ books });
|
|
@@ -4034,7 +4083,7 @@ var SNAPSHOT_KEYS = [
|
|
|
4034
4083
|
"reviewDigest",
|
|
4035
4084
|
"status"
|
|
4036
4085
|
];
|
|
4037
|
-
var
|
|
4086
|
+
var record4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4038
4087
|
function parseProposalResolutionRequest(body, bookId, proposalId) {
|
|
4039
4088
|
const allowed = /* @__PURE__ */ new Set([
|
|
4040
4089
|
"mutationId",
|
|
@@ -4078,13 +4127,13 @@ function proposalReviewSnapshot(proposal) {
|
|
|
4078
4127
|
function parseReviewedProposal(value, bookId, proposalId) {
|
|
4079
4128
|
if (!isBoundedBrandJson(value, { maxDepth: 12, maxNodes: 1500, maxBytes: 32 * 1024 }))
|
|
4080
4129
|
throw new BrandInputError('"reviewedProposal" is too deeply nested, complex, or large');
|
|
4081
|
-
if (!
|
|
4130
|
+
if (!record4(value)) throw new BrandInputError('"reviewedProposal" must be an object');
|
|
4082
4131
|
const keys = Object.keys(value).sort();
|
|
4083
4132
|
if (keys.length !== SNAPSHOT_KEYS.length || !SNAPSHOT_KEYS.every((key, index) => key === keys[index])) throw new BrandInputError('"reviewedProposal" has an invalid shape');
|
|
4084
4133
|
if (value.id !== proposalId || value.bookId !== bookId || value.status !== "open")
|
|
4085
4134
|
throw new BrandInputError('"reviewedProposal" must identify this open proposal');
|
|
4086
|
-
if (typeof value.kind !== "string" || !PROPOSAL_KINDS.includes(value.kind) || !
|
|
4087
|
-
if (!
|
|
4135
|
+
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');
|
|
4136
|
+
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(
|
|
4088
4137
|
value.provenance.sourceAsset.analysisDigest
|
|
4089
4138
|
)) || 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');
|
|
4090
4139
|
return value;
|
|
@@ -4257,7 +4306,7 @@ async function proposalReceiptByMutation(ctx, mutationKey) {
|
|
|
4257
4306
|
const row = (result[BRAND_NS.approvalReceipt] ?? [])[0];
|
|
4258
4307
|
if (!row || !Array.isArray(row.book) || row.book.length !== 1 || row.book[0]?.id !== row.bookId) return void 0;
|
|
4259
4308
|
const { book: _book, ...receipt2 } = row;
|
|
4260
|
-
return receipt2;
|
|
4309
|
+
return receiptAsWritten(receipt2);
|
|
4261
4310
|
}
|
|
4262
4311
|
async function consumeProposalAuthority(ctx, req, bookId, proposalId, actionDigest, mutationKey) {
|
|
4263
4312
|
const authority = await ctx.consumeHumanExact({
|
|
@@ -4291,7 +4340,8 @@ async function receipt(ctx, id, actionDigest, expected) {
|
|
|
4291
4340
|
});
|
|
4292
4341
|
const row = (result[BRAND_NS.approvalReceipt] ?? [])[0];
|
|
4293
4342
|
if (!row || row.actionDigest !== actionDigest || row.resolution !== "accepted" || row.bookId !== expected.bookId || row.reviewedProposal.bookId !== expected.bookId || row.reviewedProposal.kind !== expected.kind || !Array.isArray(row.book) || row.book.length !== 1 || row.book[0]?.id !== 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`);
|
|
4294
|
-
const { book: _book, ...
|
|
4343
|
+
const { book: _book, ...stored } = row;
|
|
4344
|
+
const unhydrated = receiptAsWritten(stored);
|
|
4295
4345
|
if (!await verifyBrandApprovalReceipt(unhydrated))
|
|
4296
4346
|
throw new BrandConflictError(`approval receipt ${id} is invalid`);
|
|
4297
4347
|
return unhydrated;
|
|
@@ -4529,9 +4579,9 @@ async function proposalDecisionState(ctx, req, book, proposal, resolution, recei
|
|
|
4529
4579
|
}
|
|
4530
4580
|
|
|
4531
4581
|
// src/routes/proposals.ts
|
|
4532
|
-
var
|
|
4582
|
+
var record5 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4533
4583
|
var sameStrings2 = (left, right) => left.length === right.length && left.every((value, index) => value === right[index]);
|
|
4534
|
-
var guardFailure2 = (error) =>
|
|
4584
|
+
var guardFailure2 = (error) => record5(error) && error.code === "transact_guard_failed";
|
|
4535
4585
|
async function handleProposalResolution(ctx, req, bookId, proposalId) {
|
|
4536
4586
|
if (req.method !== "POST") return methodNotAllowed();
|
|
4537
4587
|
const book = await loadMemberBook(ctx.db, bookId, ctx.actor.id);
|
|
@@ -4578,7 +4628,7 @@ async function handleProposalResolution(ctx, req, bookId, proposalId) {
|
|
|
4578
4628
|
book: {}
|
|
4579
4629
|
}
|
|
4580
4630
|
});
|
|
4581
|
-
const proposal = (result[BRAND_NS.proposal] ?? [])[0];
|
|
4631
|
+
const proposal = proposalAsWritten((result[BRAND_NS.proposal] ?? [])[0]);
|
|
4582
4632
|
if (!proposal || proposal.bookId !== book.id || !Array.isArray(proposal.book) || proposal.book.length !== 1 || proposal.book[0]?.id !== book.id) throw new BrandNotFoundError(`proposal ${proposalId}`);
|
|
4583
4633
|
const current = proposalReviewSnapshot(proposal);
|
|
4584
4634
|
const { reviewDigest, ...unsignedReview } = current;
|
|
@@ -4711,7 +4761,7 @@ async function handleProposalResolution(ctx, req, bookId, proposalId) {
|
|
|
4711
4761
|
}
|
|
4712
4762
|
|
|
4713
4763
|
// src/routes/tokens.ts
|
|
4714
|
-
var
|
|
4764
|
+
var record6 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4715
4765
|
var missing = (bookId) => {
|
|
4716
4766
|
throw new BrandNotFoundError(`compiled tokens for brand book ${bookId}`);
|
|
4717
4767
|
};
|
|
@@ -4724,13 +4774,14 @@ async function acceptedReceipt(db, bookId, receiptId, actionDigest) {
|
|
|
4724
4774
|
});
|
|
4725
4775
|
const receipt2 = (result[BRAND_NS.approvalReceipt] ?? [])[0];
|
|
4726
4776
|
if (!receipt2 || receipt2.resolution !== "accepted" || receipt2.actionDigest !== actionDigest || !Array.isArray(receipt2.book) || receipt2.book.length !== 1 || receipt2.book[0]?.id !== bookId) return missing(bookId);
|
|
4727
|
-
const { book: _book, ...
|
|
4777
|
+
const { book: _book, ...stored } = receipt2;
|
|
4778
|
+
const unhydrated = receiptAsWritten(stored);
|
|
4728
4779
|
if (!await verifyBrandApprovalReceipt(unhydrated)) return missing(bookId);
|
|
4729
4780
|
return unhydrated;
|
|
4730
4781
|
}
|
|
4731
4782
|
async function approvedCache(db, book) {
|
|
4732
4783
|
const cache = book.tokens;
|
|
4733
|
-
if (!cache || !
|
|
4784
|
+
if (!cache || !record6(cache.light) || !record6(cache.dark) || !book.activePaletteId || cache.paletteId !== book.activePaletteId || !cache.paletteReceiptId || !cache.paletteActionDigest || !cache.sourceDigest) return missing(book.id);
|
|
4734
4785
|
const paletteResult = await db.query({
|
|
4735
4786
|
[BRAND_NS.palette]: {
|
|
4736
4787
|
$: { where: { id: cache.paletteId, bookId: book.id } },
|