lane-sdk 0.2.3 → 0.2.9

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.

Potentially problematic release.


This version of lane-sdk might be problematic. Click here for more details.

Files changed (36) hide show
  1. package/SKILL.md +148 -20
  2. package/dist/adapters/crewai/index.cjs +36 -4
  3. package/dist/adapters/crewai/index.cjs.map +1 -1
  4. package/dist/adapters/crewai/index.js +36 -4
  5. package/dist/adapters/crewai/index.js.map +1 -1
  6. package/dist/adapters/langchain/index.cjs +36 -4
  7. package/dist/adapters/langchain/index.cjs.map +1 -1
  8. package/dist/adapters/langchain/index.js +36 -4
  9. package/dist/adapters/langchain/index.js.map +1 -1
  10. package/dist/adapters/openai/index.cjs +36 -4
  11. package/dist/adapters/openai/index.cjs.map +1 -1
  12. package/dist/adapters/openai/index.js +36 -4
  13. package/dist/adapters/openai/index.js.map +1 -1
  14. package/dist/adapters/vercel-ai/index.cjs +36 -4
  15. package/dist/adapters/vercel-ai/index.cjs.map +1 -1
  16. package/dist/adapters/vercel-ai/index.js +36 -4
  17. package/dist/adapters/vercel-ai/index.js.map +1 -1
  18. package/dist/cli/index.js +264 -40
  19. package/dist/cli/index.js.map +1 -1
  20. package/dist/cli/postinstall.js +2 -0
  21. package/dist/cli/postinstall.js.map +1 -1
  22. package/dist/index.cjs +36 -4
  23. package/dist/index.cjs.map +1 -1
  24. package/dist/index.js +36 -4
  25. package/dist/index.js.map +1 -1
  26. package/dist/server/vic-demo.js +1052 -0
  27. package/dist/server/vic-demo.js.map +1 -0
  28. package/dist/server-http.cjs +36 -4
  29. package/dist/server-http.cjs.map +1 -1
  30. package/dist/server-http.js +36 -4
  31. package/dist/server-http.js.map +1 -1
  32. package/dist/server-stdio.cjs +36 -4
  33. package/dist/server-stdio.cjs.map +1 -1
  34. package/dist/server-stdio.js +36 -4
  35. package/dist/server-stdio.js.map +1 -1
  36. package/package.json +6 -2
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../server/vic-demo/index.ts","../../server/vic-demo/routes.ts","../../server/vic-demo/helpers.ts"],"sourcesContent":["// ---------------------------------------------------------------------------\n// VIC Demo Server — Standalone Express Server\n// ---------------------------------------------------------------------------\n// A self-contained mock of the Lane VIC API endpoints for demos and\n// development. No Supabase or Visa access required — fully in-memory.\n//\n// Supports:\n// - All SDK VIC resource methods (issue, get, list, revoke, suspend, reactivate)\n// - Payment credential retrieval (DPAN + cryptogram)\n// - Purchase intent lifecycle (create, update, cancel, confirm)\n// - Instruction lifecycle (create, confirm, credential) for MCP tool flow\n// - Raw Visa IC 6-step flow endpoints\n// - Wallet/card lookup for auto-resolution\n// - Idempotency key support\n//\n// Usage:\n// npx tsx server/vic-demo/index.ts # Dev mode\n// node dist/server/vic-demo.js # Production build\n//\n// Point the SDK at this server:\n// const lane = Lane._unsafeCreate({ baseUrl: 'http://localhost:3020' });\n// ---------------------------------------------------------------------------\n\nimport 'dotenv/config';\nimport crypto from 'node:crypto';\nimport express from 'express';\nimport type { Request, Response, NextFunction } from 'express';\nimport {\n createVICRoutes,\n createInstructionRoutes,\n createVICFlowRoutes,\n wallets,\n cards,\n tokens,\n intents,\n instructions,\n} from './routes.js';\n\n// ---------------------------------------------------------------------------\n// Express app\n// ---------------------------------------------------------------------------\n\nconst app = express();\n\napp.use(express.json());\n\n// Permissive CORS for demo\napp.use((_req: Request, res: Response, next: NextFunction) => {\n res.header('Access-Control-Allow-Origin', '*');\n res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS');\n res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-Lane-Request-Id, X-Idempotency-Key, X-Lane-Signature, X-Lane-Timestamp');\n if (_req.method === 'OPTIONS') {\n res.status(204).send();\n return;\n }\n next();\n});\n\n// ---------------------------------------------------------------------------\n// Lightweight auth middleware — accepts any Bearer token\n// ---------------------------------------------------------------------------\n\napp.use('/agent', (req: Request, _res: Response, next: NextFunction) => {\n const auth = req.headers.authorization;\n if (!auth || !auth.startsWith('Bearer ')) {\n _res.status(401).json({\n error: { code: 'unauthorized', message: 'Bearer token required', statusCode: 401 },\n });\n return;\n }\n // Set a demo developer context\n (req as unknown as Record<string, unknown>).developer = { id: 'dev_demo_001', name: 'Demo Developer' };\n next();\n});\n\n// Also protect /vic routes\napp.use('/vic', (req: Request, _res: Response, next: NextFunction) => {\n const auth = req.headers.authorization;\n if (!auth || !auth.startsWith('Bearer ')) {\n _res.status(401).json({\n error: { code: 'unauthorized', message: 'Bearer token required', statusCode: 401 },\n });\n return;\n }\n (req as unknown as Record<string, unknown>).developer = { id: 'dev_demo_001', name: 'Demo Developer' };\n next();\n});\n\n// ---------------------------------------------------------------------------\n// Seed data\n// ---------------------------------------------------------------------------\n\nwallets.set('wallet_demo_001', {\n id: 'wallet_demo_001',\n balance: 100_000, // $1,000.00\n currency: 'USD',\n createdAt: new Date().toISOString(),\n});\n\nwallets.set('wallet_demo_002', {\n id: 'wallet_demo_002',\n balance: 500_000, // $5,000.00\n currency: 'USD',\n createdAt: new Date().toISOString(),\n});\n\ncards.set('card_demo_001', {\n id: 'card_demo_001',\n walletId: 'wallet_demo_001',\n last4: '4242',\n brand: 'visa',\n expMonth: 12,\n expYear: 2030,\n status: 'active',\n});\n\ncards.set('card_demo_002', {\n id: 'card_demo_002',\n walletId: 'wallet_demo_002',\n last4: '1234',\n brand: 'visa',\n expMonth: 6,\n expYear: 2029,\n status: 'active',\n});\n\n// ---------------------------------------------------------------------------\n// Health check\n// ---------------------------------------------------------------------------\n\napp.get('/health', (_req: Request, res: Response) => {\n res.json({\n service: 'VIC Demo Server',\n status: 'healthy',\n version: '1.1.0',\n note: 'Mock implementation of Lane VIC API for demos and development',\n features: [\n 'VIC token lifecycle (issue, suspend, reactivate, revoke)',\n 'Payment credentials (DPAN + cryptogram)',\n 'Purchase intent management (create, update, cancel, confirm)',\n 'Instruction lifecycle with biometric confirmation',\n 'Raw Visa IC 6-step flow endpoints',\n 'Idempotency key support',\n ],\n stats: {\n tokens: tokens.size,\n intents: intents.size,\n instructions: instructions.size,\n wallets: wallets.size,\n cards: cards.size,\n },\n seedData: {\n wallets: ['wallet_demo_001 ($1,000.00)', 'wallet_demo_002 ($5,000.00)'],\n cards: ['card_demo_001 (Visa ***4242)', 'card_demo_002 (Visa ***1234)'],\n },\n });\n});\n\n// ---------------------------------------------------------------------------\n// Mount routes\n// ---------------------------------------------------------------------------\n\n// SDK-facing VIC token routes (matches SDK basePath /agent/token)\napp.use('/agent/token', createVICRoutes());\n\n// SDK-facing instruction routes (matches SDK basePath /agent/instruction)\napp.use('/agent/instruction', createInstructionRoutes());\n\n// Raw Visa IC 6-step flow routes (matches production server/routes/vic.ts)\napp.use('/vic', createVICFlowRoutes());\n\n// ---------------------------------------------------------------------------\n// Wallet/card lookup endpoints (so MCP tool can auto-resolve)\n// ---------------------------------------------------------------------------\n\napp.get('/agent/wallet', (_req: Request, res: Response) => {\n const allWallets = Array.from(wallets.values()).map((w) => ({\n id: w.id,\n label: `Demo Wallet (${w.id})`,\n developerId: 'dev_demo_001',\n status: 'active' as const,\n createdAt: w.createdAt,\n updatedAt: w.createdAt,\n }));\n const limit = Math.min(parseInt(_req.query.limit as string) || 20, 100);\n const offset = parseInt(_req.query.offset as string) || 0;\n res.json({\n data: allWallets.slice(offset, offset + limit),\n total: allWallets.length,\n limit,\n offset,\n });\n});\n\napp.get('/agent/wallet/:walletId', (req: Request, res: Response) => {\n const wallet = wallets.get(req.params.walletId as string);\n if (!wallet) {\n res.status(404).json({ error: { code: 'not_found', message: 'Wallet not found' } });\n return;\n }\n res.json({\n id: wallet.id,\n label: `Demo Wallet (${wallet.id})`,\n developerId: 'dev_demo_001',\n status: 'active',\n createdAt: wallet.createdAt,\n updatedAt: wallet.createdAt,\n });\n});\n\napp.get('/agent/wallet/:walletId/cards', (req: Request, res: Response) => {\n const walletCards = Array.from(cards.values())\n .filter((c) => c.walletId === req.params.walletId)\n .map((c) => ({\n id: c.id,\n last4: c.last4,\n brand: c.brand,\n status: c.status,\n isDefault: true,\n createdAt: new Date().toISOString(),\n }));\n res.json(walletCards);\n});\n\napp.get('/agent/wallet/:walletId/balance', (req: Request, res: Response) => {\n const walletId = req.params.walletId as string;\n // 'default' resolves to the first wallet (used by lane status)\n const wallet = walletId === 'default'\n ? Array.from(wallets.values())[0]\n : wallets.get(walletId);\n if (!wallet) {\n res.status(404).json({ error: { code: 'not_found', message: 'Wallet not found' } });\n return;\n }\n res.json({\n balance: wallet.balance,\n currency: wallet.currency,\n });\n});\n\n// ---------------------------------------------------------------------------\n// Auth & admin endpoints (for CLI flow: status, whoami, pay budget check)\n// ---------------------------------------------------------------------------\n\n// POST /agent/auth/verify-sdk-access — always grants access in demo\napp.post('/agent/auth/verify-sdk-access', (_req: Request, res: Response) => {\n res.json({ access: true, demo: true });\n});\n\n// GET /agent/admin/whoami — DeveloperProfile shape for lane status / lane whoami\napp.get('/agent/admin/whoami', (_req: Request, res: Response) => {\n res.json({\n id: 'dev_demo_001',\n email: 'demo@getonlane.com',\n plan: 'demo',\n memberSince: '2024-01-01',\n });\n});\n\n// GET /agent/admin/budgets — BudgetConfig shape for lane pay budget check\napp.get('/agent/admin/budgets', (_req: Request, res: Response) => {\n res.json({\n dailyLimit: 50000,\n weeklyLimit: 200000,\n monthlyLimit: 500000,\n perTaskLimit: 10000,\n });\n});\n\n// GET /agent/card — PaginatedResponse<Card> for lane status / lane card list\napp.get('/agent/card', (_req: Request, res: Response) => {\n const allCards = Array.from(cards.values()).map((c) => ({\n id: c.id,\n last4: c.last4,\n brand: c.brand,\n status: c.status,\n isDefault: true,\n createdAt: new Date().toISOString(),\n }));\n const limit = Math.min(parseInt(_req.query.limit as string) || 20, 100);\n const offset = parseInt(_req.query.offset as string) || 0;\n res.json({\n data: allCards.slice(offset, offset + limit),\n total: allCards.length,\n limit,\n offset,\n });\n});\n\n// POST /agent/pay — Transaction shape for lane pay (non-provision)\napp.post('/agent/pay', (req: Request, res: Response) => {\n res.json({\n id: `txn_demo_${crypto.randomUUID().slice(0, 8)}`,\n amount: req.body.amount ?? 0,\n currency: req.body.currency ?? 'USD',\n recipient: req.body.recipient ?? 'demo-merchant',\n description: req.body.description,\n status: 'success',\n testMode: true,\n createdAt: new Date().toISOString(),\n });\n});\n\n// GET /agent/transaction — empty transaction list\napp.get('/agent/transaction', (_req: Request, res: Response) => {\n const limit = Math.min(parseInt(_req.query.limit as string) || 20, 100);\n const offset = parseInt(_req.query.offset as string) || 0;\n res.json({ data: [], total: 0, limit, offset });\n});\n\n// ---------------------------------------------------------------------------\n// Auth discovery endpoint (for MCP connection flow)\n// ---------------------------------------------------------------------------\n\napp.get('/agent/discovery', (_req: Request, res: Response) => {\n res.json({\n name: 'Lane VIC Demo',\n version: '1.1.0',\n capabilities: ['vic', 'instructions', 'wallets'],\n authMethods: ['bearer'],\n });\n});\n\n// ---------------------------------------------------------------------------\n// Global error handler\n// ---------------------------------------------------------------------------\n\napp.use((err: Error, _req: Request, res: Response, _next: NextFunction) => {\n const requestId = (_req.headers['x-lane-request-id'] as string) ?? `req_${Date.now()}`;\n console.error('[VIC Demo] Error:', err.message);\n res.status(500).json({\n error: {\n code: 'internal_error',\n message: err.message,\n statusCode: 500,\n },\n requestId,\n });\n});\n\n// ---------------------------------------------------------------------------\n// Start server\n// ---------------------------------------------------------------------------\n\nconst PORT = parseInt(process.env.PORT ?? '3020', 10);\n\nconst server = app.listen(PORT, () => {\n console.log(`[VIC Demo] Server running on http://localhost:${PORT}`);\n console.log(`[VIC Demo] Health: http://localhost:${PORT}/health`);\n console.log(`[VIC Demo]`);\n console.log(`[VIC Demo] Routes:`);\n console.log(`[VIC Demo] SDK VIC tokens: /agent/token/*`);\n console.log(`[VIC Demo] SDK instructions: /agent/instruction/*`);\n console.log(`[VIC Demo] SDK wallets: /agent/wallet/*`);\n console.log(`[VIC Demo] Visa IC 6-step: /vic/*`);\n console.log(`[VIC Demo]`);\n console.log(`[VIC Demo] Seed data:`);\n console.log(`[VIC Demo] Wallet: wallet_demo_001 ($1,000.00)`);\n console.log(`[VIC Demo] Wallet: wallet_demo_002 ($5,000.00)`);\n console.log(`[VIC Demo] Card: card_demo_001 (Visa ***4242)`);\n console.log(`[VIC Demo] Card: card_demo_002 (Visa ***1234)`);\n console.log(`[VIC Demo]`);\n console.log(`[VIC Demo] SDK usage:`);\n console.log(`[VIC Demo] const lane = Lane._unsafeCreate({ baseUrl: 'http://localhost:${PORT}' });`);\n console.log(`[VIC Demo] const token = await lane.vic.issue({ walletId: 'wallet_demo_001', cardId: 'card_demo_001' });`);\n console.log(`[VIC Demo] const creds = await lane.vic.getPaymentCredentials(token.id, { amount: 1999, currency: 'USD', merchantId: 'amazon.com' });`);\n});\n\n// Graceful shutdown\nfor (const signal of ['SIGTERM', 'SIGINT'] as const) {\n process.on(signal, () => {\n console.log(`[VIC Demo] Received ${signal}, shutting down...`);\n server.close(() => process.exit(0));\n });\n}\n\nexport default app;\n","// ---------------------------------------------------------------------------\n// VIC Demo Server — Route Handlers\n// ---------------------------------------------------------------------------\n// Implements all VIC-related Lane API endpoints with in-memory storage.\n// Matches the SDK resource at src/resources/vic.ts and supports the full\n// Visa Intelligent Commerce 6-step flow.\n// ---------------------------------------------------------------------------\n\nimport crypto from 'node:crypto';\nimport { Router } from 'express';\nimport type { Request, Response } from 'express';\nimport {\n generateDPAN,\n generateCryptogram,\n generateId,\n parseExpiry,\n type VICTokenRecord,\n type PurchaseIntent,\n type IntentMandate,\n type DemoWallet,\n type DemoCard,\n type DemoInstruction,\n type DemoMandate,\n type DemoConfirmation,\n type DemoCredential,\n type EnrolledCard,\n} from './helpers.js';\n\n// ---------------------------------------------------------------------------\n// In-memory stores\n// ---------------------------------------------------------------------------\n\nexport const tokens = new Map<string, VICTokenRecord>();\nexport const intents = new Map<string, PurchaseIntent>();\nexport const wallets = new Map<string, DemoWallet>();\nexport const cards = new Map<string, DemoCard>();\nexport const instructions = new Map<string, DemoInstruction>();\nexport const mandates = new Map<string, DemoMandate>();\nexport const confirmations = new Map<string, DemoConfirmation[]>();\nexport const credentials = new Map<string, DemoCredential>();\nexport const enrolledCards = new Map<string, EnrolledCard>();\n\n/** Idempotency cache: key → { statusCode, body, createdAt } */\nconst idempotencyCache = new Map<string, { statusCode: number; body: unknown; createdAt: number }>();\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction toVICTokenResponse(token: VICTokenRecord) {\n return {\n id: token.id,\n walletId: token.walletId,\n networkTokenId: token.networkTokenId,\n last4: token.last4,\n brand: token.brand,\n status: token.status,\n expiresAt: token.expiresAt,\n createdAt: token.createdAt,\n };\n}\n\nfunction checkIdempotency(req: Request, res: Response): boolean {\n const key = req.headers['x-idempotency-key'] as string | undefined;\n if (!key) return false;\n const cached = idempotencyCache.get(key);\n if (cached) {\n res.status(cached.statusCode).json(cached.body);\n return true;\n }\n return false;\n}\n\nfunction cacheIdempotent(req: Request, statusCode: number, body: unknown): void {\n const key = req.headers['x-idempotency-key'] as string | undefined;\n if (key) {\n idempotencyCache.set(key, { statusCode, body, createdAt: Date.now() });\n }\n}\n\n// ---------------------------------------------------------------------------\n// VIC Token Routes (SDK-facing: mounted at /agent/token)\n// ---------------------------------------------------------------------------\n\nexport function createVICRoutes(): Router {\n const router = Router();\n\n // -------------------------------------------------------------------------\n // Intent routes MUST be registered before /:id routes to avoid conflicts\n // -------------------------------------------------------------------------\n\n // GET /intents — List all purchase intents\n router.get('/intents', (_req: Request, res: Response) => {\n const results = Array.from(intents.values());\n const limit = Math.min(parseInt(_req.query.limit as string) || 20, 100);\n const offset = parseInt(_req.query.offset as string) || 0;\n\n // Filter by tokenId if provided\n let filtered = results;\n if (_req.query.tokenId) {\n filtered = filtered.filter((i) => i.tokenId === _req.query.tokenId);\n }\n if (_req.query.status) {\n filtered = filtered.filter((i) => i.status === _req.query.status);\n }\n\n res.json({\n data: filtered.slice(offset, offset + limit),\n total: filtered.length,\n limit,\n offset,\n });\n });\n\n // PUT /intents/:intentId — Update purchase intent (Visa IC Step 3)\n router.put('/intents/:intentId', (req: Request, res: Response) => {\n const intent = intents.get(req.params.intentId as string);\n if (!intent) {\n res.status(404).json({ error: { code: 'not_found', message: 'Purchase intent not found' } });\n return;\n }\n\n if (intent.status === 'cancelled' || intent.status === 'confirmed') {\n res.status(400).json({\n error: { code: 'invalid_state', message: `Cannot update intent in status: ${intent.status}` },\n });\n return;\n }\n\n if (req.body.amount !== undefined) intent.amount = req.body.amount;\n if (req.body.currency !== undefined) intent.currency = req.body.currency;\n if (req.body.merchantId !== undefined) intent.merchantId = req.body.merchantId;\n if (req.body.merchantName !== undefined) intent.merchantName = req.body.merchantName;\n if (req.body.description !== undefined) intent.description = req.body.description;\n if (req.body.mandates !== undefined) intent.mandates = req.body.mandates;\n intent.status = 'updated';\n intent.updatedAt = new Date().toISOString();\n\n console.log(`[VIC Demo] Intent updated: ${intent.id}`);\n res.json({ intentId: intent.id });\n });\n\n // DELETE /intents/:intentId — Cancel purchase intent (Visa IC Step 4)\n router.delete('/intents/:intentId', (req: Request, res: Response) => {\n const intent = intents.get(req.params.intentId as string);\n if (!intent) {\n res.status(404).json({ error: { code: 'not_found', message: 'Purchase intent not found' } });\n return;\n }\n\n if (intent.status === 'confirmed') {\n res.status(400).json({\n error: { code: 'invalid_state', message: 'Cannot cancel a confirmed intent' },\n });\n return;\n }\n\n intent.status = 'cancelled';\n intent.updatedAt = new Date().toISOString();\n\n console.log(`[VIC Demo] Intent cancelled: ${intent.id}`);\n // Return JSON body — SDK LaneClient always calls response.json()\n res.json({ cancelled: true, intentId: intent.id });\n });\n\n // POST /intents/:intentId/confirm — Confirm transaction (Visa IC Step 6)\n router.post('/intents/:intentId/confirm', (req: Request, res: Response) => {\n const intent = intents.get(req.params.intentId as string);\n if (!intent) {\n res.status(404).json({ error: { code: 'not_found', message: 'Purchase intent not found' } });\n return;\n }\n\n if (intent.status === 'cancelled') {\n res.status(400).json({\n error: { code: 'invalid_state', message: 'Cannot confirm a cancelled intent' },\n });\n return;\n }\n\n intent.status = 'confirmed';\n intent.updatedAt = new Date().toISOString();\n\n console.log(`[VIC Demo] Transaction confirmed: ${intent.id} (txn: ${req.body.transactionId}, status: ${req.body.status})`);\n res.json({\n confirmed: true,\n intentId: intent.id,\n transactionId: req.body.transactionId,\n confirmedAt: intent.updatedAt,\n });\n });\n\n // POST /intents/:intentId/credentials — Retrieve credentials for an intent (VIC Step 5 alternative)\n router.post('/intents/:intentId/credentials', (req: Request, res: Response) => {\n const intent = intents.get(req.params.intentId as string);\n if (!intent) {\n res.status(404).json({ error: { code: 'not_found', message: 'Purchase intent not found' } });\n return;\n }\n\n if (intent.status === 'cancelled') {\n res.status(400).json({\n error: { code: 'invalid_state', message: 'Cannot retrieve credentials for a cancelled intent' },\n });\n return;\n }\n\n // Find the associated token\n const token = tokens.get(intent.tokenId);\n const card = token ? Array.from(cards.values()).find((c) => c.walletId === token.walletId) : null;\n\n const cryptogram = generateCryptogram();\n intent.status = 'credentials_retrieved';\n intent.updatedAt = new Date().toISOString();\n\n console.log(`[VIC Demo] Credentials retrieved for intent: ${intent.id}`);\n\n res.json({\n tokenNumber: intent.networkTokenId,\n cryptogram,\n eci: '05',\n expMonth: card?.expMonth ?? 12,\n expYear: card?.expYear ?? 2030,\n });\n });\n\n // -------------------------------------------------------------------------\n // Token CRUD routes\n // -------------------------------------------------------------------------\n\n // POST / — Issue a VIC token (combines VIC Steps 1 & 2: enroll card + create intent)\n router.post('/', (req: Request, res: Response) => {\n if (checkIdempotency(req, res)) return;\n\n const { walletId, cardId, maxTransactionAmount, allowedMCCs, expiresIn } = req.body;\n\n if (!walletId || !cardId) {\n res.status(400).json({\n error: { code: 'validation_error', message: 'walletId and cardId are required' },\n });\n return;\n }\n\n const wallet = wallets.get(walletId);\n if (!wallet) {\n res.status(404).json({ error: { code: 'not_found', message: `Wallet ${walletId} not found` } });\n return;\n }\n\n const card = cards.get(cardId);\n if (!card || card.walletId !== walletId) {\n res.status(404).json({ error: { code: 'not_found', message: `Card ${cardId} not found in wallet` } });\n return;\n }\n\n if (card.status !== 'active') {\n res.status(400).json({\n error: { code: 'card_not_active', message: `Card ${cardId} is ${card.status}` },\n });\n return;\n }\n\n const tokenId = generateId('vic_tok');\n const dpan = generateDPAN();\n const now = new Date().toISOString();\n const expiresAt = parseExpiry(expiresIn ?? '24h');\n\n const token: VICTokenRecord = {\n id: tokenId,\n walletId,\n cardId,\n networkTokenId: dpan,\n last4: card.last4,\n brand: 'visa',\n status: 'active',\n maxTransactionAmount,\n allowedMCCs,\n expiresAt,\n createdAt: now,\n };\n\n tokens.set(tokenId, token);\n\n // Implicitly create a purchase intent (VIC Step 2)\n const intentId = crypto.randomUUID();\n intents.set(intentId, {\n id: intentId,\n tokenId,\n networkTokenId: dpan,\n amount: maxTransactionAmount ?? 0,\n currency: 'USD',\n merchantId: null,\n merchantName: null,\n description: null,\n mandates: allowedMCCs\n ? [{\n mandateId: crypto.randomUUID(),\n declineThreshold: { amount: String(maxTransactionAmount ?? 0), currencyCode: 'USD' },\n effectiveUntilTime: expiresAt,\n description: `MCC-restricted: ${allowedMCCs.join(', ')}`,\n }]\n : [],\n status: 'created',\n createdAt: now,\n updatedAt: now,\n });\n\n console.log(`[VIC Demo] Token issued: ${tokenId} → DPAN ***${dpan.slice(-4)} (intent: ${intentId})`);\n\n const body = toVICTokenResponse(token);\n cacheIdempotent(req, 201, body);\n res.status(201).json(body);\n });\n\n // GET / — List VIC tokens\n router.get('/', (req: Request, res: Response) => {\n let results = Array.from(tokens.values());\n\n if (req.query.walletId) {\n results = results.filter((t) => t.walletId === req.query.walletId);\n }\n if (req.query.status) {\n results = results.filter((t) => t.status === req.query.status);\n }\n if (req.query.cardId) {\n results = results.filter((t) => t.cardId === req.query.cardId);\n }\n\n const limit = Math.min(parseInt(req.query.limit as string) || 20, 100);\n const offset = parseInt(req.query.offset as string) || 0;\n const total = results.length;\n const page = results.slice(offset, offset + limit);\n\n res.json({\n data: page.map(toVICTokenResponse),\n total,\n limit,\n offset,\n });\n });\n\n // GET /:id — Get a VIC token\n router.get('/:id', (req: Request, res: Response) => {\n const token = tokens.get(req.params.id as string);\n if (!token) {\n res.status(404).json({ error: { code: 'not_found', message: 'Token not found' } });\n return;\n }\n\n // Check for token expiry\n if (token.status === 'active' && new Date(token.expiresAt) < new Date()) {\n token.status = 'expired';\n }\n\n res.json(toVICTokenResponse(token));\n });\n\n // POST /:id/cryptogram — Get payment credentials (VIC Step 5)\n router.post('/:id/cryptogram', (req: Request, res: Response) => {\n const token = tokens.get(req.params.id as string);\n if (!token) {\n res.status(404).json({ error: { code: 'not_found', message: 'Token not found' } });\n return;\n }\n\n // Check for token expiry\n if (token.status === 'active' && new Date(token.expiresAt) < new Date()) {\n token.status = 'expired';\n }\n\n if (token.status !== 'active') {\n res.status(400).json({\n error: { code: 'token_not_active', message: `Token is ${token.status}` },\n });\n return;\n }\n\n // Enforce maxTransactionAmount\n if (token.maxTransactionAmount && req.body.amount > token.maxTransactionAmount) {\n res.status(400).json({\n error: {\n code: 'amount_exceeded',\n message: `Amount ${req.body.amount} exceeds token max ${token.maxTransactionAmount}`,\n },\n });\n return;\n }\n\n // Look up card for expiry\n const card = cards.get(token.cardId) ??\n Array.from(cards.values()).find((c) => c.walletId === token.walletId);\n\n const cryptogram = generateCryptogram();\n\n // Create/update a purchase intent to track the flow\n const intentId = crypto.randomUUID();\n const now = new Date().toISOString();\n intents.set(intentId, {\n id: intentId,\n tokenId: token.id,\n networkTokenId: token.networkTokenId,\n amount: req.body.amount ?? 0,\n currency: req.body.currency ?? 'USD',\n merchantId: req.body.merchantId ?? null,\n merchantName: null,\n description: null,\n mandates: [],\n status: 'credentials_retrieved',\n createdAt: now,\n updatedAt: now,\n });\n\n console.log(`[VIC Demo] Credentials retrieved for token: ${token.id} (intent: ${intentId})`);\n\n // Return NetworkTokenPayload shape\n res.json({\n tokenNumber: token.networkTokenId,\n cryptogram,\n eci: '05',\n expMonth: card?.expMonth ?? 12,\n expYear: card?.expYear ?? 2030,\n });\n });\n\n // POST /:id/revoke — Revoke a VIC token\n router.post('/:id/revoke', (req: Request, res: Response) => {\n const token = tokens.get(req.params.id as string);\n if (!token) {\n res.status(404).json({ error: { code: 'not_found', message: 'Token not found' } });\n return;\n }\n\n if (token.status === 'revoked') {\n res.status(400).json({\n error: { code: 'invalid_state', message: 'Token is already revoked' },\n });\n return;\n }\n\n token.status = 'revoked';\n console.log(`[VIC Demo] Token revoked: ${token.id}`);\n res.json(toVICTokenResponse(token));\n });\n\n // POST /:id/suspend — Suspend a VIC token\n router.post('/:id/suspend', (req: Request, res: Response) => {\n const token = tokens.get(req.params.id as string);\n if (!token) {\n res.status(404).json({ error: { code: 'not_found', message: 'Token not found' } });\n return;\n }\n\n if (token.status !== 'active') {\n res.status(400).json({\n error: { code: 'invalid_state', message: `Cannot suspend token in status: ${token.status}` },\n });\n return;\n }\n\n token.status = 'suspended';\n console.log(`[VIC Demo] Token suspended: ${token.id}`);\n res.json(toVICTokenResponse(token));\n });\n\n // POST /:id/reactivate — Reactivate a suspended VIC token\n router.post('/:id/reactivate', (req: Request, res: Response) => {\n const token = tokens.get(req.params.id as string);\n if (!token) {\n res.status(404).json({ error: { code: 'not_found', message: 'Token not found' } });\n return;\n }\n\n if (token.status !== 'suspended') {\n res.status(400).json({\n error: { code: 'invalid_state', message: `Cannot reactivate token in status: ${token.status}` },\n });\n return;\n }\n\n token.status = 'active';\n console.log(`[VIC Demo] Token reactivated: ${token.id}`);\n res.json(toVICTokenResponse(token));\n });\n\n return router;\n}\n\n// ---------------------------------------------------------------------------\n// Instruction Routes (SDK-facing: mounted at /agent/instruction)\n// ---------------------------------------------------------------------------\n// Supports the MCP provision_vic_payment tool flow:\n// 1. Create instruction with amount/merchant constraints\n// 2. Create biometric confirmation\n// 3. Retrieve credential\n// ---------------------------------------------------------------------------\n\nexport function createInstructionRoutes(): Router {\n const router = Router();\n\n // POST / — Create instruction\n router.post('/', (req: Request, res: Response) => {\n if (checkIdempotency(req, res)) return;\n\n const now = new Date().toISOString();\n const id = generateId('instr');\n\n const instruction: DemoInstruction = {\n id,\n walletId: req.body.walletId,\n type: req.body.type ?? 'payment',\n amount: req.body.amount,\n currency: req.body.currency ?? 'USD',\n merchant: req.body.merchant,\n permissions: req.body.permissions ?? ['pay'],\n constraints: req.body.constraints ?? {},\n status: 'pending_confirmation',\n spentCents: 0,\n remainingCents: req.body.amount ?? null,\n expiresAt: req.body.expiresIn ? parseExpiry(req.body.expiresIn) : undefined,\n createdAt: now,\n };\n\n instructions.set(id, instruction);\n confirmations.set(id, []);\n\n console.log(`[VIC Demo] Instruction created: ${id} (amount: ${instruction.amount}, merchant: ${instruction.merchant})`);\n\n const body = { ...instruction };\n cacheIdempotent(req, 201, body);\n res.status(201).json(body);\n });\n\n // GET / — List instructions\n router.get('/', (_req: Request, res: Response) => {\n const results = Array.from(instructions.values());\n const limit = Math.min(parseInt(_req.query.limit as string) || 20, 100);\n const offset = parseInt(_req.query.offset as string) || 0;\n\n res.json({\n data: results.slice(offset, offset + limit),\n total: results.length,\n limit,\n offset,\n });\n });\n\n // GET /:id — Get instruction\n router.get('/:id', (req: Request, res: Response) => {\n const instruction = instructions.get(req.params.id as string);\n if (!instruction) {\n res.status(404).json({ error: { code: 'not_found', message: 'Instruction not found' } });\n return;\n }\n res.json(instruction);\n });\n\n // PUT /:id — Update instruction\n router.put('/:id', (req: Request, res: Response) => {\n const instruction = instructions.get(req.params.id as string);\n if (!instruction) {\n res.status(404).json({ error: { code: 'not_found', message: 'Instruction not found' } });\n return;\n }\n\n if (req.body.amount !== undefined) instruction.amount = req.body.amount;\n if (req.body.currency !== undefined) instruction.currency = req.body.currency;\n if (req.body.merchant !== undefined) instruction.merchant = req.body.merchant;\n if (req.body.permissions !== undefined) instruction.permissions = req.body.permissions;\n if (req.body.constraints !== undefined) instruction.constraints = req.body.constraints;\n\n res.json(instruction);\n });\n\n // POST /:id/cancel — Cancel instruction\n router.post('/:id/cancel', (req: Request, res: Response) => {\n const instruction = instructions.get(req.params.id as string);\n if (!instruction) {\n res.status(404).json({ error: { code: 'not_found', message: 'Instruction not found' } });\n return;\n }\n\n instruction.status = 'cancelled';\n console.log(`[VIC Demo] Instruction cancelled: ${instruction.id}`);\n res.json(instruction);\n });\n\n // -------------------------------------------------------------------------\n // Mandate CRUD (nested under instruction)\n // -------------------------------------------------------------------------\n\n // POST /:id/mandate — Add mandate to instruction\n router.post('/:id/mandate', (req: Request, res: Response) => {\n const instruction = instructions.get(req.params.id as string);\n if (!instruction) {\n res.status(404).json({ error: { code: 'not_found', message: 'Instruction not found' } });\n return;\n }\n\n const mandate: DemoMandate = {\n id: generateId('mdt'),\n instructionId: instruction.id,\n type: req.body.type ?? 'spending_limit',\n config: req.body.config ?? {},\n status: 'active',\n spentCents: 0,\n remainingCents: req.body.config?.maxAmount ?? 0,\n createdAt: new Date().toISOString(),\n };\n\n mandates.set(mandate.id, mandate);\n res.status(201).json(mandate);\n });\n\n // GET /:id/mandate — List mandates for instruction\n router.get('/:id/mandate', (req: Request, res: Response) => {\n const instruction = instructions.get(req.params.id as string);\n if (!instruction) {\n res.status(404).json({ error: { code: 'not_found', message: 'Instruction not found' } });\n return;\n }\n\n const result = Array.from(mandates.values()).filter((m) => m.instructionId === instruction.id);\n res.json(result);\n });\n\n // GET /:id/mandate/:mandateId — Get mandate\n router.get('/:id/mandate/:mandateId', (req: Request, res: Response) => {\n const mandate = mandates.get(req.params.mandateId as string);\n if (!mandate || mandate.instructionId !== req.params.id) {\n res.status(404).json({ error: { code: 'not_found', message: 'Mandate not found' } });\n return;\n }\n res.json(mandate);\n });\n\n // PUT /:id/mandate/:mandateId — Update mandate\n router.put('/:id/mandate/:mandateId', (req: Request, res: Response) => {\n const mandate = mandates.get(req.params.mandateId as string);\n if (!mandate || mandate.instructionId !== req.params.id) {\n res.status(404).json({ error: { code: 'not_found', message: 'Mandate not found' } });\n return;\n }\n\n if (req.body.type !== undefined) mandate.type = req.body.type;\n if (req.body.config !== undefined) mandate.config = req.body.config;\n res.json(mandate);\n });\n\n // DELETE /:id/mandate/:mandateId — Delete mandate\n router.delete('/:id/mandate/:mandateId', (req: Request, res: Response) => {\n const mandate = mandates.get(req.params.mandateId as string);\n if (!mandate || mandate.instructionId !== req.params.id) {\n res.status(404).json({ error: { code: 'not_found', message: 'Mandate not found' } });\n return;\n }\n\n mandates.delete(mandate.id);\n res.json({ deleted: true });\n });\n\n // -------------------------------------------------------------------------\n // Confirmations (biometric/manual)\n // -------------------------------------------------------------------------\n\n // GET /:id/confirmation — List confirmations for instruction\n router.get('/:id/confirmation', (req: Request, res: Response) => {\n const instruction = instructions.get(req.params.id as string);\n if (!instruction) {\n res.status(404).json({ error: { code: 'not_found', message: 'Instruction not found' } });\n return;\n }\n\n const result = confirmations.get(instruction.id) ?? [];\n res.json(result);\n });\n\n // POST /:id/confirmation — Create confirmation\n router.post('/:id/confirmation', (req: Request, res: Response) => {\n const instruction = instructions.get(req.params.id as string);\n if (!instruction) {\n res.status(404).json({ error: { code: 'not_found', message: 'Instruction not found' } });\n return;\n }\n\n const confirmation: DemoConfirmation = {\n id: generateId('conf'),\n instructionId: instruction.id,\n confirmedBy: req.body.confirmedBy,\n confirmationType: req.body.confirmationType ?? 'biometric',\n details: {\n method: req.body.method ?? 'touchId',\n timestamp: req.body.timestamp ?? new Date().toISOString(),\n machineId: req.body.machineId,\n ...req.body,\n },\n createdAt: new Date().toISOString(),\n };\n\n const existing = confirmations.get(instruction.id) ?? [];\n existing.push(confirmation);\n confirmations.set(instruction.id, existing);\n\n // Mark instruction as confirmed\n instruction.status = 'confirmed';\n\n console.log(`[VIC Demo] Confirmation created for instruction: ${instruction.id} (type: ${confirmation.confirmationType})`);\n res.status(201).json(confirmation);\n });\n\n // -------------------------------------------------------------------------\n // Credential retrieval\n // -------------------------------------------------------------------------\n\n // POST /:id/credential — Get credential for instruction\n router.post('/:id/credential', (req: Request, res: Response) => {\n const instruction = instructions.get(req.params.id as string);\n if (!instruction) {\n res.status(404).json({ error: { code: 'not_found', message: 'Instruction not found' } });\n return;\n }\n\n const credential: DemoCredential = {\n id: generateId('cred'),\n instructionId: instruction.id,\n credentialType: 'vic_dpan',\n credentialData: {\n tokenNumber: generateDPAN(),\n cryptogram: generateCryptogram(),\n eci: '05',\n expMonth: 12,\n expYear: 2030,\n },\n expiresAt: instruction.expiresAt,\n createdAt: new Date().toISOString(),\n };\n\n credentials.set(credential.id, credential);\n console.log(`[VIC Demo] Credential issued for instruction: ${instruction.id}`);\n res.status(201).json(credential);\n });\n\n // -------------------------------------------------------------------------\n // Budget\n // -------------------------------------------------------------------------\n\n // GET /:id/budget — Get budget status for instruction\n router.get('/:id/budget', (req: Request, res: Response) => {\n const instruction = instructions.get(req.params.id as string);\n if (!instruction) {\n res.status(404).json({ error: { code: 'not_found', message: 'Instruction not found' } });\n return;\n }\n\n const instructionMandates = Array.from(mandates.values())\n .filter((m) => m.instructionId === instruction.id);\n\n res.json({\n amountCents: instruction.amount ?? null,\n spentCents: instruction.spentCents,\n remainingCents: instruction.remainingCents ?? (instruction.amount ? instruction.amount - instruction.spentCents : 0),\n mandateCount: instructionMandates.length,\n completedMandates: instructionMandates.filter((m) => m.status === 'completed').length,\n mandates: instructionMandates.map((m) => ({\n id: m.id,\n name: m.type,\n spentCents: m.spentCents,\n remainingCents: m.remainingCents,\n maxAmountCents: m.config.maxAmount as number | null ?? null,\n status: m.status,\n })),\n });\n });\n\n return router;\n}\n\n// ---------------------------------------------------------------------------\n// Raw Visa IC 6-Step Flow Routes (mounted at /vic)\n// ---------------------------------------------------------------------------\n// These mirror the production server/routes/vic.ts and the raw Visa ACP API\n// for demos that want to show the full Visa Intelligent Commerce flow.\n// ---------------------------------------------------------------------------\n\nexport function createVICFlowRoutes(): Router {\n const router = Router();\n\n // POST /enroll — Step 1: Enroll a card (tokenize via Visa MDES)\n router.post('/enroll', (req: Request, res: Response) => {\n const { walletId, cardId } = req.body;\n\n if (!walletId || !cardId) {\n res.status(400).json({ error: { code: 'validation_error', message: 'walletId and cardId are required' } });\n return;\n }\n\n const card = cards.get(cardId);\n if (!card || card.walletId !== walletId) {\n res.status(404).json({ error: { code: 'not_found', message: 'Card not found in wallet' } });\n return;\n }\n\n // Check if already enrolled\n const existing = Array.from(enrolledCards.values()).find(\n (e) => e.instrumentIdentifierId === cardId && e.status === 'ACTIVE',\n );\n if (existing) {\n res.json({ data: existing });\n return;\n }\n\n const dpan = generateDPAN();\n const enrolled: EnrolledCard = {\n instrumentIdentifierId: cardId,\n clientCorrelationId: req.body.clientCorrelationId ?? crypto.randomUUID(),\n tokenReferenceId: crypto.randomBytes(16).toString('hex'),\n dpan,\n expMonth: card.expMonth,\n expYear: card.expYear,\n status: 'ACTIVE',\n enrolledAt: new Date().toISOString(),\n };\n\n enrolledCards.set(cardId, enrolled);\n\n // Also create a VIC token record for SDK compatibility\n const tokenId = generateId('vic_tok');\n const now = new Date().toISOString();\n tokens.set(tokenId, {\n id: tokenId,\n walletId,\n cardId,\n networkTokenId: dpan,\n last4: card.last4,\n brand: 'visa',\n status: 'active',\n expiresAt: new Date(Date.now() + 365 * 24 * 60 * 60 * 1000).toISOString(),\n createdAt: now,\n });\n\n console.log(`[VIC Demo] Card enrolled: ${cardId} → DPAN ***${dpan.slice(-4)}`);\n res.status(201).json({ data: enrolled });\n });\n\n // POST /intents — Step 2: Create purchase intent\n router.post('/intents', (req: Request, res: Response) => {\n const { networkTokenId, amount, currency, merchantId, merchantName, description } = req.body;\n\n if (!networkTokenId) {\n res.status(400).json({ error: { code: 'validation_error', message: 'networkTokenId is required' } });\n return;\n }\n\n // Verify network token exists\n const token = Array.from(tokens.values()).find((t) => t.networkTokenId === networkTokenId || t.id === networkTokenId);\n if (!token) {\n res.status(404).json({ error: { code: 'not_found', message: 'Network token not found' } });\n return;\n }\n\n const intentId = crypto.randomUUID();\n const now = new Date().toISOString();\n\n const intent: PurchaseIntent = {\n id: intentId,\n tokenId: token.id,\n networkTokenId: token.networkTokenId,\n amount: amount ?? 0,\n currency: currency ?? 'USD',\n merchantId: merchantId ?? null,\n merchantName: merchantName ?? null,\n description: description ?? null,\n mandates: req.body.mandates ?? [],\n status: 'created',\n createdAt: now,\n updatedAt: now,\n };\n\n intents.set(intentId, intent);\n\n console.log(`[VIC Demo] Purchase intent created: ${intentId} (token: ${token.id})`);\n res.status(201).json({ data: { intentId } });\n });\n\n // PUT /intents/:id — Step 3: Update purchase intent\n router.put('/intents/:id', (req: Request, res: Response) => {\n const intent = intents.get(req.params.id as string);\n if (!intent) {\n res.status(404).json({ error: { code: 'not_found', message: 'Purchase intent not found' } });\n return;\n }\n\n if (intent.status === 'cancelled' || intent.status === 'confirmed') {\n res.status(400).json({\n error: { code: 'invalid_state', message: `Cannot update intent in status: ${intent.status}` },\n });\n return;\n }\n\n if (req.body.amount !== undefined) intent.amount = req.body.amount;\n if (req.body.currency !== undefined) intent.currency = req.body.currency;\n if (req.body.merchantId !== undefined) intent.merchantId = req.body.merchantId;\n if (req.body.merchantName !== undefined) intent.merchantName = req.body.merchantName;\n if (req.body.description !== undefined) intent.description = req.body.description;\n if (req.body.mandates !== undefined) intent.mandates = req.body.mandates;\n intent.status = 'updated';\n intent.updatedAt = new Date().toISOString();\n\n res.json({ data: { intentId: intent.id } });\n });\n\n // DELETE /intents/:id — Step 4: Cancel purchase intent\n router.delete('/intents/:id', (req: Request, res: Response) => {\n const intent = intents.get(req.params.id as string);\n if (!intent) {\n res.status(404).json({ error: { code: 'not_found', message: 'Purchase intent not found' } });\n return;\n }\n\n if (intent.status === 'confirmed') {\n res.status(400).json({\n error: { code: 'invalid_state', message: 'Cannot cancel a confirmed intent' },\n });\n return;\n }\n\n intent.status = 'cancelled';\n intent.updatedAt = new Date().toISOString();\n res.json({ cancelled: true, intentId: intent.id });\n });\n\n // POST /intents/:id/credentials — Step 5: Retrieve payment credentials\n router.post('/intents/:id/credentials', (req: Request, res: Response) => {\n const intent = intents.get(req.params.id as string);\n if (!intent) {\n res.status(404).json({ error: { code: 'not_found', message: 'Purchase intent not found' } });\n return;\n }\n\n if (intent.status === 'cancelled') {\n res.status(400).json({\n error: { code: 'invalid_state', message: 'Cannot retrieve credentials for a cancelled intent' },\n });\n return;\n }\n\n const token = tokens.get(intent.tokenId);\n const card = token ? cards.get(token.cardId) ?? Array.from(cards.values()).find((c) => c.walletId === token.walletId) : null;\n\n const cryptogram = generateCryptogram();\n intent.status = 'credentials_retrieved';\n intent.updatedAt = new Date().toISOString();\n\n console.log(`[VIC Demo] Credentials retrieved for intent: ${intent.id}`);\n\n res.json({\n data: {\n tokenNumber: intent.networkTokenId,\n cryptogram,\n eci: '05',\n expMonth: card?.expMonth ?? 12,\n expYear: card?.expYear ?? 2030,\n },\n });\n });\n\n // POST /intents/:id/confirm — Step 6: Confirm transaction\n router.post('/intents/:id/confirm', (req: Request, res: Response) => {\n const intent = intents.get(req.params.id as string);\n if (!intent) {\n res.status(404).json({ error: { code: 'not_found', message: 'Purchase intent not found' } });\n return;\n }\n\n intent.status = 'confirmed';\n intent.updatedAt = new Date().toISOString();\n\n console.log(`[VIC Demo] Transaction confirmed: ${intent.id}`);\n res.json({ data: { confirmed: true } });\n });\n\n // GET /tokens — List network tokens\n router.get('/tokens', (_req: Request, res: Response) => {\n const results = Array.from(tokens.values());\n let filtered = results;\n if (_req.query.walletId) {\n filtered = filtered.filter((t) => t.walletId === _req.query.walletId);\n }\n res.json({ data: filtered.map(toVICTokenResponse) });\n });\n\n // GET /tokens/:id — Get network token\n router.get('/tokens/:id', (req: Request, res: Response) => {\n const token = tokens.get(req.params.id as string);\n if (!token) {\n res.status(404).json({ error: { code: 'not_found', message: 'Token not found' } });\n return;\n }\n res.json({ data: toVICTokenResponse(token) });\n });\n\n return router;\n}\n","// ---------------------------------------------------------------------------\n// VIC Demo Server — Helpers & Types\n// ---------------------------------------------------------------------------\n\nimport crypto from 'node:crypto';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface DemoWallet {\n id: string;\n balance: number; // cents\n currency: string;\n createdAt: string;\n}\n\nexport interface DemoCard {\n id: string;\n walletId: string;\n last4: string;\n brand: 'visa';\n expMonth: number;\n expYear: number;\n status: 'active' | 'inactive';\n}\n\nexport interface VICTokenRecord {\n id: string;\n walletId: string;\n cardId: string;\n networkTokenId: string;\n last4: string;\n brand: 'visa';\n status: 'active' | 'suspended' | 'expired' | 'revoked';\n maxTransactionAmount?: number;\n allowedMCCs?: string[];\n expiresAt: string;\n createdAt: string;\n}\n\nexport interface PurchaseIntent {\n id: string;\n tokenId: string;\n networkTokenId: string;\n amount: number;\n currency: string;\n merchantId: string | null;\n merchantName: string | null;\n description: string | null;\n mandates: IntentMandate[];\n status: 'created' | 'updated' | 'cancelled' | 'credentials_retrieved' | 'confirmed';\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface IntentMandate {\n mandateId: string;\n declineThreshold: { amount: string; currencyCode: string };\n effectiveUntilTime: string;\n description: string;\n}\n\nexport interface DemoInstruction {\n id: string;\n walletId?: string;\n type: string;\n amount?: number;\n currency: string;\n merchant?: string;\n permissions: string[];\n constraints: Record<string, unknown>;\n status: 'active' | 'pending_confirmation' | 'confirmed' | 'cancelled' | 'expired';\n spentCents: number;\n remainingCents: number | null;\n expiresAt?: string;\n createdAt: string;\n}\n\nexport interface DemoMandate {\n id: string;\n instructionId: string;\n type: string;\n config: Record<string, unknown>;\n status: string;\n spentCents: number;\n remainingCents: number;\n createdAt: string;\n}\n\nexport interface DemoConfirmation {\n id: string;\n instructionId: string;\n confirmedBy?: string;\n confirmationType: string;\n details: Record<string, unknown>;\n createdAt: string;\n}\n\nexport interface DemoCredential {\n id: string;\n instructionId: string;\n credentialType: string;\n credentialData: Record<string, unknown>;\n expiresAt?: string;\n createdAt: string;\n}\n\n/** Enrolled card in the raw Visa ACP flow (separate from Lane DemoCard). */\nexport interface EnrolledCard {\n instrumentIdentifierId: string;\n clientCorrelationId: string;\n tokenReferenceId: string;\n dpan: string;\n expMonth: number;\n expYear: number;\n status: 'PENDING' | 'ACTIVE' | 'SUSPENDED';\n enrolledAt: string;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/** Generate a Luhn-valid Visa DPAN (starts with 4, 16 digits). */\nexport function generateDPAN(): string {\n const prefix = '4';\n let pan = prefix;\n for (let i = 1; i < 15; i++) {\n pan += Math.floor(Math.random() * 10).toString();\n }\n // Luhn check digit\n let sum = 0;\n for (let i = 0; i < pan.length; i++) {\n let digit = parseInt(pan.charAt(pan.length - 1 - i), 10);\n if (i % 2 === 0) {\n digit *= 2;\n if (digit > 9) digit -= 9;\n }\n sum += digit;\n }\n pan += ((10 - (sum % 10)) % 10).toString();\n return pan;\n}\n\n/** Generate a random base64 cryptogram. */\nexport function generateCryptogram(): string {\n return crypto.randomBytes(20).toString('base64');\n}\n\n/** Parse an expiry duration string (e.g. '24h', '7d', '1h') to an ISO date. */\nexport function parseExpiry(expiresIn: string): string {\n const match = expiresIn.match(/^(\\d+)(h|d|m)$/);\n if (!match || !match[1] || !match[2]) {\n // Default to 24 hours\n return new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString();\n }\n const value = parseInt(match[1], 10);\n const unit = match[2];\n let ms: number;\n switch (unit) {\n case 'h':\n ms = value * 60 * 60 * 1000;\n break;\n case 'd':\n ms = value * 24 * 60 * 60 * 1000;\n break;\n case 'm':\n ms = value * 60 * 1000;\n break;\n default:\n ms = 24 * 60 * 60 * 1000;\n }\n return new Date(Date.now() + ms).toISOString();\n}\n\n/** Generate a unique ID with a prefix. */\nexport function generateId(prefix: string): string {\n return `${prefix}_${crypto.randomUUID().replace(/-/g, '').slice(0, 24)}`;\n}\n"],"mappings":"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","names":["crypto","crypto","crypto","crypto"]}
@@ -757,13 +757,38 @@ var FileTokenStore = class {
757
757
  function isNodeError(err) {
758
758
  return err instanceof Error && "code" in err;
759
759
  }
760
-
761
- // src/config.ts
762
760
  var DEFAULT_BASE_URL = "https://api.getonlane.com";
763
761
  var DEFAULT_API_URL = "https://api.getonlane.com";
764
762
  var DEFAULT_TIMEOUT = 3e4;
765
763
  var DEFAULT_MAX_RETRIES = 2;
764
+ async function readPersistentConfig() {
765
+ try {
766
+ const raw = await promises.readFile(path.join(os.homedir(), ".lane", "config.json"), "utf-8");
767
+ return JSON.parse(raw);
768
+ } catch {
769
+ return null;
770
+ }
771
+ }
766
772
  async function resolveConfig(options = {}, tokenStore) {
773
+ const persistent = await readPersistentConfig();
774
+ if (persistent?.demo && process.env["LANE_DEMO"] !== "false") {
775
+ process.env["LANE_DEMO"] = "true";
776
+ if (persistent.demoUrl && !process.env["LANE_DEMO_URL"]) {
777
+ process.env["LANE_DEMO_URL"] = persistent.demoUrl;
778
+ }
779
+ }
780
+ if (process.env["LANE_DEMO"] === "true") {
781
+ const demoBaseUrl = process.env["LANE_DEMO_URL"] ?? "http://localhost:3020";
782
+ return Object.freeze({
783
+ apiKey: options.apiKey ?? process.env["LANE_API_KEY"] ?? "lane_sk_demo_000000000000",
784
+ baseUrl: demoBaseUrl,
785
+ apiUrl: demoBaseUrl,
786
+ testMode: true,
787
+ timeout: options.timeout ?? DEFAULT_TIMEOUT,
788
+ maxRetries: options.maxRetries ?? DEFAULT_MAX_RETRIES,
789
+ circuitBreaker: void 0
790
+ });
791
+ }
767
792
  let apiKey = options.apiKey;
768
793
  if (!apiKey) {
769
794
  apiKey = process.env["LANE_API_KEY"];
@@ -2346,7 +2371,9 @@ var Lane = class _Lane {
2346
2371
  } catch {
2347
2372
  _Lane._throwWaitlistError();
2348
2373
  }
2349
- await _Lane._verifyAccess(config);
2374
+ if (process.env["LANE_DEMO"] !== "true") {
2375
+ await _Lane._verifyAccess(config);
2376
+ }
2350
2377
  return new _Lane(config);
2351
2378
  }
2352
2379
  /**
@@ -3139,6 +3166,7 @@ var BiometricVerifier = class {
3139
3166
  async tryWebAuthn(reason, instructionId) {
3140
3167
  const { createServer: createServer2 } = await import('http');
3141
3168
  const open = (await import('open')).default;
3169
+ const { hostname } = await import('os');
3142
3170
  return new Promise((resolve, reject) => {
3143
3171
  const server = createServer2((req, res) => {
3144
3172
  const url = new URL(req.url ?? "/", "http://localhost");
@@ -3150,7 +3178,11 @@ var BiometricVerifier = class {
3150
3178
  '<!DOCTYPE html><html><body style="font-family:sans-serif;display:flex;justify-content:center;align-items:center;height:100vh"><h1 style="color:#10b981">Verified</h1></body></html>'
3151
3179
  );
3152
3180
  cleanup();
3153
- resolve({ method: "webauthn_passkey", timestamp: (/* @__PURE__ */ new Date()).toISOString() });
3181
+ resolve({
3182
+ method: "webauthn_passkey",
3183
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
3184
+ machineId: `webauthn_${hostname()}`
3185
+ });
3154
3186
  return;
3155
3187
  }
3156
3188
  res.writeHead(200, { "Content-Type": "text/html" });