neutron-sdk 0.1.6 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +30 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +30 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -137,6 +137,22 @@ var HttpClient = class {
|
|
|
137
137
|
this.timeout = config.timeout ?? DEFAULT_TIMEOUT;
|
|
138
138
|
this.maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
139
139
|
this.debug = config.debug ?? false;
|
|
140
|
+
this.validateBaseUrl(this.baseUrl);
|
|
141
|
+
}
|
|
142
|
+
validateBaseUrl(url) {
|
|
143
|
+
try {
|
|
144
|
+
const u = new URL(url);
|
|
145
|
+
if (u.protocol !== "https:") {
|
|
146
|
+
throw new NeutronAuthError("baseUrl must use HTTPS");
|
|
147
|
+
}
|
|
148
|
+
const blocked = ["localhost", "127.", "0.0.0.0", "169.254.", "10.", "192.168.", "172."];
|
|
149
|
+
if (blocked.some((b) => u.hostname.startsWith(b))) {
|
|
150
|
+
throw new NeutronAuthError(`baseUrl blocked: ${u.hostname}`);
|
|
151
|
+
}
|
|
152
|
+
} catch (e) {
|
|
153
|
+
if (e instanceof NeutronAuthError) throw e;
|
|
154
|
+
throw new NeutronAuthError(`Invalid baseUrl: ${url}`);
|
|
155
|
+
}
|
|
140
156
|
}
|
|
141
157
|
log(message, data) {
|
|
142
158
|
if (!this.debug) return;
|
|
@@ -178,8 +194,8 @@ var HttpClient = class {
|
|
|
178
194
|
this.accountId = result.accountId;
|
|
179
195
|
this.accessToken = result.accessToken;
|
|
180
196
|
this.tokenExpiry = typeof result.expiredAt === "number" ? result.expiredAt : new Date(result.expiredAt).getTime();
|
|
181
|
-
return result;
|
|
182
197
|
this.log("Authenticated", { accountId: this.accountId });
|
|
198
|
+
return result;
|
|
183
199
|
}
|
|
184
200
|
async ensureAuth() {
|
|
185
201
|
if (!this.isTokenValid) {
|
|
@@ -781,7 +797,16 @@ var FiatResource = class {
|
|
|
781
797
|
ccy: params.sourceCcy,
|
|
782
798
|
method: "neutronpay",
|
|
783
799
|
amtRequested: params.sourceAmount,
|
|
784
|
-
reqDetails: {}
|
|
800
|
+
reqDetails: {},
|
|
801
|
+
kyc: {
|
|
802
|
+
type: params.kycType || "individual",
|
|
803
|
+
details: {
|
|
804
|
+
legalFullName: params.senderName || "Account Holder",
|
|
805
|
+
countryCode: params.senderCountryCode || "VN",
|
|
806
|
+
address1: params.senderAddress || "N/A",
|
|
807
|
+
contactNumber: params.senderPhone || "N/A"
|
|
808
|
+
}
|
|
809
|
+
}
|
|
785
810
|
},
|
|
786
811
|
destReq: {
|
|
787
812
|
ccy: params.destCcy,
|
|
@@ -794,7 +819,9 @@ var FiatResource = class {
|
|
|
794
819
|
type: params.kycType || "individual",
|
|
795
820
|
details: {
|
|
796
821
|
legalFullName: params.recipientName,
|
|
797
|
-
countryCode: params.countryCode
|
|
822
|
+
countryCode: params.countryCode,
|
|
823
|
+
address1: params.recipientAddress || "N/A",
|
|
824
|
+
contactNumber: params.recipientPhone || "N/A"
|
|
798
825
|
}
|
|
799
826
|
}
|
|
800
827
|
},
|
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 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"]}
|
|
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 // SECURITY: validate baseUrl to prevent SSRF\n this.validateBaseUrl(this.baseUrl);\n }\n\n private validateBaseUrl(url: string): void {\n try {\n const u = new URL(url);\n if (u.protocol !== \"https:\") {\n throw new NeutronAuthError(\"baseUrl must use HTTPS\");\n }\n const blocked = [\"localhost\", \"127.\", \"0.0.0.0\", \"169.254.\", \"10.\", \"192.168.\", \"172.\"];\n if (blocked.some(b => u.hostname.startsWith(b))) {\n throw new NeutronAuthError(`baseUrl blocked: ${u.hostname}`);\n }\n } catch (e) {\n if (e instanceof NeutronAuthError) throw e;\n throw new NeutronAuthError(`Invalid baseUrl: ${url}`);\n }\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 this.log(\"Authenticated\", { accountId: this.accountId });\n return result;\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 /** Recipient address (optional, defaults to \"N/A\") */\n recipientAddress?: string;\n /** Recipient phone (optional, defaults to \"N/A\") */\n recipientPhone?: string;\n /** Sender legal full name — pulled from account KYC if not provided */\n senderName?: string;\n /** Sender country code — pulled from account if not provided */\n senderCountryCode?: string;\n /** Sender address — pulled from account KYC if not provided */\n senderAddress?: string;\n /** Sender phone — pulled from account KYC if not provided */\n senderPhone?: 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 kyc: {\n type: params.kycType || \"individual\",\n details: {\n legalFullName: params.senderName || \"Account Holder\",\n countryCode: params.senderCountryCode || \"VN\",\n address1: params.senderAddress || \"N/A\",\n contactNumber: params.senderPhone || \"N/A\",\n },\n },\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 address1: params.recipientAddress || \"N/A\",\n contactNumber: params.recipientPhone || \"N/A\",\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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,oBAAmB;;;ACGZ,IAAM,eAAN,cAA2B,MAAM;AAAA,EACtC,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAKO,IAAM,kBAAN,cAA8B,aAAa;AAAA;AAAA,EAEvC;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA,EAET,YAAY,QAAgB,MAAW;AACrC,UAAM,UAAU,MAAM,SAAS,MAAM,WAAW,aAAa,MAAM;AACnE,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,SAAK,OAAO,MAAM;AAClB,SAAK,OAAO;AAAA,EACd;AAAA;AAAA,EAGA,IAAI,gBAAyB;AAC3B,WAAO,KAAK,WAAW;AAAA,EACzB;AAAA;AAAA,EAGA,IAAI,cAAuB;AACzB,WAAO,KAAK,WAAW,OAAO,KAAK,WAAW;AAAA,EAChD;AAAA;AAAA,EAGA,IAAI,cAAuB;AACzB,WAAO,KAAK,WAAW,OAAO,KAAK,UAAU;AAAA,EAC/C;AACF;AAKO,IAAM,mBAAN,cAA+B,aAAa;AAAA,EACjD,YAAY,UAAkB,yDAAyD;AACrF,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAKO,IAAM,sBAAN,cAAkC,aAAa;AAAA,EACpD,YAAY,WAAmB;AAC7B,UAAM,2BAA2B,SAAS,IAAI;AAC9C,SAAK,OAAO;AAAA,EACd;AACF;AAKO,IAAM,yBAAN,cAAqC,aAAa;AAAA,EACvD,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;;;ADlEA,IAAM,mBAAmB;AACzB,IAAM,kBAAkB;AACxB,IAAM,sBAAsB;AAC5B,IAAM,0BAA0B;AAEzB,IAAM,aAAN,MAAiB;AAAA,EACL;AAAA,EACA;AAAA,EACR;AAAA,EACQ;AAAA,EACA;AAAA,EACA;AAAA,EAET,cAA6B;AAAA,EAC7B,YAA2B;AAAA,EAC3B,cAAsB;AAAA,EAE9B,YAAY,QAAuB;AACjC,QAAI,CAAC,OAAO,OAAQ,OAAM,IAAI,iBAAiB,oBAAoB;AACnE,QAAI,CAAC,OAAO,UAAW,OAAM,IAAI,iBAAiB,uBAAuB;AAEzE,SAAK,SAAS,OAAO;AACrB,SAAK,YAAY,OAAO;AACxB,SAAK,WAAW,OAAO,WAAW,kBAAkB,QAAQ,QAAQ,EAAE;AACtE,SAAK,UAAU,OAAO,WAAW;AACjC,SAAK,aAAa,OAAO,cAAc;AACvC,SAAK,QAAQ,OAAO,SAAS;AAG7B,SAAK,gBAAgB,KAAK,OAAO;AAAA,EACnC;AAAA,EAEQ,gBAAgB,KAAmB;AACzC,QAAI;AACF,YAAM,IAAI,IAAI,IAAI,GAAG;AACrB,UAAI,EAAE,aAAa,UAAU;AAC3B,cAAM,IAAI,iBAAiB,wBAAwB;AAAA,MACrD;AACA,YAAM,UAAU,CAAC,aAAa,QAAQ,WAAW,YAAY,OAAO,YAAY,MAAM;AACtF,UAAI,QAAQ,KAAK,OAAK,EAAE,SAAS,WAAW,CAAC,CAAC,GAAG;AAC/C,cAAM,IAAI,iBAAiB,oBAAoB,EAAE,QAAQ,EAAE;AAAA,MAC7D;AAAA,IACF,SAAS,GAAG;AACV,UAAI,aAAa,iBAAkB,OAAM;AACzC,YAAM,IAAI,iBAAiB,oBAAoB,GAAG,EAAE;AAAA,IACtD;AAAA,EACF;AAAA,EAEQ,IAAI,SAAiB,MAAkB;AAC7C,QAAI,CAAC,KAAK,MAAO;AACjB,UAAM,MAAK,oBAAI,KAAK,GAAE,YAAY;AAClC,UAAM,QAAQ,OAAO,IAAI,KAAK,UAAU,IAAI,CAAC,KAAK;AAClD,YAAQ,MAAM,gBAAgB,EAAE,KAAK,OAAO,GAAG,KAAK,EAAE;AAAA,EACxD;AAAA;AAAA,EAIQ,kBAAkB,SAAyB;AACjD,UAAM,eAAe,GAAG,KAAK,MAAM,YAAY,OAAO;AACtD,WAAO,cAAAA,QACJ,WAAW,UAAU,KAAK,SAAS,EACnC,OAAO,YAAY,EACnB,OAAO,KAAK;AAAA,EACjB;AAAA,EAEA,IAAY,eAAwB;AAClC,WAAO,CAAC,EACN,KAAK,eACL,KAAK,aACL,KAAK,IAAI,IAAI,KAAK,cAAc;AAAA,EAEpC;AAAA,EAEA,MAAM,eAAsC;AAC1C,UAAM,UAAU,KAAK,UAAU,EAAE,MAAM,OAAO,CAAC;AAC/C,UAAM,YAAY,KAAK,kBAAkB,OAAO;AAEhD,UAAM,WAAW,MAAM,KAAK;AAAA,MAC1B,GAAG,KAAK,OAAO;AAAA,MACf;AAAA,QACE,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,aAAa,KAAK;AAAA,UAClB,mBAAmB;AAAA,QACrB;AAAA,QACA,MAAM;AAAA,MACR;AAAA,IACF;AAEA,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,OAAQ,MAAM,SAAS,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AACpD,YAAM,IAAI;AAAA,QACR,KAAK,SAAS,KAAK,WAAW,0BAA0B,SAAS,MAAM;AAAA,MACzE;AAAA,IACF;AAEA,UAAM,MAAO,MAAM,SAAS,KAAK;AAEjC,UAAM,SAAuB,IAAI,QAAQ;AACzC,SAAK,YAAY,OAAO;AACxB,SAAK,cAAc,OAAO;AAC1B,SAAK,cAAc,OAAO,OAAO,cAAc,WAC3C,OAAO,YACP,IAAI,KAAK,OAAO,SAAS,EAAE,QAAQ;AAEvC,SAAK,IAAI,iBAAiB,EAAE,WAAW,KAAK,UAAU,CAAC;AACvD,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,aAA4B;AACxC,QAAI,CAAC,KAAK,cAAc;AACtB,YAAM,KAAK,aAAa;AAAA,IAC1B;AAAA,EACF;AAAA,EAEA,eAAuB;AACrB,QAAI,CAAC,KAAK,WAAW;AACnB,YAAM,IAAI,iBAAiB,sEAAsE;AAAA,IACnG;AACA,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAM,4BAA6C;AACjD,UAAM,KAAK,WAAW;AACtB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,iBAAkD;AACtD,UAAM,KAAK,WAAW;AACtB,WAAO;AAAA,MACL,eAAe,UAAU,KAAK,WAAW;AAAA,IAC3C;AAAA,EACF;AAAA;AAAA,EAIA,MAAc,SAAS,KAAa,MAAsC;AACxE,UAAM,aAAa,IAAI,gBAAgB;AACvC,UAAM,QAAQ,WAAW,MAAM,WAAW,MAAM,GAAG,KAAK,OAAO;AAE/D,QAAI;AACF,aAAO,MAAM,MAAM,KAAK,EAAE,GAAG,MAAM,QAAQ,WAAW,OAAO,CAAC;AAAA,IAChE,SAAS,KAAU;AACjB,UAAI,IAAI,SAAS,cAAc;AAC7B,cAAM,IAAI,oBAAoB,KAAK,OAAO;AAAA,MAC5C;AACA,YAAM;AAAA,IACR,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF;AAAA,EAEA,MAAM,QAAiB,QAAgB,MAAc,MAAwB;AAC3E,UAAM,KAAK,WAAW;AAEtB,QAAI;AAEJ,aAAS,UAAU,GAAG,WAAW,KAAK,YAAY,WAAW;AAC3D,UAAI,UAAU,GAAG;AAEf,cAAM,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,KAAK,IAAI,GAAG,UAAU,CAAC,IAAI,GAAI,CAAC;AAGvE,YAAI,CAAC,KAAK,aAAc,OAAM,KAAK,aAAa;AAAA,MAClD;AAEA,YAAM,MAAM,GAAG,KAAK,OAAO,GAAG,IAAI;AAClC,WAAK,IAAI,GAAG,MAAM,IAAI,IAAI,EAAE;AAC5B,YAAM,UAAkC;AAAA,QACtC,eAAe,UAAU,KAAK,WAAW;AAAA,QACzC,gBAAgB;AAAA,MAClB;AAEA,YAAM,WAAW,MAAM,KAAK,SAAS,KAAK;AAAA,QACxC;AAAA,QACA;AAAA,QACA,MAAM,OAAO,KAAK,UAAU,IAAI,IAAI;AAAA,MACtC,CAAC;AAED,UAAI,SAAS,IAAI;AACf,eAAQ,MAAM,SAAS,KAAK;AAAA,MAC9B;AAEA,YAAM,YAAY,MAAM,SAAS,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AACxD,YAAM,WAAW,IAAI,gBAAgB,SAAS,QAAQ,SAAS;AAG/D,UAAI,SAAS,WAAW,OAAO,UAAU,KAAK,YAAY;AACxD,aAAK,cAAc;AACnB,oBAAY;AACZ;AAAA,MACF;AAGA,UAAI,SAAS,eAAe,UAAU,KAAK,YAAY;AACrD,oBAAY;AACZ;AAAA,MACF;AAEA,YAAM;AAAA,IACR;AAEA,UAAM;AAAA,EACR;AAAA,EAEA,MAAM,IAAa,MAA0B;AAC3C,WAAO,KAAK,QAAW,OAAO,IAAI;AAAA,EACpC;AAAA,EAEA,MAAM,KAAc,MAAc,MAAwB;AACxD,WAAO,KAAK,QAAW,QAAQ,MAAM,IAAI;AAAA,EAC3C;AAAA,EAEA,MAAM,IAAa,MAAc,MAAwB;AACvD,WAAO,KAAK,QAAW,OAAO,MAAM,IAAI;AAAA,EAC1C;AAAA,EAEA,MAAM,IAAa,MAA0B;AAC3C,WAAO,KAAK,QAAW,UAAU,IAAI;AAAA,EACvC;AACF;;;AEnOO,SAAS,kBAAkB,OAAe,MAAsB;AACrE,MAAI,CAAC,SAAS,OAAO,UAAU,UAAU;AACvC,UAAM,IAAI,uBAAuB,GAAG,IAAI,8CAA8C;AAAA,EACxF;AAGA,QAAM,YAAY,MAAM,QAAQ,qBAAqB,EAAE;AAEvD,MAAI,cAAc,OAAO;AACvB,UAAM,IAAI;AAAA,MACR,GAAG,IAAI;AAAA,IACT;AAAA,EACF;AAEA,MAAI,UAAU,SAAS,IAAI,GAAG;AAC5B,UAAM,IAAI,uBAAuB,GAAG,IAAI,2CAA2C;AAAA,EACrF;AAEA,SAAO;AACT;;;ACrBO,IAAM,kBAAN,MAAsB;AAAA,EAC3B,YAA6B,QAAoB;AAApB;AAAA,EAAqB;AAAA;AAAA;AAAA;AAAA,EAKlD,MAAM,MAAwB;AAC5B,UAAM,YAAY,MAAM,KAAK,OAAO,0BAA0B;AAC9D,UAAM,MAAM,MAAM,KAAK,OAAO,IAAI,mBAAmB,SAAS,EAAE;AAChE,WAAQ,IAAI,QAAQ;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UAA6B;AACjC,UAAM,YAAY,MAAM,KAAK,OAAO,0BAA0B;AAC9D,UAAM,MAAM,MAAM,KAAK,OAAO,IAAI,mBAAmB,SAAS,UAAU;AACxE,WAAO,IAAI,QAAQ;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAO,UAAmC;AAC9C,sBAAkB,UAAU,UAAU;AACtC,UAAM,YAAY,MAAM,KAAK,OAAO,0BAA0B;AAC9D,UAAM,MAAM,MAAM,KAAK,OAAO,IAAI,mBAAmB,SAAS,WAAW,QAAQ,EAAE;AACnF,WAAQ,IAAI,QAAQ;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAA2C;AAC/C,UAAM,MAAM,MAAM,KAAK,OAAO,IAAI,iCAAiC;AACnE,UAAM,OAAO,KAAK,QAAQ;AAC1B,WAAO,EAAE,SAAS,KAAK,qBAAqB;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,YAAY,QAAwB,QAAqD;AAC7F,UAAM,MAAM,MAAM,KAAK,OAAO;AAAA,MAC5B,qEAAqE,KAAK;AAAA,IAC5E;AACA,UAAM,OAAO,KAAK,QAAQ;AAC1B,WAAO;AAAA,MACL,SAAS,KAAK,kCAAkC,KAAK;AAAA,MACrD;AAAA,IACF;AAAA,EACF;AACF;;;ACjDO,IAAM,uBAAN,MAA2B;AAAA,EAChC,YAA6B,QAAoB;AAApB;AAAA,EAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA0BlD,MAAM,OAAO,QAAwD;AACnE,WAAO,KAAK,OAAO,KAAkB,uBAAuB,MAAM;AAAA,EACpE;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,QAAQ,OAAqC;AACjD,sBAAkB,OAAO,OAAO;AAChC,WAAO,KAAK,OAAO,IAAiB,uBAAuB,KAAK,UAAU;AAAA,EAC5E;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,IAAI,OAAqC;AAC7C,sBAAkB,OAAO,OAAO;AAChC,WAAO,KAAK,OAAO,IAAiB,uBAAuB,KAAK,EAAE;AAAA,EACpE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,KAAK,QAAyD;AAClE,UAAM,KAAK,IAAI,gBAAgB;AAC/B,QAAI,QAAQ;AACV,iBAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,MAAM,GAAG;AAC3C,YAAI,MAAM,UAAa,MAAM,KAAM,IAAG,OAAO,GAAG,OAAO,CAAC,CAAC;AAAA,MAC3D;AAAA,IACF;AACA,UAAM,QAAQ,GAAG,SAAS;AAC1B,UAAM,MAAM,MAAM,KAAK,OAAO,IAAI,sBAAsB,QAAQ,IAAI,KAAK,KAAK,EAAE,EAAE;AAClF,WAAO,IAAI,QAAQ;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,OAAO,QAAsC;AACjD,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,MAAM,kBACJ,OACA,SAKsB;AACtB,UAAM,eAAe,CAAC,aAAa,UAAU,WAAW,YAAY,SAAS,cAAc;AAC3F,UAAM,WAAW,SAAS,cAAc;AACxC,UAAM,UAAU,SAAS,aAAa;AACtC,UAAM,QAAQ,KAAK,IAAI;AACvB,QAAI,YAAY;AAEhB,WAAO,KAAK,IAAI,IAAI,QAAQ,SAAS;AACnC,YAAM,MAAM,MAAM,KAAK,IAAI,KAAK;AAEhC,UAAI,IAAI,aAAa,WAAW;AAC9B,oBAAY,IAAI;AAChB,iBAAS,gBAAgB,IAAI,UAAU,GAAG;AAAA,MAC5C;AAEA,UAAI,aAAa,SAAS,IAAI,QAAQ,GAAG;AACvC,eAAO;AAAA,MACT;AAEA,YAAM,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,QAAQ,CAAC;AAAA,IAClD;AAEA,UAAM,IAAI,MAAM,eAAe,KAAK,4BAA4B,OAAO,IAAI;AAAA,EAC7E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,OAAO,UAAU,eAAuB,YAAY,KAA0C;AAE5F,sBAAkB,eAAe,eAAe;AAGhD,UAAM,UAAU;AAChB,QAAI,CAAC,QAAQ,KAAK,aAAa,GAAG;AAChC,YAAM,IAAI,MAAM,wCAAwC;AAAA,IAC1D;AAGA,UAAM,iBAAiB,KAAK,IAAI,KAAK,IAAI,WAAW,GAAK,GAAG,GAAO;AAGnE,UAAM,MAAM,GAAG,KAAK,OAAO,OAAO,uCAAuC,mBAAmB,aAAa,CAAC;AAC1G,UAAM,WAAW,MAAM,MAAM,KAAK;AAAA,MAChC,SAAS;AAAA,QACP,UAAU;AAAA,QACV,GAAI,MAAM,KAAK,OAAO,eAAe;AAAA,MACvC;AAAA,MACA,QAAQ,YAAY,QAAQ,cAAc;AAAA,IAC5C,CAAC;AAED,QAAI,CAAC,SAAS,MAAM,CAAC,SAAS,MAAM;AAClC,YAAM,IAAI,MAAM,0BAA0B,SAAS,MAAM,IAAI,SAAS,UAAU,EAAE;AAAA,IACpF;AAEA,UAAM,SAAS,SAAS,KAAK,UAAU;AACvC,UAAM,UAAU,IAAI,YAAY;AAChC,QAAI,SAAS;AACb,UAAM,aAAa,KAAK;AAExB,QAAI;AACF,aAAO,MAAM;AACX,cAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,YAAI,KAAM;AACV,kBAAU,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC;AAGhD,YAAI,OAAO,SAAS,YAAY;AAC9B,gBAAM,IAAI,MAAM,0DAAqD;AAAA,QACvE;AAEA,cAAM,QAAQ,OAAO,MAAM,IAAI;AAC/B,iBAAS,MAAM,IAAI,KAAK;AACxB,mBAAW,QAAQ,OAAO;AACxB,cAAI,KAAK,WAAW,QAAQ,GAAG;AAC7B,gBAAI;AACF,oBAAM,KAAK,MAAM,KAAK,MAAM,CAAC,CAAC;AAAA,YAChC,SAAS,UAAU;AAEjB,sBAAQ,MAAM,kCAAkC,QAAQ;AAAA,YAC1D;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF,UAAE;AACA,aAAO,OAAO;AAAA,IAChB;AAAA,EACF;AACF;;;ACrMO,IAAM,oBAAN,MAAwB;AAAA,EAC7B,YAA6B,QAAoB;AAApB;AAAA,EAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBlD,MAAM,cAAc,QAAwD;AAC1E,QAAI;AAEJ,QAAI,OAAO,eAAe,UAAa,OAAO,cAAc,QAAW;AACrE,YAAM,IAAI,uBAAuB,mDAAmD;AAAA,IACtF;AACA,QAAI,OAAO,eAAe,QAAW;AACnC,UAAI,OAAO,cAAc,EAAG,OAAM,IAAI,uBAAuB,8BAA8B;AAC3F,kBAAY,OAAO,aAAa;AAAA,IAClC,WAAW,OAAO,cAAc,QAAW;AACzC,UAAI,OAAO,aAAa,EAAG,OAAM,IAAI,uBAAuB,6BAA6B;AACzF,kBAAY,OAAO;AAAA,IACrB,OAAO;AACL,YAAM,IAAI,uBAAuB,yCAAyC;AAAA,IAC5E;AAGA,UAAM,MAAM,MAAM,KAAK,OAAO,KAAkB,uBAAuB;AAAA,MACrE,UAAU,OAAO;AAAA,MACjB,WAAW,EAAE,KAAK,OAAO,QAAQ,aAAa,YAAY,CAAC,EAAE;AAAA,MAC7D,SAAS;AAAA,QACP,KAAK;AAAA,QACL,QAAQ;AAAA,QACR,cAAc;AAAA,QACd,YAAY,CAAC;AAAA,MACf;AAAA,IACF,CAAC;AAGD,UAAM,YAAY,MAAM,KAAK,OAAO;AAAA,MAClC,uBAAuB,IAAI,KAAK;AAAA,IAClC;AAEA,WAAO;AAAA,MACL,OAAO,UAAU;AAAA,MACjB,SAAS,UAAU,WAAW,YAAY,kBAAkB;AAAA,MAC5D,WAAW,UAAU,WAAW,YAAY;AAAA,MAC5C,WAAW;AAAA,MACX,YAAY,KAAK,MAAM,YAAY,GAAW;AAAA,MAC9C,QAAQ,UAAU;AAAA,IACpB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,WAAW,SAAiB,UAAyC;AACzE,WAAO,KAAK,OAAO,KAAkB,uBAAuB;AAAA,MAC1D;AAAA,MACA,WAAW,EAAE,KAAK,OAAO,QAAQ,aAAa;AAAA,MAC9C,SAAS;AAAA,QACP,KAAK;AAAA,QACL,QAAQ;AAAA,QACR,YAAY,EAAE,gBAAgB,QAAQ;AAAA,MACxC;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,WACJ,SACA,QACsB;AACtB,QAAI;AACJ,QAAI,OAAO,eAAe,QAAW;AACnC,kBAAY,OAAO,aAAa;AAAA,IAClC,WAAW,OAAO,cAAc,QAAW;AACzC,kBAAY,OAAO;AAAA,IACrB,OAAO;AACL,YAAM,IAAI,uBAAuB,yCAAyC;AAAA,IAC5E;AAEA,WAAO,KAAK,OAAO,KAAkB,uBAAuB;AAAA,MAC1D,UAAU,OAAO;AAAA,MACjB,WAAW,EAAE,KAAK,OAAO,QAAQ,cAAc,cAAc,UAAU;AAAA,MACvE,SAAS;AAAA,QACP,KAAK;AAAA,QACL,QAAQ;AAAA,QACR,YAAY,EAAE,QAAQ;AAAA,MACxB;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,cAAc,SAA0C;AAC5D,UAAM,SAAS,MAAM,KAAK,OAAO;AAAA,MAC/B;AAAA,MACA,EAAE,gBAAgB,QAAQ;AAAA,IAC5B;AACA,WAAO,OAAO;AAAA,EAChB;AAEF;;;AC5IA,IAAAC,iBAAmB;AAMZ,IAAM,mBAAN,MAAuB;AAAA,EAC5B,YAA6B,QAAoB;AAApB;AAAA,EAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWlD,MAAM,OAAO,QAA+C;AAC1D,WAAO,KAAK,OAAO,KAAc,mBAAmB,MAAM;AAAA,EAC5D;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAA2B;AAC/B,UAAM,MAAM,MAAM,KAAK,OAAO,IAAI,iBAAiB;AACnD,WAAO,IAAI,QAAQ;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAO,WAAmB,QAA+C;AAC7E,sBAAkB,WAAW,WAAW;AACxC,WAAO,KAAK,OAAO,IAAa,mBAAmB,SAAS,IAAI,MAAM;AAAA,EACxE;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAO,WAAkC;AAC7C,sBAAkB,WAAW,WAAW;AACxC,UAAM,KAAK,OAAO,IAAI,mBAAmB,SAAS,EAAE;AAAA,EACtD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA4BA,OAAO,gBACL,MACA,WACA,QACK;AACL,QAAI,CAAC,WAAW;AACd,YAAM,IAAI,uBAAuB,2DAA2D;AAAA,IAC9F;AACA,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,uBAAuB,6CAA6C;AAAA,IAChF;AAEA,UAAM,UAAU,OAAO,SAAS,WAAW,OAAO,KAAK,SAAS,MAAM;AAEtE,UAAM,WAAW,eAAAC,QACd,WAAW,UAAU,MAAM,EAC3B,OAAO,OAAO,EACd,OAAO,KAAK;AAEf,UAAM,SAAS,OAAO,KAAK,SAAS;AACpC,UAAM,SAAS,OAAO,KAAK,QAAQ;AACnC,UAAM,UAAU,OAAO,WAAW,OAAO,UAAU,eAAAA,QAAO,gBAAgB,QAAQ,MAAM;AAExF,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI,uBAAuB,2BAA2B;AAAA,IAC9D;AAEA,WAAO,KAAK,MAAM,OAAO;AAAA,EAC3B;AACF;;;AClGO,IAAM,gBAAN,MAAoB;AAAA,EACzB,YAA6B,QAAoB;AAApB;AAAA,EAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASlD,MAAM,MAA8B;AAClC,UAAM,MAAM,MAAM,KAAK,OAAO,IAAI,cAAc;AAChD,WAAO,IAAI,QAAQ;AAAA,EACrB;AACF;;;ACwBO,IAAM,eAAN,MAAmB;AAAA,EACxB,YAA6B,QAAoB;AAApB;AAAA,EAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUlD,MAAM,aAAa,aAAiD;AAClE,sBAAkB,aAAa,aAAa;AAC5C,UAAM,MAAM,MAAM,KAAK,OAAO;AAAA,MAC5B,iDAAiD,WAAW;AAAA,IAC9D;AACA,WAAO,IAAI,QAAQ;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAqBA,MAAM,OAAO,QAAgD;AAC3D,WAAO,KAAK,OAAO,KAAkB,uBAAuB;AAAA,MAC1D,UAAU,OAAO;AAAA,MACjB,WAAW;AAAA,QACT,KAAK,OAAO;AAAA,QACZ,QAAQ;AAAA,QACR,cAAc,OAAO;AAAA,QACrB,YAAY,CAAC;AAAA,QACb,KAAK;AAAA,UACH,MAAM,OAAO,WAAW;AAAA,UACxB,SAAS;AAAA,YACP,eAAe,OAAO,cAAc;AAAA,YACpC,aAAa,OAAO,qBAAqB;AAAA,YACzC,UAAU,OAAO,iBAAiB;AAAA,YAClC,eAAe,OAAO,eAAe;AAAA,UACvC;AAAA,QACF;AAAA,MACF;AAAA,MACA,SAAS;AAAA,QACP,KAAK,OAAO;AAAA,QACZ,QAAQ,OAAO;AAAA,QACf,YAAY;AAAA,UACV,aAAa,OAAO;AAAA,UACpB,iBAAiB,OAAO;AAAA,QAC1B;AAAA,QACA,KAAK;AAAA,UACH,MAAM,OAAO,WAAW;AAAA,UACxB,SAAS;AAAA,YACP,eAAe,OAAO;AAAA,YACtB,aAAa,OAAO;AAAA,YACpB,UAAU,OAAO,oBAAoB;AAAA,YACrC,eAAe,OAAO,kBAAkB;AAAA,UAC1C;AAAA,QACF;AAAA,MACF;AAAA,MACA,eAAe,OAAO,iBAAiB;AAAA,QACrC,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,cAAc;AAAA,MAChB;AAAA,IACF,CAAC;AAAA,EACH;AACF;;;ACvHA,IAAM,eAAe;AAMd,SAAS,UAAU,MAAsB;AAC9C,SAAO,OAAO;AAChB;AAMO,SAAS,UAAU,KAAqB;AAC7C,SAAO,KAAK,MAAM,MAAM,YAAY;AACtC;AAOO,SAAS,WAAW,MAAsB;AAC/C,SAAO,GAAG,KAAK,eAAe,OAAO,CAAC;AACxC;AAMO,SAAS,UAAU,KAAqB;AAC7C,SAAO,GAAG,IAAI,QAAQ,CAAC,CAAC;AAC1B;AAKO,IAAM,WAAW;AAAA,EACtB,KAAK;AAAA,EACL,MAAM;AAAA,EACN,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AACP;AAKO,IAAM,gBAAgB;AAAA;AAAA,EAE3B,SAAS;AAAA;AAAA,EAET,WAAW;AAAA;AAAA,EAEX,OAAO;AAAA;AAAA,EAEP,UAAU;AAAA;AAAA,EAEV,MAAM;AAAA;AAAA,EAEN,KAAK;AAAA;AAAA,EAEL,aAAa;AACf;AAKO,IAAM,cAAc;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAGO,IAAM,oBAAoB;AAAA,EAC/B,QAAQ;AAAA,EACR,gBAAgB;AAAA,EAChB,aAAa;AAAA,EACb,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,kBAAkB;AAAA,EAClB,eAAe;AAAA,EACf,gBAAgB;AAAA,EAChB,WAAW;AAAA,EACX,WAAW;AAAA,EACX,SAAS;AAAA,EACT,UAAU;AAAA,EACV,OAAO;AAAA,EACP,eAAe;AACjB;AAGO,IAAM,QAAQ;AAAA,EACnB,MAAM;AAAA,EACN,KAAK;AACP;;;AV1EO,IAAM,UAAN,MAAc;AAAA;AAAA,EAEV;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA,EAEQ;AAAA,EAEjB,YAAY,QAAuB;AACjC,SAAK,SAAS,IAAI,WAAW,MAAM;AACnC,SAAK,UAAU,IAAI,gBAAgB,KAAK,MAAM;AAC9C,SAAK,eAAe,IAAI,qBAAqB,KAAK,MAAM;AACxD,SAAK,YAAY,IAAI,kBAAkB,KAAK,MAAM;AAClD,SAAK,WAAW,IAAI,iBAAiB,KAAK,MAAM;AAChD,SAAK,QAAQ,IAAI,cAAc,KAAK,MAAM;AAC1C,SAAK,OAAO,IAAI,aAAa,KAAK,MAAM;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,eAAe;AACnB,WAAO,KAAK,OAAO,aAAa;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAO,cAAc,MAAuB,WAAsC,QAAgB;AAChG,WAAO,iBAAiB,gBAAgB,MAAM,WAAW,MAAM;AAAA,EACjE;AACF;","names":["crypto","import_crypto","crypto"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -187,6 +187,7 @@ declare class HttpClient {
|
|
|
187
187
|
private accountId;
|
|
188
188
|
private tokenExpiry;
|
|
189
189
|
constructor(config: NeutronConfig);
|
|
190
|
+
private validateBaseUrl;
|
|
190
191
|
private log;
|
|
191
192
|
private generateSignature;
|
|
192
193
|
private get isTokenValid();
|
|
@@ -462,6 +463,18 @@ interface FiatPayoutParams {
|
|
|
462
463
|
recipientName: string;
|
|
463
464
|
/** Recipient country code (e.g. "VN") */
|
|
464
465
|
countryCode: string;
|
|
466
|
+
/** Recipient address (optional, defaults to "N/A") */
|
|
467
|
+
recipientAddress?: string;
|
|
468
|
+
/** Recipient phone (optional, defaults to "N/A") */
|
|
469
|
+
recipientPhone?: string;
|
|
470
|
+
/** Sender legal full name — pulled from account KYC if not provided */
|
|
471
|
+
senderName?: string;
|
|
472
|
+
/** Sender country code — pulled from account if not provided */
|
|
473
|
+
senderCountryCode?: string;
|
|
474
|
+
/** Sender address — pulled from account KYC if not provided */
|
|
475
|
+
senderAddress?: string;
|
|
476
|
+
/** Sender phone — pulled from account KYC if not provided */
|
|
477
|
+
senderPhone?: string;
|
|
465
478
|
/** "individual" or "business" (default: "individual") */
|
|
466
479
|
kycType?: "individual" | "business";
|
|
467
480
|
/** Source of funds declaration */
|
package/dist/index.d.ts
CHANGED
|
@@ -187,6 +187,7 @@ declare class HttpClient {
|
|
|
187
187
|
private accountId;
|
|
188
188
|
private tokenExpiry;
|
|
189
189
|
constructor(config: NeutronConfig);
|
|
190
|
+
private validateBaseUrl;
|
|
190
191
|
private log;
|
|
191
192
|
private generateSignature;
|
|
192
193
|
private get isTokenValid();
|
|
@@ -462,6 +463,18 @@ interface FiatPayoutParams {
|
|
|
462
463
|
recipientName: string;
|
|
463
464
|
/** Recipient country code (e.g. "VN") */
|
|
464
465
|
countryCode: string;
|
|
466
|
+
/** Recipient address (optional, defaults to "N/A") */
|
|
467
|
+
recipientAddress?: string;
|
|
468
|
+
/** Recipient phone (optional, defaults to "N/A") */
|
|
469
|
+
recipientPhone?: string;
|
|
470
|
+
/** Sender legal full name — pulled from account KYC if not provided */
|
|
471
|
+
senderName?: string;
|
|
472
|
+
/** Sender country code — pulled from account if not provided */
|
|
473
|
+
senderCountryCode?: string;
|
|
474
|
+
/** Sender address — pulled from account KYC if not provided */
|
|
475
|
+
senderAddress?: string;
|
|
476
|
+
/** Sender phone — pulled from account KYC if not provided */
|
|
477
|
+
senderPhone?: string;
|
|
465
478
|
/** "individual" or "business" (default: "individual") */
|
|
466
479
|
kycType?: "individual" | "business";
|
|
467
480
|
/** Source of funds declaration */
|
package/dist/index.js
CHANGED
|
@@ -79,6 +79,22 @@ var HttpClient = class {
|
|
|
79
79
|
this.timeout = config.timeout ?? DEFAULT_TIMEOUT;
|
|
80
80
|
this.maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
81
81
|
this.debug = config.debug ?? false;
|
|
82
|
+
this.validateBaseUrl(this.baseUrl);
|
|
83
|
+
}
|
|
84
|
+
validateBaseUrl(url) {
|
|
85
|
+
try {
|
|
86
|
+
const u = new URL(url);
|
|
87
|
+
if (u.protocol !== "https:") {
|
|
88
|
+
throw new NeutronAuthError("baseUrl must use HTTPS");
|
|
89
|
+
}
|
|
90
|
+
const blocked = ["localhost", "127.", "0.0.0.0", "169.254.", "10.", "192.168.", "172."];
|
|
91
|
+
if (blocked.some((b) => u.hostname.startsWith(b))) {
|
|
92
|
+
throw new NeutronAuthError(`baseUrl blocked: ${u.hostname}`);
|
|
93
|
+
}
|
|
94
|
+
} catch (e) {
|
|
95
|
+
if (e instanceof NeutronAuthError) throw e;
|
|
96
|
+
throw new NeutronAuthError(`Invalid baseUrl: ${url}`);
|
|
97
|
+
}
|
|
82
98
|
}
|
|
83
99
|
log(message, data) {
|
|
84
100
|
if (!this.debug) return;
|
|
@@ -120,8 +136,8 @@ var HttpClient = class {
|
|
|
120
136
|
this.accountId = result.accountId;
|
|
121
137
|
this.accessToken = result.accessToken;
|
|
122
138
|
this.tokenExpiry = typeof result.expiredAt === "number" ? result.expiredAt : new Date(result.expiredAt).getTime();
|
|
123
|
-
return result;
|
|
124
139
|
this.log("Authenticated", { accountId: this.accountId });
|
|
140
|
+
return result;
|
|
125
141
|
}
|
|
126
142
|
async ensureAuth() {
|
|
127
143
|
if (!this.isTokenValid) {
|
|
@@ -723,7 +739,16 @@ var FiatResource = class {
|
|
|
723
739
|
ccy: params.sourceCcy,
|
|
724
740
|
method: "neutronpay",
|
|
725
741
|
amtRequested: params.sourceAmount,
|
|
726
|
-
reqDetails: {}
|
|
742
|
+
reqDetails: {},
|
|
743
|
+
kyc: {
|
|
744
|
+
type: params.kycType || "individual",
|
|
745
|
+
details: {
|
|
746
|
+
legalFullName: params.senderName || "Account Holder",
|
|
747
|
+
countryCode: params.senderCountryCode || "VN",
|
|
748
|
+
address1: params.senderAddress || "N/A",
|
|
749
|
+
contactNumber: params.senderPhone || "N/A"
|
|
750
|
+
}
|
|
751
|
+
}
|
|
727
752
|
},
|
|
728
753
|
destReq: {
|
|
729
754
|
ccy: params.destCcy,
|
|
@@ -736,7 +761,9 @@ var FiatResource = class {
|
|
|
736
761
|
type: params.kycType || "individual",
|
|
737
762
|
details: {
|
|
738
763
|
legalFullName: params.recipientName,
|
|
739
|
-
countryCode: params.countryCode
|
|
764
|
+
countryCode: params.countryCode,
|
|
765
|
+
address1: params.recipientAddress || "N/A",
|
|
766
|
+
contactNumber: params.recipientPhone || "N/A"
|
|
740
767
|
}
|
|
741
768
|
}
|
|
742
769
|
},
|
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 /**\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"]}
|
|
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 // SECURITY: validate baseUrl to prevent SSRF\n this.validateBaseUrl(this.baseUrl);\n }\n\n private validateBaseUrl(url: string): void {\n try {\n const u = new URL(url);\n if (u.protocol !== \"https:\") {\n throw new NeutronAuthError(\"baseUrl must use HTTPS\");\n }\n const blocked = [\"localhost\", \"127.\", \"0.0.0.0\", \"169.254.\", \"10.\", \"192.168.\", \"172.\"];\n if (blocked.some(b => u.hostname.startsWith(b))) {\n throw new NeutronAuthError(`baseUrl blocked: ${u.hostname}`);\n }\n } catch (e) {\n if (e instanceof NeutronAuthError) throw e;\n throw new NeutronAuthError(`Invalid baseUrl: ${url}`);\n }\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 this.log(\"Authenticated\", { accountId: this.accountId });\n return result;\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 /** Recipient address (optional, defaults to \"N/A\") */\n recipientAddress?: string;\n /** Recipient phone (optional, defaults to \"N/A\") */\n recipientPhone?: string;\n /** Sender legal full name — pulled from account KYC if not provided */\n senderName?: string;\n /** Sender country code — pulled from account if not provided */\n senderCountryCode?: string;\n /** Sender address — pulled from account KYC if not provided */\n senderAddress?: string;\n /** Sender phone — pulled from account KYC if not provided */\n senderPhone?: 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 kyc: {\n type: params.kycType || \"individual\",\n details: {\n legalFullName: params.senderName || \"Account Holder\",\n countryCode: params.senderCountryCode || \"VN\",\n address1: params.senderAddress || \"N/A\",\n contactNumber: params.senderPhone || \"N/A\",\n },\n },\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 address1: params.recipientAddress || \"N/A\",\n contactNumber: params.recipientPhone || \"N/A\",\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