@txnod/sdk 1.0.1

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.
Files changed (121) hide show
  1. package/AGENTS.md +29 -0
  2. package/CHANGELOG.md +22 -0
  3. package/LICENSE +21 -0
  4. package/README.md +434 -0
  5. package/dist/_shared/index.d.ts +68 -0
  6. package/dist/client-sandbox.d.ts +396 -0
  7. package/dist/client-sandbox.d.ts.map +1 -0
  8. package/dist/client-sandbox.js +448 -0
  9. package/dist/client-sandbox.js.map +1 -0
  10. package/dist/client.d.ts +429 -0
  11. package/dist/client.d.ts.map +1 -0
  12. package/dist/client.js +588 -0
  13. package/dist/client.js.map +1 -0
  14. package/dist/env.d.ts +29 -0
  15. package/dist/env.d.ts.map +1 -0
  16. package/dist/env.js +44 -0
  17. package/dist/env.js.map +1 -0
  18. package/dist/errors.d.ts +1887 -0
  19. package/dist/errors.d.ts.map +1 -0
  20. package/dist/errors.js +2107 -0
  21. package/dist/errors.js.map +1 -0
  22. package/dist/index.d.ts +35 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +32 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/internals/error-ctor-map.d.ts +11 -0
  27. package/dist/internals/error-ctor-map.d.ts.map +1 -0
  28. package/dist/internals/error-ctor-map.js +75 -0
  29. package/dist/internals/error-ctor-map.js.map +1 -0
  30. package/dist/internals/fetch-with-retry.d.ts +34 -0
  31. package/dist/internals/fetch-with-retry.d.ts.map +1 -0
  32. package/dist/internals/fetch-with-retry.js +233 -0
  33. package/dist/internals/fetch-with-retry.js.map +1 -0
  34. package/dist/internals/hmac.d.ts +2 -0
  35. package/dist/internals/hmac.d.ts.map +1 -0
  36. package/dist/internals/hmac.js +10 -0
  37. package/dist/internals/hmac.js.map +1 -0
  38. package/dist/internals/logger.d.ts +9 -0
  39. package/dist/internals/logger.d.ts.map +1 -0
  40. package/dist/internals/logger.js +16 -0
  41. package/dist/internals/logger.js.map +1 -0
  42. package/dist/internals/parse-problem-details.d.ts +3 -0
  43. package/dist/internals/parse-problem-details.d.ts.map +1 -0
  44. package/dist/internals/parse-problem-details.js +76 -0
  45. package/dist/internals/parse-problem-details.js.map +1 -0
  46. package/dist/internals/synthetic-details.d.ts +12 -0
  47. package/dist/internals/synthetic-details.d.ts.map +1 -0
  48. package/dist/internals/synthetic-details.js +19 -0
  49. package/dist/internals/synthetic-details.js.map +1 -0
  50. package/dist/verify/chains/bsc.d.ts +17 -0
  51. package/dist/verify/chains/bsc.d.ts.map +1 -0
  52. package/dist/verify/chains/bsc.js +15 -0
  53. package/dist/verify/chains/bsc.js.map +1 -0
  54. package/dist/verify/chains/btc.d.ts +22 -0
  55. package/dist/verify/chains/btc.d.ts.map +1 -0
  56. package/dist/verify/chains/btc.js +55 -0
  57. package/dist/verify/chains/btc.js.map +1 -0
  58. package/dist/verify/chains/cardano.d.ts +73 -0
  59. package/dist/verify/chains/cardano.d.ts.map +1 -0
  60. package/dist/verify/chains/cardano.js +175 -0
  61. package/dist/verify/chains/cardano.js.map +1 -0
  62. package/dist/verify/chains/evm.d.ts +21 -0
  63. package/dist/verify/chains/evm.d.ts.map +1 -0
  64. package/dist/verify/chains/evm.js +46 -0
  65. package/dist/verify/chains/evm.js.map +1 -0
  66. package/dist/verify/chains/polygon.d.ts +17 -0
  67. package/dist/verify/chains/polygon.d.ts.map +1 -0
  68. package/dist/verify/chains/polygon.js +15 -0
  69. package/dist/verify/chains/polygon.js.map +1 -0
  70. package/dist/verify/chains/secp256k1-bip32.d.ts +20 -0
  71. package/dist/verify/chains/secp256k1-bip32.d.ts.map +1 -0
  72. package/dist/verify/chains/secp256k1-bip32.js +88 -0
  73. package/dist/verify/chains/secp256k1-bip32.js.map +1 -0
  74. package/dist/verify/chains/ton-cell.d.ts +179 -0
  75. package/dist/verify/chains/ton-cell.d.ts.map +1 -0
  76. package/dist/verify/chains/ton-cell.js +614 -0
  77. package/dist/verify/chains/ton-cell.js.map +1 -0
  78. package/dist/verify/chains/ton.d.ts +84 -0
  79. package/dist/verify/chains/ton.d.ts.map +1 -0
  80. package/dist/verify/chains/ton.js +131 -0
  81. package/dist/verify/chains/ton.js.map +1 -0
  82. package/dist/verify/chains/tron.d.ts +21 -0
  83. package/dist/verify/chains/tron.d.ts.map +1 -0
  84. package/dist/verify/chains/tron.js +42 -0
  85. package/dist/verify/chains/tron.js.map +1 -0
  86. package/dist/verify/config.d.ts +41 -0
  87. package/dist/verify/config.d.ts.map +1 -0
  88. package/dist/verify/config.js +120 -0
  89. package/dist/verify/config.js.map +1 -0
  90. package/dist/verify/errors.d.ts +56 -0
  91. package/dist/verify/errors.d.ts.map +1 -0
  92. package/dist/verify/errors.js +58 -0
  93. package/dist/verify/errors.js.map +1 -0
  94. package/dist/verify/index.d.ts +119 -0
  95. package/dist/verify/index.d.ts.map +1 -0
  96. package/dist/verify/index.js +166 -0
  97. package/dist/verify/index.js.map +1 -0
  98. package/dist/verify/xpub-safety.d.ts +33 -0
  99. package/dist/verify/xpub-safety.d.ts.map +1 -0
  100. package/dist/verify/xpub-safety.js +54 -0
  101. package/dist/verify/xpub-safety.js.map +1 -0
  102. package/dist/verify-webhook-signature.d.ts +30 -0
  103. package/dist/verify-webhook-signature.d.ts.map +1 -0
  104. package/dist/verify-webhook-signature.js +84 -0
  105. package/dist/verify-webhook-signature.js.map +1 -0
  106. package/docs/00-getting-started.md +135 -0
  107. package/docs/01-authentication.md +114 -0
  108. package/docs/02-invoices.md +216 -0
  109. package/docs/03-rates-and-quotes.md +82 -0
  110. package/docs/04-webhooks.md +126 -0
  111. package/docs/05-errors.md +199 -0
  112. package/docs/05-sandbox.md +159 -0
  113. package/docs/06-idempotency.md +132 -0
  114. package/docs/examples/express-webhook-receiver.md +97 -0
  115. package/docs/examples/nextjs-route-handler.md +206 -0
  116. package/docs/examples/sandbox-vitest-suite.md +263 -0
  117. package/docs/index.md +66 -0
  118. package/docs/reference/client.md +392 -0
  119. package/docs/reference/errors.md +161 -0
  120. package/docs/reference/types.md +400 -0
  121. package/package.json +53 -0
package/dist/client.js ADDED
@@ -0,0 +1,588 @@
1
+ import { signedFetch, } from './internals/fetch-with-retry.js';
2
+ import { parseProblemDetails } from './internals/parse-problem-details.js';
3
+ import { parseXpubConfig, parseTonConfig } from './verify/config.js';
4
+ import { verifyAddress } from './verify/index.js';
5
+ import { assertNoTestnetXpubsInProduction } from './verify/xpub-safety.js';
6
+ import { TxnodEnvironmentUnknownError, TxnodExternalIdConflictError, TxnodSandboxKeyInProductionError, } from './errors.js';
7
+ import { getSdkEnv } from './env.js';
8
+ import { TxnodClientSandbox } from './client-sandbox.js';
9
+ const DEFAULT_BASE_URL = 'https://txnod.com';
10
+ function stripTrailingSlash(url) {
11
+ return url.endsWith('/') ? url.slice(0, -1) : url;
12
+ }
13
+ function toQueryParams(q) {
14
+ const out = {};
15
+ for (const [k, v] of Object.entries(q)) {
16
+ if (v === undefined)
17
+ continue;
18
+ out[k] = typeof v === 'boolean' ? String(v) : v;
19
+ }
20
+ return out;
21
+ }
22
+ const SANDBOX_API_SECRET_PREFIX = 'sk_sandbox_';
23
+ /**
24
+ * Implements spec §7.2 behavior matrix. Called from `TxnodClient.constructor`
25
+ * BEFORE any field assignment so a misconfiguration fails boot loudly.
26
+ *
27
+ * Per-constructor-invocation diagnostics: every call to `new TxnodClient(...)`
28
+ * with a sandbox secret emits exactly one `console.warn` (non-production env)
29
+ * or one `console.error` (production-detected with override) — module-level
30
+ * dedup is deliberately avoided so multiple clients in the same process all
31
+ * surface their config moment.
32
+ */
33
+ function assertEnvironmentSafety(apiSecret, projectId, options) {
34
+ const isSandboxSecret = apiSecret.startsWith(SANDBOX_API_SECRET_PREFIX);
35
+ if (!isSandboxSecret) {
36
+ return { prodOverrideActive: false };
37
+ }
38
+ const env = getSdkEnv(options.environment);
39
+ if (env === 'production') {
40
+ if (options.iAcknowledgeRoutingRealCustomerFundsToSandboxAddresses === true) {
41
+ // Non-suppressible diagnostic per spec §7.2. The byte-exact string is
42
+ // load-bearing — partner runbooks may grep for it.
43
+ console.error(`[txnod-sdk] CRITICAL: Sandbox API secret active in production-detected environment for project_id=${projectId}. Real on-chain payments will NOT be observed. iAcknowledgeRoutingRealCustomerFundsToSandboxAddresses=true is set; X-Txnod-Client-Environment: production will be sent on every request.`);
44
+ return { prodOverrideActive: true };
45
+ }
46
+ const signal = options.environment !== undefined
47
+ ? 'environment_option'
48
+ : process.env['TXNOD_ENVIRONMENT'] === 'production'
49
+ ? 'TXNOD_ENVIRONMENT'
50
+ : 'NODE_ENV';
51
+ throw new TxnodSandboxKeyInProductionError(signal);
52
+ }
53
+ if (env === 'unknown') {
54
+ throw new TxnodEnvironmentUnknownError();
55
+ }
56
+ // env === 'non-production' — emit one warn per construction.
57
+ console.warn('[txnod-sdk] Sandbox API secret detected. Real on-chain payments will not be observed.');
58
+ return { prodOverrideActive: false };
59
+ }
60
+ const REQUEST_ID_HEADER = 'X-Txnod-Request-Id';
61
+ /**
62
+ * Typed client for the TxNod integration API. Every method signs outbound
63
+ * requests with HMAC-SHA256 using `apiSecret`, retries on 429 and 5xx, and
64
+ * throws `TxnodError` on non-2xx responses.
65
+ *
66
+ * @example
67
+ * ```ts
68
+ * import { TxnodClient } from '@txnod/sdk';
69
+ *
70
+ * const client = new TxnodClient({
71
+ * projectId: process.env.TXNOD_PROJECT_ID!,
72
+ * apiSecret: process.env.TXNOD_API_SECRET!,
73
+ * });
74
+ *
75
+ * const invoice = await client.createInvoice({
76
+ * amount_usd: 10.0,
77
+ * coin: 'btc',
78
+ * external_id: 'order-123',
79
+ * callback_url: 'https://my-site.com/webhooks/txnod',
80
+ * });
81
+ * console.log(invoice.id, invoice.address);
82
+ * ```
83
+ */
84
+ export class TxnodClient {
85
+ #projectId;
86
+ #apiSecret;
87
+ #baseUrl;
88
+ #requestTimeoutMs;
89
+ #maxResponseBytes;
90
+ #requestLogger;
91
+ #prodOverrideActive;
92
+ #environmentOption;
93
+ #xpubConfig;
94
+ #tonConfig;
95
+ #sandboxNamespace;
96
+ #requestBound;
97
+ /**
98
+ * Server `X-Txnod-Request-Id` header from the most recently completed call,
99
+ * regardless of HTTP status. Reset to `undefined` at the start of every call,
100
+ * so a value here always corresponds to the call that just finished. Use it
101
+ * to correlate a successful response with TxNod-side logs (on failure paths
102
+ * the same id is also surfaced as `err.request_id` on the thrown
103
+ * `TxnodError`).
104
+ *
105
+ * Caveat: the field is per-instance, not per-call. Concurrent calls on a
106
+ * shared `TxnodClient` will overwrite each other; create a new client per
107
+ * request scope, or read the field synchronously after `await`-ing a single
108
+ * call.
109
+ */
110
+ lastRequestId;
111
+ constructor(options) {
112
+ const safety = assertEnvironmentSafety(options.apiSecret, options.projectId, options);
113
+ this.#projectId = options.projectId;
114
+ this.#apiSecret = options.apiSecret;
115
+ this.#baseUrl = stripTrailingSlash(options.baseUrl ?? DEFAULT_BASE_URL);
116
+ this.#requestTimeoutMs = options.requestTimeoutMs;
117
+ this.#maxResponseBytes = options.maxResponseBytes;
118
+ this.#requestLogger = options.requestLogger;
119
+ this.#prodOverrideActive = safety.prodOverrideActive;
120
+ this.#environmentOption = options.environment;
121
+ this.#xpubConfig = parseXpubConfig();
122
+ this.#tonConfig = parseTonConfig();
123
+ assertNoTestnetXpubsInProduction(this.#xpubConfig, getSdkEnv(this.#environmentOption));
124
+ }
125
+ /**
126
+ * Lazy accessor for the `client.sandbox.*` namespace exposing 14 thin HTTP
127
+ * wrappers around `/api/v1/sandbox/...` endpoints. The namespace class is
128
+ * only constructed on first access — when an integrator never references
129
+ * `client.sandbox`, the bundler's tree-shaker drops the entire
130
+ * `TxnodClientSandbox` class graph from the produced bundle.
131
+ *
132
+ * Methods throw the typed sandbox-specific error classes (e.g.
133
+ * `TxnodSandboxInvoiceTransitionInvalidError`) on 4xx/5xx server responses
134
+ * per FR55. See `docs/05-sandbox.md` in the bundled tarball for the full
135
+ * surface and code examples.
136
+ *
137
+ * @example
138
+ * ```ts
139
+ * import { TxnodClient, TxnodSandboxInvoiceTransitionInvalidError } from '@txnod/sdk';
140
+ *
141
+ * const client = new TxnodClient({
142
+ * projectId: process.env.TXNOD_PROJECT_ID!,
143
+ * apiSecret: process.env.TXNOD_API_SECRET!,
144
+ * environment: 'non-production',
145
+ * });
146
+ *
147
+ * try {
148
+ * const result = await client.sandbox.simulatePaid('01HK8MAR2QEXAMPLE000000000');
149
+ * console.log(result.event_id, result.status);
150
+ * } catch (err) {
151
+ * if (err instanceof TxnodSandboxInvoiceTransitionInvalidError) {
152
+ * console.error('forbidden simulate transition', err.request_id);
153
+ * } else {
154
+ * throw err;
155
+ * }
156
+ * }
157
+ * ```
158
+ */
159
+ get sandbox() {
160
+ if (this.#sandboxNamespace === undefined) {
161
+ if (this.#requestBound === undefined) {
162
+ this.#requestBound = (input) => this.#request(input);
163
+ }
164
+ this.#sandboxNamespace = new TxnodClientSandbox(this.#requestBound);
165
+ }
166
+ return this.#sandboxNamespace;
167
+ }
168
+ /**
169
+ * Re-read `TXNOD_<chain>_XPUB` env vars (and TON-specific siblings — the
170
+ * `TXNOD_TON_PUBKEY` family) into the client's xpub config. Useful after a
171
+ * wallet rotation in long-lived processes (Lambda containers, daemon-style
172
+ * workers) where the constructor ran with stale env values. Idempotent —
173
+ * calling it when env is unchanged is a no-op.
174
+ *
175
+ * @example
176
+ * ```ts
177
+ * import { TxnodClient } from '@txnod/sdk';
178
+ *
179
+ * const client = new TxnodClient({
180
+ * projectId: process.env.TXNOD_PROJECT_ID!,
181
+ * apiSecret: process.env.TXNOD_API_SECRET!,
182
+ * });
183
+ *
184
+ * // Operator rotated their xpub via the dashboard and your secrets manager
185
+ * // pushed the new TXNOD_BTC_XPUB into process.env. Pick it up without a restart:
186
+ * process.env.TXNOD_BTC_XPUB = 'zpub6r_NEW';
187
+ * client.refreshXpubConfig();
188
+ *
189
+ * // Subsequent createInvoice calls now verify the address against the new xpub.
190
+ * await client.createInvoice({
191
+ * external_id: 'after-rotation',
192
+ * coin: 'btc',
193
+ * amount_usd: 10,
194
+ * });
195
+ * ```
196
+ */
197
+ refreshXpubConfig() {
198
+ this.#xpubConfig = parseXpubConfig();
199
+ this.#tonConfig = parseTonConfig();
200
+ assertNoTestnetXpubsInProduction(this.#xpubConfig, getSdkEnv(this.#environmentOption));
201
+ }
202
+ async #request(input) {
203
+ const fetchInput = {
204
+ baseUrl: this.#baseUrl,
205
+ projectId: this.#projectId,
206
+ apiSecret: this.#apiSecret,
207
+ method: input.method,
208
+ path: input.path,
209
+ };
210
+ if (input.query !== undefined)
211
+ fetchInput.query = input.query;
212
+ if (input.body !== undefined)
213
+ fetchInput.body = input.body;
214
+ if (this.#requestTimeoutMs !== undefined)
215
+ fetchInput.requestTimeoutMs = this.#requestTimeoutMs;
216
+ if (this.#maxResponseBytes !== undefined)
217
+ fetchInput.maxResponseBytes = this.#maxResponseBytes;
218
+ if (this.#requestLogger !== undefined)
219
+ fetchInput.requestLogger = this.#requestLogger;
220
+ if (this.#prodOverrideActive) {
221
+ fetchInput.extraHeaders = { 'X-Txnod-Client-Environment': 'production' };
222
+ }
223
+ this.lastRequestId = undefined;
224
+ const response = await signedFetch(fetchInput);
225
+ const headerRequestId = response.headers.get(REQUEST_ID_HEADER);
226
+ this.lastRequestId =
227
+ headerRequestId !== null && headerRequestId.length > 0
228
+ ? headerRequestId
229
+ : undefined;
230
+ if (response.status >= 200 && response.status < 300) {
231
+ return (await response.json());
232
+ }
233
+ throw await parseProblemDetails(response);
234
+ }
235
+ /**
236
+ * Create a new invoice. Idempotent on `(project_id, external_id)`. When the
237
+ * matching `TXNOD_<chain>_XPUB` env var is set, the SDK automatically
238
+ * verifies the returned address derives from the configured xpub at the
239
+ * invoice's `derivation_path` and throws `AddressVerificationError` on
240
+ * mismatch — no flag needed.
241
+ *
242
+ * @example
243
+ * ```ts
244
+ * import { TxnodClient, TxnodError, AddressVerificationError } from '@txnod/sdk';
245
+ *
246
+ * // Set TXNOD_BTC_XPUB=zpub6r... in env to enable address verification.
247
+ * const client = new TxnodClient({
248
+ * projectId: process.env.TXNOD_PROJECT_ID!,
249
+ * apiSecret: process.env.TXNOD_API_SECRET!,
250
+ * });
251
+ *
252
+ * try {
253
+ * const invoice = await client.createInvoice({
254
+ * amount_usd: 10.0,
255
+ * coin: 'btc',
256
+ * external_id: 'order-123',
257
+ * callback_url: 'https://my-site.com/webhooks/txnod',
258
+ * });
259
+ * console.log(invoice.id, invoice.address, invoice.payment_uri);
260
+ * } catch (err) {
261
+ * if (err instanceof AddressVerificationError) {
262
+ * console.error('address verify failed', err.expected_address, err.derived_address);
263
+ * } else if (err instanceof TxnodError) {
264
+ * console.error(err.error_code, err.status, err.request_id);
265
+ * }
266
+ * throw err;
267
+ * }
268
+ * ```
269
+ */
270
+ async createInvoice(body) {
271
+ const invoice = await this.#request({
272
+ method: 'POST',
273
+ path: '/api/v1/invoices',
274
+ body,
275
+ });
276
+ const verifyInput = {
277
+ invoice,
278
+ config: this.#xpubConfig,
279
+ };
280
+ if (this.#tonConfig !== undefined)
281
+ verifyInput.tonConfig = this.#tonConfig;
282
+ verifyAddress(verifyInput);
283
+ return invoice;
284
+ }
285
+ /**
286
+ * Idempotent invoice creation. Tries `createInvoice`; on
287
+ * `TxnodExternalIdConflictError` fetches the pre-existing invoice via
288
+ * `searchInvoices({ external_id })` and returns it. Use this when your
289
+ * checkout flow may retry the same `external_id` (network glitches, idempotent
290
+ * upstream queues) and you want a single round-trip-then-fetch path.
291
+ *
292
+ * @example
293
+ * ```ts
294
+ * const invoice = await client.createOrGetInvoice({
295
+ * external_id: 'order-42',
296
+ * coin: 'usdt_trc20',
297
+ * amount_usd: 9.99,
298
+ * });
299
+ * ```
300
+ */
301
+ async createOrGetInvoice(body) {
302
+ try {
303
+ return await this.createInvoice(body);
304
+ }
305
+ catch (err) {
306
+ if (!(err instanceof TxnodExternalIdConflictError))
307
+ throw err;
308
+ const page = await this.searchInvoices({
309
+ external_id: body.external_id,
310
+ limit: 1,
311
+ });
312
+ const existing = page.items[0];
313
+ if (existing === undefined) {
314
+ // Conflict raised but the row is not findable via search — surface the
315
+ // original error rather than silently masking it.
316
+ throw err;
317
+ }
318
+ return existing;
319
+ }
320
+ }
321
+ /**
322
+ * Fetch an invoice by ULID.
323
+ *
324
+ * @example
325
+ * ```ts
326
+ * import { TxnodClient, TxnodError } from '@txnod/sdk';
327
+ *
328
+ * const client = new TxnodClient({
329
+ * projectId: process.env.TXNOD_PROJECT_ID!,
330
+ * apiSecret: process.env.TXNOD_API_SECRET!,
331
+ * });
332
+ *
333
+ * try {
334
+ * const invoice = await client.getInvoice('01HK8MAR2QEXAMPLE000000000');
335
+ * console.log(invoice.status);
336
+ * } catch (err) {
337
+ * if (err instanceof TxnodError) console.error(err.error_code);
338
+ * throw err;
339
+ * }
340
+ * ```
341
+ */
342
+ getInvoice(id) {
343
+ return this.#request({
344
+ method: 'GET',
345
+ path: `/api/v1/invoices/${id}`,
346
+ });
347
+ }
348
+ /**
349
+ * Search invoices with snake_case query filters.
350
+ *
351
+ * @example
352
+ * ```ts
353
+ * import { TxnodClient, TxnodError } from '@txnod/sdk';
354
+ *
355
+ * const client = new TxnodClient({
356
+ * projectId: process.env.TXNOD_PROJECT_ID!,
357
+ * apiSecret: process.env.TXNOD_API_SECRET!,
358
+ * });
359
+ *
360
+ * try {
361
+ * const page = await client.searchInvoices({
362
+ * status: 'paid',
363
+ * limit: 20,
364
+ * });
365
+ * for (const invoice of page.items) console.log(invoice.id);
366
+ * } catch (err) {
367
+ * if (err instanceof TxnodError) console.error(err.error_code);
368
+ * throw err;
369
+ * }
370
+ * ```
371
+ */
372
+ searchInvoices(query) {
373
+ return this.#request({
374
+ method: 'GET',
375
+ path: '/api/v1/invoices',
376
+ query: toQueryParams(query),
377
+ });
378
+ }
379
+ /**
380
+ * Cancel a pending invoice.
381
+ *
382
+ * @example
383
+ * ```ts
384
+ * import { TxnodClient, TxnodError } from '@txnod/sdk';
385
+ *
386
+ * const client = new TxnodClient({
387
+ * projectId: process.env.TXNOD_PROJECT_ID!,
388
+ * apiSecret: process.env.TXNOD_API_SECRET!,
389
+ * });
390
+ *
391
+ * try {
392
+ * const cancelled = await client.cancelInvoice('01HK8MAR2QEXAMPLE000000000');
393
+ * console.log(cancelled.status);
394
+ * } catch (err) {
395
+ * if (err instanceof TxnodError) console.error(err.error_code);
396
+ * throw err;
397
+ * }
398
+ * ```
399
+ */
400
+ cancelInvoice(id) {
401
+ return this.#request({
402
+ method: 'POST',
403
+ path: `/api/v1/invoices/${id}/cancel`,
404
+ });
405
+ }
406
+ /**
407
+ * List on-chain receipts that did not match any invoice address.
408
+ *
409
+ * @example
410
+ * ```ts
411
+ * import { TxnodClient, TxnodError } from '@txnod/sdk';
412
+ *
413
+ * const client = new TxnodClient({
414
+ * projectId: process.env.TXNOD_PROJECT_ID!,
415
+ * apiSecret: process.env.TXNOD_API_SECRET!,
416
+ * });
417
+ *
418
+ * try {
419
+ * const page = await client.listOrphanPayments({ chain: 'btc', limit: 50 });
420
+ * for (const orphan of page.items) console.log(orphan.tx_hash);
421
+ * } catch (err) {
422
+ * if (err instanceof TxnodError) console.error(err.error_code);
423
+ * throw err;
424
+ * }
425
+ * ```
426
+ */
427
+ listOrphanPayments(query) {
428
+ return this.#request({
429
+ method: 'GET',
430
+ path: '/api/v1/orphan-payments',
431
+ query: toQueryParams(query),
432
+ });
433
+ }
434
+ /**
435
+ * Attribute an orphan payment to an external invoice id.
436
+ *
437
+ * @example
438
+ * ```ts
439
+ * import { TxnodClient, TxnodError } from '@txnod/sdk';
440
+ *
441
+ * const client = new TxnodClient({
442
+ * projectId: process.env.TXNOD_PROJECT_ID!,
443
+ * apiSecret: process.env.TXNOD_API_SECRET!,
444
+ * });
445
+ *
446
+ * try {
447
+ * const invoice = await client.attributeOrphanPayment('0xabc123', {
448
+ * external_id: 'order-123',
449
+ * });
450
+ * console.log(invoice.id);
451
+ * } catch (err) {
452
+ * if (err instanceof TxnodError) console.error(err.error_code);
453
+ * throw err;
454
+ * }
455
+ * ```
456
+ */
457
+ attributeOrphanPayment(txHash, body) {
458
+ return this.#request({
459
+ method: 'POST',
460
+ path: `/api/v1/orphan-payments/${txHash}/attribute`,
461
+ body,
462
+ });
463
+ }
464
+ /**
465
+ * List outbound webhook events for the authenticated project.
466
+ *
467
+ * @example
468
+ * ```ts
469
+ * import { TxnodClient, TxnodError } from '@txnod/sdk';
470
+ *
471
+ * const client = new TxnodClient({
472
+ * projectId: process.env.TXNOD_PROJECT_ID!,
473
+ * apiSecret: process.env.TXNOD_API_SECRET!,
474
+ * });
475
+ *
476
+ * try {
477
+ * const page = await client.listWebhookEvents({
478
+ * status: 'delivered',
479
+ * limit: 100,
480
+ * });
481
+ * for (const event of page.items) console.log(event.id, event.status);
482
+ * } catch (err) {
483
+ * if (err instanceof TxnodError) console.error(err.error_code);
484
+ * throw err;
485
+ * }
486
+ * ```
487
+ */
488
+ listWebhookEvents(query) {
489
+ return this.#request({
490
+ method: 'GET',
491
+ path: '/api/v1/webhooks/events',
492
+ query: toQueryParams(query),
493
+ });
494
+ }
495
+ /**
496
+ * Resend a previously dispatched webhook event.
497
+ *
498
+ * @example
499
+ * ```ts
500
+ * import { TxnodClient, TxnodError } from '@txnod/sdk';
501
+ *
502
+ * const client = new TxnodClient({
503
+ * projectId: process.env.TXNOD_PROJECT_ID!,
504
+ * apiSecret: process.env.TXNOD_API_SECRET!,
505
+ * });
506
+ *
507
+ * try {
508
+ * const resent = await client.resendWebhookEvent(
509
+ * '01HK8MAR2QEXAMPLE000000000',
510
+ * );
511
+ * console.log(resent.event_id);
512
+ * } catch (err) {
513
+ * if (err instanceof TxnodError) console.error(err.error_code);
514
+ * throw err;
515
+ * }
516
+ * ```
517
+ */
518
+ resendWebhookEvent(eventId) {
519
+ return this.#request({
520
+ method: 'POST',
521
+ path: `/api/v1/webhooks/events/${eventId}/resend`,
522
+ });
523
+ }
524
+ /**
525
+ * Returns an indicative rate for pre-invoice pricing. The binding rate is
526
+ * captured by `createInvoice` in `rate_snapshot`; any delta between this
527
+ * quote and the invoice is the partner's responsibility per FR33c.
528
+ *
529
+ * @example
530
+ * ```ts
531
+ * import { TxnodClient, TxnodError } from '@txnod/sdk';
532
+ *
533
+ * const client = new TxnodClient({
534
+ * projectId: process.env.TXNOD_PROJECT_ID!,
535
+ * apiSecret: process.env.TXNOD_API_SECRET!,
536
+ * });
537
+ *
538
+ * try {
539
+ * const rates = await client.getRates({ coins: 'btc,eth' });
540
+ * console.log(rates.rates.btc);
541
+ * } catch (err) {
542
+ * if (err instanceof TxnodError) console.error(err.error_code);
543
+ * throw err;
544
+ * }
545
+ * ```
546
+ */
547
+ getRates(query) {
548
+ return this.#request({
549
+ method: 'GET',
550
+ path: '/api/v1/rates',
551
+ query: toQueryParams(query),
552
+ });
553
+ }
554
+ /**
555
+ * Returns an indicative rate for pre-invoice pricing. The binding rate is
556
+ * captured by `createInvoice` in `rate_snapshot`; any delta between this
557
+ * quote and the invoice is the partner's responsibility per FR33c.
558
+ *
559
+ * @example
560
+ * ```ts
561
+ * import { TxnodClient, TxnodError } from '@txnod/sdk';
562
+ *
563
+ * const client = new TxnodClient({
564
+ * projectId: process.env.TXNOD_PROJECT_ID!,
565
+ * apiSecret: process.env.TXNOD_API_SECRET!,
566
+ * });
567
+ *
568
+ * try {
569
+ * const quote = await client.quoteAmount({
570
+ * amount_usd: 10.0,
571
+ * coins: 'btc',
572
+ * });
573
+ * console.log(quote.quotes.btc);
574
+ * } catch (err) {
575
+ * if (err instanceof TxnodError) console.error(err.error_code);
576
+ * throw err;
577
+ * }
578
+ * ```
579
+ */
580
+ quoteAmount(query) {
581
+ return this.#request({
582
+ method: 'GET',
583
+ path: '/api/v1/quote',
584
+ query: toQueryParams(query),
585
+ });
586
+ }
587
+ }
588
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
package/dist/env.d.ts ADDED
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Single, concentrated reader for environment-detection signals consumed by
3
+ * `TxnodClient`'s sandbox-safety guards. Resolution order (per spec §7.2 + F-2):
4
+ *
5
+ * 1. `explicit` argument — the constructor's `environment` option wins
6
+ * everything when set. Use it for staging replicas where `NODE_ENV` is
7
+ * conventionally `'production'` but the secret is sandbox.
8
+ * 2. `process.env.TXNOD_ENVIRONMENT === 'production'` → `'production'`.
9
+ * 3. `process.env.TXNOD_ENVIRONMENT === 'non-production'` → `'non-production'`.
10
+ * 4. `process.env.NODE_ENV === 'production'` → `'production'`.
11
+ * 5. `process.env.NODE_ENV === 'development' | 'test'` → `'non-production'`.
12
+ * 6. Otherwise → `'unknown'`.
13
+ *
14
+ * **String comparisons are case-sensitive** to match Node.js convention
15
+ * (`NODE_ENV=Production` is treated as unrecognised by Express, Next.js, and
16
+ * Node's own runtime checks). A misconfigured `'Production'` therefore
17
+ * resolves to `'unknown'` and — paired with a sandbox secret — surfaces as
18
+ * `TxnodEnvironmentUnknownError` at construction, prompting the operator to
19
+ * fix the casing.
20
+ *
21
+ * The optional `env` parameter exists for testability — production callers
22
+ * always omit it. Mirrors the same shape as `parseXpubConfig`.
23
+ *
24
+ * **This is the only `process.env` reader in `packages/sdk/src/` for environment
25
+ * signals.** Do not introduce a second; it would split the resolution rules
26
+ * across files and bypass the sandbox-safety matrix in `TxnodClient`.
27
+ */
28
+ export declare function getSdkEnv(explicit?: 'production' | 'non-production', env?: NodeJS.ProcessEnv): 'production' | 'non-production' | 'unknown';
29
+ //# sourceMappingURL=env.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,SAAS,CACvB,QAAQ,CAAC,EAAE,YAAY,GAAG,gBAAgB,EAC1C,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,YAAY,GAAG,gBAAgB,GAAG,SAAS,CAW7C"}
package/dist/env.js ADDED
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Single, concentrated reader for environment-detection signals consumed by
3
+ * `TxnodClient`'s sandbox-safety guards. Resolution order (per spec §7.2 + F-2):
4
+ *
5
+ * 1. `explicit` argument — the constructor's `environment` option wins
6
+ * everything when set. Use it for staging replicas where `NODE_ENV` is
7
+ * conventionally `'production'` but the secret is sandbox.
8
+ * 2. `process.env.TXNOD_ENVIRONMENT === 'production'` → `'production'`.
9
+ * 3. `process.env.TXNOD_ENVIRONMENT === 'non-production'` → `'non-production'`.
10
+ * 4. `process.env.NODE_ENV === 'production'` → `'production'`.
11
+ * 5. `process.env.NODE_ENV === 'development' | 'test'` → `'non-production'`.
12
+ * 6. Otherwise → `'unknown'`.
13
+ *
14
+ * **String comparisons are case-sensitive** to match Node.js convention
15
+ * (`NODE_ENV=Production` is treated as unrecognised by Express, Next.js, and
16
+ * Node's own runtime checks). A misconfigured `'Production'` therefore
17
+ * resolves to `'unknown'` and — paired with a sandbox secret — surfaces as
18
+ * `TxnodEnvironmentUnknownError` at construction, prompting the operator to
19
+ * fix the casing.
20
+ *
21
+ * The optional `env` parameter exists for testability — production callers
22
+ * always omit it. Mirrors the same shape as `parseXpubConfig`.
23
+ *
24
+ * **This is the only `process.env` reader in `packages/sdk/src/` for environment
25
+ * signals.** Do not introduce a second; it would split the resolution rules
26
+ * across files and bypass the sandbox-safety matrix in `TxnodClient`.
27
+ */
28
+ export function getSdkEnv(explicit, env = process.env) {
29
+ if (explicit === 'production' || explicit === 'non-production') {
30
+ return explicit;
31
+ }
32
+ const txnodEnv = env['TXNOD_ENVIRONMENT'];
33
+ if (txnodEnv === 'production')
34
+ return 'production';
35
+ if (txnodEnv === 'non-production')
36
+ return 'non-production';
37
+ const nodeEnv = env['NODE_ENV'];
38
+ if (nodeEnv === 'production')
39
+ return 'production';
40
+ if (nodeEnv === 'development' || nodeEnv === 'test')
41
+ return 'non-production';
42
+ return 'unknown';
43
+ }
44
+ //# sourceMappingURL=env.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,UAAU,SAAS,CACvB,QAA0C,EAC1C,MAAyB,OAAO,CAAC,GAAG;IAEpC,IAAI,QAAQ,KAAK,YAAY,IAAI,QAAQ,KAAK,gBAAgB,EAAE,CAAC;QAC/D,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,MAAM,QAAQ,GAAG,GAAG,CAAC,mBAAmB,CAAC,CAAC;IAC1C,IAAI,QAAQ,KAAK,YAAY;QAAE,OAAO,YAAY,CAAC;IACnD,IAAI,QAAQ,KAAK,gBAAgB;QAAE,OAAO,gBAAgB,CAAC;IAC3D,MAAM,OAAO,GAAG,GAAG,CAAC,UAAU,CAAC,CAAC;IAChC,IAAI,OAAO,KAAK,YAAY;QAAE,OAAO,YAAY,CAAC;IAClD,IAAI,OAAO,KAAK,aAAa,IAAI,OAAO,KAAK,MAAM;QAAE,OAAO,gBAAgB,CAAC;IAC7E,OAAO,SAAS,CAAC;AACnB,CAAC"}