@closeloop/sdk 0.1.0 → 0.1.2

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/README.md CHANGED
@@ -213,8 +213,8 @@ app.post("/webhook", (req, res) => {
213
213
 
214
214
  // Type-safe event handling
215
215
  if (client.webhooks.isPaymentSuccess(event)) {
216
- const { creditAmount, payerAddress, planId } = event.data
217
- console.log(`${payerAddress} purchased ${creditAmount} credits`)
216
+ const { type, walletAddress, planId, amount } = event.data
217
+ console.log(`${walletAddress} purchased plan ${planId} for $${amount} (${type})`)
218
218
  }
219
219
 
220
220
  if (client.webhooks.isCreditsLow(event)) {
@@ -568,9 +568,9 @@ interface WebhookEvent<T = WebhookPayload> {
568
568
  */
569
569
  interface PaymentSuccessPayload {
570
570
  /**
571
- * Transaction ID
571
+ * Access type of the plan (API, CREDIT, DISCORD, etc.)
572
572
  */
573
- transactionId: string;
573
+ type: string;
574
574
  /**
575
575
  * Plan ID that was purchased
576
576
  */
@@ -584,25 +584,17 @@ interface PaymentSuccessPayload {
584
584
  */
585
585
  amount: number;
586
586
  /**
587
- * Number of API requests (for API access type)
588
- */
589
- requests: number | null;
590
- /**
591
- * Number of credits (for CREDIT access type)
592
- */
593
- creditAmount: number | null;
594
- /**
595
- * Blockchain transaction hash
587
+ * Wallet address of the payer
596
588
  */
597
- transactionHash: string;
589
+ walletAddress: string;
598
590
  /**
599
- * Wallet address of the payer
591
+ * Transaction ID
600
592
  */
601
- payerAddress: string;
593
+ transactionId: string;
602
594
  /**
603
- * Access type of the plan
595
+ * Allow additional properties for extensibility
604
596
  */
605
- accessType: string;
597
+ [key: string]: unknown;
606
598
  }
607
599
  /**
608
600
  * Payload for credits.low events
@@ -687,8 +679,8 @@ declare class Webhooks {
687
679
  * })
688
680
  *
689
681
  * if (client.webhooks.isPaymentSuccess(event)) {
690
- * const { creditAmount, payerAddress } = event.data
691
- * // Handle credit purchase
682
+ * const { type, walletAddress, planId, amount } = event.data
683
+ * // Handle payment success
692
684
  * }
693
685
  *
694
686
  * res.json({ received: true })
@@ -727,7 +719,7 @@ declare class Webhooks {
727
719
  * ```typescript
728
720
  * if (client.webhooks.isPaymentSuccess(event)) {
729
721
  * // TypeScript knows event.data is PaymentSuccessPayload
730
- * console.log(event.data.creditAmount)
722
+ * console.log(event.data.planId, event.data.walletAddress)
731
723
  * }
732
724
  * ```
733
725
  */
@@ -568,9 +568,9 @@ interface WebhookEvent<T = WebhookPayload> {
568
568
  */
569
569
  interface PaymentSuccessPayload {
570
570
  /**
571
- * Transaction ID
571
+ * Access type of the plan (API, CREDIT, DISCORD, etc.)
572
572
  */
573
- transactionId: string;
573
+ type: string;
574
574
  /**
575
575
  * Plan ID that was purchased
576
576
  */
@@ -584,25 +584,17 @@ interface PaymentSuccessPayload {
584
584
  */
585
585
  amount: number;
586
586
  /**
587
- * Number of API requests (for API access type)
588
- */
589
- requests: number | null;
590
- /**
591
- * Number of credits (for CREDIT access type)
592
- */
593
- creditAmount: number | null;
594
- /**
595
- * Blockchain transaction hash
587
+ * Wallet address of the payer
596
588
  */
597
- transactionHash: string;
589
+ walletAddress: string;
598
590
  /**
599
- * Wallet address of the payer
591
+ * Transaction ID
600
592
  */
601
- payerAddress: string;
593
+ transactionId: string;
602
594
  /**
603
- * Access type of the plan
595
+ * Allow additional properties for extensibility
604
596
  */
605
- accessType: string;
597
+ [key: string]: unknown;
606
598
  }
607
599
  /**
608
600
  * Payload for credits.low events
@@ -687,8 +679,8 @@ declare class Webhooks {
687
679
  * })
688
680
  *
689
681
  * if (client.webhooks.isPaymentSuccess(event)) {
690
- * const { creditAmount, payerAddress } = event.data
691
- * // Handle credit purchase
682
+ * const { type, walletAddress, planId, amount } = event.data
683
+ * // Handle payment success
692
684
  * }
693
685
  *
694
686
  * res.json({ received: true })
@@ -727,7 +719,7 @@ declare class Webhooks {
727
719
  * ```typescript
728
720
  * if (client.webhooks.isPaymentSuccess(event)) {
729
721
  * // TypeScript knows event.data is PaymentSuccessPayload
730
- * console.log(event.data.creditAmount)
722
+ * console.log(event.data.planId, event.data.walletAddress)
731
723
  * }
732
724
  * ```
733
725
  */
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- export { A as AuthenticationError, B as Balances, k as BatchConsumeParams, l as BatchConsumeResponse, C as CloseLoop, c as CloseLoopError, a as CloseLoopOptions, i as ConsumeCreditsParams, j as ConsumeCreditsResponse, m as CreditBalance, r as CreditStats, o as CreditTransaction, b as Credits, d as CreditsExpiredError, v as CreditsExpiredPayload, u as CreditsLowPayload, G as GetBalanceParams, I as InsufficientCreditsError, L as ListBalancesParams, n as ListBalancesResponse, p as ListTransactionsParams, q as ListTransactionsResponse, N as NetworkError, e as NotFoundError, P as PaymentSuccessPayload, R as RateLimitError, f as ValidationError, g as VerifyCreditsParams, h as VerifyCreditsResponse, V as VerifyWebhookParams, t as WebhookEvent, s as WebhookEventType, w as WebhookPayload, W as Webhooks } from './errors-B0i1OvBd.mjs';
1
+ export { A as AuthenticationError, B as Balances, k as BatchConsumeParams, l as BatchConsumeResponse, C as CloseLoop, c as CloseLoopError, a as CloseLoopOptions, i as ConsumeCreditsParams, j as ConsumeCreditsResponse, m as CreditBalance, r as CreditStats, o as CreditTransaction, b as Credits, d as CreditsExpiredError, v as CreditsExpiredPayload, u as CreditsLowPayload, G as GetBalanceParams, I as InsufficientCreditsError, L as ListBalancesParams, n as ListBalancesResponse, p as ListTransactionsParams, q as ListTransactionsResponse, N as NetworkError, e as NotFoundError, P as PaymentSuccessPayload, R as RateLimitError, f as ValidationError, g as VerifyCreditsParams, h as VerifyCreditsResponse, V as VerifyWebhookParams, t as WebhookEvent, s as WebhookEventType, w as WebhookPayload, W as Webhooks } from './errors-CmMqVxNU.mjs';
2
2
 
3
3
  /**
4
4
  * Generic schema interface for validation
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { A as AuthenticationError, B as Balances, k as BatchConsumeParams, l as BatchConsumeResponse, C as CloseLoop, c as CloseLoopError, a as CloseLoopOptions, i as ConsumeCreditsParams, j as ConsumeCreditsResponse, m as CreditBalance, r as CreditStats, o as CreditTransaction, b as Credits, d as CreditsExpiredError, v as CreditsExpiredPayload, u as CreditsLowPayload, G as GetBalanceParams, I as InsufficientCreditsError, L as ListBalancesParams, n as ListBalancesResponse, p as ListTransactionsParams, q as ListTransactionsResponse, N as NetworkError, e as NotFoundError, P as PaymentSuccessPayload, R as RateLimitError, f as ValidationError, g as VerifyCreditsParams, h as VerifyCreditsResponse, V as VerifyWebhookParams, t as WebhookEvent, s as WebhookEventType, w as WebhookPayload, W as Webhooks } from './errors-B0i1OvBd.js';
1
+ export { A as AuthenticationError, B as Balances, k as BatchConsumeParams, l as BatchConsumeResponse, C as CloseLoop, c as CloseLoopError, a as CloseLoopOptions, i as ConsumeCreditsParams, j as ConsumeCreditsResponse, m as CreditBalance, r as CreditStats, o as CreditTransaction, b as Credits, d as CreditsExpiredError, v as CreditsExpiredPayload, u as CreditsLowPayload, G as GetBalanceParams, I as InsufficientCreditsError, L as ListBalancesParams, n as ListBalancesResponse, p as ListTransactionsParams, q as ListTransactionsResponse, N as NetworkError, e as NotFoundError, P as PaymentSuccessPayload, R as RateLimitError, f as ValidationError, g as VerifyCreditsParams, h as VerifyCreditsResponse, V as VerifyWebhookParams, t as WebhookEvent, s as WebhookEventType, w as WebhookPayload, W as Webhooks } from './errors-CmMqVxNU.js';
2
2
 
3
3
  /**
4
4
  * Generic schema interface for validation
package/dist/index.js CHANGED
@@ -118,16 +118,13 @@ var webhookEventSchema = import_zod.z.object({
118
118
  data: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown())
119
119
  });
120
120
  var paymentSuccessPayloadSchema = import_zod.z.object({
121
- transactionId: import_zod.z.string(),
121
+ type: import_zod.z.string(),
122
122
  planId: import_zod.z.string(),
123
123
  planName: import_zod.z.string(),
124
124
  amount: import_zod.z.number(),
125
- requests: import_zod.z.number().nullable(),
126
- creditAmount: import_zod.z.number().nullable(),
127
- transactionHash: import_zod.z.string(),
128
- payerAddress: import_zod.z.string(),
129
- accessType: import_zod.z.string()
130
- });
125
+ walletAddress: import_zod.z.string(),
126
+ transactionId: import_zod.z.string()
127
+ }).loose();
131
128
  var creditsLowPayloadSchema = import_zod.z.object({
132
129
  walletAddress: import_zod.z.string(),
133
130
  planId: import_zod.z.string(),
@@ -593,8 +590,8 @@ var Webhooks = class {
593
590
  * })
594
591
  *
595
592
  * if (client.webhooks.isPaymentSuccess(event)) {
596
- * const { creditAmount, payerAddress } = event.data
597
- * // Handle credit purchase
593
+ * const { type, walletAddress, planId, amount } = event.data
594
+ * // Handle payment success
598
595
  * }
599
596
  *
600
597
  * res.json({ received: true })
@@ -639,7 +636,7 @@ var Webhooks = class {
639
636
  * ```typescript
640
637
  * if (client.webhooks.isPaymentSuccess(event)) {
641
638
  * // TypeScript knows event.data is PaymentSuccessPayload
642
- * console.log(event.data.creditAmount)
639
+ * console.log(event.data.planId, event.data.walletAddress)
643
640
  * }
644
641
  * ```
645
642
  */
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/constants.ts","../src/schemas/validation.ts","../src/utils/errors.ts","../src/utils/validation.ts","../src/resources/balances.ts","../src/resources/credits.ts","../src/utils/crypto.ts","../src/resources/webhooks.ts","../src/utils/http.ts","../src/client.ts"],"sourcesContent":["// Main client\nexport { CloseLoop } from \"./client\"\nexport type { CloseLoopOptions } from \"./client\"\n\n// Resources\nexport { Credits } from \"./resources/credits\"\nexport { Balances } from \"./resources/balances\"\nexport { Webhooks } from \"./resources/webhooks\"\nexport type { VerifyWebhookParams } from \"./resources/webhooks\"\n\n// Errors\nexport {\n CloseLoopError,\n InsufficientCreditsError,\n CreditsExpiredError,\n AuthenticationError,\n RateLimitError,\n NetworkError,\n NotFoundError,\n ValidationError\n} from \"./utils/errors\"\n\n// Utilities\nexport { validateInput } from \"./utils/validation\"\n\n// Credit types\nexport type {\n VerifyCreditsParams,\n VerifyCreditsResponse,\n ConsumeCreditsParams,\n ConsumeCreditsResponse,\n BatchConsumeParams,\n BatchConsumeResponse\n} from \"./types/credits\"\n\n// Balance types\nexport type {\n CreditBalance,\n GetBalanceParams,\n ListBalancesParams,\n ListBalancesResponse,\n CreditTransaction,\n ListTransactionsParams,\n ListTransactionsResponse,\n CreditStats\n} from \"./types/balances\"\n\n// Webhook types\nexport type {\n WebhookEventType,\n WebhookEvent,\n PaymentSuccessPayload,\n CreditsLowPayload,\n CreditsExpiredPayload,\n WebhookPayload\n} from \"./types/webhooks\"\n","export const DEFAULT_BASE_URL = \"https://closeloop.app\"\nexport const DEFAULT_TIMEOUT = 30000 // 30 seconds\nexport const SDK_VERSION = \"0.1.0\"\nexport const USER_AGENT = `closeloop-node/${SDK_VERSION}`\n","import { z } from \"zod\"\n\n/**\n * Ethereum wallet address validation (0x + 40 hex chars)\n */\nexport const walletAddressSchema = z\n .string()\n .regex(/^0x[a-fA-F0-9]{40}$/, \"Invalid Ethereum wallet address\")\n\n/**\n * Plan ID validation (non-empty string with reasonable length)\n */\nexport const planIdSchema = z\n .string()\n .min(1, \"Plan ID is required\")\n .max(100, \"Plan ID too long\")\n\n/**\n * Balance ID validation\n */\nexport const balanceIdSchema = z\n .string()\n .min(1, \"Balance ID is required\")\n .max(100, \"Balance ID too long\")\n\n/**\n * Credit amount validation (positive integer with reasonable max)\n */\nexport const creditAmountSchema = z\n .number()\n .int(\"Amount must be an integer\")\n .positive(\"Amount must be positive\")\n .max(1_000_000_000, \"Amount exceeds maximum\")\n\n/**\n * Pagination limit validation\n */\nexport const paginationLimitSchema = z\n .number()\n .int()\n .positive()\n .max(100, \"Limit cannot exceed 100\")\n\n/**\n * Transaction type validation\n */\nexport const transactionTypeSchema = z.enum([\n \"PURCHASE\",\n \"CONSUMPTION\",\n \"REFUND\",\n \"EXPIRATION\"\n])\n\n/**\n * Dangerous prototype pollution keys to skip\n */\nconst DANGEROUS_KEYS = new Set([\"__proto__\", \"constructor\", \"prototype\"])\n\n/**\n * Sanitize metadata object to prevent prototype pollution\n * Creates a clean object with no prototype chain\n */\nexport function sanitizeMetadata(\n metadata: Record<string, unknown> | undefined\n): Record<string, unknown> | undefined {\n if (!metadata) return undefined\n\n // Create a clean object with null prototype to prevent prototype pollution\n const clean = Object.create(null) as Record<string, unknown>\n\n for (const [key, value] of Object.entries(metadata)) {\n // Skip dangerous prototype pollution keys\n if (DANGEROUS_KEYS.has(key)) continue\n\n // Copy all JSON-serializable values\n clean[key] = value\n }\n\n return Object.freeze(clean)\n}\n\n// ============================================================================\n// Credit Schemas\n// ============================================================================\n\nexport const verifyCreditsSchema = z.object({\n walletAddress: walletAddressSchema,\n planId: planIdSchema,\n amount: creditAmountSchema\n})\n\nexport const consumeCreditsSchema = z.object({\n walletAddress: walletAddressSchema,\n planId: planIdSchema,\n amount: creditAmountSchema,\n consumedBy: z.string().max(100).optional(),\n metadata: z.record(z.string(), z.unknown()).optional(),\n idempotencyKey: z.string().max(100).optional()\n})\n\nexport const batchConsumeSchema = z.object({\n operations: z\n .array(\n z.object({\n walletAddress: walletAddressSchema,\n planId: planIdSchema,\n amount: creditAmountSchema,\n consumedBy: z.string().max(100).optional(),\n metadata: z.record(z.string(), z.unknown()).optional()\n })\n )\n .min(1, \"At least one operation required\")\n .max(100, \"Maximum 100 operations per batch\"),\n atomic: z.boolean().optional()\n})\n\n// ============================================================================\n// Balance Schemas\n// ============================================================================\n\nexport const getBalanceSchema = z.object({\n walletAddress: walletAddressSchema,\n planId: planIdSchema\n})\n\nexport const listBalancesSchema = z.object({\n walletAddress: walletAddressSchema,\n activeOnly: z.boolean().optional(),\n limit: paginationLimitSchema.optional(),\n cursor: z.string().max(200).optional()\n})\n\nexport const listTransactionsSchema = z.object({\n balanceId: balanceIdSchema,\n type: transactionTypeSchema.optional(),\n limit: paginationLimitSchema.optional(),\n cursor: z.string().max(200).optional()\n})\n\n// ============================================================================\n// Webhook Schemas\n// ============================================================================\n\nexport const webhookEventTypeSchema = z.enum([\n \"payment.success\",\n \"credits.low\",\n \"credits.expired\"\n])\n\nexport const webhookEventSchema = z.object({\n type: webhookEventTypeSchema,\n id: z.string().min(1),\n createdAt: z.string(),\n data: z.record(z.string(), z.unknown())\n})\n\nexport const paymentSuccessPayloadSchema = z.object({\n transactionId: z.string(),\n planId: z.string(),\n planName: z.string(),\n amount: z.number(),\n requests: z.number().nullable(),\n creditAmount: z.number().nullable(),\n transactionHash: z.string(),\n payerAddress: z.string(),\n accessType: z.string()\n})\n\nexport const creditsLowPayloadSchema = z.object({\n walletAddress: z.string(),\n planId: z.string(),\n remainingCredits: z.number(),\n threshold: z.number()\n})\n\nexport const creditsExpiredPayloadSchema = z.object({\n walletAddress: z.string(),\n planId: z.string(),\n expiredCredits: z.number(),\n expiresAt: z.string()\n})\n","/**\n * Base error class for all CloseLoop SDK errors\n */\nexport class CloseLoopError extends Error {\n constructor(\n message: string,\n public code: string,\n public statusCode?: number,\n public details?: Record<string, unknown>\n ) {\n super(message)\n this.name = \"CloseLoopError\"\n }\n}\n\n/**\n * Thrown when a user doesn't have enough credits for an operation\n */\nexport class InsufficientCreditsError extends CloseLoopError {\n constructor(\n public remainingCredits: number,\n public requiredCredits: number\n ) {\n super(\n `Insufficient credits: ${remainingCredits} available, ${requiredCredits} required`,\n \"INSUFFICIENT_CREDITS\",\n 402\n )\n this.name = \"InsufficientCreditsError\"\n }\n}\n\n/**\n * Thrown when credits have expired\n */\nexport class CreditsExpiredError extends CloseLoopError {\n constructor(public expiresAt: Date) {\n super(\n `Credits expired at ${expiresAt.toISOString()}`,\n \"CREDITS_EXPIRED\",\n 410\n )\n this.name = \"CreditsExpiredError\"\n }\n}\n\n/**\n * Thrown when authentication fails (invalid API key)\n */\nexport class AuthenticationError extends CloseLoopError {\n constructor(message = \"Invalid API key\") {\n super(message, \"AUTHENTICATION_ERROR\", 401)\n this.name = \"AuthenticationError\"\n }\n}\n\n/**\n * Thrown when rate limit is exceeded\n */\nexport class RateLimitError extends CloseLoopError {\n constructor(public retryAfter?: number) {\n super(\"Rate limit exceeded\", \"RATE_LIMIT\", 429)\n this.name = \"RateLimitError\"\n }\n}\n\n/**\n * Thrown when a network error occurs\n */\nexport class NetworkError extends CloseLoopError {\n constructor(\n message: string,\n public cause?: Error\n ) {\n super(message, \"NETWORK_ERROR\")\n this.name = \"NetworkError\"\n }\n}\n\n/**\n * Thrown when a resource is not found\n */\nexport class NotFoundError extends CloseLoopError {\n constructor(resource: string) {\n super(`${resource} not found`, \"NOT_FOUND\", 404)\n this.name = \"NotFoundError\"\n }\n}\n\n/**\n * Thrown when input validation fails\n */\nexport class ValidationError extends CloseLoopError {\n constructor(\n message: string,\n public field?: string\n ) {\n super(message, \"VALIDATION_ERROR\", 400)\n this.name = \"ValidationError\"\n }\n}\n","import { CloseLoopError } from \"./errors\"\n\n/**\n * Generic schema interface for validation\n */\nexport interface ValidationSchema<T> {\n safeParse: (data: unknown) => {\n success: boolean\n data?: T\n error?: { message: string }\n }\n}\n\n/**\n * Validate input against a Zod schema\n * Throws CloseLoopError if validation fails\n *\n * @param schema - Zod schema to validate against\n * @param data - Data to validate\n * @returns Validated and typed data\n * @throws {CloseLoopError} When validation fails\n */\nexport function validateInput<T>(\n schema: ValidationSchema<T>,\n data: unknown\n): T {\n const result = schema.safeParse(data)\n\n if (!result.success) {\n throw new CloseLoopError(\n `Validation error: ${result.error?.message || \"Invalid input\"}`,\n \"VALIDATION_ERROR\",\n 400\n )\n }\n\n return result.data as T\n}\n\n/**\n * Validate a single value against a Zod schema\n * Returns a boolean without throwing\n */\nexport function isValid<T>(\n schema: ValidationSchema<T>,\n data: unknown\n): data is T {\n return schema.safeParse(data).success\n}\n","import {\n getBalanceSchema,\n listBalancesSchema,\n listTransactionsSchema,\n walletAddressSchema\n} from \"../schemas/validation\"\nimport type {\n CreditBalance,\n CreditStats,\n GetBalanceParams,\n ListBalancesParams,\n ListBalancesResponse,\n ListTransactionsParams,\n ListTransactionsResponse\n} from \"../types/balances\"\nimport { NotFoundError } from \"../utils/errors\"\nimport { HttpClient } from \"../utils/http\"\nimport { validateInput } from \"../utils/validation\"\n\n// API Endpoints\nconst ENDPOINTS = {\n BALANCE: \"/api/credit/balance\",\n BALANCES: \"/api/credit/balances\",\n STATS: \"/api/credit/stats\"\n} as const\n\n/**\n * Resource for querying credit balances and transaction history\n */\nexport class Balances {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Get a specific credit balance for a wallet and plan.\n *\n * @example\n * ```typescript\n * const balance = await client.balances.get({\n * walletAddress: \"0x1234...\",\n * planId: \"plan_abc123\"\n * })\n *\n * if (balance) {\n * console.log(`Credits: ${balance.remainingCredits}/${balance.totalCredits}`)\n * }\n * ```\n *\n * @returns The credit balance, or null if not found\n * @throws {CloseLoopError} When input validation fails\n */\n async get(params: GetBalanceParams): Promise<CreditBalance | null> {\n const validated = validateInput(getBalanceSchema, params)\n\n const query = this.buildQueryString({\n wallet: validated.walletAddress,\n plan: validated.planId\n })\n\n try {\n return await this.http.request<CreditBalance>({\n method: \"GET\",\n path: `${ENDPOINTS.BALANCE}?${query}`\n })\n } catch (error) {\n if (error instanceof NotFoundError) {\n return null\n }\n throw error\n }\n }\n\n /**\n * List all credit balances for a wallet.\n *\n * @example\n * ```typescript\n * const { balances, nextCursor } = await client.balances.list({\n * walletAddress: \"0x1234...\",\n * activeOnly: true,\n * limit: 10\n * })\n *\n * for (const balance of balances) {\n * console.log(`${balance.planName}: ${balance.remainingCredits} credits`)\n * }\n *\n * // Paginate if needed\n * if (nextCursor) {\n * const nextPage = await client.balances.list({\n * walletAddress: \"0x1234...\",\n * cursor: nextCursor\n * })\n * }\n * ```\n *\n * @throws {CloseLoopError} When input validation fails\n */\n async list(params: ListBalancesParams): Promise<ListBalancesResponse> {\n const validated = validateInput(listBalancesSchema, params)\n\n const query = this.buildQueryString({\n wallet: validated.walletAddress,\n activeOnly: validated.activeOnly,\n limit: validated.limit,\n cursor: validated.cursor\n })\n\n return this.http.request<ListBalancesResponse>({\n method: \"GET\",\n path: `${ENDPOINTS.BALANCES}?${query}`\n })\n }\n\n /**\n * Get transaction history for a balance.\n *\n * @example\n * ```typescript\n * const { transactions } = await client.balances.transactions({\n * balanceId: \"bal_xyz\",\n * type: \"CONSUMPTION\",\n * limit: 50\n * })\n *\n * for (const tx of transactions) {\n * console.log(`${tx.type}: ${tx.amount} - ${tx.description}`)\n * }\n * ```\n *\n * @throws {CloseLoopError} When input validation fails\n */\n async transactions(\n params: ListTransactionsParams\n ): Promise<ListTransactionsResponse> {\n const validated = validateInput(listTransactionsSchema, params)\n\n const query = this.buildQueryString({\n type: validated.type,\n limit: validated.limit,\n cursor: validated.cursor\n })\n\n const basePath = `${ENDPOINTS.BALANCE}/${encodeURIComponent(validated.balanceId)}/transactions`\n const path = query ? `${basePath}?${query}` : basePath\n\n return this.http.request<ListTransactionsResponse>({\n method: \"GET\",\n path\n })\n }\n\n /**\n * Get aggregated stats for a wallet's credits.\n *\n * @example\n * ```typescript\n * const stats = await client.balances.stats(\"0x1234...\")\n * console.log(`Total: ${stats.totalCredits}, Used: ${stats.totalUsed}`)\n * ```\n *\n * @throws {CloseLoopError} When input validation fails\n */\n async stats(walletAddress: string): Promise<CreditStats> {\n // Validate using the shared utility for consistency\n validateInput(walletAddressSchema, walletAddress)\n\n const query = this.buildQueryString({ wallet: walletAddress })\n\n return this.http.request<CreditStats>({\n method: \"GET\",\n path: `${ENDPOINTS.STATS}?${query}`\n })\n }\n\n // ==========================================================================\n // Private Helpers\n // ==========================================================================\n\n /**\n * Build URL query string from params, filtering out undefined values\n */\n private buildQueryString(\n params: Record<string, string | number | boolean | undefined>\n ): string {\n const query = new URLSearchParams()\n\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined) {\n query.set(key, String(value))\n }\n }\n\n return query.toString()\n }\n}\n","import {\n batchConsumeSchema,\n consumeCreditsSchema,\n sanitizeMetadata,\n verifyCreditsSchema\n} from \"../schemas/validation\"\nimport type {\n BatchConsumeParams,\n BatchConsumeResponse,\n ConsumeCreditsParams,\n ConsumeCreditsResponse,\n VerifyCreditsParams,\n VerifyCreditsResponse\n} from \"../types/credits\"\nimport { CreditsExpiredError, InsufficientCreditsError } from \"../utils/errors\"\nimport { HttpClient } from \"../utils/http\"\nimport { validateInput } from \"../utils/validation\"\n\n// API Endpoints\nconst ENDPOINTS = {\n VERIFY: \"/api/credit/verify\",\n CONSUME: \"/api/credit/consume\",\n BATCH_CONSUME: \"/api/credit/consume/batch\"\n} as const\n\n/**\n * Resource for credit verification and consumption operations\n */\nexport class Credits {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Verify if a user has enough credits without consuming them.\n *\n * @example\n * ```typescript\n * const result = await client.credits.verify({\n * walletAddress: \"0x1234...\",\n * planId: \"plan_abc123\",\n * amount: 10\n * })\n *\n * if (result.hasEnoughCredits) {\n * // Proceed with service\n * }\n * ```\n *\n * @throws {CloseLoopError} When input validation fails\n */\n async verify(params: VerifyCreditsParams): Promise<VerifyCreditsResponse> {\n const validated = validateInput(verifyCreditsSchema, params)\n\n return this.http.request<VerifyCreditsResponse>({\n method: \"POST\",\n path: ENDPOINTS.VERIFY,\n body: validated\n })\n }\n\n /**\n * Consume credits from a user's balance.\n *\n * @example\n * ```typescript\n * const result = await client.credits.consume({\n * walletAddress: \"0x1234...\",\n * planId: \"plan_abc123\",\n * amount: 1,\n * consumedBy: \"ai-generation\",\n * metadata: { requestId: \"req_xyz\" }\n * })\n *\n * console.log(`Remaining: ${result.remainingCredits}`)\n * ```\n *\n * @throws {InsufficientCreditsError} When user doesn't have enough credits\n * @throws {CreditsExpiredError} When credits have expired\n * @throws {CloseLoopError} When input validation fails\n */\n async consume(params: ConsumeCreditsParams): Promise<ConsumeCreditsResponse> {\n const validated = validateInput(consumeCreditsSchema, params)\n\n return this.http.request<ConsumeCreditsResponse>({\n method: \"POST\",\n path: ENDPOINTS.CONSUME,\n body: this.buildConsumeBody(validated),\n headers: this.buildIdempotencyHeaders(validated.idempotencyKey)\n })\n }\n\n /**\n * Verify and consume credits in a single atomic operation.\n * This is useful when you want to ensure credits are available\n * before consuming them, without race conditions.\n *\n * @example\n * ```typescript\n * try {\n * const result = await client.credits.verifyAndConsume({\n * walletAddress: \"0x1234...\",\n * planId: \"plan_abc123\",\n * amount: 5,\n * consumedBy: \"batch-processing\"\n * })\n * // Credits were verified and consumed\n * } catch (error) {\n * if (error instanceof InsufficientCreditsError) {\n * // Handle insufficient credits\n * }\n * }\n * ```\n *\n * @throws {InsufficientCreditsError} When user doesn't have enough credits\n * @throws {CreditsExpiredError} When credits have expired\n * @throws {CloseLoopError} When input validation fails\n */\n async verifyAndConsume(\n params: ConsumeCreditsParams\n ): Promise<ConsumeCreditsResponse> {\n const validated = validateInput(consumeCreditsSchema, params)\n\n // First verify\n const verification = await this.http.request<VerifyCreditsResponse>({\n method: \"POST\",\n path: ENDPOINTS.VERIFY,\n body: {\n walletAddress: validated.walletAddress,\n planId: validated.planId,\n amount: validated.amount\n }\n })\n\n this.assertCreditsAvailable(verification, validated.amount)\n\n // Then consume\n return this.http.request<ConsumeCreditsResponse>({\n method: \"POST\",\n path: ENDPOINTS.CONSUME,\n body: this.buildConsumeBody(validated),\n headers: this.buildIdempotencyHeaders(validated.idempotencyKey)\n })\n }\n\n /**\n * Consume credits in batch.\n *\n * @example\n * ```typescript\n * const result = await client.credits.batchConsume({\n * operations: [\n * { walletAddress: \"0x1234...\", planId: \"plan_a\", amount: 1 },\n * { walletAddress: \"0x5678...\", planId: \"plan_b\", amount: 2 }\n * ],\n * atomic: false // Allow partial success\n * })\n *\n * console.log(`Success: ${result.successCount}, Failed: ${result.failedCount}`)\n * ```\n *\n * @throws {CloseLoopError} When input validation fails\n */\n async batchConsume(\n params: BatchConsumeParams\n ): Promise<BatchConsumeResponse> {\n const validated = validateInput(batchConsumeSchema, params)\n\n // Sanitize metadata in each operation\n const sanitizedOperations = validated.operations.map(op => ({\n ...op,\n metadata: sanitizeMetadata(op.metadata)\n }))\n\n return this.http.request<BatchConsumeResponse>({\n method: \"POST\",\n path: ENDPOINTS.BATCH_CONSUME,\n body: {\n operations: sanitizedOperations,\n atomic: validated.atomic\n }\n })\n }\n\n // ==========================================================================\n // Private Helpers\n // ==========================================================================\n\n /**\n * Build consumption request body with sanitized metadata\n */\n private buildConsumeBody(validated: {\n walletAddress: string\n planId: string\n amount: number\n consumedBy?: string\n metadata?: Record<string, unknown>\n }) {\n return {\n walletAddress: validated.walletAddress,\n planId: validated.planId,\n amount: validated.amount,\n consumedBy: validated.consumedBy,\n metadata: sanitizeMetadata(validated.metadata)\n }\n }\n\n /**\n * Build idempotency headers if key is provided\n */\n private buildIdempotencyHeaders(\n idempotencyKey?: string\n ): Record<string, string> {\n if (!idempotencyKey) return {}\n return { \"Idempotency-Key\": idempotencyKey }\n }\n\n /**\n * Assert credits are available, throw typed errors if not\n */\n private assertCreditsAvailable(\n verification: VerifyCreditsResponse,\n requiredAmount: number\n ): void {\n if (!verification.hasEnoughCredits) {\n throw new InsufficientCreditsError(\n verification.remainingCredits,\n requiredAmount\n )\n }\n\n if (verification.expiresAt) {\n const expirationDate = new Date(verification.expiresAt)\n if (expirationDate < new Date()) {\n throw new CreditsExpiredError(expirationDate)\n }\n }\n }\n}\n","import { createHmac, timingSafeEqual } from \"crypto\"\n\n/**\n * Generates an HMAC signature for webhook verification\n */\nexport function generateSignature(payload: string, secret: string): string {\n return createHmac(\"sha256\", secret).update(payload).digest(\"hex\")\n}\n\n/**\n * Verifies that a webhook signature is valid using timing-safe comparison\n */\nexport function verifySignature(\n payload: string,\n signature: string,\n secret: string\n): boolean {\n const expectedSignature = generateSignature(payload, secret)\n\n // Use timing-safe comparison to prevent timing attacks\n if (signature.length !== expectedSignature.length) {\n return false\n }\n\n return timingSafeEqual(Buffer.from(signature), Buffer.from(expectedSignature))\n}\n","import {\n creditsExpiredPayloadSchema,\n creditsLowPayloadSchema,\n paymentSuccessPayloadSchema,\n webhookEventSchema\n} from \"../schemas/validation\"\nimport type {\n CreditsExpiredPayload,\n CreditsLowPayload,\n PaymentSuccessPayload,\n WebhookEvent,\n WebhookPayload\n} from \"../types/webhooks\"\nimport { verifySignature } from \"../utils/crypto\"\nimport { CloseLoopError } from \"../utils/errors\"\n\n/**\n * Parameters for verifying a webhook\n */\nexport interface VerifyWebhookParams {\n /**\n * Raw request body as string or Buffer\n */\n payload: string | Buffer\n\n /**\n * X-CloseLoop-Signature header value\n */\n signature: string\n\n /**\n * Your webhook secret\n */\n secret: string\n}\n\n// Validation error codes\nconst ERROR_CODES = {\n VALIDATION: \"VALIDATION_ERROR\",\n INVALID_SIGNATURE: \"INVALID_SIGNATURE\",\n INVALID_PAYLOAD: \"INVALID_PAYLOAD\"\n} as const\n\n/**\n * Resource for webhook signature verification and event handling\n */\nexport class Webhooks {\n /**\n * Verify a webhook signature and parse the event.\n *\n * @example\n * ```typescript\n * // Express handler\n * app.post(\"/webhook\", (req, res) => {\n * try {\n * const event = client.webhooks.verify({\n * payload: req.body,\n * signature: req.headers[\"x-closeloop-signature\"],\n * secret: process.env.WEBHOOK_SECRET!\n * })\n *\n * if (client.webhooks.isPaymentSuccess(event)) {\n * const { creditAmount, payerAddress } = event.data\n * // Handle credit purchase\n * }\n *\n * res.json({ received: true })\n * } catch (error) {\n * res.status(400).json({ error: \"Invalid signature\" })\n * }\n * })\n * ```\n *\n * @example\n * ```typescript\n * // Next.js App Router\n * export async function POST(request: Request) {\n * const payload = await request.text()\n * const signature = request.headers.get(\"x-closeloop-signature\")!\n *\n * const event = client.webhooks.verify({\n * payload,\n * signature,\n * secret: process.env.WEBHOOK_SECRET!\n * })\n *\n * // Handle event...\n * return Response.json({ received: true })\n * }\n * ```\n *\n * @throws {CloseLoopError} When signature is invalid or payload is malformed\n */\n verify(params: VerifyWebhookParams): WebhookEvent {\n this.validateRequiredParams(params)\n\n const payloadString = this.normalizePayload(params.payload)\n\n this.verifySignatureOrThrow(payloadString, params.signature, params.secret)\n\n const parsed = this.parseJsonOrThrow(payloadString)\n\n return this.validateEventStructure(parsed)\n }\n\n /**\n * Type guard for payment.success events\n * Also validates the payload structure\n *\n * @example\n * ```typescript\n * if (client.webhooks.isPaymentSuccess(event)) {\n * // TypeScript knows event.data is PaymentSuccessPayload\n * console.log(event.data.creditAmount)\n * }\n * ```\n */\n isPaymentSuccess(\n event: WebhookEvent<WebhookPayload>\n ): event is WebhookEvent<PaymentSuccessPayload> {\n return (\n event.type === \"payment.success\" &&\n paymentSuccessPayloadSchema.safeParse(event.data).success\n )\n }\n\n /**\n * Type guard for credits.low events\n * Also validates the payload structure\n *\n * @example\n * ```typescript\n * if (client.webhooks.isCreditsLow(event)) {\n * // TypeScript knows event.data is CreditsLowPayload\n * console.log(`Low balance: ${event.data.remainingCredits}`)\n * }\n * ```\n */\n isCreditsLow(\n event: WebhookEvent<WebhookPayload>\n ): event is WebhookEvent<CreditsLowPayload> {\n return (\n event.type === \"credits.low\" &&\n creditsLowPayloadSchema.safeParse(event.data).success\n )\n }\n\n /**\n * Type guard for credits.expired events\n * Also validates the payload structure\n *\n * @example\n * ```typescript\n * if (client.webhooks.isCreditsExpired(event)) {\n * // TypeScript knows event.data is CreditsExpiredPayload\n * console.log(`Expired: ${event.data.expiredCredits} credits`)\n * }\n * ```\n */\n isCreditsExpired(\n event: WebhookEvent<WebhookPayload>\n ): event is WebhookEvent<CreditsExpiredPayload> {\n return (\n event.type === \"credits.expired\" &&\n creditsExpiredPayloadSchema.safeParse(event.data).success\n )\n }\n\n // ==========================================================================\n // Private Helpers\n // ==========================================================================\n\n /**\n * Validate that all required parameters are present\n */\n private validateRequiredParams(params: VerifyWebhookParams): void {\n if (!params.payload) {\n throw new CloseLoopError(\n \"Webhook payload is required\",\n ERROR_CODES.VALIDATION,\n 400\n )\n }\n\n if (!params.signature) {\n throw new CloseLoopError(\n \"Webhook signature is required\",\n ERROR_CODES.VALIDATION,\n 400\n )\n }\n\n if (!params.secret) {\n throw new CloseLoopError(\n \"Webhook secret is required\",\n ERROR_CODES.VALIDATION,\n 400\n )\n }\n }\n\n /**\n * Convert payload to string regardless of input type\n */\n private normalizePayload(payload: string | Buffer): string {\n return typeof payload === \"string\" ? payload : payload.toString(\"utf8\")\n }\n\n /**\n * Verify HMAC signature or throw error\n */\n private verifySignatureOrThrow(\n payload: string,\n signature: string,\n secret: string\n ): void {\n if (!verifySignature(payload, signature, secret)) {\n throw new CloseLoopError(\n \"Invalid webhook signature\",\n ERROR_CODES.INVALID_SIGNATURE,\n 401\n )\n }\n }\n\n /**\n * Parse JSON payload or throw error\n */\n private parseJsonOrThrow(payload: string): unknown {\n try {\n return JSON.parse(payload)\n } catch {\n throw new CloseLoopError(\n \"Invalid webhook payload: could not parse JSON\",\n ERROR_CODES.INVALID_PAYLOAD,\n 400\n )\n }\n }\n\n /**\n * Validate event structure using Zod schema\n */\n private validateEventStructure(parsed: unknown): WebhookEvent {\n const result = webhookEventSchema.safeParse(parsed)\n\n if (!result.success) {\n throw new CloseLoopError(\n \"Invalid webhook payload structure\",\n ERROR_CODES.INVALID_PAYLOAD,\n 400\n )\n }\n\n // Safe to cast: we've validated the base structure, and the type guards\n // will validate specific payload types when used\n return result.data as unknown as WebhookEvent\n }\n}\n","import { DEFAULT_TIMEOUT, USER_AGENT } from \"../constants\"\nimport {\n AuthenticationError,\n CloseLoopError,\n NetworkError,\n NotFoundError,\n RateLimitError\n} from \"./errors\"\n\nexport interface HttpClientOptions {\n baseUrl: string\n apiKey: string\n timeout?: number\n}\n\nexport interface RequestOptions {\n method: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\"\n path: string\n body?: unknown\n headers?: Record<string, string>\n}\n\ninterface ErrorResponse {\n message?: string\n code?: string\n details?: Record<string, unknown>\n}\n\n/**\n * HTTP client for making requests to the CloseLoop API\n */\nexport class HttpClient {\n private baseUrl: string\n private apiKey: string\n private timeout: number\n\n constructor(options: HttpClientOptions) {\n this.baseUrl = options.baseUrl.replace(/\\/$/, \"\") // Remove trailing slash\n this.apiKey = options.apiKey\n this.timeout = options.timeout ?? DEFAULT_TIMEOUT\n }\n\n /**\n * Make an HTTP request to the CloseLoop API\n */\n async request<T>(options: RequestOptions): Promise<T> {\n const url = `${this.baseUrl}${options.path}`\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), this.timeout)\n\n try {\n const response = await fetch(url, {\n method: options.method,\n headers: {\n \"Content-Type\": \"application/json\",\n \"User-Agent\": USER_AGENT,\n \"X-API-Key\": this.apiKey,\n ...options.headers\n },\n body: options.body ? JSON.stringify(options.body) : undefined,\n signal: controller.signal\n })\n\n clearTimeout(timeoutId)\n\n if (!response.ok) {\n await this.handleErrorResponse(response)\n }\n\n // Handle empty responses (204 No Content)\n if (response.status === 204) {\n return {} as T\n }\n\n return (await response.json()) as T\n } catch (error) {\n clearTimeout(timeoutId)\n\n if (error instanceof CloseLoopError) {\n throw error\n }\n\n if (error instanceof Error && error.name === \"AbortError\") {\n throw new NetworkError(\"Request timeout\")\n }\n\n throw new NetworkError(\n error instanceof Error ? error.message : \"Network request failed\",\n error instanceof Error ? error : undefined\n )\n }\n }\n\n private async handleErrorResponse(response: Response): Promise<never> {\n let errorData: ErrorResponse = {}\n\n try {\n const json = (await response.json()) as ErrorResponse\n errorData = json\n } catch {\n // Response body is not JSON\n }\n\n const message =\n errorData.message || `Request failed with status ${response.status}`\n\n switch (response.status) {\n case 401:\n throw new AuthenticationError(message)\n case 404:\n throw new NotFoundError(message)\n case 429: {\n const retryAfter = response.headers.get(\"Retry-After\")\n throw new RateLimitError(\n retryAfter ? parseInt(retryAfter, 10) : undefined\n )\n }\n default:\n throw new CloseLoopError(\n message,\n errorData.code || \"API_ERROR\",\n response.status,\n errorData.details\n )\n }\n }\n}\n","import { DEFAULT_BASE_URL } from \"./constants\"\nimport { Balances } from \"./resources/balances\"\nimport { Credits } from \"./resources/credits\"\nimport { Webhooks } from \"./resources/webhooks\"\nimport { HttpClient } from \"./utils/http\"\n\n/**\n * Configuration options for the CloseLoop client\n */\nexport interface CloseLoopOptions {\n /**\n * Your CloseLoop API key.\n * Get this from your CloseLoop dashboard.\n */\n apiKey: string\n\n /**\n * Base URL for the CloseLoop API.\n * Defaults to https://closeloop.app\n */\n baseUrl?: string\n\n /**\n * Request timeout in milliseconds.\n * Defaults to 30000 (30 seconds)\n */\n timeout?: number\n}\n\n/**\n * CloseLoop SDK client for credit billing integration.\n *\n * @example\n * ```typescript\n * import { CloseLoop } from \"@closeloop/sdk\"\n *\n * const client = new CloseLoop({\n * apiKey: process.env.CLOSELOOP_API_KEY!\n * })\n *\n * // Verify credits\n * const verification = await client.credits.verify({\n * walletAddress: \"0x1234...\",\n * planId: \"plan_abc123\",\n * amount: 1\n * })\n *\n * if (verification.hasEnoughCredits) {\n * // Process request...\n *\n * // Consume credit\n * await client.credits.consume({\n * walletAddress: \"0x1234...\",\n * planId: \"plan_abc123\",\n * amount: 1,\n * consumedBy: \"my-service\"\n * })\n * }\n * ```\n */\nexport class CloseLoop {\n private httpClient: HttpClient\n\n /**\n * Credit consumption and verification operations\n */\n readonly credits: Credits\n\n /**\n * Credit balance queries\n */\n readonly balances: Balances\n\n /**\n * Webhook signature verification utilities\n */\n readonly webhooks: Webhooks\n\n constructor(options: CloseLoopOptions) {\n if (!options.apiKey) {\n throw new Error(\"CloseLoop API key is required\")\n }\n\n const baseUrl = options.baseUrl ?? DEFAULT_BASE_URL\n\n this.httpClient = new HttpClient({\n baseUrl,\n apiKey: options.apiKey,\n timeout: options.timeout\n })\n\n this.credits = new Credits(this.httpClient)\n this.balances = new Balances(this.httpClient)\n this.webhooks = new Webhooks()\n }\n}\n"],"mappings":"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","names":["ENDPOINTS"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/constants.ts","../src/schemas/validation.ts","../src/utils/errors.ts","../src/utils/validation.ts","../src/resources/balances.ts","../src/resources/credits.ts","../src/utils/crypto.ts","../src/resources/webhooks.ts","../src/utils/http.ts","../src/client.ts"],"sourcesContent":["// Main client\nexport { CloseLoop } from \"./client\"\nexport type { CloseLoopOptions } from \"./client\"\n\n// Resources\nexport { Credits } from \"./resources/credits\"\nexport { Balances } from \"./resources/balances\"\nexport { Webhooks } from \"./resources/webhooks\"\nexport type { VerifyWebhookParams } from \"./resources/webhooks\"\n\n// Errors\nexport {\n CloseLoopError,\n InsufficientCreditsError,\n CreditsExpiredError,\n AuthenticationError,\n RateLimitError,\n NetworkError,\n NotFoundError,\n ValidationError\n} from \"./utils/errors\"\n\n// Utilities\nexport { validateInput } from \"./utils/validation\"\n\n// Credit types\nexport type {\n VerifyCreditsParams,\n VerifyCreditsResponse,\n ConsumeCreditsParams,\n ConsumeCreditsResponse,\n BatchConsumeParams,\n BatchConsumeResponse\n} from \"./types/credits\"\n\n// Balance types\nexport type {\n CreditBalance,\n GetBalanceParams,\n ListBalancesParams,\n ListBalancesResponse,\n CreditTransaction,\n ListTransactionsParams,\n ListTransactionsResponse,\n CreditStats\n} from \"./types/balances\"\n\n// Webhook types\nexport type {\n WebhookEventType,\n WebhookEvent,\n PaymentSuccessPayload,\n CreditsLowPayload,\n CreditsExpiredPayload,\n WebhookPayload\n} from \"./types/webhooks\"\n","export const DEFAULT_BASE_URL = \"https://closeloop.app\"\nexport const DEFAULT_TIMEOUT = 30000 // 30 seconds\nexport const SDK_VERSION = \"0.1.0\"\nexport const USER_AGENT = `closeloop-node/${SDK_VERSION}`\n","import { z } from \"zod\"\n\n/**\n * Ethereum wallet address validation (0x + 40 hex chars)\n */\nexport const walletAddressSchema = z\n .string()\n .regex(/^0x[a-fA-F0-9]{40}$/, \"Invalid Ethereum wallet address\")\n\n/**\n * Plan ID validation (non-empty string with reasonable length)\n */\nexport const planIdSchema = z\n .string()\n .min(1, \"Plan ID is required\")\n .max(100, \"Plan ID too long\")\n\n/**\n * Balance ID validation\n */\nexport const balanceIdSchema = z\n .string()\n .min(1, \"Balance ID is required\")\n .max(100, \"Balance ID too long\")\n\n/**\n * Credit amount validation (positive integer with reasonable max)\n */\nexport const creditAmountSchema = z\n .number()\n .int(\"Amount must be an integer\")\n .positive(\"Amount must be positive\")\n .max(1_000_000_000, \"Amount exceeds maximum\")\n\n/**\n * Pagination limit validation\n */\nexport const paginationLimitSchema = z\n .number()\n .int()\n .positive()\n .max(100, \"Limit cannot exceed 100\")\n\n/**\n * Transaction type validation\n */\nexport const transactionTypeSchema = z.enum([\n \"PURCHASE\",\n \"CONSUMPTION\",\n \"REFUND\",\n \"EXPIRATION\"\n])\n\n/**\n * Dangerous prototype pollution keys to skip\n */\nconst DANGEROUS_KEYS = new Set([\"__proto__\", \"constructor\", \"prototype\"])\n\n/**\n * Sanitize metadata object to prevent prototype pollution\n * Creates a clean object with no prototype chain\n */\nexport function sanitizeMetadata(\n metadata: Record<string, unknown> | undefined\n): Record<string, unknown> | undefined {\n if (!metadata) return undefined\n\n // Create a clean object with null prototype to prevent prototype pollution\n const clean = Object.create(null) as Record<string, unknown>\n\n for (const [key, value] of Object.entries(metadata)) {\n // Skip dangerous prototype pollution keys\n if (DANGEROUS_KEYS.has(key)) continue\n\n // Copy all JSON-serializable values\n clean[key] = value\n }\n\n return Object.freeze(clean)\n}\n\n// ============================================================================\n// Credit Schemas\n// ============================================================================\n\nexport const verifyCreditsSchema = z.object({\n walletAddress: walletAddressSchema,\n planId: planIdSchema,\n amount: creditAmountSchema\n})\n\nexport const consumeCreditsSchema = z.object({\n walletAddress: walletAddressSchema,\n planId: planIdSchema,\n amount: creditAmountSchema,\n consumedBy: z.string().max(100).optional(),\n metadata: z.record(z.string(), z.unknown()).optional(),\n idempotencyKey: z.string().max(100).optional()\n})\n\nexport const batchConsumeSchema = z.object({\n operations: z\n .array(\n z.object({\n walletAddress: walletAddressSchema,\n planId: planIdSchema,\n amount: creditAmountSchema,\n consumedBy: z.string().max(100).optional(),\n metadata: z.record(z.string(), z.unknown()).optional()\n })\n )\n .min(1, \"At least one operation required\")\n .max(100, \"Maximum 100 operations per batch\"),\n atomic: z.boolean().optional()\n})\n\n// ============================================================================\n// Balance Schemas\n// ============================================================================\n\nexport const getBalanceSchema = z.object({\n walletAddress: walletAddressSchema,\n planId: planIdSchema\n})\n\nexport const listBalancesSchema = z.object({\n walletAddress: walletAddressSchema,\n activeOnly: z.boolean().optional(),\n limit: paginationLimitSchema.optional(),\n cursor: z.string().max(200).optional()\n})\n\nexport const listTransactionsSchema = z.object({\n balanceId: balanceIdSchema,\n type: transactionTypeSchema.optional(),\n limit: paginationLimitSchema.optional(),\n cursor: z.string().max(200).optional()\n})\n\n// ============================================================================\n// Webhook Schemas\n// ============================================================================\n\nexport const webhookEventTypeSchema = z.enum([\n \"payment.success\",\n \"credits.low\",\n \"credits.expired\"\n])\n\nexport const webhookEventSchema = z.object({\n type: webhookEventTypeSchema,\n id: z.string().min(1),\n createdAt: z.string(),\n data: z.record(z.string(), z.unknown())\n})\n\nexport const paymentSuccessPayloadSchema = z\n .object({\n type: z.string(),\n planId: z.string(),\n planName: z.string(),\n amount: z.number(),\n walletAddress: z.string(),\n transactionId: z.string()\n })\n .loose()\n\nexport const creditsLowPayloadSchema = z.object({\n walletAddress: z.string(),\n planId: z.string(),\n remainingCredits: z.number(),\n threshold: z.number()\n})\n\nexport const creditsExpiredPayloadSchema = z.object({\n walletAddress: z.string(),\n planId: z.string(),\n expiredCredits: z.number(),\n expiresAt: z.string()\n})\n","/**\n * Base error class for all CloseLoop SDK errors\n */\nexport class CloseLoopError extends Error {\n constructor(\n message: string,\n public code: string,\n public statusCode?: number,\n public details?: Record<string, unknown>\n ) {\n super(message)\n this.name = \"CloseLoopError\"\n }\n}\n\n/**\n * Thrown when a user doesn't have enough credits for an operation\n */\nexport class InsufficientCreditsError extends CloseLoopError {\n constructor(\n public remainingCredits: number,\n public requiredCredits: number\n ) {\n super(\n `Insufficient credits: ${remainingCredits} available, ${requiredCredits} required`,\n \"INSUFFICIENT_CREDITS\",\n 402\n )\n this.name = \"InsufficientCreditsError\"\n }\n}\n\n/**\n * Thrown when credits have expired\n */\nexport class CreditsExpiredError extends CloseLoopError {\n constructor(public expiresAt: Date) {\n super(\n `Credits expired at ${expiresAt.toISOString()}`,\n \"CREDITS_EXPIRED\",\n 410\n )\n this.name = \"CreditsExpiredError\"\n }\n}\n\n/**\n * Thrown when authentication fails (invalid API key)\n */\nexport class AuthenticationError extends CloseLoopError {\n constructor(message = \"Invalid API key\") {\n super(message, \"AUTHENTICATION_ERROR\", 401)\n this.name = \"AuthenticationError\"\n }\n}\n\n/**\n * Thrown when rate limit is exceeded\n */\nexport class RateLimitError extends CloseLoopError {\n constructor(public retryAfter?: number) {\n super(\"Rate limit exceeded\", \"RATE_LIMIT\", 429)\n this.name = \"RateLimitError\"\n }\n}\n\n/**\n * Thrown when a network error occurs\n */\nexport class NetworkError extends CloseLoopError {\n constructor(\n message: string,\n public cause?: Error\n ) {\n super(message, \"NETWORK_ERROR\")\n this.name = \"NetworkError\"\n }\n}\n\n/**\n * Thrown when a resource is not found\n */\nexport class NotFoundError extends CloseLoopError {\n constructor(resource: string) {\n super(`${resource} not found`, \"NOT_FOUND\", 404)\n this.name = \"NotFoundError\"\n }\n}\n\n/**\n * Thrown when input validation fails\n */\nexport class ValidationError extends CloseLoopError {\n constructor(\n message: string,\n public field?: string\n ) {\n super(message, \"VALIDATION_ERROR\", 400)\n this.name = \"ValidationError\"\n }\n}\n","import { CloseLoopError } from \"./errors\"\n\n/**\n * Generic schema interface for validation\n */\nexport interface ValidationSchema<T> {\n safeParse: (data: unknown) => {\n success: boolean\n data?: T\n error?: { message: string }\n }\n}\n\n/**\n * Validate input against a Zod schema\n * Throws CloseLoopError if validation fails\n *\n * @param schema - Zod schema to validate against\n * @param data - Data to validate\n * @returns Validated and typed data\n * @throws {CloseLoopError} When validation fails\n */\nexport function validateInput<T>(\n schema: ValidationSchema<T>,\n data: unknown\n): T {\n const result = schema.safeParse(data)\n\n if (!result.success) {\n throw new CloseLoopError(\n `Validation error: ${result.error?.message || \"Invalid input\"}`,\n \"VALIDATION_ERROR\",\n 400\n )\n }\n\n return result.data as T\n}\n\n/**\n * Validate a single value against a Zod schema\n * Returns a boolean without throwing\n */\nexport function isValid<T>(\n schema: ValidationSchema<T>,\n data: unknown\n): data is T {\n return schema.safeParse(data).success\n}\n","import {\n getBalanceSchema,\n listBalancesSchema,\n listTransactionsSchema,\n walletAddressSchema\n} from \"../schemas/validation\"\nimport type {\n CreditBalance,\n CreditStats,\n GetBalanceParams,\n ListBalancesParams,\n ListBalancesResponse,\n ListTransactionsParams,\n ListTransactionsResponse\n} from \"../types/balances\"\nimport { NotFoundError } from \"../utils/errors\"\nimport { HttpClient } from \"../utils/http\"\nimport { validateInput } from \"../utils/validation\"\n\n// API Endpoints\nconst ENDPOINTS = {\n BALANCE: \"/api/credit/balance\",\n BALANCES: \"/api/credit/balances\",\n STATS: \"/api/credit/stats\"\n} as const\n\n/**\n * Resource for querying credit balances and transaction history\n */\nexport class Balances {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Get a specific credit balance for a wallet and plan.\n *\n * @example\n * ```typescript\n * const balance = await client.balances.get({\n * walletAddress: \"0x1234...\",\n * planId: \"plan_abc123\"\n * })\n *\n * if (balance) {\n * console.log(`Credits: ${balance.remainingCredits}/${balance.totalCredits}`)\n * }\n * ```\n *\n * @returns The credit balance, or null if not found\n * @throws {CloseLoopError} When input validation fails\n */\n async get(params: GetBalanceParams): Promise<CreditBalance | null> {\n const validated = validateInput(getBalanceSchema, params)\n\n const query = this.buildQueryString({\n wallet: validated.walletAddress,\n plan: validated.planId\n })\n\n try {\n return await this.http.request<CreditBalance>({\n method: \"GET\",\n path: `${ENDPOINTS.BALANCE}?${query}`\n })\n } catch (error) {\n if (error instanceof NotFoundError) {\n return null\n }\n throw error\n }\n }\n\n /**\n * List all credit balances for a wallet.\n *\n * @example\n * ```typescript\n * const { balances, nextCursor } = await client.balances.list({\n * walletAddress: \"0x1234...\",\n * activeOnly: true,\n * limit: 10\n * })\n *\n * for (const balance of balances) {\n * console.log(`${balance.planName}: ${balance.remainingCredits} credits`)\n * }\n *\n * // Paginate if needed\n * if (nextCursor) {\n * const nextPage = await client.balances.list({\n * walletAddress: \"0x1234...\",\n * cursor: nextCursor\n * })\n * }\n * ```\n *\n * @throws {CloseLoopError} When input validation fails\n */\n async list(params: ListBalancesParams): Promise<ListBalancesResponse> {\n const validated = validateInput(listBalancesSchema, params)\n\n const query = this.buildQueryString({\n wallet: validated.walletAddress,\n activeOnly: validated.activeOnly,\n limit: validated.limit,\n cursor: validated.cursor\n })\n\n return this.http.request<ListBalancesResponse>({\n method: \"GET\",\n path: `${ENDPOINTS.BALANCES}?${query}`\n })\n }\n\n /**\n * Get transaction history for a balance.\n *\n * @example\n * ```typescript\n * const { transactions } = await client.balances.transactions({\n * balanceId: \"bal_xyz\",\n * type: \"CONSUMPTION\",\n * limit: 50\n * })\n *\n * for (const tx of transactions) {\n * console.log(`${tx.type}: ${tx.amount} - ${tx.description}`)\n * }\n * ```\n *\n * @throws {CloseLoopError} When input validation fails\n */\n async transactions(\n params: ListTransactionsParams\n ): Promise<ListTransactionsResponse> {\n const validated = validateInput(listTransactionsSchema, params)\n\n const query = this.buildQueryString({\n type: validated.type,\n limit: validated.limit,\n cursor: validated.cursor\n })\n\n const basePath = `${ENDPOINTS.BALANCE}/${encodeURIComponent(validated.balanceId)}/transactions`\n const path = query ? `${basePath}?${query}` : basePath\n\n return this.http.request<ListTransactionsResponse>({\n method: \"GET\",\n path\n })\n }\n\n /**\n * Get aggregated stats for a wallet's credits.\n *\n * @example\n * ```typescript\n * const stats = await client.balances.stats(\"0x1234...\")\n * console.log(`Total: ${stats.totalCredits}, Used: ${stats.totalUsed}`)\n * ```\n *\n * @throws {CloseLoopError} When input validation fails\n */\n async stats(walletAddress: string): Promise<CreditStats> {\n // Validate using the shared utility for consistency\n validateInput(walletAddressSchema, walletAddress)\n\n const query = this.buildQueryString({ wallet: walletAddress })\n\n return this.http.request<CreditStats>({\n method: \"GET\",\n path: `${ENDPOINTS.STATS}?${query}`\n })\n }\n\n // ==========================================================================\n // Private Helpers\n // ==========================================================================\n\n /**\n * Build URL query string from params, filtering out undefined values\n */\n private buildQueryString(\n params: Record<string, string | number | boolean | undefined>\n ): string {\n const query = new URLSearchParams()\n\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined) {\n query.set(key, String(value))\n }\n }\n\n return query.toString()\n }\n}\n","import {\n batchConsumeSchema,\n consumeCreditsSchema,\n sanitizeMetadata,\n verifyCreditsSchema\n} from \"../schemas/validation\"\nimport type {\n BatchConsumeParams,\n BatchConsumeResponse,\n ConsumeCreditsParams,\n ConsumeCreditsResponse,\n VerifyCreditsParams,\n VerifyCreditsResponse\n} from \"../types/credits\"\nimport { CreditsExpiredError, InsufficientCreditsError } from \"../utils/errors\"\nimport { HttpClient } from \"../utils/http\"\nimport { validateInput } from \"../utils/validation\"\n\n// API Endpoints\nconst ENDPOINTS = {\n VERIFY: \"/api/credit/verify\",\n CONSUME: \"/api/credit/consume\",\n BATCH_CONSUME: \"/api/credit/consume/batch\"\n} as const\n\n/**\n * Resource for credit verification and consumption operations\n */\nexport class Credits {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Verify if a user has enough credits without consuming them.\n *\n * @example\n * ```typescript\n * const result = await client.credits.verify({\n * walletAddress: \"0x1234...\",\n * planId: \"plan_abc123\",\n * amount: 10\n * })\n *\n * if (result.hasEnoughCredits) {\n * // Proceed with service\n * }\n * ```\n *\n * @throws {CloseLoopError} When input validation fails\n */\n async verify(params: VerifyCreditsParams): Promise<VerifyCreditsResponse> {\n const validated = validateInput(verifyCreditsSchema, params)\n\n return this.http.request<VerifyCreditsResponse>({\n method: \"POST\",\n path: ENDPOINTS.VERIFY,\n body: validated\n })\n }\n\n /**\n * Consume credits from a user's balance.\n *\n * @example\n * ```typescript\n * const result = await client.credits.consume({\n * walletAddress: \"0x1234...\",\n * planId: \"plan_abc123\",\n * amount: 1,\n * consumedBy: \"ai-generation\",\n * metadata: { requestId: \"req_xyz\" }\n * })\n *\n * console.log(`Remaining: ${result.remainingCredits}`)\n * ```\n *\n * @throws {InsufficientCreditsError} When user doesn't have enough credits\n * @throws {CreditsExpiredError} When credits have expired\n * @throws {CloseLoopError} When input validation fails\n */\n async consume(params: ConsumeCreditsParams): Promise<ConsumeCreditsResponse> {\n const validated = validateInput(consumeCreditsSchema, params)\n\n return this.http.request<ConsumeCreditsResponse>({\n method: \"POST\",\n path: ENDPOINTS.CONSUME,\n body: this.buildConsumeBody(validated),\n headers: this.buildIdempotencyHeaders(validated.idempotencyKey)\n })\n }\n\n /**\n * Verify and consume credits in a single atomic operation.\n * This is useful when you want to ensure credits are available\n * before consuming them, without race conditions.\n *\n * @example\n * ```typescript\n * try {\n * const result = await client.credits.verifyAndConsume({\n * walletAddress: \"0x1234...\",\n * planId: \"plan_abc123\",\n * amount: 5,\n * consumedBy: \"batch-processing\"\n * })\n * // Credits were verified and consumed\n * } catch (error) {\n * if (error instanceof InsufficientCreditsError) {\n * // Handle insufficient credits\n * }\n * }\n * ```\n *\n * @throws {InsufficientCreditsError} When user doesn't have enough credits\n * @throws {CreditsExpiredError} When credits have expired\n * @throws {CloseLoopError} When input validation fails\n */\n async verifyAndConsume(\n params: ConsumeCreditsParams\n ): Promise<ConsumeCreditsResponse> {\n const validated = validateInput(consumeCreditsSchema, params)\n\n // First verify\n const verification = await this.http.request<VerifyCreditsResponse>({\n method: \"POST\",\n path: ENDPOINTS.VERIFY,\n body: {\n walletAddress: validated.walletAddress,\n planId: validated.planId,\n amount: validated.amount\n }\n })\n\n this.assertCreditsAvailable(verification, validated.amount)\n\n // Then consume\n return this.http.request<ConsumeCreditsResponse>({\n method: \"POST\",\n path: ENDPOINTS.CONSUME,\n body: this.buildConsumeBody(validated),\n headers: this.buildIdempotencyHeaders(validated.idempotencyKey)\n })\n }\n\n /**\n * Consume credits in batch.\n *\n * @example\n * ```typescript\n * const result = await client.credits.batchConsume({\n * operations: [\n * { walletAddress: \"0x1234...\", planId: \"plan_a\", amount: 1 },\n * { walletAddress: \"0x5678...\", planId: \"plan_b\", amount: 2 }\n * ],\n * atomic: false // Allow partial success\n * })\n *\n * console.log(`Success: ${result.successCount}, Failed: ${result.failedCount}`)\n * ```\n *\n * @throws {CloseLoopError} When input validation fails\n */\n async batchConsume(\n params: BatchConsumeParams\n ): Promise<BatchConsumeResponse> {\n const validated = validateInput(batchConsumeSchema, params)\n\n // Sanitize metadata in each operation\n const sanitizedOperations = validated.operations.map(op => ({\n ...op,\n metadata: sanitizeMetadata(op.metadata)\n }))\n\n return this.http.request<BatchConsumeResponse>({\n method: \"POST\",\n path: ENDPOINTS.BATCH_CONSUME,\n body: {\n operations: sanitizedOperations,\n atomic: validated.atomic\n }\n })\n }\n\n // ==========================================================================\n // Private Helpers\n // ==========================================================================\n\n /**\n * Build consumption request body with sanitized metadata\n */\n private buildConsumeBody(validated: {\n walletAddress: string\n planId: string\n amount: number\n consumedBy?: string\n metadata?: Record<string, unknown>\n }) {\n return {\n walletAddress: validated.walletAddress,\n planId: validated.planId,\n amount: validated.amount,\n consumedBy: validated.consumedBy,\n metadata: sanitizeMetadata(validated.metadata)\n }\n }\n\n /**\n * Build idempotency headers if key is provided\n */\n private buildIdempotencyHeaders(\n idempotencyKey?: string\n ): Record<string, string> {\n if (!idempotencyKey) return {}\n return { \"Idempotency-Key\": idempotencyKey }\n }\n\n /**\n * Assert credits are available, throw typed errors if not\n */\n private assertCreditsAvailable(\n verification: VerifyCreditsResponse,\n requiredAmount: number\n ): void {\n if (!verification.hasEnoughCredits) {\n throw new InsufficientCreditsError(\n verification.remainingCredits,\n requiredAmount\n )\n }\n\n if (verification.expiresAt) {\n const expirationDate = new Date(verification.expiresAt)\n if (expirationDate < new Date()) {\n throw new CreditsExpiredError(expirationDate)\n }\n }\n }\n}\n","import { createHmac, timingSafeEqual } from \"crypto\"\n\n/**\n * Generates an HMAC signature for webhook verification\n */\nexport function generateSignature(payload: string, secret: string): string {\n return createHmac(\"sha256\", secret).update(payload).digest(\"hex\")\n}\n\n/**\n * Verifies that a webhook signature is valid using timing-safe comparison\n */\nexport function verifySignature(\n payload: string,\n signature: string,\n secret: string\n): boolean {\n const expectedSignature = generateSignature(payload, secret)\n\n // Use timing-safe comparison to prevent timing attacks\n if (signature.length !== expectedSignature.length) {\n return false\n }\n\n return timingSafeEqual(Buffer.from(signature), Buffer.from(expectedSignature))\n}\n","import {\n creditsExpiredPayloadSchema,\n creditsLowPayloadSchema,\n paymentSuccessPayloadSchema,\n webhookEventSchema\n} from \"../schemas/validation\"\nimport type {\n CreditsExpiredPayload,\n CreditsLowPayload,\n PaymentSuccessPayload,\n WebhookEvent,\n WebhookPayload\n} from \"../types/webhooks\"\nimport { verifySignature } from \"../utils/crypto\"\nimport { CloseLoopError } from \"../utils/errors\"\n\n/**\n * Parameters for verifying a webhook\n */\nexport interface VerifyWebhookParams {\n /**\n * Raw request body as string or Buffer\n */\n payload: string | Buffer\n\n /**\n * X-CloseLoop-Signature header value\n */\n signature: string\n\n /**\n * Your webhook secret\n */\n secret: string\n}\n\n// Validation error codes\nconst ERROR_CODES = {\n VALIDATION: \"VALIDATION_ERROR\",\n INVALID_SIGNATURE: \"INVALID_SIGNATURE\",\n INVALID_PAYLOAD: \"INVALID_PAYLOAD\"\n} as const\n\n/**\n * Resource for webhook signature verification and event handling\n */\nexport class Webhooks {\n /**\n * Verify a webhook signature and parse the event.\n *\n * @example\n * ```typescript\n * // Express handler\n * app.post(\"/webhook\", (req, res) => {\n * try {\n * const event = client.webhooks.verify({\n * payload: req.body,\n * signature: req.headers[\"x-closeloop-signature\"],\n * secret: process.env.WEBHOOK_SECRET!\n * })\n *\n * if (client.webhooks.isPaymentSuccess(event)) {\n * const { type, walletAddress, planId, amount } = event.data\n * // Handle payment success\n * }\n *\n * res.json({ received: true })\n * } catch (error) {\n * res.status(400).json({ error: \"Invalid signature\" })\n * }\n * })\n * ```\n *\n * @example\n * ```typescript\n * // Next.js App Router\n * export async function POST(request: Request) {\n * const payload = await request.text()\n * const signature = request.headers.get(\"x-closeloop-signature\")!\n *\n * const event = client.webhooks.verify({\n * payload,\n * signature,\n * secret: process.env.WEBHOOK_SECRET!\n * })\n *\n * // Handle event...\n * return Response.json({ received: true })\n * }\n * ```\n *\n * @throws {CloseLoopError} When signature is invalid or payload is malformed\n */\n verify(params: VerifyWebhookParams): WebhookEvent {\n this.validateRequiredParams(params)\n\n const payloadString = this.normalizePayload(params.payload)\n\n this.verifySignatureOrThrow(payloadString, params.signature, params.secret)\n\n const parsed = this.parseJsonOrThrow(payloadString)\n\n return this.validateEventStructure(parsed)\n }\n\n /**\n * Type guard for payment.success events\n * Also validates the payload structure\n *\n * @example\n * ```typescript\n * if (client.webhooks.isPaymentSuccess(event)) {\n * // TypeScript knows event.data is PaymentSuccessPayload\n * console.log(event.data.planId, event.data.walletAddress)\n * }\n * ```\n */\n isPaymentSuccess(\n event: WebhookEvent<WebhookPayload>\n ): event is WebhookEvent<PaymentSuccessPayload> {\n return (\n event.type === \"payment.success\" &&\n paymentSuccessPayloadSchema.safeParse(event.data).success\n )\n }\n\n /**\n * Type guard for credits.low events\n * Also validates the payload structure\n *\n * @example\n * ```typescript\n * if (client.webhooks.isCreditsLow(event)) {\n * // TypeScript knows event.data is CreditsLowPayload\n * console.log(`Low balance: ${event.data.remainingCredits}`)\n * }\n * ```\n */\n isCreditsLow(\n event: WebhookEvent<WebhookPayload>\n ): event is WebhookEvent<CreditsLowPayload> {\n return (\n event.type === \"credits.low\" &&\n creditsLowPayloadSchema.safeParse(event.data).success\n )\n }\n\n /**\n * Type guard for credits.expired events\n * Also validates the payload structure\n *\n * @example\n * ```typescript\n * if (client.webhooks.isCreditsExpired(event)) {\n * // TypeScript knows event.data is CreditsExpiredPayload\n * console.log(`Expired: ${event.data.expiredCredits} credits`)\n * }\n * ```\n */\n isCreditsExpired(\n event: WebhookEvent<WebhookPayload>\n ): event is WebhookEvent<CreditsExpiredPayload> {\n return (\n event.type === \"credits.expired\" &&\n creditsExpiredPayloadSchema.safeParse(event.data).success\n )\n }\n\n // ==========================================================================\n // Private Helpers\n // ==========================================================================\n\n /**\n * Validate that all required parameters are present\n */\n private validateRequiredParams(params: VerifyWebhookParams): void {\n if (!params.payload) {\n throw new CloseLoopError(\n \"Webhook payload is required\",\n ERROR_CODES.VALIDATION,\n 400\n )\n }\n\n if (!params.signature) {\n throw new CloseLoopError(\n \"Webhook signature is required\",\n ERROR_CODES.VALIDATION,\n 400\n )\n }\n\n if (!params.secret) {\n throw new CloseLoopError(\n \"Webhook secret is required\",\n ERROR_CODES.VALIDATION,\n 400\n )\n }\n }\n\n /**\n * Convert payload to string regardless of input type\n */\n private normalizePayload(payload: string | Buffer): string {\n return typeof payload === \"string\" ? payload : payload.toString(\"utf8\")\n }\n\n /**\n * Verify HMAC signature or throw error\n */\n private verifySignatureOrThrow(\n payload: string,\n signature: string,\n secret: string\n ): void {\n if (!verifySignature(payload, signature, secret)) {\n throw new CloseLoopError(\n \"Invalid webhook signature\",\n ERROR_CODES.INVALID_SIGNATURE,\n 401\n )\n }\n }\n\n /**\n * Parse JSON payload or throw error\n */\n private parseJsonOrThrow(payload: string): unknown {\n try {\n return JSON.parse(payload)\n } catch {\n throw new CloseLoopError(\n \"Invalid webhook payload: could not parse JSON\",\n ERROR_CODES.INVALID_PAYLOAD,\n 400\n )\n }\n }\n\n /**\n * Validate event structure using Zod schema\n */\n private validateEventStructure(parsed: unknown): WebhookEvent {\n const result = webhookEventSchema.safeParse(parsed)\n\n if (!result.success) {\n throw new CloseLoopError(\n \"Invalid webhook payload structure\",\n ERROR_CODES.INVALID_PAYLOAD,\n 400\n )\n }\n\n // Safe to cast: we've validated the base structure, and the type guards\n // will validate specific payload types when used\n return result.data as unknown as WebhookEvent\n }\n}\n","import { DEFAULT_TIMEOUT, USER_AGENT } from \"../constants\"\nimport {\n AuthenticationError,\n CloseLoopError,\n NetworkError,\n NotFoundError,\n RateLimitError\n} from \"./errors\"\n\nexport interface HttpClientOptions {\n baseUrl: string\n apiKey: string\n timeout?: number\n}\n\nexport interface RequestOptions {\n method: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\"\n path: string\n body?: unknown\n headers?: Record<string, string>\n}\n\ninterface ErrorResponse {\n message?: string\n code?: string\n details?: Record<string, unknown>\n}\n\n/**\n * HTTP client for making requests to the CloseLoop API\n */\nexport class HttpClient {\n private baseUrl: string\n private apiKey: string\n private timeout: number\n\n constructor(options: HttpClientOptions) {\n this.baseUrl = options.baseUrl.replace(/\\/$/, \"\") // Remove trailing slash\n this.apiKey = options.apiKey\n this.timeout = options.timeout ?? DEFAULT_TIMEOUT\n }\n\n /**\n * Make an HTTP request to the CloseLoop API\n */\n async request<T>(options: RequestOptions): Promise<T> {\n const url = `${this.baseUrl}${options.path}`\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), this.timeout)\n\n try {\n const response = await fetch(url, {\n method: options.method,\n headers: {\n \"Content-Type\": \"application/json\",\n \"User-Agent\": USER_AGENT,\n \"X-API-Key\": this.apiKey,\n ...options.headers\n },\n body: options.body ? JSON.stringify(options.body) : undefined,\n signal: controller.signal\n })\n\n clearTimeout(timeoutId)\n\n if (!response.ok) {\n await this.handleErrorResponse(response)\n }\n\n // Handle empty responses (204 No Content)\n if (response.status === 204) {\n return {} as T\n }\n\n return (await response.json()) as T\n } catch (error) {\n clearTimeout(timeoutId)\n\n if (error instanceof CloseLoopError) {\n throw error\n }\n\n if (error instanceof Error && error.name === \"AbortError\") {\n throw new NetworkError(\"Request timeout\")\n }\n\n throw new NetworkError(\n error instanceof Error ? error.message : \"Network request failed\",\n error instanceof Error ? error : undefined\n )\n }\n }\n\n private async handleErrorResponse(response: Response): Promise<never> {\n let errorData: ErrorResponse = {}\n\n try {\n const json = (await response.json()) as ErrorResponse\n errorData = json\n } catch {\n // Response body is not JSON\n }\n\n const message =\n errorData.message || `Request failed with status ${response.status}`\n\n switch (response.status) {\n case 401:\n throw new AuthenticationError(message)\n case 404:\n throw new NotFoundError(message)\n case 429: {\n const retryAfter = response.headers.get(\"Retry-After\")\n throw new RateLimitError(\n retryAfter ? parseInt(retryAfter, 10) : undefined\n )\n }\n default:\n throw new CloseLoopError(\n message,\n errorData.code || \"API_ERROR\",\n response.status,\n errorData.details\n )\n }\n }\n}\n","import { DEFAULT_BASE_URL } from \"./constants\"\nimport { Balances } from \"./resources/balances\"\nimport { Credits } from \"./resources/credits\"\nimport { Webhooks } from \"./resources/webhooks\"\nimport { HttpClient } from \"./utils/http\"\n\n/**\n * Configuration options for the CloseLoop client\n */\nexport interface CloseLoopOptions {\n /**\n * Your CloseLoop API key.\n * Get this from your CloseLoop dashboard.\n */\n apiKey: string\n\n /**\n * Base URL for the CloseLoop API.\n * Defaults to https://closeloop.app\n */\n baseUrl?: string\n\n /**\n * Request timeout in milliseconds.\n * Defaults to 30000 (30 seconds)\n */\n timeout?: number\n}\n\n/**\n * CloseLoop SDK client for credit billing integration.\n *\n * @example\n * ```typescript\n * import { CloseLoop } from \"@closeloop/sdk\"\n *\n * const client = new CloseLoop({\n * apiKey: process.env.CLOSELOOP_API_KEY!\n * })\n *\n * // Verify credits\n * const verification = await client.credits.verify({\n * walletAddress: \"0x1234...\",\n * planId: \"plan_abc123\",\n * amount: 1\n * })\n *\n * if (verification.hasEnoughCredits) {\n * // Process request...\n *\n * // Consume credit\n * await client.credits.consume({\n * walletAddress: \"0x1234...\",\n * planId: \"plan_abc123\",\n * amount: 1,\n * consumedBy: \"my-service\"\n * })\n * }\n * ```\n */\nexport class CloseLoop {\n private httpClient: HttpClient\n\n /**\n * Credit consumption and verification operations\n */\n readonly credits: Credits\n\n /**\n * Credit balance queries\n */\n readonly balances: Balances\n\n /**\n * Webhook signature verification utilities\n */\n readonly webhooks: Webhooks\n\n constructor(options: CloseLoopOptions) {\n if (!options.apiKey) {\n throw new Error(\"CloseLoop API key is required\")\n }\n\n const baseUrl = options.baseUrl ?? DEFAULT_BASE_URL\n\n this.httpClient = new HttpClient({\n baseUrl,\n apiKey: options.apiKey,\n timeout: options.timeout\n })\n\n this.credits = new Credits(this.httpClient)\n this.balances = new Balances(this.httpClient)\n this.webhooks = new Webhooks()\n }\n}\n"],"mappings":"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","names":["ENDPOINTS"]}
package/dist/index.mjs CHANGED
@@ -80,16 +80,13 @@ var webhookEventSchema = z.object({
80
80
  data: z.record(z.string(), z.unknown())
81
81
  });
82
82
  var paymentSuccessPayloadSchema = z.object({
83
- transactionId: z.string(),
83
+ type: z.string(),
84
84
  planId: z.string(),
85
85
  planName: z.string(),
86
86
  amount: z.number(),
87
- requests: z.number().nullable(),
88
- creditAmount: z.number().nullable(),
89
- transactionHash: z.string(),
90
- payerAddress: z.string(),
91
- accessType: z.string()
92
- });
87
+ walletAddress: z.string(),
88
+ transactionId: z.string()
89
+ }).loose();
93
90
  var creditsLowPayloadSchema = z.object({
94
91
  walletAddress: z.string(),
95
92
  planId: z.string(),
@@ -555,8 +552,8 @@ var Webhooks = class {
555
552
  * })
556
553
  *
557
554
  * if (client.webhooks.isPaymentSuccess(event)) {
558
- * const { creditAmount, payerAddress } = event.data
559
- * // Handle credit purchase
555
+ * const { type, walletAddress, planId, amount } = event.data
556
+ * // Handle payment success
560
557
  * }
561
558
  *
562
559
  * res.json({ received: true })
@@ -601,7 +598,7 @@ var Webhooks = class {
601
598
  * ```typescript
602
599
  * if (client.webhooks.isPaymentSuccess(event)) {
603
600
  * // TypeScript knows event.data is PaymentSuccessPayload
604
- * console.log(event.data.creditAmount)
601
+ * console.log(event.data.planId, event.data.walletAddress)
605
602
  * }
606
603
  * ```
607
604
  */