mirror of
https://github.com/profullstack/logicsrc.git
synced 2026-10-02 20:57:03 +00:00
feat(agentad): AgentAd Marketplace PRD + reference exchange (M5)
Add the AgentBBS M5 "AgentAd marketplace" spec and a working reference
implementation built on the existing @logicsrc/schemas AgentAd contracts.
- docs/agentad-marketplace.md: two-sided exchange PRD (buy/sell sides,
match -> auction -> pace -> serve -> meter -> settle, CoinPay settlement,
AgentBBS as reference publisher, milestones M5.0-M5.5).
- packages/agentad (@logicsrc/agentad): reference exchange
- builders that emit schema-valid, always-disclosed ad/campaign/placement docs
- HMAC-signed, single-use impression/click tracking tokens
- AgentAdExchange: targeting/format/category matching, second-price auction,
budget pacing + daily caps, frequency capping, token-driven metering
- pluggable settlement (InMemorySettlement) that can't overspend escrow
- runtime validation against the canonical agentad-*.schema.json
- 22 vitest cases (builders, tokens, full serve/meter/settle lifecycle).
- Wire package into root build; link the PRD from README + docs/agentad.md.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
0bca203527
commit
7d62e3b661
18 changed files with 1862 additions and 2 deletions
49
packages/agentad/src/tokens.test.ts
Normal file
49
packages/agentad/src/tokens.test.ts
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
import { mintToken, verifyToken, type TokenPayload } from "./tokens.js";
|
||||
|
||||
const base: TokenPayload = {
|
||||
k: "impression",
|
||||
rid: "req-1",
|
||||
pid: "plc-1",
|
||||
aid: "ad-1",
|
||||
cid: "cmp-1",
|
||||
model: "cpc",
|
||||
charge: 0.5,
|
||||
cur: "USD",
|
||||
exp: 2_000_000_000_000,
|
||||
n: "abc123"
|
||||
};
|
||||
|
||||
describe("AgentAd tracking tokens", () => {
|
||||
it("round-trips a signed payload", () => {
|
||||
const token = mintToken("s3cret", base);
|
||||
const result = verifyToken("s3cret", token, 1_000);
|
||||
expect(result.ok).toBe(true);
|
||||
expect(result.payload).toEqual(base);
|
||||
});
|
||||
|
||||
it("rejects a token signed with a different secret", () => {
|
||||
const token = mintToken("s3cret", base);
|
||||
const result = verifyToken("other", token, 1_000);
|
||||
expect(result.ok).toBe(false);
|
||||
expect(result.reason).toBe("bad_signature");
|
||||
});
|
||||
|
||||
it("rejects a tampered body", () => {
|
||||
const token = mintToken("s3cret", base);
|
||||
const [, sig] = token.split(".");
|
||||
const forged = `${Buffer.from(JSON.stringify({ ...base, charge: 9999 })).toString("base64url")}.${sig}`;
|
||||
expect(verifyToken("s3cret", forged).ok).toBe(false);
|
||||
});
|
||||
|
||||
it("rejects expired tokens", () => {
|
||||
const token = mintToken("s3cret", { ...base, exp: 500 });
|
||||
const result = verifyToken("s3cret", token, 1_000);
|
||||
expect(result.ok).toBe(false);
|
||||
expect(result.reason).toBe("expired");
|
||||
});
|
||||
|
||||
it("flags malformed tokens", () => {
|
||||
expect(verifyToken("s3cret", "not-a-token").reason).toBe("malformed");
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue