Tactical Media Broadcast Hub — initial release
Self-hosted multi-platform broadcast newsroom for activist collectives: publishing pipeline with group approval and DST-proof scheduling, TweetDeck-style column wall with hostile-content-safe rendering, live control room with Auto Director, bridged chat governance with polls and quorum, distributed sandboxed transcode workers, encrypted content-addressed archive, monthly analytics. MIT licensed. See README.md and docs/.
This commit is contained in:
commit
aa5e262f3a
880 changed files with 111042 additions and 0 deletions
17
packages/publishing-execution/src/approval.test.ts
Normal file
17
packages/publishing-execution/src/approval.test.ts
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
import { publishingIdempotencyKey } from "@tactical-media-broadcast-hub/core";
|
||||
import { canonicalPostHash } from "./approval.js";
|
||||
describe("approval and attempt identity", () => {
|
||||
it("sorts nested keys, excludes execution metadata, and preserves target and array order", () => {
|
||||
const post = { text: "hi", mediaAssetIds: ["a", "b"], providerMetadata: { connectionId: "target", nested: { z: 2, a: 1 } } };
|
||||
const reordered = { providerMetadata: { nested: { a: 1, z: 2 }, connectionId: "target", draftId: "injected", idempotencyKey: "key" }, mediaAssetIds: ["a", "b"], text: "hi" };
|
||||
expect(canonicalPostHash(post)).toBe(canonicalPostHash(reordered));
|
||||
expect(canonicalPostHash(post)).not.toBe(canonicalPostHash({ ...post, mediaAssetIds: ["b", "a"] }));
|
||||
expect(canonicalPostHash(post)).not.toBe(canonicalPostHash({ ...post, providerMetadata: { ...post.providerMetadata, connectionId: "other" } }));
|
||||
});
|
||||
it("uses decimal bigint attempts without precision loss", () => {
|
||||
expect(publishingIdempotencyKey({ workspaceId: "ws", draftId: "draft", attemptNo: "9007199254740993" })).toBe("wp3:ws:draft:a9007199254740993:publish");
|
||||
expect(() => publishingIdempotencyKey({ workspaceId: "ws", draftId: "draft", attemptNo: Number.MAX_SAFE_INTEGER + 1 })).toThrow();
|
||||
for (const attemptNo of ["0", "01", "-1", "1.1"]) expect(() => publishingIdempotencyKey({ workspaceId: "ws", draftId: "draft", attemptNo })).toThrow();
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue