@aamp/protocol 1.1.0 → 1.1.2

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.
@@ -6,3 +6,4 @@ export declare function generateKeyPair(): Promise<CryptoKeyPair>;
6
6
  export declare function signData(privateKey: CryptoKey, data: string): Promise<string>;
7
7
  export declare function verifySignature(publicKey: CryptoKey, data: string, signatureHex: string): Promise<boolean>;
8
8
  export declare function exportPublicKey(key: CryptoKey): Promise<string>;
9
+ export declare function importPublicKey(keyData: string): Promise<CryptoKey>;
@@ -8,6 +8,7 @@ exports.generateKeyPair = generateKeyPair;
8
8
  exports.signData = signData;
9
9
  exports.verifySignature = verifySignature;
10
10
  exports.exportPublicKey = exportPublicKey;
11
+ exports.importPublicKey = importPublicKey;
11
12
  async function generateKeyPair() {
12
13
  // Uses standard Web Crypto API (Node 19+ compatible)
13
14
  return await crypto.subtle.generateKey({ name: "ECDSA", namedCurve: "P-256" }, true, ["sign", "verify"]);
@@ -28,6 +29,14 @@ async function exportPublicKey(key) {
28
29
  const exported = await crypto.subtle.exportKey("spki", key);
29
30
  return btoa(String.fromCharCode(...new Uint8Array(exported)));
30
31
  }
32
+ async function importPublicKey(keyData) {
33
+ const binaryString = atob(keyData);
34
+ const bytes = new Uint8Array(binaryString.length);
35
+ for (let i = 0; i < binaryString.length; i++) {
36
+ bytes[i] = binaryString.charCodeAt(i);
37
+ }
38
+ return await crypto.subtle.importKey("spki", bytes, { name: "ECDSA", namedCurve: "P-256" }, true, ["verify"]);
39
+ }
31
40
  // Helpers
32
41
  function bufToHex(buffer) {
33
42
  return Array.from(new Uint8Array(buffer))
package/package.json CHANGED
@@ -1,24 +1,24 @@
1
- {
2
- "name": "@aamp/protocol",
3
- "version": "1.1.0",
4
- "description": "TypeScript reference implementation of AAMP",
5
- "main": "dist/index.js",
6
- "types": "dist/index.d.ts",
7
- "scripts": {
8
- "build": "tsc",
9
- "test": "ts-node test/handshake.spec.ts",
10
- "prepublishOnly": "npm run test && npm run build"
11
- },
12
- "repository": {
13
- "type": "git",
14
- "url": "https://github.com/aamp-protocol/aamp.git"
15
- },
16
- "publishConfig": {
17
- "access": "public"
18
- },
19
- "devDependencies": {
20
- "typescript": "^5.0.0",
21
- "ts-node": "^10.9.0",
22
- "@types/node": "^20.0.0"
23
- }
1
+ {
2
+ "name": "@aamp/protocol",
3
+ "version": "1.1.2",
4
+ "description": "TypeScript reference implementation of AAMP",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "scripts": {
8
+ "build": "tsc",
9
+ "test": "ts-node test/handshake.spec.ts",
10
+ "prepublishOnly": "npm run test && npm run build"
11
+ },
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "https://github.com/aamp-protocol/aamp.git"
15
+ },
16
+ "publishConfig": {
17
+ "access": "public"
18
+ },
19
+ "devDependencies": {
20
+ "typescript": "^5.0.0",
21
+ "ts-node": "^10.9.0",
22
+ "@types/node": "^20.0.0"
23
+ }
24
24
  }
package/src/agent.ts CHANGED
@@ -1,72 +1,72 @@
1
- /**
2
- * Layer 2: Agent SDK
3
- */
4
- import { AccessPurpose, ProtocolHeader, SignedAccessRequest, FeedbackSignal, QualityFlag } from './types';
5
- import { generateKeyPair, signData, exportPublicKey } from './crypto';
6
- import { AAMP_VERSION } from './constants';
7
-
8
- export interface AccessOptions {
9
- adsDisplayed?: boolean;
10
- }
11
-
12
- export class AAMPAgent {
13
- private keyPair: CryptoKeyPair | null = null;
14
- public agentId: string = "pending";
15
-
16
- /**
17
- * Initialize the Agent Identity (Ephemeral or Persisted)
18
- * @param customAgentId Optional persistent ID for this agent. If omitted, generates a session ID.
19
- */
20
- async initialize(customAgentId?: string) {
21
- this.keyPair = await generateKeyPair();
22
- // Use the provided ID (authentic) or generate a session ID (ephemeral)
23
- this.agentId = customAgentId || "agent_" + Math.random().toString(36).substring(7);
24
- }
25
-
26
- async createAccessRequest(
27
- resource: string,
28
- purpose: AccessPurpose,
29
- options: AccessOptions = {}
30
- ): Promise<SignedAccessRequest> {
31
- if (!this.keyPair) throw new Error("Agent not initialized. Call initialize() first.");
32
-
33
- const header: ProtocolHeader = {
34
- v: AAMP_VERSION,
35
- ts: new Date().toISOString(),
36
- agent_id: this.agentId,
37
- resource,
38
- purpose,
39
- context: {
40
- ads_displayed: options.adsDisplayed || false
41
- }
42
- };
43
-
44
- const signature = await signData(this.keyPair.privateKey, JSON.stringify(header));
45
- const publicKeyExport = await exportPublicKey(this.keyPair.publicKey);
46
-
47
- return { header, signature, publicKey: publicKeyExport };
48
- }
49
-
50
- /**
51
- * NEW IN V1.1: Quality Feedback Loop
52
- * Allows the Agent to report spam or verify quality of a resource.
53
- */
54
- async generateFeedback(
55
- resource: string,
56
- score: number,
57
- flags: QualityFlag[]
58
- ): Promise<{ signal: FeedbackSignal, signature: string }> {
59
- if (!this.keyPair) throw new Error("Agent not initialized.");
60
-
61
- const signal: FeedbackSignal = {
62
- target_resource: resource,
63
- agent_id: this.agentId,
64
- quality_score: Math.max(0, Math.min(1, score)),
65
- flags,
66
- timestamp: new Date().toISOString()
67
- };
68
-
69
- const signature = await signData(this.keyPair.privateKey, JSON.stringify(signal));
70
- return { signal, signature };
71
- }
1
+ /**
2
+ * Layer 2: Agent SDK
3
+ */
4
+ import { AccessPurpose, ProtocolHeader, SignedAccessRequest, FeedbackSignal, QualityFlag } from './types';
5
+ import { generateKeyPair, signData, exportPublicKey } from './crypto';
6
+ import { AAMP_VERSION } from './constants';
7
+
8
+ export interface AccessOptions {
9
+ adsDisplayed?: boolean;
10
+ }
11
+
12
+ export class AAMPAgent {
13
+ private keyPair: CryptoKeyPair | null = null;
14
+ public agentId: string = "pending";
15
+
16
+ /**
17
+ * Initialize the Agent Identity (Ephemeral or Persisted)
18
+ * @param customAgentId Optional persistent ID for this agent. If omitted, generates a session ID.
19
+ */
20
+ async initialize(customAgentId?: string) {
21
+ this.keyPair = await generateKeyPair();
22
+ // Use the provided ID (authentic) or generate a session ID (ephemeral)
23
+ this.agentId = customAgentId || "agent_" + Math.random().toString(36).substring(7);
24
+ }
25
+
26
+ async createAccessRequest(
27
+ resource: string,
28
+ purpose: AccessPurpose,
29
+ options: AccessOptions = {}
30
+ ): Promise<SignedAccessRequest> {
31
+ if (!this.keyPair) throw new Error("Agent not initialized. Call initialize() first.");
32
+
33
+ const header: ProtocolHeader = {
34
+ v: AAMP_VERSION,
35
+ ts: new Date().toISOString(),
36
+ agent_id: this.agentId,
37
+ resource,
38
+ purpose,
39
+ context: {
40
+ ads_displayed: options.adsDisplayed || false
41
+ }
42
+ };
43
+
44
+ const signature = await signData(this.keyPair.privateKey, JSON.stringify(header));
45
+ const publicKeyExport = await exportPublicKey(this.keyPair.publicKey);
46
+
47
+ return { header, signature, publicKey: publicKeyExport };
48
+ }
49
+
50
+ /**
51
+ * NEW IN V1.1: Quality Feedback Loop
52
+ * Allows the Agent to report spam or verify quality of a resource.
53
+ */
54
+ async generateFeedback(
55
+ resource: string,
56
+ score: number,
57
+ flags: QualityFlag[]
58
+ ): Promise<{ signal: FeedbackSignal, signature: string }> {
59
+ if (!this.keyPair) throw new Error("Agent not initialized.");
60
+
61
+ const signal: FeedbackSignal = {
62
+ target_resource: resource,
63
+ agent_id: this.agentId,
64
+ quality_score: Math.max(0, Math.min(1, score)),
65
+ flags,
66
+ timestamp: new Date().toISOString()
67
+ };
68
+
69
+ const signature = await signData(this.keyPair.privateKey, JSON.stringify(signal));
70
+ return { signal, signature };
71
+ }
72
72
  }
package/src/constants.ts CHANGED
@@ -1,35 +1,35 @@
1
- /**
2
- * Layer 1: Protocol Constants
3
- * These values are immutable and defined by the AAMP Specification.
4
- */
5
-
6
- export const AAMP_VERSION = '1.1';
7
-
8
- // HTTP Headers used for the handshake
9
- export const HEADERS = {
10
- // Transport: The signed payload (Base64 encoded JSON of ProtocolHeader)
11
- PAYLOAD: 'x-aamp-payload',
12
- // Transport: The cryptographic signature (Hex)
13
- SIGNATURE: 'x-aamp-signature',
14
- // Transport: The Agent's Public Key (Base64 SPKI)
15
- PUBLIC_KEY: 'x-aamp-public-key',
16
-
17
- // Informational / Legacy (Optional if Payload is present)
18
- AGENT_ID: 'x-aamp-agent-id',
19
- TIMESTAMP: 'x-aamp-timestamp',
20
- ALGORITHM: 'x-aamp-alg',
21
-
22
- // v1.1 Addition: Provenance (Server to Agent)
23
- CONTENT_ORIGIN: 'x-aamp-content-origin',
24
- PROVENANCE_SIG: 'x-aamp-provenance-sig'
25
- } as const;
26
-
27
- // Cryptographic Settings
28
- export const CRYPTO_CONFIG = {
29
- ALGORITHM_NAME: 'ECDSA',
30
- CURVE: 'P-256',
31
- HASH: 'SHA-256',
32
- } as const;
33
-
34
- // Tolerance
1
+ /**
2
+ * Layer 1: Protocol Constants
3
+ * These values are immutable and defined by the AAMP Specification.
4
+ */
5
+
6
+ export const AAMP_VERSION = '1.1';
7
+
8
+ // HTTP Headers used for the handshake
9
+ export const HEADERS = {
10
+ // Transport: The signed payload (Base64 encoded JSON of ProtocolHeader)
11
+ PAYLOAD: 'x-aamp-payload',
12
+ // Transport: The cryptographic signature (Hex)
13
+ SIGNATURE: 'x-aamp-signature',
14
+ // Transport: The Agent's Public Key (Base64 SPKI)
15
+ PUBLIC_KEY: 'x-aamp-public-key',
16
+
17
+ // Informational / Legacy (Optional if Payload is present)
18
+ AGENT_ID: 'x-aamp-agent-id',
19
+ TIMESTAMP: 'x-aamp-timestamp',
20
+ ALGORITHM: 'x-aamp-alg',
21
+
22
+ // v1.1 Addition: Provenance (Server to Agent)
23
+ CONTENT_ORIGIN: 'x-aamp-content-origin',
24
+ PROVENANCE_SIG: 'x-aamp-provenance-sig'
25
+ } as const;
26
+
27
+ // Cryptographic Settings
28
+ export const CRYPTO_CONFIG = {
29
+ ALGORITHM_NAME: 'ECDSA',
30
+ CURVE: 'P-256',
31
+ HASH: 'SHA-256',
32
+ } as const;
33
+
34
+ // Tolerance
35
35
  export const MAX_CLOCK_SKEW_MS = 5 * 60 * 1000; // 5 minutes
package/src/crypto.ts CHANGED
@@ -1,53 +1,69 @@
1
- /**
2
- * Layer 1: Cryptographic Primitives
3
- * Implementation of ECDSA P-256 signing/verification.
4
- */
5
-
6
- export async function generateKeyPair(): Promise<CryptoKeyPair> {
7
- // Uses standard Web Crypto API (Node 19+ compatible)
8
- return await crypto.subtle.generateKey(
9
- { name: "ECDSA", namedCurve: "P-256" },
10
- true,
11
- ["sign", "verify"]
12
- );
13
- }
14
-
15
- export async function signData(privateKey: CryptoKey, data: string): Promise<string> {
16
- const encoder = new TextEncoder();
17
- const encoded = encoder.encode(data);
18
- const signature = await crypto.subtle.sign(
19
- { name: "ECDSA", hash: { name: "SHA-256" } },
20
- privateKey,
21
- encoded as any
22
- );
23
- return bufToHex(signature);
24
- }
25
-
26
- export async function verifySignature(publicKey: CryptoKey, data: string, signatureHex: string): Promise<boolean> {
27
- const encoder = new TextEncoder();
28
- const encodedData = encoder.encode(data);
29
- const signatureBytes = hexToBuf(signatureHex);
30
-
31
- return await crypto.subtle.verify(
32
- { name: "ECDSA", hash: { name: "SHA-256" } },
33
- publicKey,
34
- signatureBytes as any,
35
- encodedData as any
36
- );
37
- }
38
-
39
- export async function exportPublicKey(key: CryptoKey): Promise<string> {
40
- const exported = await crypto.subtle.exportKey("spki", key);
41
- return btoa(String.fromCharCode(...new Uint8Array(exported)));
42
- }
43
-
44
- // Helpers
45
- function bufToHex(buffer: ArrayBuffer): string {
46
- return Array.from(new Uint8Array(buffer))
47
- .map(b => b.toString(16).padStart(2, '0'))
48
- .join('');
49
- }
50
-
51
- function hexToBuf(hex: string): Uint8Array {
52
- return new Uint8Array(hex.match(/.{1,2}/g)!.map(byte => parseInt(byte, 16)));
1
+ /**
2
+ * Layer 1: Cryptographic Primitives
3
+ * Implementation of ECDSA P-256 signing/verification.
4
+ */
5
+
6
+ export async function generateKeyPair(): Promise<CryptoKeyPair> {
7
+ // Uses standard Web Crypto API (Node 19+ compatible)
8
+ return await crypto.subtle.generateKey(
9
+ { name: "ECDSA", namedCurve: "P-256" },
10
+ true,
11
+ ["sign", "verify"]
12
+ );
13
+ }
14
+
15
+ export async function signData(privateKey: CryptoKey, data: string): Promise<string> {
16
+ const encoder = new TextEncoder();
17
+ const encoded = encoder.encode(data);
18
+ const signature = await crypto.subtle.sign(
19
+ { name: "ECDSA", hash: { name: "SHA-256" } },
20
+ privateKey,
21
+ encoded as any
22
+ );
23
+ return bufToHex(signature);
24
+ }
25
+
26
+ export async function verifySignature(publicKey: CryptoKey, data: string, signatureHex: string): Promise<boolean> {
27
+ const encoder = new TextEncoder();
28
+ const encodedData = encoder.encode(data);
29
+ const signatureBytes = hexToBuf(signatureHex);
30
+
31
+ return await crypto.subtle.verify(
32
+ { name: "ECDSA", hash: { name: "SHA-256" } },
33
+ publicKey,
34
+ signatureBytes as any,
35
+ encodedData as any
36
+ );
37
+ }
38
+
39
+ export async function exportPublicKey(key: CryptoKey): Promise<string> {
40
+ const exported = await crypto.subtle.exportKey("spki", key);
41
+ return btoa(String.fromCharCode(...new Uint8Array(exported)));
42
+ }
43
+
44
+ export async function importPublicKey(keyData: string): Promise<CryptoKey> {
45
+ const binaryString = atob(keyData);
46
+ const bytes = new Uint8Array(binaryString.length);
47
+ for (let i = 0; i < binaryString.length; i++) {
48
+ bytes[i] = binaryString.charCodeAt(i);
49
+ }
50
+
51
+ return await crypto.subtle.importKey(
52
+ "spki",
53
+ bytes,
54
+ { name: "ECDSA", namedCurve: "P-256" },
55
+ true,
56
+ ["verify"]
57
+ );
58
+ }
59
+
60
+ // Helpers
61
+ function bufToHex(buffer: ArrayBuffer): string {
62
+ return Array.from(new Uint8Array(buffer))
63
+ .map(b => b.toString(16).padStart(2, '0'))
64
+ .join('');
65
+ }
66
+
67
+ function hexToBuf(hex: string): Uint8Array {
68
+ return new Uint8Array(hex.match(/.{1,2}/g)!.map(byte => parseInt(byte, 16)));
53
69
  }
package/src/express.ts CHANGED
@@ -1,104 +1,104 @@
1
- /**
2
- * Layer 3: Framework Adapters
3
- * Zero-friction integration for Express/Node.js.
4
- */
5
- import { AAMPPublisher } from './publisher';
6
- import { AccessPolicy, ContentOrigin, SignedAccessRequest } from './types';
7
- import { generateKeyPair, verifySignature } from './crypto';
8
- import { HEADERS } from './constants';
9
-
10
- export interface AAMPConfig {
11
- policy: Omit<AccessPolicy, 'version'>;
12
- meta: {
13
- origin: keyof typeof ContentOrigin;
14
- paymentPointer?: string;
15
- };
16
- }
17
-
18
- export class AAMP {
19
- private publisher: AAMPPublisher;
20
- private origin: ContentOrigin;
21
- private ready: Promise<void>;
22
-
23
- private constructor(config: AAMPConfig) {
24
- this.publisher = new AAMPPublisher({
25
- version: '1.1',
26
- ...config.policy
27
- } as AccessPolicy);
28
-
29
- this.origin = ContentOrigin[config.meta.origin];
30
-
31
- this.ready = generateKeyPair().then(keys => {
32
- return this.publisher.initialize(keys);
33
- });
34
- }
35
-
36
- static init(config: AAMPConfig): AAMP {
37
- return new AAMP(config);
38
- }
39
-
40
- /**
41
- * Express Middleware
42
- */
43
- middleware() {
44
- return async (req: any, res: any, next: any) => {
45
- await this.ready;
46
-
47
- // 1. Inject Provenance Headers (Passive Protection)
48
- const headers = await this.publisher.generateResponseHeaders(this.origin);
49
- Object.entries(headers).forEach(([k, v]) => {
50
- res.setHeader(k, v);
51
- });
52
-
53
- // 2. Active Verification (If Agent sends signed headers)
54
- const payloadHeader = req.headers[HEADERS.PAYLOAD];
55
- const sigHeader = req.headers[HEADERS.SIGNATURE];
56
- const keyHeader = req.headers[HEADERS.PUBLIC_KEY];
57
-
58
- if (payloadHeader && sigHeader && keyHeader) {
59
- try {
60
- const headerJson = atob(payloadHeader); // RAW STRING
61
- const requestHeader = JSON.parse(headerJson);
62
-
63
- const signedRequest: SignedAccessRequest = {
64
- header: requestHeader,
65
- signature: sigHeader,
66
- publicKey: keyHeader
67
- };
68
-
69
- const agentKey = await crypto.subtle.importKey(
70
- "spki",
71
- new Uint8Array(atob(keyHeader).split('').map(c => c.charCodeAt(0))),
72
- { name: "ECDSA", namedCurve: "P-256" },
73
- true,
74
- ["verify"]
75
- );
76
-
77
- // Pass raw headerJson to ensure signature matches exactly what was signed
78
- const result = await this.publisher.verifyRequest(signedRequest, agentKey, headerJson);
79
-
80
- if (!result.allowed) {
81
- res.status(403).json({ error: result.reason });
82
- return;
83
- }
84
-
85
- // Verified!
86
- req.aamp = { verified: true, ...requestHeader };
87
-
88
- } catch (e) {
89
- res.status(400).json({ error: "Invalid AAMP Signature" });
90
- return;
91
- }
92
- }
93
-
94
- next();
95
- };
96
- }
97
-
98
- discoveryHandler() {
99
- return (req: any, res: any) => {
100
- res.setHeader('Content-Type', 'application/json');
101
- res.send(JSON.stringify(this.publisher.getPolicy(), null, 2));
102
- };
103
- }
1
+ /**
2
+ * Layer 3: Framework Adapters
3
+ * Zero-friction integration for Express/Node.js.
4
+ */
5
+ import { AAMPPublisher } from './publisher';
6
+ import { AccessPolicy, ContentOrigin, SignedAccessRequest } from './types';
7
+ import { generateKeyPair, verifySignature } from './crypto';
8
+ import { HEADERS } from './constants';
9
+
10
+ export interface AAMPConfig {
11
+ policy: Omit<AccessPolicy, 'version'>;
12
+ meta: {
13
+ origin: keyof typeof ContentOrigin;
14
+ paymentPointer?: string;
15
+ };
16
+ }
17
+
18
+ export class AAMP {
19
+ private publisher: AAMPPublisher;
20
+ private origin: ContentOrigin;
21
+ private ready: Promise<void>;
22
+
23
+ private constructor(config: AAMPConfig) {
24
+ this.publisher = new AAMPPublisher({
25
+ version: '1.1',
26
+ ...config.policy
27
+ } as AccessPolicy);
28
+
29
+ this.origin = ContentOrigin[config.meta.origin];
30
+
31
+ this.ready = generateKeyPair().then(keys => {
32
+ return this.publisher.initialize(keys);
33
+ });
34
+ }
35
+
36
+ static init(config: AAMPConfig): AAMP {
37
+ return new AAMP(config);
38
+ }
39
+
40
+ /**
41
+ * Express Middleware
42
+ */
43
+ middleware() {
44
+ return async (req: any, res: any, next: any) => {
45
+ await this.ready;
46
+
47
+ // 1. Inject Provenance Headers (Passive Protection)
48
+ const headers = await this.publisher.generateResponseHeaders(this.origin);
49
+ Object.entries(headers).forEach(([k, v]) => {
50
+ res.setHeader(k, v);
51
+ });
52
+
53
+ // 2. Active Verification (If Agent sends signed headers)
54
+ const payloadHeader = req.headers[HEADERS.PAYLOAD];
55
+ const sigHeader = req.headers[HEADERS.SIGNATURE];
56
+ const keyHeader = req.headers[HEADERS.PUBLIC_KEY];
57
+
58
+ if (payloadHeader && sigHeader && keyHeader) {
59
+ try {
60
+ const headerJson = atob(payloadHeader); // RAW STRING
61
+ const requestHeader = JSON.parse(headerJson);
62
+
63
+ const signedRequest: SignedAccessRequest = {
64
+ header: requestHeader,
65
+ signature: sigHeader,
66
+ publicKey: keyHeader
67
+ };
68
+
69
+ const agentKey = await crypto.subtle.importKey(
70
+ "spki",
71
+ new Uint8Array(atob(keyHeader).split('').map(c => c.charCodeAt(0))),
72
+ { name: "ECDSA", namedCurve: "P-256" },
73
+ true,
74
+ ["verify"]
75
+ );
76
+
77
+ // Pass raw headerJson to ensure signature matches exactly what was signed
78
+ const result = await this.publisher.verifyRequest(signedRequest, agentKey, headerJson);
79
+
80
+ if (!result.allowed) {
81
+ res.status(403).json({ error: result.reason });
82
+ return;
83
+ }
84
+
85
+ // Verified!
86
+ req.aamp = { verified: true, ...requestHeader };
87
+
88
+ } catch (e) {
89
+ res.status(400).json({ error: "Invalid AAMP Signature" });
90
+ return;
91
+ }
92
+ }
93
+
94
+ next();
95
+ };
96
+ }
97
+
98
+ discoveryHandler() {
99
+ return (req: any, res: any) => {
100
+ res.setHeader('Content-Type', 'application/json');
101
+ res.send(JSON.stringify(this.publisher.getPolicy(), null, 2));
102
+ };
103
+ }
104
104
  }
package/src/index.ts CHANGED
@@ -1,13 +1,13 @@
1
- /**
2
- * AAMP SDK Public API
3
- *
4
- * This is the main entry point for the library.
5
- */
6
-
7
- export * from './types';
8
- export * from './constants';
9
- export * from './agent';
10
- export * from './publisher';
11
- export * from './crypto';
12
- export * from './express'; // Node.js / Express Adapter
1
+ /**
2
+ * AAMP SDK Public API
3
+ *
4
+ * This is the main entry point for the library.
5
+ */
6
+
7
+ export * from './types';
8
+ export * from './constants';
9
+ export * from './agent';
10
+ export * from './publisher';
11
+ export * from './crypto';
12
+ export * from './express'; // Node.js / Express Adapter
13
13
  export { AAMPNext } from './nextjs'; // Serverless / Next.js Adapter