{"_id":"@afrokala/ads-sdk-react","name":"@afrokala/ads-sdk-react","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@afrokala/ads-sdk-react","version":"0.1.0","description":"Afrokala Ads SDK — React bindings. <AdsProvider>, <AdBanner>, <AdInline>, useInterstitial, useRewardedAd.","license":"UNLICENSED","repository":{"type":"git","url":"git+https://github.com/kumbiraibenjamin/afrokala-ads-sdk.git","directory":"packages/ads-sdk-react"},"type":"module","sideEffects":false,"engines":{"node":">=18"},"main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}},"./package.json":"./package.json"},"publishConfig":{"access":"public","provenance":false},"dependencies":{"@afrokala/ads-sdk":"0.1.0"},"peerDependencies":{"react":">=18","react-dom":">=18"},"devDependencies":{"@arethetypeswrong/cli":"^0.18.5","@testing-library/react":"^16.3.0","@types/react":"^18.3.18","@types/react-dom":"^18.3.5","@vitejs/plugin-react":"^4.3.4","eslint":"^9.17.0","eslint-plugin-react-hooks":"^5.1.0","jsdom":"^25.0.1","publint":"^0.3.22","react":"^18.3.1","react-dom":"^18.3.1","tsup":"^8.3.5","typescript":"^5.7.2","vitest":"^2.1.8","@afrokala/config":"0.0.0"},"scripts":{"build":"tsup","dev":"tsup --watch","lint":"eslint .","typecheck":"tsc --noEmit","test":"vitest run","check:pkg-hygiene":"publint && attw --pack ."},"_id":"@afrokala/ads-sdk-react@0.1.0","bugs":{"url":"https://github.com/kumbiraibenjamin/afrokala-ads-sdk/issues"},"homepage":"https://github.com/kumbiraibenjamin/afrokala-ads-sdk#readme","_integrity":"sha512-WVEq4XfQzRl/VkF0QUJgYPx++kQqDR07Nj2ERvzgZF7m8QEvp+g2KHFq1pyVHpsRQ0a2BvNz/asw6Dwj2sdieA==","_resolved":"C:\\Users\\kbdev\\AppData\\Local\\Temp\\f239f3a909d6916edbaa06c3ef79e3b6\\afrokala-ads-sdk-react-0.1.0.tgz","_from":"file:afrokala-ads-sdk-react-0.1.0.tgz","_nodeVersion":"22.13.1","_npmVersion":"11.4.1","dist":{"integrity":"sha512-WVEq4XfQzRl/VkF0QUJgYPx++kQqDR07Nj2ERvzgZF7m8QEvp+g2KHFq1pyVHpsRQ0a2BvNz/asw6Dwj2sdieA==","shasum":"568f9a5add55049435ca6f5606330cfbd0e0b14c","tarball":"https://registry.npmjs.org/@afrokala/ads-sdk-react/-/ads-sdk-react-0.1.0.tgz","fileCount":8,"unpackedSize":50868,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIFs8WZ2k6CRQkPnqvR4bdVnjlmO4TkXzRqc0DxGf2+l2AiBvO3VGVc+3cGKur9S2avyDKceq5Pw/GZVh0AIP1f0b4g=="}]},"_npmUser":{"name":"kumbiraibenjamin","email":"kbdeve@gmail.com"},"directories":{},"maintainers":[{"name":"kumbiraibenjamin","email":"kbdeve@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/ads-sdk-react_0.1.0_1785171219570_0.9510338205205031"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-27T16:53:39.355Z","0.1.0":"2026-07-27T16:53:39.716Z","modified":"2026-07-27T16:53:39.961Z"},"maintainers":[{"name":"kumbiraibenjamin","email":"kbdeve@gmail.com"}],"description":"Afrokala Ads SDK — React bindings. <AdsProvider>, <AdBanner>, <AdInline>, useInterstitial, useRewardedAd.","homepage":"https://github.com/kumbiraibenjamin/afrokala-ads-sdk#readme","repository":{"type":"git","url":"git+https://github.com/kumbiraibenjamin/afrokala-ads-sdk.git","directory":"packages/ads-sdk-react"},"bugs":{"url":"https://github.com/kumbiraibenjamin/afrokala-ads-sdk/issues"},"license":"UNLICENSED","readme":"# @afrokala/ads-sdk-react\r\n\r\nReact bindings for the Afrokala Ads SDK: `<AdsProvider>`, `<AdBanner>`, `<AdInline>`,\r\n`useInterstitial`, `useRewardedAd` — thin, tree-shakeable, SSR-safe wrappers over\r\n[`@afrokala/ads-sdk`](../ads-sdk). No serving logic lives in this package; every component/hook is a\r\nmount/lifecycle wrapper over the core `AdsClient` (peer dep `react >= 18`).\r\n\r\n## Install\r\n\r\n```bash\r\npnpm add @afrokala/ads-sdk-react\r\n```\r\n\r\n## Quick start\r\n\r\nProvider → one banner, in under 10 lines:\r\n\r\n```tsx\r\nimport { AdsProvider, AdBanner } from \"@afrokala/ads-sdk-react\";\r\n\r\nexport function App() {\r\n  return (\r\n    <AdsProvider appId=\"your-app-id\" endpointBase=\"https://serve.afrokala.example\">\r\n      <AdBanner unitId=\"home_banner\" />\r\n    </AdsProvider>\r\n  );\r\n}\r\n```\r\n\r\n`<AdsProvider>` takes every `AdsClientOptions` field from the core package (`onError`, `onOpenUrl`,\r\n`testMode`, `prefetch`, `storage`, …) as flattened props alongside `children`.\r\n\r\n## Components + hooks\r\n\r\n```tsx\r\nimport {\r\n  AdsProvider,\r\n  AdBanner,\r\n  AdInline,\r\n  useInterstitial,\r\n  useRewardedAd,\r\n} from \"@afrokala/ads-sdk-react\";\r\n\r\nfunction Feed() {\r\n  // Inline (in-feed) unit — `mode` is an advisory render hint (\"block\" | \"interstitial\").\r\n  return <AdInline unitId=\"feed_slot\" mode=\"block\" />;\r\n}\r\n\r\nfunction InterstitialButton() {\r\n  const { state, show } = useInterstitial(\"interstitial_unit\");\r\n  return (\r\n    <button disabled={state === \"loading\" || state === \"showing\"} onClick={() => void show()}>\r\n      Show interstitial\r\n    </button>\r\n  );\r\n}\r\n\r\nfunction RewardedButton() {\r\n  const { state, serveId, load, show, onReward, onClose } = useRewardedAd(\"rewarded_unit\");\r\n\r\n  onReward((meta) => {\r\n    // ADVISORY ONLY — a UX hint that playback completed. Server-Side Verification (SSV) is the\r\n    // SOLE authoritative grant path; never credit a user on this callback alone.\r\n    console.log(\"advisory reward\", meta);\r\n  });\r\n  onClose((info) => console.log(\"closed\", info.state, \"rewarded(advisory)=\", info.rewarded));\r\n\r\n  if (state === \"idle\") return <button onClick={load}>Load rewarded ad</button>;\r\n  if (state === \"loaded\") return <button onClick={show}>Watch for a reward</button>;\r\n  return <p>{state}</p>;\r\n}\r\n```\r\n\r\n- `<AdBanner unitId sectionId? className? style?>` / `<AdInline unitId mode? sectionId? className? style?>`\r\n  render into an owned `<div>`, mount on effect, and fully tear down (impression observer, refresh\r\n  timer, DOM) on unmount or when `unitId`/`mode`/`sectionId` changes.\r\n- `useInterstitial(unitId)` → `{ state, show, close }`. `state` is one of\r\n  `\"idle\" | \"loading\" | \"showing\" | \"closed\" | \"no-fill\"`. `show()` requests a decision and displays\r\n  the full-screen overlay in one call; unmounting mid-load or while showing tears the overlay down.\r\n- `useRewardedAd(unitId)` → `{ state, serveId, load, show, onReward, onClose }`. `state` mirrors the\r\n  core state machine (`\"idle\" | \"loading\" | \"loaded\" | \"showing\" | \"completed\" | \"skipped\" | \"closed\"\r\n  | \"error\"`). Call `load()` to start loading, `show()` once `state === \"loaded\"`. `serveId` is\r\n  `null` until a fill loads (and stays `null` on a no-fill) — it's an attribution HINT for binding a\r\n  reward intent to the exact serve, not proof of anything: SSV remains the only money-grade signal.\r\n\r\n## StrictMode + Capacitor WebView\r\n\r\n`<AdsProvider>` constructs exactly one `AdsClient` per mounted provider (a ref-guarded singleton —\r\nsafe under React 18 Strict Mode's dev-only double-render) and starts/stops its background event-\r\noutbox drain via the client's idempotent `resume()`/`pause()` pair, so Strict Mode's synthetic\r\nmount→unmount→mount settles to one running client with one coalesced decision request per unit — no\r\nduplicate serves, no leaked timers/listeners in dev.\r\n\r\nNothing in this package touches `window`/`document` at import time (SSR-safe), and every entry point\r\ncarries a `\"use client\"` marker for RSC frameworks. In a Capacitor WebView, wire `onOpenUrl` to the\r\n[`@capacitor/browser`](https://capacitorjs.com/docs/apis/browser) plugin so click-throughs open in\r\nthe system browser instead of the WebView:\r\n\r\n```tsx\r\nimport { Browser } from \"@capacitor/browser\";\r\nimport { AdsProvider } from \"@afrokala/ads-sdk-react\";\r\n\r\n<AdsProvider\r\n  appId=\"your-app-id\"\r\n  endpointBase=\"https://serve.afrokala.example\"\r\n  onOpenUrl={(url) => void Browser.open({ url })}\r\n>\r\n  {/* ... */}\r\n</AdsProvider>;\r\n```\r\n\r\n## Scripts\r\n\r\n| Script | What it does |\r\n|---|---|\r\n| `build` | `tsup` — emits ESM + CJS (`dist/index.{js,cjs}`), each carrying a `\"use client\"` marker |\r\n| `test` | `vitest run` (jsdom + `@testing-library/react`) |\r\n| `typecheck` | `tsc --noEmit` — also statically checks `src/type-surface.test.tsx`'s API-contract assertions |\r\n| `lint` | `eslint .` |\r\n","readmeFilename":"README.md","_rev":"1-601d0ffe69e071920f243445097b4ae3"}