{"_id":"@aura-labs-ai/beacon","name":"@aura-labs-ai/beacon","dist-tags":{"latest":"0.3.0"},"versions":{"0.3.0":{"name":"@aura-labs-ai/beacon","version":"0.3.0","description":"Beacon SDK for AURA - Build selling agents that participate in agentic commerce","type":"module","main":"src/index.js","bin":{"beacon-cli":"bin/beacon-cli.js","aura-beacon":"bin/beacon-cli.js"},"exports":{".":{"import":"./src/index.js"}},"scripts":{"test":"node --test src/**/*.test.js","cli":"node bin/beacon-cli.js","demo":"node examples/run-all-beacons.js","demo:widgets":"node examples/widget-supplier.js","demo:electronics":"node examples/electronics-vendor.js","demo:office":"node examples/office-supplies.js","demo:cloud":"node examples/cloud-services.js","demo:travel":"node examples/travel-agent.js"},"dependencies":{"@aura-labs-ai/nlp":"^0.2.0","@aura-labs-ai/sdk-common":"^0.2.0"},"devDependencies":{"@types/node":"^20.11.0"},"engines":{"node":">=18.0.0"},"keywords":["aura","agentic-commerce","ai-agent","seller-agent","beacon"],"author":{"name":"AURA Labs"},"license":"BSL-1.1","repository":{"type":"git","url":"git+https://github.com/aura-labs-ai/aura-labs.git"},"homepage":"https://aura-labs.ai/docs/beacon","gitHead":"1f285d7a30186e2d2a7d6b7146ff16ddcbbe56d0","_id":"@aura-labs-ai/beacon@0.3.0","bugs":{"url":"https://github.com/aura-labs-ai/aura-labs/issues"},"_nodeVersion":"25.8.0","_npmVersion":"11.11.0","dist":{"integrity":"sha512-upancckIImY/vJHsT5LJC6Xz3F8s9jg/P7PVn+byEEtnYRDIh5pneGrlNpf//sBCPXus+YAXq3Gp9SBDXfXWjQ==","shasum":"555f081d7008c4ab64bc841aebac5020448b8101","tarball":"https://registry.npmjs.org/@aura-labs-ai/beacon/-/beacon-0.3.0.tgz","fileCount":19,"unpackedSize":182333,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIDzO6Rk1ViTJu2UBqi4q9ja8UTCCfko7xVSi97B4dKYeAiBUI8ZSONUhKo0Ob2ar6Y4DADRnkI3zKWE+4c9Btei0Xg=="}]},"_npmUser":{"name":"marcmassar","email":"marc@aura-labs.ai"},"directories":{},"maintainers":[{"name":"marcmassar","email":"marc@aura-labs.ai"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/beacon_0.3.0_1783273691081_0.16169128767801721"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-05T17:48:10.898Z","0.3.0":"2026-07-05T17:48:11.255Z","modified":"2026-07-05T17:48:11.474Z"},"maintainers":[{"name":"marcmassar","email":"marc@aura-labs.ai"}],"description":"Beacon SDK for AURA - Build selling agents that participate in agentic commerce","homepage":"https://aura-labs.ai/docs/beacon","keywords":["aura","agentic-commerce","ai-agent","seller-agent","beacon"],"repository":{"type":"git","url":"git+https://github.com/aura-labs-ai/aura-labs.git"},"author":{"name":"AURA Labs"},"bugs":{"url":"https://github.com/aura-labs-ai/aura-labs/issues"},"license":"BSL-1.1","readme":"# @aura-labs-ai/beacon\n\nBeacon SDK for AURA — Build selling agents that participate in agentic commerce.\n\n## What is a Beacon?\n\nA Beacon is a seller agent in the AURA ecosystem. Beacons:\n- Register their capabilities with AURA Core\n- Poll for sessions matching their products/services\n- Submit offers in response to Scout intents\n- Fulfill committed transactions\n\n## Installation\n\n```bash\nnpm install @aura-labs-ai/beacon\n```\n\n## Quick Start\n\n```javascript\nimport { createBeacon } from '@aura-labs-ai/beacon';\n\n// Create and register a Beacon\nconst beacon = createBeacon({\n  externalId: 'my-store-001',\n  name: 'My Store',\n  capabilities: { products: ['widgets', 'gadgets'] },\n});\n\nawait beacon.register();\n\n// Handle incoming sessions\nbeacon.onSession(async (session) => {\n  if (session.intent.raw.includes('widget')) {\n    await beacon.submitOffer(session.sessionId, {\n      product: { name: 'Premium Widget', sku: 'WDG-001' },\n      unitPrice: 85.00,\n      quantity: 500,\n      deliveryDate: '2026-02-20',\n    });\n  }\n});\n\n// Start polling for sessions\n// (For production use, see Merchant Integration Hooks below for offer validation and fulfillment tracking)\nawait beacon.startPolling();\n```\n\n## Test Beacons (Stubs)\n\nThe SDK includes several test beacons simulating different vendor types:\n\n| Beacon | Description | Responds To |\n|--------|-------------|-------------|\n| `widgets` | Acme Widget Co. | widget, industrial |\n| `electronics` | TechMart Electronics | laptop, computer, monitor, keyboard |\n| `office` | OfficeMax Pro | desk, chair, paper, printer, office |\n| `cloud` | Nimbus Cloud Services | server, vm, cloud, database, storage, gpu |\n| `travel` | Wanderlust Travel | flight, hotel, travel, vacation |\n\n### Running Individual Beacons\n\n```bash\n# Using npm scripts\nnpm run demo:widgets\nnpm run demo:electronics\nnpm run demo:office\nnpm run demo:cloud\nnpm run demo:travel\n\n# Or run files directly\nnode examples/widget-supplier.js\nnode examples/electronics-vendor.js\nnode examples/office-supplies.js\nnode examples/cloud-services.js\nnode examples/travel-agent.js\n```\n\n### Running All Beacons (Marketplace Demo)\n\nRun all beacons simultaneously for a full marketplace simulation:\n\n```bash\nnpm run demo\n# or\nnode examples/run-all-beacons.js\n```\n\n### Beacon CLI\n\n```bash\n# List available beacons\nnpx beacon-cli list\n\n# Run a specific beacon\nnpx beacon-cli run widgets\nnpx beacon-cli run electronics\n\n# Run all beacons\nnpx beacon-cli run all\n\n# Show connection info\nnpx beacon-cli info\n```\n\n### Environment Variables\n\n```bash\n# Custom Core URL\nAURA_CORE_URL=http://localhost:3000 npm run demo\n\n# Custom polling interval (ms)\nPOLL_INTERVAL=5000 npm run demo:widgets\n```\n\n## API Reference\n\n### `createBeacon(config)`\n\nCreate a new Beacon instance.\n\n```javascript\nconst beacon = createBeacon({\n  externalId: 'required-unique-id',  // Your unique identifier\n  name: 'Required Name',              // Display name\n  description: 'Optional description',\n  endpointUrl: 'https://...',         // Optional webhook URL\n  capabilities: {},                    // What you sell\n  coreUrl: 'https://...',             // Optional, defaults to production\n  pollIntervalMs: 5000,               // Polling interval\n});\n```\n\n### `beacon.ping()`\n\nRead-only connectivity check. Verifies Core is reachable and its dependencies are healthy. Does not require `register()` — works on a freshly created instance. No auth headers sent.\n\n```javascript\nconst health = await beacon.ping();\n\n// When Core is healthy:\n// { status: 'ok', core: { status: 'ready', checks: { database: {...}, redis: {...} } }, latency_ms: 42, timestamp: '...' }\n\n// When Core is alive but degraded (503):\n// { status: 'degraded', core: { status: 'not_ready', checks: {...} }, latency_ms: 105, timestamp: '...' }\n\n// When Core is unreachable:\n// { status: 'error', code: 'CORE_UNREACHABLE', message: '...', latency_ms: 30000, timestamp: '...' }\n```\n\nActivity events: `ping.success` (Core responded), `ping.failed` (network error or timeout). Summary counters available via `beacon.activity.getSummary().ping`.\n\n### `beacon.register()`\n\nRegister with AURA Core. Called automatically by `startPolling()` if needed.\n\n```javascript\nconst result = await beacon.register();\n// { beaconId: 'uuid', externalId: '...', name: '...', status: 'active' }\n```\n\n### `beacon.onSession(handler)`\n\nRegister a handler for incoming sessions.\n\n```javascript\nbeacon.onSession(async (session, beacon) => {\n  console.log('New session:', session.sessionId);\n  console.log('Intent:', session.intent.raw);\n\n  // Decide whether to submit an offer\n  if (matchesMyProducts(session)) {\n    await beacon.submitOffer(session.sessionId, myOffer);\n  }\n});\n```\n\n### `beacon.submitOffer(sessionId, offer)`\n\nSubmit an offer to a session.\n\n```javascript\nawait beacon.submitOffer(sessionId, {\n  product: { name: 'Widget', sku: 'WDG-001' },\n  unitPrice: 85.00,\n  quantity: 500,\n  totalPrice: 42500.00,  // Optional, calculated if not provided\n  currency: 'USD',\n  deliveryDate: '2026-02-20',\n  terms: { warranty: '2 years' },\n  metadata: { sustainable: true },\n  actingForPrincipalId: 'prn_01HMERCHANT...',  // Optional — for platform_delegated Beacons\n});\n```\n\n**Platform-delegated Beacons:** When a Beacon operates as `platform_delegated` (e.g., a Shopify app serving multiple merchants), use `actingForPrincipalId` to declare which merchant principal this offer is for. The merchant's principal must be registered with Core. This principal (not the platform's) is recorded on the transaction.\n\n### `beacon.startPolling()`\n\nStart polling for sessions. Calls registered handlers for each new session.\n\n### `beacon.stopPolling()`\n\nStop polling.\n\n### `beacon.getSessions()`\n\nManually fetch available sessions without polling.\n\n```javascript\nconst sessions = await beacon.getSessions();\n```\n\n## Merchant Integration Hooks\n\nIntegration hooks enable advanced merchant logic including offer validation, business rule enforcement, and fulfillment tracking. All hook methods return `this` for method chaining.\n\n### `beacon.beforeOffer(validator)`\n\nRegister a pre-offer validation middleware. Runs sequentially before each `submitOffer()` call. Use this to validate inventory, apply dynamic pricing, or enforce business rules.\n\n**Validator Signature:**\n```javascript\nasync (session, proposedOffer) => modifiedOffer | undefined\n```\n\n- If validator throws an error, the offer is blocked\n- If validator returns an object, it is merged into the offer\n- If validator returns `undefined`, the offer proceeds unchanged\n\n**Example: Inventory Check**\n```javascript\nbeacon.beforeOffer(async (session, proposedOffer) => {\n  const inventory = await checkInventory(proposedOffer.product.sku);\n  if (inventory < proposedOffer.quantity) {\n    throw new Error(`Insufficient inventory: only ${inventory} available`);\n  }\n  // Return undefined to proceed with original offer\n});\n```\n\n**Example: Dynamic Price Floor**\n```javascript\nbeacon.beforeOffer(async (session, proposedOffer) => {\n  const minPrice = await calculateMinPrice(proposedOffer.product.sku);\n  if (proposedOffer.unitPrice < minPrice) {\n    // Return modified offer with minimum price\n    return { unitPrice: minPrice };\n  }\n});\n```\n\n### `beacon.onOfferAccepted(handler)`\n\nRegister a handler called when an offer is committed/accepted by the buyer.\n\n**Handler Signature:**\n```javascript\nasync (transactionData) => void\n```\n\n**Example: Log Accepted Orders**\n```javascript\nbeacon.onOfferAccepted(async (transactionData) => {\n  console.log(`Order ${transactionData.transactionId} accepted`);\n  await logOrderToSystem(transactionData);\n  await notifyWarehouse(transactionData);\n});\n```\n\n### `beacon.onTransactionUpdate(handler)`\n\nRegister a handler for transaction status changes (e.g., payment confirmed, shipped, delivered).\n\n**Handler Signature:**\n```javascript\nasync (event) => void\n```\n\n**Example: Track Transaction Status**\n```javascript\nbeacon.onTransactionUpdate(async (event) => {\n  console.log(`Transaction ${event.transactionId}: ${event.status}`);\n  if (event.status === 'payment_confirmed') {\n    await chargeCard(event.paymentReference);\n  }\n});\n```\n\n### `beacon.registerPolicies(policies)`\n\nDeclare your merchant business rules. Auto-adds a built-in `beforeOffer` validator enforcing these policies.\n\n**Policies Object:**\n```javascript\n{\n  minPrice?: number,              // Minimum unit price\n  maxQuantityPerOrder?: number,   // Order quantity cap\n  maxDeliveryDays?: number,       // Maximum days until delivery\n  deliveryRegions?: string[],     // Supported shipping regions\n}\n```\n\n**Example: Enforce Business Rules**\n```javascript\nbeacon.registerPolicies({\n  minPrice: 10.00,\n  maxQuantityPerOrder: 1000,\n  maxDeliveryDays: 7,\n  deliveryRegions: ['US', 'CA', 'MX'],\n});\n\n// Now all offers are validated against these policies automatically\n```\n\n### `beacon.updateFulfillment(transactionId, update)`\n\nReport fulfillment progress to AURA Core.\n\n**Update Object:**\n```javascript\n{\n  fulfillmentStatus: 'shipped' | 'delivered',\n  fulfillmentReference?: string,  // Tracking number, shipment ID, etc.\n  metadata?: object,              // Additional metadata\n}\n```\n\n**Example: Report Shipment**\n```javascript\nawait beacon.updateFulfillment(transactionId, {\n  fulfillmentStatus: 'shipped',\n  fulfillmentReference: 'FDX123456789',\n  metadata: { carrier: 'FedEx', estimatedDelivery: '2026-03-10' },\n});\n```\n\n### `beacon.getTransaction(transactionId)`\n\nFetch detailed transaction information from AURA Core.\n\n**Example: Check Transaction Details**\n```javascript\nconst transaction = await beacon.getTransaction(transactionId);\nconsole.log(`Status: ${transaction.status}`);\nconsole.log(`Amount: ${transaction.total_price} ${transaction.currency}`);\nconsole.log(`Buyer: ${transaction.buyer_info.name}`);\n```\n\n### Chaining Example\n\nIntegration hooks support method chaining for clean setup:\n\n```javascript\nbeacon\n  .registerPolicies({\n    minPrice: 15.00,\n    maxQuantityPerOrder: 500,\n  })\n  .beforeOffer(async (session, offer) => {\n    const inventory = await checkInventory(offer.product.sku);\n    if (inventory < offer.quantity) {\n      throw new Error('Out of stock');\n    }\n  })\n  .onOfferAccepted(async (tx) => {\n    await fulfillmentService.createOrder(tx);\n  })\n  .onTransactionUpdate(async (event) => {\n    if (event.status === 'dispute') {\n      await escalationTeam.alert(event);\n    }\n  });\n\nawait beacon.register();\nawait beacon.startPolling();\n```\n\n### `beacon.interpretIntent(intentText, catalog, options?)`\n\nInterpret an incoming intent against your product catalog. Uses `@aura-labs-ai/nlp` for category presence detection and matches intent keywords against catalog item names, categories, and tags.\n\nThis is Layer 3 of the ADR-002 three-layer NLP architecture. Presence detection only — Core retains semantic authority per NEUTRAL_BROKER.md Property 1.\n\n```javascript\nconst catalog = [\n  { name: 'Ergonomic Keyboard', sku: 'KB-ERG-001', category: 'keyboards', tags: ['ergonomic', 'wireless'] },\n  { name: 'Gaming Mouse', sku: 'MS-GAM-001', category: 'mice', tags: ['gaming', 'wireless'] },\n];\n\nconst result = await beacon.interpretIntent(\n  'I need 50 ergonomic keyboards under $5000',\n  catalog,\n);\n// {\n//   matches: [\n//     { item: { name: 'Ergonomic Keyboard', ... }, score: 60, matchedOn: ['name', 'category', 'tags'] }\n//   ],\n//   confidence: 0.45,\n//   categories: { how_many: { present: true }, how_much_cost: { present: true }, ... },\n//   suggestions: ['How many would you like?', ...]\n// }\n```\n\n**Parameters:**\n- `intentText` — Raw intent text from the buyer (max 5000 chars)\n- `catalog` — Array of catalog items with `name`, `category`, and/or `tags` fields\n- `options.provider` — Optional LLM provider for model-based category detection\n\n**Returns:** `{ matches, confidence, categories, suggestions }`\n\n**Usage in onSession handler:**\n```javascript\nbeacon.onSession(async (session) => {\n  const interpretation = await beacon.interpretIntent(session.intent.raw, myCatalog);\n\n  if (interpretation.matches.length > 0) {\n    const topMatch = interpretation.matches[0];\n    await beacon.submitOffer(session.sessionId, {\n      product: topMatch.item,\n      unitPrice: topMatch.item.price,\n      quantity: 1,\n    });\n  }\n});\n```\n\n## Beacon Properties\n\nAccess beacon state and metadata:\n\n```javascript\nbeacon.isRegistered  // boolean — beacon registered with Core\nbeacon.id            // UUID assigned by AURA Core\nbeacon.externalId    // Your external identifier\nbeacon.name          // Display name\nbeacon.isPolling     // boolean — polling active\n```\n\n## Error Classes\n\nThe SDK exports the following error types for precise error handling:\n\n- `BeaconError` — Base error class\n- `ConnectionError` — Core API connection failures\n- `RegistrationError` — Registration failures\n- `OfferError` — Offer submission failures\n- `ValidationError` — Thrown by `beforeOffer` validators\n- `AuthenticationError` — Ed25519 signature or Bearer token authentication failures (HTTP 401/403)\n\n**Example: Error Handling**\n```javascript\nimport { createBeacon, ValidationError, OfferError, AuthenticationError } from '@aura-labs-ai/beacon';\n\ntry {\n  await beacon.submitOffer(sessionId, offer);\n} catch (error) {\n  if (error instanceof AuthenticationError) {\n    console.error('Authentication failed:', error.message);\n  } else if (error instanceof ValidationError) {\n    console.error('Offer validation failed:', error.message);\n  } else if (error instanceof OfferError) {\n    console.error('Offer submission failed:', error.message);\n  }\n}\n```\n\n## Session Object\n\nSessions returned from `beacon.getSessions()` have buyer constraints redacted to preserve information asymmetry. Beacons only see the `categories` field — budget, delivery deadline, and other constraint details are not exposed.\n\n```javascript\n{\n  sessionId: 'uuid',\n  status: 'market_forming',\n  intent: {\n    raw: 'I need 500 widgets',\n    parsed: { keywords: ['need', '500', 'widgets'] }\n  },\n  constraints: {\n    categories: ['widgets', 'industrial']\n  },\n  createdAt: '2026-02-08T...'\n}\n```\n\n## Beacon Registration and Agent Registration\n\nBeacons have two optional registration paths:\n\n### 1. Beacon Registration (Required for polling)\nCall `beacon.register()` or `beacon.startPolling()` to register via `POST /v1/beacons/register`. This creates a **Beacon** record in Core, allowing the beacon to poll for sessions and submit offers.\n\n```javascript\nconst result = await beacon.register();\n// { beaconId: 'uuid', externalId: '...', name: '...', status: 'active' }\n```\n\n### 2. Agent Registration (Optional, for Ed25519 signing)\nFor added security and to participate in protocols requiring cryptographic identity (like AP2 mandates or TAP), a Beacon can optionally register as an **Agent** via `POST /v1/agents/register` with type `beacon`. This generates and stores an Ed25519 key pair for signing requests.\n\n**Dual Authentication:** The Beacon SDK supports Ed25519 signed requests (preferred) with automatic fallback to Bearer token authentication. When a key manager is configured via `beacon.setKeyManager(keyManager, agentId)`, all requests are signed with `X-Agent-Id`, `X-Agent-Signature`, and `X-Agent-Timestamp` headers. If no key manager is set, the SDK falls back to the Bearer token from registration. The SDK throws `AuthenticationError` on HTTP 401/403 responses.\n\n### 3. Offer Signing (Required for offer submission)\n\nWhen a KeyManager is configured via `setKeyManager()`, offers are automatically signed with Ed25519 before submission. Core verifies the signature and counter-signs, creating a three-layer cryptographic receipt chain.\n\n```javascript\nimport { createBeacon } from '@aura-labs-ai/beacon';\n\nconst beacon = createBeacon({ ... });\nbeacon.setKeyManager(keyManager, agentId);\n\n// Offers are auto-signed when submitted\nawait beacon.submitOffer(sessionId, {\n  product: { name: 'Widget', sku: 'WDG-001' },\n  unitPrice: 85.00,\n  quantity: 500,\n});\n// Response includes: signatures.beacon, signatures.core, signatures.core_receipt_at\n```\n\n**Manual signing** is also available via `beacon.signOffer(sessionId, offer)` or the exported `signOffer()` function.\n\n**Canonical payload format** (newline-delimited, deterministic):\n`session_id\\nbeacon_id\\nproduct_json\\nunit_price\\nquantity\\ntotal_price\\ncurrency`\n\nUnsigned offers are hard-rejected by Core (HTTP 400).\n\n## Key Storage\n\nEd25519 private keys are persisted across restarts using pluggable storage adapters from `@aura-labs-ai/sdk-common`. The `createStorage()` factory auto-detects the best adapter for the current platform:\n\n| Platform | Adapter | Details |\n|----------|---------|---------|\n| **macOS** | `KeychainStorage` | Hardware-backed encryption at rest via Secure Enclave on Apple Silicon. Uses the `security` CLI — zero native dependencies. |\n| **Linux / Windows** | `FileStorage` | JSON file at `~/.aura/keys.json` with `0600` permissions (owner read/write only). |\n| **Testing** | `MemoryStorage` | In-memory, ephemeral. No persistence. |\n\n```javascript\nimport { createBeacon, createStorage } from '@aura-labs-ai/beacon';\n\n// Auto-detect (recommended)\nconst storage = createStorage();\n\n// Force file-based storage\nconst storage = createStorage({ type: 'file' });\n\n// Force Keychain (macOS only — throws on other platforms)\nconst storage = createStorage({ type: 'keychain' });\n```\n\nOverride the default file path with the `AURA_KEY_PATH` environment variable.\n\n## Environment Variables\n\n| Variable | Description |\n|----------|-------------|\n| `AURA_CORE_URL` | Core API URL (optional) |\n| `POLL_INTERVAL` | Polling interval in ms (optional) |\n| `AURA_KEY_PATH` | Custom path for file-based key storage (default: `~/.aura/keys.json`) |\n\n## License\n\nBusiness Source License 1.1 — See [LICENSE](LICENSE) for details.\n","readmeFilename":"README.md","_rev":"1-591ff07cd646a030291c2e4639026854"}