@tallion/sdk 0.1.2 → 0.1.4

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.d.mts CHANGED
@@ -2,12 +2,19 @@ interface TallyConfig {
2
2
  apiKey: string;
3
3
  baseUrl?: string;
4
4
  }
5
+ interface PurchaseContext {
6
+ amount: number;
7
+ description: string;
8
+ merchant?: string;
9
+ reference?: string;
10
+ }
5
11
  interface CreateAuthUrlOptions {
6
12
  customerIdentifier?: string;
7
13
  redirectUrl: string;
8
14
  scopes?: string[];
9
15
  codeChallengeMethod?: "S256" | "plain";
10
16
  suggestedLimits?: SpendLimits;
17
+ purchaseContext?: PurchaseContext;
11
18
  }
12
19
  interface AuthUrlResult {
13
20
  url: string;
@@ -92,6 +99,59 @@ interface WebhookEvent {
92
99
  timestamp: string;
93
100
  data: Record<string, unknown>;
94
101
  }
102
+ interface CreateIntentOptions {
103
+ customerToken: string;
104
+ amount: number;
105
+ currency?: string;
106
+ merchant?: {
107
+ name: string;
108
+ url?: string;
109
+ mcc?: string;
110
+ };
111
+ product?: {
112
+ description: string;
113
+ url?: string;
114
+ };
115
+ walletId?: string;
116
+ amountTolerancePct?: number;
117
+ }
118
+ interface IntentCardDetails {
119
+ pan: string;
120
+ cvv: string;
121
+ expMonth: number;
122
+ expYear: number;
123
+ lastFour: string;
124
+ }
125
+ interface IntentResult {
126
+ intentId: string;
127
+ status: 'card_issued' | 'awaiting_approval' | 'declined';
128
+ amount: number;
129
+ currency: string;
130
+ merchantName?: string;
131
+ expiresAt?: string;
132
+ transactionId?: string;
133
+ /** Card details — only present when status is "card_issued". */
134
+ card?: IntentCardDetails;
135
+ }
136
+ interface IntentStatusResult {
137
+ intentId: string;
138
+ status: string;
139
+ amount: number;
140
+ currency: string;
141
+ merchantName?: string;
142
+ cardLastFour?: string;
143
+ asaVerified: boolean;
144
+ asaAmount?: number;
145
+ asaMerchantDescriptor?: string;
146
+ asaMismatchReason?: string;
147
+ transactionId?: string;
148
+ expiresAt?: string;
149
+ createdAt: string;
150
+ }
151
+ interface ListIntentsOptions {
152
+ limit?: number;
153
+ offset?: number;
154
+ }
95
155
 
96
156
  declare class AuthorizeModule {
97
157
  private baseUrl;
@@ -126,6 +186,29 @@ declare class BalanceModule {
126
186
  get(customerToken: string, walletId?: string): Promise<BalanceResult>;
127
187
  }
128
188
 
189
+ declare class IntentsModule {
190
+ private baseUrl;
191
+ private apiKey;
192
+ constructor(baseUrl: string, apiKey: string);
193
+ /**
194
+ * Create a purchase intent (Buy Anywhere).
195
+ * Returns a virtual card for the customer to use at the merchant.
196
+ */
197
+ create(options: CreateIntentOptions): Promise<IntentResult>;
198
+ /**
199
+ * Get the current status of a purchase intent.
200
+ */
201
+ get(customerToken: string, intentId: string): Promise<IntentStatusResult>;
202
+ /**
203
+ * Cancel an active purchase intent.
204
+ */
205
+ cancel(customerToken: string, intentId: string): Promise<IntentStatusResult>;
206
+ /**
207
+ * List purchase intents for the authenticated customer.
208
+ */
209
+ list(customerToken: string, options?: ListIntentsOptions): Promise<IntentStatusResult[]>;
210
+ }
211
+
129
212
  declare class PurchaseModule {
130
213
  private baseUrl;
131
214
  private apiKey;
@@ -163,6 +246,8 @@ declare class Tally {
163
246
  purchases: PurchaseModule;
164
247
  /** Balance operations */
165
248
  balances: BalanceModule;
249
+ /** Purchase intents (Buy Anywhere) */
250
+ intents: IntentsModule;
166
251
  /** Webhook signature verification */
167
252
  webhooks: WebhooksModule;
168
253
  constructor(config: TallyConfig);
@@ -190,4 +275,4 @@ declare class TallionError extends Error {
190
275
  constructor(status: number, message: string, code?: string);
191
276
  }
192
277
 
193
- export { type AuthUrlResult, AuthorizeModule, BalanceModule, type BalanceResult, type CreateAuthUrlOptions, type ExchangeCodeOptions, type LegacyPurchaseOptions, type LineItem, type MerchantInfo, PurchaseModule, type PurchaseOptions, type PurchaseResult, type RefreshTokenOptions, type SpendLimits, TallionError, Tally, type TallyConfig, type TokenResult, type TransactionContext, type WebhookEvent, WebhooksModule };
278
+ export { type AuthUrlResult, AuthorizeModule, BalanceModule, type BalanceResult, type CreateAuthUrlOptions, type CreateIntentOptions, type ExchangeCodeOptions, type IntentCardDetails, type IntentResult, type IntentStatusResult, IntentsModule, type LegacyPurchaseOptions, type LineItem, type ListIntentsOptions, type MerchantInfo, PurchaseModule, type PurchaseOptions, type PurchaseResult, type RefreshTokenOptions, type SpendLimits, TallionError, Tally, type TallyConfig, type TokenResult, type TransactionContext, type WebhookEvent, WebhooksModule };
package/dist/index.d.ts CHANGED
@@ -2,12 +2,19 @@ interface TallyConfig {
2
2
  apiKey: string;
3
3
  baseUrl?: string;
4
4
  }
5
+ interface PurchaseContext {
6
+ amount: number;
7
+ description: string;
8
+ merchant?: string;
9
+ reference?: string;
10
+ }
5
11
  interface CreateAuthUrlOptions {
6
12
  customerIdentifier?: string;
7
13
  redirectUrl: string;
8
14
  scopes?: string[];
9
15
  codeChallengeMethod?: "S256" | "plain";
10
16
  suggestedLimits?: SpendLimits;
17
+ purchaseContext?: PurchaseContext;
11
18
  }
12
19
  interface AuthUrlResult {
13
20
  url: string;
@@ -92,6 +99,59 @@ interface WebhookEvent {
92
99
  timestamp: string;
93
100
  data: Record<string, unknown>;
94
101
  }
102
+ interface CreateIntentOptions {
103
+ customerToken: string;
104
+ amount: number;
105
+ currency?: string;
106
+ merchant?: {
107
+ name: string;
108
+ url?: string;
109
+ mcc?: string;
110
+ };
111
+ product?: {
112
+ description: string;
113
+ url?: string;
114
+ };
115
+ walletId?: string;
116
+ amountTolerancePct?: number;
117
+ }
118
+ interface IntentCardDetails {
119
+ pan: string;
120
+ cvv: string;
121
+ expMonth: number;
122
+ expYear: number;
123
+ lastFour: string;
124
+ }
125
+ interface IntentResult {
126
+ intentId: string;
127
+ status: 'card_issued' | 'awaiting_approval' | 'declined';
128
+ amount: number;
129
+ currency: string;
130
+ merchantName?: string;
131
+ expiresAt?: string;
132
+ transactionId?: string;
133
+ /** Card details — only present when status is "card_issued". */
134
+ card?: IntentCardDetails;
135
+ }
136
+ interface IntentStatusResult {
137
+ intentId: string;
138
+ status: string;
139
+ amount: number;
140
+ currency: string;
141
+ merchantName?: string;
142
+ cardLastFour?: string;
143
+ asaVerified: boolean;
144
+ asaAmount?: number;
145
+ asaMerchantDescriptor?: string;
146
+ asaMismatchReason?: string;
147
+ transactionId?: string;
148
+ expiresAt?: string;
149
+ createdAt: string;
150
+ }
151
+ interface ListIntentsOptions {
152
+ limit?: number;
153
+ offset?: number;
154
+ }
95
155
 
96
156
  declare class AuthorizeModule {
97
157
  private baseUrl;
@@ -126,6 +186,29 @@ declare class BalanceModule {
126
186
  get(customerToken: string, walletId?: string): Promise<BalanceResult>;
127
187
  }
128
188
 
189
+ declare class IntentsModule {
190
+ private baseUrl;
191
+ private apiKey;
192
+ constructor(baseUrl: string, apiKey: string);
193
+ /**
194
+ * Create a purchase intent (Buy Anywhere).
195
+ * Returns a virtual card for the customer to use at the merchant.
196
+ */
197
+ create(options: CreateIntentOptions): Promise<IntentResult>;
198
+ /**
199
+ * Get the current status of a purchase intent.
200
+ */
201
+ get(customerToken: string, intentId: string): Promise<IntentStatusResult>;
202
+ /**
203
+ * Cancel an active purchase intent.
204
+ */
205
+ cancel(customerToken: string, intentId: string): Promise<IntentStatusResult>;
206
+ /**
207
+ * List purchase intents for the authenticated customer.
208
+ */
209
+ list(customerToken: string, options?: ListIntentsOptions): Promise<IntentStatusResult[]>;
210
+ }
211
+
129
212
  declare class PurchaseModule {
130
213
  private baseUrl;
131
214
  private apiKey;
@@ -163,6 +246,8 @@ declare class Tally {
163
246
  purchases: PurchaseModule;
164
247
  /** Balance operations */
165
248
  balances: BalanceModule;
249
+ /** Purchase intents (Buy Anywhere) */
250
+ intents: IntentsModule;
166
251
  /** Webhook signature verification */
167
252
  webhooks: WebhooksModule;
168
253
  constructor(config: TallyConfig);
@@ -190,4 +275,4 @@ declare class TallionError extends Error {
190
275
  constructor(status: number, message: string, code?: string);
191
276
  }
192
277
 
193
- export { type AuthUrlResult, AuthorizeModule, BalanceModule, type BalanceResult, type CreateAuthUrlOptions, type ExchangeCodeOptions, type LegacyPurchaseOptions, type LineItem, type MerchantInfo, PurchaseModule, type PurchaseOptions, type PurchaseResult, type RefreshTokenOptions, type SpendLimits, TallionError, Tally, type TallyConfig, type TokenResult, type TransactionContext, type WebhookEvent, WebhooksModule };
278
+ export { type AuthUrlResult, AuthorizeModule, BalanceModule, type BalanceResult, type CreateAuthUrlOptions, type CreateIntentOptions, type ExchangeCodeOptions, type IntentCardDetails, type IntentResult, type IntentStatusResult, IntentsModule, type LegacyPurchaseOptions, type LineItem, type ListIntentsOptions, type MerchantInfo, PurchaseModule, type PurchaseOptions, type PurchaseResult, type RefreshTokenOptions, type SpendLimits, TallionError, Tally, type TallyConfig, type TokenResult, type TransactionContext, type WebhookEvent, WebhooksModule };
package/dist/index.js CHANGED
@@ -22,6 +22,7 @@ var index_exports = {};
22
22
  __export(index_exports, {
23
23
  AuthorizeModule: () => AuthorizeModule,
24
24
  BalanceModule: () => BalanceModule,
25
+ IntentsModule: () => IntentsModule,
25
26
  PurchaseModule: () => PurchaseModule,
26
27
  TallionError: () => TallionError,
27
28
  Tally: () => Tally,
@@ -115,6 +116,12 @@ var AuthorizeModule = class {
115
116
  max_per_day: options.suggestedLimits.maxPerDay,
116
117
  max_per_month: options.suggestedLimits.maxPerMonth,
117
118
  require_approval_above: options.suggestedLimits.requireApprovalAbove
119
+ } : void 0,
120
+ purchase_context: options.purchaseContext ? {
121
+ amount: options.purchaseContext.amount,
122
+ description: options.purchaseContext.description,
123
+ merchant: options.purchaseContext.merchant,
124
+ reference: options.purchaseContext.reference
118
125
  } : void 0
119
126
  }
120
127
  });
@@ -200,6 +207,111 @@ var BalanceModule = class {
200
207
  }
201
208
  };
202
209
 
210
+ // src/intents.ts
211
+ var IntentsModule = class {
212
+ constructor(baseUrl, apiKey) {
213
+ this.baseUrl = baseUrl;
214
+ this.apiKey = apiKey;
215
+ }
216
+ /**
217
+ * Create a purchase intent (Buy Anywhere).
218
+ * Returns a virtual card for the customer to use at the merchant.
219
+ */
220
+ async create(options) {
221
+ const res = await request(this.baseUrl, "/intents", options.customerToken, {
222
+ method: "POST",
223
+ body: {
224
+ amount: options.amount,
225
+ currency: options.currency || "USD",
226
+ wallet_id: options.walletId,
227
+ merchant: options.merchant ? {
228
+ name: options.merchant.name,
229
+ url: options.merchant.url,
230
+ mcc: options.merchant.mcc
231
+ } : void 0,
232
+ product: options.product ? {
233
+ description: options.product.description,
234
+ url: options.product.url
235
+ } : void 0,
236
+ amount_tolerance_pct: options.amountTolerancePct
237
+ }
238
+ });
239
+ return {
240
+ intentId: res.intent_id,
241
+ status: res.status,
242
+ amount: res.amount,
243
+ currency: res.currency,
244
+ merchantName: res.merchant_name,
245
+ expiresAt: res.expires_at,
246
+ transactionId: res.transaction_id,
247
+ card: res.card ? {
248
+ pan: res.card.pan,
249
+ cvv: res.card.cvv,
250
+ expMonth: res.card.exp_month,
251
+ expYear: res.card.exp_year,
252
+ lastFour: res.card.last_four
253
+ } : void 0
254
+ };
255
+ }
256
+ /**
257
+ * Get the current status of a purchase intent.
258
+ */
259
+ async get(customerToken, intentId) {
260
+ const res = await request(
261
+ this.baseUrl,
262
+ `/intents/${intentId}`,
263
+ customerToken
264
+ );
265
+ return mapIntentStatus(res);
266
+ }
267
+ /**
268
+ * Cancel an active purchase intent.
269
+ */
270
+ async cancel(customerToken, intentId) {
271
+ const res = await request(
272
+ this.baseUrl,
273
+ `/intents/${intentId}/cancel`,
274
+ customerToken,
275
+ { method: "POST" }
276
+ );
277
+ return mapIntentStatus(res);
278
+ }
279
+ /**
280
+ * List purchase intents for the authenticated customer.
281
+ */
282
+ async list(customerToken, options) {
283
+ const params = new URLSearchParams();
284
+ if (options?.limit !== void 0) params.set("limit", String(options.limit));
285
+ if (options?.offset !== void 0)
286
+ params.set("offset", String(options.offset));
287
+ const query = params.toString();
288
+ const path = query ? `/intents?${query}` : "/intents";
289
+ const res = await request(
290
+ this.baseUrl,
291
+ path,
292
+ customerToken
293
+ );
294
+ return res.map(mapIntentStatus);
295
+ }
296
+ };
297
+ function mapIntentStatus(raw) {
298
+ return {
299
+ intentId: raw.intent_id,
300
+ status: raw.status,
301
+ amount: raw.amount,
302
+ currency: raw.currency,
303
+ merchantName: raw.merchant_name,
304
+ cardLastFour: raw.card_last_four,
305
+ asaVerified: raw.asa_verified,
306
+ asaAmount: raw.asa_amount,
307
+ asaMerchantDescriptor: raw.asa_merchant_descriptor,
308
+ asaMismatchReason: raw.asa_mismatch_reason,
309
+ transactionId: raw.transaction_id,
310
+ expiresAt: raw.expires_at,
311
+ createdAt: raw.created_at
312
+ };
313
+ }
314
+
203
315
  // src/purchase.ts
204
316
  var PurchaseModule = class {
205
317
  constructor(baseUrl, apiKey) {
@@ -352,6 +464,7 @@ var Tally = class {
352
464
  this.baseUrl = resolveBaseUrl(config.apiKey, config.baseUrl);
353
465
  this.authorize = new AuthorizeModule(this.baseUrl, this.apiKey);
354
466
  this.purchases = new PurchaseModule(this.baseUrl, this.apiKey);
467
+ this.intents = new IntentsModule(this.baseUrl, this.apiKey);
355
468
  this.balances = new BalanceModule(this.baseUrl, this.apiKey);
356
469
  this.webhooks = new WebhooksModule();
357
470
  }
@@ -384,6 +497,7 @@ var Tally = class {
384
497
  0 && (module.exports = {
385
498
  AuthorizeModule,
386
499
  BalanceModule,
500
+ IntentsModule,
387
501
  PurchaseModule,
388
502
  TallionError,
389
503
  Tally,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/http.ts","../src/authorize.ts","../src/balance.ts","../src/purchase.ts","../src/webhooks.ts","../src/tally.ts"],"sourcesContent":["export { Tally } from \"./tally\";\nexport { TallionError } from \"./errors\";\nexport { AuthorizeModule } from \"./authorize\";\nexport { PurchaseModule } from \"./purchase\";\nexport { BalanceModule } from \"./balance\";\nexport { WebhooksModule } from \"./webhooks\";\n\nexport type {\n TallyConfig,\n CreateAuthUrlOptions,\n AuthUrlResult,\n ExchangeCodeOptions,\n TokenResult,\n RefreshTokenOptions,\n PurchaseOptions,\n LegacyPurchaseOptions,\n PurchaseResult,\n MerchantInfo,\n TransactionContext,\n LineItem,\n BalanceResult,\n SpendLimits,\n WebhookEvent,\n} from \"./types\";\n","export class TallionError extends Error {\n public readonly status: number;\n public readonly code?: string;\n\n constructor(status: number, message: string, code?: string) {\n super(message);\n this.name = \"TallionError\";\n this.status = status;\n this.code = code;\n }\n}\n","import { TallionError } from \"./errors\";\n\nconst SANDBOX_URL = \"https://api.sandbox.tallion.ai\";\nconst PRODUCTION_URL = \"https://api.tallion.ai\";\n\nexport function resolveBaseUrl(apiKey: string, overrideUrl?: string): string {\n if (overrideUrl) return overrideUrl;\n if (apiKey.startsWith(\"sk_live_\")) return PRODUCTION_URL;\n return SANDBOX_URL;\n}\n\nexport interface RequestOptions {\n method?: string;\n headers?: Record<string, string>;\n body?: unknown;\n}\n\nexport async function request<T>(\n baseUrl: string,\n path: string,\n apiKey: string,\n options: RequestOptions = {},\n): Promise<T> {\n if (!apiKey) {\n throw new TallionError(\n 401,\n \"Tallion API key is required. Get one at https://tallion.ai/developer\",\n \"missing_api_key\",\n );\n }\n const url = `${baseUrl}/api${path}`;\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${apiKey}`,\n ...options.headers,\n };\n\n const res = await fetch(url, {\n method: options.method || \"GET\",\n headers,\n body: options.body ? JSON.stringify(options.body) : undefined,\n });\n\n if (!res.ok) {\n const body = await res.json().catch(() => ({ error: \"Unknown error\" }));\n throw new TallionError(\n res.status,\n body.error || \"Request failed\",\n body.code,\n );\n }\n\n return res.json() as Promise<T>;\n}\n","import { request } from \"./http\";\nimport type {\n AuthUrlResult,\n CreateAuthUrlOptions,\n ExchangeCodeOptions,\n RefreshTokenOptions,\n TokenResult,\n} from \"./types\";\n\n/** Generate a random string for PKCE */\nfunction generateRandomString(length: number): string {\n const chars = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~\";\n const array = new Uint8Array(length);\n crypto.getRandomValues(array);\n return Array.from(array, (byte) => chars[byte % chars.length]).join(\"\");\n}\n\n/** SHA-256 hash for PKCE S256 challenge */\nasync function sha256(plain: string): Promise<string> {\n const encoder = new TextEncoder();\n const data = encoder.encode(plain);\n const hash = await crypto.subtle.digest(\"SHA-256\", data);\n return btoa(String.fromCharCode(...new Uint8Array(hash)))\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=+$/, \"\");\n}\n\nexport class AuthorizeModule {\n constructor(\n private baseUrl: string,\n private apiKey: string,\n ) {}\n\n /**\n * Create an authorization URL for customer consent.\n * Returns the URL to open in a popup/browser plus the PKCE code verifier.\n */\n async createUrl(options: CreateAuthUrlOptions): Promise<AuthUrlResult> {\n const codeVerifier = generateRandomString(64);\n const codeChallenge = await sha256(codeVerifier);\n\n const res = await request<{\n authorization_id: string;\n url: string;\n state: string;\n }>(this.baseUrl, \"/oauth/authorize\", this.apiKey, {\n method: \"POST\",\n body: {\n customer_identifier: options.customerIdentifier,\n redirect_url: options.redirectUrl,\n scopes: options.scopes || [\"purchase\", \"balance:read\"],\n code_challenge: codeChallenge,\n code_challenge_method: options.codeChallengeMethod || \"S256\",\n suggested_limits: options.suggestedLimits\n ? {\n max_per_transaction: options.suggestedLimits.maxPerTransaction,\n max_per_day: options.suggestedLimits.maxPerDay,\n max_per_month: options.suggestedLimits.maxPerMonth,\n require_approval_above: options.suggestedLimits.requireApprovalAbove,\n }\n : undefined,\n },\n });\n\n return {\n url: res.url,\n state: res.state,\n codeVerifier,\n authorizationId: res.authorization_id,\n };\n }\n\n /**\n * Exchange an authorization code for access + refresh tokens.\n */\n async exchangeCode(options: ExchangeCodeOptions): Promise<TokenResult> {\n const res = await request<{\n access_token: string;\n refresh_token: string;\n token_type: string;\n expires_in: number;\n customer_id: string;\n installation_id: string;\n }>(this.baseUrl, \"/oauth/token\", this.apiKey, {\n method: \"POST\",\n body: {\n grant_type: \"authorization_code\",\n code: options.code,\n code_verifier: options.codeVerifier,\n },\n });\n\n return {\n accessToken: res.access_token,\n refreshToken: res.refresh_token,\n tokenType: res.token_type,\n expiresIn: res.expires_in,\n customerId: res.customer_id,\n installationId: res.installation_id,\n };\n }\n\n /**\n * Refresh an access token using a refresh token.\n */\n async refreshToken(options: RefreshTokenOptions): Promise<TokenResult> {\n const res = await request<{\n access_token: string;\n refresh_token: string;\n token_type: string;\n expires_in: number;\n customer_id: string;\n installation_id: string;\n }>(this.baseUrl, \"/oauth/token\", this.apiKey, {\n method: \"POST\",\n body: {\n grant_type: \"refresh_token\",\n refresh_token: options.refreshToken,\n },\n });\n\n return {\n accessToken: res.access_token,\n refreshToken: res.refresh_token,\n tokenType: res.token_type,\n expiresIn: res.expires_in,\n customerId: res.customer_id,\n installationId: res.installation_id,\n };\n }\n\n /**\n * Revoke an access or refresh token.\n */\n async revoke(token: string): Promise<void> {\n await request(this.baseUrl, \"/oauth/revoke\", this.apiKey, {\n method: \"POST\",\n body: { token },\n });\n }\n}\n","import { request } from \"./http\";\nimport type { BalanceResult } from \"./types\";\n\nexport class BalanceModule {\n constructor(\n private baseUrl: string,\n private apiKey: string,\n ) {}\n\n /**\n * Get wallet balance for a customer (using OAuth token).\n */\n async get(customerToken: string, walletId?: string): Promise<BalanceResult> {\n const path = walletId ? `/wallets/${walletId}/budget` : \"/wallets/me\";\n const res = await request<{\n id?: string;\n wallet_id?: string;\n funding_amount: number;\n spent_amount: number;\n remaining: number;\n }>(this.baseUrl, path, customerToken, {\n method: \"GET\",\n });\n\n return {\n walletId: res.wallet_id || res.id || \"\",\n fundingAmount: res.funding_amount,\n spentAmount: res.spent_amount,\n remaining: res.remaining,\n };\n }\n}\n","import { request } from \"./http\";\nimport type { LegacyPurchaseOptions, PurchaseOptions, PurchaseResult } from \"./types\";\n\nexport class PurchaseModule {\n constructor(\n private baseUrl: string,\n private apiKey: string,\n ) {}\n\n /**\n * Make a purchase using an OAuth customer token.\n */\n async create(options: PurchaseOptions): Promise<PurchaseResult> {\n const res = await request<{\n transaction_id: string;\n status: string;\n decision: string;\n decision_reason: string;\n amount: number;\n merchant_name: string;\n approval_deadline?: string;\n }>(this.baseUrl, \"/purchase\", options.customerToken, {\n method: \"POST\",\n headers: {\n \"X-Tallion-Installation\": \"\", // Resolved by OAuth token\n },\n body: {\n amount: options.amount,\n currency: options.currency || \"USD\",\n wallet_id: options.walletId,\n merchant: {\n name: options.merchant.name,\n mcc: options.merchant.mcc || \"\",\n country: options.merchant.country || \"US\",\n },\n context: {\n description: options.context.description,\n category: options.context.category,\n line_items: options.context.lineItems,\n external_reference: options.context.externalReference,\n refund_policy: options.context.refundPolicy,\n metadata: options.context.metadata,\n },\n },\n });\n\n return {\n transactionId: res.transaction_id,\n status: res.status as PurchaseResult[\"status\"],\n decision: res.decision,\n decisionReason: res.decision_reason,\n amount: res.amount,\n merchantName: res.merchant_name,\n approvalDeadline: res.approval_deadline,\n };\n }\n\n /**\n * Make a purchase using the legacy API key + installation ID auth.\n */\n async legacyCreate(options: LegacyPurchaseOptions): Promise<PurchaseResult> {\n const res = await request<{\n transaction_id: string;\n status: string;\n decision: string;\n decision_reason: string;\n amount: number;\n merchant_name: string;\n approval_deadline?: string;\n }>(this.baseUrl, \"/purchase\", this.apiKey, {\n method: \"POST\",\n headers: {\n \"X-Tallion-Installation\": options.installationId,\n },\n body: {\n amount: options.amount,\n merchant_name: options.merchantName,\n merchant_mcc: options.merchantMcc || \"\",\n merchant_country: options.merchantCountry || \"US\",\n currency: options.currency || \"USD\",\n wallet_id: options.walletId,\n reasoning: options.reasoning,\n },\n });\n\n return {\n transactionId: res.transaction_id,\n status: res.status as PurchaseResult[\"status\"],\n decision: res.decision,\n decisionReason: res.decision_reason,\n amount: res.amount,\n merchantName: res.merchant_name,\n approvalDeadline: res.approval_deadline,\n };\n }\n}\n","import type { WebhookEvent } from \"./types\";\nimport { TallionError } from \"./errors\";\n\nexport class WebhooksModule {\n constructor(private secret?: string) {}\n\n /**\n * Verify a webhook signature and parse the event.\n * Uses Web Crypto API (works in Node 18+, Deno, Bun, Cloudflare Workers, etc.)\n *\n * @param body - Raw request body string\n * @param signature - Value of X-Tally-Signature header\n * @param tolerance - Max age in seconds (default: 300 = 5 minutes)\n */\n async verify(\n body: string,\n signature: string,\n tolerance = 300,\n ): Promise<WebhookEvent> {\n if (!this.secret) {\n throw new TallionError(500, \"Webhook secret not configured\");\n }\n\n // Parse signature header: \"t={timestamp},v1={hex_signature}\"\n const parts: Record<string, string> = {};\n for (const part of signature.split(\",\")) {\n const [key, ...val] = part.split(\"=\");\n if (key && val.length > 0) {\n parts[key] = val.join(\"=\");\n }\n }\n\n const timestamp = parts[\"t\"];\n const sig = parts[\"v1\"];\n\n if (!timestamp || !sig) {\n throw new TallionError(400, \"Invalid webhook signature format\");\n }\n\n // Check timestamp freshness\n const ts = parseInt(timestamp, 10);\n const now = Math.floor(Date.now() / 1000);\n if (Math.abs(now - ts) > tolerance) {\n throw new TallionError(400, \"Webhook timestamp expired\");\n }\n\n // Compute HMAC-SHA256\n const message = `${timestamp}.${body}`;\n const encoder = new TextEncoder();\n const key = await crypto.subtle.importKey(\n \"raw\",\n encoder.encode(this.secret),\n { name: \"HMAC\", hash: \"SHA-256\" },\n false,\n [\"sign\"],\n );\n\n const signatureBytes = await crypto.subtle.sign(\n \"HMAC\",\n key,\n encoder.encode(message),\n );\n\n const computed = Array.from(new Uint8Array(signatureBytes))\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n\n // Constant-time comparison\n if (computed.length !== sig.length || !timingSafeEqual(computed, sig)) {\n throw new TallionError(401, \"Invalid webhook signature\");\n }\n\n return JSON.parse(body) as WebhookEvent;\n }\n}\n\n/** Simple constant-time string comparison */\nfunction timingSafeEqual(a: string, b: string): boolean {\n if (a.length !== b.length) return false;\n let result = 0;\n for (let i = 0; i < a.length; i++) {\n result |= a.charCodeAt(i) ^ b.charCodeAt(i);\n }\n return result === 0;\n}\n","import { AuthorizeModule } from \"./authorize\";\nimport { BalanceModule } from \"./balance\";\nimport { resolveBaseUrl } from \"./http\";\nimport { PurchaseModule } from \"./purchase\";\nimport { WebhooksModule } from \"./webhooks\";\nimport type { PurchaseOptions, PurchaseResult, TallyConfig } from \"./types\";\n\nexport class Tally {\n private baseUrl: string;\n private apiKey: string;\n\n /** OAuth authorization flow */\n public authorize: AuthorizeModule;\n\n /** Purchase operations */\n public purchases: PurchaseModule;\n\n /** Balance operations */\n public balances: BalanceModule;\n\n /** Webhook signature verification */\n public webhooks: WebhooksModule;\n\n constructor(config: TallyConfig) {\n if (!config.apiKey) {\n throw new Error(\n \"Tallion API key is required. Get one at https://tallion.ai/developer\",\n );\n }\n this.apiKey = config.apiKey;\n this.baseUrl = resolveBaseUrl(config.apiKey, config.baseUrl);\n this.authorize = new AuthorizeModule(this.baseUrl, this.apiKey);\n this.purchases = new PurchaseModule(this.baseUrl, this.apiKey);\n this.balances = new BalanceModule(this.baseUrl, this.apiKey);\n this.webhooks = new WebhooksModule();\n }\n\n /**\n * Convenience method: Make a purchase (delegates to purchases.create).\n */\n async purchase(options: PurchaseOptions): Promise<PurchaseResult> {\n return this.purchases.create(options);\n }\n\n /**\n * Convenience method: Get balance for a customer.\n */\n async balance(customerToken: string, walletId?: string) {\n return this.balances.get(customerToken, walletId);\n }\n\n /**\n * Check if this is a sandbox instance.\n */\n get isSandbox(): boolean {\n return this.apiKey.startsWith(\"sk_sandbox_\");\n }\n\n /**\n * Get the resolved base URL.\n */\n get url(): string {\n return this.baseUrl;\n }\n}\n"],"mappings":"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","names":["key"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/http.ts","../src/authorize.ts","../src/balance.ts","../src/intents.ts","../src/purchase.ts","../src/webhooks.ts","../src/tally.ts"],"sourcesContent":["export { Tally } from \"./tally\";\nexport { TallionError } from \"./errors\";\nexport { AuthorizeModule } from \"./authorize\";\nexport { PurchaseModule } from \"./purchase\";\nexport { IntentsModule } from \"./intents\";\nexport { BalanceModule } from \"./balance\";\nexport { WebhooksModule } from \"./webhooks\";\n\nexport type {\n TallyConfig,\n CreateAuthUrlOptions,\n AuthUrlResult,\n ExchangeCodeOptions,\n TokenResult,\n RefreshTokenOptions,\n PurchaseOptions,\n LegacyPurchaseOptions,\n PurchaseResult,\n MerchantInfo,\n TransactionContext,\n LineItem,\n BalanceResult,\n SpendLimits,\n WebhookEvent,\n CreateIntentOptions,\n IntentCardDetails,\n IntentResult,\n IntentStatusResult,\n ListIntentsOptions,\n} from \"./types\";\n","export class TallionError extends Error {\n public readonly status: number;\n public readonly code?: string;\n\n constructor(status: number, message: string, code?: string) {\n super(message);\n this.name = \"TallionError\";\n this.status = status;\n this.code = code;\n }\n}\n","import { TallionError } from \"./errors\";\n\nconst SANDBOX_URL = \"https://api.sandbox.tallion.ai\";\nconst PRODUCTION_URL = \"https://api.tallion.ai\";\n\nexport function resolveBaseUrl(apiKey: string, overrideUrl?: string): string {\n if (overrideUrl) return overrideUrl;\n if (apiKey.startsWith(\"sk_live_\")) return PRODUCTION_URL;\n return SANDBOX_URL;\n}\n\nexport interface RequestOptions {\n method?: string;\n headers?: Record<string, string>;\n body?: unknown;\n}\n\nexport async function request<T>(\n baseUrl: string,\n path: string,\n apiKey: string,\n options: RequestOptions = {},\n): Promise<T> {\n if (!apiKey) {\n throw new TallionError(\n 401,\n \"Tallion API key is required. Get one at https://tallion.ai/developer\",\n \"missing_api_key\",\n );\n }\n const url = `${baseUrl}/api${path}`;\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${apiKey}`,\n ...options.headers,\n };\n\n const res = await fetch(url, {\n method: options.method || \"GET\",\n headers,\n body: options.body ? JSON.stringify(options.body) : undefined,\n });\n\n if (!res.ok) {\n const body = await res.json().catch(() => ({ error: \"Unknown error\" }));\n throw new TallionError(\n res.status,\n body.error || \"Request failed\",\n body.code,\n );\n }\n\n return res.json() as Promise<T>;\n}\n","import { request } from \"./http\";\nimport type {\n AuthUrlResult,\n CreateAuthUrlOptions,\n ExchangeCodeOptions,\n RefreshTokenOptions,\n TokenResult,\n} from \"./types\";\n\n/** Generate a random string for PKCE */\nfunction generateRandomString(length: number): string {\n const chars = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~\";\n const array = new Uint8Array(length);\n crypto.getRandomValues(array);\n return Array.from(array, (byte) => chars[byte % chars.length]).join(\"\");\n}\n\n/** SHA-256 hash for PKCE S256 challenge */\nasync function sha256(plain: string): Promise<string> {\n const encoder = new TextEncoder();\n const data = encoder.encode(plain);\n const hash = await crypto.subtle.digest(\"SHA-256\", data);\n return btoa(String.fromCharCode(...new Uint8Array(hash)))\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=+$/, \"\");\n}\n\nexport class AuthorizeModule {\n constructor(\n private baseUrl: string,\n private apiKey: string,\n ) {}\n\n /**\n * Create an authorization URL for customer consent.\n * Returns the URL to open in a popup/browser plus the PKCE code verifier.\n */\n async createUrl(options: CreateAuthUrlOptions): Promise<AuthUrlResult> {\n const codeVerifier = generateRandomString(64);\n const codeChallenge = await sha256(codeVerifier);\n\n const res = await request<{\n authorization_id: string;\n url: string;\n state: string;\n }>(this.baseUrl, \"/oauth/authorize\", this.apiKey, {\n method: \"POST\",\n body: {\n customer_identifier: options.customerIdentifier,\n redirect_url: options.redirectUrl,\n scopes: options.scopes || [\"purchase\", \"balance:read\"],\n code_challenge: codeChallenge,\n code_challenge_method: options.codeChallengeMethod || \"S256\",\n suggested_limits: options.suggestedLimits\n ? {\n max_per_transaction: options.suggestedLimits.maxPerTransaction,\n max_per_day: options.suggestedLimits.maxPerDay,\n max_per_month: options.suggestedLimits.maxPerMonth,\n require_approval_above: options.suggestedLimits.requireApprovalAbove,\n }\n : undefined,\n purchase_context: options.purchaseContext\n ? {\n amount: options.purchaseContext.amount,\n description: options.purchaseContext.description,\n merchant: options.purchaseContext.merchant,\n reference: options.purchaseContext.reference,\n }\n : undefined,\n },\n });\n\n return {\n url: res.url,\n state: res.state,\n codeVerifier,\n authorizationId: res.authorization_id,\n };\n }\n\n /**\n * Exchange an authorization code for access + refresh tokens.\n */\n async exchangeCode(options: ExchangeCodeOptions): Promise<TokenResult> {\n const res = await request<{\n access_token: string;\n refresh_token: string;\n token_type: string;\n expires_in: number;\n customer_id: string;\n installation_id: string;\n }>(this.baseUrl, \"/oauth/token\", this.apiKey, {\n method: \"POST\",\n body: {\n grant_type: \"authorization_code\",\n code: options.code,\n code_verifier: options.codeVerifier,\n },\n });\n\n return {\n accessToken: res.access_token,\n refreshToken: res.refresh_token,\n tokenType: res.token_type,\n expiresIn: res.expires_in,\n customerId: res.customer_id,\n installationId: res.installation_id,\n };\n }\n\n /**\n * Refresh an access token using a refresh token.\n */\n async refreshToken(options: RefreshTokenOptions): Promise<TokenResult> {\n const res = await request<{\n access_token: string;\n refresh_token: string;\n token_type: string;\n expires_in: number;\n customer_id: string;\n installation_id: string;\n }>(this.baseUrl, \"/oauth/token\", this.apiKey, {\n method: \"POST\",\n body: {\n grant_type: \"refresh_token\",\n refresh_token: options.refreshToken,\n },\n });\n\n return {\n accessToken: res.access_token,\n refreshToken: res.refresh_token,\n tokenType: res.token_type,\n expiresIn: res.expires_in,\n customerId: res.customer_id,\n installationId: res.installation_id,\n };\n }\n\n /**\n * Revoke an access or refresh token.\n */\n async revoke(token: string): Promise<void> {\n await request(this.baseUrl, \"/oauth/revoke\", this.apiKey, {\n method: \"POST\",\n body: { token },\n });\n }\n}\n","import { request } from \"./http\";\nimport type { BalanceResult } from \"./types\";\n\nexport class BalanceModule {\n constructor(\n private baseUrl: string,\n private apiKey: string,\n ) {}\n\n /**\n * Get wallet balance for a customer (using OAuth token).\n */\n async get(customerToken: string, walletId?: string): Promise<BalanceResult> {\n const path = walletId ? `/wallets/${walletId}/budget` : \"/wallets/me\";\n const res = await request<{\n id?: string;\n wallet_id?: string;\n funding_amount: number;\n spent_amount: number;\n remaining: number;\n }>(this.baseUrl, path, customerToken, {\n method: \"GET\",\n });\n\n return {\n walletId: res.wallet_id || res.id || \"\",\n fundingAmount: res.funding_amount,\n spentAmount: res.spent_amount,\n remaining: res.remaining,\n };\n }\n}\n","import { request } from \"./http\";\nimport type {\n CreateIntentOptions,\n IntentResult,\n IntentStatusResult,\n ListIntentsOptions,\n} from \"./types\";\n\nexport class IntentsModule {\n constructor(\n private baseUrl: string,\n private apiKey: string,\n ) {}\n\n /**\n * Create a purchase intent (Buy Anywhere).\n * Returns a virtual card for the customer to use at the merchant.\n */\n async create(options: CreateIntentOptions): Promise<IntentResult> {\n const res = await request<{\n intent_id: string;\n status: string;\n amount: number;\n currency: string;\n merchant_name?: string;\n expires_at?: string;\n transaction_id?: string;\n card?: {\n pan: string;\n cvv: string;\n exp_month: number;\n exp_year: number;\n last_four: string;\n };\n }>(this.baseUrl, \"/intents\", options.customerToken, {\n method: \"POST\",\n body: {\n amount: options.amount,\n currency: options.currency || \"USD\",\n wallet_id: options.walletId,\n merchant: options.merchant\n ? {\n name: options.merchant.name,\n url: options.merchant.url,\n mcc: options.merchant.mcc,\n }\n : undefined,\n product: options.product\n ? {\n description: options.product.description,\n url: options.product.url,\n }\n : undefined,\n amount_tolerance_pct: options.amountTolerancePct,\n },\n });\n\n return {\n intentId: res.intent_id,\n status: res.status as IntentResult[\"status\"],\n amount: res.amount,\n currency: res.currency,\n merchantName: res.merchant_name,\n expiresAt: res.expires_at,\n transactionId: res.transaction_id,\n card: res.card\n ? {\n pan: res.card.pan,\n cvv: res.card.cvv,\n expMonth: res.card.exp_month,\n expYear: res.card.exp_year,\n lastFour: res.card.last_four,\n }\n : undefined,\n };\n }\n\n /**\n * Get the current status of a purchase intent.\n */\n async get(\n customerToken: string,\n intentId: string,\n ): Promise<IntentStatusResult> {\n const res = await request<RawIntentStatus>(\n this.baseUrl,\n `/intents/${intentId}`,\n customerToken,\n );\n\n return mapIntentStatus(res);\n }\n\n /**\n * Cancel an active purchase intent.\n */\n async cancel(\n customerToken: string,\n intentId: string,\n ): Promise<IntentStatusResult> {\n const res = await request<RawIntentStatus>(\n this.baseUrl,\n `/intents/${intentId}/cancel`,\n customerToken,\n { method: \"POST\" },\n );\n\n return mapIntentStatus(res);\n }\n\n /**\n * List purchase intents for the authenticated customer.\n */\n async list(\n customerToken: string,\n options?: ListIntentsOptions,\n ): Promise<IntentStatusResult[]> {\n const params = new URLSearchParams();\n if (options?.limit !== undefined) params.set(\"limit\", String(options.limit));\n if (options?.offset !== undefined)\n params.set(\"offset\", String(options.offset));\n\n const query = params.toString();\n const path = query ? `/intents?${query}` : \"/intents\";\n\n const res = await request<RawIntentStatus[]>(\n this.baseUrl,\n path,\n customerToken,\n );\n\n return res.map(mapIntentStatus);\n }\n}\n\n// ── Internal helpers ──\n\ninterface RawIntentStatus {\n intent_id: string;\n status: string;\n amount: number;\n currency: string;\n merchant_name?: string;\n card_last_four?: string;\n asa_verified: boolean;\n asa_amount?: number;\n asa_merchant_descriptor?: string;\n asa_mismatch_reason?: string;\n transaction_id?: string;\n expires_at?: string;\n created_at: string;\n}\n\nfunction mapIntentStatus(raw: RawIntentStatus): IntentStatusResult {\n return {\n intentId: raw.intent_id,\n status: raw.status,\n amount: raw.amount,\n currency: raw.currency,\n merchantName: raw.merchant_name,\n cardLastFour: raw.card_last_four,\n asaVerified: raw.asa_verified,\n asaAmount: raw.asa_amount,\n asaMerchantDescriptor: raw.asa_merchant_descriptor,\n asaMismatchReason: raw.asa_mismatch_reason,\n transactionId: raw.transaction_id,\n expiresAt: raw.expires_at,\n createdAt: raw.created_at,\n };\n}\n","import { request } from \"./http\";\nimport type { LegacyPurchaseOptions, PurchaseOptions, PurchaseResult } from \"./types\";\n\nexport class PurchaseModule {\n constructor(\n private baseUrl: string,\n private apiKey: string,\n ) {}\n\n /**\n * Make a purchase using an OAuth customer token.\n */\n async create(options: PurchaseOptions): Promise<PurchaseResult> {\n const res = await request<{\n transaction_id: string;\n status: string;\n decision: string;\n decision_reason: string;\n amount: number;\n merchant_name: string;\n approval_deadline?: string;\n }>(this.baseUrl, \"/purchase\", options.customerToken, {\n method: \"POST\",\n headers: {\n \"X-Tallion-Installation\": \"\", // Resolved by OAuth token\n },\n body: {\n amount: options.amount,\n currency: options.currency || \"USD\",\n wallet_id: options.walletId,\n merchant: {\n name: options.merchant.name,\n mcc: options.merchant.mcc || \"\",\n country: options.merchant.country || \"US\",\n },\n context: {\n description: options.context.description,\n category: options.context.category,\n line_items: options.context.lineItems,\n external_reference: options.context.externalReference,\n refund_policy: options.context.refundPolicy,\n metadata: options.context.metadata,\n },\n },\n });\n\n return {\n transactionId: res.transaction_id,\n status: res.status as PurchaseResult[\"status\"],\n decision: res.decision,\n decisionReason: res.decision_reason,\n amount: res.amount,\n merchantName: res.merchant_name,\n approvalDeadline: res.approval_deadline,\n };\n }\n\n /**\n * Make a purchase using the legacy API key + installation ID auth.\n */\n async legacyCreate(options: LegacyPurchaseOptions): Promise<PurchaseResult> {\n const res = await request<{\n transaction_id: string;\n status: string;\n decision: string;\n decision_reason: string;\n amount: number;\n merchant_name: string;\n approval_deadline?: string;\n }>(this.baseUrl, \"/purchase\", this.apiKey, {\n method: \"POST\",\n headers: {\n \"X-Tallion-Installation\": options.installationId,\n },\n body: {\n amount: options.amount,\n merchant_name: options.merchantName,\n merchant_mcc: options.merchantMcc || \"\",\n merchant_country: options.merchantCountry || \"US\",\n currency: options.currency || \"USD\",\n wallet_id: options.walletId,\n reasoning: options.reasoning,\n },\n });\n\n return {\n transactionId: res.transaction_id,\n status: res.status as PurchaseResult[\"status\"],\n decision: res.decision,\n decisionReason: res.decision_reason,\n amount: res.amount,\n merchantName: res.merchant_name,\n approvalDeadline: res.approval_deadline,\n };\n }\n}\n","import type { WebhookEvent } from \"./types\";\nimport { TallionError } from \"./errors\";\n\nexport class WebhooksModule {\n constructor(private secret?: string) {}\n\n /**\n * Verify a webhook signature and parse the event.\n * Uses Web Crypto API (works in Node 18+, Deno, Bun, Cloudflare Workers, etc.)\n *\n * @param body - Raw request body string\n * @param signature - Value of X-Tally-Signature header\n * @param tolerance - Max age in seconds (default: 300 = 5 minutes)\n */\n async verify(\n body: string,\n signature: string,\n tolerance = 300,\n ): Promise<WebhookEvent> {\n if (!this.secret) {\n throw new TallionError(500, \"Webhook secret not configured\");\n }\n\n // Parse signature header: \"t={timestamp},v1={hex_signature}\"\n const parts: Record<string, string> = {};\n for (const part of signature.split(\",\")) {\n const [key, ...val] = part.split(\"=\");\n if (key && val.length > 0) {\n parts[key] = val.join(\"=\");\n }\n }\n\n const timestamp = parts[\"t\"];\n const sig = parts[\"v1\"];\n\n if (!timestamp || !sig) {\n throw new TallionError(400, \"Invalid webhook signature format\");\n }\n\n // Check timestamp freshness\n const ts = parseInt(timestamp, 10);\n const now = Math.floor(Date.now() / 1000);\n if (Math.abs(now - ts) > tolerance) {\n throw new TallionError(400, \"Webhook timestamp expired\");\n }\n\n // Compute HMAC-SHA256\n const message = `${timestamp}.${body}`;\n const encoder = new TextEncoder();\n const key = await crypto.subtle.importKey(\n \"raw\",\n encoder.encode(this.secret),\n { name: \"HMAC\", hash: \"SHA-256\" },\n false,\n [\"sign\"],\n );\n\n const signatureBytes = await crypto.subtle.sign(\n \"HMAC\",\n key,\n encoder.encode(message),\n );\n\n const computed = Array.from(new Uint8Array(signatureBytes))\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n\n // Constant-time comparison\n if (computed.length !== sig.length || !timingSafeEqual(computed, sig)) {\n throw new TallionError(401, \"Invalid webhook signature\");\n }\n\n return JSON.parse(body) as WebhookEvent;\n }\n}\n\n/** Simple constant-time string comparison */\nfunction timingSafeEqual(a: string, b: string): boolean {\n if (a.length !== b.length) return false;\n let result = 0;\n for (let i = 0; i < a.length; i++) {\n result |= a.charCodeAt(i) ^ b.charCodeAt(i);\n }\n return result === 0;\n}\n","import { AuthorizeModule } from \"./authorize\";\nimport { BalanceModule } from \"./balance\";\nimport { resolveBaseUrl } from \"./http\";\nimport { IntentsModule } from \"./intents\";\nimport { PurchaseModule } from \"./purchase\";\nimport { WebhooksModule } from \"./webhooks\";\nimport type { PurchaseOptions, PurchaseResult, TallyConfig } from \"./types\";\n\nexport class Tally {\n private baseUrl: string;\n private apiKey: string;\n\n /** OAuth authorization flow */\n public authorize: AuthorizeModule;\n\n /** Purchase operations */\n public purchases: PurchaseModule;\n\n /** Balance operations */\n public balances: BalanceModule;\n\n /** Purchase intents (Buy Anywhere) */\n public intents: IntentsModule;\n\n /** Webhook signature verification */\n public webhooks: WebhooksModule;\n\n constructor(config: TallyConfig) {\n if (!config.apiKey) {\n throw new Error(\n \"Tallion API key is required. Get one at https://tallion.ai/developer\",\n );\n }\n this.apiKey = config.apiKey;\n this.baseUrl = resolveBaseUrl(config.apiKey, config.baseUrl);\n this.authorize = new AuthorizeModule(this.baseUrl, this.apiKey);\n this.purchases = new PurchaseModule(this.baseUrl, this.apiKey);\n this.intents = new IntentsModule(this.baseUrl, this.apiKey);\n this.balances = new BalanceModule(this.baseUrl, this.apiKey);\n this.webhooks = new WebhooksModule();\n }\n\n /**\n * Convenience method: Make a purchase (delegates to purchases.create).\n */\n async purchase(options: PurchaseOptions): Promise<PurchaseResult> {\n return this.purchases.create(options);\n }\n\n /**\n * Convenience method: Get balance for a customer.\n */\n async balance(customerToken: string, walletId?: string) {\n return this.balances.get(customerToken, walletId);\n }\n\n /**\n * Check if this is a sandbox instance.\n */\n get isSandbox(): boolean {\n return this.apiKey.startsWith(\"sk_sandbox_\");\n }\n\n /**\n * Get the resolved base URL.\n */\n get url(): string {\n return this.baseUrl;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAO,IAAM,eAAN,cAA2B,MAAM;AAAA,EAItC,YAAY,QAAgB,SAAiB,MAAe;AAC1D,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,SAAK,OAAO;AAAA,EACd;AACF;;;ACRA,IAAM,cAAc;AACpB,IAAM,iBAAiB;AAEhB,SAAS,eAAe,QAAgB,aAA8B;AAC3E,MAAI,YAAa,QAAO;AACxB,MAAI,OAAO,WAAW,UAAU,EAAG,QAAO;AAC1C,SAAO;AACT;AAQA,eAAsB,QACpB,SACA,MACA,QACA,UAA0B,CAAC,GACf;AACZ,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACA,QAAM,MAAM,GAAG,OAAO,OAAO,IAAI;AACjC,QAAM,UAAkC;AAAA,IACtC,gBAAgB;AAAA,IAChB,eAAe,UAAU,MAAM;AAAA,IAC/B,GAAG,QAAQ;AAAA,EACb;AAEA,QAAM,MAAM,MAAM,MAAM,KAAK;AAAA,IAC3B,QAAQ,QAAQ,UAAU;AAAA,IAC1B;AAAA,IACA,MAAM,QAAQ,OAAO,KAAK,UAAU,QAAQ,IAAI,IAAI;AAAA,EACtD,CAAC;AAED,MAAI,CAAC,IAAI,IAAI;AACX,UAAM,OAAO,MAAM,IAAI,KAAK,EAAE,MAAM,OAAO,EAAE,OAAO,gBAAgB,EAAE;AACtE,UAAM,IAAI;AAAA,MACR,IAAI;AAAA,MACJ,KAAK,SAAS;AAAA,MACd,KAAK;AAAA,IACP;AAAA,EACF;AAEA,SAAO,IAAI,KAAK;AAClB;;;AC3CA,SAAS,qBAAqB,QAAwB;AACpD,QAAM,QAAQ;AACd,QAAM,QAAQ,IAAI,WAAW,MAAM;AACnC,SAAO,gBAAgB,KAAK;AAC5B,SAAO,MAAM,KAAK,OAAO,CAAC,SAAS,MAAM,OAAO,MAAM,MAAM,CAAC,EAAE,KAAK,EAAE;AACxE;AAGA,eAAe,OAAO,OAAgC;AACpD,QAAM,UAAU,IAAI,YAAY;AAChC,QAAM,OAAO,QAAQ,OAAO,KAAK;AACjC,QAAM,OAAO,MAAM,OAAO,OAAO,OAAO,WAAW,IAAI;AACvD,SAAO,KAAK,OAAO,aAAa,GAAG,IAAI,WAAW,IAAI,CAAC,CAAC,EACrD,QAAQ,OAAO,GAAG,EAClB,QAAQ,OAAO,GAAG,EAClB,QAAQ,OAAO,EAAE;AACtB;AAEO,IAAM,kBAAN,MAAsB;AAAA,EAC3B,YACU,SACA,QACR;AAFQ;AACA;AAAA,EACP;AAAA;AAAA;AAAA;AAAA;AAAA,EAMH,MAAM,UAAU,SAAuD;AACrE,UAAM,eAAe,qBAAqB,EAAE;AAC5C,UAAM,gBAAgB,MAAM,OAAO,YAAY;AAE/C,UAAM,MAAM,MAAM,QAIf,KAAK,SAAS,oBAAoB,KAAK,QAAQ;AAAA,MAChD,QAAQ;AAAA,MACR,MAAM;AAAA,QACJ,qBAAqB,QAAQ;AAAA,QAC7B,cAAc,QAAQ;AAAA,QACtB,QAAQ,QAAQ,UAAU,CAAC,YAAY,cAAc;AAAA,QACrD,gBAAgB;AAAA,QAChB,uBAAuB,QAAQ,uBAAuB;AAAA,QACtD,kBAAkB,QAAQ,kBACtB;AAAA,UACE,qBAAqB,QAAQ,gBAAgB;AAAA,UAC7C,aAAa,QAAQ,gBAAgB;AAAA,UACrC,eAAe,QAAQ,gBAAgB;AAAA,UACvC,wBAAwB,QAAQ,gBAAgB;AAAA,QAClD,IACA;AAAA,QACJ,kBAAkB,QAAQ,kBACtB;AAAA,UACE,QAAQ,QAAQ,gBAAgB;AAAA,UAChC,aAAa,QAAQ,gBAAgB;AAAA,UACrC,UAAU,QAAQ,gBAAgB;AAAA,UAClC,WAAW,QAAQ,gBAAgB;AAAA,QACrC,IACA;AAAA,MACN;AAAA,IACF,CAAC;AAED,WAAO;AAAA,MACL,KAAK,IAAI;AAAA,MACT,OAAO,IAAI;AAAA,MACX;AAAA,MACA,iBAAiB,IAAI;AAAA,IACvB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAAa,SAAoD;AACrE,UAAM,MAAM,MAAM,QAOf,KAAK,SAAS,gBAAgB,KAAK,QAAQ;AAAA,MAC5C,QAAQ;AAAA,MACR,MAAM;AAAA,QACJ,YAAY;AAAA,QACZ,MAAM,QAAQ;AAAA,QACd,eAAe,QAAQ;AAAA,MACzB;AAAA,IACF,CAAC;AAED,WAAO;AAAA,MACL,aAAa,IAAI;AAAA,MACjB,cAAc,IAAI;AAAA,MAClB,WAAW,IAAI;AAAA,MACf,WAAW,IAAI;AAAA,MACf,YAAY,IAAI;AAAA,MAChB,gBAAgB,IAAI;AAAA,IACtB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAAa,SAAoD;AACrE,UAAM,MAAM,MAAM,QAOf,KAAK,SAAS,gBAAgB,KAAK,QAAQ;AAAA,MAC5C,QAAQ;AAAA,MACR,MAAM;AAAA,QACJ,YAAY;AAAA,QACZ,eAAe,QAAQ;AAAA,MACzB;AAAA,IACF,CAAC;AAED,WAAO;AAAA,MACL,aAAa,IAAI;AAAA,MACjB,cAAc,IAAI;AAAA,MAClB,WAAW,IAAI;AAAA,MACf,WAAW,IAAI;AAAA,MACf,YAAY,IAAI;AAAA,MAChB,gBAAgB,IAAI;AAAA,IACtB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAO,OAA8B;AACzC,UAAM,QAAQ,KAAK,SAAS,iBAAiB,KAAK,QAAQ;AAAA,MACxD,QAAQ;AAAA,MACR,MAAM,EAAE,MAAM;AAAA,IAChB,CAAC;AAAA,EACH;AACF;;;AClJO,IAAM,gBAAN,MAAoB;AAAA,EACzB,YACU,SACA,QACR;AAFQ;AACA;AAAA,EACP;AAAA;AAAA;AAAA;AAAA,EAKH,MAAM,IAAI,eAAuB,UAA2C;AAC1E,UAAM,OAAO,WAAW,YAAY,QAAQ,YAAY;AACxD,UAAM,MAAM,MAAM,QAMf,KAAK,SAAS,MAAM,eAAe;AAAA,MACpC,QAAQ;AAAA,IACV,CAAC;AAED,WAAO;AAAA,MACL,UAAU,IAAI,aAAa,IAAI,MAAM;AAAA,MACrC,eAAe,IAAI;AAAA,MACnB,aAAa,IAAI;AAAA,MACjB,WAAW,IAAI;AAAA,IACjB;AAAA,EACF;AACF;;;ACvBO,IAAM,gBAAN,MAAoB;AAAA,EACzB,YACU,SACA,QACR;AAFQ;AACA;AAAA,EACP;AAAA;AAAA;AAAA;AAAA;AAAA,EAMH,MAAM,OAAO,SAAqD;AAChE,UAAM,MAAM,MAAM,QAef,KAAK,SAAS,YAAY,QAAQ,eAAe;AAAA,MAClD,QAAQ;AAAA,MACR,MAAM;AAAA,QACJ,QAAQ,QAAQ;AAAA,QAChB,UAAU,QAAQ,YAAY;AAAA,QAC9B,WAAW,QAAQ;AAAA,QACnB,UAAU,QAAQ,WACd;AAAA,UACE,MAAM,QAAQ,SAAS;AAAA,UACvB,KAAK,QAAQ,SAAS;AAAA,UACtB,KAAK,QAAQ,SAAS;AAAA,QACxB,IACA;AAAA,QACJ,SAAS,QAAQ,UACb;AAAA,UACE,aAAa,QAAQ,QAAQ;AAAA,UAC7B,KAAK,QAAQ,QAAQ;AAAA,QACvB,IACA;AAAA,QACJ,sBAAsB,QAAQ;AAAA,MAChC;AAAA,IACF,CAAC;AAED,WAAO;AAAA,MACL,UAAU,IAAI;AAAA,MACd,QAAQ,IAAI;AAAA,MACZ,QAAQ,IAAI;AAAA,MACZ,UAAU,IAAI;AAAA,MACd,cAAc,IAAI;AAAA,MAClB,WAAW,IAAI;AAAA,MACf,eAAe,IAAI;AAAA,MACnB,MAAM,IAAI,OACN;AAAA,QACE,KAAK,IAAI,KAAK;AAAA,QACd,KAAK,IAAI,KAAK;AAAA,QACd,UAAU,IAAI,KAAK;AAAA,QACnB,SAAS,IAAI,KAAK;AAAA,QAClB,UAAU,IAAI,KAAK;AAAA,MACrB,IACA;AAAA,IACN;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,IACJ,eACA,UAC6B;AAC7B,UAAM,MAAM,MAAM;AAAA,MAChB,KAAK;AAAA,MACL,YAAY,QAAQ;AAAA,MACpB;AAAA,IACF;AAEA,WAAO,gBAAgB,GAAG;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OACJ,eACA,UAC6B;AAC7B,UAAM,MAAM,MAAM;AAAA,MAChB,KAAK;AAAA,MACL,YAAY,QAAQ;AAAA,MACpB;AAAA,MACA,EAAE,QAAQ,OAAO;AAAA,IACnB;AAEA,WAAO,gBAAgB,GAAG;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,KACJ,eACA,SAC+B;AAC/B,UAAM,SAAS,IAAI,gBAAgB;AACnC,QAAI,SAAS,UAAU,OAAW,QAAO,IAAI,SAAS,OAAO,QAAQ,KAAK,CAAC;AAC3E,QAAI,SAAS,WAAW;AACtB,aAAO,IAAI,UAAU,OAAO,QAAQ,MAAM,CAAC;AAE7C,UAAM,QAAQ,OAAO,SAAS;AAC9B,UAAM,OAAO,QAAQ,YAAY,KAAK,KAAK;AAE3C,UAAM,MAAM,MAAM;AAAA,MAChB,KAAK;AAAA,MACL;AAAA,MACA;AAAA,IACF;AAEA,WAAO,IAAI,IAAI,eAAe;AAAA,EAChC;AACF;AAoBA,SAAS,gBAAgB,KAA0C;AACjE,SAAO;AAAA,IACL,UAAU,IAAI;AAAA,IACd,QAAQ,IAAI;AAAA,IACZ,QAAQ,IAAI;AAAA,IACZ,UAAU,IAAI;AAAA,IACd,cAAc,IAAI;AAAA,IAClB,cAAc,IAAI;AAAA,IAClB,aAAa,IAAI;AAAA,IACjB,WAAW,IAAI;AAAA,IACf,uBAAuB,IAAI;AAAA,IAC3B,mBAAmB,IAAI;AAAA,IACvB,eAAe,IAAI;AAAA,IACnB,WAAW,IAAI;AAAA,IACf,WAAW,IAAI;AAAA,EACjB;AACF;;;ACtKO,IAAM,iBAAN,MAAqB;AAAA,EAC1B,YACU,SACA,QACR;AAFQ;AACA;AAAA,EACP;AAAA;AAAA;AAAA;AAAA,EAKH,MAAM,OAAO,SAAmD;AAC9D,UAAM,MAAM,MAAM,QAQf,KAAK,SAAS,aAAa,QAAQ,eAAe;AAAA,MACnD,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,0BAA0B;AAAA;AAAA,MAC5B;AAAA,MACA,MAAM;AAAA,QACJ,QAAQ,QAAQ;AAAA,QAChB,UAAU,QAAQ,YAAY;AAAA,QAC9B,WAAW,QAAQ;AAAA,QACnB,UAAU;AAAA,UACR,MAAM,QAAQ,SAAS;AAAA,UACvB,KAAK,QAAQ,SAAS,OAAO;AAAA,UAC7B,SAAS,QAAQ,SAAS,WAAW;AAAA,QACvC;AAAA,QACA,SAAS;AAAA,UACP,aAAa,QAAQ,QAAQ;AAAA,UAC7B,UAAU,QAAQ,QAAQ;AAAA,UAC1B,YAAY,QAAQ,QAAQ;AAAA,UAC5B,oBAAoB,QAAQ,QAAQ;AAAA,UACpC,eAAe,QAAQ,QAAQ;AAAA,UAC/B,UAAU,QAAQ,QAAQ;AAAA,QAC5B;AAAA,MACF;AAAA,IACF,CAAC;AAED,WAAO;AAAA,MACL,eAAe,IAAI;AAAA,MACnB,QAAQ,IAAI;AAAA,MACZ,UAAU,IAAI;AAAA,MACd,gBAAgB,IAAI;AAAA,MACpB,QAAQ,IAAI;AAAA,MACZ,cAAc,IAAI;AAAA,MAClB,kBAAkB,IAAI;AAAA,IACxB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAAa,SAAyD;AAC1E,UAAM,MAAM,MAAM,QAQf,KAAK,SAAS,aAAa,KAAK,QAAQ;AAAA,MACzC,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,0BAA0B,QAAQ;AAAA,MACpC;AAAA,MACA,MAAM;AAAA,QACJ,QAAQ,QAAQ;AAAA,QAChB,eAAe,QAAQ;AAAA,QACvB,cAAc,QAAQ,eAAe;AAAA,QACrC,kBAAkB,QAAQ,mBAAmB;AAAA,QAC7C,UAAU,QAAQ,YAAY;AAAA,QAC9B,WAAW,QAAQ;AAAA,QACnB,WAAW,QAAQ;AAAA,MACrB;AAAA,IACF,CAAC;AAED,WAAO;AAAA,MACL,eAAe,IAAI;AAAA,MACnB,QAAQ,IAAI;AAAA,MACZ,UAAU,IAAI;AAAA,MACd,gBAAgB,IAAI;AAAA,MACpB,QAAQ,IAAI;AAAA,MACZ,cAAc,IAAI;AAAA,MAClB,kBAAkB,IAAI;AAAA,IACxB;AAAA,EACF;AACF;;;AC5FO,IAAM,iBAAN,MAAqB;AAAA,EAC1B,YAAoB,QAAiB;AAAjB;AAAA,EAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUtC,MAAM,OACJ,MACA,WACA,YAAY,KACW;AACvB,QAAI,CAAC,KAAK,QAAQ;AAChB,YAAM,IAAI,aAAa,KAAK,+BAA+B;AAAA,IAC7D;AAGA,UAAM,QAAgC,CAAC;AACvC,eAAW,QAAQ,UAAU,MAAM,GAAG,GAAG;AACvC,YAAM,CAACA,MAAK,GAAG,GAAG,IAAI,KAAK,MAAM,GAAG;AACpC,UAAIA,QAAO,IAAI,SAAS,GAAG;AACzB,cAAMA,IAAG,IAAI,IAAI,KAAK,GAAG;AAAA,MAC3B;AAAA,IACF;AAEA,UAAM,YAAY,MAAM,GAAG;AAC3B,UAAM,MAAM,MAAM,IAAI;AAEtB,QAAI,CAAC,aAAa,CAAC,KAAK;AACtB,YAAM,IAAI,aAAa,KAAK,kCAAkC;AAAA,IAChE;AAGA,UAAM,KAAK,SAAS,WAAW,EAAE;AACjC,UAAM,MAAM,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AACxC,QAAI,KAAK,IAAI,MAAM,EAAE,IAAI,WAAW;AAClC,YAAM,IAAI,aAAa,KAAK,2BAA2B;AAAA,IACzD;AAGA,UAAM,UAAU,GAAG,SAAS,IAAI,IAAI;AACpC,UAAM,UAAU,IAAI,YAAY;AAChC,UAAM,MAAM,MAAM,OAAO,OAAO;AAAA,MAC9B;AAAA,MACA,QAAQ,OAAO,KAAK,MAAM;AAAA,MAC1B,EAAE,MAAM,QAAQ,MAAM,UAAU;AAAA,MAChC;AAAA,MACA,CAAC,MAAM;AAAA,IACT;AAEA,UAAM,iBAAiB,MAAM,OAAO,OAAO;AAAA,MACzC;AAAA,MACA;AAAA,MACA,QAAQ,OAAO,OAAO;AAAA,IACxB;AAEA,UAAM,WAAW,MAAM,KAAK,IAAI,WAAW,cAAc,CAAC,EACvD,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,EAC1C,KAAK,EAAE;AAGV,QAAI,SAAS,WAAW,IAAI,UAAU,CAAC,gBAAgB,UAAU,GAAG,GAAG;AACrE,YAAM,IAAI,aAAa,KAAK,2BAA2B;AAAA,IACzD;AAEA,WAAO,KAAK,MAAM,IAAI;AAAA,EACxB;AACF;AAGA,SAAS,gBAAgB,GAAW,GAAoB;AACtD,MAAI,EAAE,WAAW,EAAE,OAAQ,QAAO;AAClC,MAAI,SAAS;AACb,WAAS,IAAI,GAAG,IAAI,EAAE,QAAQ,KAAK;AACjC,cAAU,EAAE,WAAW,CAAC,IAAI,EAAE,WAAW,CAAC;AAAA,EAC5C;AACA,SAAO,WAAW;AACpB;;;AC5EO,IAAM,QAAN,MAAY;AAAA,EAmBjB,YAAY,QAAqB;AAC/B,QAAI,CAAC,OAAO,QAAQ;AAClB,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AACA,SAAK,SAAS,OAAO;AACrB,SAAK,UAAU,eAAe,OAAO,QAAQ,OAAO,OAAO;AAC3D,SAAK,YAAY,IAAI,gBAAgB,KAAK,SAAS,KAAK,MAAM;AAC9D,SAAK,YAAY,IAAI,eAAe,KAAK,SAAS,KAAK,MAAM;AAC7D,SAAK,UAAU,IAAI,cAAc,KAAK,SAAS,KAAK,MAAM;AAC1D,SAAK,WAAW,IAAI,cAAc,KAAK,SAAS,KAAK,MAAM;AAC3D,SAAK,WAAW,IAAI,eAAe;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SAAS,SAAmD;AAChE,WAAO,KAAK,UAAU,OAAO,OAAO;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QAAQ,eAAuB,UAAmB;AACtD,WAAO,KAAK,SAAS,IAAI,eAAe,QAAQ;AAAA,EAClD;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,YAAqB;AACvB,WAAO,KAAK,OAAO,WAAW,aAAa;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,MAAc;AAChB,WAAO,KAAK;AAAA,EACd;AACF;","names":["key"]}
package/dist/index.mjs CHANGED
@@ -84,6 +84,12 @@ var AuthorizeModule = class {
84
84
  max_per_day: options.suggestedLimits.maxPerDay,
85
85
  max_per_month: options.suggestedLimits.maxPerMonth,
86
86
  require_approval_above: options.suggestedLimits.requireApprovalAbove
87
+ } : void 0,
88
+ purchase_context: options.purchaseContext ? {
89
+ amount: options.purchaseContext.amount,
90
+ description: options.purchaseContext.description,
91
+ merchant: options.purchaseContext.merchant,
92
+ reference: options.purchaseContext.reference
87
93
  } : void 0
88
94
  }
89
95
  });
@@ -169,6 +175,111 @@ var BalanceModule = class {
169
175
  }
170
176
  };
171
177
 
178
+ // src/intents.ts
179
+ var IntentsModule = class {
180
+ constructor(baseUrl, apiKey) {
181
+ this.baseUrl = baseUrl;
182
+ this.apiKey = apiKey;
183
+ }
184
+ /**
185
+ * Create a purchase intent (Buy Anywhere).
186
+ * Returns a virtual card for the customer to use at the merchant.
187
+ */
188
+ async create(options) {
189
+ const res = await request(this.baseUrl, "/intents", options.customerToken, {
190
+ method: "POST",
191
+ body: {
192
+ amount: options.amount,
193
+ currency: options.currency || "USD",
194
+ wallet_id: options.walletId,
195
+ merchant: options.merchant ? {
196
+ name: options.merchant.name,
197
+ url: options.merchant.url,
198
+ mcc: options.merchant.mcc
199
+ } : void 0,
200
+ product: options.product ? {
201
+ description: options.product.description,
202
+ url: options.product.url
203
+ } : void 0,
204
+ amount_tolerance_pct: options.amountTolerancePct
205
+ }
206
+ });
207
+ return {
208
+ intentId: res.intent_id,
209
+ status: res.status,
210
+ amount: res.amount,
211
+ currency: res.currency,
212
+ merchantName: res.merchant_name,
213
+ expiresAt: res.expires_at,
214
+ transactionId: res.transaction_id,
215
+ card: res.card ? {
216
+ pan: res.card.pan,
217
+ cvv: res.card.cvv,
218
+ expMonth: res.card.exp_month,
219
+ expYear: res.card.exp_year,
220
+ lastFour: res.card.last_four
221
+ } : void 0
222
+ };
223
+ }
224
+ /**
225
+ * Get the current status of a purchase intent.
226
+ */
227
+ async get(customerToken, intentId) {
228
+ const res = await request(
229
+ this.baseUrl,
230
+ `/intents/${intentId}`,
231
+ customerToken
232
+ );
233
+ return mapIntentStatus(res);
234
+ }
235
+ /**
236
+ * Cancel an active purchase intent.
237
+ */
238
+ async cancel(customerToken, intentId) {
239
+ const res = await request(
240
+ this.baseUrl,
241
+ `/intents/${intentId}/cancel`,
242
+ customerToken,
243
+ { method: "POST" }
244
+ );
245
+ return mapIntentStatus(res);
246
+ }
247
+ /**
248
+ * List purchase intents for the authenticated customer.
249
+ */
250
+ async list(customerToken, options) {
251
+ const params = new URLSearchParams();
252
+ if (options?.limit !== void 0) params.set("limit", String(options.limit));
253
+ if (options?.offset !== void 0)
254
+ params.set("offset", String(options.offset));
255
+ const query = params.toString();
256
+ const path = query ? `/intents?${query}` : "/intents";
257
+ const res = await request(
258
+ this.baseUrl,
259
+ path,
260
+ customerToken
261
+ );
262
+ return res.map(mapIntentStatus);
263
+ }
264
+ };
265
+ function mapIntentStatus(raw) {
266
+ return {
267
+ intentId: raw.intent_id,
268
+ status: raw.status,
269
+ amount: raw.amount,
270
+ currency: raw.currency,
271
+ merchantName: raw.merchant_name,
272
+ cardLastFour: raw.card_last_four,
273
+ asaVerified: raw.asa_verified,
274
+ asaAmount: raw.asa_amount,
275
+ asaMerchantDescriptor: raw.asa_merchant_descriptor,
276
+ asaMismatchReason: raw.asa_mismatch_reason,
277
+ transactionId: raw.transaction_id,
278
+ expiresAt: raw.expires_at,
279
+ createdAt: raw.created_at
280
+ };
281
+ }
282
+
172
283
  // src/purchase.ts
173
284
  var PurchaseModule = class {
174
285
  constructor(baseUrl, apiKey) {
@@ -321,6 +432,7 @@ var Tally = class {
321
432
  this.baseUrl = resolveBaseUrl(config.apiKey, config.baseUrl);
322
433
  this.authorize = new AuthorizeModule(this.baseUrl, this.apiKey);
323
434
  this.purchases = new PurchaseModule(this.baseUrl, this.apiKey);
435
+ this.intents = new IntentsModule(this.baseUrl, this.apiKey);
324
436
  this.balances = new BalanceModule(this.baseUrl, this.apiKey);
325
437
  this.webhooks = new WebhooksModule();
326
438
  }
@@ -352,6 +464,7 @@ var Tally = class {
352
464
  export {
353
465
  AuthorizeModule,
354
466
  BalanceModule,
467
+ IntentsModule,
355
468
  PurchaseModule,
356
469
  TallionError,
357
470
  Tally,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/http.ts","../src/authorize.ts","../src/balance.ts","../src/purchase.ts","../src/webhooks.ts","../src/tally.ts"],"sourcesContent":["export class TallionError extends Error {\n public readonly status: number;\n public readonly code?: string;\n\n constructor(status: number, message: string, code?: string) {\n super(message);\n this.name = \"TallionError\";\n this.status = status;\n this.code = code;\n }\n}\n","import { TallionError } from \"./errors\";\n\nconst SANDBOX_URL = \"https://api.sandbox.tallion.ai\";\nconst PRODUCTION_URL = \"https://api.tallion.ai\";\n\nexport function resolveBaseUrl(apiKey: string, overrideUrl?: string): string {\n if (overrideUrl) return overrideUrl;\n if (apiKey.startsWith(\"sk_live_\")) return PRODUCTION_URL;\n return SANDBOX_URL;\n}\n\nexport interface RequestOptions {\n method?: string;\n headers?: Record<string, string>;\n body?: unknown;\n}\n\nexport async function request<T>(\n baseUrl: string,\n path: string,\n apiKey: string,\n options: RequestOptions = {},\n): Promise<T> {\n if (!apiKey) {\n throw new TallionError(\n 401,\n \"Tallion API key is required. Get one at https://tallion.ai/developer\",\n \"missing_api_key\",\n );\n }\n const url = `${baseUrl}/api${path}`;\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${apiKey}`,\n ...options.headers,\n };\n\n const res = await fetch(url, {\n method: options.method || \"GET\",\n headers,\n body: options.body ? JSON.stringify(options.body) : undefined,\n });\n\n if (!res.ok) {\n const body = await res.json().catch(() => ({ error: \"Unknown error\" }));\n throw new TallionError(\n res.status,\n body.error || \"Request failed\",\n body.code,\n );\n }\n\n return res.json() as Promise<T>;\n}\n","import { request } from \"./http\";\nimport type {\n AuthUrlResult,\n CreateAuthUrlOptions,\n ExchangeCodeOptions,\n RefreshTokenOptions,\n TokenResult,\n} from \"./types\";\n\n/** Generate a random string for PKCE */\nfunction generateRandomString(length: number): string {\n const chars = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~\";\n const array = new Uint8Array(length);\n crypto.getRandomValues(array);\n return Array.from(array, (byte) => chars[byte % chars.length]).join(\"\");\n}\n\n/** SHA-256 hash for PKCE S256 challenge */\nasync function sha256(plain: string): Promise<string> {\n const encoder = new TextEncoder();\n const data = encoder.encode(plain);\n const hash = await crypto.subtle.digest(\"SHA-256\", data);\n return btoa(String.fromCharCode(...new Uint8Array(hash)))\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=+$/, \"\");\n}\n\nexport class AuthorizeModule {\n constructor(\n private baseUrl: string,\n private apiKey: string,\n ) {}\n\n /**\n * Create an authorization URL for customer consent.\n * Returns the URL to open in a popup/browser plus the PKCE code verifier.\n */\n async createUrl(options: CreateAuthUrlOptions): Promise<AuthUrlResult> {\n const codeVerifier = generateRandomString(64);\n const codeChallenge = await sha256(codeVerifier);\n\n const res = await request<{\n authorization_id: string;\n url: string;\n state: string;\n }>(this.baseUrl, \"/oauth/authorize\", this.apiKey, {\n method: \"POST\",\n body: {\n customer_identifier: options.customerIdentifier,\n redirect_url: options.redirectUrl,\n scopes: options.scopes || [\"purchase\", \"balance:read\"],\n code_challenge: codeChallenge,\n code_challenge_method: options.codeChallengeMethod || \"S256\",\n suggested_limits: options.suggestedLimits\n ? {\n max_per_transaction: options.suggestedLimits.maxPerTransaction,\n max_per_day: options.suggestedLimits.maxPerDay,\n max_per_month: options.suggestedLimits.maxPerMonth,\n require_approval_above: options.suggestedLimits.requireApprovalAbove,\n }\n : undefined,\n },\n });\n\n return {\n url: res.url,\n state: res.state,\n codeVerifier,\n authorizationId: res.authorization_id,\n };\n }\n\n /**\n * Exchange an authorization code for access + refresh tokens.\n */\n async exchangeCode(options: ExchangeCodeOptions): Promise<TokenResult> {\n const res = await request<{\n access_token: string;\n refresh_token: string;\n token_type: string;\n expires_in: number;\n customer_id: string;\n installation_id: string;\n }>(this.baseUrl, \"/oauth/token\", this.apiKey, {\n method: \"POST\",\n body: {\n grant_type: \"authorization_code\",\n code: options.code,\n code_verifier: options.codeVerifier,\n },\n });\n\n return {\n accessToken: res.access_token,\n refreshToken: res.refresh_token,\n tokenType: res.token_type,\n expiresIn: res.expires_in,\n customerId: res.customer_id,\n installationId: res.installation_id,\n };\n }\n\n /**\n * Refresh an access token using a refresh token.\n */\n async refreshToken(options: RefreshTokenOptions): Promise<TokenResult> {\n const res = await request<{\n access_token: string;\n refresh_token: string;\n token_type: string;\n expires_in: number;\n customer_id: string;\n installation_id: string;\n }>(this.baseUrl, \"/oauth/token\", this.apiKey, {\n method: \"POST\",\n body: {\n grant_type: \"refresh_token\",\n refresh_token: options.refreshToken,\n },\n });\n\n return {\n accessToken: res.access_token,\n refreshToken: res.refresh_token,\n tokenType: res.token_type,\n expiresIn: res.expires_in,\n customerId: res.customer_id,\n installationId: res.installation_id,\n };\n }\n\n /**\n * Revoke an access or refresh token.\n */\n async revoke(token: string): Promise<void> {\n await request(this.baseUrl, \"/oauth/revoke\", this.apiKey, {\n method: \"POST\",\n body: { token },\n });\n }\n}\n","import { request } from \"./http\";\nimport type { BalanceResult } from \"./types\";\n\nexport class BalanceModule {\n constructor(\n private baseUrl: string,\n private apiKey: string,\n ) {}\n\n /**\n * Get wallet balance for a customer (using OAuth token).\n */\n async get(customerToken: string, walletId?: string): Promise<BalanceResult> {\n const path = walletId ? `/wallets/${walletId}/budget` : \"/wallets/me\";\n const res = await request<{\n id?: string;\n wallet_id?: string;\n funding_amount: number;\n spent_amount: number;\n remaining: number;\n }>(this.baseUrl, path, customerToken, {\n method: \"GET\",\n });\n\n return {\n walletId: res.wallet_id || res.id || \"\",\n fundingAmount: res.funding_amount,\n spentAmount: res.spent_amount,\n remaining: res.remaining,\n };\n }\n}\n","import { request } from \"./http\";\nimport type { LegacyPurchaseOptions, PurchaseOptions, PurchaseResult } from \"./types\";\n\nexport class PurchaseModule {\n constructor(\n private baseUrl: string,\n private apiKey: string,\n ) {}\n\n /**\n * Make a purchase using an OAuth customer token.\n */\n async create(options: PurchaseOptions): Promise<PurchaseResult> {\n const res = await request<{\n transaction_id: string;\n status: string;\n decision: string;\n decision_reason: string;\n amount: number;\n merchant_name: string;\n approval_deadline?: string;\n }>(this.baseUrl, \"/purchase\", options.customerToken, {\n method: \"POST\",\n headers: {\n \"X-Tallion-Installation\": \"\", // Resolved by OAuth token\n },\n body: {\n amount: options.amount,\n currency: options.currency || \"USD\",\n wallet_id: options.walletId,\n merchant: {\n name: options.merchant.name,\n mcc: options.merchant.mcc || \"\",\n country: options.merchant.country || \"US\",\n },\n context: {\n description: options.context.description,\n category: options.context.category,\n line_items: options.context.lineItems,\n external_reference: options.context.externalReference,\n refund_policy: options.context.refundPolicy,\n metadata: options.context.metadata,\n },\n },\n });\n\n return {\n transactionId: res.transaction_id,\n status: res.status as PurchaseResult[\"status\"],\n decision: res.decision,\n decisionReason: res.decision_reason,\n amount: res.amount,\n merchantName: res.merchant_name,\n approvalDeadline: res.approval_deadline,\n };\n }\n\n /**\n * Make a purchase using the legacy API key + installation ID auth.\n */\n async legacyCreate(options: LegacyPurchaseOptions): Promise<PurchaseResult> {\n const res = await request<{\n transaction_id: string;\n status: string;\n decision: string;\n decision_reason: string;\n amount: number;\n merchant_name: string;\n approval_deadline?: string;\n }>(this.baseUrl, \"/purchase\", this.apiKey, {\n method: \"POST\",\n headers: {\n \"X-Tallion-Installation\": options.installationId,\n },\n body: {\n amount: options.amount,\n merchant_name: options.merchantName,\n merchant_mcc: options.merchantMcc || \"\",\n merchant_country: options.merchantCountry || \"US\",\n currency: options.currency || \"USD\",\n wallet_id: options.walletId,\n reasoning: options.reasoning,\n },\n });\n\n return {\n transactionId: res.transaction_id,\n status: res.status as PurchaseResult[\"status\"],\n decision: res.decision,\n decisionReason: res.decision_reason,\n amount: res.amount,\n merchantName: res.merchant_name,\n approvalDeadline: res.approval_deadline,\n };\n }\n}\n","import type { WebhookEvent } from \"./types\";\nimport { TallionError } from \"./errors\";\n\nexport class WebhooksModule {\n constructor(private secret?: string) {}\n\n /**\n * Verify a webhook signature and parse the event.\n * Uses Web Crypto API (works in Node 18+, Deno, Bun, Cloudflare Workers, etc.)\n *\n * @param body - Raw request body string\n * @param signature - Value of X-Tally-Signature header\n * @param tolerance - Max age in seconds (default: 300 = 5 minutes)\n */\n async verify(\n body: string,\n signature: string,\n tolerance = 300,\n ): Promise<WebhookEvent> {\n if (!this.secret) {\n throw new TallionError(500, \"Webhook secret not configured\");\n }\n\n // Parse signature header: \"t={timestamp},v1={hex_signature}\"\n const parts: Record<string, string> = {};\n for (const part of signature.split(\",\")) {\n const [key, ...val] = part.split(\"=\");\n if (key && val.length > 0) {\n parts[key] = val.join(\"=\");\n }\n }\n\n const timestamp = parts[\"t\"];\n const sig = parts[\"v1\"];\n\n if (!timestamp || !sig) {\n throw new TallionError(400, \"Invalid webhook signature format\");\n }\n\n // Check timestamp freshness\n const ts = parseInt(timestamp, 10);\n const now = Math.floor(Date.now() / 1000);\n if (Math.abs(now - ts) > tolerance) {\n throw new TallionError(400, \"Webhook timestamp expired\");\n }\n\n // Compute HMAC-SHA256\n const message = `${timestamp}.${body}`;\n const encoder = new TextEncoder();\n const key = await crypto.subtle.importKey(\n \"raw\",\n encoder.encode(this.secret),\n { name: \"HMAC\", hash: \"SHA-256\" },\n false,\n [\"sign\"],\n );\n\n const signatureBytes = await crypto.subtle.sign(\n \"HMAC\",\n key,\n encoder.encode(message),\n );\n\n const computed = Array.from(new Uint8Array(signatureBytes))\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n\n // Constant-time comparison\n if (computed.length !== sig.length || !timingSafeEqual(computed, sig)) {\n throw new TallionError(401, \"Invalid webhook signature\");\n }\n\n return JSON.parse(body) as WebhookEvent;\n }\n}\n\n/** Simple constant-time string comparison */\nfunction timingSafeEqual(a: string, b: string): boolean {\n if (a.length !== b.length) return false;\n let result = 0;\n for (let i = 0; i < a.length; i++) {\n result |= a.charCodeAt(i) ^ b.charCodeAt(i);\n }\n return result === 0;\n}\n","import { AuthorizeModule } from \"./authorize\";\nimport { BalanceModule } from \"./balance\";\nimport { resolveBaseUrl } from \"./http\";\nimport { PurchaseModule } from \"./purchase\";\nimport { WebhooksModule } from \"./webhooks\";\nimport type { PurchaseOptions, PurchaseResult, TallyConfig } from \"./types\";\n\nexport class Tally {\n private baseUrl: string;\n private apiKey: string;\n\n /** OAuth authorization flow */\n public authorize: AuthorizeModule;\n\n /** Purchase operations */\n public purchases: PurchaseModule;\n\n /** Balance operations */\n public balances: BalanceModule;\n\n /** Webhook signature verification */\n public webhooks: WebhooksModule;\n\n constructor(config: TallyConfig) {\n if (!config.apiKey) {\n throw new Error(\n \"Tallion API key is required. Get one at https://tallion.ai/developer\",\n );\n }\n this.apiKey = config.apiKey;\n this.baseUrl = resolveBaseUrl(config.apiKey, config.baseUrl);\n this.authorize = new AuthorizeModule(this.baseUrl, this.apiKey);\n this.purchases = new PurchaseModule(this.baseUrl, this.apiKey);\n this.balances = new BalanceModule(this.baseUrl, this.apiKey);\n this.webhooks = new WebhooksModule();\n }\n\n /**\n * Convenience method: Make a purchase (delegates to purchases.create).\n */\n async purchase(options: PurchaseOptions): Promise<PurchaseResult> {\n return this.purchases.create(options);\n }\n\n /**\n * Convenience method: Get balance for a customer.\n */\n async balance(customerToken: string, walletId?: string) {\n return this.balances.get(customerToken, walletId);\n }\n\n /**\n * Check if this is a sandbox instance.\n */\n get isSandbox(): boolean {\n return this.apiKey.startsWith(\"sk_sandbox_\");\n }\n\n /**\n * Get the resolved base URL.\n */\n get url(): string {\n return this.baseUrl;\n }\n}\n"],"mappings":"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","names":["key"]}
1
+ {"version":3,"sources":["../src/errors.ts","../src/http.ts","../src/authorize.ts","../src/balance.ts","../src/intents.ts","../src/purchase.ts","../src/webhooks.ts","../src/tally.ts"],"sourcesContent":["export class TallionError extends Error {\n public readonly status: number;\n public readonly code?: string;\n\n constructor(status: number, message: string, code?: string) {\n super(message);\n this.name = \"TallionError\";\n this.status = status;\n this.code = code;\n }\n}\n","import { TallionError } from \"./errors\";\n\nconst SANDBOX_URL = \"https://api.sandbox.tallion.ai\";\nconst PRODUCTION_URL = \"https://api.tallion.ai\";\n\nexport function resolveBaseUrl(apiKey: string, overrideUrl?: string): string {\n if (overrideUrl) return overrideUrl;\n if (apiKey.startsWith(\"sk_live_\")) return PRODUCTION_URL;\n return SANDBOX_URL;\n}\n\nexport interface RequestOptions {\n method?: string;\n headers?: Record<string, string>;\n body?: unknown;\n}\n\nexport async function request<T>(\n baseUrl: string,\n path: string,\n apiKey: string,\n options: RequestOptions = {},\n): Promise<T> {\n if (!apiKey) {\n throw new TallionError(\n 401,\n \"Tallion API key is required. Get one at https://tallion.ai/developer\",\n \"missing_api_key\",\n );\n }\n const url = `${baseUrl}/api${path}`;\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${apiKey}`,\n ...options.headers,\n };\n\n const res = await fetch(url, {\n method: options.method || \"GET\",\n headers,\n body: options.body ? JSON.stringify(options.body) : undefined,\n });\n\n if (!res.ok) {\n const body = await res.json().catch(() => ({ error: \"Unknown error\" }));\n throw new TallionError(\n res.status,\n body.error || \"Request failed\",\n body.code,\n );\n }\n\n return res.json() as Promise<T>;\n}\n","import { request } from \"./http\";\nimport type {\n AuthUrlResult,\n CreateAuthUrlOptions,\n ExchangeCodeOptions,\n RefreshTokenOptions,\n TokenResult,\n} from \"./types\";\n\n/** Generate a random string for PKCE */\nfunction generateRandomString(length: number): string {\n const chars = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~\";\n const array = new Uint8Array(length);\n crypto.getRandomValues(array);\n return Array.from(array, (byte) => chars[byte % chars.length]).join(\"\");\n}\n\n/** SHA-256 hash for PKCE S256 challenge */\nasync function sha256(plain: string): Promise<string> {\n const encoder = new TextEncoder();\n const data = encoder.encode(plain);\n const hash = await crypto.subtle.digest(\"SHA-256\", data);\n return btoa(String.fromCharCode(...new Uint8Array(hash)))\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=+$/, \"\");\n}\n\nexport class AuthorizeModule {\n constructor(\n private baseUrl: string,\n private apiKey: string,\n ) {}\n\n /**\n * Create an authorization URL for customer consent.\n * Returns the URL to open in a popup/browser plus the PKCE code verifier.\n */\n async createUrl(options: CreateAuthUrlOptions): Promise<AuthUrlResult> {\n const codeVerifier = generateRandomString(64);\n const codeChallenge = await sha256(codeVerifier);\n\n const res = await request<{\n authorization_id: string;\n url: string;\n state: string;\n }>(this.baseUrl, \"/oauth/authorize\", this.apiKey, {\n method: \"POST\",\n body: {\n customer_identifier: options.customerIdentifier,\n redirect_url: options.redirectUrl,\n scopes: options.scopes || [\"purchase\", \"balance:read\"],\n code_challenge: codeChallenge,\n code_challenge_method: options.codeChallengeMethod || \"S256\",\n suggested_limits: options.suggestedLimits\n ? {\n max_per_transaction: options.suggestedLimits.maxPerTransaction,\n max_per_day: options.suggestedLimits.maxPerDay,\n max_per_month: options.suggestedLimits.maxPerMonth,\n require_approval_above: options.suggestedLimits.requireApprovalAbove,\n }\n : undefined,\n purchase_context: options.purchaseContext\n ? {\n amount: options.purchaseContext.amount,\n description: options.purchaseContext.description,\n merchant: options.purchaseContext.merchant,\n reference: options.purchaseContext.reference,\n }\n : undefined,\n },\n });\n\n return {\n url: res.url,\n state: res.state,\n codeVerifier,\n authorizationId: res.authorization_id,\n };\n }\n\n /**\n * Exchange an authorization code for access + refresh tokens.\n */\n async exchangeCode(options: ExchangeCodeOptions): Promise<TokenResult> {\n const res = await request<{\n access_token: string;\n refresh_token: string;\n token_type: string;\n expires_in: number;\n customer_id: string;\n installation_id: string;\n }>(this.baseUrl, \"/oauth/token\", this.apiKey, {\n method: \"POST\",\n body: {\n grant_type: \"authorization_code\",\n code: options.code,\n code_verifier: options.codeVerifier,\n },\n });\n\n return {\n accessToken: res.access_token,\n refreshToken: res.refresh_token,\n tokenType: res.token_type,\n expiresIn: res.expires_in,\n customerId: res.customer_id,\n installationId: res.installation_id,\n };\n }\n\n /**\n * Refresh an access token using a refresh token.\n */\n async refreshToken(options: RefreshTokenOptions): Promise<TokenResult> {\n const res = await request<{\n access_token: string;\n refresh_token: string;\n token_type: string;\n expires_in: number;\n customer_id: string;\n installation_id: string;\n }>(this.baseUrl, \"/oauth/token\", this.apiKey, {\n method: \"POST\",\n body: {\n grant_type: \"refresh_token\",\n refresh_token: options.refreshToken,\n },\n });\n\n return {\n accessToken: res.access_token,\n refreshToken: res.refresh_token,\n tokenType: res.token_type,\n expiresIn: res.expires_in,\n customerId: res.customer_id,\n installationId: res.installation_id,\n };\n }\n\n /**\n * Revoke an access or refresh token.\n */\n async revoke(token: string): Promise<void> {\n await request(this.baseUrl, \"/oauth/revoke\", this.apiKey, {\n method: \"POST\",\n body: { token },\n });\n }\n}\n","import { request } from \"./http\";\nimport type { BalanceResult } from \"./types\";\n\nexport class BalanceModule {\n constructor(\n private baseUrl: string,\n private apiKey: string,\n ) {}\n\n /**\n * Get wallet balance for a customer (using OAuth token).\n */\n async get(customerToken: string, walletId?: string): Promise<BalanceResult> {\n const path = walletId ? `/wallets/${walletId}/budget` : \"/wallets/me\";\n const res = await request<{\n id?: string;\n wallet_id?: string;\n funding_amount: number;\n spent_amount: number;\n remaining: number;\n }>(this.baseUrl, path, customerToken, {\n method: \"GET\",\n });\n\n return {\n walletId: res.wallet_id || res.id || \"\",\n fundingAmount: res.funding_amount,\n spentAmount: res.spent_amount,\n remaining: res.remaining,\n };\n }\n}\n","import { request } from \"./http\";\nimport type {\n CreateIntentOptions,\n IntentResult,\n IntentStatusResult,\n ListIntentsOptions,\n} from \"./types\";\n\nexport class IntentsModule {\n constructor(\n private baseUrl: string,\n private apiKey: string,\n ) {}\n\n /**\n * Create a purchase intent (Buy Anywhere).\n * Returns a virtual card for the customer to use at the merchant.\n */\n async create(options: CreateIntentOptions): Promise<IntentResult> {\n const res = await request<{\n intent_id: string;\n status: string;\n amount: number;\n currency: string;\n merchant_name?: string;\n expires_at?: string;\n transaction_id?: string;\n card?: {\n pan: string;\n cvv: string;\n exp_month: number;\n exp_year: number;\n last_four: string;\n };\n }>(this.baseUrl, \"/intents\", options.customerToken, {\n method: \"POST\",\n body: {\n amount: options.amount,\n currency: options.currency || \"USD\",\n wallet_id: options.walletId,\n merchant: options.merchant\n ? {\n name: options.merchant.name,\n url: options.merchant.url,\n mcc: options.merchant.mcc,\n }\n : undefined,\n product: options.product\n ? {\n description: options.product.description,\n url: options.product.url,\n }\n : undefined,\n amount_tolerance_pct: options.amountTolerancePct,\n },\n });\n\n return {\n intentId: res.intent_id,\n status: res.status as IntentResult[\"status\"],\n amount: res.amount,\n currency: res.currency,\n merchantName: res.merchant_name,\n expiresAt: res.expires_at,\n transactionId: res.transaction_id,\n card: res.card\n ? {\n pan: res.card.pan,\n cvv: res.card.cvv,\n expMonth: res.card.exp_month,\n expYear: res.card.exp_year,\n lastFour: res.card.last_four,\n }\n : undefined,\n };\n }\n\n /**\n * Get the current status of a purchase intent.\n */\n async get(\n customerToken: string,\n intentId: string,\n ): Promise<IntentStatusResult> {\n const res = await request<RawIntentStatus>(\n this.baseUrl,\n `/intents/${intentId}`,\n customerToken,\n );\n\n return mapIntentStatus(res);\n }\n\n /**\n * Cancel an active purchase intent.\n */\n async cancel(\n customerToken: string,\n intentId: string,\n ): Promise<IntentStatusResult> {\n const res = await request<RawIntentStatus>(\n this.baseUrl,\n `/intents/${intentId}/cancel`,\n customerToken,\n { method: \"POST\" },\n );\n\n return mapIntentStatus(res);\n }\n\n /**\n * List purchase intents for the authenticated customer.\n */\n async list(\n customerToken: string,\n options?: ListIntentsOptions,\n ): Promise<IntentStatusResult[]> {\n const params = new URLSearchParams();\n if (options?.limit !== undefined) params.set(\"limit\", String(options.limit));\n if (options?.offset !== undefined)\n params.set(\"offset\", String(options.offset));\n\n const query = params.toString();\n const path = query ? `/intents?${query}` : \"/intents\";\n\n const res = await request<RawIntentStatus[]>(\n this.baseUrl,\n path,\n customerToken,\n );\n\n return res.map(mapIntentStatus);\n }\n}\n\n// ── Internal helpers ──\n\ninterface RawIntentStatus {\n intent_id: string;\n status: string;\n amount: number;\n currency: string;\n merchant_name?: string;\n card_last_four?: string;\n asa_verified: boolean;\n asa_amount?: number;\n asa_merchant_descriptor?: string;\n asa_mismatch_reason?: string;\n transaction_id?: string;\n expires_at?: string;\n created_at: string;\n}\n\nfunction mapIntentStatus(raw: RawIntentStatus): IntentStatusResult {\n return {\n intentId: raw.intent_id,\n status: raw.status,\n amount: raw.amount,\n currency: raw.currency,\n merchantName: raw.merchant_name,\n cardLastFour: raw.card_last_four,\n asaVerified: raw.asa_verified,\n asaAmount: raw.asa_amount,\n asaMerchantDescriptor: raw.asa_merchant_descriptor,\n asaMismatchReason: raw.asa_mismatch_reason,\n transactionId: raw.transaction_id,\n expiresAt: raw.expires_at,\n createdAt: raw.created_at,\n };\n}\n","import { request } from \"./http\";\nimport type { LegacyPurchaseOptions, PurchaseOptions, PurchaseResult } from \"./types\";\n\nexport class PurchaseModule {\n constructor(\n private baseUrl: string,\n private apiKey: string,\n ) {}\n\n /**\n * Make a purchase using an OAuth customer token.\n */\n async create(options: PurchaseOptions): Promise<PurchaseResult> {\n const res = await request<{\n transaction_id: string;\n status: string;\n decision: string;\n decision_reason: string;\n amount: number;\n merchant_name: string;\n approval_deadline?: string;\n }>(this.baseUrl, \"/purchase\", options.customerToken, {\n method: \"POST\",\n headers: {\n \"X-Tallion-Installation\": \"\", // Resolved by OAuth token\n },\n body: {\n amount: options.amount,\n currency: options.currency || \"USD\",\n wallet_id: options.walletId,\n merchant: {\n name: options.merchant.name,\n mcc: options.merchant.mcc || \"\",\n country: options.merchant.country || \"US\",\n },\n context: {\n description: options.context.description,\n category: options.context.category,\n line_items: options.context.lineItems,\n external_reference: options.context.externalReference,\n refund_policy: options.context.refundPolicy,\n metadata: options.context.metadata,\n },\n },\n });\n\n return {\n transactionId: res.transaction_id,\n status: res.status as PurchaseResult[\"status\"],\n decision: res.decision,\n decisionReason: res.decision_reason,\n amount: res.amount,\n merchantName: res.merchant_name,\n approvalDeadline: res.approval_deadline,\n };\n }\n\n /**\n * Make a purchase using the legacy API key + installation ID auth.\n */\n async legacyCreate(options: LegacyPurchaseOptions): Promise<PurchaseResult> {\n const res = await request<{\n transaction_id: string;\n status: string;\n decision: string;\n decision_reason: string;\n amount: number;\n merchant_name: string;\n approval_deadline?: string;\n }>(this.baseUrl, \"/purchase\", this.apiKey, {\n method: \"POST\",\n headers: {\n \"X-Tallion-Installation\": options.installationId,\n },\n body: {\n amount: options.amount,\n merchant_name: options.merchantName,\n merchant_mcc: options.merchantMcc || \"\",\n merchant_country: options.merchantCountry || \"US\",\n currency: options.currency || \"USD\",\n wallet_id: options.walletId,\n reasoning: options.reasoning,\n },\n });\n\n return {\n transactionId: res.transaction_id,\n status: res.status as PurchaseResult[\"status\"],\n decision: res.decision,\n decisionReason: res.decision_reason,\n amount: res.amount,\n merchantName: res.merchant_name,\n approvalDeadline: res.approval_deadline,\n };\n }\n}\n","import type { WebhookEvent } from \"./types\";\nimport { TallionError } from \"./errors\";\n\nexport class WebhooksModule {\n constructor(private secret?: string) {}\n\n /**\n * Verify a webhook signature and parse the event.\n * Uses Web Crypto API (works in Node 18+, Deno, Bun, Cloudflare Workers, etc.)\n *\n * @param body - Raw request body string\n * @param signature - Value of X-Tally-Signature header\n * @param tolerance - Max age in seconds (default: 300 = 5 minutes)\n */\n async verify(\n body: string,\n signature: string,\n tolerance = 300,\n ): Promise<WebhookEvent> {\n if (!this.secret) {\n throw new TallionError(500, \"Webhook secret not configured\");\n }\n\n // Parse signature header: \"t={timestamp},v1={hex_signature}\"\n const parts: Record<string, string> = {};\n for (const part of signature.split(\",\")) {\n const [key, ...val] = part.split(\"=\");\n if (key && val.length > 0) {\n parts[key] = val.join(\"=\");\n }\n }\n\n const timestamp = parts[\"t\"];\n const sig = parts[\"v1\"];\n\n if (!timestamp || !sig) {\n throw new TallionError(400, \"Invalid webhook signature format\");\n }\n\n // Check timestamp freshness\n const ts = parseInt(timestamp, 10);\n const now = Math.floor(Date.now() / 1000);\n if (Math.abs(now - ts) > tolerance) {\n throw new TallionError(400, \"Webhook timestamp expired\");\n }\n\n // Compute HMAC-SHA256\n const message = `${timestamp}.${body}`;\n const encoder = new TextEncoder();\n const key = await crypto.subtle.importKey(\n \"raw\",\n encoder.encode(this.secret),\n { name: \"HMAC\", hash: \"SHA-256\" },\n false,\n [\"sign\"],\n );\n\n const signatureBytes = await crypto.subtle.sign(\n \"HMAC\",\n key,\n encoder.encode(message),\n );\n\n const computed = Array.from(new Uint8Array(signatureBytes))\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n\n // Constant-time comparison\n if (computed.length !== sig.length || !timingSafeEqual(computed, sig)) {\n throw new TallionError(401, \"Invalid webhook signature\");\n }\n\n return JSON.parse(body) as WebhookEvent;\n }\n}\n\n/** Simple constant-time string comparison */\nfunction timingSafeEqual(a: string, b: string): boolean {\n if (a.length !== b.length) return false;\n let result = 0;\n for (let i = 0; i < a.length; i++) {\n result |= a.charCodeAt(i) ^ b.charCodeAt(i);\n }\n return result === 0;\n}\n","import { AuthorizeModule } from \"./authorize\";\nimport { BalanceModule } from \"./balance\";\nimport { resolveBaseUrl } from \"./http\";\nimport { IntentsModule } from \"./intents\";\nimport { PurchaseModule } from \"./purchase\";\nimport { WebhooksModule } from \"./webhooks\";\nimport type { PurchaseOptions, PurchaseResult, TallyConfig } from \"./types\";\n\nexport class Tally {\n private baseUrl: string;\n private apiKey: string;\n\n /** OAuth authorization flow */\n public authorize: AuthorizeModule;\n\n /** Purchase operations */\n public purchases: PurchaseModule;\n\n /** Balance operations */\n public balances: BalanceModule;\n\n /** Purchase intents (Buy Anywhere) */\n public intents: IntentsModule;\n\n /** Webhook signature verification */\n public webhooks: WebhooksModule;\n\n constructor(config: TallyConfig) {\n if (!config.apiKey) {\n throw new Error(\n \"Tallion API key is required. Get one at https://tallion.ai/developer\",\n );\n }\n this.apiKey = config.apiKey;\n this.baseUrl = resolveBaseUrl(config.apiKey, config.baseUrl);\n this.authorize = new AuthorizeModule(this.baseUrl, this.apiKey);\n this.purchases = new PurchaseModule(this.baseUrl, this.apiKey);\n this.intents = new IntentsModule(this.baseUrl, this.apiKey);\n this.balances = new BalanceModule(this.baseUrl, this.apiKey);\n this.webhooks = new WebhooksModule();\n }\n\n /**\n * Convenience method: Make a purchase (delegates to purchases.create).\n */\n async purchase(options: PurchaseOptions): Promise<PurchaseResult> {\n return this.purchases.create(options);\n }\n\n /**\n * Convenience method: Get balance for a customer.\n */\n async balance(customerToken: string, walletId?: string) {\n return this.balances.get(customerToken, walletId);\n }\n\n /**\n * Check if this is a sandbox instance.\n */\n get isSandbox(): boolean {\n return this.apiKey.startsWith(\"sk_sandbox_\");\n }\n\n /**\n * Get the resolved base URL.\n */\n get url(): string {\n return this.baseUrl;\n }\n}\n"],"mappings":";AAAO,IAAM,eAAN,cAA2B,MAAM;AAAA,EAItC,YAAY,QAAgB,SAAiB,MAAe;AAC1D,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,SAAK,OAAO;AAAA,EACd;AACF;;;ACRA,IAAM,cAAc;AACpB,IAAM,iBAAiB;AAEhB,SAAS,eAAe,QAAgB,aAA8B;AAC3E,MAAI,YAAa,QAAO;AACxB,MAAI,OAAO,WAAW,UAAU,EAAG,QAAO;AAC1C,SAAO;AACT;AAQA,eAAsB,QACpB,SACA,MACA,QACA,UAA0B,CAAC,GACf;AACZ,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACA,QAAM,MAAM,GAAG,OAAO,OAAO,IAAI;AACjC,QAAM,UAAkC;AAAA,IACtC,gBAAgB;AAAA,IAChB,eAAe,UAAU,MAAM;AAAA,IAC/B,GAAG,QAAQ;AAAA,EACb;AAEA,QAAM,MAAM,MAAM,MAAM,KAAK;AAAA,IAC3B,QAAQ,QAAQ,UAAU;AAAA,IAC1B;AAAA,IACA,MAAM,QAAQ,OAAO,KAAK,UAAU,QAAQ,IAAI,IAAI;AAAA,EACtD,CAAC;AAED,MAAI,CAAC,IAAI,IAAI;AACX,UAAM,OAAO,MAAM,IAAI,KAAK,EAAE,MAAM,OAAO,EAAE,OAAO,gBAAgB,EAAE;AACtE,UAAM,IAAI;AAAA,MACR,IAAI;AAAA,MACJ,KAAK,SAAS;AAAA,MACd,KAAK;AAAA,IACP;AAAA,EACF;AAEA,SAAO,IAAI,KAAK;AAClB;;;AC3CA,SAAS,qBAAqB,QAAwB;AACpD,QAAM,QAAQ;AACd,QAAM,QAAQ,IAAI,WAAW,MAAM;AACnC,SAAO,gBAAgB,KAAK;AAC5B,SAAO,MAAM,KAAK,OAAO,CAAC,SAAS,MAAM,OAAO,MAAM,MAAM,CAAC,EAAE,KAAK,EAAE;AACxE;AAGA,eAAe,OAAO,OAAgC;AACpD,QAAM,UAAU,IAAI,YAAY;AAChC,QAAM,OAAO,QAAQ,OAAO,KAAK;AACjC,QAAM,OAAO,MAAM,OAAO,OAAO,OAAO,WAAW,IAAI;AACvD,SAAO,KAAK,OAAO,aAAa,GAAG,IAAI,WAAW,IAAI,CAAC,CAAC,EACrD,QAAQ,OAAO,GAAG,EAClB,QAAQ,OAAO,GAAG,EAClB,QAAQ,OAAO,EAAE;AACtB;AAEO,IAAM,kBAAN,MAAsB;AAAA,EAC3B,YACU,SACA,QACR;AAFQ;AACA;AAAA,EACP;AAAA;AAAA;AAAA;AAAA;AAAA,EAMH,MAAM,UAAU,SAAuD;AACrE,UAAM,eAAe,qBAAqB,EAAE;AAC5C,UAAM,gBAAgB,MAAM,OAAO,YAAY;AAE/C,UAAM,MAAM,MAAM,QAIf,KAAK,SAAS,oBAAoB,KAAK,QAAQ;AAAA,MAChD,QAAQ;AAAA,MACR,MAAM;AAAA,QACJ,qBAAqB,QAAQ;AAAA,QAC7B,cAAc,QAAQ;AAAA,QACtB,QAAQ,QAAQ,UAAU,CAAC,YAAY,cAAc;AAAA,QACrD,gBAAgB;AAAA,QAChB,uBAAuB,QAAQ,uBAAuB;AAAA,QACtD,kBAAkB,QAAQ,kBACtB;AAAA,UACE,qBAAqB,QAAQ,gBAAgB;AAAA,UAC7C,aAAa,QAAQ,gBAAgB;AAAA,UACrC,eAAe,QAAQ,gBAAgB;AAAA,UACvC,wBAAwB,QAAQ,gBAAgB;AAAA,QAClD,IACA;AAAA,QACJ,kBAAkB,QAAQ,kBACtB;AAAA,UACE,QAAQ,QAAQ,gBAAgB;AAAA,UAChC,aAAa,QAAQ,gBAAgB;AAAA,UACrC,UAAU,QAAQ,gBAAgB;AAAA,UAClC,WAAW,QAAQ,gBAAgB;AAAA,QACrC,IACA;AAAA,MACN;AAAA,IACF,CAAC;AAED,WAAO;AAAA,MACL,KAAK,IAAI;AAAA,MACT,OAAO,IAAI;AAAA,MACX;AAAA,MACA,iBAAiB,IAAI;AAAA,IACvB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAAa,SAAoD;AACrE,UAAM,MAAM,MAAM,QAOf,KAAK,SAAS,gBAAgB,KAAK,QAAQ;AAAA,MAC5C,QAAQ;AAAA,MACR,MAAM;AAAA,QACJ,YAAY;AAAA,QACZ,MAAM,QAAQ;AAAA,QACd,eAAe,QAAQ;AAAA,MACzB;AAAA,IACF,CAAC;AAED,WAAO;AAAA,MACL,aAAa,IAAI;AAAA,MACjB,cAAc,IAAI;AAAA,MAClB,WAAW,IAAI;AAAA,MACf,WAAW,IAAI;AAAA,MACf,YAAY,IAAI;AAAA,MAChB,gBAAgB,IAAI;AAAA,IACtB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAAa,SAAoD;AACrE,UAAM,MAAM,MAAM,QAOf,KAAK,SAAS,gBAAgB,KAAK,QAAQ;AAAA,MAC5C,QAAQ;AAAA,MACR,MAAM;AAAA,QACJ,YAAY;AAAA,QACZ,eAAe,QAAQ;AAAA,MACzB;AAAA,IACF,CAAC;AAED,WAAO;AAAA,MACL,aAAa,IAAI;AAAA,MACjB,cAAc,IAAI;AAAA,MAClB,WAAW,IAAI;AAAA,MACf,WAAW,IAAI;AAAA,MACf,YAAY,IAAI;AAAA,MAChB,gBAAgB,IAAI;AAAA,IACtB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAO,OAA8B;AACzC,UAAM,QAAQ,KAAK,SAAS,iBAAiB,KAAK,QAAQ;AAAA,MACxD,QAAQ;AAAA,MACR,MAAM,EAAE,MAAM;AAAA,IAChB,CAAC;AAAA,EACH;AACF;;;AClJO,IAAM,gBAAN,MAAoB;AAAA,EACzB,YACU,SACA,QACR;AAFQ;AACA;AAAA,EACP;AAAA;AAAA;AAAA;AAAA,EAKH,MAAM,IAAI,eAAuB,UAA2C;AAC1E,UAAM,OAAO,WAAW,YAAY,QAAQ,YAAY;AACxD,UAAM,MAAM,MAAM,QAMf,KAAK,SAAS,MAAM,eAAe;AAAA,MACpC,QAAQ;AAAA,IACV,CAAC;AAED,WAAO;AAAA,MACL,UAAU,IAAI,aAAa,IAAI,MAAM;AAAA,MACrC,eAAe,IAAI;AAAA,MACnB,aAAa,IAAI;AAAA,MACjB,WAAW,IAAI;AAAA,IACjB;AAAA,EACF;AACF;;;ACvBO,IAAM,gBAAN,MAAoB;AAAA,EACzB,YACU,SACA,QACR;AAFQ;AACA;AAAA,EACP;AAAA;AAAA;AAAA;AAAA;AAAA,EAMH,MAAM,OAAO,SAAqD;AAChE,UAAM,MAAM,MAAM,QAef,KAAK,SAAS,YAAY,QAAQ,eAAe;AAAA,MAClD,QAAQ;AAAA,MACR,MAAM;AAAA,QACJ,QAAQ,QAAQ;AAAA,QAChB,UAAU,QAAQ,YAAY;AAAA,QAC9B,WAAW,QAAQ;AAAA,QACnB,UAAU,QAAQ,WACd;AAAA,UACE,MAAM,QAAQ,SAAS;AAAA,UACvB,KAAK,QAAQ,SAAS;AAAA,UACtB,KAAK,QAAQ,SAAS;AAAA,QACxB,IACA;AAAA,QACJ,SAAS,QAAQ,UACb;AAAA,UACE,aAAa,QAAQ,QAAQ;AAAA,UAC7B,KAAK,QAAQ,QAAQ;AAAA,QACvB,IACA;AAAA,QACJ,sBAAsB,QAAQ;AAAA,MAChC;AAAA,IACF,CAAC;AAED,WAAO;AAAA,MACL,UAAU,IAAI;AAAA,MACd,QAAQ,IAAI;AAAA,MACZ,QAAQ,IAAI;AAAA,MACZ,UAAU,IAAI;AAAA,MACd,cAAc,IAAI;AAAA,MAClB,WAAW,IAAI;AAAA,MACf,eAAe,IAAI;AAAA,MACnB,MAAM,IAAI,OACN;AAAA,QACE,KAAK,IAAI,KAAK;AAAA,QACd,KAAK,IAAI,KAAK;AAAA,QACd,UAAU,IAAI,KAAK;AAAA,QACnB,SAAS,IAAI,KAAK;AAAA,QAClB,UAAU,IAAI,KAAK;AAAA,MACrB,IACA;AAAA,IACN;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,IACJ,eACA,UAC6B;AAC7B,UAAM,MAAM,MAAM;AAAA,MAChB,KAAK;AAAA,MACL,YAAY,QAAQ;AAAA,MACpB;AAAA,IACF;AAEA,WAAO,gBAAgB,GAAG;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OACJ,eACA,UAC6B;AAC7B,UAAM,MAAM,MAAM;AAAA,MAChB,KAAK;AAAA,MACL,YAAY,QAAQ;AAAA,MACpB;AAAA,MACA,EAAE,QAAQ,OAAO;AAAA,IACnB;AAEA,WAAO,gBAAgB,GAAG;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,KACJ,eACA,SAC+B;AAC/B,UAAM,SAAS,IAAI,gBAAgB;AACnC,QAAI,SAAS,UAAU,OAAW,QAAO,IAAI,SAAS,OAAO,QAAQ,KAAK,CAAC;AAC3E,QAAI,SAAS,WAAW;AACtB,aAAO,IAAI,UAAU,OAAO,QAAQ,MAAM,CAAC;AAE7C,UAAM,QAAQ,OAAO,SAAS;AAC9B,UAAM,OAAO,QAAQ,YAAY,KAAK,KAAK;AAE3C,UAAM,MAAM,MAAM;AAAA,MAChB,KAAK;AAAA,MACL;AAAA,MACA;AAAA,IACF;AAEA,WAAO,IAAI,IAAI,eAAe;AAAA,EAChC;AACF;AAoBA,SAAS,gBAAgB,KAA0C;AACjE,SAAO;AAAA,IACL,UAAU,IAAI;AAAA,IACd,QAAQ,IAAI;AAAA,IACZ,QAAQ,IAAI;AAAA,IACZ,UAAU,IAAI;AAAA,IACd,cAAc,IAAI;AAAA,IAClB,cAAc,IAAI;AAAA,IAClB,aAAa,IAAI;AAAA,IACjB,WAAW,IAAI;AAAA,IACf,uBAAuB,IAAI;AAAA,IAC3B,mBAAmB,IAAI;AAAA,IACvB,eAAe,IAAI;AAAA,IACnB,WAAW,IAAI;AAAA,IACf,WAAW,IAAI;AAAA,EACjB;AACF;;;ACtKO,IAAM,iBAAN,MAAqB;AAAA,EAC1B,YACU,SACA,QACR;AAFQ;AACA;AAAA,EACP;AAAA;AAAA;AAAA;AAAA,EAKH,MAAM,OAAO,SAAmD;AAC9D,UAAM,MAAM,MAAM,QAQf,KAAK,SAAS,aAAa,QAAQ,eAAe;AAAA,MACnD,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,0BAA0B;AAAA;AAAA,MAC5B;AAAA,MACA,MAAM;AAAA,QACJ,QAAQ,QAAQ;AAAA,QAChB,UAAU,QAAQ,YAAY;AAAA,QAC9B,WAAW,QAAQ;AAAA,QACnB,UAAU;AAAA,UACR,MAAM,QAAQ,SAAS;AAAA,UACvB,KAAK,QAAQ,SAAS,OAAO;AAAA,UAC7B,SAAS,QAAQ,SAAS,WAAW;AAAA,QACvC;AAAA,QACA,SAAS;AAAA,UACP,aAAa,QAAQ,QAAQ;AAAA,UAC7B,UAAU,QAAQ,QAAQ;AAAA,UAC1B,YAAY,QAAQ,QAAQ;AAAA,UAC5B,oBAAoB,QAAQ,QAAQ;AAAA,UACpC,eAAe,QAAQ,QAAQ;AAAA,UAC/B,UAAU,QAAQ,QAAQ;AAAA,QAC5B;AAAA,MACF;AAAA,IACF,CAAC;AAED,WAAO;AAAA,MACL,eAAe,IAAI;AAAA,MACnB,QAAQ,IAAI;AAAA,MACZ,UAAU,IAAI;AAAA,MACd,gBAAgB,IAAI;AAAA,MACpB,QAAQ,IAAI;AAAA,MACZ,cAAc,IAAI;AAAA,MAClB,kBAAkB,IAAI;AAAA,IACxB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAAa,SAAyD;AAC1E,UAAM,MAAM,MAAM,QAQf,KAAK,SAAS,aAAa,KAAK,QAAQ;AAAA,MACzC,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,0BAA0B,QAAQ;AAAA,MACpC;AAAA,MACA,MAAM;AAAA,QACJ,QAAQ,QAAQ;AAAA,QAChB,eAAe,QAAQ;AAAA,QACvB,cAAc,QAAQ,eAAe;AAAA,QACrC,kBAAkB,QAAQ,mBAAmB;AAAA,QAC7C,UAAU,QAAQ,YAAY;AAAA,QAC9B,WAAW,QAAQ;AAAA,QACnB,WAAW,QAAQ;AAAA,MACrB;AAAA,IACF,CAAC;AAED,WAAO;AAAA,MACL,eAAe,IAAI;AAAA,MACnB,QAAQ,IAAI;AAAA,MACZ,UAAU,IAAI;AAAA,MACd,gBAAgB,IAAI;AAAA,MACpB,QAAQ,IAAI;AAAA,MACZ,cAAc,IAAI;AAAA,MAClB,kBAAkB,IAAI;AAAA,IACxB;AAAA,EACF;AACF;;;AC5FO,IAAM,iBAAN,MAAqB;AAAA,EAC1B,YAAoB,QAAiB;AAAjB;AAAA,EAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUtC,MAAM,OACJ,MACA,WACA,YAAY,KACW;AACvB,QAAI,CAAC,KAAK,QAAQ;AAChB,YAAM,IAAI,aAAa,KAAK,+BAA+B;AAAA,IAC7D;AAGA,UAAM,QAAgC,CAAC;AACvC,eAAW,QAAQ,UAAU,MAAM,GAAG,GAAG;AACvC,YAAM,CAACA,MAAK,GAAG,GAAG,IAAI,KAAK,MAAM,GAAG;AACpC,UAAIA,QAAO,IAAI,SAAS,GAAG;AACzB,cAAMA,IAAG,IAAI,IAAI,KAAK,GAAG;AAAA,MAC3B;AAAA,IACF;AAEA,UAAM,YAAY,MAAM,GAAG;AAC3B,UAAM,MAAM,MAAM,IAAI;AAEtB,QAAI,CAAC,aAAa,CAAC,KAAK;AACtB,YAAM,IAAI,aAAa,KAAK,kCAAkC;AAAA,IAChE;AAGA,UAAM,KAAK,SAAS,WAAW,EAAE;AACjC,UAAM,MAAM,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AACxC,QAAI,KAAK,IAAI,MAAM,EAAE,IAAI,WAAW;AAClC,YAAM,IAAI,aAAa,KAAK,2BAA2B;AAAA,IACzD;AAGA,UAAM,UAAU,GAAG,SAAS,IAAI,IAAI;AACpC,UAAM,UAAU,IAAI,YAAY;AAChC,UAAM,MAAM,MAAM,OAAO,OAAO;AAAA,MAC9B;AAAA,MACA,QAAQ,OAAO,KAAK,MAAM;AAAA,MAC1B,EAAE,MAAM,QAAQ,MAAM,UAAU;AAAA,MAChC;AAAA,MACA,CAAC,MAAM;AAAA,IACT;AAEA,UAAM,iBAAiB,MAAM,OAAO,OAAO;AAAA,MACzC;AAAA,MACA;AAAA,MACA,QAAQ,OAAO,OAAO;AAAA,IACxB;AAEA,UAAM,WAAW,MAAM,KAAK,IAAI,WAAW,cAAc,CAAC,EACvD,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,EAC1C,KAAK,EAAE;AAGV,QAAI,SAAS,WAAW,IAAI,UAAU,CAAC,gBAAgB,UAAU,GAAG,GAAG;AACrE,YAAM,IAAI,aAAa,KAAK,2BAA2B;AAAA,IACzD;AAEA,WAAO,KAAK,MAAM,IAAI;AAAA,EACxB;AACF;AAGA,SAAS,gBAAgB,GAAW,GAAoB;AACtD,MAAI,EAAE,WAAW,EAAE,OAAQ,QAAO;AAClC,MAAI,SAAS;AACb,WAAS,IAAI,GAAG,IAAI,EAAE,QAAQ,KAAK;AACjC,cAAU,EAAE,WAAW,CAAC,IAAI,EAAE,WAAW,CAAC;AAAA,EAC5C;AACA,SAAO,WAAW;AACpB;;;AC5EO,IAAM,QAAN,MAAY;AAAA,EAmBjB,YAAY,QAAqB;AAC/B,QAAI,CAAC,OAAO,QAAQ;AAClB,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AACA,SAAK,SAAS,OAAO;AACrB,SAAK,UAAU,eAAe,OAAO,QAAQ,OAAO,OAAO;AAC3D,SAAK,YAAY,IAAI,gBAAgB,KAAK,SAAS,KAAK,MAAM;AAC9D,SAAK,YAAY,IAAI,eAAe,KAAK,SAAS,KAAK,MAAM;AAC7D,SAAK,UAAU,IAAI,cAAc,KAAK,SAAS,KAAK,MAAM;AAC1D,SAAK,WAAW,IAAI,cAAc,KAAK,SAAS,KAAK,MAAM;AAC3D,SAAK,WAAW,IAAI,eAAe;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SAAS,SAAmD;AAChE,WAAO,KAAK,UAAU,OAAO,OAAO;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QAAQ,eAAuB,UAAmB;AACtD,WAAO,KAAK,SAAS,IAAI,eAAe,QAAQ;AAAA,EAClD;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,YAAqB;AACvB,WAAO,KAAK,OAAO,WAAW,aAAa;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,MAAc;AAChB,WAAO,KAAK;AAAA,EACd;AACF;","names":["key"]}
package/package.json CHANGED
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "@tallion/sdk",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Tallion SDK — AI agent spend control for developers",
5
- "main": "./dist/index.cjs",
6
- "module": "./dist/index.js",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
7
  "types": "./dist/index.d.ts",
8
8
  "exports": {
9
9
  ".": {
10
10
  "types": "./dist/index.d.ts",
11
- "import": "./dist/index.js",
12
- "require": "./dist/index.cjs"
11
+ "import": "./dist/index.mjs",
12
+ "require": "./dist/index.js"
13
13
  }
14
14
  },
15
15
  "files": [