{"_id":"@drop-africa/drop-js","_rev":"2-fdb79463e1a7b31ffbd9f2c91453230c","name":"@drop-africa/drop-js","dist-tags":{"latest":"0.1.2"},"versions":{"0.1.1":{"name":"@drop-africa/drop-js","version":"0.1.1","keywords":["drop","payment","qr-code","mobile-money","africa","sdk","typescript"],"author":{"name":"Drop Africa"},"license":"MIT","_id":"@drop-africa/drop-js@0.1.1","maintainers":[{"name":"fabala","email":"fabaladibbasey27@gmail.com"}],"homepage":"https://github.com/Fabaladibbasey/drop/tree/main/sdk/drop-js#readme","bugs":{"url":"https://github.com/Fabaladibbasey/drop/issues"},"dist":{"shasum":"7c3c61e6fc554d7c6e8e252d5b56b34602172f09","tarball":"https://registry.npmjs.org/@drop-africa/drop-js/-/drop-js-0.1.1.tgz","fileCount":8,"integrity":"sha512-V42sNhxzr63wuJlPPdaEHSjc1d7b4NZwGB9TS30/pJ/RdCa5lvamZHiltYkOZPLYbO1tiJ1vHCO3ML3tIc9zzA==","signatures":[{"sig":"MEUCIQCC0HbmqKPFCEcSJu/Lenj4UfxkZuCXx11rw5BOre7oNwIgV0pmKHTRRNUH2D+SXl94wFhsAd3GaGjA3JjRrHPAZR4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":476854},"main":"./dist/drop.umd.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/drop.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/drop.js","require":"./dist/drop.umd.cjs"}},"gitHead":"8abafcc6a98f006e5c06d776fa36407bc63d35d9","scripts":{"dev":"vite","test":"vitest run","build":"tsc && vite build","test:watch":"vitest"},"_npmUser":{"name":"fabala","email":"fabaladibbasey27@gmail.com"},"repository":{"url":"git+https://github.com/Fabaladibbasey/drop.git","type":"git"},"_npmVersion":"11.6.2","description":"Drop.js SDK - Embed payment QR codes and poll for payment status","directories":{},"_nodeVersion":"22.17.0","dependencies":{"qr-code-styling":"^1.9.2"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^6.0.0","jsdom":"^25.0.0","vitest":"^2.1.0","typescript":"^5.7.0","@types/jsdom":"^27.0.0","vite-plugin-dts":"^4.3.0"},"_npmOperationalInternal":{"tmp":"tmp/drop-js_0.1.1_1769910284775_0.2680332379811625","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@drop-africa/drop-js","version":"0.1.2","description":"Drop.js SDK - Embed payment QR codes and poll for payment status","type":"module","main":"./dist/drop.umd.cjs","module":"./dist/drop.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/drop.js","require":"./dist/drop.umd.cjs"}},"scripts":{"dev":"vite","build":"tsc && vite build","test":"vitest run","test:watch":"vitest"},"devDependencies":{"@types/jsdom":"^27.0.0","jsdom":"^25.0.0","typescript":"^5.7.0","vite":"^6.0.0","vite-plugin-dts":"^4.3.0","vitest":"^4.0.18"},"license":"MIT","keywords":["drop","payment","mobile-money","africa"],"author":{"name":"Drop Africa"},"repository":{"type":"git","url":"git+https://github.com/drop-africa/Drop.js-SDK.git"},"bugs":{"url":"https://github.com/drop-africa/Drop.js-SDK/issues"},"homepage":"https://drop.africa","dependencies":{"qr-code-styling":"^1.9.2"},"gitHead":"118a9e4af4f830c0a79cec3c5a3b65a5dc89bb65","_id":"@drop-africa/drop-js@0.1.2","_nodeVersion":"22.17.0","_npmVersion":"11.6.2","dist":{"integrity":"sha512-bckZ0B9i+Ic4/2sAGQfnx9H4S59Se6zjTnkbU/SfaCWyCS8POe+5Ye5Gt/QN2SUmzRGnWp2e01AbTeAkmQiFpw==","shasum":"a49e0d6973918eda5435e81b675a4dee36119b11","tarball":"https://registry.npmjs.org/@drop-africa/drop-js/-/drop-js-0.1.2.tgz","fileCount":9,"unpackedSize":483796,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCICe35ITzTUtqiddsi6MtHefGSd7++D9YAKA89ywqVKmgAiB6g6VD3ep1D6yNoLiVA14+Msuf6g2F3BpYEn3aC8MB0Q=="}]},"_npmUser":{"name":"fabala","email":"fabaladibbasey27@gmail.com"},"directories":{},"maintainers":[{"name":"fabala","email":"fabaladibbasey27@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/drop-js_0.1.2_1770252739584_0.8301639110113315"},"_hasShrinkwrap":false}},"time":{"created":"2026-02-01T01:44:44.698Z","modified":"2026-02-05T00:52:19.896Z","0.1.1":"2026-02-01T01:44:44.948Z","0.1.2":"2026-02-05T00:52:19.751Z"},"bugs":{"url":"https://github.com/drop-africa/Drop.js-SDK/issues"},"author":{"name":"Drop Africa"},"license":"MIT","homepage":"https://drop.africa","keywords":["drop","payment","mobile-money","africa"],"repository":{"type":"git","url":"git+https://github.com/drop-africa/Drop.js-SDK.git"},"description":"Drop.js SDK - Embed payment QR codes and poll for payment status","maintainers":[{"name":"fabala","email":"fabaladibbasey27@gmail.com"}],"readme":"# Drop.js SDK\r\n\r\nEmbed payment QR codes in your web app and poll for payment status changes in real-time.\r\n\r\n[![npm version](https://img.shields.io/npm/v/@drop-africa/drop-js.svg)](https://www.npmjs.com/package/@drop-africa/drop-js)\r\n[![npm bundle size](https://img.shields.io/bundlephobia/minzip/@drop-africa/drop-js)](https://bundlephobia.com/package/@drop-africa/drop-js)\r\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)\r\n\r\n## Features\r\n\r\n- **QR Code Rendering**: Scannable QR codes with customizable styling\r\n- **Polling**: Automatic status updates with configurable intervals\r\n- **Copyable Links**: Optional fallback for users who can't scan QR codes\r\n- **TypeScript Support**: Full type definitions included\r\n- **Validation**: Input validation with descriptive error messages\r\n- **Browser Compatible**: Works in modern browsers (Chrome, Firefox, Safari, Edge)\r\n- **Lightweight**: ~22KB gzipped (ESM), ~19KB gzipped (UMD)\r\n\r\n## Installation\r\n\r\n### NPM\r\n\r\n```bash\r\nnpm install @drop-africa/drop-js\r\n```\r\n\r\n### CDN (Browser)\r\n\r\n```html\r\n<script src=\"https://cdn.drop.africa/sdk/drop.js\"></script>\r\n```\r\n\r\n## Quick Start\r\n\r\n### CDN Usage (6 lines)\r\n\r\n```html\r\n<div id=\"payment-qr\"></div>\r\n\r\n<script src=\"https://cdn.drop.africa/sdk/drop.js\"></script>\r\n<script>\r\n  Drop.create({\r\n    clientSecret: 'pi_secret_your_payment_intent_secret',\r\n    instanceUrl: 'https://drop.africa/api/v1/payment-accounts/acc_123/payment-intents/pi_456',\r\n    containerId: 'payment-qr'\r\n  });\r\n</script>\r\n```\r\n\r\n### NPM/React Usage\r\n\r\n```typescript\r\nimport { Drop, PaymentStatuses } from '@drop-africa/drop-js';\r\n\r\nfunction PaymentPage() {\r\n  useEffect(() => {\r\n    const instance = await Drop.create({\r\n      clientSecret: 'pi_secret_your_payment_intent_secret',\r\n      instanceUrl: 'https://drop.africa/api/v1/payment-accounts/acc_123/payment-intents/pi_456',\r\n      containerId: 'payment-qr',\r\n      onStatusChange: (status) => {\r\n        if (status === PaymentStatuses.SUCCEEDED) {\r\n          console.log('Payment successful!');\r\n        }\r\n      }\r\n    });\r\n\r\n    return () => instance.destroy();\r\n  }, []);\r\n\r\n  return <div id=\"payment-qr\"></div>;\r\n}\r\n```\r\n\r\n## API Reference\r\n\r\n### `Drop.create(config: DropConfig): Promise<DropInstance>`\r\n\r\nCreates a Drop instance that renders a QR code and polls for payment status.\r\n\r\n#### Parameters\r\n\r\n| Parameter | Type | Required | Default | Description |\r\n|-----------|------|----------|---------|-------------|\r\n| `clientSecret` | `string` | ✅ | - | Payment intent client secret (starts with `pi_secret_`) |\r\n| `instanceUrl` | `string` | ✅ | - | Full URL to the payment intent resource |\r\n| `containerId` | `string` | ✅ | - | DOM element ID where QR code will be rendered |\r\n| `apiBaseUrl` | `string` | ❌ | `https://drop.africa` | Base URL for API requests |\r\n| `qrSize` | `number` | ❌ | `256` | QR code size in pixels (128-1024) |\r\n| `pollingInterval` | `number` | ❌ | `3000` | Polling interval in milliseconds (1000-60000) |\r\n| `showCopyableLink` | `boolean` | ❌ | `true` | Show copyable payment link below QR code |\r\n| `linkText` | `string` | ❌ | `\"Or paste this link:\"` | Text above copyable link (max 100 chars) |\r\n| `qrOptions.moduleColor` | `string` | ❌ | `hsl(160, 65%, 25%)` | QR code foreground color |\r\n| `qrOptions.backgroundColor` | `string` | ❌ | `hsl(0, 0%, 98%)` | QR code background color |\r\n| `qrOptions.cornerRadius` | `number` | ❌ | `0` | Corner radius for QR modules (0-1) |\r\n| `onStatusChange` | `(status) => void` | ❌ | - | Callback when payment status changes |\r\n| `onError` | `(error) => void` | ❌ | - | Callback when errors occur |\r\n| `onPoll` | `() => void` | ❌ | - | Callback on each polling attempt |\r\n\r\n#### Returns\r\n\r\n`Promise<DropInstance>` - Instance with `destroy()` and `getStatus()` methods\r\n\r\n#### Example\r\n\r\n```javascript\r\nconst instance = await Drop.create({\r\n  clientSecret: 'pi_secret_1234567890abcdef',\r\n  instanceUrl: 'https://drop.africa/api/v1/payment-accounts/acc_123/payment-intents/pi_456',\r\n  containerId: 'payment-qr',\r\n  qrSize: 512,\r\n  pollingInterval: 5000,\r\n  qrOptions: {\r\n    cornerRadius: 0.5,\r\n    moduleColor: '#00796B',\r\n    backgroundColor: '#F5F5F5'\r\n  },\r\n  linkText: 'Scan or paste this link',\r\n  onStatusChange: (status) => {\r\n    console.log('Payment status:', status);\r\n  },\r\n  onError: (error) => {\r\n    console.error('Error:', error.message);\r\n  }\r\n});\r\n```\r\n\r\n### `DropInstance`\r\n\r\n#### Methods\r\n\r\n##### `destroy(): void`\r\n\r\nStops polling and removes the QR code from the DOM.\r\n\r\n```javascript\r\ninstance.destroy();\r\n```\r\n\r\n##### `getStatus(): DropPaymentStatus`\r\n\r\nReturns the current payment status.\r\n\r\n```javascript\r\nconst status = instance.getStatus();\r\n// Returns: \"initiated\" | \"pending\" | \"succeeded\" | \"failed\" | \"cancelled\" | \"expired\"\r\n```\r\n\r\n## Configuration\r\n\r\n### Payment Statuses\r\n\r\n| Status | Description |\r\n|--------|-------------|\r\n| `initiated` | Payment intent created, waiting for customer action |\r\n| `pending` | Customer scanned QR code, payment processing |\r\n| `succeeded` | Payment completed successfully |\r\n| `failed` | Payment failed (insufficient funds, network error, etc.) |\r\n| `cancelled` | Payment cancelled by customer or merchant |\r\n| `expired` | Payment intent expired (typically after 24 hours) |\r\n\r\n### Color Formats\r\n\r\nSupported color formats for `moduleColor` and `backgroundColor`:\r\n\r\n- **Hex**: `#000`, `#000000`, `#AbC123`\r\n- **RGB**: `rgb(0, 0, 0)`, `rgb(255, 128, 64)`\r\n- **RGBA**: `rgba(0, 0, 0, 1)`, `rgba(255, 128, 64, 0.5)`\r\n- **HSL**: `hsl(0, 0%, 0%)`, `hsl(240, 100%, 50%)`\r\n- **HSLA**: `hsla(0, 0%, 0%, 1)`, `hsla(240, 100%, 50%, 0.5)`\r\n\r\n### Validation Constraints\r\n\r\nThe SDK validates all configuration parameters and throws `ValidationError` for invalid inputs:\r\n\r\n| Parameter | Constraint | Rationale |\r\n|-----------|-----------|-----------|\r\n| `clientSecret` | Min 10 chars, starts with `pi_secret_` | Catches auth errors early |\r\n| `qrSize` | 128-1024 pixels | Below 128 = hard to scan; above 1024 = memory issues |\r\n| `pollingInterval` | 1000-60000 ms | Prevents server DOS; maintains real-time UX |\r\n| `cornerRadius` | 0-1 | QR libraries use 0-1 range |\r\n| `moduleColor` | Valid color format | Must be hex, rgb, rgba, hsl, or hsla |\r\n| `backgroundColor` | Valid color format | Must be hex, rgb, rgba, hsl, or hsla |\r\n| `linkText` | Max 100 characters | Prevents UI layout breaking |\r\n\r\n## Error Handling\r\n\r\n### Validation Errors\r\n\r\n```javascript\r\nimport { Drop, ValidationError } from '@drop-africa/drop-js';\r\n\r\ntry {\r\n  await Drop.create({\r\n    clientSecret: 'invalid',\r\n    instanceUrl: '...',\r\n    containerId: 'qr'\r\n  });\r\n} catch (error) {\r\n  if (error instanceof ValidationError) {\r\n    console.error('Configuration error:', error.message);\r\n    // Output: \"clientSecret must be at least 10 characters long. Received length: 7\"\r\n  }\r\n}\r\n```\r\n\r\n### Runtime Errors\r\n\r\n```javascript\r\nDrop.create({\r\n  clientSecret: 'pi_secret_1234567890',\r\n  instanceUrl: '...',\r\n  containerId: 'payment-qr',\r\n  onError: (error) => {\r\n    switch (error.code) {\r\n      case 'NETWORK_ERROR':\r\n        console.error('Network issue:', error.message);\r\n        if (error.retryable) {\r\n          // Polling will automatically retry\r\n        }\r\n        break;\r\n      case 'AUTH_ERROR':\r\n        console.error('Invalid client secret');\r\n        break;\r\n      case 'RATE_LIMITED':\r\n        console.error('Too many requests');\r\n        break;\r\n      case 'NOT_FOUND':\r\n        console.error('Payment intent not found');\r\n        break;\r\n    }\r\n  }\r\n});\r\n```\r\n\r\n### Error Codes\r\n\r\n| Code | Description | Retryable |\r\n|------|-------------|-----------|\r\n| `NETWORK_ERROR` | Network connectivity issue | ✅ |\r\n| `AUTH_ERROR` | Invalid client secret | ❌ |\r\n| `RATE_LIMITED` | Too many polling requests | ✅ |\r\n| `NOT_FOUND` | Payment intent not found | ❌ |\r\n| `VALIDATION_ERROR` | Invalid configuration | ❌ |\r\n| `UNKNOWN` | Unexpected error | ❌ |\r\n\r\n### Using Constants\r\n\r\nFor type-safe handling, use the exported constants instead of string literals:\r\n\r\n```typescript\r\nimport { Drop, ErrorCodes, PaymentStatuses } from '@drop-africa/drop-js';\r\n\r\nDrop.create({\r\n  clientSecret: 'pi_secret_1234567890',\r\n  instanceUrl: '...',\r\n  containerId: 'payment-qr',\r\n  onStatusChange: (status) => {\r\n    if (status === PaymentStatuses.SUCCEEDED) {\r\n      console.log('Payment successful!');\r\n    }\r\n  },\r\n  onError: (error) => {\r\n    if (error.code === ErrorCodes.NETWORK_ERROR) {\r\n      console.error('Network issue:', error.message);\r\n    }\r\n  }\r\n});\r\n```\r\n\r\n## Browser Support\r\n\r\nDrop.js works in all modern browsers:\r\n\r\n- Chrome/Edge 90+\r\n- Firefox 88+\r\n- Safari 14+\r\n- Opera 76+\r\n\r\n**Not supported**: Internet Explorer (use a polyfill for Promise and fetch if needed)\r\n\r\n## TypeScript\r\n\r\nFull TypeScript definitions are included. Import types directly:\r\n\r\n```typescript\r\nimport { Drop, DropConfig, DropInstance, DropPaymentStatus, DropError, ErrorCodes, PaymentStatuses } from '@drop-africa/drop-js';\r\n\r\nconst config: DropConfig = {\r\n  clientSecret: 'pi_secret_1234567890',\r\n  instanceUrl: 'https://drop.africa/api/v1/payment-accounts/acc_123/payment-intents/pi_456',\r\n  containerId: 'payment-qr'\r\n};\r\n\r\nconst instance: DropInstance = await Drop.create(config);\r\nconst status: DropPaymentStatus = instance.getStatus();\r\n```\r\n\r\n## Examples\r\n\r\n### React Component\r\n\r\n```typescript\r\nimport { Drop, DropPaymentStatus, PaymentStatuses } from '@drop-africa/drop-js';\r\nimport { useEffect, useState } from 'react';\r\n\r\nexport function Payment({ clientSecret, instanceUrl }) {\r\n  const [status, setStatus] = useState<DropPaymentStatus>(PaymentStatuses.INITIATED);\r\n\r\n  useEffect(() => {\r\n    const instance = await Drop.create({\r\n      clientSecret,\r\n      instanceUrl,\r\n      containerId: 'payment-qr',\r\n      onStatusChange: setStatus\r\n    });\r\n\r\n    return () => instance.destroy();\r\n  }, [clientSecret, instanceUrl]);\r\n\r\n  return (\r\n    <div>\r\n      {status === PaymentStatuses.SUCCEEDED ? (\r\n        <p>Payment successful!</p>\r\n      ) : (\r\n        <div id=\"payment-qr\"></div>\r\n      )}\r\n    </div>\r\n  );\r\n}\r\n```\r\n\r\n### Vue Component\r\n\r\n```vue\r\n<template>\r\n  <div>\r\n    <div v-if=\"status === PaymentStatuses.SUCCEEDED\">Payment successful!</div>\r\n    <div v-else id=\"payment-qr\"></div>\r\n  </div>\r\n</template>\r\n\r\n<script setup>\r\nimport { Drop, PaymentStatuses } from '@drop-africa/drop-js';\r\nimport { ref, onMounted, onUnmounted } from 'vue';\r\n\r\nconst props = defineProps(['clientSecret', 'instanceUrl']);\r\nconst status = ref(PaymentStatuses.INITIATED);\r\nlet instance;\r\n\r\nonMounted(async () => {\r\n  instance = await Drop.create({\r\n    clientSecret: props.clientSecret,\r\n    instanceUrl: props.instanceUrl,\r\n    containerId: 'payment-qr',\r\n    onStatusChange: (newStatus) => {\r\n      status.value = newStatus;\r\n    }\r\n  });\r\n});\r\n\r\nonUnmounted(() => {\r\n  instance?.destroy();\r\n});\r\n</script>\r\n```\r\n\r\n### Vanilla JavaScript\r\n\r\n```html\r\n<!DOCTYPE html>\r\n<html>\r\n<head>\r\n  <title>Drop.js Payment</title>\r\n</head>\r\n<body>\r\n  <div id=\"payment-qr\"></div>\r\n  <div id=\"status\"></div>\r\n\r\n  <script src=\"https://cdn.drop.africa/sdk/drop.js\"></script>\r\n  <script>\r\n    const { PaymentStatuses } = Drop;\r\n\r\n    Drop.create({\r\n      clientSecret: 'pi_secret_1234567890abcdef',\r\n      instanceUrl: 'https://drop.africa/api/v1/payment-accounts/acc_123/payment-intents/pi_456',\r\n      containerId: 'payment-qr',\r\n      onStatusChange: (status) => {\r\n        document.getElementById('status').textContent = `Status: ${status}`;\r\n        if (status === PaymentStatuses.SUCCEEDED) {\r\n          alert('Payment successful!');\r\n        }\r\n      },\r\n      onError: (error) => {\r\n        console.error('Payment error:', error);\r\n      }\r\n    });\r\n  </script>\r\n</body>\r\n</html>\r\n```\r\n\r\n## Links\r\n\r\n- [Documentation](https://github.com/drop-africa/Drop.js-SDK#readme)\r\n- [GitHub Repository](https://github.com/drop-africa/Drop.js-SDK)\r\n- [npm Package](https://www.npmjs.com/package/@drop-africa/drop-js)\r\n- [Issues](https://github.com/drop-africa/Drop.js-SDK/issues)\r\n\r\n## License\r\n\r\nMIT\r\n","readmeFilename":"README.md"}