@tallion/sdk 0.1.2 → 0.1.3

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;
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;
package/dist/index.js CHANGED
@@ -115,6 +115,12 @@ var AuthorizeModule = class {
115
115
  max_per_day: options.suggestedLimits.maxPerDay,
116
116
  max_per_month: options.suggestedLimits.maxPerMonth,
117
117
  require_approval_above: options.suggestedLimits.requireApprovalAbove
118
+ } : void 0,
119
+ purchase_context: options.purchaseContext ? {
120
+ amount: options.purchaseContext.amount,
121
+ description: options.purchaseContext.description,
122
+ merchant: options.purchaseContext.merchant,
123
+ reference: options.purchaseContext.reference
118
124
  } : void 0
119
125
  }
120
126
  });
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/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 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 { 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"]}
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
  });
@@ -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/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 { 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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tallion/sdk",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Tallion SDK — AI agent spend control for developers",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",