@imagxp/protocol 1.0.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/README.md ADDED
@@ -0,0 +1,103 @@
1
+ # @imagxp/protocol
2
+
3
+ The official TypeScript reference implementation of the **Identity Monetization Auto Governance Exchange Protocol (IMAGXP)**.
4
+
5
+ IMAGXP is an open standard that enables "Transactional Content Negotiation" between AI Agents and Web Publishers, replacing `robots.txt` with cryptographic signatures and micro-payments.
6
+
7
+ **Keywords:** `imagxp`, `aamp`, `protocol`, `ai agent`, `web monetization`, `content negotiation`, `rag`, `llm`, `crawler`, `publisher tool`
8
+
9
+ **Website:** https://imagxp.com (Coming Soon)
10
+ **Repository:** [GitHub](https://github.com/imagxp-protocol/imagxp)
11
+
12
+ ## 📦 Installation
13
+
14
+ ```bash
15
+ npm install @imagxp/protocol
16
+ # Optional: Install 'jose' for crypto signing if you are building a custom implementation
17
+ npm install jose
18
+ ```
19
+
20
+ ## 🚀 Usage
21
+
22
+ ### 1. For AI Agents (Clients)
23
+
24
+ Use `IMAGXPAgent` to crawl websites with automatic protocol negotiation.
25
+
26
+ ```typescript
27
+ import { IMAGXPAgent } from '@imagxp/protocol';
28
+
29
+ async function main() {
30
+ // 1. Initialize Identity (Loads from IMAGXP_PRIVATE_KEY env var)
31
+ const agent = await IMAGXPAgent.init();
32
+
33
+ // 2. Fetch URL (Automatically signs request if IMAGXP is detected)
34
+ const response = await agent.fetch('https://example.com/article', {
35
+ purpose: 'RAG_RETRIEVAL'
36
+ });
37
+
38
+ if (response.status === 200) {
39
+ console.log('Success:', response.data);
40
+ } else {
41
+ console.error('Blocked:', response.status);
42
+ }
43
+ }
44
+ ```
45
+
46
+ ### 2. For Publishers (Next.js Middleware)
47
+
48
+ Use `IMAGXPNext` to protect your routes.
49
+
50
+ ```typescript
51
+ // src/middleware.ts
52
+ import { IMAGXPNext } from '@imagxp/protocol';
53
+ import { NextResponse } from 'next/server';
54
+
55
+ const imagxp = IMAGXPNext.init({
56
+ meta: {
57
+ origin: 'HUMAN',
58
+ paymentPointer: '$wallet.example.com'
59
+ },
60
+ policy: {
61
+ // Security: Verify DNS Binding
62
+ requireIdentityBinding: true,
63
+
64
+ // Economics: Connect to Broker
65
+ monetization: {
66
+ brokerUrl: "https://broker.imagxp.network"
67
+ }
68
+ }
69
+ });
70
+
71
+ // Create the middleware handler
72
+ export const middleware = imagxp.withProtection(async (req) => {
73
+ return NextResponse.next();
74
+ });
75
+
76
+ export const config = {
77
+ matcher: ['/api/premium/:path*', '/articles/:path*']
78
+ };
79
+ ```
80
+
81
+ ## 🔑 Key Features
82
+
83
+ - **Zero Dependencies:** The core logic is dependency-free.
84
+ - **Isomorphic:** Works in Node.js, Edge Runtime (Vercel/Cloudflare), and Browsers.
85
+ - **Cryptographically Secure:** Implements ECDSA P-256 signatures and JSON Web Tokens.
86
+ - **Type Safe:** Written in strict TypeScript with full definition files included.
87
+
88
+ ## 📚 API Reference
89
+
90
+ ### `IMAGXPAgent`
91
+ - `init(options?)`: Create a new agent instance.
92
+ - `fetch(url, options)`: IMAGXP-aware fetch wrapper.
93
+ - `sendFeedback(url, feedback)`: Send Quality/Spam reports.
94
+
95
+ ### `IMAGXPNext` (Adapter)
96
+ - `init(config)`: Configure the Publisher Policy Engine.
97
+ - `withProtection(handler)`: Wrap a Next.js Middleware or Route Handler.
98
+
99
+ ## 📄 License
100
+
101
+ Apache 2.0
102
+
103
+ By the IMAGXP Community.
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Layer 2: Agent SDK
3
+ */
4
+ import { AccessPurpose, SignedAccessRequest, FeedbackSignal, QualityFlag, AgentIdentityManifest } from './types.js';
5
+ export interface AccessOptions {
6
+ adsDisplayed?: boolean;
7
+ }
8
+ export declare class IMAGXPAgent {
9
+ private keyPair;
10
+ agentId: string;
11
+ /**
12
+ * Initialize the Agent Identity (Ephemeral or Persisted)
13
+ * @param customAgentId For PRODUCTION, this should be your domain (e.g., "bot.openai.com")
14
+ */
15
+ initialize(customAgentId?: string): Promise<void>;
16
+ createAccessRequest(resource: string, purpose: AccessPurpose, options?: AccessOptions): Promise<SignedAccessRequest>;
17
+ /**
18
+ * Helper: Generate the JSON file you must host on your domain
19
+ * Host this at: https://{agentId}/.well-known/imagxp-agent.json
20
+ */
21
+ getIdentityManifest(contactEmail?: string): Promise<AgentIdentityManifest>;
22
+ /**
23
+ * NEW IN V1.1: Quality Feedback Loop
24
+ * Allows the Agent to report spam or verify quality of a resource.
25
+ */
26
+ generateFeedback(resource: string, score: number, flags: QualityFlag[]): Promise<{
27
+ signal: FeedbackSignal;
28
+ signature: string;
29
+ }>;
30
+ }
package/dist/agent.js ADDED
@@ -0,0 +1,65 @@
1
+ import { generateKeyPair, signData, exportPublicKey } from './crypto.js';
2
+ import { IMAGXP_VERSION } from './constants.js';
3
+ export class IMAGXPAgent {
4
+ constructor() {
5
+ this.keyPair = null;
6
+ this.agentId = "pending";
7
+ }
8
+ /**
9
+ * Initialize the Agent Identity (Ephemeral or Persisted)
10
+ * @param customAgentId For PRODUCTION, this should be your domain (e.g., "bot.openai.com")
11
+ */
12
+ async initialize(customAgentId) {
13
+ this.keyPair = await generateKeyPair();
14
+ // Use the provided ID (authentic) or generate a session ID (ephemeral)
15
+ this.agentId = customAgentId || "agent_" + Math.random().toString(36).substring(7);
16
+ }
17
+ async createAccessRequest(resource, purpose, options = {}) {
18
+ if (!this.keyPair)
19
+ throw new Error("Agent not initialized. Call initialize() first.");
20
+ const header = {
21
+ v: IMAGXP_VERSION,
22
+ ts: new Date().toISOString(),
23
+ agent_id: this.agentId,
24
+ resource,
25
+ purpose,
26
+ context: {
27
+ ads_displayed: options.adsDisplayed || false
28
+ }
29
+ };
30
+ const signature = await signData(this.keyPair.privateKey, JSON.stringify(header));
31
+ const publicKeyExport = await exportPublicKey(this.keyPair.publicKey);
32
+ return { header, signature, publicKey: publicKeyExport };
33
+ }
34
+ /**
35
+ * Helper: Generate the JSON file you must host on your domain
36
+ * Host this at: https://{agentId}/.well-known/imagxp-agent.json
37
+ */
38
+ async getIdentityManifest(contactEmail) {
39
+ if (!this.keyPair)
40
+ throw new Error("Agent not initialized.");
41
+ const publicKey = await exportPublicKey(this.keyPair.publicKey);
42
+ return {
43
+ agent_id: this.agentId,
44
+ public_key: publicKey,
45
+ contact_email: contactEmail
46
+ };
47
+ }
48
+ /**
49
+ * NEW IN V1.1: Quality Feedback Loop
50
+ * Allows the Agent to report spam or verify quality of a resource.
51
+ */
52
+ async generateFeedback(resource, score, flags) {
53
+ if (!this.keyPair)
54
+ throw new Error("Agent not initialized.");
55
+ const signal = {
56
+ target_resource: resource,
57
+ agent_id: this.agentId,
58
+ quality_score: Math.max(0, Math.min(1, score)),
59
+ flags,
60
+ timestamp: new Date().toISOString()
61
+ };
62
+ const signature = await signData(this.keyPair.privateKey, JSON.stringify(signal));
63
+ return { signal, signature };
64
+ }
65
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Layer 1: Protocol Constants
3
+ * These values are immutable and defined by the IMAGXP Specification.
4
+ */
5
+ export declare const IMAGXP_VERSION = "1.1";
6
+ export declare const WELL_KNOWN_AGENT_PATH = "/.well-known/imagxp-agent.json";
7
+ export declare const HEADERS: {
8
+ readonly PAYLOAD: "x-imagxp-payload";
9
+ readonly SIGNATURE: "x-imagxp-signature";
10
+ readonly PUBLIC_KEY: "x-imagxp-public-key";
11
+ readonly AGENT_ID: "x-imagxp-agent-id";
12
+ readonly TIMESTAMP: "x-imagxp-timestamp";
13
+ readonly ALGORITHM: "x-imagxp-alg";
14
+ readonly CONTENT_ORIGIN: "x-imagxp-content-origin";
15
+ readonly PROVENANCE_SIG: "x-imagxp-provenance-sig";
16
+ readonly PROOF_TOKEN: "x-imagxp-proof";
17
+ readonly PAYMENT_CREDENTIAL: "x-imagxp-credential";
18
+ readonly FEEDBACK: "x-imagxp-feedback";
19
+ };
20
+ export declare const CRYPTO_CONFIG: {
21
+ readonly ALGORITHM_NAME: "ECDSA";
22
+ readonly CURVE: "P-256";
23
+ readonly HASH: "SHA-256";
24
+ };
25
+ export declare const MAX_CLOCK_SKEW_MS: number;
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Layer 1: Protocol Constants
3
+ * These values are immutable and defined by the IMAGXP Specification.
4
+ */
5
+ export const IMAGXP_VERSION = '1.1';
6
+ // The path where Agents MUST host their public key to prove identity.
7
+ // Example: https://bot.openai.com/.well-known/imagxp-agent.json
8
+ export const WELL_KNOWN_AGENT_PATH = '/.well-known/imagxp-agent.json';
9
+ // HTTP Headers used for the handshake
10
+ export const HEADERS = {
11
+ // Transport: The signed payload (Base64 encoded JSON of ProtocolHeader)
12
+ PAYLOAD: 'x-imagxp-payload',
13
+ // Transport: The cryptographic signature (Hex)
14
+ SIGNATURE: 'x-imagxp-signature',
15
+ // Transport: The Agent's Public Key (Base64 SPKI)
16
+ PUBLIC_KEY: 'x-imagxp-public-key',
17
+ // Informational / Legacy (Optional if Payload is present)
18
+ AGENT_ID: 'x-imagxp-agent-id',
19
+ TIMESTAMP: 'x-imagxp-timestamp',
20
+ ALGORITHM: 'x-imagxp-alg',
21
+ // v1.1 Addition: Provenance (Server to Agent)
22
+ CONTENT_ORIGIN: 'x-imagxp-content-origin',
23
+ PROVENANCE_SIG: 'x-imagxp-provenance-sig',
24
+ // v1.2 Proof of Value
25
+ PROOF_TOKEN: 'x-imagxp-proof',
26
+ // v1.2 Payment Credential (The "Digital Receipt")
27
+ PAYMENT_CREDENTIAL: 'x-imagxp-credential',
28
+ // v1.2 Quality Feedback (The "Dispute Token")
29
+ FEEDBACK: 'x-imagxp-feedback'
30
+ };
31
+ // Cryptographic Settings
32
+ export const CRYPTO_CONFIG = {
33
+ ALGORITHM_NAME: 'ECDSA',
34
+ CURVE: 'P-256',
35
+ HASH: 'SHA-256',
36
+ };
37
+ // Tolerance
38
+ export const MAX_CLOCK_SKEW_MS = 5 * 60 * 1000; // 5 minutes
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Layer 1: Cryptographic Primitives
3
+ * Implementation of ECDSA P-256 signing/verification.
4
+ */
5
+ export declare function generateKeyPair(): Promise<CryptoKeyPair>;
6
+ export declare function signData(privateKey: CryptoKey, data: string): Promise<string>;
7
+ export declare function verifySignature(publicKey: CryptoKey, data: string, signatureHex: string): Promise<boolean>;
8
+ export declare function exportPublicKey(key: CryptoKey): Promise<string>;
9
+ export declare function importPublicKey(keyData: string): Promise<CryptoKey>;
package/dist/crypto.js ADDED
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Layer 1: Cryptographic Primitives
3
+ * Implementation of ECDSA P-256 signing/verification.
4
+ */
5
+ export async function generateKeyPair() {
6
+ // Uses standard Web Crypto API (Node 19+ compatible)
7
+ return await crypto.subtle.generateKey({ name: "ECDSA", namedCurve: "P-256" }, true, ["sign", "verify"]);
8
+ }
9
+ export async function signData(privateKey, data) {
10
+ const encoder = new TextEncoder();
11
+ const encoded = encoder.encode(data);
12
+ const signature = await crypto.subtle.sign({ name: "ECDSA", hash: { name: "SHA-256" } }, privateKey, encoded);
13
+ return bufToHex(signature);
14
+ }
15
+ export async function verifySignature(publicKey, data, signatureHex) {
16
+ const encoder = new TextEncoder();
17
+ const encodedData = encoder.encode(data);
18
+ const signatureBytes = hexToBuf(signatureHex);
19
+ console.log(" 🔐 [IMAGXP Crypto] Verifying ECDSA P-256 Signature...");
20
+ const isValid = await crypto.subtle.verify({ name: "ECDSA", hash: { name: "SHA-256" } }, publicKey, signatureBytes, encodedData);
21
+ console.log(` ${isValid ? "✅" : "❌"} [IMAGXP Crypto] Signature Result: ${isValid ? "VALID" : "INVALID"}`);
22
+ return isValid;
23
+ }
24
+ export async function exportPublicKey(key) {
25
+ const exported = await crypto.subtle.exportKey("spki", key);
26
+ return btoa(String.fromCharCode(...new Uint8Array(exported)));
27
+ }
28
+ export async function importPublicKey(keyData) {
29
+ const binaryString = atob(keyData);
30
+ const bytes = new Uint8Array(binaryString.length);
31
+ for (let i = 0; i < binaryString.length; i++) {
32
+ bytes[i] = binaryString.charCodeAt(i);
33
+ }
34
+ return await crypto.subtle.importKey("spki", bytes, { name: "ECDSA", namedCurve: "P-256" }, true, ["verify"]);
35
+ }
36
+ // Helpers
37
+ function bufToHex(buffer) {
38
+ return Array.from(new Uint8Array(buffer))
39
+ .map(b => b.toString(16).padStart(2, '0'))
40
+ .join('');
41
+ }
42
+ function hexToBuf(hex) {
43
+ return new Uint8Array(hex.match(/.{1,2}/g).map(byte => parseInt(byte, 16)));
44
+ }
@@ -0,0 +1,22 @@
1
+ import { AccessPolicy, ContentOrigin, UnauthenticatedStrategy, IdentityCache } from './types.js';
2
+ export interface IMAGXPConfig {
3
+ policy: Omit<AccessPolicy, 'version'>;
4
+ meta: {
5
+ origin: keyof typeof ContentOrigin;
6
+ paymentPointer?: string;
7
+ };
8
+ strategy?: UnauthenticatedStrategy;
9
+ cache?: IdentityCache;
10
+ }
11
+ export declare class IMAGXP {
12
+ private publisher;
13
+ private origin;
14
+ private ready;
15
+ private constructor();
16
+ static init(config: IMAGXPConfig): IMAGXP;
17
+ /**
18
+ * Express Middleware
19
+ */
20
+ middleware(): (req: any, res: any, next: any) => Promise<void>;
21
+ discoveryHandler(): (req: any, res: any) => void;
22
+ }
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Layer 3: Framework Adapters
3
+ * Zero-friction integration for Express/Node.js.
4
+ */
5
+ import { IMAGXPPublisher } from './publisher.js';
6
+ import { ContentOrigin } from './types.js';
7
+ import { generateKeyPair } from './crypto.js';
8
+ export class IMAGXP {
9
+ constructor(config) {
10
+ this.publisher = new IMAGXPPublisher({ version: '1.1', ...config.policy }, config.strategy || 'PASSIVE', config.cache);
11
+ this.origin = ContentOrigin[config.meta.origin];
12
+ this.ready = generateKeyPair().then(keys => {
13
+ return this.publisher.initialize(keys);
14
+ });
15
+ }
16
+ static init(config) {
17
+ return new IMAGXP(config);
18
+ }
19
+ /**
20
+ * Express Middleware
21
+ */
22
+ middleware() {
23
+ return async (req, res, next) => {
24
+ await this.ready;
25
+ // Normalize headers to lowercase dictionary
26
+ const headers = {};
27
+ Object.keys(req.headers).forEach(key => {
28
+ headers[key.toLowerCase()] = req.headers[key];
29
+ });
30
+ // Retrieve Raw Payload if available (optional but good for crypto)
31
+ // Note: Express body parsing might interfere, so we usually rely on the header content.
32
+ const rawPayload = headers['x-imagxp-payload'];
33
+ // Evaluate Visitor
34
+ const result = await this.publisher.evaluateVisitor(headers, rawPayload);
35
+ // Enforce Decision
36
+ if (!result.allowed) {
37
+ res.status(result.status).json({
38
+ error: result.reason,
39
+ visitor_type: result.visitorType,
40
+ proof_used: result.proofUsed
41
+ });
42
+ return;
43
+ }
44
+ // Inject Provenance Headers (For the humans/agents that got through)
45
+ const respHeaders = await this.publisher.generateResponseHeaders(this.origin);
46
+ Object.entries(respHeaders).forEach(([k, v]) => {
47
+ res.setHeader(k, v);
48
+ });
49
+ // Attach metadata to request for downstream use
50
+ req.aamp = {
51
+ verified: result.visitorType === 'VERIFIED_AGENT',
52
+ type: result.visitorType,
53
+ ...result.metadata
54
+ };
55
+ next();
56
+ };
57
+ }
58
+ discoveryHandler() {
59
+ return (req, res) => {
60
+ res.setHeader('Content-Type', 'application/json');
61
+ res.send(JSON.stringify(this.publisher.getPolicy(), null, 2));
62
+ };
63
+ }
64
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * IMAGXP SDK Public API
3
+ *
4
+ * This is the main entry point for the library.
5
+ */
6
+ export * from './types.js';
7
+ export * from './constants.js';
8
+ export * from './agent.js';
9
+ export * from './publisher.js';
10
+ export * from './crypto.js';
11
+ export * from './express.js';
12
+ export { IMAGXPNext } from './nextjs.js';
package/dist/index.js ADDED
@@ -0,0 +1,12 @@
1
+ /**
2
+ * IMAGXP SDK Public API
3
+ *
4
+ * This is the main entry point for the library.
5
+ */
6
+ export * from './types.js';
7
+ export * from './constants.js';
8
+ export * from './agent.js';
9
+ export * from './publisher.js';
10
+ export * from './crypto.js';
11
+ export * from './express.js'; // Node.js / Express Adapter
12
+ export { IMAGXPNext } from './nextjs.js'; // Serverless / Next.js Adapter
@@ -0,0 +1,25 @@
1
+ import { AccessPolicy, ContentOrigin, UnauthenticatedStrategy, IdentityCache } from './types.js';
2
+ type NextRequest = any;
3
+ type NextResponse = any;
4
+ export interface IMAGXPConfig {
5
+ policy: Omit<AccessPolicy, 'version'>;
6
+ meta: {
7
+ origin: keyof typeof ContentOrigin;
8
+ paymentPointer?: string;
9
+ };
10
+ strategy?: UnauthenticatedStrategy;
11
+ cache?: IdentityCache;
12
+ }
13
+ export declare class IMAGXPNext {
14
+ private publisher;
15
+ private origin;
16
+ private ready;
17
+ private constructor();
18
+ static init(config: IMAGXPConfig): IMAGXPNext;
19
+ /**
20
+ * Serverless Route Wrapper
21
+ */
22
+ withProtection(handler: (req: NextRequest) => Promise<NextResponse>): (req: NextRequest) => Promise<any>;
23
+ discoveryHandler(): () => Promise<Response>;
24
+ }
25
+ export {};
package/dist/nextjs.js ADDED
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Layer 3: Framework Adapters
3
+ * Serverless integration for Next.js (App Router & API Routes).
4
+ */
5
+ import { IMAGXPPublisher } from './publisher.js';
6
+ import { ContentOrigin } from './types.js';
7
+ import { generateKeyPair } from './crypto.js';
8
+ const createJsonResponse = (body, status = 200) => {
9
+ return new Response(JSON.stringify(body), {
10
+ status,
11
+ headers: { 'Content-Type': 'application/json' }
12
+ });
13
+ };
14
+ export class IMAGXPNext {
15
+ constructor(config) {
16
+ this.publisher = new IMAGXPPublisher({ version: '1.1', ...config.policy }, config.strategy || 'PASSIVE', config.cache);
17
+ this.origin = ContentOrigin[config.meta.origin];
18
+ this.ready = generateKeyPair().then(keys => this.publisher.initialize(keys));
19
+ }
20
+ static init(config) {
21
+ return new IMAGXPNext(config);
22
+ }
23
+ /**
24
+ * Serverless Route Wrapper
25
+ */
26
+ withProtection(handler) {
27
+ return async (req) => {
28
+ await this.ready;
29
+ // Extract Headers map
30
+ const headers = {};
31
+ req.headers.forEach((value, key) => {
32
+ headers[key.toLowerCase()] = value;
33
+ });
34
+ // Evaluate
35
+ const result = await this.publisher.evaluateVisitor(headers, headers['x-imagxp-payload']);
36
+ if (!result.allowed) {
37
+ return createJsonResponse({
38
+ error: result.reason,
39
+ visitor_type: result.visitorType,
40
+ proof_used: result.proofUsed
41
+ }, result.status);
42
+ }
43
+ // Execute Handler
44
+ const response = await handler(req);
45
+ // Inject Provenance
46
+ const imagxpHeaders = await this.publisher.generateResponseHeaders(this.origin);
47
+ if (response && response.headers) {
48
+ Object.entries(imagxpHeaders).forEach(([k, v]) => {
49
+ response.headers.set(k, v);
50
+ });
51
+ }
52
+ return response;
53
+ };
54
+ }
55
+ discoveryHandler() {
56
+ return async () => {
57
+ return createJsonResponse(this.publisher.getPolicy());
58
+ };
59
+ }
60
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Verifies a JWT (Proof Token or Payment Credential) using JWKS.
3
+ *
4
+ * @param token The JWT string
5
+ * @param jwksUrl The URL to fetch Public Keys
6
+ * @param issuer The expected issuer
7
+ * @param audience The expected audience range
8
+ */
9
+ export declare function verifyJwt(token: string, jwksUrl: string, issuer: string, audience?: string): Promise<boolean>;
package/dist/proof.js ADDED
@@ -0,0 +1,27 @@
1
+ import { createRemoteJWKSet, jwtVerify } from 'jose';
2
+ // In-memory cache for JWKS to avoid repeated fetches
3
+ // Jose's createRemoteJWKSet handles caching/cooldowns internally.
4
+ /**
5
+ * Verifies a JWT (Proof Token or Payment Credential) using JWKS.
6
+ *
7
+ * @param token The JWT string
8
+ * @param jwksUrl The URL to fetch Public Keys
9
+ * @param issuer The expected issuer
10
+ * @param audience The expected audience range
11
+ */
12
+ export async function verifyJwt(token, jwksUrl, issuer, audience) {
13
+ try {
14
+ const JWKS = createRemoteJWKSet(new URL(jwksUrl));
15
+ const { payload } = await jwtVerify(token, JWKS, {
16
+ issuer: issuer,
17
+ audience: audience // specific audience check if provided
18
+ });
19
+ // Check specific IMAGXP claims if we standardize them
20
+ // if (payload.type !== 'AD_IMPRESSION') return false;
21
+ return true;
22
+ }
23
+ catch (error) {
24
+ // console.error("Ad Proof Verification Failed:", error);
25
+ return false;
26
+ }
27
+ }
@@ -0,0 +1,48 @@
1
+ import { AccessPolicy, ContentOrigin, EvaluationResult, IdentityCache, UnauthenticatedStrategy } from './types.js';
2
+ export declare class IMAGXPPublisher {
3
+ private policy;
4
+ private keyPair;
5
+ private unauthenticatedStrategy;
6
+ private cache;
7
+ private readonly CACHE_TTL_SECONDS;
8
+ constructor(policy: AccessPolicy, strategy?: UnauthenticatedStrategy, cacheImpl?: IdentityCache);
9
+ initialize(keyPair: CryptoKeyPair): Promise<void>;
10
+ getPolicy(): AccessPolicy;
11
+ /**
12
+ * Main Entry Point: Evaluate ANY visitor (Human, Bot, or Agent)
13
+ * STAGE 1: IDENTITY (Strict)
14
+ * STAGE 2: POLICY (Permissions)
15
+ * STAGE 3: ACCESS (HQ Content)
16
+ */
17
+ evaluateVisitor(reqHeaders: Record<string, string | undefined>, rawPayload?: string): Promise<EvaluationResult>;
18
+ /**
19
+ * Browser Heuristics (Hardened)
20
+ * 1. Checks Known Bot Signatures (Fast Fail)
21
+ * 2. Checks Trusted Upstream Signals (Cloudflare/Vercel)
22
+ * 3. Checks Browser Header Consistency
23
+ */
24
+ private performBrowserHeuristics;
25
+ /**
26
+ * Handle IMAGXP Protocol Logic (Strict Mode)
27
+ */
28
+ private handleAgentStrict;
29
+ private handleAgent;
30
+ /**
31
+ * STAGE 2: POLICY ENFORCEMENT CHECK
32
+ */
33
+ private checkPolicyStrict;
34
+ private verifyRequestLogic;
35
+ private verifyDnsBinding;
36
+ /**
37
+ * NEW: Verify a Broker-Issued Token (JWT)
38
+ * Checks if the request contains a valid "Visa" from the Broker.
39
+ */
40
+ private verifyBrokerCred;
41
+ private isDomain;
42
+ generateResponseHeaders(origin: ContentOrigin): Promise<Record<string, string>>;
43
+ /**
44
+ * Handling Quality Feedback (The "Dispute" Layer)
45
+ * This runs when an Agent sends 'x-imagxp-feedback'.
46
+ */
47
+ private handleFeedback;
48
+ }