satonomous 0.2.1 → 0.2.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.
- package/dist/index.cjs +8 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +8 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -210,7 +210,14 @@ var L402Agent = class {
|
|
|
210
210
|
}
|
|
211
211
|
// Offers
|
|
212
212
|
async createOffer(params) {
|
|
213
|
-
|
|
213
|
+
const { sla_minutes, dispute_window_minutes, ...rest } = params;
|
|
214
|
+
return this.request("POST", "/api/v1/offers", {
|
|
215
|
+
...rest,
|
|
216
|
+
terms: {
|
|
217
|
+
sla_minutes: sla_minutes ?? 30,
|
|
218
|
+
dispute_window_minutes: dispute_window_minutes ?? 1440
|
|
219
|
+
}
|
|
220
|
+
});
|
|
214
221
|
}
|
|
215
222
|
async listOffers() {
|
|
216
223
|
const result = await this.request("GET", "/api/v1/offers");
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/client.ts"],"sourcesContent":["/**\n * satonomous — SDK for autonomous AI agents to earn and spend sats\n *\n * AI agents can't pay Lightning invoices — they don't have wallets.\n * This SDK bridges that gap: when an agent needs funds, it notifies\n * a human (via callback) and waits for payment.\n *\n * @example\n * ```ts\n * import { L402Agent } from 'satonomous';\n *\n * const agent = new L402Agent({\n * apiKey: 'sk_...',\n * // This is the key part: how the agent asks a human for money\n * onPaymentNeeded: async (invoice) => {\n * await sendSlackMessage(`⚡ Pay ${invoice.amount_sats} sats: ${invoice.invoice}`);\n * },\n * });\n *\n * // Agent ensures it has funds before working\n * await agent.ensureBalance(500, 'Need funds for code-review contract');\n * ```\n *\n * @module\n */\n\nexport { L402Agent, L402Error } from './client.js';\nexport type {\n L402AgentOptions,\n BalanceInfo,\n Offer,\n CreateOfferParams,\n Contract,\n FundResult,\n DepositInvoice,\n DepositStatus,\n LedgerEntry,\n WithdrawResult,\n AgentRegistration,\n PaymentNeededCallback,\n} from './types.js';\n","import type {\n L402AgentOptions,\n BalanceInfo,\n Offer,\n CreateOfferParams,\n Contract,\n FundResult,\n DepositInvoice,\n DepositStatus,\n LedgerEntry,\n WithdrawResult,\n AgentRegistration,\n PaymentNeededCallback,\n} from './types.js';\n\nexport class L402Error extends Error {\n status: number;\n code?: string;\n\n constructor(message: string, status: number, code?: string) {\n super(message);\n this.name = 'L402Error';\n this.status = status;\n this.code = code;\n }\n}\n\nexport class L402Agent {\n private apiKey: string;\n private apiUrl: string;\n\n private onPaymentNeeded?: PaymentNeededCallback;\n private paymentTimeoutMs: number;\n private paymentPollIntervalMs: number;\n\n constructor(options: L402AgentOptions) {\n if (!options.apiKey) {\n throw new Error('apiKey is required');\n }\n this.apiKey = options.apiKey;\n this.apiUrl = options.apiUrl ?? 'https://l402gw.nosaltres2.info';\n this.onPaymentNeeded = options.onPaymentNeeded;\n this.paymentTimeoutMs = options.paymentTimeoutMs ?? 300_000;\n this.paymentPollIntervalMs = options.paymentPollIntervalMs ?? 5_000;\n }\n\n private async request<T>(method: string, path: string, body?: any): Promise<T> {\n const url = `${this.apiUrl}${path}`;\n const options: RequestInit = {\n method,\n headers: {\n 'X-L402-Key': this.apiKey,\n 'Content-Type': 'application/json',\n },\n };\n\n if (body) {\n options.body = JSON.stringify(body);\n }\n\n const res = await fetch(url, options);\n\n if (!res.ok) {\n let errorMsg = `HTTP ${res.status}`;\n let errorCode: string | undefined;\n\n try {\n const data = await res.json() as { error?: string; code?: string };\n errorMsg = data.error || errorMsg;\n errorCode = data.code;\n } catch {\n // Use default error message\n }\n\n throw new L402Error(errorMsg, res.status, errorCode);\n }\n\n return res.json() as Promise<T>;\n }\n\n // Static: register a new agent (no auth needed)\n static async register(options: {\n name: string;\n description?: string;\n wallet_type?: 'custodial' | 'external';\n lightning_address?: string;\n apiUrl?: string;\n }): Promise<AgentRegistration> {\n const apiUrl = options.apiUrl ?? 'https://l402gw.nosaltres2.info';\n const url = `${apiUrl}/api/v1/agents/register`;\n\n const res = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n name: options.name,\n description: options.description,\n wallet_type: options.wallet_type ?? 'custodial',\n lightning_address: options.lightning_address,\n }),\n });\n\n if (!res.ok) {\n let errorMsg = `HTTP ${res.status}`;\n try {\n const data = await res.json() as { error?: string };\n errorMsg = data.error || errorMsg;\n } catch {\n // Use default error message\n }\n throw new L402Error(errorMsg, res.status);\n }\n\n return res.json() as Promise<AgentRegistration>;\n }\n\n // Wallet\n async getBalance(): Promise<BalanceInfo> {\n return this.request('GET', '/api/v1/wallet/balance');\n }\n\n /**\n * Low-level: create a deposit invoice. Returns the invoice for manual handling.\n * Most agents should use `deposit()` instead, which notifies the human and waits.\n */\n async createDeposit(amount_sats: number): Promise<DepositInvoice> {\n const result = await this.request<DepositInvoice>('POST', '/api/v1/wallet/deposit', { amount_sats });\n // Add pay_url for easy wallet linking\n return {\n ...result,\n pay_url: `lightning:${result.invoice}`,\n };\n }\n\n /**\n * Check if a deposit invoice has been paid.\n */\n async checkDeposit(paymentHash: string): Promise<DepositStatus> {\n return this.request('GET', `/api/v1/wallet/deposit/${paymentHash}`);\n }\n\n /**\n * High-level deposit: creates invoice, notifies human, waits for payment.\n *\n * WHY THIS EXISTS: AI agents don't have Lightning wallets. They can't pay\n * invoices. When an agent needs sats, it must ask a human to pay.\n *\n * This method:\n * 1. Creates a Lightning invoice for the requested amount\n * 2. Calls `onPaymentNeeded` so you can notify the human (chat, email, UI)\n * 3. Polls until the invoice is paid or times out\n * 4. Returns the confirmed deposit status\n *\n * If `onPaymentNeeded` is not configured, throws with the invoice so the\n * caller can handle notification manually.\n *\n * @param amount_sats - Amount to deposit\n * @param reason - Human-readable reason (shown in the notification)\n * @returns Confirmed deposit status\n * @throws {L402Error} if payment times out or fails\n *\n * @example\n * const agent = new L402Agent({\n * apiKey: 'sk_...',\n * onPaymentNeeded: async (invoice) => {\n * // Send to Slack, Discord, Signal, email, etc.\n * await notify(`Pay ${invoice.amount_sats} sats: ${invoice.invoice}`);\n * },\n * });\n *\n * // Agent requests funding and waits\n * const deposit = await agent.deposit(1000, 'Need funds to accept code-review offer');\n * console.log(`Funded! Balance: ${deposit.amount_sats} sats`);\n */\n async deposit(amount_sats: number, reason?: string): Promise<DepositStatus> {\n const invoice = await this.createDeposit(amount_sats);\n\n // If no callback, throw with invoice details so caller can handle it\n if (!this.onPaymentNeeded) {\n throw new L402Error(\n `Payment needed: ${amount_sats} sats. ` +\n `Invoice: ${invoice.invoice}. ` +\n `No onPaymentNeeded callback configured — pay this invoice manually ` +\n `and call checkDeposit('${invoice.payment_hash}') to confirm.`,\n 402,\n 'PAYMENT_NEEDED'\n );\n }\n\n // Notify the human with clear payment instructions\n const enrichedInvoice: DepositInvoice = {\n ...invoice,\n message: [\n reason\n ? `⚡ Agent needs ${amount_sats} sats: ${reason}`\n : `⚡ Agent needs ${amount_sats} sats deposited`,\n '',\n `📱 Tap to pay: ${invoice.pay_url}`,\n '',\n `Or paste this invoice into any Lightning wallet:`,\n invoice.invoice,\n ].join('\\n'),\n };\n await this.onPaymentNeeded(enrichedInvoice);\n\n // Poll for payment\n if (this.paymentTimeoutMs === 0) {\n return { status: 'pending', amount_sats, paid_at: null };\n }\n\n const deadline = Date.now() + this.paymentTimeoutMs;\n while (Date.now() < deadline) {\n await new Promise(r => setTimeout(r, this.paymentPollIntervalMs));\n const status = await this.checkDeposit(invoice.payment_hash);\n if (status.status === 'paid') return status;\n if (status.status === 'expired') {\n throw new L402Error('Deposit invoice expired before payment', 408, 'PAYMENT_EXPIRED');\n }\n }\n\n throw new L402Error(\n `Payment not received within ${this.paymentTimeoutMs / 1000}s. ` +\n `Invoice may still be valid — check with checkDeposit('${invoice.payment_hash}')`,\n 408,\n 'PAYMENT_TIMEOUT'\n );\n }\n\n /**\n * Ensure the agent has at least `minBalance` sats. If not, request a deposit.\n * Convenience method that checks balance first, then deposits the difference.\n *\n * @example\n * // Before accepting an offer, make sure you can pay\n * await agent.ensureBalance(500, 'Need funds for code-review contract');\n * await agent.fundContract(contractId);\n */\n async ensureBalance(minBalance: number, reason?: string): Promise<BalanceInfo> {\n const current = await this.getBalance();\n if (current.balance_sats >= minBalance) return current;\n\n const needed = minBalance - current.balance_sats;\n await this.deposit(needed, reason ?? `Need ${needed} more sats (have ${current.balance_sats}, need ${minBalance})`);\n return this.getBalance();\n }\n\n async withdraw(amount_sats?: number): Promise<WithdrawResult> {\n return this.request('POST', '/api/v1/wallet/withdraw', amount_sats ? { amount_sats } : {});\n }\n\n // Offers\n async createOffer(params: CreateOfferParams): Promise<Offer> {\n return this.request('POST', '/api/v1/offers', params);\n }\n\n async listOffers(): Promise<Offer[]> {\n const result = await this.request<{ offers: Offer[] }>('GET', '/api/v1/offers');\n return result.offers || [];\n }\n\n async getOffer(offerId: string): Promise<Offer> {\n return this.request('GET', `/api/v1/offers/${offerId}`);\n }\n\n async updateOffer(offerId: string, active: boolean): Promise<Offer> {\n return this.request('PATCH', `/api/v1/offers/${offerId}`, { active });\n }\n\n // Contracts\n async acceptOffer(offerId: string): Promise<Contract> {\n return this.request('POST', '/api/v1/contracts', { offer_id: offerId });\n }\n\n async fundContract(contractId: string): Promise<FundResult> {\n return this.request('POST', `/api/v1/contracts/${contractId}/fund`, {});\n }\n\n async listContracts(filters?: { role?: 'buyer' | 'seller'; status?: string }): Promise<Contract[]> {\n let path = '/api/v1/contracts';\n const params = new URLSearchParams();\n if (filters?.role) params.append('role', filters.role);\n if (filters?.status) params.append('status', filters.status);\n if (params.toString()) path += '?' + params.toString();\n const result = await this.request<{ contracts: Contract[] }>('GET', path);\n return result.contracts || [];\n }\n\n async getContract(contractId: string): Promise<Contract> {\n return this.request('GET', `/api/v1/contracts/${contractId}`);\n }\n\n // Delivery\n async submitDelivery(contractId: string, proofUrl: string, proofData?: any): Promise<Contract> {\n return this.request('POST', `/api/v1/contracts/${contractId}/deliver`, {\n proof_url: proofUrl,\n proof_data: proofData,\n });\n }\n\n async confirmDelivery(contractId: string): Promise<Contract> {\n return this.request('POST', `/api/v1/contracts/${contractId}/confirm`, {});\n }\n\n async disputeDelivery(contractId: string, reason: string, evidenceUrl?: string): Promise<Contract> {\n return this.request('POST', `/api/v1/contracts/${contractId}/dispute`, {\n reason,\n evidence_url: evidenceUrl,\n });\n }\n\n // Ledger\n async getLedger(limit?: number, offset?: number): Promise<{ balance_sats: number; entries: LedgerEntry[] }> {\n let path = '/api/v1/ledger';\n const params = new URLSearchParams();\n if (limit) params.append('limit', String(limit));\n if (offset) params.append('offset', String(offset));\n if (params.toString()) path += '?' + params.toString();\n return this.request('GET', path);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACeO,IAAM,YAAN,cAAwB,MAAM;AAAA,EAInC,YAAY,SAAiB,QAAgB,MAAe;AAC1D,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,YAAN,MAAgB;AAAA,EAQrB,YAAY,SAA2B;AACrC,QAAI,CAAC,QAAQ,QAAQ;AACnB,YAAM,IAAI,MAAM,oBAAoB;AAAA,IACtC;AACA,SAAK,SAAS,QAAQ;AACtB,SAAK,SAAS,QAAQ,UAAU;AAChC,SAAK,kBAAkB,QAAQ;AAC/B,SAAK,mBAAmB,QAAQ,oBAAoB;AACpD,SAAK,wBAAwB,QAAQ,yBAAyB;AAAA,EAChE;AAAA,EAEA,MAAc,QAAW,QAAgB,MAAc,MAAwB;AAC7E,UAAM,MAAM,GAAG,KAAK,MAAM,GAAG,IAAI;AACjC,UAAM,UAAuB;AAAA,MAC3B;AAAA,MACA,SAAS;AAAA,QACP,cAAc,KAAK;AAAA,QACnB,gBAAgB;AAAA,MAClB;AAAA,IACF;AAEA,QAAI,MAAM;AACR,cAAQ,OAAO,KAAK,UAAU,IAAI;AAAA,IACpC;AAEA,UAAM,MAAM,MAAM,MAAM,KAAK,OAAO;AAEpC,QAAI,CAAC,IAAI,IAAI;AACX,UAAI,WAAW,QAAQ,IAAI,MAAM;AACjC,UAAI;AAEJ,UAAI;AACF,cAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,mBAAW,KAAK,SAAS;AACzB,oBAAY,KAAK;AAAA,MACnB,QAAQ;AAAA,MAER;AAEA,YAAM,IAAI,UAAU,UAAU,IAAI,QAAQ,SAAS;AAAA,IACrD;AAEA,WAAO,IAAI,KAAK;AAAA,EAClB;AAAA;AAAA,EAGA,aAAa,SAAS,SAMS;AAC7B,UAAM,SAAS,QAAQ,UAAU;AACjC,UAAM,MAAM,GAAG,MAAM;AAErB,UAAM,MAAM,MAAM,MAAM,KAAK;AAAA,MAC3B,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,MAAM,KAAK,UAAU;AAAA,QACnB,MAAM,QAAQ;AAAA,QACd,aAAa,QAAQ;AAAA,QACrB,aAAa,QAAQ,eAAe;AAAA,QACpC,mBAAmB,QAAQ;AAAA,MAC7B,CAAC;AAAA,IACH,CAAC;AAED,QAAI,CAAC,IAAI,IAAI;AACX,UAAI,WAAW,QAAQ,IAAI,MAAM;AACjC,UAAI;AACF,cAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,mBAAW,KAAK,SAAS;AAAA,MAC3B,QAAQ;AAAA,MAER;AACA,YAAM,IAAI,UAAU,UAAU,IAAI,MAAM;AAAA,IAC1C;AAEA,WAAO,IAAI,KAAK;AAAA,EAClB;AAAA;AAAA,EAGA,MAAM,aAAmC;AACvC,WAAO,KAAK,QAAQ,OAAO,wBAAwB;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,cAAc,aAA8C;AAChE,UAAM,SAAS,MAAM,KAAK,QAAwB,QAAQ,0BAA0B,EAAE,YAAY,CAAC;AAEnG,WAAO;AAAA,MACL,GAAG;AAAA,MACH,SAAS,aAAa,OAAO,OAAO;AAAA,IACtC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAAa,aAA6C;AAC9D,WAAO,KAAK,QAAQ,OAAO,0BAA0B,WAAW,EAAE;AAAA,EACpE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmCA,MAAM,QAAQ,aAAqB,QAAyC;AAC1E,UAAM,UAAU,MAAM,KAAK,cAAc,WAAW;AAGpD,QAAI,CAAC,KAAK,iBAAiB;AACzB,YAAM,IAAI;AAAA,QACR,mBAAmB,WAAW,mBAClB,QAAQ,OAAO,oGAED,QAAQ,YAAY;AAAA,QAC9C;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAGA,UAAM,kBAAkC;AAAA,MACtC,GAAG;AAAA,MACH,SAAS;AAAA,QACP,SACI,sBAAiB,WAAW,UAAU,MAAM,KAC5C,sBAAiB,WAAW;AAAA,QAChC;AAAA,QACA,yBAAkB,QAAQ,OAAO;AAAA,QACjC;AAAA,QACA;AAAA,QACA,QAAQ;AAAA,MACV,EAAE,KAAK,IAAI;AAAA,IACb;AACA,UAAM,KAAK,gBAAgB,eAAe;AAG1C,QAAI,KAAK,qBAAqB,GAAG;AAC/B,aAAO,EAAE,QAAQ,WAAW,aAAa,SAAS,KAAK;AAAA,IACzD;AAEA,UAAM,WAAW,KAAK,IAAI,IAAI,KAAK;AACnC,WAAO,KAAK,IAAI,IAAI,UAAU;AAC5B,YAAM,IAAI,QAAQ,OAAK,WAAW,GAAG,KAAK,qBAAqB,CAAC;AAChE,YAAM,SAAS,MAAM,KAAK,aAAa,QAAQ,YAAY;AAC3D,UAAI,OAAO,WAAW,OAAQ,QAAO;AACrC,UAAI,OAAO,WAAW,WAAW;AAC/B,cAAM,IAAI,UAAU,0CAA0C,KAAK,iBAAiB;AAAA,MACtF;AAAA,IACF;AAEA,UAAM,IAAI;AAAA,MACR,+BAA+B,KAAK,mBAAmB,GAAI,iEACF,QAAQ,YAAY;AAAA,MAC7E;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,cAAc,YAAoB,QAAuC;AAC7E,UAAM,UAAU,MAAM,KAAK,WAAW;AACtC,QAAI,QAAQ,gBAAgB,WAAY,QAAO;AAE/C,UAAM,SAAS,aAAa,QAAQ;AACpC,UAAM,KAAK,QAAQ,QAAQ,UAAU,QAAQ,MAAM,oBAAoB,QAAQ,YAAY,UAAU,UAAU,GAAG;AAClH,WAAO,KAAK,WAAW;AAAA,EACzB;AAAA,EAEA,MAAM,SAAS,aAA+C;AAC5D,WAAO,KAAK,QAAQ,QAAQ,2BAA2B,cAAc,EAAE,YAAY,IAAI,CAAC,CAAC;AAAA,EAC3F;AAAA;AAAA,EAGA,MAAM,YAAY,QAA2C;AAC3D,WAAO,KAAK,QAAQ,QAAQ,kBAAkB,MAAM;AAAA,EACtD;AAAA,EAEA,MAAM,aAA+B;AACnC,UAAM,SAAS,MAAM,KAAK,QAA6B,OAAO,gBAAgB;AAC9E,WAAO,OAAO,UAAU,CAAC;AAAA,EAC3B;AAAA,EAEA,MAAM,SAAS,SAAiC;AAC9C,WAAO,KAAK,QAAQ,OAAO,kBAAkB,OAAO,EAAE;AAAA,EACxD;AAAA,EAEA,MAAM,YAAY,SAAiB,QAAiC;AAClE,WAAO,KAAK,QAAQ,SAAS,kBAAkB,OAAO,IAAI,EAAE,OAAO,CAAC;AAAA,EACtE;AAAA;AAAA,EAGA,MAAM,YAAY,SAAoC;AACpD,WAAO,KAAK,QAAQ,QAAQ,qBAAqB,EAAE,UAAU,QAAQ,CAAC;AAAA,EACxE;AAAA,EAEA,MAAM,aAAa,YAAyC;AAC1D,WAAO,KAAK,QAAQ,QAAQ,qBAAqB,UAAU,SAAS,CAAC,CAAC;AAAA,EACxE;AAAA,EAEA,MAAM,cAAc,SAA+E;AACjG,QAAI,OAAO;AACX,UAAM,SAAS,IAAI,gBAAgB;AACnC,QAAI,SAAS,KAAM,QAAO,OAAO,QAAQ,QAAQ,IAAI;AACrD,QAAI,SAAS,OAAQ,QAAO,OAAO,UAAU,QAAQ,MAAM;AAC3D,QAAI,OAAO,SAAS,EAAG,SAAQ,MAAM,OAAO,SAAS;AACrD,UAAM,SAAS,MAAM,KAAK,QAAmC,OAAO,IAAI;AACxE,WAAO,OAAO,aAAa,CAAC;AAAA,EAC9B;AAAA,EAEA,MAAM,YAAY,YAAuC;AACvD,WAAO,KAAK,QAAQ,OAAO,qBAAqB,UAAU,EAAE;AAAA,EAC9D;AAAA;AAAA,EAGA,MAAM,eAAe,YAAoB,UAAkB,WAAoC;AAC7F,WAAO,KAAK,QAAQ,QAAQ,qBAAqB,UAAU,YAAY;AAAA,MACrE,WAAW;AAAA,MACX,YAAY;AAAA,IACd,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,gBAAgB,YAAuC;AAC3D,WAAO,KAAK,QAAQ,QAAQ,qBAAqB,UAAU,YAAY,CAAC,CAAC;AAAA,EAC3E;AAAA,EAEA,MAAM,gBAAgB,YAAoB,QAAgB,aAAyC;AACjG,WAAO,KAAK,QAAQ,QAAQ,qBAAqB,UAAU,YAAY;AAAA,MACrE;AAAA,MACA,cAAc;AAAA,IAChB,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,MAAM,UAAU,OAAgB,QAA4E;AAC1G,QAAI,OAAO;AACX,UAAM,SAAS,IAAI,gBAAgB;AACnC,QAAI,MAAO,QAAO,OAAO,SAAS,OAAO,KAAK,CAAC;AAC/C,QAAI,OAAQ,QAAO,OAAO,UAAU,OAAO,MAAM,CAAC;AAClD,QAAI,OAAO,SAAS,EAAG,SAAQ,MAAM,OAAO,SAAS;AACrD,WAAO,KAAK,QAAQ,OAAO,IAAI;AAAA,EACjC;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/client.ts"],"sourcesContent":["/**\n * satonomous — SDK for autonomous AI agents to earn and spend sats\n *\n * AI agents can't pay Lightning invoices — they don't have wallets.\n * This SDK bridges that gap: when an agent needs funds, it notifies\n * a human (via callback) and waits for payment.\n *\n * @example\n * ```ts\n * import { L402Agent } from 'satonomous';\n *\n * const agent = new L402Agent({\n * apiKey: 'sk_...',\n * // This is the key part: how the agent asks a human for money\n * onPaymentNeeded: async (invoice) => {\n * await sendSlackMessage(`⚡ Pay ${invoice.amount_sats} sats: ${invoice.invoice}`);\n * },\n * });\n *\n * // Agent ensures it has funds before working\n * await agent.ensureBalance(500, 'Need funds for code-review contract');\n * ```\n *\n * @module\n */\n\nexport { L402Agent, L402Error } from './client.js';\nexport type {\n L402AgentOptions,\n BalanceInfo,\n Offer,\n CreateOfferParams,\n Contract,\n FundResult,\n DepositInvoice,\n DepositStatus,\n LedgerEntry,\n WithdrawResult,\n AgentRegistration,\n PaymentNeededCallback,\n} from './types.js';\n","import type {\n L402AgentOptions,\n BalanceInfo,\n Offer,\n CreateOfferParams,\n Contract,\n FundResult,\n DepositInvoice,\n DepositStatus,\n LedgerEntry,\n WithdrawResult,\n AgentRegistration,\n PaymentNeededCallback,\n} from './types.js';\n\nexport class L402Error extends Error {\n status: number;\n code?: string;\n\n constructor(message: string, status: number, code?: string) {\n super(message);\n this.name = 'L402Error';\n this.status = status;\n this.code = code;\n }\n}\n\nexport class L402Agent {\n private apiKey: string;\n private apiUrl: string;\n\n private onPaymentNeeded?: PaymentNeededCallback;\n private paymentTimeoutMs: number;\n private paymentPollIntervalMs: number;\n\n constructor(options: L402AgentOptions) {\n if (!options.apiKey) {\n throw new Error('apiKey is required');\n }\n this.apiKey = options.apiKey;\n this.apiUrl = options.apiUrl ?? 'https://l402gw.nosaltres2.info';\n this.onPaymentNeeded = options.onPaymentNeeded;\n this.paymentTimeoutMs = options.paymentTimeoutMs ?? 300_000;\n this.paymentPollIntervalMs = options.paymentPollIntervalMs ?? 5_000;\n }\n\n private async request<T>(method: string, path: string, body?: any): Promise<T> {\n const url = `${this.apiUrl}${path}`;\n const options: RequestInit = {\n method,\n headers: {\n 'X-L402-Key': this.apiKey,\n 'Content-Type': 'application/json',\n },\n };\n\n if (body) {\n options.body = JSON.stringify(body);\n }\n\n const res = await fetch(url, options);\n\n if (!res.ok) {\n let errorMsg = `HTTP ${res.status}`;\n let errorCode: string | undefined;\n\n try {\n const data = await res.json() as { error?: string; code?: string };\n errorMsg = data.error || errorMsg;\n errorCode = data.code;\n } catch {\n // Use default error message\n }\n\n throw new L402Error(errorMsg, res.status, errorCode);\n }\n\n return res.json() as Promise<T>;\n }\n\n // Static: register a new agent (no auth needed)\n static async register(options: {\n name: string;\n description?: string;\n wallet_type?: 'custodial' | 'external';\n lightning_address?: string;\n apiUrl?: string;\n }): Promise<AgentRegistration> {\n const apiUrl = options.apiUrl ?? 'https://l402gw.nosaltres2.info';\n const url = `${apiUrl}/api/v1/agents/register`;\n\n const res = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n name: options.name,\n description: options.description,\n wallet_type: options.wallet_type ?? 'custodial',\n lightning_address: options.lightning_address,\n }),\n });\n\n if (!res.ok) {\n let errorMsg = `HTTP ${res.status}`;\n try {\n const data = await res.json() as { error?: string };\n errorMsg = data.error || errorMsg;\n } catch {\n // Use default error message\n }\n throw new L402Error(errorMsg, res.status);\n }\n\n return res.json() as Promise<AgentRegistration>;\n }\n\n // Wallet\n async getBalance(): Promise<BalanceInfo> {\n return this.request('GET', '/api/v1/wallet/balance');\n }\n\n /**\n * Low-level: create a deposit invoice. Returns the invoice for manual handling.\n * Most agents should use `deposit()` instead, which notifies the human and waits.\n */\n async createDeposit(amount_sats: number): Promise<DepositInvoice> {\n const result = await this.request<DepositInvoice>('POST', '/api/v1/wallet/deposit', { amount_sats });\n // Add pay_url for easy wallet linking\n return {\n ...result,\n pay_url: `lightning:${result.invoice}`,\n };\n }\n\n /**\n * Check if a deposit invoice has been paid.\n */\n async checkDeposit(paymentHash: string): Promise<DepositStatus> {\n return this.request('GET', `/api/v1/wallet/deposit/${paymentHash}`);\n }\n\n /**\n * High-level deposit: creates invoice, notifies human, waits for payment.\n *\n * WHY THIS EXISTS: AI agents don't have Lightning wallets. They can't pay\n * invoices. When an agent needs sats, it must ask a human to pay.\n *\n * This method:\n * 1. Creates a Lightning invoice for the requested amount\n * 2. Calls `onPaymentNeeded` so you can notify the human (chat, email, UI)\n * 3. Polls until the invoice is paid or times out\n * 4. Returns the confirmed deposit status\n *\n * If `onPaymentNeeded` is not configured, throws with the invoice so the\n * caller can handle notification manually.\n *\n * @param amount_sats - Amount to deposit\n * @param reason - Human-readable reason (shown in the notification)\n * @returns Confirmed deposit status\n * @throws {L402Error} if payment times out or fails\n *\n * @example\n * const agent = new L402Agent({\n * apiKey: 'sk_...',\n * onPaymentNeeded: async (invoice) => {\n * // Send to Slack, Discord, Signal, email, etc.\n * await notify(`Pay ${invoice.amount_sats} sats: ${invoice.invoice}`);\n * },\n * });\n *\n * // Agent requests funding and waits\n * const deposit = await agent.deposit(1000, 'Need funds to accept code-review offer');\n * console.log(`Funded! Balance: ${deposit.amount_sats} sats`);\n */\n async deposit(amount_sats: number, reason?: string): Promise<DepositStatus> {\n const invoice = await this.createDeposit(amount_sats);\n\n // If no callback, throw with invoice details so caller can handle it\n if (!this.onPaymentNeeded) {\n throw new L402Error(\n `Payment needed: ${amount_sats} sats. ` +\n `Invoice: ${invoice.invoice}. ` +\n `No onPaymentNeeded callback configured — pay this invoice manually ` +\n `and call checkDeposit('${invoice.payment_hash}') to confirm.`,\n 402,\n 'PAYMENT_NEEDED'\n );\n }\n\n // Notify the human with clear payment instructions\n const enrichedInvoice: DepositInvoice = {\n ...invoice,\n message: [\n reason\n ? `⚡ Agent needs ${amount_sats} sats: ${reason}`\n : `⚡ Agent needs ${amount_sats} sats deposited`,\n '',\n `📱 Tap to pay: ${invoice.pay_url}`,\n '',\n `Or paste this invoice into any Lightning wallet:`,\n invoice.invoice,\n ].join('\\n'),\n };\n await this.onPaymentNeeded(enrichedInvoice);\n\n // Poll for payment\n if (this.paymentTimeoutMs === 0) {\n return { status: 'pending', amount_sats, paid_at: null };\n }\n\n const deadline = Date.now() + this.paymentTimeoutMs;\n while (Date.now() < deadline) {\n await new Promise(r => setTimeout(r, this.paymentPollIntervalMs));\n const status = await this.checkDeposit(invoice.payment_hash);\n if (status.status === 'paid') return status;\n if (status.status === 'expired') {\n throw new L402Error('Deposit invoice expired before payment', 408, 'PAYMENT_EXPIRED');\n }\n }\n\n throw new L402Error(\n `Payment not received within ${this.paymentTimeoutMs / 1000}s. ` +\n `Invoice may still be valid — check with checkDeposit('${invoice.payment_hash}')`,\n 408,\n 'PAYMENT_TIMEOUT'\n );\n }\n\n /**\n * Ensure the agent has at least `minBalance` sats. If not, request a deposit.\n * Convenience method that checks balance first, then deposits the difference.\n *\n * @example\n * // Before accepting an offer, make sure you can pay\n * await agent.ensureBalance(500, 'Need funds for code-review contract');\n * await agent.fundContract(contractId);\n */\n async ensureBalance(minBalance: number, reason?: string): Promise<BalanceInfo> {\n const current = await this.getBalance();\n if (current.balance_sats >= minBalance) return current;\n\n const needed = minBalance - current.balance_sats;\n await this.deposit(needed, reason ?? `Need ${needed} more sats (have ${current.balance_sats}, need ${minBalance})`);\n return this.getBalance();\n }\n\n async withdraw(amount_sats?: number): Promise<WithdrawResult> {\n return this.request('POST', '/api/v1/wallet/withdraw', amount_sats ? { amount_sats } : {});\n }\n\n // Offers\n async createOffer(params: CreateOfferParams): Promise<Offer> {\n const { sla_minutes, dispute_window_minutes, ...rest } = params;\n return this.request('POST', '/api/v1/offers', {\n ...rest,\n terms: {\n sla_minutes: sla_minutes ?? 30,\n dispute_window_minutes: dispute_window_minutes ?? 1440,\n },\n });\n }\n\n async listOffers(): Promise<Offer[]> {\n const result = await this.request<{ offers: Offer[] }>('GET', '/api/v1/offers');\n return result.offers || [];\n }\n\n async getOffer(offerId: string): Promise<Offer> {\n return this.request('GET', `/api/v1/offers/${offerId}`);\n }\n\n async updateOffer(offerId: string, active: boolean): Promise<Offer> {\n return this.request('PATCH', `/api/v1/offers/${offerId}`, { active });\n }\n\n // Contracts\n async acceptOffer(offerId: string): Promise<Contract> {\n return this.request('POST', '/api/v1/contracts', { offer_id: offerId });\n }\n\n async fundContract(contractId: string): Promise<FundResult> {\n return this.request('POST', `/api/v1/contracts/${contractId}/fund`, {});\n }\n\n async listContracts(filters?: { role?: 'buyer' | 'seller'; status?: string }): Promise<Contract[]> {\n let path = '/api/v1/contracts';\n const params = new URLSearchParams();\n if (filters?.role) params.append('role', filters.role);\n if (filters?.status) params.append('status', filters.status);\n if (params.toString()) path += '?' + params.toString();\n const result = await this.request<{ contracts: Contract[] }>('GET', path);\n return result.contracts || [];\n }\n\n async getContract(contractId: string): Promise<Contract> {\n return this.request('GET', `/api/v1/contracts/${contractId}`);\n }\n\n // Delivery\n async submitDelivery(contractId: string, proofUrl: string, proofData?: any): Promise<Contract> {\n return this.request('POST', `/api/v1/contracts/${contractId}/deliver`, {\n proof_url: proofUrl,\n proof_data: proofData,\n });\n }\n\n async confirmDelivery(contractId: string): Promise<Contract> {\n return this.request('POST', `/api/v1/contracts/${contractId}/confirm`, {});\n }\n\n async disputeDelivery(contractId: string, reason: string, evidenceUrl?: string): Promise<Contract> {\n return this.request('POST', `/api/v1/contracts/${contractId}/dispute`, {\n reason,\n evidence_url: evidenceUrl,\n });\n }\n\n // Ledger\n async getLedger(limit?: number, offset?: number): Promise<{ balance_sats: number; entries: LedgerEntry[] }> {\n let path = '/api/v1/ledger';\n const params = new URLSearchParams();\n if (limit) params.append('limit', String(limit));\n if (offset) params.append('offset', String(offset));\n if (params.toString()) path += '?' + params.toString();\n return this.request('GET', path);\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.js
CHANGED
|
@@ -183,7 +183,14 @@ var L402Agent = class {
|
|
|
183
183
|
}
|
|
184
184
|
// Offers
|
|
185
185
|
async createOffer(params) {
|
|
186
|
-
|
|
186
|
+
const { sla_minutes, dispute_window_minutes, ...rest } = params;
|
|
187
|
+
return this.request("POST", "/api/v1/offers", {
|
|
188
|
+
...rest,
|
|
189
|
+
terms: {
|
|
190
|
+
sla_minutes: sla_minutes ?? 30,
|
|
191
|
+
dispute_window_minutes: dispute_window_minutes ?? 1440
|
|
192
|
+
}
|
|
193
|
+
});
|
|
187
194
|
}
|
|
188
195
|
async listOffers() {
|
|
189
196
|
const result = await this.request("GET", "/api/v1/offers");
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client.ts"],"sourcesContent":["import type {\n L402AgentOptions,\n BalanceInfo,\n Offer,\n CreateOfferParams,\n Contract,\n FundResult,\n DepositInvoice,\n DepositStatus,\n LedgerEntry,\n WithdrawResult,\n AgentRegistration,\n PaymentNeededCallback,\n} from './types.js';\n\nexport class L402Error extends Error {\n status: number;\n code?: string;\n\n constructor(message: string, status: number, code?: string) {\n super(message);\n this.name = 'L402Error';\n this.status = status;\n this.code = code;\n }\n}\n\nexport class L402Agent {\n private apiKey: string;\n private apiUrl: string;\n\n private onPaymentNeeded?: PaymentNeededCallback;\n private paymentTimeoutMs: number;\n private paymentPollIntervalMs: number;\n\n constructor(options: L402AgentOptions) {\n if (!options.apiKey) {\n throw new Error('apiKey is required');\n }\n this.apiKey = options.apiKey;\n this.apiUrl = options.apiUrl ?? 'https://l402gw.nosaltres2.info';\n this.onPaymentNeeded = options.onPaymentNeeded;\n this.paymentTimeoutMs = options.paymentTimeoutMs ?? 300_000;\n this.paymentPollIntervalMs = options.paymentPollIntervalMs ?? 5_000;\n }\n\n private async request<T>(method: string, path: string, body?: any): Promise<T> {\n const url = `${this.apiUrl}${path}`;\n const options: RequestInit = {\n method,\n headers: {\n 'X-L402-Key': this.apiKey,\n 'Content-Type': 'application/json',\n },\n };\n\n if (body) {\n options.body = JSON.stringify(body);\n }\n\n const res = await fetch(url, options);\n\n if (!res.ok) {\n let errorMsg = `HTTP ${res.status}`;\n let errorCode: string | undefined;\n\n try {\n const data = await res.json() as { error?: string; code?: string };\n errorMsg = data.error || errorMsg;\n errorCode = data.code;\n } catch {\n // Use default error message\n }\n\n throw new L402Error(errorMsg, res.status, errorCode);\n }\n\n return res.json() as Promise<T>;\n }\n\n // Static: register a new agent (no auth needed)\n static async register(options: {\n name: string;\n description?: string;\n wallet_type?: 'custodial' | 'external';\n lightning_address?: string;\n apiUrl?: string;\n }): Promise<AgentRegistration> {\n const apiUrl = options.apiUrl ?? 'https://l402gw.nosaltres2.info';\n const url = `${apiUrl}/api/v1/agents/register`;\n\n const res = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n name: options.name,\n description: options.description,\n wallet_type: options.wallet_type ?? 'custodial',\n lightning_address: options.lightning_address,\n }),\n });\n\n if (!res.ok) {\n let errorMsg = `HTTP ${res.status}`;\n try {\n const data = await res.json() as { error?: string };\n errorMsg = data.error || errorMsg;\n } catch {\n // Use default error message\n }\n throw new L402Error(errorMsg, res.status);\n }\n\n return res.json() as Promise<AgentRegistration>;\n }\n\n // Wallet\n async getBalance(): Promise<BalanceInfo> {\n return this.request('GET', '/api/v1/wallet/balance');\n }\n\n /**\n * Low-level: create a deposit invoice. Returns the invoice for manual handling.\n * Most agents should use `deposit()` instead, which notifies the human and waits.\n */\n async createDeposit(amount_sats: number): Promise<DepositInvoice> {\n const result = await this.request<DepositInvoice>('POST', '/api/v1/wallet/deposit', { amount_sats });\n // Add pay_url for easy wallet linking\n return {\n ...result,\n pay_url: `lightning:${result.invoice}`,\n };\n }\n\n /**\n * Check if a deposit invoice has been paid.\n */\n async checkDeposit(paymentHash: string): Promise<DepositStatus> {\n return this.request('GET', `/api/v1/wallet/deposit/${paymentHash}`);\n }\n\n /**\n * High-level deposit: creates invoice, notifies human, waits for payment.\n *\n * WHY THIS EXISTS: AI agents don't have Lightning wallets. They can't pay\n * invoices. When an agent needs sats, it must ask a human to pay.\n *\n * This method:\n * 1. Creates a Lightning invoice for the requested amount\n * 2. Calls `onPaymentNeeded` so you can notify the human (chat, email, UI)\n * 3. Polls until the invoice is paid or times out\n * 4. Returns the confirmed deposit status\n *\n * If `onPaymentNeeded` is not configured, throws with the invoice so the\n * caller can handle notification manually.\n *\n * @param amount_sats - Amount to deposit\n * @param reason - Human-readable reason (shown in the notification)\n * @returns Confirmed deposit status\n * @throws {L402Error} if payment times out or fails\n *\n * @example\n * const agent = new L402Agent({\n * apiKey: 'sk_...',\n * onPaymentNeeded: async (invoice) => {\n * // Send to Slack, Discord, Signal, email, etc.\n * await notify(`Pay ${invoice.amount_sats} sats: ${invoice.invoice}`);\n * },\n * });\n *\n * // Agent requests funding and waits\n * const deposit = await agent.deposit(1000, 'Need funds to accept code-review offer');\n * console.log(`Funded! Balance: ${deposit.amount_sats} sats`);\n */\n async deposit(amount_sats: number, reason?: string): Promise<DepositStatus> {\n const invoice = await this.createDeposit(amount_sats);\n\n // If no callback, throw with invoice details so caller can handle it\n if (!this.onPaymentNeeded) {\n throw new L402Error(\n `Payment needed: ${amount_sats} sats. ` +\n `Invoice: ${invoice.invoice}. ` +\n `No onPaymentNeeded callback configured — pay this invoice manually ` +\n `and call checkDeposit('${invoice.payment_hash}') to confirm.`,\n 402,\n 'PAYMENT_NEEDED'\n );\n }\n\n // Notify the human with clear payment instructions\n const enrichedInvoice: DepositInvoice = {\n ...invoice,\n message: [\n reason\n ? `⚡ Agent needs ${amount_sats} sats: ${reason}`\n : `⚡ Agent needs ${amount_sats} sats deposited`,\n '',\n `📱 Tap to pay: ${invoice.pay_url}`,\n '',\n `Or paste this invoice into any Lightning wallet:`,\n invoice.invoice,\n ].join('\\n'),\n };\n await this.onPaymentNeeded(enrichedInvoice);\n\n // Poll for payment\n if (this.paymentTimeoutMs === 0) {\n return { status: 'pending', amount_sats, paid_at: null };\n }\n\n const deadline = Date.now() + this.paymentTimeoutMs;\n while (Date.now() < deadline) {\n await new Promise(r => setTimeout(r, this.paymentPollIntervalMs));\n const status = await this.checkDeposit(invoice.payment_hash);\n if (status.status === 'paid') return status;\n if (status.status === 'expired') {\n throw new L402Error('Deposit invoice expired before payment', 408, 'PAYMENT_EXPIRED');\n }\n }\n\n throw new L402Error(\n `Payment not received within ${this.paymentTimeoutMs / 1000}s. ` +\n `Invoice may still be valid — check with checkDeposit('${invoice.payment_hash}')`,\n 408,\n 'PAYMENT_TIMEOUT'\n );\n }\n\n /**\n * Ensure the agent has at least `minBalance` sats. If not, request a deposit.\n * Convenience method that checks balance first, then deposits the difference.\n *\n * @example\n * // Before accepting an offer, make sure you can pay\n * await agent.ensureBalance(500, 'Need funds for code-review contract');\n * await agent.fundContract(contractId);\n */\n async ensureBalance(minBalance: number, reason?: string): Promise<BalanceInfo> {\n const current = await this.getBalance();\n if (current.balance_sats >= minBalance) return current;\n\n const needed = minBalance - current.balance_sats;\n await this.deposit(needed, reason ?? `Need ${needed} more sats (have ${current.balance_sats}, need ${minBalance})`);\n return this.getBalance();\n }\n\n async withdraw(amount_sats?: number): Promise<WithdrawResult> {\n return this.request('POST', '/api/v1/wallet/withdraw', amount_sats ? { amount_sats } : {});\n }\n\n // Offers\n async createOffer(params: CreateOfferParams): Promise<Offer> {\n return this.request('POST', '/api/v1/offers', params);\n }\n\n async listOffers(): Promise<Offer[]> {\n const result = await this.request<{ offers: Offer[] }>('GET', '/api/v1/offers');\n return result.offers || [];\n }\n\n async getOffer(offerId: string): Promise<Offer> {\n return this.request('GET', `/api/v1/offers/${offerId}`);\n }\n\n async updateOffer(offerId: string, active: boolean): Promise<Offer> {\n return this.request('PATCH', `/api/v1/offers/${offerId}`, { active });\n }\n\n // Contracts\n async acceptOffer(offerId: string): Promise<Contract> {\n return this.request('POST', '/api/v1/contracts', { offer_id: offerId });\n }\n\n async fundContract(contractId: string): Promise<FundResult> {\n return this.request('POST', `/api/v1/contracts/${contractId}/fund`, {});\n }\n\n async listContracts(filters?: { role?: 'buyer' | 'seller'; status?: string }): Promise<Contract[]> {\n let path = '/api/v1/contracts';\n const params = new URLSearchParams();\n if (filters?.role) params.append('role', filters.role);\n if (filters?.status) params.append('status', filters.status);\n if (params.toString()) path += '?' + params.toString();\n const result = await this.request<{ contracts: Contract[] }>('GET', path);\n return result.contracts || [];\n }\n\n async getContract(contractId: string): Promise<Contract> {\n return this.request('GET', `/api/v1/contracts/${contractId}`);\n }\n\n // Delivery\n async submitDelivery(contractId: string, proofUrl: string, proofData?: any): Promise<Contract> {\n return this.request('POST', `/api/v1/contracts/${contractId}/deliver`, {\n proof_url: proofUrl,\n proof_data: proofData,\n });\n }\n\n async confirmDelivery(contractId: string): Promise<Contract> {\n return this.request('POST', `/api/v1/contracts/${contractId}/confirm`, {});\n }\n\n async disputeDelivery(contractId: string, reason: string, evidenceUrl?: string): Promise<Contract> {\n return this.request('POST', `/api/v1/contracts/${contractId}/dispute`, {\n reason,\n evidence_url: evidenceUrl,\n });\n }\n\n // Ledger\n async getLedger(limit?: number, offset?: number): Promise<{ balance_sats: number; entries: LedgerEntry[] }> {\n let path = '/api/v1/ledger';\n const params = new URLSearchParams();\n if (limit) params.append('limit', String(limit));\n if (offset) params.append('offset', String(offset));\n if (params.toString()) path += '?' + params.toString();\n return this.request('GET', path);\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/client.ts"],"sourcesContent":["import type {\n L402AgentOptions,\n BalanceInfo,\n Offer,\n CreateOfferParams,\n Contract,\n FundResult,\n DepositInvoice,\n DepositStatus,\n LedgerEntry,\n WithdrawResult,\n AgentRegistration,\n PaymentNeededCallback,\n} from './types.js';\n\nexport class L402Error extends Error {\n status: number;\n code?: string;\n\n constructor(message: string, status: number, code?: string) {\n super(message);\n this.name = 'L402Error';\n this.status = status;\n this.code = code;\n }\n}\n\nexport class L402Agent {\n private apiKey: string;\n private apiUrl: string;\n\n private onPaymentNeeded?: PaymentNeededCallback;\n private paymentTimeoutMs: number;\n private paymentPollIntervalMs: number;\n\n constructor(options: L402AgentOptions) {\n if (!options.apiKey) {\n throw new Error('apiKey is required');\n }\n this.apiKey = options.apiKey;\n this.apiUrl = options.apiUrl ?? 'https://l402gw.nosaltres2.info';\n this.onPaymentNeeded = options.onPaymentNeeded;\n this.paymentTimeoutMs = options.paymentTimeoutMs ?? 300_000;\n this.paymentPollIntervalMs = options.paymentPollIntervalMs ?? 5_000;\n }\n\n private async request<T>(method: string, path: string, body?: any): Promise<T> {\n const url = `${this.apiUrl}${path}`;\n const options: RequestInit = {\n method,\n headers: {\n 'X-L402-Key': this.apiKey,\n 'Content-Type': 'application/json',\n },\n };\n\n if (body) {\n options.body = JSON.stringify(body);\n }\n\n const res = await fetch(url, options);\n\n if (!res.ok) {\n let errorMsg = `HTTP ${res.status}`;\n let errorCode: string | undefined;\n\n try {\n const data = await res.json() as { error?: string; code?: string };\n errorMsg = data.error || errorMsg;\n errorCode = data.code;\n } catch {\n // Use default error message\n }\n\n throw new L402Error(errorMsg, res.status, errorCode);\n }\n\n return res.json() as Promise<T>;\n }\n\n // Static: register a new agent (no auth needed)\n static async register(options: {\n name: string;\n description?: string;\n wallet_type?: 'custodial' | 'external';\n lightning_address?: string;\n apiUrl?: string;\n }): Promise<AgentRegistration> {\n const apiUrl = options.apiUrl ?? 'https://l402gw.nosaltres2.info';\n const url = `${apiUrl}/api/v1/agents/register`;\n\n const res = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n name: options.name,\n description: options.description,\n wallet_type: options.wallet_type ?? 'custodial',\n lightning_address: options.lightning_address,\n }),\n });\n\n if (!res.ok) {\n let errorMsg = `HTTP ${res.status}`;\n try {\n const data = await res.json() as { error?: string };\n errorMsg = data.error || errorMsg;\n } catch {\n // Use default error message\n }\n throw new L402Error(errorMsg, res.status);\n }\n\n return res.json() as Promise<AgentRegistration>;\n }\n\n // Wallet\n async getBalance(): Promise<BalanceInfo> {\n return this.request('GET', '/api/v1/wallet/balance');\n }\n\n /**\n * Low-level: create a deposit invoice. Returns the invoice for manual handling.\n * Most agents should use `deposit()` instead, which notifies the human and waits.\n */\n async createDeposit(amount_sats: number): Promise<DepositInvoice> {\n const result = await this.request<DepositInvoice>('POST', '/api/v1/wallet/deposit', { amount_sats });\n // Add pay_url for easy wallet linking\n return {\n ...result,\n pay_url: `lightning:${result.invoice}`,\n };\n }\n\n /**\n * Check if a deposit invoice has been paid.\n */\n async checkDeposit(paymentHash: string): Promise<DepositStatus> {\n return this.request('GET', `/api/v1/wallet/deposit/${paymentHash}`);\n }\n\n /**\n * High-level deposit: creates invoice, notifies human, waits for payment.\n *\n * WHY THIS EXISTS: AI agents don't have Lightning wallets. They can't pay\n * invoices. When an agent needs sats, it must ask a human to pay.\n *\n * This method:\n * 1. Creates a Lightning invoice for the requested amount\n * 2. Calls `onPaymentNeeded` so you can notify the human (chat, email, UI)\n * 3. Polls until the invoice is paid or times out\n * 4. Returns the confirmed deposit status\n *\n * If `onPaymentNeeded` is not configured, throws with the invoice so the\n * caller can handle notification manually.\n *\n * @param amount_sats - Amount to deposit\n * @param reason - Human-readable reason (shown in the notification)\n * @returns Confirmed deposit status\n * @throws {L402Error} if payment times out or fails\n *\n * @example\n * const agent = new L402Agent({\n * apiKey: 'sk_...',\n * onPaymentNeeded: async (invoice) => {\n * // Send to Slack, Discord, Signal, email, etc.\n * await notify(`Pay ${invoice.amount_sats} sats: ${invoice.invoice}`);\n * },\n * });\n *\n * // Agent requests funding and waits\n * const deposit = await agent.deposit(1000, 'Need funds to accept code-review offer');\n * console.log(`Funded! Balance: ${deposit.amount_sats} sats`);\n */\n async deposit(amount_sats: number, reason?: string): Promise<DepositStatus> {\n const invoice = await this.createDeposit(amount_sats);\n\n // If no callback, throw with invoice details so caller can handle it\n if (!this.onPaymentNeeded) {\n throw new L402Error(\n `Payment needed: ${amount_sats} sats. ` +\n `Invoice: ${invoice.invoice}. ` +\n `No onPaymentNeeded callback configured — pay this invoice manually ` +\n `and call checkDeposit('${invoice.payment_hash}') to confirm.`,\n 402,\n 'PAYMENT_NEEDED'\n );\n }\n\n // Notify the human with clear payment instructions\n const enrichedInvoice: DepositInvoice = {\n ...invoice,\n message: [\n reason\n ? `⚡ Agent needs ${amount_sats} sats: ${reason}`\n : `⚡ Agent needs ${amount_sats} sats deposited`,\n '',\n `📱 Tap to pay: ${invoice.pay_url}`,\n '',\n `Or paste this invoice into any Lightning wallet:`,\n invoice.invoice,\n ].join('\\n'),\n };\n await this.onPaymentNeeded(enrichedInvoice);\n\n // Poll for payment\n if (this.paymentTimeoutMs === 0) {\n return { status: 'pending', amount_sats, paid_at: null };\n }\n\n const deadline = Date.now() + this.paymentTimeoutMs;\n while (Date.now() < deadline) {\n await new Promise(r => setTimeout(r, this.paymentPollIntervalMs));\n const status = await this.checkDeposit(invoice.payment_hash);\n if (status.status === 'paid') return status;\n if (status.status === 'expired') {\n throw new L402Error('Deposit invoice expired before payment', 408, 'PAYMENT_EXPIRED');\n }\n }\n\n throw new L402Error(\n `Payment not received within ${this.paymentTimeoutMs / 1000}s. ` +\n `Invoice may still be valid — check with checkDeposit('${invoice.payment_hash}')`,\n 408,\n 'PAYMENT_TIMEOUT'\n );\n }\n\n /**\n * Ensure the agent has at least `minBalance` sats. If not, request a deposit.\n * Convenience method that checks balance first, then deposits the difference.\n *\n * @example\n * // Before accepting an offer, make sure you can pay\n * await agent.ensureBalance(500, 'Need funds for code-review contract');\n * await agent.fundContract(contractId);\n */\n async ensureBalance(minBalance: number, reason?: string): Promise<BalanceInfo> {\n const current = await this.getBalance();\n if (current.balance_sats >= minBalance) return current;\n\n const needed = minBalance - current.balance_sats;\n await this.deposit(needed, reason ?? `Need ${needed} more sats (have ${current.balance_sats}, need ${minBalance})`);\n return this.getBalance();\n }\n\n async withdraw(amount_sats?: number): Promise<WithdrawResult> {\n return this.request('POST', '/api/v1/wallet/withdraw', amount_sats ? { amount_sats } : {});\n }\n\n // Offers\n async createOffer(params: CreateOfferParams): Promise<Offer> {\n const { sla_minutes, dispute_window_minutes, ...rest } = params;\n return this.request('POST', '/api/v1/offers', {\n ...rest,\n terms: {\n sla_minutes: sla_minutes ?? 30,\n dispute_window_minutes: dispute_window_minutes ?? 1440,\n },\n });\n }\n\n async listOffers(): Promise<Offer[]> {\n const result = await this.request<{ offers: Offer[] }>('GET', '/api/v1/offers');\n return result.offers || [];\n }\n\n async getOffer(offerId: string): Promise<Offer> {\n return this.request('GET', `/api/v1/offers/${offerId}`);\n }\n\n async updateOffer(offerId: string, active: boolean): Promise<Offer> {\n return this.request('PATCH', `/api/v1/offers/${offerId}`, { active });\n }\n\n // Contracts\n async acceptOffer(offerId: string): Promise<Contract> {\n return this.request('POST', '/api/v1/contracts', { offer_id: offerId });\n }\n\n async fundContract(contractId: string): Promise<FundResult> {\n return this.request('POST', `/api/v1/contracts/${contractId}/fund`, {});\n }\n\n async listContracts(filters?: { role?: 'buyer' | 'seller'; status?: string }): Promise<Contract[]> {\n let path = '/api/v1/contracts';\n const params = new URLSearchParams();\n if (filters?.role) params.append('role', filters.role);\n if (filters?.status) params.append('status', filters.status);\n if (params.toString()) path += '?' + params.toString();\n const result = await this.request<{ contracts: Contract[] }>('GET', path);\n return result.contracts || [];\n }\n\n async getContract(contractId: string): Promise<Contract> {\n return this.request('GET', `/api/v1/contracts/${contractId}`);\n }\n\n // Delivery\n async submitDelivery(contractId: string, proofUrl: string, proofData?: any): Promise<Contract> {\n return this.request('POST', `/api/v1/contracts/${contractId}/deliver`, {\n proof_url: proofUrl,\n proof_data: proofData,\n });\n }\n\n async confirmDelivery(contractId: string): Promise<Contract> {\n return this.request('POST', `/api/v1/contracts/${contractId}/confirm`, {});\n }\n\n async disputeDelivery(contractId: string, reason: string, evidenceUrl?: string): Promise<Contract> {\n return this.request('POST', `/api/v1/contracts/${contractId}/dispute`, {\n reason,\n evidence_url: evidenceUrl,\n });\n }\n\n // Ledger\n async getLedger(limit?: number, offset?: number): Promise<{ balance_sats: number; entries: LedgerEntry[] }> {\n let path = '/api/v1/ledger';\n const params = new URLSearchParams();\n if (limit) params.append('limit', String(limit));\n if (offset) params.append('offset', String(offset));\n if (params.toString()) path += '?' + params.toString();\n return this.request('GET', path);\n }\n}\n"],"mappings":"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","names":[]}
|