{"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["/**\n * Manual Payment Provider\n * @classytic/revenue-manual\n *\n * Reference implementation for building payment providers\n * Perfect for: Cash, bank transfers, mobile money without API\n *\n * Use this as a template for building:\n * - @classytic/revenue-stripe\n * - @classytic/revenue-sslcommerz\n * - @classytic/revenue-bkash\n * - Your custom provider\n */\n\nimport { PaymentProvider } from '@classytic/revenue';\nimport type {\n  CreateIntentParams,\n  PaymentIntent,\n  PaymentResult,\n  ProviderCapabilities,\n  RefundResult,\n  WebhookEvent,\n} from '@classytic/primitives/payment-gateway';\nimport { nanoid } from 'nanoid';\n\n/**\n * Configuration options for ManualProvider\n */\nexport interface ManualProviderConfig {\n  [key: string]: unknown;\n}\n\n/**\n * Refund options for manual refunds\n */\nexport interface ManualRefundOptions {\n  currency?: string;\n  reason?: string;\n  metadata?: Record<string, unknown>;\n}\n\n/**\n * Payment info structure for manual payments\n */\ninterface PaymentInfo {\n  [key: string]: string | number | Record<string, unknown>;\n}\n\n/**\n * Manual Payment Provider\n * Reference implementation for building payment providers\n * Perfect for: Cash, bank transfers, mobile money without API\n */\nexport class ManualProvider extends PaymentProvider {\n  public override readonly name: string = 'manual';\n\n  constructor(config: ManualProviderConfig = {}) {\n    super(config);\n  }\n\n  /**\n   * Create manual payment intent\n   * Returns instructions for manual payment\n   */\n  async createIntent(params: CreateIntentParams): Promise<PaymentIntent> {\n    const intentId = `manual_${nanoid(16)}`;\n    const amountValue = params.amount.amount;\n    const currency = params.amount.currency ?? this.defaultCurrency;\n\n    return {\n      id: intentId,\n      sessionId: null,\n      paymentIntentId: null,\n      provider: 'manual',\n      status: 'pending',\n      amount: { amount: amountValue, currency },\n      metadata: params.metadata ?? {},\n      instructions: this._getPaymentInstructions(params, currency),\n      raw: params,\n    };\n  }\n\n  /**\n   * Verify manual payment\n   * For manual provider, verification is done by admin approval\n   * When admin calls revenue.payments.verify(), this confirms the payment\n   */\n  async verifyPayment(intentId: string): Promise<PaymentResult> {\n    return {\n      id: intentId,\n      provider: 'manual',\n      status: 'succeeded', // Admin has verified, mark as succeeded\n      // amount is optional now — engine fills in from the transaction's\n      // currency. Don't hardcode a placeholder.\n      paidAt: new Date(),\n      metadata: {\n        manuallyVerified: true,\n      },\n    };\n  }\n\n  /**\n   * Get payment status\n   */\n  async getStatus(intentId: string): Promise<PaymentResult> {\n    return this.verifyPayment(intentId);\n  }\n\n  /**\n   * Refund manual payment\n   */\n  async refund(\n    _paymentId: string,\n    amount?: number | null,\n    options: ManualRefundOptions = {}\n  ): Promise<RefundResult> {\n    const refundId = `refund_${nanoid(16)}`;\n    const currency = options.currency ?? this.defaultCurrency;\n\n    return {\n      id: refundId,\n      provider: 'manual',\n      status: 'succeeded', // Manual refunds are immediately marked as succeeded\n      amount: { amount: amount ?? 0, currency },\n      refundedAt: new Date(),\n      reason: options.reason ?? 'Manual refund',\n      metadata: options.metadata ?? {},\n    };\n  }\n\n  /**\n   * Manual provider doesn't support webhooks\n   */\n  async handleWebhook(\n    _payload: unknown,\n    _headers?: Record<string, string>\n  ): Promise<WebhookEvent> {\n    throw new Error('Manual provider does not support webhooks');\n  }\n\n  /**\n   * Get provider capabilities\n   */\n  override getCapabilities(): ProviderCapabilities {\n    return {\n      supportsWebhooks: false,\n      supportsRefunds: true,\n      supportsPartialRefunds: true,\n      requiresManualVerification: true,\n    };\n  }\n\n  /**\n   * Generate payment instructions for customer\n   * @private\n   */\n  private _getPaymentInstructions(params: CreateIntentParams, currency: string): string {\n    const metadata = params.metadata as Record<string, unknown> | undefined;\n    const paymentInfo = metadata?.paymentInfo as PaymentInfo | undefined;\n    const paymentInstructions = metadata?.paymentInstructions as string | undefined;\n\n    // If user provided custom instructions, use them\n    if (paymentInstructions) {\n      return paymentInstructions;\n    }\n\n    const amountValue = params.amount.amount;\n\n    // Generic fallback\n    if (!paymentInfo) {\n      return `Payment Amount: ${amountValue} ${currency}\\n\\nPlease contact the organization for payment details.`;\n    }\n\n    // Build instructions from paymentInfo\n    const lines: string[] = [`Payment Amount: ${amountValue} ${currency}`, ''];\n\n    // Add all payment info fields generically\n    Object.entries(paymentInfo).forEach(([key, value]) => {\n      if (typeof value === 'string' || typeof value === 'number') {\n        lines.push(`${key}: ${value}`);\n      } else if (typeof value === 'object' && value !== null) {\n        lines.push(`${key}:`);\n        Object.entries(value as Record<string, unknown>).forEach(([subKey, subValue]) => {\n          lines.push(`  ${subKey}: ${subValue}`);\n        });\n      }\n    });\n\n    return lines.join('\\n');\n  }\n}\n\nexport default ManualProvider;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAqDA,IAAa,iBAAb,cAAoC,gBAAgB;CAClD,AAAyB,OAAe;CAExC,YAAY,SAA+B,EAAE,EAAE;AAC7C,QAAM,OAAO;;;;;;CAOf,MAAM,aAAa,QAAoD;EACrE,MAAM,WAAW,UAAU,OAAO,GAAG;EACrC,MAAM,cAAc,OAAO,OAAO;EAClC,MAAM,WAAW,OAAO,OAAO,YAAY,KAAK;AAEhD,SAAO;GACL,IAAI;GACJ,WAAW;GACX,iBAAiB;GACjB,UAAU;GACV,QAAQ;GACR,QAAQ;IAAE,QAAQ;IAAa;IAAU;GACzC,UAAU,OAAO,YAAY,EAAE;GAC/B,cAAc,KAAK,wBAAwB,QAAQ,SAAS;GAC5D,KAAK;GACN;;;;;;;CAQH,MAAM,cAAc,UAA0C;AAC5D,SAAO;GACL,IAAI;GACJ,UAAU;GACV,QAAQ;GAGR,wBAAQ,IAAI,MAAM;GAClB,UAAU,EACR,kBAAkB,MACnB;GACF;;;;;CAMH,MAAM,UAAU,UAA0C;AACxD,SAAO,KAAK,cAAc,SAAS;;;;;CAMrC,MAAM,OACJ,YACA,QACA,UAA+B,EAAE,EACV;EACvB,MAAM,WAAW,UAAU,OAAO,GAAG;EACrC,MAAM,WAAW,QAAQ,YAAY,KAAK;AAE1C,SAAO;GACL,IAAI;GACJ,UAAU;GACV,QAAQ;GACR,QAAQ;IAAE,QAAQ,UAAU;IAAG;IAAU;GACzC,4BAAY,IAAI,MAAM;GACtB,QAAQ,QAAQ,UAAU;GAC1B,UAAU,QAAQ,YAAY,EAAE;GACjC;;;;;CAMH,MAAM,cACJ,UACA,UACuB;AACvB,QAAM,IAAI,MAAM,4CAA4C;;;;;CAM9D,AAAS,kBAAwC;AAC/C,SAAO;GACL,kBAAkB;GAClB,iBAAiB;GACjB,wBAAwB;GACxB,4BAA4B;GAC7B;;;;;;CAOH,AAAQ,wBAAwB,QAA4B,UAA0B;EACpF,MAAM,WAAW,OAAO;EACxB,MAAM,cAAc,UAAU;EAC9B,MAAM,sBAAsB,UAAU;AAGtC,MAAI,oBACF,QAAO;EAGT,MAAM,cAAc,OAAO,OAAO;AAGlC,MAAI,CAAC,YACH,QAAO,mBAAmB,YAAY,GAAG,SAAS;EAIpD,MAAM,QAAkB,CAAC,mBAAmB,YAAY,GAAG,YAAY,GAAG;AAG1E,SAAO,QAAQ,YAAY,CAAC,SAAS,CAAC,KAAK,WAAW;AACpD,OAAI,OAAO,UAAU,YAAY,OAAO,UAAU,SAChD,OAAM,KAAK,GAAG,IAAI,IAAI,QAAQ;YACrB,OAAO,UAAU,YAAY,UAAU,MAAM;AACtD,UAAM,KAAK,GAAG,IAAI,GAAG;AACrB,WAAO,QAAQ,MAAiC,CAAC,SAAS,CAAC,QAAQ,cAAc;AAC/E,WAAM,KAAK,KAAK,OAAO,IAAI,WAAW;MACtC;;IAEJ;AAEF,SAAO,MAAM,KAAK,KAAK"}