@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 +86 -1
- package/dist/index.d.ts +86 -1
- package/dist/index.js +114 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +113 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
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":"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","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,
|
package/dist/index.mjs.map
CHANGED
|
@@ -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":"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","names":["key"]}
|
package/package.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tallion/sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Tallion SDK — AI agent spend control for developers",
|
|
5
|
-
"main": "./dist/index.
|
|
6
|
-
"module": "./dist/index.
|
|
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.
|
|
12
|
-
"require": "./dist/index.
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.js"
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
15
|
"files": [
|