neutron-sdk 0.1.4 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.cjs +97 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +64 -3
- package/dist/index.d.ts +64 -3
- package/dist/index.js +97 -7
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -297,7 +297,7 @@ const neutron = new Neutron({
|
|
|
297
297
|
- **Two-step flow**: `.create()` returns a quote → `.confirm()` executes it.
|
|
298
298
|
- **Set amount on one side only** — `sourceReq` OR `destReq`, not both.
|
|
299
299
|
- **`createInvoice()` auto-confirms** — no second step needed for receiving.
|
|
300
|
-
- **KYC only for fiat payouts**. Lightning
|
|
300
|
+
- **KYC only for fiat payouts**. Bitcoin (Lightning + on-chain), stablecoins (USDT on TRON/ETH), and swaps require **no KYC**.
|
|
301
301
|
- **Token management is automatic** — the SDK authenticates on first request and refreshes as needed.
|
|
302
302
|
|
|
303
303
|
---
|
package/dist/index.cjs
CHANGED
|
@@ -196,6 +196,16 @@ var HttpClient = class {
|
|
|
196
196
|
await this.ensureAuth();
|
|
197
197
|
return this.accountId;
|
|
198
198
|
}
|
|
199
|
+
/**
|
|
200
|
+
* Returns auth headers for use in raw fetch calls (e.g. SSE streams).
|
|
201
|
+
* Ensures a valid token is present before returning.
|
|
202
|
+
*/
|
|
203
|
+
async getAuthHeaders() {
|
|
204
|
+
await this.ensureAuth();
|
|
205
|
+
return {
|
|
206
|
+
Authorization: `Bearer ${this.accessToken}`
|
|
207
|
+
};
|
|
208
|
+
}
|
|
199
209
|
// ── HTTP ──────────────────────────────────────────────
|
|
200
210
|
async rawFetch(url, init) {
|
|
201
211
|
const controller = new AbortController();
|
|
@@ -222,9 +232,9 @@ var HttpClient = class {
|
|
|
222
232
|
const url = `${this.baseUrl}${path}`;
|
|
223
233
|
this.log(`${method} ${path}`);
|
|
224
234
|
const headers = {
|
|
225
|
-
Authorization: `Bearer ${this.accessToken}
|
|
235
|
+
Authorization: `Bearer ${this.accessToken}`,
|
|
236
|
+
"Content-Type": "application/json"
|
|
226
237
|
};
|
|
227
|
-
if (body) headers["Content-Type"] = "application/json";
|
|
228
238
|
const response = await this.rawFetch(url, {
|
|
229
239
|
method,
|
|
230
240
|
headers,
|
|
@@ -399,10 +409,14 @@ var TransactionsResource = class {
|
|
|
399
409
|
}
|
|
400
410
|
/**
|
|
401
411
|
* Cancel a quoted (unconfirmed) transaction.
|
|
412
|
+
*
|
|
413
|
+
* @deprecated This endpoint is not currently available on the Neutron API.
|
|
414
|
+
* Unconfirmed transactions expire automatically after their TTL.
|
|
402
415
|
*/
|
|
403
|
-
async cancel(
|
|
404
|
-
|
|
405
|
-
|
|
416
|
+
async cancel(_txnId) {
|
|
417
|
+
throw new Error(
|
|
418
|
+
"transactions.cancel() is not available. Unconfirmed transactions expire automatically."
|
|
419
|
+
);
|
|
406
420
|
}
|
|
407
421
|
/**
|
|
408
422
|
* Wait for a transaction to reach a final state. Polls at the given interval.
|
|
@@ -437,6 +451,65 @@ var TransactionsResource = class {
|
|
|
437
451
|
}
|
|
438
452
|
throw new Error(`Transaction ${txnId} did not complete within ${timeout}ms`);
|
|
439
453
|
}
|
|
454
|
+
/**
|
|
455
|
+
* Stream real-time transaction status updates via SSE.
|
|
456
|
+
* For agents without a public endpoint who can't receive webhook POSTs.
|
|
457
|
+
*
|
|
458
|
+
* NOTE: Requires the server-side endpoint /api/v2/events/stream (not yet live).
|
|
459
|
+
* Use neutron.transactions.waitForCompletion() as a polling fallback in the meantime.
|
|
460
|
+
*
|
|
461
|
+
* @example
|
|
462
|
+
* for await (const event of neutron.transactions.subscribe("txn-123")) {
|
|
463
|
+
* console.log(event.status);
|
|
464
|
+
* if (event.status === "completed") break;
|
|
465
|
+
* }
|
|
466
|
+
*/
|
|
467
|
+
async *subscribe(transactionId, timeoutMs = 6e4) {
|
|
468
|
+
sanitizePathParam(transactionId, "transactionId");
|
|
469
|
+
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
470
|
+
if (!UUID_RE.test(transactionId)) {
|
|
471
|
+
throw new Error("Invalid transactionId: must be a UUID.");
|
|
472
|
+
}
|
|
473
|
+
const clampedTimeout = Math.min(Math.max(timeoutMs, 5e3), 3e5);
|
|
474
|
+
const url = `${this.client.baseUrl}/api/v2/events/stream?transactionId=${encodeURIComponent(transactionId)}`;
|
|
475
|
+
const response = await fetch(url, {
|
|
476
|
+
headers: {
|
|
477
|
+
"Accept": "text/event-stream",
|
|
478
|
+
...await this.client.getAuthHeaders()
|
|
479
|
+
},
|
|
480
|
+
signal: AbortSignal.timeout(clampedTimeout)
|
|
481
|
+
});
|
|
482
|
+
if (!response.ok || !response.body) {
|
|
483
|
+
throw new Error(`SSE connection failed: ${response.status} ${response.statusText}`);
|
|
484
|
+
}
|
|
485
|
+
const reader = response.body.getReader();
|
|
486
|
+
const decoder = new TextDecoder();
|
|
487
|
+
let buffer = "";
|
|
488
|
+
const MAX_BUFFER = 64 * 1024;
|
|
489
|
+
try {
|
|
490
|
+
while (true) {
|
|
491
|
+
const { done, value } = await reader.read();
|
|
492
|
+
if (done) break;
|
|
493
|
+
buffer += decoder.decode(value, { stream: true });
|
|
494
|
+
if (buffer.length > MAX_BUFFER) {
|
|
495
|
+
throw new Error("SSE buffer overflow \u2014 server sent malformed stream.");
|
|
496
|
+
}
|
|
497
|
+
const lines = buffer.split("\n");
|
|
498
|
+
buffer = lines.pop() || "";
|
|
499
|
+
for (const line of lines) {
|
|
500
|
+
if (line.startsWith("data: ")) {
|
|
501
|
+
try {
|
|
502
|
+
yield JSON.parse(line.slice(6));
|
|
503
|
+
} catch (parseErr) {
|
|
504
|
+
console.error("[neutron-sdk] SSE parse error:", parseErr);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
} finally {
|
|
510
|
+
reader.cancel();
|
|
511
|
+
}
|
|
512
|
+
}
|
|
440
513
|
};
|
|
441
514
|
|
|
442
515
|
// src/resources/lightning.ts
|
|
@@ -538,10 +611,26 @@ var LightningResource = class {
|
|
|
538
611
|
destReq: {
|
|
539
612
|
ccy: "BTC",
|
|
540
613
|
method: "lnurl",
|
|
541
|
-
reqDetails: {
|
|
614
|
+
reqDetails: { address }
|
|
542
615
|
}
|
|
543
616
|
});
|
|
544
617
|
}
|
|
618
|
+
/**
|
|
619
|
+
* Decode a Lightning invoice (BOLT11) to inspect amount, description, etc.
|
|
620
|
+
* Useful for showing users what they're about to pay before confirming.
|
|
621
|
+
*
|
|
622
|
+
* @example
|
|
623
|
+
* const decoded = await neutron.lightning.decodeInvoice("lnbc100u1p...");
|
|
624
|
+
* console.log(decoded.amount); // 0.001 (BTC)
|
|
625
|
+
* console.log(decoded.description); // "Coffee payment"
|
|
626
|
+
*/
|
|
627
|
+
async decodeInvoice(invoice) {
|
|
628
|
+
const result = await this.client.post(
|
|
629
|
+
`/api/v2/decode/lightning`,
|
|
630
|
+
{ paymentRequest: invoice }
|
|
631
|
+
);
|
|
632
|
+
return result.invoice;
|
|
633
|
+
}
|
|
545
634
|
};
|
|
546
635
|
|
|
547
636
|
// src/resources/webhooks.ts
|
|
@@ -667,7 +756,8 @@ var FiatResource = class {
|
|
|
667
756
|
return res.data ?? res;
|
|
668
757
|
}
|
|
669
758
|
/**
|
|
670
|
-
* Create a fiat payout transaction.
|
|
759
|
+
* Create a fiat payout transaction. KYC is required only for fiat payouts — not for
|
|
760
|
+
* Bitcoin, stablecoins, or swaps. Handles KYC and source of funds automatically.
|
|
671
761
|
* Returns a quoted transaction — call `neutron.transactions.confirm()` to execute.
|
|
672
762
|
*
|
|
673
763
|
* @example
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/client.ts","../src/errors.ts","../src/sanitize.ts","../src/resources/account.ts","../src/resources/transactions.ts","../src/resources/lightning.ts","../src/resources/webhooks.ts","../src/resources/rates.ts","../src/resources/fiat.ts","../src/utils.ts"],"sourcesContent":["import { HttpClient } from \"./client.js\";\nimport { AccountResource } from \"./resources/account.js\";\nimport { TransactionsResource } from \"./resources/transactions.js\";\nimport { LightningResource } from \"./resources/lightning.js\";\nimport { WebhooksResource } from \"./resources/webhooks.js\";\nimport { RatesResource } from \"./resources/rates.js\";\nimport { FiatResource } from \"./resources/fiat.js\";\nimport type { NeutronConfig } from \"./types.js\";\n\n/**\n * Neutron SDK — Bitcoin Lightning, stablecoins, and fiat payments.\n *\n * @example\n * import { Neutron } from \"neutron-sdk\";\n *\n * const neutron = new Neutron({\n * apiKey: process.env.NEUTRON_API_KEY!,\n * apiSecret: process.env.NEUTRON_API_SECRET!,\n * });\n *\n * // Check balances\n * const wallets = await neutron.account.wallets();\n *\n * // Create a Lightning invoice\n * const invoice = await neutron.lightning.createInvoice({ amountSats: 10000 });\n *\n * // Send to a Lightning Address\n * const txn = await neutron.lightning.payAddress(\"alice@getalby.com\", { amountSats: 5000 });\n * await neutron.transactions.confirm(txn.txnId);\n */\nexport class Neutron {\n /** Account info, wallets, and deposit addresses */\n readonly account: AccountResource;\n /** Create, confirm, list, and track transactions */\n readonly transactions: TransactionsResource;\n /** Lightning invoices, payments, and utilities */\n readonly lightning: LightningResource;\n /** Webhook management */\n readonly webhooks: WebhooksResource;\n /** BTC exchange rates */\n readonly rates: RatesResource;\n /** Fiat payouts and bank lookups */\n readonly fiat: FiatResource;\n\n private readonly client: HttpClient;\n\n constructor(config: NeutronConfig) {\n this.client = new HttpClient(config);\n this.account = new AccountResource(this.client);\n this.transactions = new TransactionsResource(this.client);\n this.lightning = new LightningResource(this.client);\n this.webhooks = new WebhooksResource(this.client);\n this.rates = new RatesResource(this.client);\n this.fiat = new FiatResource(this.client);\n }\n\n /**\n * Explicitly authenticate and verify credentials.\n * Usually not needed — the SDK auto-authenticates on first request.\n */\n async authenticate() {\n return this.client.authenticate();\n }\n\n /**\n * Verify a webhook signature. Static method — no client instance needed.\n *\n * @example\n * const event = Neutron.verifyWebhook(req.body, req.headers[\"x-neutronpay-signature\"], secret);\n */\n static verifyWebhook(body: string | Buffer, signature: string | undefined | null, secret: string) {\n return WebhooksResource.verifySignature(body, signature, secret);\n }\n}\n\n// ── Exports ─────────────────────────────────────────────────\n\nexport { HttpClient } from \"./client.js\";\nexport { AccountResource } from \"./resources/account.js\";\nexport { TransactionsResource } from \"./resources/transactions.js\";\nexport { LightningResource } from \"./resources/lightning.js\";\nexport { WebhooksResource } from \"./resources/webhooks.js\";\nexport { RatesResource } from \"./resources/rates.js\";\nexport { FiatResource } from \"./resources/fiat.js\";\nexport type { FiatPayoutParams } from \"./resources/fiat.js\";\n\nexport { sanitizePathParam } from \"./sanitize.js\";\n\nexport {\n NeutronError,\n NeutronApiError,\n NeutronAuthError,\n NeutronTimeoutError,\n NeutronValidationError,\n} from \"./errors.js\";\n\nexport {\n satsToBtc,\n btcToSats,\n formatSats,\n formatBtc,\n Currency,\n PaymentMethod,\n TransactionStates,\n FinalStates,\n Chain,\n} from \"./utils.js\";\n\nexport type {\n Currency as CurrencyType,\n PaymentMethodType,\n} from \"./utils.js\";\n\nexport type {\n NeutronConfig,\n AuthResponse,\n Account,\n Wallet,\n Transaction,\n TransactionState,\n TransactionSide,\n PaymentMethod as PaymentMethodString,\n CreateTransactionRequest,\n ListTransactionsParams,\n CreateInvoiceParams,\n LightningInvoice,\n BtcAddress,\n UsdtAddress,\n Webhook,\n CreateWebhookParams,\n UpdateWebhookParams,\n ExchangeRates,\n FiatInstitution,\n KycInfo,\n SourceOfFunds,\n ApiResponse,\n} from \"./types.js\";\n","import crypto from \"crypto\";\nimport type { NeutronConfig, AuthResponse } from \"./types.js\";\nimport {\n NeutronApiError,\n NeutronAuthError,\n NeutronTimeoutError,\n} from \"./errors.js\";\n\nconst DEFAULT_BASE_URL = \"https://api.neutron.me\";\nconst DEFAULT_TIMEOUT = 30_000;\nconst DEFAULT_MAX_RETRIES = 2;\nconst TOKEN_REFRESH_BUFFER_MS = 60_000; // refresh 1 min before expiry\n\nexport class HttpClient {\n private readonly apiKey: string;\n private readonly apiSecret: string;\n readonly baseUrl: string;\n private readonly timeout: number;\n private readonly maxRetries: number;\n private readonly debug: boolean;\n\n private accessToken: string | null = null;\n private accountId: string | null = null;\n private tokenExpiry: number = 0;\n\n constructor(config: NeutronConfig) {\n if (!config.apiKey) throw new NeutronAuthError(\"apiKey is required\");\n if (!config.apiSecret) throw new NeutronAuthError(\"apiSecret is required\");\n\n this.apiKey = config.apiKey;\n this.apiSecret = config.apiSecret;\n this.baseUrl = (config.baseUrl || DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this.timeout = config.timeout ?? DEFAULT_TIMEOUT;\n this.maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES;\n this.debug = config.debug ?? false;\n }\n\n private log(message: string, data?: any): void {\n if (!this.debug) return;\n const ts = new Date().toISOString();\n const extra = data ? ` ${JSON.stringify(data)}` : \"\";\n console.error(`[neutron-sdk ${ts}] ${message}${extra}`);\n }\n\n // ── Auth ──────────────────────────────────────────────\n\n private generateSignature(payload: string): string {\n const stringToSign = `${this.apiKey}&payload=${payload}`;\n return crypto\n .createHmac(\"sha256\", this.apiSecret)\n .update(stringToSign)\n .digest(\"hex\");\n }\n\n private get isTokenValid(): boolean {\n return !!(\n this.accessToken &&\n this.accountId &&\n Date.now() < this.tokenExpiry - TOKEN_REFRESH_BUFFER_MS\n );\n }\n\n async authenticate(): Promise<AuthResponse> {\n const payload = JSON.stringify({ test: \"auth\" });\n const signature = this.generateSignature(payload);\n\n const response = await this.rawFetch(\n `${this.baseUrl}/api/v2/authentication/token-signature`,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Api-Key\": this.apiKey,\n \"X-Api-Signature\": signature,\n },\n body: payload,\n }\n );\n\n if (!response.ok) {\n const body = (await response.json().catch(() => ({}))) as Record<string, any>;\n throw new NeutronAuthError(\n body.error || body.message || `Authentication failed (${response.status})`\n );\n }\n\n const raw = (await response.json()) as any;\n // API wraps auth response in { data: { ... } }\n const result: AuthResponse = raw.data ?? raw;\n this.accountId = result.accountId;\n this.accessToken = result.accessToken;\n this.tokenExpiry = typeof result.expiredAt === \"number\"\n ? result.expiredAt\n : new Date(result.expiredAt).getTime();\n\n return result;\n this.log(\"Authenticated\", { accountId: this.accountId });\n }\n\n private async ensureAuth(): Promise<void> {\n if (!this.isTokenValid) {\n await this.authenticate();\n }\n }\n\n getAccountId(): string {\n if (!this.accountId) {\n throw new NeutronAuthError(\"Not authenticated. Call a method first or use neutron.account.get().\");\n }\n return this.accountId;\n }\n\n async ensureAuthAndGetAccountId(): Promise<string> {\n await this.ensureAuth();\n return this.accountId!;\n }\n\n // ── HTTP ──────────────────────────────────────────────\n\n private async rawFetch(url: string, init: RequestInit): Promise<Response> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n return await fetch(url, { ...init, signal: controller.signal });\n } catch (err: any) {\n if (err.name === \"AbortError\") {\n throw new NeutronTimeoutError(this.timeout);\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n }\n\n async request<T = any>(method: string, path: string, body?: any): Promise<T> {\n await this.ensureAuth();\n\n let lastError: any;\n\n for (let attempt = 0; attempt <= this.maxRetries; attempt++) {\n if (attempt > 0) {\n // Exponential backoff: 1s, 2s, 4s...\n await new Promise((r) => setTimeout(r, Math.pow(2, attempt - 1) * 1000));\n\n // Re-auth if token might have expired during retries\n if (!this.isTokenValid) await this.authenticate();\n }\n\n const url = `${this.baseUrl}${path}`;\n this.log(`${method} ${path}`);\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.accessToken}`,\n };\n if (body) headers[\"Content-Type\"] = \"application/json\";\n\n const response = await this.rawFetch(url, {\n method,\n headers,\n body: body ? JSON.stringify(body) : undefined,\n });\n\n if (response.ok) {\n return (await response.json()) as T;\n }\n\n const errorBody = await response.json().catch(() => ({}));\n const apiError = new NeutronApiError(response.status, errorBody);\n\n // Re-authenticate on 401 and retry\n if (response.status === 401 && attempt < this.maxRetries) {\n this.accessToken = null;\n lastError = apiError;\n continue;\n }\n\n // Retry on 5xx and 429\n if (apiError.isRetryable && attempt < this.maxRetries) {\n lastError = apiError;\n continue;\n }\n\n throw apiError;\n }\n\n throw lastError;\n }\n\n async get<T = any>(path: string): Promise<T> {\n return this.request<T>(\"GET\", path);\n }\n\n async post<T = any>(path: string, body?: any): Promise<T> {\n return this.request<T>(\"POST\", path, body);\n }\n\n async put<T = any>(path: string, body?: any): Promise<T> {\n return this.request<T>(\"PUT\", path, body);\n }\n\n async del<T = any>(path: string): Promise<T> {\n return this.request<T>(\"DELETE\", path);\n }\n}\n","/**\n * Base error for all Neutron SDK errors.\n */\nexport class NeutronError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"NeutronError\";\n }\n}\n\n/**\n * Thrown when the API returns an error response (4xx/5xx).\n */\nexport class NeutronApiError extends NeutronError {\n /** HTTP status code */\n readonly status: number;\n /** Neutron error code (e.g. \"2005\") */\n readonly code: string | undefined;\n /** Raw error body from the API */\n readonly body: any;\n\n constructor(status: number, body: any) {\n const message = body?.error || body?.message || `API error ${status}`;\n super(message);\n this.name = \"NeutronApiError\";\n this.status = status;\n this.code = body?.code;\n this.body = body;\n }\n\n /** True if this is a rate limit error (429) */\n get isRateLimited(): boolean {\n return this.status === 429;\n }\n\n /** True if this is an auth error (401/403) */\n get isAuthError(): boolean {\n return this.status === 401 || this.status === 403;\n }\n\n /** True if retrying might help (5xx, 429) */\n get isRetryable(): boolean {\n return this.status === 429 || this.status >= 500;\n }\n}\n\n/**\n * Thrown when authentication fails.\n */\nexport class NeutronAuthError extends NeutronError {\n constructor(message: string = \"Authentication failed. Check your API key and secret.\") {\n super(message);\n this.name = \"NeutronAuthError\";\n }\n}\n\n/**\n * Thrown when a request times out.\n */\nexport class NeutronTimeoutError extends NeutronError {\n constructor(timeoutMs: number) {\n super(`Request timed out after ${timeoutMs}ms`);\n this.name = \"NeutronTimeoutError\";\n }\n}\n\n/**\n * Thrown for SDK usage errors (bad params, missing fields).\n */\nexport class NeutronValidationError extends NeutronError {\n constructor(message: string) {\n super(message);\n this.name = \"NeutronValidationError\";\n }\n}\n","import { NeutronValidationError } from \"./errors.js\";\n\n/**\n * Sanitize a path parameter to prevent path traversal and injection.\n * Only allows alphanumeric characters, hyphens, underscores, and dots.\n */\nexport function sanitizePathParam(value: string, name: string): string {\n if (!value || typeof value !== \"string\") {\n throw new NeutronValidationError(`${name} is required and must be a non-empty string.`);\n }\n\n // Strip any path traversal or special characters\n const sanitized = value.replace(/[^a-zA-Z0-9\\-_.]/g, \"\");\n\n if (sanitized !== value) {\n throw new NeutronValidationError(\n `${name} contains invalid characters. Only alphanumeric, hyphens, underscores, and dots are allowed.`\n );\n }\n\n if (sanitized.includes(\"..\")) {\n throw new NeutronValidationError(`${name} cannot contain path traversal sequences.`);\n }\n\n return sanitized;\n}\n","import type { HttpClient } from \"../client.js\";\nimport type { Account, Wallet } from \"../types.js\";\nimport { sanitizePathParam } from \"../sanitize.js\";\n\nexport class AccountResource {\n constructor(private readonly client: HttpClient) {}\n\n /**\n * Get account info: display name, status, country, timezone.\n */\n async get(): Promise<Account> {\n const accountId = await this.client.ensureAuthAndGetAccountId();\n const res = await this.client.get(`/api/v2/account/${accountId}`);\n return (res.data ?? res) as Account;\n }\n\n /**\n * List all wallets with balances (BTC, USDT, fiat).\n */\n async wallets(): Promise<Wallet[]> {\n const accountId = await this.client.ensureAuthAndGetAccountId();\n const res = await this.client.get(`/api/v2/account/${accountId}/wallet/`);\n return res.data ?? res;\n }\n\n /**\n * Get a specific wallet by ID.\n */\n async wallet(walletId: string): Promise<Wallet> {\n sanitizePathParam(walletId, \"walletId\");\n const accountId = await this.client.ensureAuthAndGetAccountId();\n const res = await this.client.get(`/api/v2/account/${accountId}/wallet/${walletId}`);\n return (res.data ?? res) as Wallet;\n }\n\n /**\n * Get your Bitcoin on-chain deposit address (static, reusable).\n */\n async btcAddress(): Promise<{ address: string }> {\n const raw = await this.client.get(`/api/v2/account/onchain-address`);\n const data = raw?.data ?? raw;\n return { address: data.staticOnchainAddress };\n }\n\n /**\n * Get your USDT deposit address.\n * @param chain \"TRON\" (default, recommended) or \"ETH\"\n */\n async usdtAddress(chain: \"TRON\" | \"ETH\" = \"TRON\"): Promise<{ address: string; chain: string }> {\n const raw = await this.client.get(\n `/api/v2/account/stablecoin-onchain-address?walletCcy=USDT&chainId=${chain}`\n );\n const data = raw?.data ?? raw;\n return {\n address: data.staticStablecoinOnchainAddress || data.staticOnchainAddress,\n chain,\n };\n }\n}\n","import type { HttpClient } from \"../client.js\";\nimport type {\n Transaction,\n CreateTransactionRequest,\n ListTransactionsParams,\n} from \"../types.js\";\nimport { sanitizePathParam } from \"../sanitize.js\";\n\nexport class TransactionsResource {\n constructor(private readonly client: HttpClient) {}\n\n /**\n * Create a transaction (returns a quote). Call `.confirm()` to execute.\n *\n * @example\n * // Lightning receive (create invoice)\n * const txn = await neutron.transactions.create({\n * sourceReq: { ccy: \"BTC\", method: \"lightning\", reqDetails: {} },\n * destReq: { ccy: \"BTC\", method: \"neutronpay\", amtRequested: 0.0001, reqDetails: {} },\n * });\n *\n * @example\n * // Lightning send (pay invoice)\n * const txn = await neutron.transactions.create({\n * sourceReq: { ccy: \"BTC\", method: \"neutronpay\" },\n * destReq: { ccy: \"BTC\", method: \"lightning\", reqDetails: { paymentRequest: \"lnbc...\" } },\n * });\n *\n * @example\n * // Internal swap (BTC → USDT)\n * const txn = await neutron.transactions.create({\n * sourceReq: { ccy: \"BTC\", method: \"neutronpay\", amtRequested: 0.001, reqDetails: {} },\n * destReq: { ccy: \"USDT\", method: \"neutronpay\", reqDetails: {} },\n * });\n */\n async create(params: CreateTransactionRequest): Promise<Transaction> {\n return this.client.post<Transaction>(`/api/v2/transaction`, params);\n }\n\n /**\n * Confirm a quoted transaction to execute it.\n * After confirmation, Lightning invoices become payable and sends are dispatched.\n */\n async confirm(txnId: string): Promise<Transaction> {\n sanitizePathParam(txnId, \"txnId\");\n return this.client.put<Transaction>(`/api/v2/transaction/${txnId}/confirm`);\n }\n\n /**\n * Get transaction status and details.\n */\n async get(txnId: string): Promise<Transaction> {\n sanitizePathParam(txnId, \"txnId\");\n return this.client.get<Transaction>(`/api/v2/transaction/${txnId}`);\n }\n\n /**\n * List transactions with optional filters.\n *\n * @example\n * const completed = await neutron.transactions.list({ status: \"completed\", limit: 10 });\n */\n async list(params?: ListTransactionsParams): Promise<Transaction[]> {\n const qs = new URLSearchParams();\n if (params) {\n for (const [k, v] of Object.entries(params)) {\n if (v !== undefined && v !== null) qs.append(k, String(v));\n }\n }\n const query = qs.toString();\n const res = await this.client.get(`/api/v2/transaction${query ? `?${query}` : \"\"}`);\n return res.data ?? res;\n }\n\n /**\n * Cancel a quoted (unconfirmed) transaction.\n */\n async cancel(txnId: string): Promise<Transaction> {\n sanitizePathParam(txnId, \"txnId\");\n return this.client.put<Transaction>(`/api/v2/transaction/${txnId}/cancel`);\n }\n\n /**\n * Wait for a transaction to reach a final state. Polls at the given interval.\n *\n * @param txnId Transaction ID\n * @param options.intervalMs Polling interval in ms (default: 3000)\n * @param options.timeoutMs Max wait time in ms (default: 300000 = 5 min)\n * @param options.onStateChange Callback fired on each state change\n * @returns The transaction in a final state\n *\n * @example\n * const txn = await neutron.transactions.waitForCompletion(txnId, {\n * onStateChange: (state) => console.log(\"State:\", state),\n * });\n */\n async waitForCompletion(\n txnId: string,\n options?: {\n intervalMs?: number;\n timeoutMs?: number;\n onStateChange?: (state: string, txn: Transaction) => void;\n }\n ): Promise<Transaction> {\n const FINAL_STATES = [\"completed\", \"failed\", \"expired\", \"rejected\", \"error\", \"usercanceled\"];\n const interval = options?.intervalMs ?? 3000;\n const timeout = options?.timeoutMs ?? 300_000;\n const start = Date.now();\n let lastState = \"\";\n\n while (Date.now() - start < timeout) {\n const txn = await this.get(txnId);\n\n if (txn.txnState !== lastState) {\n lastState = txn.txnState;\n options?.onStateChange?.(txn.txnState, txn);\n }\n\n if (FINAL_STATES.includes(txn.txnState)) {\n return txn;\n }\n\n await new Promise((r) => setTimeout(r, interval));\n }\n\n throw new Error(`Transaction ${txnId} did not complete within ${timeout}ms`);\n }\n}\n","import type { HttpClient } from \"../client.js\";\nimport type {\n CreateInvoiceParams,\n LightningInvoice,\n Transaction,\n} from \"../types.js\";\nimport { NeutronValidationError } from \"../errors.js\";\n\nexport class LightningResource {\n constructor(private readonly client: HttpClient) {}\n\n /**\n * Create a Lightning invoice to receive Bitcoin. Auto-confirms — ready to pay immediately.\n *\n * @example\n * const invoice = await neutron.lightning.createInvoice({ amountSats: 10000 });\n * console.log(invoice.invoice); // \"lnbc100u1p...\"\n * console.log(invoice.qrPageUrl); // hosted QR code page\n *\n * @example\n * const invoice = await neutron.lightning.createInvoice({\n * amountBtc: 0.001,\n * memo: \"Order #1234\",\n * extRefId: \"order-1234\",\n * });\n */\n async createInvoice(params: CreateInvoiceParams): Promise<LightningInvoice> {\n let btcAmount: number;\n\n if (params.amountSats !== undefined && params.amountBtc !== undefined) {\n throw new NeutronValidationError(\"Provide either amountSats or amountBtc, not both.\");\n }\n if (params.amountSats !== undefined) {\n if (params.amountSats <= 0) throw new NeutronValidationError(\"amountSats must be positive.\");\n btcAmount = params.amountSats / 100_000_000;\n } else if (params.amountBtc !== undefined) {\n if (params.amountBtc <= 0) throw new NeutronValidationError(\"amountBtc must be positive.\");\n btcAmount = params.amountBtc;\n } else {\n throw new NeutronValidationError(\"Provide either amountSats or amountBtc.\");\n }\n\n // Create\n const txn = await this.client.post<Transaction>(`/api/v2/transaction`, {\n extRefId: params.extRefId,\n sourceReq: { ccy: \"BTC\", method: \"lightning\", reqDetails: {} },\n destReq: {\n ccy: \"BTC\",\n method: \"neutronpay\",\n amtRequested: btcAmount,\n reqDetails: {},\n },\n });\n\n // Auto-confirm\n const confirmed = await this.client.put<Transaction>(\n `/api/v2/transaction/${txn.txnId}/confirm`\n );\n\n return {\n txnId: confirmed.txnId,\n invoice: confirmed.sourceReq?.reqDetails?.paymentRequest ?? \"\",\n qrPageUrl: confirmed.sourceReq?.reqDetails?.invoicePageUrl,\n amountBtc: btcAmount,\n amountSats: Math.round(btcAmount * 100_000_000),\n status: confirmed.txnState,\n };\n }\n\n /**\n * Pay a Lightning invoice (BOLT11).\n * Returns a quoted transaction — call `neutron.transactions.confirm()` to send.\n *\n * @example\n * const txn = await neutron.lightning.payInvoice(\"lnbc100u1p...\");\n * // Review fees: txn.sourceReq.neutronpayFees\n * await neutron.transactions.confirm(txn.txnId);\n */\n async payInvoice(invoice: string, extRefId?: string): Promise<Transaction> {\n return this.client.post<Transaction>(`/api/v2/transaction`, {\n extRefId,\n sourceReq: { ccy: \"BTC\", method: \"neutronpay\" },\n destReq: {\n ccy: \"BTC\",\n method: \"lightning\",\n reqDetails: { paymentRequest: invoice },\n },\n });\n }\n\n /**\n * Send to a Lightning Address (user@domain.com).\n * Returns a quoted transaction — call `neutron.transactions.confirm()` to send.\n *\n * @example\n * const txn = await neutron.lightning.payAddress(\"alice@getalby.com\", { amountSats: 5000 });\n * await neutron.transactions.confirm(txn.txnId);\n */\n async payAddress(\n address: string,\n params: { amountSats?: number; amountBtc?: number; extRefId?: string }\n ): Promise<Transaction> {\n let btcAmount: number;\n if (params.amountSats !== undefined) {\n btcAmount = params.amountSats / 100_000_000;\n } else if (params.amountBtc !== undefined) {\n btcAmount = params.amountBtc;\n } else {\n throw new NeutronValidationError(\"Provide either amountSats or amountBtc.\");\n }\n\n return this.client.post<Transaction>(`/api/v2/transaction`, {\n extRefId: params.extRefId,\n sourceReq: { ccy: \"BTC\", method: \"neutronpay\", amtRequested: btcAmount },\n destReq: {\n ccy: \"BTC\",\n method: \"lnurl\",\n reqDetails: { lnurl: address },\n },\n });\n }\n\n}\n","import crypto from \"crypto\";\nimport type { HttpClient } from \"../client.js\";\nimport type { Webhook, CreateWebhookParams, UpdateWebhookParams } from \"../types.js\";\nimport { NeutronValidationError } from \"../errors.js\";\nimport { sanitizePathParam } from \"../sanitize.js\";\n\nexport class WebhooksResource {\n constructor(private readonly client: HttpClient) {}\n\n /**\n * Register a webhook to receive transaction state change notifications.\n *\n * @example\n * const webhook = await neutron.webhooks.create({\n * callback: \"https://myapp.com/webhooks/neutron\",\n * secret: \"my-webhook-secret\",\n * });\n */\n async create(params: CreateWebhookParams): Promise<Webhook> {\n return this.client.post<Webhook>(`/api/v2/webhook`, params);\n }\n\n /**\n * List all registered webhooks.\n */\n async list(): Promise<Webhook[]> {\n const res = await this.client.get(`/api/v2/webhook`);\n return res.data ?? res;\n }\n\n /**\n * Update a webhook's callback URL or secret.\n */\n async update(webhookId: string, params: UpdateWebhookParams): Promise<Webhook> {\n sanitizePathParam(webhookId, \"webhookId\");\n return this.client.put<Webhook>(`/api/v2/webhook/${webhookId}`, params);\n }\n\n /**\n * Delete a webhook.\n */\n async delete(webhookId: string): Promise<void> {\n sanitizePathParam(webhookId, \"webhookId\");\n await this.client.del(`/api/v2/webhook/${webhookId}`);\n }\n\n /**\n * Verify a webhook signature from an incoming request.\n * Throws if the signature is invalid.\n *\n * @param body The raw request body (string or Buffer)\n * @param signature The `X-Neutronpay-Signature` header value\n * @param secret Your webhook secret\n * @returns The parsed event payload\n *\n * @example\n * // Express\n * app.post(\"/webhooks/neutron\", express.raw({ type: \"application/json\" }), (req, res) => {\n * try {\n * const event = Neutron.webhooks.verifySignature(\n * req.body,\n * req.headers[\"x-neutronpay-signature\"],\n * \"my-webhook-secret\"\n * );\n * // event is verified and safe to use\n * if (event.txnState === \"completed\") fulfillOrder(event.extRefId);\n * } catch (err) {\n * return res.status(401).send(\"Invalid signature\");\n * }\n * res.status(200).send(\"OK\");\n * });\n */\n static verifySignature(\n body: string | Buffer,\n signature: string | undefined | null,\n secret: string\n ): any {\n if (!signature) {\n throw new NeutronValidationError(\"Missing webhook signature header (X-Neutronpay-Signature)\");\n }\n if (!secret) {\n throw new NeutronValidationError(\"Webhook secret is required for verification\");\n }\n\n const bodyStr = typeof body === \"string\" ? body : body.toString(\"utf8\");\n\n const expected = crypto\n .createHmac(\"sha256\", secret)\n .update(bodyStr)\n .digest(\"hex\");\n\n const sigBuf = Buffer.from(signature);\n const expBuf = Buffer.from(expected);\n const isValid = sigBuf.length === expBuf.length && crypto.timingSafeEqual(sigBuf, expBuf);\n\n if (!isValid) {\n throw new NeutronValidationError(\"Invalid webhook signature\");\n }\n\n return JSON.parse(bodyStr);\n }\n}\n","import type { HttpClient } from \"../client.js\";\nimport type { ExchangeRates } from \"../types.js\";\n\nexport class RatesResource {\n constructor(private readonly client: HttpClient) {}\n\n /**\n * Get current BTC exchange rates against all supported currencies.\n *\n * @example\n * const rates = await neutron.rates.get();\n * console.log(rates); // { BTCUSD: 97500, BTCVND: 2437500000, ... }\n */\n async get(): Promise<ExchangeRates> {\n const res = await this.client.get(`/api/v2/rate`);\n return res.data ?? res;\n }\n}\n","import type { HttpClient } from \"../client.js\";\nimport type { FiatInstitution, Transaction, SourceOfFunds } from \"../types.js\";\nimport { sanitizePathParam } from \"../sanitize.js\";\n\nexport interface FiatPayoutParams {\n /** Source currency (e.g. \"BTC\") */\n sourceCcy: string;\n /** Amount from source (in BTC for Bitcoin) */\n sourceAmount: number;\n /** Destination fiat currency (e.g. \"VND\") */\n destCcy: string;\n /** Payment method (e.g. \"vnd-instant\") */\n destMethod: string;\n /** Bank account number */\n bankAcctNum: string;\n /** Bank code from `neutron.fiat.institutions()` */\n institutionCode: string;\n /** Recipient legal full name */\n recipientName: string;\n /** Recipient country code (e.g. \"VN\") */\n countryCode: string;\n /** \"individual\" or \"business\" (default: \"individual\") */\n kycType?: \"individual\" | \"business\";\n /** Source of funds declaration */\n sourceOfFunds?: SourceOfFunds;\n /** Your reference ID */\n extRefId?: string;\n}\n\nexport class FiatResource {\n constructor(private readonly client: HttpClient) {}\n\n /**\n * List banks and financial institutions for a country.\n * Returns institution codes needed for fiat payouts.\n *\n * @example\n * const banks = await neutron.fiat.institutions(\"VN\");\n * // [{ code: \"970422\", name: \"MB Bank\" }, ...]\n */\n async institutions(countryCode: string): Promise<FiatInstitution[]> {\n sanitizePathParam(countryCode, \"countryCode\");\n const res = await this.client.get(\n `/api/v2/reference/fiat-institution/by-country/${countryCode}`\n );\n return res.data ?? res;\n }\n\n /**\n * Create a fiat payout transaction. Handles KYC and source of funds automatically.\n * Returns a quoted transaction — call `neutron.transactions.confirm()` to execute.\n *\n * @example\n * const txn = await neutron.fiat.payout({\n * sourceCcy: \"BTC\",\n * sourceAmount: 0.001,\n * destCcy: \"VND\",\n * destMethod: \"vnd-instant\",\n * bankAcctNum: \"0123456789\",\n * institutionCode: \"970422\",\n * recipientName: \"LE VAN A\",\n * countryCode: \"VN\",\n * });\n * // Review rate: txn.fxRate\n * await neutron.transactions.confirm(txn.txnId);\n */\n async payout(params: FiatPayoutParams): Promise<Transaction> {\n return this.client.post<Transaction>(`/api/v2/transaction`, {\n extRefId: params.extRefId,\n sourceReq: {\n ccy: params.sourceCcy,\n method: \"neutronpay\",\n amtRequested: params.sourceAmount,\n reqDetails: {},\n },\n destReq: {\n ccy: params.destCcy,\n method: params.destMethod,\n reqDetails: {\n bankAcctNum: params.bankAcctNum,\n institutionCode: params.institutionCode,\n },\n kyc: {\n type: params.kycType || \"individual\",\n details: {\n legalFullName: params.recipientName,\n countryCode: params.countryCode,\n },\n },\n },\n sourceOfFunds: params.sourceOfFunds ?? {\n purpose: 1,\n source: 5,\n relationship: 3,\n },\n });\n }\n}\n","// ── Satoshi / BTC conversion ────────────────────────────────\n\nconst SATS_PER_BTC = 100_000_000;\n\n/**\n * Convert satoshis to BTC.\n * @example satsToBtc(10000) // 0.0001\n */\nexport function satsToBtc(sats: number): number {\n return sats / SATS_PER_BTC;\n}\n\n/**\n * Convert BTC to satoshis.\n * @example btcToSats(0.0001) // 10000\n */\nexport function btcToSats(btc: number): number {\n return Math.round(btc * SATS_PER_BTC);\n}\n\n/**\n * Format a satoshi amount as a human-readable string.\n * @example formatSats(1500000) // \"1,500,000 sats\"\n * @example formatSats(100) // \"100 sats\"\n */\nexport function formatSats(sats: number): string {\n return `${sats.toLocaleString(\"en-US\")} sats`;\n}\n\n/**\n * Format a BTC amount with appropriate precision.\n * @example formatBtc(0.00015) // \"0.00015000 BTC\"\n */\nexport function formatBtc(btc: number): string {\n return `${btc.toFixed(8)} BTC`;\n}\n\n// ── Constants ───────────────────────────────────────────────\n\n/** Supported currencies */\nexport const Currency = {\n BTC: \"BTC\",\n USDT: \"USDT\",\n VND: \"VND\",\n USD: \"USD\",\n CAD: \"CAD\",\n NGN: \"NGN\",\n KES: \"KES\",\n GHS: \"GHS\",\n} as const;\n\nexport type Currency = (typeof Currency)[keyof typeof Currency];\n\n/** Payment methods for sourceReq/destReq */\nexport const PaymentMethod = {\n /** Internal Neutron wallet */\n NEUTRON: \"neutronpay\",\n /** Lightning Network (BOLT11 invoices) */\n LIGHTNING: \"lightning\",\n /** Lightning Address / LNURL */\n LNURL: \"lnurl\",\n /** Bitcoin on-chain */\n ON_CHAIN: \"on-chain\",\n /** USDT on TRON (TRC-20) */\n TRON: \"tron\",\n /** USDT on Ethereum (ERC-20) */\n ETH: \"eth\",\n /** Vietnamese Dong instant bank transfer */\n VND_INSTANT: \"vnd-instant\",\n} as const;\n\nexport type PaymentMethodType = (typeof PaymentMethod)[keyof typeof PaymentMethod];\n\n/** Transaction final states (terminal — won't change) */\nexport const FinalStates = [\n \"completed\",\n \"expired\",\n \"rejected\",\n \"error\",\n \"usercanceled\",\n] as const;\n\n/** All transaction states */\nexport const TransactionStates = {\n QUOTED: \"quoted\",\n USER_CONFIRMED: \"userconfirmed\",\n SRC_CREATED: \"srccreated\",\n SRC_SENT: \"srcsent\",\n SRC_INTENT: \"srcintent\",\n SRC_PEND_CONFIRM: \"srcpendconfirmfill\",\n SRC_CONFIRMED: \"srcconfirmfilled\",\n DEST_PEND_SENT: \"destpendsent\",\n DEST_SENT: \"destsent\",\n COMPLETED: \"completed\",\n EXPIRED: \"expired\",\n REJECTED: \"rejected\",\n ERROR: \"error\",\n USER_CANCELED: \"usercanceled\",\n} as const;\n\n/** USDT blockchain options */\nexport const Chain = {\n TRON: \"TRON\",\n ETH: \"ETH\",\n} as const;\n"],"mappings":"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","names":["crypto","import_crypto","crypto"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/client.ts","../src/errors.ts","../src/sanitize.ts","../src/resources/account.ts","../src/resources/transactions.ts","../src/resources/lightning.ts","../src/resources/webhooks.ts","../src/resources/rates.ts","../src/resources/fiat.ts","../src/utils.ts"],"sourcesContent":["import { HttpClient } from \"./client.js\";\nimport { AccountResource } from \"./resources/account.js\";\nimport { TransactionsResource } from \"./resources/transactions.js\";\nimport { LightningResource } from \"./resources/lightning.js\";\nimport { WebhooksResource } from \"./resources/webhooks.js\";\nimport { RatesResource } from \"./resources/rates.js\";\nimport { FiatResource } from \"./resources/fiat.js\";\nimport type { NeutronConfig } from \"./types.js\";\n\n/**\n * Neutron SDK — Bitcoin Lightning, stablecoins, and fiat payments.\n *\n * @example\n * import { Neutron } from \"neutron-sdk\";\n *\n * const neutron = new Neutron({\n * apiKey: process.env.NEUTRON_API_KEY!,\n * apiSecret: process.env.NEUTRON_API_SECRET!,\n * });\n *\n * // Check balances\n * const wallets = await neutron.account.wallets();\n *\n * // Create a Lightning invoice\n * const invoice = await neutron.lightning.createInvoice({ amountSats: 10000 });\n *\n * // Send to a Lightning Address\n * const txn = await neutron.lightning.payAddress(\"alice@getalby.com\", { amountSats: 5000 });\n * await neutron.transactions.confirm(txn.txnId);\n */\nexport class Neutron {\n /** Account info, wallets, and deposit addresses */\n readonly account: AccountResource;\n /** Create, confirm, list, and track transactions */\n readonly transactions: TransactionsResource;\n /** Lightning invoices, payments, and utilities */\n readonly lightning: LightningResource;\n /** Webhook management */\n readonly webhooks: WebhooksResource;\n /** BTC exchange rates */\n readonly rates: RatesResource;\n /** Fiat payouts and bank lookups */\n readonly fiat: FiatResource;\n\n private readonly client: HttpClient;\n\n constructor(config: NeutronConfig) {\n this.client = new HttpClient(config);\n this.account = new AccountResource(this.client);\n this.transactions = new TransactionsResource(this.client);\n this.lightning = new LightningResource(this.client);\n this.webhooks = new WebhooksResource(this.client);\n this.rates = new RatesResource(this.client);\n this.fiat = new FiatResource(this.client);\n }\n\n /**\n * Explicitly authenticate and verify credentials.\n * Usually not needed — the SDK auto-authenticates on first request.\n */\n async authenticate() {\n return this.client.authenticate();\n }\n\n /**\n * Verify a webhook signature. Static method — no client instance needed.\n *\n * @example\n * const event = Neutron.verifyWebhook(req.body, req.headers[\"x-neutronpay-signature\"], secret);\n */\n static verifyWebhook(body: string | Buffer, signature: string | undefined | null, secret: string) {\n return WebhooksResource.verifySignature(body, signature, secret);\n }\n}\n\n// ── Exports ─────────────────────────────────────────────────\n\nexport { HttpClient } from \"./client.js\";\nexport { AccountResource } from \"./resources/account.js\";\nexport { TransactionsResource } from \"./resources/transactions.js\";\nexport { LightningResource } from \"./resources/lightning.js\";\nexport { WebhooksResource } from \"./resources/webhooks.js\";\nexport { RatesResource } from \"./resources/rates.js\";\nexport { FiatResource } from \"./resources/fiat.js\";\nexport type { FiatPayoutParams } from \"./resources/fiat.js\";\n\nexport { sanitizePathParam } from \"./sanitize.js\";\n\nexport {\n NeutronError,\n NeutronApiError,\n NeutronAuthError,\n NeutronTimeoutError,\n NeutronValidationError,\n} from \"./errors.js\";\n\nexport {\n satsToBtc,\n btcToSats,\n formatSats,\n formatBtc,\n Currency,\n PaymentMethod,\n TransactionStates,\n FinalStates,\n Chain,\n} from \"./utils.js\";\n\nexport type {\n Currency as CurrencyType,\n PaymentMethodType,\n} from \"./utils.js\";\n\nexport type {\n NeutronConfig,\n AuthResponse,\n Account,\n Wallet,\n Transaction,\n TransactionState,\n TransactionSide,\n PaymentMethod as PaymentMethodString,\n CreateTransactionRequest,\n ListTransactionsParams,\n TransactionEvent,\n CreateInvoiceParams,\n LightningInvoice,\n DecodedInvoice,\n BtcAddress,\n UsdtAddress,\n Webhook,\n CreateWebhookParams,\n UpdateWebhookParams,\n ExchangeRates,\n FiatInstitution,\n KycInfo,\n SourceOfFunds,\n ApiResponse,\n} from \"./types.js\";\n","import crypto from \"crypto\";\nimport type { NeutronConfig, AuthResponse } from \"./types.js\";\nimport {\n NeutronApiError,\n NeutronAuthError,\n NeutronTimeoutError,\n} from \"./errors.js\";\n\nconst DEFAULT_BASE_URL = \"https://api.neutron.me\";\nconst DEFAULT_TIMEOUT = 30_000;\nconst DEFAULT_MAX_RETRIES = 2;\nconst TOKEN_REFRESH_BUFFER_MS = 60_000; // refresh 1 min before expiry\n\nexport class HttpClient {\n private readonly apiKey: string;\n private readonly apiSecret: string;\n readonly baseUrl: string;\n private readonly timeout: number;\n private readonly maxRetries: number;\n private readonly debug: boolean;\n\n private accessToken: string | null = null;\n private accountId: string | null = null;\n private tokenExpiry: number = 0;\n\n constructor(config: NeutronConfig) {\n if (!config.apiKey) throw new NeutronAuthError(\"apiKey is required\");\n if (!config.apiSecret) throw new NeutronAuthError(\"apiSecret is required\");\n\n this.apiKey = config.apiKey;\n this.apiSecret = config.apiSecret;\n this.baseUrl = (config.baseUrl || DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this.timeout = config.timeout ?? DEFAULT_TIMEOUT;\n this.maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES;\n this.debug = config.debug ?? false;\n }\n\n private log(message: string, data?: any): void {\n if (!this.debug) return;\n const ts = new Date().toISOString();\n const extra = data ? ` ${JSON.stringify(data)}` : \"\";\n console.error(`[neutron-sdk ${ts}] ${message}${extra}`);\n }\n\n // ── Auth ──────────────────────────────────────────────\n\n private generateSignature(payload: string): string {\n const stringToSign = `${this.apiKey}&payload=${payload}`;\n return crypto\n .createHmac(\"sha256\", this.apiSecret)\n .update(stringToSign)\n .digest(\"hex\");\n }\n\n private get isTokenValid(): boolean {\n return !!(\n this.accessToken &&\n this.accountId &&\n Date.now() < this.tokenExpiry - TOKEN_REFRESH_BUFFER_MS\n );\n }\n\n async authenticate(): Promise<AuthResponse> {\n const payload = JSON.stringify({ test: \"auth\" });\n const signature = this.generateSignature(payload);\n\n const response = await this.rawFetch(\n `${this.baseUrl}/api/v2/authentication/token-signature`,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Api-Key\": this.apiKey,\n \"X-Api-Signature\": signature,\n },\n body: payload,\n }\n );\n\n if (!response.ok) {\n const body = (await response.json().catch(() => ({}))) as Record<string, any>;\n throw new NeutronAuthError(\n body.error || body.message || `Authentication failed (${response.status})`\n );\n }\n\n const raw = (await response.json()) as any;\n // API wraps auth response in { data: { ... } }\n const result: AuthResponse = raw.data ?? raw;\n this.accountId = result.accountId;\n this.accessToken = result.accessToken;\n this.tokenExpiry = typeof result.expiredAt === \"number\"\n ? result.expiredAt\n : new Date(result.expiredAt).getTime();\n\n return result;\n this.log(\"Authenticated\", { accountId: this.accountId });\n }\n\n private async ensureAuth(): Promise<void> {\n if (!this.isTokenValid) {\n await this.authenticate();\n }\n }\n\n getAccountId(): string {\n if (!this.accountId) {\n throw new NeutronAuthError(\"Not authenticated. Call a method first or use neutron.account.get().\");\n }\n return this.accountId;\n }\n\n async ensureAuthAndGetAccountId(): Promise<string> {\n await this.ensureAuth();\n return this.accountId!;\n }\n\n /**\n * Returns auth headers for use in raw fetch calls (e.g. SSE streams).\n * Ensures a valid token is present before returning.\n */\n async getAuthHeaders(): Promise<Record<string, string>> {\n await this.ensureAuth();\n return {\n Authorization: `Bearer ${this.accessToken}`,\n };\n }\n\n // ── HTTP ──────────────────────────────────────────────\n\n private async rawFetch(url: string, init: RequestInit): Promise<Response> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n return await fetch(url, { ...init, signal: controller.signal });\n } catch (err: any) {\n if (err.name === \"AbortError\") {\n throw new NeutronTimeoutError(this.timeout);\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n }\n\n async request<T = any>(method: string, path: string, body?: any): Promise<T> {\n await this.ensureAuth();\n\n let lastError: any;\n\n for (let attempt = 0; attempt <= this.maxRetries; attempt++) {\n if (attempt > 0) {\n // Exponential backoff: 1s, 2s, 4s...\n await new Promise((r) => setTimeout(r, Math.pow(2, attempt - 1) * 1000));\n\n // Re-auth if token might have expired during retries\n if (!this.isTokenValid) await this.authenticate();\n }\n\n const url = `${this.baseUrl}${path}`;\n this.log(`${method} ${path}`);\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.accessToken}`,\n \"Content-Type\": \"application/json\",\n };\n\n const response = await this.rawFetch(url, {\n method,\n headers,\n body: body ? JSON.stringify(body) : undefined,\n });\n\n if (response.ok) {\n return (await response.json()) as T;\n }\n\n const errorBody = await response.json().catch(() => ({}));\n const apiError = new NeutronApiError(response.status, errorBody);\n\n // Re-authenticate on 401 and retry\n if (response.status === 401 && attempt < this.maxRetries) {\n this.accessToken = null;\n lastError = apiError;\n continue;\n }\n\n // Retry on 5xx and 429\n if (apiError.isRetryable && attempt < this.maxRetries) {\n lastError = apiError;\n continue;\n }\n\n throw apiError;\n }\n\n throw lastError;\n }\n\n async get<T = any>(path: string): Promise<T> {\n return this.request<T>(\"GET\", path);\n }\n\n async post<T = any>(path: string, body?: any): Promise<T> {\n return this.request<T>(\"POST\", path, body);\n }\n\n async put<T = any>(path: string, body?: any): Promise<T> {\n return this.request<T>(\"PUT\", path, body);\n }\n\n async del<T = any>(path: string): Promise<T> {\n return this.request<T>(\"DELETE\", path);\n }\n}\n","/**\n * Base error for all Neutron SDK errors.\n */\nexport class NeutronError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"NeutronError\";\n }\n}\n\n/**\n * Thrown when the API returns an error response (4xx/5xx).\n */\nexport class NeutronApiError extends NeutronError {\n /** HTTP status code */\n readonly status: number;\n /** Neutron error code (e.g. \"2005\") */\n readonly code: string | undefined;\n /** Raw error body from the API */\n readonly body: any;\n\n constructor(status: number, body: any) {\n const message = body?.error || body?.message || `API error ${status}`;\n super(message);\n this.name = \"NeutronApiError\";\n this.status = status;\n this.code = body?.code;\n this.body = body;\n }\n\n /** True if this is a rate limit error (429) */\n get isRateLimited(): boolean {\n return this.status === 429;\n }\n\n /** True if this is an auth error (401/403) */\n get isAuthError(): boolean {\n return this.status === 401 || this.status === 403;\n }\n\n /** True if retrying might help (5xx, 429) */\n get isRetryable(): boolean {\n return this.status === 429 || this.status >= 500;\n }\n}\n\n/**\n * Thrown when authentication fails.\n */\nexport class NeutronAuthError extends NeutronError {\n constructor(message: string = \"Authentication failed. Check your API key and secret.\") {\n super(message);\n this.name = \"NeutronAuthError\";\n }\n}\n\n/**\n * Thrown when a request times out.\n */\nexport class NeutronTimeoutError extends NeutronError {\n constructor(timeoutMs: number) {\n super(`Request timed out after ${timeoutMs}ms`);\n this.name = \"NeutronTimeoutError\";\n }\n}\n\n/**\n * Thrown for SDK usage errors (bad params, missing fields).\n */\nexport class NeutronValidationError extends NeutronError {\n constructor(message: string) {\n super(message);\n this.name = \"NeutronValidationError\";\n }\n}\n","import { NeutronValidationError } from \"./errors.js\";\n\n/**\n * Sanitize a path parameter to prevent path traversal and injection.\n * Only allows alphanumeric characters, hyphens, underscores, and dots.\n */\nexport function sanitizePathParam(value: string, name: string): string {\n if (!value || typeof value !== \"string\") {\n throw new NeutronValidationError(`${name} is required and must be a non-empty string.`);\n }\n\n // Strip any path traversal or special characters\n const sanitized = value.replace(/[^a-zA-Z0-9\\-_.]/g, \"\");\n\n if (sanitized !== value) {\n throw new NeutronValidationError(\n `${name} contains invalid characters. Only alphanumeric, hyphens, underscores, and dots are allowed.`\n );\n }\n\n if (sanitized.includes(\"..\")) {\n throw new NeutronValidationError(`${name} cannot contain path traversal sequences.`);\n }\n\n return sanitized;\n}\n","import type { HttpClient } from \"../client.js\";\nimport type { Account, Wallet } from \"../types.js\";\nimport { sanitizePathParam } from \"../sanitize.js\";\n\nexport class AccountResource {\n constructor(private readonly client: HttpClient) {}\n\n /**\n * Get account info: display name, status, country, timezone.\n */\n async get(): Promise<Account> {\n const accountId = await this.client.ensureAuthAndGetAccountId();\n const res = await this.client.get(`/api/v2/account/${accountId}`);\n return (res.data ?? res) as Account;\n }\n\n /**\n * List all wallets with balances (BTC, USDT, fiat).\n */\n async wallets(): Promise<Wallet[]> {\n const accountId = await this.client.ensureAuthAndGetAccountId();\n const res = await this.client.get(`/api/v2/account/${accountId}/wallet/`);\n return res.data ?? res;\n }\n\n /**\n * Get a specific wallet by ID.\n */\n async wallet(walletId: string): Promise<Wallet> {\n sanitizePathParam(walletId, \"walletId\");\n const accountId = await this.client.ensureAuthAndGetAccountId();\n const res = await this.client.get(`/api/v2/account/${accountId}/wallet/${walletId}`);\n return (res.data ?? res) as Wallet;\n }\n\n /**\n * Get your Bitcoin on-chain deposit address (static, reusable).\n */\n async btcAddress(): Promise<{ address: string }> {\n const raw = await this.client.get(`/api/v2/account/onchain-address`);\n const data = raw?.data ?? raw;\n return { address: data.staticOnchainAddress };\n }\n\n /**\n * Get your USDT deposit address.\n * @param chain \"TRON\" (default, recommended) or \"ETH\"\n */\n async usdtAddress(chain: \"TRON\" | \"ETH\" = \"TRON\"): Promise<{ address: string; chain: string }> {\n const raw = await this.client.get(\n `/api/v2/account/stablecoin-onchain-address?walletCcy=USDT&chainId=${chain}`\n );\n const data = raw?.data ?? raw;\n return {\n address: data.staticStablecoinOnchainAddress || data.staticOnchainAddress,\n chain,\n };\n }\n}\n","import type { HttpClient } from \"../client.js\";\nimport type {\n Transaction,\n CreateTransactionRequest,\n ListTransactionsParams,\n TransactionEvent,\n} from \"../types.js\";\nimport { sanitizePathParam } from \"../sanitize.js\";\n\nexport class TransactionsResource {\n constructor(private readonly client: HttpClient) {}\n\n /**\n * Create a transaction (returns a quote). Call `.confirm()` to execute.\n *\n * @example\n * // Lightning receive (create invoice)\n * const txn = await neutron.transactions.create({\n * sourceReq: { ccy: \"BTC\", method: \"lightning\", reqDetails: {} },\n * destReq: { ccy: \"BTC\", method: \"neutronpay\", amtRequested: 0.0001, reqDetails: {} },\n * });\n *\n * @example\n * // Lightning send (pay invoice)\n * const txn = await neutron.transactions.create({\n * sourceReq: { ccy: \"BTC\", method: \"neutronpay\" },\n * destReq: { ccy: \"BTC\", method: \"lightning\", reqDetails: { paymentRequest: \"lnbc...\" } },\n * });\n *\n * @example\n * // Internal swap (BTC → USDT)\n * const txn = await neutron.transactions.create({\n * sourceReq: { ccy: \"BTC\", method: \"neutronpay\", amtRequested: 0.001, reqDetails: {} },\n * destReq: { ccy: \"USDT\", method: \"neutronpay\", reqDetails: {} },\n * });\n */\n async create(params: CreateTransactionRequest): Promise<Transaction> {\n return this.client.post<Transaction>(`/api/v2/transaction`, params);\n }\n\n /**\n * Confirm a quoted transaction to execute it.\n * After confirmation, Lightning invoices become payable and sends are dispatched.\n */\n async confirm(txnId: string): Promise<Transaction> {\n sanitizePathParam(txnId, \"txnId\");\n return this.client.put<Transaction>(`/api/v2/transaction/${txnId}/confirm`);\n }\n\n /**\n * Get transaction status and details.\n */\n async get(txnId: string): Promise<Transaction> {\n sanitizePathParam(txnId, \"txnId\");\n return this.client.get<Transaction>(`/api/v2/transaction/${txnId}`);\n }\n\n /**\n * List transactions with optional filters.\n *\n * @example\n * const completed = await neutron.transactions.list({ status: \"completed\", limit: 10 });\n */\n async list(params?: ListTransactionsParams): Promise<Transaction[]> {\n const qs = new URLSearchParams();\n if (params) {\n for (const [k, v] of Object.entries(params)) {\n if (v !== undefined && v !== null) qs.append(k, String(v));\n }\n }\n const query = qs.toString();\n const res = await this.client.get(`/api/v2/transaction${query ? `?${query}` : \"\"}`);\n return res.data ?? res;\n }\n\n /**\n * Cancel a quoted (unconfirmed) transaction.\n *\n * @deprecated This endpoint is not currently available on the Neutron API.\n * Unconfirmed transactions expire automatically after their TTL.\n */\n async cancel(_txnId: string): Promise<Transaction> {\n throw new Error(\n \"transactions.cancel() is not available. Unconfirmed transactions expire automatically.\"\n );\n }\n\n /**\n * Wait for a transaction to reach a final state. Polls at the given interval.\n *\n * @param txnId Transaction ID\n * @param options.intervalMs Polling interval in ms (default: 3000)\n * @param options.timeoutMs Max wait time in ms (default: 300000 = 5 min)\n * @param options.onStateChange Callback fired on each state change\n * @returns The transaction in a final state\n *\n * @example\n * const txn = await neutron.transactions.waitForCompletion(txnId, {\n * onStateChange: (state) => console.log(\"State:\", state),\n * });\n */\n async waitForCompletion(\n txnId: string,\n options?: {\n intervalMs?: number;\n timeoutMs?: number;\n onStateChange?: (state: string, txn: Transaction) => void;\n }\n ): Promise<Transaction> {\n const FINAL_STATES = [\"completed\", \"failed\", \"expired\", \"rejected\", \"error\", \"usercanceled\"];\n const interval = options?.intervalMs ?? 3000;\n const timeout = options?.timeoutMs ?? 300_000;\n const start = Date.now();\n let lastState = \"\";\n\n while (Date.now() - start < timeout) {\n const txn = await this.get(txnId);\n\n if (txn.txnState !== lastState) {\n lastState = txn.txnState;\n options?.onStateChange?.(txn.txnState, txn);\n }\n\n if (FINAL_STATES.includes(txn.txnState)) {\n return txn;\n }\n\n await new Promise((r) => setTimeout(r, interval));\n }\n\n throw new Error(`Transaction ${txnId} did not complete within ${timeout}ms`);\n }\n\n /**\n * Stream real-time transaction status updates via SSE.\n * For agents without a public endpoint who can't receive webhook POSTs.\n *\n * NOTE: Requires the server-side endpoint /api/v2/events/stream (not yet live).\n * Use neutron.transactions.waitForCompletion() as a polling fallback in the meantime.\n *\n * @example\n * for await (const event of neutron.transactions.subscribe(\"txn-123\")) {\n * console.log(event.status);\n * if (event.status === \"completed\") break;\n * }\n */\n async *subscribe(transactionId: string, timeoutMs = 60_000): AsyncGenerator<TransactionEvent> {\n // SECURITY: sanitize input — consistent with all other resource methods\n sanitizePathParam(transactionId, \"transactionId\");\n\n // SECURITY: validate transactionId is a UUID to prevent SSRF/path traversal\n const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n if (!UUID_RE.test(transactionId)) {\n throw new Error(\"Invalid transactionId: must be a UUID.\");\n }\n\n // SECURITY: clamp timeout to 5s–300s to prevent resource exhaustion\n const clampedTimeout = Math.min(Math.max(timeoutMs, 5_000), 300_000);\n\n // SECURITY: encodeURIComponent — UUID chars are safe but be explicit\n const url = `${this.client.baseUrl}/api/v2/events/stream?transactionId=${encodeURIComponent(transactionId)}`;\n const response = await fetch(url, {\n headers: {\n \"Accept\": \"text/event-stream\",\n ...(await this.client.getAuthHeaders()),\n },\n signal: AbortSignal.timeout(clampedTimeout),\n });\n\n if (!response.ok || !response.body) {\n throw new Error(`SSE connection failed: ${response.status} ${response.statusText}`);\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n const MAX_BUFFER = 64 * 1024; // 64KB — prevent OOM from malformed stream\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n\n // SECURITY: abort on unbounded buffer growth\n if (buffer.length > MAX_BUFFER) {\n throw new Error(\"SSE buffer overflow — server sent malformed stream.\");\n }\n\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() || \"\";\n for (const line of lines) {\n if (line.startsWith(\"data: \")) {\n try {\n yield JSON.parse(line.slice(6)) as TransactionEvent;\n } catch (parseErr) {\n // Log malformed SSE data but keep the stream alive\n console.error(\"[neutron-sdk] SSE parse error:\", parseErr);\n }\n }\n }\n }\n } finally {\n reader.cancel();\n }\n }\n}\n","import type { HttpClient } from \"../client.js\";\nimport type {\n CreateInvoiceParams,\n DecodedInvoice,\n LightningInvoice,\n Transaction,\n} from \"../types.js\";\nimport { NeutronValidationError } from \"../errors.js\";\n\nexport class LightningResource {\n constructor(private readonly client: HttpClient) {}\n\n /**\n * Create a Lightning invoice to receive Bitcoin. Auto-confirms — ready to pay immediately.\n *\n * @example\n * const invoice = await neutron.lightning.createInvoice({ amountSats: 10000 });\n * console.log(invoice.invoice); // \"lnbc100u1p...\"\n * console.log(invoice.qrPageUrl); // hosted QR code page\n *\n * @example\n * const invoice = await neutron.lightning.createInvoice({\n * amountBtc: 0.001,\n * memo: \"Order #1234\",\n * extRefId: \"order-1234\",\n * });\n */\n async createInvoice(params: CreateInvoiceParams): Promise<LightningInvoice> {\n let btcAmount: number;\n\n if (params.amountSats !== undefined && params.amountBtc !== undefined) {\n throw new NeutronValidationError(\"Provide either amountSats or amountBtc, not both.\");\n }\n if (params.amountSats !== undefined) {\n if (params.amountSats <= 0) throw new NeutronValidationError(\"amountSats must be positive.\");\n btcAmount = params.amountSats / 100_000_000;\n } else if (params.amountBtc !== undefined) {\n if (params.amountBtc <= 0) throw new NeutronValidationError(\"amountBtc must be positive.\");\n btcAmount = params.amountBtc;\n } else {\n throw new NeutronValidationError(\"Provide either amountSats or amountBtc.\");\n }\n\n // Create\n const txn = await this.client.post<Transaction>(`/api/v2/transaction`, {\n extRefId: params.extRefId,\n sourceReq: { ccy: \"BTC\", method: \"lightning\", reqDetails: {} },\n destReq: {\n ccy: \"BTC\",\n method: \"neutronpay\",\n amtRequested: btcAmount,\n reqDetails: {},\n },\n });\n\n // Auto-confirm\n const confirmed = await this.client.put<Transaction>(\n `/api/v2/transaction/${txn.txnId}/confirm`\n );\n\n return {\n txnId: confirmed.txnId,\n invoice: confirmed.sourceReq?.reqDetails?.paymentRequest ?? \"\",\n qrPageUrl: confirmed.sourceReq?.reqDetails?.invoicePageUrl,\n amountBtc: btcAmount,\n amountSats: Math.round(btcAmount * 100_000_000),\n status: confirmed.txnState,\n };\n }\n\n /**\n * Pay a Lightning invoice (BOLT11).\n * Returns a quoted transaction — call `neutron.transactions.confirm()` to send.\n *\n * @example\n * const txn = await neutron.lightning.payInvoice(\"lnbc100u1p...\");\n * // Review fees: txn.sourceReq.neutronpayFees\n * await neutron.transactions.confirm(txn.txnId);\n */\n async payInvoice(invoice: string, extRefId?: string): Promise<Transaction> {\n return this.client.post<Transaction>(`/api/v2/transaction`, {\n extRefId,\n sourceReq: { ccy: \"BTC\", method: \"neutronpay\" },\n destReq: {\n ccy: \"BTC\",\n method: \"lightning\",\n reqDetails: { paymentRequest: invoice },\n },\n });\n }\n\n /**\n * Send to a Lightning Address (user@domain.com).\n * Returns a quoted transaction — call `neutron.transactions.confirm()` to send.\n *\n * @example\n * const txn = await neutron.lightning.payAddress(\"alice@getalby.com\", { amountSats: 5000 });\n * await neutron.transactions.confirm(txn.txnId);\n */\n async payAddress(\n address: string,\n params: { amountSats?: number; amountBtc?: number; extRefId?: string }\n ): Promise<Transaction> {\n let btcAmount: number;\n if (params.amountSats !== undefined) {\n btcAmount = params.amountSats / 100_000_000;\n } else if (params.amountBtc !== undefined) {\n btcAmount = params.amountBtc;\n } else {\n throw new NeutronValidationError(\"Provide either amountSats or amountBtc.\");\n }\n\n return this.client.post<Transaction>(`/api/v2/transaction`, {\n extRefId: params.extRefId,\n sourceReq: { ccy: \"BTC\", method: \"neutronpay\", amtRequested: btcAmount },\n destReq: {\n ccy: \"BTC\",\n method: \"lnurl\",\n reqDetails: { address },\n },\n });\n }\n\n /**\n * Decode a Lightning invoice (BOLT11) to inspect amount, description, etc.\n * Useful for showing users what they're about to pay before confirming.\n *\n * @example\n * const decoded = await neutron.lightning.decodeInvoice(\"lnbc100u1p...\");\n * console.log(decoded.amount); // 0.001 (BTC)\n * console.log(decoded.description); // \"Coffee payment\"\n */\n async decodeInvoice(invoice: string): Promise<DecodedInvoice> {\n const result = await this.client.post<{ invoice: DecodedInvoice }>(\n `/api/v2/decode/lightning`,\n { paymentRequest: invoice }\n );\n return result.invoice;\n }\n\n}\n","import crypto from \"crypto\";\nimport type { HttpClient } from \"../client.js\";\nimport type { Webhook, CreateWebhookParams, UpdateWebhookParams } from \"../types.js\";\nimport { NeutronValidationError } from \"../errors.js\";\nimport { sanitizePathParam } from \"../sanitize.js\";\n\nexport class WebhooksResource {\n constructor(private readonly client: HttpClient) {}\n\n /**\n * Register a webhook to receive transaction state change notifications.\n *\n * @example\n * const webhook = await neutron.webhooks.create({\n * callback: \"https://myapp.com/webhooks/neutron\",\n * secret: \"my-webhook-secret\",\n * });\n */\n async create(params: CreateWebhookParams): Promise<Webhook> {\n return this.client.post<Webhook>(`/api/v2/webhook`, params);\n }\n\n /**\n * List all registered webhooks.\n */\n async list(): Promise<Webhook[]> {\n const res = await this.client.get(`/api/v2/webhook`);\n return res.data ?? res;\n }\n\n /**\n * Update a webhook's callback URL or secret.\n */\n async update(webhookId: string, params: UpdateWebhookParams): Promise<Webhook> {\n sanitizePathParam(webhookId, \"webhookId\");\n return this.client.put<Webhook>(`/api/v2/webhook/${webhookId}`, params);\n }\n\n /**\n * Delete a webhook.\n */\n async delete(webhookId: string): Promise<void> {\n sanitizePathParam(webhookId, \"webhookId\");\n await this.client.del(`/api/v2/webhook/${webhookId}`);\n }\n\n /**\n * Verify a webhook signature from an incoming request.\n * Throws if the signature is invalid.\n *\n * @param body The raw request body (string or Buffer)\n * @param signature The `X-Neutronpay-Signature` header value\n * @param secret Your webhook secret\n * @returns The parsed event payload\n *\n * @example\n * // Express\n * app.post(\"/webhooks/neutron\", express.raw({ type: \"application/json\" }), (req, res) => {\n * try {\n * const event = Neutron.webhooks.verifySignature(\n * req.body,\n * req.headers[\"x-neutronpay-signature\"],\n * \"my-webhook-secret\"\n * );\n * // event is verified and safe to use\n * if (event.txnState === \"completed\") fulfillOrder(event.extRefId);\n * } catch (err) {\n * return res.status(401).send(\"Invalid signature\");\n * }\n * res.status(200).send(\"OK\");\n * });\n */\n static verifySignature(\n body: string | Buffer,\n signature: string | undefined | null,\n secret: string\n ): any {\n if (!signature) {\n throw new NeutronValidationError(\"Missing webhook signature header (X-Neutronpay-Signature)\");\n }\n if (!secret) {\n throw new NeutronValidationError(\"Webhook secret is required for verification\");\n }\n\n const bodyStr = typeof body === \"string\" ? body : body.toString(\"utf8\");\n\n const expected = crypto\n .createHmac(\"sha256\", secret)\n .update(bodyStr)\n .digest(\"hex\");\n\n const sigBuf = Buffer.from(signature);\n const expBuf = Buffer.from(expected);\n const isValid = sigBuf.length === expBuf.length && crypto.timingSafeEqual(sigBuf, expBuf);\n\n if (!isValid) {\n throw new NeutronValidationError(\"Invalid webhook signature\");\n }\n\n return JSON.parse(bodyStr);\n }\n}\n","import type { HttpClient } from \"../client.js\";\nimport type { ExchangeRates } from \"../types.js\";\n\nexport class RatesResource {\n constructor(private readonly client: HttpClient) {}\n\n /**\n * Get current BTC exchange rates against all supported currencies.\n *\n * @example\n * const rates = await neutron.rates.get();\n * console.log(rates); // { BTCUSD: 97500, BTCVND: 2437500000, ... }\n */\n async get(): Promise<ExchangeRates> {\n const res = await this.client.get(`/api/v2/rate`);\n return res.data ?? res;\n }\n}\n","import type { HttpClient } from \"../client.js\";\nimport type { FiatInstitution, Transaction, SourceOfFunds } from \"../types.js\";\nimport { sanitizePathParam } from \"../sanitize.js\";\n\nexport interface FiatPayoutParams {\n /** Source currency (e.g. \"BTC\") */\n sourceCcy: string;\n /** Amount from source (in BTC for Bitcoin) */\n sourceAmount: number;\n /** Destination fiat currency (e.g. \"VND\") */\n destCcy: string;\n /** Payment method (e.g. \"vnd-instant\") */\n destMethod: string;\n /** Bank account number */\n bankAcctNum: string;\n /** Bank code from `neutron.fiat.institutions()` */\n institutionCode: string;\n /** Recipient legal full name */\n recipientName: string;\n /** Recipient country code (e.g. \"VN\") */\n countryCode: string;\n /** \"individual\" or \"business\" (default: \"individual\") */\n kycType?: \"individual\" | \"business\";\n /** Source of funds declaration */\n sourceOfFunds?: SourceOfFunds;\n /** Your reference ID */\n extRefId?: string;\n}\n\nexport class FiatResource {\n constructor(private readonly client: HttpClient) {}\n\n /**\n * List banks and financial institutions for a country.\n * Returns institution codes needed for fiat payouts.\n *\n * @example\n * const banks = await neutron.fiat.institutions(\"VN\");\n * // [{ code: \"970422\", name: \"MB Bank\" }, ...]\n */\n async institutions(countryCode: string): Promise<FiatInstitution[]> {\n sanitizePathParam(countryCode, \"countryCode\");\n const res = await this.client.get(\n `/api/v2/reference/fiat-institution/by-country/${countryCode}`\n );\n return res.data ?? res;\n }\n\n /**\n * Create a fiat payout transaction. KYC is required only for fiat payouts — not for\n * Bitcoin, stablecoins, or swaps. Handles KYC and source of funds automatically.\n * Returns a quoted transaction — call `neutron.transactions.confirm()` to execute.\n *\n * @example\n * const txn = await neutron.fiat.payout({\n * sourceCcy: \"BTC\",\n * sourceAmount: 0.001,\n * destCcy: \"VND\",\n * destMethod: \"vnd-instant\",\n * bankAcctNum: \"0123456789\",\n * institutionCode: \"970422\",\n * recipientName: \"LE VAN A\",\n * countryCode: \"VN\",\n * });\n * // Review rate: txn.fxRate\n * await neutron.transactions.confirm(txn.txnId);\n */\n async payout(params: FiatPayoutParams): Promise<Transaction> {\n return this.client.post<Transaction>(`/api/v2/transaction`, {\n extRefId: params.extRefId,\n sourceReq: {\n ccy: params.sourceCcy,\n method: \"neutronpay\",\n amtRequested: params.sourceAmount,\n reqDetails: {},\n },\n destReq: {\n ccy: params.destCcy,\n method: params.destMethod,\n reqDetails: {\n bankAcctNum: params.bankAcctNum,\n institutionCode: params.institutionCode,\n },\n kyc: {\n type: params.kycType || \"individual\",\n details: {\n legalFullName: params.recipientName,\n countryCode: params.countryCode,\n },\n },\n },\n sourceOfFunds: params.sourceOfFunds ?? {\n purpose: 1,\n source: 5,\n relationship: 3,\n },\n });\n }\n}\n","// ── Satoshi / BTC conversion ────────────────────────────────\n\nconst SATS_PER_BTC = 100_000_000;\n\n/**\n * Convert satoshis to BTC.\n * @example satsToBtc(10000) // 0.0001\n */\nexport function satsToBtc(sats: number): number {\n return sats / SATS_PER_BTC;\n}\n\n/**\n * Convert BTC to satoshis.\n * @example btcToSats(0.0001) // 10000\n */\nexport function btcToSats(btc: number): number {\n return Math.round(btc * SATS_PER_BTC);\n}\n\n/**\n * Format a satoshi amount as a human-readable string.\n * @example formatSats(1500000) // \"1,500,000 sats\"\n * @example formatSats(100) // \"100 sats\"\n */\nexport function formatSats(sats: number): string {\n return `${sats.toLocaleString(\"en-US\")} sats`;\n}\n\n/**\n * Format a BTC amount with appropriate precision.\n * @example formatBtc(0.00015) // \"0.00015000 BTC\"\n */\nexport function formatBtc(btc: number): string {\n return `${btc.toFixed(8)} BTC`;\n}\n\n// ── Constants ───────────────────────────────────────────────\n\n/** Supported currencies */\nexport const Currency = {\n BTC: \"BTC\",\n USDT: \"USDT\",\n VND: \"VND\",\n USD: \"USD\",\n CAD: \"CAD\",\n NGN: \"NGN\",\n KES: \"KES\",\n GHS: \"GHS\",\n} as const;\n\nexport type Currency = (typeof Currency)[keyof typeof Currency];\n\n/** Payment methods for sourceReq/destReq */\nexport const PaymentMethod = {\n /** Internal Neutron wallet */\n NEUTRON: \"neutronpay\",\n /** Lightning Network (BOLT11 invoices) */\n LIGHTNING: \"lightning\",\n /** Lightning Address / LNURL */\n LNURL: \"lnurl\",\n /** Bitcoin on-chain */\n ON_CHAIN: \"on-chain\",\n /** USDT on TRON (TRC-20) */\n TRON: \"tron\",\n /** USDT on Ethereum (ERC-20) */\n ETH: \"eth\",\n /** Vietnamese Dong instant bank transfer */\n VND_INSTANT: \"vnd-instant\",\n} as const;\n\nexport type PaymentMethodType = (typeof PaymentMethod)[keyof typeof PaymentMethod];\n\n/** Transaction final states (terminal — won't change) */\nexport const FinalStates = [\n \"completed\",\n \"expired\",\n \"rejected\",\n \"error\",\n \"usercanceled\",\n] as const;\n\n/** All transaction states */\nexport const TransactionStates = {\n QUOTED: \"quoted\",\n USER_CONFIRMED: \"userconfirmed\",\n SRC_CREATED: \"srccreated\",\n SRC_SENT: \"srcsent\",\n SRC_INTENT: \"srcintent\",\n SRC_PEND_CONFIRM: \"srcpendconfirmfill\",\n SRC_CONFIRMED: \"srcconfirmfilled\",\n DEST_PEND_SENT: \"destpendsent\",\n DEST_SENT: \"destsent\",\n COMPLETED: \"completed\",\n EXPIRED: \"expired\",\n REJECTED: \"rejected\",\n ERROR: \"error\",\n USER_CANCELED: \"usercanceled\",\n} as const;\n\n/** USDT blockchain options */\nexport const Chain = {\n TRON: \"TRON\",\n ETH: \"ETH\",\n} as const;\n"],"mappings":"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","names":["crypto","import_crypto","crypto"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -88,6 +88,16 @@ interface ListTransactionsParams {
|
|
|
88
88
|
limit?: number;
|
|
89
89
|
offset?: number;
|
|
90
90
|
}
|
|
91
|
+
/**
|
|
92
|
+
* A real-time transaction status event delivered via SSE.
|
|
93
|
+
* NOTE: Requires the server-side endpoint /api/v2/events/stream (not yet live).
|
|
94
|
+
*/
|
|
95
|
+
interface TransactionEvent {
|
|
96
|
+
transactionId: string;
|
|
97
|
+
status: string;
|
|
98
|
+
timestamp: string;
|
|
99
|
+
data?: Record<string, unknown>;
|
|
100
|
+
}
|
|
91
101
|
interface CreateInvoiceParams {
|
|
92
102
|
/** Amount in satoshis (use this OR amountBtc) */
|
|
93
103
|
amountSats?: number;
|
|
@@ -106,6 +116,24 @@ interface LightningInvoice {
|
|
|
106
116
|
amountSats: number;
|
|
107
117
|
status: TransactionState;
|
|
108
118
|
}
|
|
119
|
+
interface DecodedInvoice {
|
|
120
|
+
/** Amount in BTC (may be undefined if invoice has no amount) */
|
|
121
|
+
amount?: number;
|
|
122
|
+
/** Invoice description/memo */
|
|
123
|
+
description?: string;
|
|
124
|
+
/** Payment hash */
|
|
125
|
+
paymentHash?: string;
|
|
126
|
+
/** Destination node pubkey */
|
|
127
|
+
destination?: string;
|
|
128
|
+
/** Invoice timestamp */
|
|
129
|
+
timestamp?: number;
|
|
130
|
+
/** Invoice expiry in seconds */
|
|
131
|
+
expiry?: number;
|
|
132
|
+
/** Raw invoice string */
|
|
133
|
+
invoice: string;
|
|
134
|
+
/** Invoice status (e.g., "valid", "expired") */
|
|
135
|
+
status?: string;
|
|
136
|
+
}
|
|
109
137
|
interface BtcAddress {
|
|
110
138
|
staticOnchainAddress: string;
|
|
111
139
|
accountId: string;
|
|
@@ -166,6 +194,11 @@ declare class HttpClient {
|
|
|
166
194
|
private ensureAuth;
|
|
167
195
|
getAccountId(): string;
|
|
168
196
|
ensureAuthAndGetAccountId(): Promise<string>;
|
|
197
|
+
/**
|
|
198
|
+
* Returns auth headers for use in raw fetch calls (e.g. SSE streams).
|
|
199
|
+
* Ensures a valid token is present before returning.
|
|
200
|
+
*/
|
|
201
|
+
getAuthHeaders(): Promise<Record<string, string>>;
|
|
169
202
|
private rawFetch;
|
|
170
203
|
request<T = any>(method: string, path: string, body?: any): Promise<T>;
|
|
171
204
|
get<T = any>(path: string): Promise<T>;
|
|
@@ -251,8 +284,11 @@ declare class TransactionsResource {
|
|
|
251
284
|
list(params?: ListTransactionsParams): Promise<Transaction[]>;
|
|
252
285
|
/**
|
|
253
286
|
* Cancel a quoted (unconfirmed) transaction.
|
|
287
|
+
*
|
|
288
|
+
* @deprecated This endpoint is not currently available on the Neutron API.
|
|
289
|
+
* Unconfirmed transactions expire automatically after their TTL.
|
|
254
290
|
*/
|
|
255
|
-
cancel(
|
|
291
|
+
cancel(_txnId: string): Promise<Transaction>;
|
|
256
292
|
/**
|
|
257
293
|
* Wait for a transaction to reach a final state. Polls at the given interval.
|
|
258
294
|
*
|
|
@@ -272,6 +308,20 @@ declare class TransactionsResource {
|
|
|
272
308
|
timeoutMs?: number;
|
|
273
309
|
onStateChange?: (state: string, txn: Transaction) => void;
|
|
274
310
|
}): Promise<Transaction>;
|
|
311
|
+
/**
|
|
312
|
+
* Stream real-time transaction status updates via SSE.
|
|
313
|
+
* For agents without a public endpoint who can't receive webhook POSTs.
|
|
314
|
+
*
|
|
315
|
+
* NOTE: Requires the server-side endpoint /api/v2/events/stream (not yet live).
|
|
316
|
+
* Use neutron.transactions.waitForCompletion() as a polling fallback in the meantime.
|
|
317
|
+
*
|
|
318
|
+
* @example
|
|
319
|
+
* for await (const event of neutron.transactions.subscribe("txn-123")) {
|
|
320
|
+
* console.log(event.status);
|
|
321
|
+
* if (event.status === "completed") break;
|
|
322
|
+
* }
|
|
323
|
+
*/
|
|
324
|
+
subscribe(transactionId: string, timeoutMs?: number): AsyncGenerator<TransactionEvent>;
|
|
275
325
|
}
|
|
276
326
|
|
|
277
327
|
declare class LightningResource {
|
|
@@ -316,6 +366,16 @@ declare class LightningResource {
|
|
|
316
366
|
amountBtc?: number;
|
|
317
367
|
extRefId?: string;
|
|
318
368
|
}): Promise<Transaction>;
|
|
369
|
+
/**
|
|
370
|
+
* Decode a Lightning invoice (BOLT11) to inspect amount, description, etc.
|
|
371
|
+
* Useful for showing users what they're about to pay before confirming.
|
|
372
|
+
*
|
|
373
|
+
* @example
|
|
374
|
+
* const decoded = await neutron.lightning.decodeInvoice("lnbc100u1p...");
|
|
375
|
+
* console.log(decoded.amount); // 0.001 (BTC)
|
|
376
|
+
* console.log(decoded.description); // "Coffee payment"
|
|
377
|
+
*/
|
|
378
|
+
decodeInvoice(invoice: string): Promise<DecodedInvoice>;
|
|
319
379
|
}
|
|
320
380
|
|
|
321
381
|
declare class WebhooksResource {
|
|
@@ -422,7 +482,8 @@ declare class FiatResource {
|
|
|
422
482
|
*/
|
|
423
483
|
institutions(countryCode: string): Promise<FiatInstitution[]>;
|
|
424
484
|
/**
|
|
425
|
-
* Create a fiat payout transaction.
|
|
485
|
+
* Create a fiat payout transaction. KYC is required only for fiat payouts — not for
|
|
486
|
+
* Bitcoin, stablecoins, or swaps. Handles KYC and source of funds automatically.
|
|
426
487
|
* Returns a quoted transaction — call `neutron.transactions.confirm()` to execute.
|
|
427
488
|
*
|
|
428
489
|
* @example
|
|
@@ -617,4 +678,4 @@ declare class Neutron {
|
|
|
617
678
|
static verifyWebhook(body: string | Buffer, signature: string | undefined | null, secret: string): any;
|
|
618
679
|
}
|
|
619
680
|
|
|
620
|
-
export { type Account, AccountResource, type ApiResponse, type AuthResponse, type BtcAddress, Chain, type CreateInvoiceParams, type CreateTransactionRequest, type CreateWebhookParams, Currency, Currency as CurrencyType, type ExchangeRates, type FiatInstitution, type FiatPayoutParams, FiatResource, FinalStates, HttpClient, type KycInfo, type LightningInvoice, LightningResource, type ListTransactionsParams, Neutron, NeutronApiError, NeutronAuthError, type NeutronConfig, NeutronError, NeutronTimeoutError, NeutronValidationError, PaymentMethod, type PaymentMethod$1 as PaymentMethodString, type PaymentMethodType, RatesResource, type SourceOfFunds, type Transaction, type TransactionSide, type TransactionState, TransactionStates, TransactionsResource, type UpdateWebhookParams, type UsdtAddress, type Wallet, type Webhook, WebhooksResource, btcToSats, formatBtc, formatSats, sanitizePathParam, satsToBtc };
|
|
681
|
+
export { type Account, AccountResource, type ApiResponse, type AuthResponse, type BtcAddress, Chain, type CreateInvoiceParams, type CreateTransactionRequest, type CreateWebhookParams, Currency, Currency as CurrencyType, type DecodedInvoice, type ExchangeRates, type FiatInstitution, type FiatPayoutParams, FiatResource, FinalStates, HttpClient, type KycInfo, type LightningInvoice, LightningResource, type ListTransactionsParams, Neutron, NeutronApiError, NeutronAuthError, type NeutronConfig, NeutronError, NeutronTimeoutError, NeutronValidationError, PaymentMethod, type PaymentMethod$1 as PaymentMethodString, type PaymentMethodType, RatesResource, type SourceOfFunds, type Transaction, type TransactionEvent, type TransactionSide, type TransactionState, TransactionStates, TransactionsResource, type UpdateWebhookParams, type UsdtAddress, type Wallet, type Webhook, WebhooksResource, btcToSats, formatBtc, formatSats, sanitizePathParam, satsToBtc };
|
package/dist/index.d.ts
CHANGED
|
@@ -88,6 +88,16 @@ interface ListTransactionsParams {
|
|
|
88
88
|
limit?: number;
|
|
89
89
|
offset?: number;
|
|
90
90
|
}
|
|
91
|
+
/**
|
|
92
|
+
* A real-time transaction status event delivered via SSE.
|
|
93
|
+
* NOTE: Requires the server-side endpoint /api/v2/events/stream (not yet live).
|
|
94
|
+
*/
|
|
95
|
+
interface TransactionEvent {
|
|
96
|
+
transactionId: string;
|
|
97
|
+
status: string;
|
|
98
|
+
timestamp: string;
|
|
99
|
+
data?: Record<string, unknown>;
|
|
100
|
+
}
|
|
91
101
|
interface CreateInvoiceParams {
|
|
92
102
|
/** Amount in satoshis (use this OR amountBtc) */
|
|
93
103
|
amountSats?: number;
|
|
@@ -106,6 +116,24 @@ interface LightningInvoice {
|
|
|
106
116
|
amountSats: number;
|
|
107
117
|
status: TransactionState;
|
|
108
118
|
}
|
|
119
|
+
interface DecodedInvoice {
|
|
120
|
+
/** Amount in BTC (may be undefined if invoice has no amount) */
|
|
121
|
+
amount?: number;
|
|
122
|
+
/** Invoice description/memo */
|
|
123
|
+
description?: string;
|
|
124
|
+
/** Payment hash */
|
|
125
|
+
paymentHash?: string;
|
|
126
|
+
/** Destination node pubkey */
|
|
127
|
+
destination?: string;
|
|
128
|
+
/** Invoice timestamp */
|
|
129
|
+
timestamp?: number;
|
|
130
|
+
/** Invoice expiry in seconds */
|
|
131
|
+
expiry?: number;
|
|
132
|
+
/** Raw invoice string */
|
|
133
|
+
invoice: string;
|
|
134
|
+
/** Invoice status (e.g., "valid", "expired") */
|
|
135
|
+
status?: string;
|
|
136
|
+
}
|
|
109
137
|
interface BtcAddress {
|
|
110
138
|
staticOnchainAddress: string;
|
|
111
139
|
accountId: string;
|
|
@@ -166,6 +194,11 @@ declare class HttpClient {
|
|
|
166
194
|
private ensureAuth;
|
|
167
195
|
getAccountId(): string;
|
|
168
196
|
ensureAuthAndGetAccountId(): Promise<string>;
|
|
197
|
+
/**
|
|
198
|
+
* Returns auth headers for use in raw fetch calls (e.g. SSE streams).
|
|
199
|
+
* Ensures a valid token is present before returning.
|
|
200
|
+
*/
|
|
201
|
+
getAuthHeaders(): Promise<Record<string, string>>;
|
|
169
202
|
private rawFetch;
|
|
170
203
|
request<T = any>(method: string, path: string, body?: any): Promise<T>;
|
|
171
204
|
get<T = any>(path: string): Promise<T>;
|
|
@@ -251,8 +284,11 @@ declare class TransactionsResource {
|
|
|
251
284
|
list(params?: ListTransactionsParams): Promise<Transaction[]>;
|
|
252
285
|
/**
|
|
253
286
|
* Cancel a quoted (unconfirmed) transaction.
|
|
287
|
+
*
|
|
288
|
+
* @deprecated This endpoint is not currently available on the Neutron API.
|
|
289
|
+
* Unconfirmed transactions expire automatically after their TTL.
|
|
254
290
|
*/
|
|
255
|
-
cancel(
|
|
291
|
+
cancel(_txnId: string): Promise<Transaction>;
|
|
256
292
|
/**
|
|
257
293
|
* Wait for a transaction to reach a final state. Polls at the given interval.
|
|
258
294
|
*
|
|
@@ -272,6 +308,20 @@ declare class TransactionsResource {
|
|
|
272
308
|
timeoutMs?: number;
|
|
273
309
|
onStateChange?: (state: string, txn: Transaction) => void;
|
|
274
310
|
}): Promise<Transaction>;
|
|
311
|
+
/**
|
|
312
|
+
* Stream real-time transaction status updates via SSE.
|
|
313
|
+
* For agents without a public endpoint who can't receive webhook POSTs.
|
|
314
|
+
*
|
|
315
|
+
* NOTE: Requires the server-side endpoint /api/v2/events/stream (not yet live).
|
|
316
|
+
* Use neutron.transactions.waitForCompletion() as a polling fallback in the meantime.
|
|
317
|
+
*
|
|
318
|
+
* @example
|
|
319
|
+
* for await (const event of neutron.transactions.subscribe("txn-123")) {
|
|
320
|
+
* console.log(event.status);
|
|
321
|
+
* if (event.status === "completed") break;
|
|
322
|
+
* }
|
|
323
|
+
*/
|
|
324
|
+
subscribe(transactionId: string, timeoutMs?: number): AsyncGenerator<TransactionEvent>;
|
|
275
325
|
}
|
|
276
326
|
|
|
277
327
|
declare class LightningResource {
|
|
@@ -316,6 +366,16 @@ declare class LightningResource {
|
|
|
316
366
|
amountBtc?: number;
|
|
317
367
|
extRefId?: string;
|
|
318
368
|
}): Promise<Transaction>;
|
|
369
|
+
/**
|
|
370
|
+
* Decode a Lightning invoice (BOLT11) to inspect amount, description, etc.
|
|
371
|
+
* Useful for showing users what they're about to pay before confirming.
|
|
372
|
+
*
|
|
373
|
+
* @example
|
|
374
|
+
* const decoded = await neutron.lightning.decodeInvoice("lnbc100u1p...");
|
|
375
|
+
* console.log(decoded.amount); // 0.001 (BTC)
|
|
376
|
+
* console.log(decoded.description); // "Coffee payment"
|
|
377
|
+
*/
|
|
378
|
+
decodeInvoice(invoice: string): Promise<DecodedInvoice>;
|
|
319
379
|
}
|
|
320
380
|
|
|
321
381
|
declare class WebhooksResource {
|
|
@@ -422,7 +482,8 @@ declare class FiatResource {
|
|
|
422
482
|
*/
|
|
423
483
|
institutions(countryCode: string): Promise<FiatInstitution[]>;
|
|
424
484
|
/**
|
|
425
|
-
* Create a fiat payout transaction.
|
|
485
|
+
* Create a fiat payout transaction. KYC is required only for fiat payouts — not for
|
|
486
|
+
* Bitcoin, stablecoins, or swaps. Handles KYC and source of funds automatically.
|
|
426
487
|
* Returns a quoted transaction — call `neutron.transactions.confirm()` to execute.
|
|
427
488
|
*
|
|
428
489
|
* @example
|
|
@@ -617,4 +678,4 @@ declare class Neutron {
|
|
|
617
678
|
static verifyWebhook(body: string | Buffer, signature: string | undefined | null, secret: string): any;
|
|
618
679
|
}
|
|
619
680
|
|
|
620
|
-
export { type Account, AccountResource, type ApiResponse, type AuthResponse, type BtcAddress, Chain, type CreateInvoiceParams, type CreateTransactionRequest, type CreateWebhookParams, Currency, Currency as CurrencyType, type ExchangeRates, type FiatInstitution, type FiatPayoutParams, FiatResource, FinalStates, HttpClient, type KycInfo, type LightningInvoice, LightningResource, type ListTransactionsParams, Neutron, NeutronApiError, NeutronAuthError, type NeutronConfig, NeutronError, NeutronTimeoutError, NeutronValidationError, PaymentMethod, type PaymentMethod$1 as PaymentMethodString, type PaymentMethodType, RatesResource, type SourceOfFunds, type Transaction, type TransactionSide, type TransactionState, TransactionStates, TransactionsResource, type UpdateWebhookParams, type UsdtAddress, type Wallet, type Webhook, WebhooksResource, btcToSats, formatBtc, formatSats, sanitizePathParam, satsToBtc };
|
|
681
|
+
export { type Account, AccountResource, type ApiResponse, type AuthResponse, type BtcAddress, Chain, type CreateInvoiceParams, type CreateTransactionRequest, type CreateWebhookParams, Currency, Currency as CurrencyType, type DecodedInvoice, type ExchangeRates, type FiatInstitution, type FiatPayoutParams, FiatResource, FinalStates, HttpClient, type KycInfo, type LightningInvoice, LightningResource, type ListTransactionsParams, Neutron, NeutronApiError, NeutronAuthError, type NeutronConfig, NeutronError, NeutronTimeoutError, NeutronValidationError, PaymentMethod, type PaymentMethod$1 as PaymentMethodString, type PaymentMethodType, RatesResource, type SourceOfFunds, type Transaction, type TransactionEvent, type TransactionSide, type TransactionState, TransactionStates, TransactionsResource, type UpdateWebhookParams, type UsdtAddress, type Wallet, type Webhook, WebhooksResource, btcToSats, formatBtc, formatSats, sanitizePathParam, satsToBtc };
|
package/dist/index.js
CHANGED
|
@@ -138,6 +138,16 @@ var HttpClient = class {
|
|
|
138
138
|
await this.ensureAuth();
|
|
139
139
|
return this.accountId;
|
|
140
140
|
}
|
|
141
|
+
/**
|
|
142
|
+
* Returns auth headers for use in raw fetch calls (e.g. SSE streams).
|
|
143
|
+
* Ensures a valid token is present before returning.
|
|
144
|
+
*/
|
|
145
|
+
async getAuthHeaders() {
|
|
146
|
+
await this.ensureAuth();
|
|
147
|
+
return {
|
|
148
|
+
Authorization: `Bearer ${this.accessToken}`
|
|
149
|
+
};
|
|
150
|
+
}
|
|
141
151
|
// ── HTTP ──────────────────────────────────────────────
|
|
142
152
|
async rawFetch(url, init) {
|
|
143
153
|
const controller = new AbortController();
|
|
@@ -164,9 +174,9 @@ var HttpClient = class {
|
|
|
164
174
|
const url = `${this.baseUrl}${path}`;
|
|
165
175
|
this.log(`${method} ${path}`);
|
|
166
176
|
const headers = {
|
|
167
|
-
Authorization: `Bearer ${this.accessToken}
|
|
177
|
+
Authorization: `Bearer ${this.accessToken}`,
|
|
178
|
+
"Content-Type": "application/json"
|
|
168
179
|
};
|
|
169
|
-
if (body) headers["Content-Type"] = "application/json";
|
|
170
180
|
const response = await this.rawFetch(url, {
|
|
171
181
|
method,
|
|
172
182
|
headers,
|
|
@@ -341,10 +351,14 @@ var TransactionsResource = class {
|
|
|
341
351
|
}
|
|
342
352
|
/**
|
|
343
353
|
* Cancel a quoted (unconfirmed) transaction.
|
|
354
|
+
*
|
|
355
|
+
* @deprecated This endpoint is not currently available on the Neutron API.
|
|
356
|
+
* Unconfirmed transactions expire automatically after their TTL.
|
|
344
357
|
*/
|
|
345
|
-
async cancel(
|
|
346
|
-
|
|
347
|
-
|
|
358
|
+
async cancel(_txnId) {
|
|
359
|
+
throw new Error(
|
|
360
|
+
"transactions.cancel() is not available. Unconfirmed transactions expire automatically."
|
|
361
|
+
);
|
|
348
362
|
}
|
|
349
363
|
/**
|
|
350
364
|
* Wait for a transaction to reach a final state. Polls at the given interval.
|
|
@@ -379,6 +393,65 @@ var TransactionsResource = class {
|
|
|
379
393
|
}
|
|
380
394
|
throw new Error(`Transaction ${txnId} did not complete within ${timeout}ms`);
|
|
381
395
|
}
|
|
396
|
+
/**
|
|
397
|
+
* Stream real-time transaction status updates via SSE.
|
|
398
|
+
* For agents without a public endpoint who can't receive webhook POSTs.
|
|
399
|
+
*
|
|
400
|
+
* NOTE: Requires the server-side endpoint /api/v2/events/stream (not yet live).
|
|
401
|
+
* Use neutron.transactions.waitForCompletion() as a polling fallback in the meantime.
|
|
402
|
+
*
|
|
403
|
+
* @example
|
|
404
|
+
* for await (const event of neutron.transactions.subscribe("txn-123")) {
|
|
405
|
+
* console.log(event.status);
|
|
406
|
+
* if (event.status === "completed") break;
|
|
407
|
+
* }
|
|
408
|
+
*/
|
|
409
|
+
async *subscribe(transactionId, timeoutMs = 6e4) {
|
|
410
|
+
sanitizePathParam(transactionId, "transactionId");
|
|
411
|
+
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
412
|
+
if (!UUID_RE.test(transactionId)) {
|
|
413
|
+
throw new Error("Invalid transactionId: must be a UUID.");
|
|
414
|
+
}
|
|
415
|
+
const clampedTimeout = Math.min(Math.max(timeoutMs, 5e3), 3e5);
|
|
416
|
+
const url = `${this.client.baseUrl}/api/v2/events/stream?transactionId=${encodeURIComponent(transactionId)}`;
|
|
417
|
+
const response = await fetch(url, {
|
|
418
|
+
headers: {
|
|
419
|
+
"Accept": "text/event-stream",
|
|
420
|
+
...await this.client.getAuthHeaders()
|
|
421
|
+
},
|
|
422
|
+
signal: AbortSignal.timeout(clampedTimeout)
|
|
423
|
+
});
|
|
424
|
+
if (!response.ok || !response.body) {
|
|
425
|
+
throw new Error(`SSE connection failed: ${response.status} ${response.statusText}`);
|
|
426
|
+
}
|
|
427
|
+
const reader = response.body.getReader();
|
|
428
|
+
const decoder = new TextDecoder();
|
|
429
|
+
let buffer = "";
|
|
430
|
+
const MAX_BUFFER = 64 * 1024;
|
|
431
|
+
try {
|
|
432
|
+
while (true) {
|
|
433
|
+
const { done, value } = await reader.read();
|
|
434
|
+
if (done) break;
|
|
435
|
+
buffer += decoder.decode(value, { stream: true });
|
|
436
|
+
if (buffer.length > MAX_BUFFER) {
|
|
437
|
+
throw new Error("SSE buffer overflow \u2014 server sent malformed stream.");
|
|
438
|
+
}
|
|
439
|
+
const lines = buffer.split("\n");
|
|
440
|
+
buffer = lines.pop() || "";
|
|
441
|
+
for (const line of lines) {
|
|
442
|
+
if (line.startsWith("data: ")) {
|
|
443
|
+
try {
|
|
444
|
+
yield JSON.parse(line.slice(6));
|
|
445
|
+
} catch (parseErr) {
|
|
446
|
+
console.error("[neutron-sdk] SSE parse error:", parseErr);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
} finally {
|
|
452
|
+
reader.cancel();
|
|
453
|
+
}
|
|
454
|
+
}
|
|
382
455
|
};
|
|
383
456
|
|
|
384
457
|
// src/resources/lightning.ts
|
|
@@ -480,10 +553,26 @@ var LightningResource = class {
|
|
|
480
553
|
destReq: {
|
|
481
554
|
ccy: "BTC",
|
|
482
555
|
method: "lnurl",
|
|
483
|
-
reqDetails: {
|
|
556
|
+
reqDetails: { address }
|
|
484
557
|
}
|
|
485
558
|
});
|
|
486
559
|
}
|
|
560
|
+
/**
|
|
561
|
+
* Decode a Lightning invoice (BOLT11) to inspect amount, description, etc.
|
|
562
|
+
* Useful for showing users what they're about to pay before confirming.
|
|
563
|
+
*
|
|
564
|
+
* @example
|
|
565
|
+
* const decoded = await neutron.lightning.decodeInvoice("lnbc100u1p...");
|
|
566
|
+
* console.log(decoded.amount); // 0.001 (BTC)
|
|
567
|
+
* console.log(decoded.description); // "Coffee payment"
|
|
568
|
+
*/
|
|
569
|
+
async decodeInvoice(invoice) {
|
|
570
|
+
const result = await this.client.post(
|
|
571
|
+
`/api/v2/decode/lightning`,
|
|
572
|
+
{ paymentRequest: invoice }
|
|
573
|
+
);
|
|
574
|
+
return result.invoice;
|
|
575
|
+
}
|
|
487
576
|
};
|
|
488
577
|
|
|
489
578
|
// src/resources/webhooks.ts
|
|
@@ -609,7 +698,8 @@ var FiatResource = class {
|
|
|
609
698
|
return res.data ?? res;
|
|
610
699
|
}
|
|
611
700
|
/**
|
|
612
|
-
* Create a fiat payout transaction.
|
|
701
|
+
* Create a fiat payout transaction. KYC is required only for fiat payouts — not for
|
|
702
|
+
* Bitcoin, stablecoins, or swaps. Handles KYC and source of funds automatically.
|
|
613
703
|
* Returns a quoted transaction — call `neutron.transactions.confirm()` to execute.
|
|
614
704
|
*
|
|
615
705
|
* @example
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client.ts","../src/errors.ts","../src/sanitize.ts","../src/resources/account.ts","../src/resources/transactions.ts","../src/resources/lightning.ts","../src/resources/webhooks.ts","../src/resources/rates.ts","../src/resources/fiat.ts","../src/utils.ts","../src/index.ts"],"sourcesContent":["import crypto from \"crypto\";\nimport type { NeutronConfig, AuthResponse } from \"./types.js\";\nimport {\n NeutronApiError,\n NeutronAuthError,\n NeutronTimeoutError,\n} from \"./errors.js\";\n\nconst DEFAULT_BASE_URL = \"https://api.neutron.me\";\nconst DEFAULT_TIMEOUT = 30_000;\nconst DEFAULT_MAX_RETRIES = 2;\nconst TOKEN_REFRESH_BUFFER_MS = 60_000; // refresh 1 min before expiry\n\nexport class HttpClient {\n private readonly apiKey: string;\n private readonly apiSecret: string;\n readonly baseUrl: string;\n private readonly timeout: number;\n private readonly maxRetries: number;\n private readonly debug: boolean;\n\n private accessToken: string | null = null;\n private accountId: string | null = null;\n private tokenExpiry: number = 0;\n\n constructor(config: NeutronConfig) {\n if (!config.apiKey) throw new NeutronAuthError(\"apiKey is required\");\n if (!config.apiSecret) throw new NeutronAuthError(\"apiSecret is required\");\n\n this.apiKey = config.apiKey;\n this.apiSecret = config.apiSecret;\n this.baseUrl = (config.baseUrl || DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this.timeout = config.timeout ?? DEFAULT_TIMEOUT;\n this.maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES;\n this.debug = config.debug ?? false;\n }\n\n private log(message: string, data?: any): void {\n if (!this.debug) return;\n const ts = new Date().toISOString();\n const extra = data ? ` ${JSON.stringify(data)}` : \"\";\n console.error(`[neutron-sdk ${ts}] ${message}${extra}`);\n }\n\n // ── Auth ──────────────────────────────────────────────\n\n private generateSignature(payload: string): string {\n const stringToSign = `${this.apiKey}&payload=${payload}`;\n return crypto\n .createHmac(\"sha256\", this.apiSecret)\n .update(stringToSign)\n .digest(\"hex\");\n }\n\n private get isTokenValid(): boolean {\n return !!(\n this.accessToken &&\n this.accountId &&\n Date.now() < this.tokenExpiry - TOKEN_REFRESH_BUFFER_MS\n );\n }\n\n async authenticate(): Promise<AuthResponse> {\n const payload = JSON.stringify({ test: \"auth\" });\n const signature = this.generateSignature(payload);\n\n const response = await this.rawFetch(\n `${this.baseUrl}/api/v2/authentication/token-signature`,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Api-Key\": this.apiKey,\n \"X-Api-Signature\": signature,\n },\n body: payload,\n }\n );\n\n if (!response.ok) {\n const body = (await response.json().catch(() => ({}))) as Record<string, any>;\n throw new NeutronAuthError(\n body.error || body.message || `Authentication failed (${response.status})`\n );\n }\n\n const raw = (await response.json()) as any;\n // API wraps auth response in { data: { ... } }\n const result: AuthResponse = raw.data ?? raw;\n this.accountId = result.accountId;\n this.accessToken = result.accessToken;\n this.tokenExpiry = typeof result.expiredAt === \"number\"\n ? result.expiredAt\n : new Date(result.expiredAt).getTime();\n\n return result;\n this.log(\"Authenticated\", { accountId: this.accountId });\n }\n\n private async ensureAuth(): Promise<void> {\n if (!this.isTokenValid) {\n await this.authenticate();\n }\n }\n\n getAccountId(): string {\n if (!this.accountId) {\n throw new NeutronAuthError(\"Not authenticated. Call a method first or use neutron.account.get().\");\n }\n return this.accountId;\n }\n\n async ensureAuthAndGetAccountId(): Promise<string> {\n await this.ensureAuth();\n return this.accountId!;\n }\n\n // ── HTTP ──────────────────────────────────────────────\n\n private async rawFetch(url: string, init: RequestInit): Promise<Response> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n return await fetch(url, { ...init, signal: controller.signal });\n } catch (err: any) {\n if (err.name === \"AbortError\") {\n throw new NeutronTimeoutError(this.timeout);\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n }\n\n async request<T = any>(method: string, path: string, body?: any): Promise<T> {\n await this.ensureAuth();\n\n let lastError: any;\n\n for (let attempt = 0; attempt <= this.maxRetries; attempt++) {\n if (attempt > 0) {\n // Exponential backoff: 1s, 2s, 4s...\n await new Promise((r) => setTimeout(r, Math.pow(2, attempt - 1) * 1000));\n\n // Re-auth if token might have expired during retries\n if (!this.isTokenValid) await this.authenticate();\n }\n\n const url = `${this.baseUrl}${path}`;\n this.log(`${method} ${path}`);\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.accessToken}`,\n };\n if (body) headers[\"Content-Type\"] = \"application/json\";\n\n const response = await this.rawFetch(url, {\n method,\n headers,\n body: body ? JSON.stringify(body) : undefined,\n });\n\n if (response.ok) {\n return (await response.json()) as T;\n }\n\n const errorBody = await response.json().catch(() => ({}));\n const apiError = new NeutronApiError(response.status, errorBody);\n\n // Re-authenticate on 401 and retry\n if (response.status === 401 && attempt < this.maxRetries) {\n this.accessToken = null;\n lastError = apiError;\n continue;\n }\n\n // Retry on 5xx and 429\n if (apiError.isRetryable && attempt < this.maxRetries) {\n lastError = apiError;\n continue;\n }\n\n throw apiError;\n }\n\n throw lastError;\n }\n\n async get<T = any>(path: string): Promise<T> {\n return this.request<T>(\"GET\", path);\n }\n\n async post<T = any>(path: string, body?: any): Promise<T> {\n return this.request<T>(\"POST\", path, body);\n }\n\n async put<T = any>(path: string, body?: any): Promise<T> {\n return this.request<T>(\"PUT\", path, body);\n }\n\n async del<T = any>(path: string): Promise<T> {\n return this.request<T>(\"DELETE\", path);\n }\n}\n","/**\n * Base error for all Neutron SDK errors.\n */\nexport class NeutronError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"NeutronError\";\n }\n}\n\n/**\n * Thrown when the API returns an error response (4xx/5xx).\n */\nexport class NeutronApiError extends NeutronError {\n /** HTTP status code */\n readonly status: number;\n /** Neutron error code (e.g. \"2005\") */\n readonly code: string | undefined;\n /** Raw error body from the API */\n readonly body: any;\n\n constructor(status: number, body: any) {\n const message = body?.error || body?.message || `API error ${status}`;\n super(message);\n this.name = \"NeutronApiError\";\n this.status = status;\n this.code = body?.code;\n this.body = body;\n }\n\n /** True if this is a rate limit error (429) */\n get isRateLimited(): boolean {\n return this.status === 429;\n }\n\n /** True if this is an auth error (401/403) */\n get isAuthError(): boolean {\n return this.status === 401 || this.status === 403;\n }\n\n /** True if retrying might help (5xx, 429) */\n get isRetryable(): boolean {\n return this.status === 429 || this.status >= 500;\n }\n}\n\n/**\n * Thrown when authentication fails.\n */\nexport class NeutronAuthError extends NeutronError {\n constructor(message: string = \"Authentication failed. Check your API key and secret.\") {\n super(message);\n this.name = \"NeutronAuthError\";\n }\n}\n\n/**\n * Thrown when a request times out.\n */\nexport class NeutronTimeoutError extends NeutronError {\n constructor(timeoutMs: number) {\n super(`Request timed out after ${timeoutMs}ms`);\n this.name = \"NeutronTimeoutError\";\n }\n}\n\n/**\n * Thrown for SDK usage errors (bad params, missing fields).\n */\nexport class NeutronValidationError extends NeutronError {\n constructor(message: string) {\n super(message);\n this.name = \"NeutronValidationError\";\n }\n}\n","import { NeutronValidationError } from \"./errors.js\";\n\n/**\n * Sanitize a path parameter to prevent path traversal and injection.\n * Only allows alphanumeric characters, hyphens, underscores, and dots.\n */\nexport function sanitizePathParam(value: string, name: string): string {\n if (!value || typeof value !== \"string\") {\n throw new NeutronValidationError(`${name} is required and must be a non-empty string.`);\n }\n\n // Strip any path traversal or special characters\n const sanitized = value.replace(/[^a-zA-Z0-9\\-_.]/g, \"\");\n\n if (sanitized !== value) {\n throw new NeutronValidationError(\n `${name} contains invalid characters. Only alphanumeric, hyphens, underscores, and dots are allowed.`\n );\n }\n\n if (sanitized.includes(\"..\")) {\n throw new NeutronValidationError(`${name} cannot contain path traversal sequences.`);\n }\n\n return sanitized;\n}\n","import type { HttpClient } from \"../client.js\";\nimport type { Account, Wallet } from \"../types.js\";\nimport { sanitizePathParam } from \"../sanitize.js\";\n\nexport class AccountResource {\n constructor(private readonly client: HttpClient) {}\n\n /**\n * Get account info: display name, status, country, timezone.\n */\n async get(): Promise<Account> {\n const accountId = await this.client.ensureAuthAndGetAccountId();\n const res = await this.client.get(`/api/v2/account/${accountId}`);\n return (res.data ?? res) as Account;\n }\n\n /**\n * List all wallets with balances (BTC, USDT, fiat).\n */\n async wallets(): Promise<Wallet[]> {\n const accountId = await this.client.ensureAuthAndGetAccountId();\n const res = await this.client.get(`/api/v2/account/${accountId}/wallet/`);\n return res.data ?? res;\n }\n\n /**\n * Get a specific wallet by ID.\n */\n async wallet(walletId: string): Promise<Wallet> {\n sanitizePathParam(walletId, \"walletId\");\n const accountId = await this.client.ensureAuthAndGetAccountId();\n const res = await this.client.get(`/api/v2/account/${accountId}/wallet/${walletId}`);\n return (res.data ?? res) as Wallet;\n }\n\n /**\n * Get your Bitcoin on-chain deposit address (static, reusable).\n */\n async btcAddress(): Promise<{ address: string }> {\n const raw = await this.client.get(`/api/v2/account/onchain-address`);\n const data = raw?.data ?? raw;\n return { address: data.staticOnchainAddress };\n }\n\n /**\n * Get your USDT deposit address.\n * @param chain \"TRON\" (default, recommended) or \"ETH\"\n */\n async usdtAddress(chain: \"TRON\" | \"ETH\" = \"TRON\"): Promise<{ address: string; chain: string }> {\n const raw = await this.client.get(\n `/api/v2/account/stablecoin-onchain-address?walletCcy=USDT&chainId=${chain}`\n );\n const data = raw?.data ?? raw;\n return {\n address: data.staticStablecoinOnchainAddress || data.staticOnchainAddress,\n chain,\n };\n }\n}\n","import type { HttpClient } from \"../client.js\";\nimport type {\n Transaction,\n CreateTransactionRequest,\n ListTransactionsParams,\n} from \"../types.js\";\nimport { sanitizePathParam } from \"../sanitize.js\";\n\nexport class TransactionsResource {\n constructor(private readonly client: HttpClient) {}\n\n /**\n * Create a transaction (returns a quote). Call `.confirm()` to execute.\n *\n * @example\n * // Lightning receive (create invoice)\n * const txn = await neutron.transactions.create({\n * sourceReq: { ccy: \"BTC\", method: \"lightning\", reqDetails: {} },\n * destReq: { ccy: \"BTC\", method: \"neutronpay\", amtRequested: 0.0001, reqDetails: {} },\n * });\n *\n * @example\n * // Lightning send (pay invoice)\n * const txn = await neutron.transactions.create({\n * sourceReq: { ccy: \"BTC\", method: \"neutronpay\" },\n * destReq: { ccy: \"BTC\", method: \"lightning\", reqDetails: { paymentRequest: \"lnbc...\" } },\n * });\n *\n * @example\n * // Internal swap (BTC → USDT)\n * const txn = await neutron.transactions.create({\n * sourceReq: { ccy: \"BTC\", method: \"neutronpay\", amtRequested: 0.001, reqDetails: {} },\n * destReq: { ccy: \"USDT\", method: \"neutronpay\", reqDetails: {} },\n * });\n */\n async create(params: CreateTransactionRequest): Promise<Transaction> {\n return this.client.post<Transaction>(`/api/v2/transaction`, params);\n }\n\n /**\n * Confirm a quoted transaction to execute it.\n * After confirmation, Lightning invoices become payable and sends are dispatched.\n */\n async confirm(txnId: string): Promise<Transaction> {\n sanitizePathParam(txnId, \"txnId\");\n return this.client.put<Transaction>(`/api/v2/transaction/${txnId}/confirm`);\n }\n\n /**\n * Get transaction status and details.\n */\n async get(txnId: string): Promise<Transaction> {\n sanitizePathParam(txnId, \"txnId\");\n return this.client.get<Transaction>(`/api/v2/transaction/${txnId}`);\n }\n\n /**\n * List transactions with optional filters.\n *\n * @example\n * const completed = await neutron.transactions.list({ status: \"completed\", limit: 10 });\n */\n async list(params?: ListTransactionsParams): Promise<Transaction[]> {\n const qs = new URLSearchParams();\n if (params) {\n for (const [k, v] of Object.entries(params)) {\n if (v !== undefined && v !== null) qs.append(k, String(v));\n }\n }\n const query = qs.toString();\n const res = await this.client.get(`/api/v2/transaction${query ? `?${query}` : \"\"}`);\n return res.data ?? res;\n }\n\n /**\n * Cancel a quoted (unconfirmed) transaction.\n */\n async cancel(txnId: string): Promise<Transaction> {\n sanitizePathParam(txnId, \"txnId\");\n return this.client.put<Transaction>(`/api/v2/transaction/${txnId}/cancel`);\n }\n\n /**\n * Wait for a transaction to reach a final state. Polls at the given interval.\n *\n * @param txnId Transaction ID\n * @param options.intervalMs Polling interval in ms (default: 3000)\n * @param options.timeoutMs Max wait time in ms (default: 300000 = 5 min)\n * @param options.onStateChange Callback fired on each state change\n * @returns The transaction in a final state\n *\n * @example\n * const txn = await neutron.transactions.waitForCompletion(txnId, {\n * onStateChange: (state) => console.log(\"State:\", state),\n * });\n */\n async waitForCompletion(\n txnId: string,\n options?: {\n intervalMs?: number;\n timeoutMs?: number;\n onStateChange?: (state: string, txn: Transaction) => void;\n }\n ): Promise<Transaction> {\n const FINAL_STATES = [\"completed\", \"failed\", \"expired\", \"rejected\", \"error\", \"usercanceled\"];\n const interval = options?.intervalMs ?? 3000;\n const timeout = options?.timeoutMs ?? 300_000;\n const start = Date.now();\n let lastState = \"\";\n\n while (Date.now() - start < timeout) {\n const txn = await this.get(txnId);\n\n if (txn.txnState !== lastState) {\n lastState = txn.txnState;\n options?.onStateChange?.(txn.txnState, txn);\n }\n\n if (FINAL_STATES.includes(txn.txnState)) {\n return txn;\n }\n\n await new Promise((r) => setTimeout(r, interval));\n }\n\n throw new Error(`Transaction ${txnId} did not complete within ${timeout}ms`);\n }\n}\n","import type { HttpClient } from \"../client.js\";\nimport type {\n CreateInvoiceParams,\n LightningInvoice,\n Transaction,\n} from \"../types.js\";\nimport { NeutronValidationError } from \"../errors.js\";\n\nexport class LightningResource {\n constructor(private readonly client: HttpClient) {}\n\n /**\n * Create a Lightning invoice to receive Bitcoin. Auto-confirms — ready to pay immediately.\n *\n * @example\n * const invoice = await neutron.lightning.createInvoice({ amountSats: 10000 });\n * console.log(invoice.invoice); // \"lnbc100u1p...\"\n * console.log(invoice.qrPageUrl); // hosted QR code page\n *\n * @example\n * const invoice = await neutron.lightning.createInvoice({\n * amountBtc: 0.001,\n * memo: \"Order #1234\",\n * extRefId: \"order-1234\",\n * });\n */\n async createInvoice(params: CreateInvoiceParams): Promise<LightningInvoice> {\n let btcAmount: number;\n\n if (params.amountSats !== undefined && params.amountBtc !== undefined) {\n throw new NeutronValidationError(\"Provide either amountSats or amountBtc, not both.\");\n }\n if (params.amountSats !== undefined) {\n if (params.amountSats <= 0) throw new NeutronValidationError(\"amountSats must be positive.\");\n btcAmount = params.amountSats / 100_000_000;\n } else if (params.amountBtc !== undefined) {\n if (params.amountBtc <= 0) throw new NeutronValidationError(\"amountBtc must be positive.\");\n btcAmount = params.amountBtc;\n } else {\n throw new NeutronValidationError(\"Provide either amountSats or amountBtc.\");\n }\n\n // Create\n const txn = await this.client.post<Transaction>(`/api/v2/transaction`, {\n extRefId: params.extRefId,\n sourceReq: { ccy: \"BTC\", method: \"lightning\", reqDetails: {} },\n destReq: {\n ccy: \"BTC\",\n method: \"neutronpay\",\n amtRequested: btcAmount,\n reqDetails: {},\n },\n });\n\n // Auto-confirm\n const confirmed = await this.client.put<Transaction>(\n `/api/v2/transaction/${txn.txnId}/confirm`\n );\n\n return {\n txnId: confirmed.txnId,\n invoice: confirmed.sourceReq?.reqDetails?.paymentRequest ?? \"\",\n qrPageUrl: confirmed.sourceReq?.reqDetails?.invoicePageUrl,\n amountBtc: btcAmount,\n amountSats: Math.round(btcAmount * 100_000_000),\n status: confirmed.txnState,\n };\n }\n\n /**\n * Pay a Lightning invoice (BOLT11).\n * Returns a quoted transaction — call `neutron.transactions.confirm()` to send.\n *\n * @example\n * const txn = await neutron.lightning.payInvoice(\"lnbc100u1p...\");\n * // Review fees: txn.sourceReq.neutronpayFees\n * await neutron.transactions.confirm(txn.txnId);\n */\n async payInvoice(invoice: string, extRefId?: string): Promise<Transaction> {\n return this.client.post<Transaction>(`/api/v2/transaction`, {\n extRefId,\n sourceReq: { ccy: \"BTC\", method: \"neutronpay\" },\n destReq: {\n ccy: \"BTC\",\n method: \"lightning\",\n reqDetails: { paymentRequest: invoice },\n },\n });\n }\n\n /**\n * Send to a Lightning Address (user@domain.com).\n * Returns a quoted transaction — call `neutron.transactions.confirm()` to send.\n *\n * @example\n * const txn = await neutron.lightning.payAddress(\"alice@getalby.com\", { amountSats: 5000 });\n * await neutron.transactions.confirm(txn.txnId);\n */\n async payAddress(\n address: string,\n params: { amountSats?: number; amountBtc?: number; extRefId?: string }\n ): Promise<Transaction> {\n let btcAmount: number;\n if (params.amountSats !== undefined) {\n btcAmount = params.amountSats / 100_000_000;\n } else if (params.amountBtc !== undefined) {\n btcAmount = params.amountBtc;\n } else {\n throw new NeutronValidationError(\"Provide either amountSats or amountBtc.\");\n }\n\n return this.client.post<Transaction>(`/api/v2/transaction`, {\n extRefId: params.extRefId,\n sourceReq: { ccy: \"BTC\", method: \"neutronpay\", amtRequested: btcAmount },\n destReq: {\n ccy: \"BTC\",\n method: \"lnurl\",\n reqDetails: { lnurl: address },\n },\n });\n }\n\n}\n","import crypto from \"crypto\";\nimport type { HttpClient } from \"../client.js\";\nimport type { Webhook, CreateWebhookParams, UpdateWebhookParams } from \"../types.js\";\nimport { NeutronValidationError } from \"../errors.js\";\nimport { sanitizePathParam } from \"../sanitize.js\";\n\nexport class WebhooksResource {\n constructor(private readonly client: HttpClient) {}\n\n /**\n * Register a webhook to receive transaction state change notifications.\n *\n * @example\n * const webhook = await neutron.webhooks.create({\n * callback: \"https://myapp.com/webhooks/neutron\",\n * secret: \"my-webhook-secret\",\n * });\n */\n async create(params: CreateWebhookParams): Promise<Webhook> {\n return this.client.post<Webhook>(`/api/v2/webhook`, params);\n }\n\n /**\n * List all registered webhooks.\n */\n async list(): Promise<Webhook[]> {\n const res = await this.client.get(`/api/v2/webhook`);\n return res.data ?? res;\n }\n\n /**\n * Update a webhook's callback URL or secret.\n */\n async update(webhookId: string, params: UpdateWebhookParams): Promise<Webhook> {\n sanitizePathParam(webhookId, \"webhookId\");\n return this.client.put<Webhook>(`/api/v2/webhook/${webhookId}`, params);\n }\n\n /**\n * Delete a webhook.\n */\n async delete(webhookId: string): Promise<void> {\n sanitizePathParam(webhookId, \"webhookId\");\n await this.client.del(`/api/v2/webhook/${webhookId}`);\n }\n\n /**\n * Verify a webhook signature from an incoming request.\n * Throws if the signature is invalid.\n *\n * @param body The raw request body (string or Buffer)\n * @param signature The `X-Neutronpay-Signature` header value\n * @param secret Your webhook secret\n * @returns The parsed event payload\n *\n * @example\n * // Express\n * app.post(\"/webhooks/neutron\", express.raw({ type: \"application/json\" }), (req, res) => {\n * try {\n * const event = Neutron.webhooks.verifySignature(\n * req.body,\n * req.headers[\"x-neutronpay-signature\"],\n * \"my-webhook-secret\"\n * );\n * // event is verified and safe to use\n * if (event.txnState === \"completed\") fulfillOrder(event.extRefId);\n * } catch (err) {\n * return res.status(401).send(\"Invalid signature\");\n * }\n * res.status(200).send(\"OK\");\n * });\n */\n static verifySignature(\n body: string | Buffer,\n signature: string | undefined | null,\n secret: string\n ): any {\n if (!signature) {\n throw new NeutronValidationError(\"Missing webhook signature header (X-Neutronpay-Signature)\");\n }\n if (!secret) {\n throw new NeutronValidationError(\"Webhook secret is required for verification\");\n }\n\n const bodyStr = typeof body === \"string\" ? body : body.toString(\"utf8\");\n\n const expected = crypto\n .createHmac(\"sha256\", secret)\n .update(bodyStr)\n .digest(\"hex\");\n\n const sigBuf = Buffer.from(signature);\n const expBuf = Buffer.from(expected);\n const isValid = sigBuf.length === expBuf.length && crypto.timingSafeEqual(sigBuf, expBuf);\n\n if (!isValid) {\n throw new NeutronValidationError(\"Invalid webhook signature\");\n }\n\n return JSON.parse(bodyStr);\n }\n}\n","import type { HttpClient } from \"../client.js\";\nimport type { ExchangeRates } from \"../types.js\";\n\nexport class RatesResource {\n constructor(private readonly client: HttpClient) {}\n\n /**\n * Get current BTC exchange rates against all supported currencies.\n *\n * @example\n * const rates = await neutron.rates.get();\n * console.log(rates); // { BTCUSD: 97500, BTCVND: 2437500000, ... }\n */\n async get(): Promise<ExchangeRates> {\n const res = await this.client.get(`/api/v2/rate`);\n return res.data ?? res;\n }\n}\n","import type { HttpClient } from \"../client.js\";\nimport type { FiatInstitution, Transaction, SourceOfFunds } from \"../types.js\";\nimport { sanitizePathParam } from \"../sanitize.js\";\n\nexport interface FiatPayoutParams {\n /** Source currency (e.g. \"BTC\") */\n sourceCcy: string;\n /** Amount from source (in BTC for Bitcoin) */\n sourceAmount: number;\n /** Destination fiat currency (e.g. \"VND\") */\n destCcy: string;\n /** Payment method (e.g. \"vnd-instant\") */\n destMethod: string;\n /** Bank account number */\n bankAcctNum: string;\n /** Bank code from `neutron.fiat.institutions()` */\n institutionCode: string;\n /** Recipient legal full name */\n recipientName: string;\n /** Recipient country code (e.g. \"VN\") */\n countryCode: string;\n /** \"individual\" or \"business\" (default: \"individual\") */\n kycType?: \"individual\" | \"business\";\n /** Source of funds declaration */\n sourceOfFunds?: SourceOfFunds;\n /** Your reference ID */\n extRefId?: string;\n}\n\nexport class FiatResource {\n constructor(private readonly client: HttpClient) {}\n\n /**\n * List banks and financial institutions for a country.\n * Returns institution codes needed for fiat payouts.\n *\n * @example\n * const banks = await neutron.fiat.institutions(\"VN\");\n * // [{ code: \"970422\", name: \"MB Bank\" }, ...]\n */\n async institutions(countryCode: string): Promise<FiatInstitution[]> {\n sanitizePathParam(countryCode, \"countryCode\");\n const res = await this.client.get(\n `/api/v2/reference/fiat-institution/by-country/${countryCode}`\n );\n return res.data ?? res;\n }\n\n /**\n * Create a fiat payout transaction. Handles KYC and source of funds automatically.\n * Returns a quoted transaction — call `neutron.transactions.confirm()` to execute.\n *\n * @example\n * const txn = await neutron.fiat.payout({\n * sourceCcy: \"BTC\",\n * sourceAmount: 0.001,\n * destCcy: \"VND\",\n * destMethod: \"vnd-instant\",\n * bankAcctNum: \"0123456789\",\n * institutionCode: \"970422\",\n * recipientName: \"LE VAN A\",\n * countryCode: \"VN\",\n * });\n * // Review rate: txn.fxRate\n * await neutron.transactions.confirm(txn.txnId);\n */\n async payout(params: FiatPayoutParams): Promise<Transaction> {\n return this.client.post<Transaction>(`/api/v2/transaction`, {\n extRefId: params.extRefId,\n sourceReq: {\n ccy: params.sourceCcy,\n method: \"neutronpay\",\n amtRequested: params.sourceAmount,\n reqDetails: {},\n },\n destReq: {\n ccy: params.destCcy,\n method: params.destMethod,\n reqDetails: {\n bankAcctNum: params.bankAcctNum,\n institutionCode: params.institutionCode,\n },\n kyc: {\n type: params.kycType || \"individual\",\n details: {\n legalFullName: params.recipientName,\n countryCode: params.countryCode,\n },\n },\n },\n sourceOfFunds: params.sourceOfFunds ?? {\n purpose: 1,\n source: 5,\n relationship: 3,\n },\n });\n }\n}\n","// ── Satoshi / BTC conversion ────────────────────────────────\n\nconst SATS_PER_BTC = 100_000_000;\n\n/**\n * Convert satoshis to BTC.\n * @example satsToBtc(10000) // 0.0001\n */\nexport function satsToBtc(sats: number): number {\n return sats / SATS_PER_BTC;\n}\n\n/**\n * Convert BTC to satoshis.\n * @example btcToSats(0.0001) // 10000\n */\nexport function btcToSats(btc: number): number {\n return Math.round(btc * SATS_PER_BTC);\n}\n\n/**\n * Format a satoshi amount as a human-readable string.\n * @example formatSats(1500000) // \"1,500,000 sats\"\n * @example formatSats(100) // \"100 sats\"\n */\nexport function formatSats(sats: number): string {\n return `${sats.toLocaleString(\"en-US\")} sats`;\n}\n\n/**\n * Format a BTC amount with appropriate precision.\n * @example formatBtc(0.00015) // \"0.00015000 BTC\"\n */\nexport function formatBtc(btc: number): string {\n return `${btc.toFixed(8)} BTC`;\n}\n\n// ── Constants ───────────────────────────────────────────────\n\n/** Supported currencies */\nexport const Currency = {\n BTC: \"BTC\",\n USDT: \"USDT\",\n VND: \"VND\",\n USD: \"USD\",\n CAD: \"CAD\",\n NGN: \"NGN\",\n KES: \"KES\",\n GHS: \"GHS\",\n} as const;\n\nexport type Currency = (typeof Currency)[keyof typeof Currency];\n\n/** Payment methods for sourceReq/destReq */\nexport const PaymentMethod = {\n /** Internal Neutron wallet */\n NEUTRON: \"neutronpay\",\n /** Lightning Network (BOLT11 invoices) */\n LIGHTNING: \"lightning\",\n /** Lightning Address / LNURL */\n LNURL: \"lnurl\",\n /** Bitcoin on-chain */\n ON_CHAIN: \"on-chain\",\n /** USDT on TRON (TRC-20) */\n TRON: \"tron\",\n /** USDT on Ethereum (ERC-20) */\n ETH: \"eth\",\n /** Vietnamese Dong instant bank transfer */\n VND_INSTANT: \"vnd-instant\",\n} as const;\n\nexport type PaymentMethodType = (typeof PaymentMethod)[keyof typeof PaymentMethod];\n\n/** Transaction final states (terminal — won't change) */\nexport const FinalStates = [\n \"completed\",\n \"expired\",\n \"rejected\",\n \"error\",\n \"usercanceled\",\n] as const;\n\n/** All transaction states */\nexport const TransactionStates = {\n QUOTED: \"quoted\",\n USER_CONFIRMED: \"userconfirmed\",\n SRC_CREATED: \"srccreated\",\n SRC_SENT: \"srcsent\",\n SRC_INTENT: \"srcintent\",\n SRC_PEND_CONFIRM: \"srcpendconfirmfill\",\n SRC_CONFIRMED: \"srcconfirmfilled\",\n DEST_PEND_SENT: \"destpendsent\",\n DEST_SENT: \"destsent\",\n COMPLETED: \"completed\",\n EXPIRED: \"expired\",\n REJECTED: \"rejected\",\n ERROR: \"error\",\n USER_CANCELED: \"usercanceled\",\n} as const;\n\n/** USDT blockchain options */\nexport const Chain = {\n TRON: \"TRON\",\n ETH: \"ETH\",\n} as const;\n","import { HttpClient } from \"./client.js\";\nimport { AccountResource } from \"./resources/account.js\";\nimport { TransactionsResource } from \"./resources/transactions.js\";\nimport { LightningResource } from \"./resources/lightning.js\";\nimport { WebhooksResource } from \"./resources/webhooks.js\";\nimport { RatesResource } from \"./resources/rates.js\";\nimport { FiatResource } from \"./resources/fiat.js\";\nimport type { NeutronConfig } from \"./types.js\";\n\n/**\n * Neutron SDK — Bitcoin Lightning, stablecoins, and fiat payments.\n *\n * @example\n * import { Neutron } from \"neutron-sdk\";\n *\n * const neutron = new Neutron({\n * apiKey: process.env.NEUTRON_API_KEY!,\n * apiSecret: process.env.NEUTRON_API_SECRET!,\n * });\n *\n * // Check balances\n * const wallets = await neutron.account.wallets();\n *\n * // Create a Lightning invoice\n * const invoice = await neutron.lightning.createInvoice({ amountSats: 10000 });\n *\n * // Send to a Lightning Address\n * const txn = await neutron.lightning.payAddress(\"alice@getalby.com\", { amountSats: 5000 });\n * await neutron.transactions.confirm(txn.txnId);\n */\nexport class Neutron {\n /** Account info, wallets, and deposit addresses */\n readonly account: AccountResource;\n /** Create, confirm, list, and track transactions */\n readonly transactions: TransactionsResource;\n /** Lightning invoices, payments, and utilities */\n readonly lightning: LightningResource;\n /** Webhook management */\n readonly webhooks: WebhooksResource;\n /** BTC exchange rates */\n readonly rates: RatesResource;\n /** Fiat payouts and bank lookups */\n readonly fiat: FiatResource;\n\n private readonly client: HttpClient;\n\n constructor(config: NeutronConfig) {\n this.client = new HttpClient(config);\n this.account = new AccountResource(this.client);\n this.transactions = new TransactionsResource(this.client);\n this.lightning = new LightningResource(this.client);\n this.webhooks = new WebhooksResource(this.client);\n this.rates = new RatesResource(this.client);\n this.fiat = new FiatResource(this.client);\n }\n\n /**\n * Explicitly authenticate and verify credentials.\n * Usually not needed — the SDK auto-authenticates on first request.\n */\n async authenticate() {\n return this.client.authenticate();\n }\n\n /**\n * Verify a webhook signature. Static method — no client instance needed.\n *\n * @example\n * const event = Neutron.verifyWebhook(req.body, req.headers[\"x-neutronpay-signature\"], secret);\n */\n static verifyWebhook(body: string | Buffer, signature: string | undefined | null, secret: string) {\n return WebhooksResource.verifySignature(body, signature, secret);\n }\n}\n\n// ── Exports ─────────────────────────────────────────────────\n\nexport { HttpClient } from \"./client.js\";\nexport { AccountResource } from \"./resources/account.js\";\nexport { TransactionsResource } from \"./resources/transactions.js\";\nexport { LightningResource } from \"./resources/lightning.js\";\nexport { WebhooksResource } from \"./resources/webhooks.js\";\nexport { RatesResource } from \"./resources/rates.js\";\nexport { FiatResource } from \"./resources/fiat.js\";\nexport type { FiatPayoutParams } from \"./resources/fiat.js\";\n\nexport { sanitizePathParam } from \"./sanitize.js\";\n\nexport {\n NeutronError,\n NeutronApiError,\n NeutronAuthError,\n NeutronTimeoutError,\n NeutronValidationError,\n} from \"./errors.js\";\n\nexport {\n satsToBtc,\n btcToSats,\n formatSats,\n formatBtc,\n Currency,\n PaymentMethod,\n TransactionStates,\n FinalStates,\n Chain,\n} from \"./utils.js\";\n\nexport type {\n Currency as CurrencyType,\n PaymentMethodType,\n} from \"./utils.js\";\n\nexport type {\n NeutronConfig,\n AuthResponse,\n Account,\n Wallet,\n Transaction,\n TransactionState,\n TransactionSide,\n PaymentMethod as PaymentMethodString,\n CreateTransactionRequest,\n ListTransactionsParams,\n CreateInvoiceParams,\n LightningInvoice,\n BtcAddress,\n UsdtAddress,\n Webhook,\n CreateWebhookParams,\n UpdateWebhookParams,\n ExchangeRates,\n FiatInstitution,\n KycInfo,\n SourceOfFunds,\n ApiResponse,\n} from \"./types.js\";\n"],"mappings":"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","names":["crypto","crypto"]}
|
|
1
|
+
{"version":3,"sources":["../src/client.ts","../src/errors.ts","../src/sanitize.ts","../src/resources/account.ts","../src/resources/transactions.ts","../src/resources/lightning.ts","../src/resources/webhooks.ts","../src/resources/rates.ts","../src/resources/fiat.ts","../src/utils.ts","../src/index.ts"],"sourcesContent":["import crypto from \"crypto\";\nimport type { NeutronConfig, AuthResponse } from \"./types.js\";\nimport {\n NeutronApiError,\n NeutronAuthError,\n NeutronTimeoutError,\n} from \"./errors.js\";\n\nconst DEFAULT_BASE_URL = \"https://api.neutron.me\";\nconst DEFAULT_TIMEOUT = 30_000;\nconst DEFAULT_MAX_RETRIES = 2;\nconst TOKEN_REFRESH_BUFFER_MS = 60_000; // refresh 1 min before expiry\n\nexport class HttpClient {\n private readonly apiKey: string;\n private readonly apiSecret: string;\n readonly baseUrl: string;\n private readonly timeout: number;\n private readonly maxRetries: number;\n private readonly debug: boolean;\n\n private accessToken: string | null = null;\n private accountId: string | null = null;\n private tokenExpiry: number = 0;\n\n constructor(config: NeutronConfig) {\n if (!config.apiKey) throw new NeutronAuthError(\"apiKey is required\");\n if (!config.apiSecret) throw new NeutronAuthError(\"apiSecret is required\");\n\n this.apiKey = config.apiKey;\n this.apiSecret = config.apiSecret;\n this.baseUrl = (config.baseUrl || DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this.timeout = config.timeout ?? DEFAULT_TIMEOUT;\n this.maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES;\n this.debug = config.debug ?? false;\n }\n\n private log(message: string, data?: any): void {\n if (!this.debug) return;\n const ts = new Date().toISOString();\n const extra = data ? ` ${JSON.stringify(data)}` : \"\";\n console.error(`[neutron-sdk ${ts}] ${message}${extra}`);\n }\n\n // ── Auth ──────────────────────────────────────────────\n\n private generateSignature(payload: string): string {\n const stringToSign = `${this.apiKey}&payload=${payload}`;\n return crypto\n .createHmac(\"sha256\", this.apiSecret)\n .update(stringToSign)\n .digest(\"hex\");\n }\n\n private get isTokenValid(): boolean {\n return !!(\n this.accessToken &&\n this.accountId &&\n Date.now() < this.tokenExpiry - TOKEN_REFRESH_BUFFER_MS\n );\n }\n\n async authenticate(): Promise<AuthResponse> {\n const payload = JSON.stringify({ test: \"auth\" });\n const signature = this.generateSignature(payload);\n\n const response = await this.rawFetch(\n `${this.baseUrl}/api/v2/authentication/token-signature`,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Api-Key\": this.apiKey,\n \"X-Api-Signature\": signature,\n },\n body: payload,\n }\n );\n\n if (!response.ok) {\n const body = (await response.json().catch(() => ({}))) as Record<string, any>;\n throw new NeutronAuthError(\n body.error || body.message || `Authentication failed (${response.status})`\n );\n }\n\n const raw = (await response.json()) as any;\n // API wraps auth response in { data: { ... } }\n const result: AuthResponse = raw.data ?? raw;\n this.accountId = result.accountId;\n this.accessToken = result.accessToken;\n this.tokenExpiry = typeof result.expiredAt === \"number\"\n ? result.expiredAt\n : new Date(result.expiredAt).getTime();\n\n return result;\n this.log(\"Authenticated\", { accountId: this.accountId });\n }\n\n private async ensureAuth(): Promise<void> {\n if (!this.isTokenValid) {\n await this.authenticate();\n }\n }\n\n getAccountId(): string {\n if (!this.accountId) {\n throw new NeutronAuthError(\"Not authenticated. Call a method first or use neutron.account.get().\");\n }\n return this.accountId;\n }\n\n async ensureAuthAndGetAccountId(): Promise<string> {\n await this.ensureAuth();\n return this.accountId!;\n }\n\n /**\n * Returns auth headers for use in raw fetch calls (e.g. SSE streams).\n * Ensures a valid token is present before returning.\n */\n async getAuthHeaders(): Promise<Record<string, string>> {\n await this.ensureAuth();\n return {\n Authorization: `Bearer ${this.accessToken}`,\n };\n }\n\n // ── HTTP ──────────────────────────────────────────────\n\n private async rawFetch(url: string, init: RequestInit): Promise<Response> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n return await fetch(url, { ...init, signal: controller.signal });\n } catch (err: any) {\n if (err.name === \"AbortError\") {\n throw new NeutronTimeoutError(this.timeout);\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n }\n\n async request<T = any>(method: string, path: string, body?: any): Promise<T> {\n await this.ensureAuth();\n\n let lastError: any;\n\n for (let attempt = 0; attempt <= this.maxRetries; attempt++) {\n if (attempt > 0) {\n // Exponential backoff: 1s, 2s, 4s...\n await new Promise((r) => setTimeout(r, Math.pow(2, attempt - 1) * 1000));\n\n // Re-auth if token might have expired during retries\n if (!this.isTokenValid) await this.authenticate();\n }\n\n const url = `${this.baseUrl}${path}`;\n this.log(`${method} ${path}`);\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.accessToken}`,\n \"Content-Type\": \"application/json\",\n };\n\n const response = await this.rawFetch(url, {\n method,\n headers,\n body: body ? JSON.stringify(body) : undefined,\n });\n\n if (response.ok) {\n return (await response.json()) as T;\n }\n\n const errorBody = await response.json().catch(() => ({}));\n const apiError = new NeutronApiError(response.status, errorBody);\n\n // Re-authenticate on 401 and retry\n if (response.status === 401 && attempt < this.maxRetries) {\n this.accessToken = null;\n lastError = apiError;\n continue;\n }\n\n // Retry on 5xx and 429\n if (apiError.isRetryable && attempt < this.maxRetries) {\n lastError = apiError;\n continue;\n }\n\n throw apiError;\n }\n\n throw lastError;\n }\n\n async get<T = any>(path: string): Promise<T> {\n return this.request<T>(\"GET\", path);\n }\n\n async post<T = any>(path: string, body?: any): Promise<T> {\n return this.request<T>(\"POST\", path, body);\n }\n\n async put<T = any>(path: string, body?: any): Promise<T> {\n return this.request<T>(\"PUT\", path, body);\n }\n\n async del<T = any>(path: string): Promise<T> {\n return this.request<T>(\"DELETE\", path);\n }\n}\n","/**\n * Base error for all Neutron SDK errors.\n */\nexport class NeutronError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"NeutronError\";\n }\n}\n\n/**\n * Thrown when the API returns an error response (4xx/5xx).\n */\nexport class NeutronApiError extends NeutronError {\n /** HTTP status code */\n readonly status: number;\n /** Neutron error code (e.g. \"2005\") */\n readonly code: string | undefined;\n /** Raw error body from the API */\n readonly body: any;\n\n constructor(status: number, body: any) {\n const message = body?.error || body?.message || `API error ${status}`;\n super(message);\n this.name = \"NeutronApiError\";\n this.status = status;\n this.code = body?.code;\n this.body = body;\n }\n\n /** True if this is a rate limit error (429) */\n get isRateLimited(): boolean {\n return this.status === 429;\n }\n\n /** True if this is an auth error (401/403) */\n get isAuthError(): boolean {\n return this.status === 401 || this.status === 403;\n }\n\n /** True if retrying might help (5xx, 429) */\n get isRetryable(): boolean {\n return this.status === 429 || this.status >= 500;\n }\n}\n\n/**\n * Thrown when authentication fails.\n */\nexport class NeutronAuthError extends NeutronError {\n constructor(message: string = \"Authentication failed. Check your API key and secret.\") {\n super(message);\n this.name = \"NeutronAuthError\";\n }\n}\n\n/**\n * Thrown when a request times out.\n */\nexport class NeutronTimeoutError extends NeutronError {\n constructor(timeoutMs: number) {\n super(`Request timed out after ${timeoutMs}ms`);\n this.name = \"NeutronTimeoutError\";\n }\n}\n\n/**\n * Thrown for SDK usage errors (bad params, missing fields).\n */\nexport class NeutronValidationError extends NeutronError {\n constructor(message: string) {\n super(message);\n this.name = \"NeutronValidationError\";\n }\n}\n","import { NeutronValidationError } from \"./errors.js\";\n\n/**\n * Sanitize a path parameter to prevent path traversal and injection.\n * Only allows alphanumeric characters, hyphens, underscores, and dots.\n */\nexport function sanitizePathParam(value: string, name: string): string {\n if (!value || typeof value !== \"string\") {\n throw new NeutronValidationError(`${name} is required and must be a non-empty string.`);\n }\n\n // Strip any path traversal or special characters\n const sanitized = value.replace(/[^a-zA-Z0-9\\-_.]/g, \"\");\n\n if (sanitized !== value) {\n throw new NeutronValidationError(\n `${name} contains invalid characters. Only alphanumeric, hyphens, underscores, and dots are allowed.`\n );\n }\n\n if (sanitized.includes(\"..\")) {\n throw new NeutronValidationError(`${name} cannot contain path traversal sequences.`);\n }\n\n return sanitized;\n}\n","import type { HttpClient } from \"../client.js\";\nimport type { Account, Wallet } from \"../types.js\";\nimport { sanitizePathParam } from \"../sanitize.js\";\n\nexport class AccountResource {\n constructor(private readonly client: HttpClient) {}\n\n /**\n * Get account info: display name, status, country, timezone.\n */\n async get(): Promise<Account> {\n const accountId = await this.client.ensureAuthAndGetAccountId();\n const res = await this.client.get(`/api/v2/account/${accountId}`);\n return (res.data ?? res) as Account;\n }\n\n /**\n * List all wallets with balances (BTC, USDT, fiat).\n */\n async wallets(): Promise<Wallet[]> {\n const accountId = await this.client.ensureAuthAndGetAccountId();\n const res = await this.client.get(`/api/v2/account/${accountId}/wallet/`);\n return res.data ?? res;\n }\n\n /**\n * Get a specific wallet by ID.\n */\n async wallet(walletId: string): Promise<Wallet> {\n sanitizePathParam(walletId, \"walletId\");\n const accountId = await this.client.ensureAuthAndGetAccountId();\n const res = await this.client.get(`/api/v2/account/${accountId}/wallet/${walletId}`);\n return (res.data ?? res) as Wallet;\n }\n\n /**\n * Get your Bitcoin on-chain deposit address (static, reusable).\n */\n async btcAddress(): Promise<{ address: string }> {\n const raw = await this.client.get(`/api/v2/account/onchain-address`);\n const data = raw?.data ?? raw;\n return { address: data.staticOnchainAddress };\n }\n\n /**\n * Get your USDT deposit address.\n * @param chain \"TRON\" (default, recommended) or \"ETH\"\n */\n async usdtAddress(chain: \"TRON\" | \"ETH\" = \"TRON\"): Promise<{ address: string; chain: string }> {\n const raw = await this.client.get(\n `/api/v2/account/stablecoin-onchain-address?walletCcy=USDT&chainId=${chain}`\n );\n const data = raw?.data ?? raw;\n return {\n address: data.staticStablecoinOnchainAddress || data.staticOnchainAddress,\n chain,\n };\n }\n}\n","import type { HttpClient } from \"../client.js\";\nimport type {\n Transaction,\n CreateTransactionRequest,\n ListTransactionsParams,\n TransactionEvent,\n} from \"../types.js\";\nimport { sanitizePathParam } from \"../sanitize.js\";\n\nexport class TransactionsResource {\n constructor(private readonly client: HttpClient) {}\n\n /**\n * Create a transaction (returns a quote). Call `.confirm()` to execute.\n *\n * @example\n * // Lightning receive (create invoice)\n * const txn = await neutron.transactions.create({\n * sourceReq: { ccy: \"BTC\", method: \"lightning\", reqDetails: {} },\n * destReq: { ccy: \"BTC\", method: \"neutronpay\", amtRequested: 0.0001, reqDetails: {} },\n * });\n *\n * @example\n * // Lightning send (pay invoice)\n * const txn = await neutron.transactions.create({\n * sourceReq: { ccy: \"BTC\", method: \"neutronpay\" },\n * destReq: { ccy: \"BTC\", method: \"lightning\", reqDetails: { paymentRequest: \"lnbc...\" } },\n * });\n *\n * @example\n * // Internal swap (BTC → USDT)\n * const txn = await neutron.transactions.create({\n * sourceReq: { ccy: \"BTC\", method: \"neutronpay\", amtRequested: 0.001, reqDetails: {} },\n * destReq: { ccy: \"USDT\", method: \"neutronpay\", reqDetails: {} },\n * });\n */\n async create(params: CreateTransactionRequest): Promise<Transaction> {\n return this.client.post<Transaction>(`/api/v2/transaction`, params);\n }\n\n /**\n * Confirm a quoted transaction to execute it.\n * After confirmation, Lightning invoices become payable and sends are dispatched.\n */\n async confirm(txnId: string): Promise<Transaction> {\n sanitizePathParam(txnId, \"txnId\");\n return this.client.put<Transaction>(`/api/v2/transaction/${txnId}/confirm`);\n }\n\n /**\n * Get transaction status and details.\n */\n async get(txnId: string): Promise<Transaction> {\n sanitizePathParam(txnId, \"txnId\");\n return this.client.get<Transaction>(`/api/v2/transaction/${txnId}`);\n }\n\n /**\n * List transactions with optional filters.\n *\n * @example\n * const completed = await neutron.transactions.list({ status: \"completed\", limit: 10 });\n */\n async list(params?: ListTransactionsParams): Promise<Transaction[]> {\n const qs = new URLSearchParams();\n if (params) {\n for (const [k, v] of Object.entries(params)) {\n if (v !== undefined && v !== null) qs.append(k, String(v));\n }\n }\n const query = qs.toString();\n const res = await this.client.get(`/api/v2/transaction${query ? `?${query}` : \"\"}`);\n return res.data ?? res;\n }\n\n /**\n * Cancel a quoted (unconfirmed) transaction.\n *\n * @deprecated This endpoint is not currently available on the Neutron API.\n * Unconfirmed transactions expire automatically after their TTL.\n */\n async cancel(_txnId: string): Promise<Transaction> {\n throw new Error(\n \"transactions.cancel() is not available. Unconfirmed transactions expire automatically.\"\n );\n }\n\n /**\n * Wait for a transaction to reach a final state. Polls at the given interval.\n *\n * @param txnId Transaction ID\n * @param options.intervalMs Polling interval in ms (default: 3000)\n * @param options.timeoutMs Max wait time in ms (default: 300000 = 5 min)\n * @param options.onStateChange Callback fired on each state change\n * @returns The transaction in a final state\n *\n * @example\n * const txn = await neutron.transactions.waitForCompletion(txnId, {\n * onStateChange: (state) => console.log(\"State:\", state),\n * });\n */\n async waitForCompletion(\n txnId: string,\n options?: {\n intervalMs?: number;\n timeoutMs?: number;\n onStateChange?: (state: string, txn: Transaction) => void;\n }\n ): Promise<Transaction> {\n const FINAL_STATES = [\"completed\", \"failed\", \"expired\", \"rejected\", \"error\", \"usercanceled\"];\n const interval = options?.intervalMs ?? 3000;\n const timeout = options?.timeoutMs ?? 300_000;\n const start = Date.now();\n let lastState = \"\";\n\n while (Date.now() - start < timeout) {\n const txn = await this.get(txnId);\n\n if (txn.txnState !== lastState) {\n lastState = txn.txnState;\n options?.onStateChange?.(txn.txnState, txn);\n }\n\n if (FINAL_STATES.includes(txn.txnState)) {\n return txn;\n }\n\n await new Promise((r) => setTimeout(r, interval));\n }\n\n throw new Error(`Transaction ${txnId} did not complete within ${timeout}ms`);\n }\n\n /**\n * Stream real-time transaction status updates via SSE.\n * For agents without a public endpoint who can't receive webhook POSTs.\n *\n * NOTE: Requires the server-side endpoint /api/v2/events/stream (not yet live).\n * Use neutron.transactions.waitForCompletion() as a polling fallback in the meantime.\n *\n * @example\n * for await (const event of neutron.transactions.subscribe(\"txn-123\")) {\n * console.log(event.status);\n * if (event.status === \"completed\") break;\n * }\n */\n async *subscribe(transactionId: string, timeoutMs = 60_000): AsyncGenerator<TransactionEvent> {\n // SECURITY: sanitize input — consistent with all other resource methods\n sanitizePathParam(transactionId, \"transactionId\");\n\n // SECURITY: validate transactionId is a UUID to prevent SSRF/path traversal\n const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n if (!UUID_RE.test(transactionId)) {\n throw new Error(\"Invalid transactionId: must be a UUID.\");\n }\n\n // SECURITY: clamp timeout to 5s–300s to prevent resource exhaustion\n const clampedTimeout = Math.min(Math.max(timeoutMs, 5_000), 300_000);\n\n // SECURITY: encodeURIComponent — UUID chars are safe but be explicit\n const url = `${this.client.baseUrl}/api/v2/events/stream?transactionId=${encodeURIComponent(transactionId)}`;\n const response = await fetch(url, {\n headers: {\n \"Accept\": \"text/event-stream\",\n ...(await this.client.getAuthHeaders()),\n },\n signal: AbortSignal.timeout(clampedTimeout),\n });\n\n if (!response.ok || !response.body) {\n throw new Error(`SSE connection failed: ${response.status} ${response.statusText}`);\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n const MAX_BUFFER = 64 * 1024; // 64KB — prevent OOM from malformed stream\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n\n // SECURITY: abort on unbounded buffer growth\n if (buffer.length > MAX_BUFFER) {\n throw new Error(\"SSE buffer overflow — server sent malformed stream.\");\n }\n\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() || \"\";\n for (const line of lines) {\n if (line.startsWith(\"data: \")) {\n try {\n yield JSON.parse(line.slice(6)) as TransactionEvent;\n } catch (parseErr) {\n // Log malformed SSE data but keep the stream alive\n console.error(\"[neutron-sdk] SSE parse error:\", parseErr);\n }\n }\n }\n }\n } finally {\n reader.cancel();\n }\n }\n}\n","import type { HttpClient } from \"../client.js\";\nimport type {\n CreateInvoiceParams,\n DecodedInvoice,\n LightningInvoice,\n Transaction,\n} from \"../types.js\";\nimport { NeutronValidationError } from \"../errors.js\";\n\nexport class LightningResource {\n constructor(private readonly client: HttpClient) {}\n\n /**\n * Create a Lightning invoice to receive Bitcoin. Auto-confirms — ready to pay immediately.\n *\n * @example\n * const invoice = await neutron.lightning.createInvoice({ amountSats: 10000 });\n * console.log(invoice.invoice); // \"lnbc100u1p...\"\n * console.log(invoice.qrPageUrl); // hosted QR code page\n *\n * @example\n * const invoice = await neutron.lightning.createInvoice({\n * amountBtc: 0.001,\n * memo: \"Order #1234\",\n * extRefId: \"order-1234\",\n * });\n */\n async createInvoice(params: CreateInvoiceParams): Promise<LightningInvoice> {\n let btcAmount: number;\n\n if (params.amountSats !== undefined && params.amountBtc !== undefined) {\n throw new NeutronValidationError(\"Provide either amountSats or amountBtc, not both.\");\n }\n if (params.amountSats !== undefined) {\n if (params.amountSats <= 0) throw new NeutronValidationError(\"amountSats must be positive.\");\n btcAmount = params.amountSats / 100_000_000;\n } else if (params.amountBtc !== undefined) {\n if (params.amountBtc <= 0) throw new NeutronValidationError(\"amountBtc must be positive.\");\n btcAmount = params.amountBtc;\n } else {\n throw new NeutronValidationError(\"Provide either amountSats or amountBtc.\");\n }\n\n // Create\n const txn = await this.client.post<Transaction>(`/api/v2/transaction`, {\n extRefId: params.extRefId,\n sourceReq: { ccy: \"BTC\", method: \"lightning\", reqDetails: {} },\n destReq: {\n ccy: \"BTC\",\n method: \"neutronpay\",\n amtRequested: btcAmount,\n reqDetails: {},\n },\n });\n\n // Auto-confirm\n const confirmed = await this.client.put<Transaction>(\n `/api/v2/transaction/${txn.txnId}/confirm`\n );\n\n return {\n txnId: confirmed.txnId,\n invoice: confirmed.sourceReq?.reqDetails?.paymentRequest ?? \"\",\n qrPageUrl: confirmed.sourceReq?.reqDetails?.invoicePageUrl,\n amountBtc: btcAmount,\n amountSats: Math.round(btcAmount * 100_000_000),\n status: confirmed.txnState,\n };\n }\n\n /**\n * Pay a Lightning invoice (BOLT11).\n * Returns a quoted transaction — call `neutron.transactions.confirm()` to send.\n *\n * @example\n * const txn = await neutron.lightning.payInvoice(\"lnbc100u1p...\");\n * // Review fees: txn.sourceReq.neutronpayFees\n * await neutron.transactions.confirm(txn.txnId);\n */\n async payInvoice(invoice: string, extRefId?: string): Promise<Transaction> {\n return this.client.post<Transaction>(`/api/v2/transaction`, {\n extRefId,\n sourceReq: { ccy: \"BTC\", method: \"neutronpay\" },\n destReq: {\n ccy: \"BTC\",\n method: \"lightning\",\n reqDetails: { paymentRequest: invoice },\n },\n });\n }\n\n /**\n * Send to a Lightning Address (user@domain.com).\n * Returns a quoted transaction — call `neutron.transactions.confirm()` to send.\n *\n * @example\n * const txn = await neutron.lightning.payAddress(\"alice@getalby.com\", { amountSats: 5000 });\n * await neutron.transactions.confirm(txn.txnId);\n */\n async payAddress(\n address: string,\n params: { amountSats?: number; amountBtc?: number; extRefId?: string }\n ): Promise<Transaction> {\n let btcAmount: number;\n if (params.amountSats !== undefined) {\n btcAmount = params.amountSats / 100_000_000;\n } else if (params.amountBtc !== undefined) {\n btcAmount = params.amountBtc;\n } else {\n throw new NeutronValidationError(\"Provide either amountSats or amountBtc.\");\n }\n\n return this.client.post<Transaction>(`/api/v2/transaction`, {\n extRefId: params.extRefId,\n sourceReq: { ccy: \"BTC\", method: \"neutronpay\", amtRequested: btcAmount },\n destReq: {\n ccy: \"BTC\",\n method: \"lnurl\",\n reqDetails: { address },\n },\n });\n }\n\n /**\n * Decode a Lightning invoice (BOLT11) to inspect amount, description, etc.\n * Useful for showing users what they're about to pay before confirming.\n *\n * @example\n * const decoded = await neutron.lightning.decodeInvoice(\"lnbc100u1p...\");\n * console.log(decoded.amount); // 0.001 (BTC)\n * console.log(decoded.description); // \"Coffee payment\"\n */\n async decodeInvoice(invoice: string): Promise<DecodedInvoice> {\n const result = await this.client.post<{ invoice: DecodedInvoice }>(\n `/api/v2/decode/lightning`,\n { paymentRequest: invoice }\n );\n return result.invoice;\n }\n\n}\n","import crypto from \"crypto\";\nimport type { HttpClient } from \"../client.js\";\nimport type { Webhook, CreateWebhookParams, UpdateWebhookParams } from \"../types.js\";\nimport { NeutronValidationError } from \"../errors.js\";\nimport { sanitizePathParam } from \"../sanitize.js\";\n\nexport class WebhooksResource {\n constructor(private readonly client: HttpClient) {}\n\n /**\n * Register a webhook to receive transaction state change notifications.\n *\n * @example\n * const webhook = await neutron.webhooks.create({\n * callback: \"https://myapp.com/webhooks/neutron\",\n * secret: \"my-webhook-secret\",\n * });\n */\n async create(params: CreateWebhookParams): Promise<Webhook> {\n return this.client.post<Webhook>(`/api/v2/webhook`, params);\n }\n\n /**\n * List all registered webhooks.\n */\n async list(): Promise<Webhook[]> {\n const res = await this.client.get(`/api/v2/webhook`);\n return res.data ?? res;\n }\n\n /**\n * Update a webhook's callback URL or secret.\n */\n async update(webhookId: string, params: UpdateWebhookParams): Promise<Webhook> {\n sanitizePathParam(webhookId, \"webhookId\");\n return this.client.put<Webhook>(`/api/v2/webhook/${webhookId}`, params);\n }\n\n /**\n * Delete a webhook.\n */\n async delete(webhookId: string): Promise<void> {\n sanitizePathParam(webhookId, \"webhookId\");\n await this.client.del(`/api/v2/webhook/${webhookId}`);\n }\n\n /**\n * Verify a webhook signature from an incoming request.\n * Throws if the signature is invalid.\n *\n * @param body The raw request body (string or Buffer)\n * @param signature The `X-Neutronpay-Signature` header value\n * @param secret Your webhook secret\n * @returns The parsed event payload\n *\n * @example\n * // Express\n * app.post(\"/webhooks/neutron\", express.raw({ type: \"application/json\" }), (req, res) => {\n * try {\n * const event = Neutron.webhooks.verifySignature(\n * req.body,\n * req.headers[\"x-neutronpay-signature\"],\n * \"my-webhook-secret\"\n * );\n * // event is verified and safe to use\n * if (event.txnState === \"completed\") fulfillOrder(event.extRefId);\n * } catch (err) {\n * return res.status(401).send(\"Invalid signature\");\n * }\n * res.status(200).send(\"OK\");\n * });\n */\n static verifySignature(\n body: string | Buffer,\n signature: string | undefined | null,\n secret: string\n ): any {\n if (!signature) {\n throw new NeutronValidationError(\"Missing webhook signature header (X-Neutronpay-Signature)\");\n }\n if (!secret) {\n throw new NeutronValidationError(\"Webhook secret is required for verification\");\n }\n\n const bodyStr = typeof body === \"string\" ? body : body.toString(\"utf8\");\n\n const expected = crypto\n .createHmac(\"sha256\", secret)\n .update(bodyStr)\n .digest(\"hex\");\n\n const sigBuf = Buffer.from(signature);\n const expBuf = Buffer.from(expected);\n const isValid = sigBuf.length === expBuf.length && crypto.timingSafeEqual(sigBuf, expBuf);\n\n if (!isValid) {\n throw new NeutronValidationError(\"Invalid webhook signature\");\n }\n\n return JSON.parse(bodyStr);\n }\n}\n","import type { HttpClient } from \"../client.js\";\nimport type { ExchangeRates } from \"../types.js\";\n\nexport class RatesResource {\n constructor(private readonly client: HttpClient) {}\n\n /**\n * Get current BTC exchange rates against all supported currencies.\n *\n * @example\n * const rates = await neutron.rates.get();\n * console.log(rates); // { BTCUSD: 97500, BTCVND: 2437500000, ... }\n */\n async get(): Promise<ExchangeRates> {\n const res = await this.client.get(`/api/v2/rate`);\n return res.data ?? res;\n }\n}\n","import type { HttpClient } from \"../client.js\";\nimport type { FiatInstitution, Transaction, SourceOfFunds } from \"../types.js\";\nimport { sanitizePathParam } from \"../sanitize.js\";\n\nexport interface FiatPayoutParams {\n /** Source currency (e.g. \"BTC\") */\n sourceCcy: string;\n /** Amount from source (in BTC for Bitcoin) */\n sourceAmount: number;\n /** Destination fiat currency (e.g. \"VND\") */\n destCcy: string;\n /** Payment method (e.g. \"vnd-instant\") */\n destMethod: string;\n /** Bank account number */\n bankAcctNum: string;\n /** Bank code from `neutron.fiat.institutions()` */\n institutionCode: string;\n /** Recipient legal full name */\n recipientName: string;\n /** Recipient country code (e.g. \"VN\") */\n countryCode: string;\n /** \"individual\" or \"business\" (default: \"individual\") */\n kycType?: \"individual\" | \"business\";\n /** Source of funds declaration */\n sourceOfFunds?: SourceOfFunds;\n /** Your reference ID */\n extRefId?: string;\n}\n\nexport class FiatResource {\n constructor(private readonly client: HttpClient) {}\n\n /**\n * List banks and financial institutions for a country.\n * Returns institution codes needed for fiat payouts.\n *\n * @example\n * const banks = await neutron.fiat.institutions(\"VN\");\n * // [{ code: \"970422\", name: \"MB Bank\" }, ...]\n */\n async institutions(countryCode: string): Promise<FiatInstitution[]> {\n sanitizePathParam(countryCode, \"countryCode\");\n const res = await this.client.get(\n `/api/v2/reference/fiat-institution/by-country/${countryCode}`\n );\n return res.data ?? res;\n }\n\n /**\n * Create a fiat payout transaction. KYC is required only for fiat payouts — not for\n * Bitcoin, stablecoins, or swaps. Handles KYC and source of funds automatically.\n * Returns a quoted transaction — call `neutron.transactions.confirm()` to execute.\n *\n * @example\n * const txn = await neutron.fiat.payout({\n * sourceCcy: \"BTC\",\n * sourceAmount: 0.001,\n * destCcy: \"VND\",\n * destMethod: \"vnd-instant\",\n * bankAcctNum: \"0123456789\",\n * institutionCode: \"970422\",\n * recipientName: \"LE VAN A\",\n * countryCode: \"VN\",\n * });\n * // Review rate: txn.fxRate\n * await neutron.transactions.confirm(txn.txnId);\n */\n async payout(params: FiatPayoutParams): Promise<Transaction> {\n return this.client.post<Transaction>(`/api/v2/transaction`, {\n extRefId: params.extRefId,\n sourceReq: {\n ccy: params.sourceCcy,\n method: \"neutronpay\",\n amtRequested: params.sourceAmount,\n reqDetails: {},\n },\n destReq: {\n ccy: params.destCcy,\n method: params.destMethod,\n reqDetails: {\n bankAcctNum: params.bankAcctNum,\n institutionCode: params.institutionCode,\n },\n kyc: {\n type: params.kycType || \"individual\",\n details: {\n legalFullName: params.recipientName,\n countryCode: params.countryCode,\n },\n },\n },\n sourceOfFunds: params.sourceOfFunds ?? {\n purpose: 1,\n source: 5,\n relationship: 3,\n },\n });\n }\n}\n","// ── Satoshi / BTC conversion ────────────────────────────────\n\nconst SATS_PER_BTC = 100_000_000;\n\n/**\n * Convert satoshis to BTC.\n * @example satsToBtc(10000) // 0.0001\n */\nexport function satsToBtc(sats: number): number {\n return sats / SATS_PER_BTC;\n}\n\n/**\n * Convert BTC to satoshis.\n * @example btcToSats(0.0001) // 10000\n */\nexport function btcToSats(btc: number): number {\n return Math.round(btc * SATS_PER_BTC);\n}\n\n/**\n * Format a satoshi amount as a human-readable string.\n * @example formatSats(1500000) // \"1,500,000 sats\"\n * @example formatSats(100) // \"100 sats\"\n */\nexport function formatSats(sats: number): string {\n return `${sats.toLocaleString(\"en-US\")} sats`;\n}\n\n/**\n * Format a BTC amount with appropriate precision.\n * @example formatBtc(0.00015) // \"0.00015000 BTC\"\n */\nexport function formatBtc(btc: number): string {\n return `${btc.toFixed(8)} BTC`;\n}\n\n// ── Constants ───────────────────────────────────────────────\n\n/** Supported currencies */\nexport const Currency = {\n BTC: \"BTC\",\n USDT: \"USDT\",\n VND: \"VND\",\n USD: \"USD\",\n CAD: \"CAD\",\n NGN: \"NGN\",\n KES: \"KES\",\n GHS: \"GHS\",\n} as const;\n\nexport type Currency = (typeof Currency)[keyof typeof Currency];\n\n/** Payment methods for sourceReq/destReq */\nexport const PaymentMethod = {\n /** Internal Neutron wallet */\n NEUTRON: \"neutronpay\",\n /** Lightning Network (BOLT11 invoices) */\n LIGHTNING: \"lightning\",\n /** Lightning Address / LNURL */\n LNURL: \"lnurl\",\n /** Bitcoin on-chain */\n ON_CHAIN: \"on-chain\",\n /** USDT on TRON (TRC-20) */\n TRON: \"tron\",\n /** USDT on Ethereum (ERC-20) */\n ETH: \"eth\",\n /** Vietnamese Dong instant bank transfer */\n VND_INSTANT: \"vnd-instant\",\n} as const;\n\nexport type PaymentMethodType = (typeof PaymentMethod)[keyof typeof PaymentMethod];\n\n/** Transaction final states (terminal — won't change) */\nexport const FinalStates = [\n \"completed\",\n \"expired\",\n \"rejected\",\n \"error\",\n \"usercanceled\",\n] as const;\n\n/** All transaction states */\nexport const TransactionStates = {\n QUOTED: \"quoted\",\n USER_CONFIRMED: \"userconfirmed\",\n SRC_CREATED: \"srccreated\",\n SRC_SENT: \"srcsent\",\n SRC_INTENT: \"srcintent\",\n SRC_PEND_CONFIRM: \"srcpendconfirmfill\",\n SRC_CONFIRMED: \"srcconfirmfilled\",\n DEST_PEND_SENT: \"destpendsent\",\n DEST_SENT: \"destsent\",\n COMPLETED: \"completed\",\n EXPIRED: \"expired\",\n REJECTED: \"rejected\",\n ERROR: \"error\",\n USER_CANCELED: \"usercanceled\",\n} as const;\n\n/** USDT blockchain options */\nexport const Chain = {\n TRON: \"TRON\",\n ETH: \"ETH\",\n} as const;\n","import { HttpClient } from \"./client.js\";\nimport { AccountResource } from \"./resources/account.js\";\nimport { TransactionsResource } from \"./resources/transactions.js\";\nimport { LightningResource } from \"./resources/lightning.js\";\nimport { WebhooksResource } from \"./resources/webhooks.js\";\nimport { RatesResource } from \"./resources/rates.js\";\nimport { FiatResource } from \"./resources/fiat.js\";\nimport type { NeutronConfig } from \"./types.js\";\n\n/**\n * Neutron SDK — Bitcoin Lightning, stablecoins, and fiat payments.\n *\n * @example\n * import { Neutron } from \"neutron-sdk\";\n *\n * const neutron = new Neutron({\n * apiKey: process.env.NEUTRON_API_KEY!,\n * apiSecret: process.env.NEUTRON_API_SECRET!,\n * });\n *\n * // Check balances\n * const wallets = await neutron.account.wallets();\n *\n * // Create a Lightning invoice\n * const invoice = await neutron.lightning.createInvoice({ amountSats: 10000 });\n *\n * // Send to a Lightning Address\n * const txn = await neutron.lightning.payAddress(\"alice@getalby.com\", { amountSats: 5000 });\n * await neutron.transactions.confirm(txn.txnId);\n */\nexport class Neutron {\n /** Account info, wallets, and deposit addresses */\n readonly account: AccountResource;\n /** Create, confirm, list, and track transactions */\n readonly transactions: TransactionsResource;\n /** Lightning invoices, payments, and utilities */\n readonly lightning: LightningResource;\n /** Webhook management */\n readonly webhooks: WebhooksResource;\n /** BTC exchange rates */\n readonly rates: RatesResource;\n /** Fiat payouts and bank lookups */\n readonly fiat: FiatResource;\n\n private readonly client: HttpClient;\n\n constructor(config: NeutronConfig) {\n this.client = new HttpClient(config);\n this.account = new AccountResource(this.client);\n this.transactions = new TransactionsResource(this.client);\n this.lightning = new LightningResource(this.client);\n this.webhooks = new WebhooksResource(this.client);\n this.rates = new RatesResource(this.client);\n this.fiat = new FiatResource(this.client);\n }\n\n /**\n * Explicitly authenticate and verify credentials.\n * Usually not needed — the SDK auto-authenticates on first request.\n */\n async authenticate() {\n return this.client.authenticate();\n }\n\n /**\n * Verify a webhook signature. Static method — no client instance needed.\n *\n * @example\n * const event = Neutron.verifyWebhook(req.body, req.headers[\"x-neutronpay-signature\"], secret);\n */\n static verifyWebhook(body: string | Buffer, signature: string | undefined | null, secret: string) {\n return WebhooksResource.verifySignature(body, signature, secret);\n }\n}\n\n// ── Exports ─────────────────────────────────────────────────\n\nexport { HttpClient } from \"./client.js\";\nexport { AccountResource } from \"./resources/account.js\";\nexport { TransactionsResource } from \"./resources/transactions.js\";\nexport { LightningResource } from \"./resources/lightning.js\";\nexport { WebhooksResource } from \"./resources/webhooks.js\";\nexport { RatesResource } from \"./resources/rates.js\";\nexport { FiatResource } from \"./resources/fiat.js\";\nexport type { FiatPayoutParams } from \"./resources/fiat.js\";\n\nexport { sanitizePathParam } from \"./sanitize.js\";\n\nexport {\n NeutronError,\n NeutronApiError,\n NeutronAuthError,\n NeutronTimeoutError,\n NeutronValidationError,\n} from \"./errors.js\";\n\nexport {\n satsToBtc,\n btcToSats,\n formatSats,\n formatBtc,\n Currency,\n PaymentMethod,\n TransactionStates,\n FinalStates,\n Chain,\n} from \"./utils.js\";\n\nexport type {\n Currency as CurrencyType,\n PaymentMethodType,\n} from \"./utils.js\";\n\nexport type {\n NeutronConfig,\n AuthResponse,\n Account,\n Wallet,\n Transaction,\n TransactionState,\n TransactionSide,\n PaymentMethod as PaymentMethodString,\n CreateTransactionRequest,\n ListTransactionsParams,\n TransactionEvent,\n CreateInvoiceParams,\n LightningInvoice,\n DecodedInvoice,\n BtcAddress,\n UsdtAddress,\n Webhook,\n CreateWebhookParams,\n UpdateWebhookParams,\n ExchangeRates,\n FiatInstitution,\n KycInfo,\n SourceOfFunds,\n ApiResponse,\n} from \"./types.js\";\n"],"mappings":"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","names":["crypto","crypto"]}
|
package/package.json
CHANGED