{"_id":"@afrokala/ads-sdk-vue","name":"@afrokala/ads-sdk-vue","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@afrokala/ads-sdk-vue","version":"0.1.0","description":"Afrokala Ads SDK — Vue 3 bindings. AfrokalaAds plugin, <AdBanner>, <AdInline>, useInterstitial, useRewardedAd.","license":"UNLICENSED","repository":{"type":"git","url":"git+https://github.com/kumbiraibenjamin/afrokala-ads-sdk.git","directory":"packages/ads-sdk-vue"},"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":{"vue":"^3.4"},"devDependencies":{"@arethetypeswrong/cli":"^0.18.5","@vue/test-utils":"^2.4.6","eslint":"^9.17.0","eslint-plugin-vue":"^9.32.0","jsdom":"^25.0.1","publint":"^0.3.22","tsup":"^8.3.5","typescript":"^5.7.2","vitest":"^2.1.8","vue":"^3.5.13","@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-vue@0.1.0","bugs":{"url":"https://github.com/kumbiraibenjamin/afrokala-ads-sdk/issues"},"homepage":"https://github.com/kumbiraibenjamin/afrokala-ads-sdk#readme","_integrity":"sha512-pNG8cUmg7LcbaHKNapKjpYOUYt/kWzM6lI/aeeUQXK+iSYGQNzsbh6LWJ0kVwkDjjPalBhbRLPJivXmN6gjO4g==","_resolved":"C:\\Users\\kbdev\\AppData\\Local\\Temp\\73192f498db6a1199d60402649c65078\\afrokala-ads-sdk-vue-0.1.0.tgz","_from":"file:afrokala-ads-sdk-vue-0.1.0.tgz","_nodeVersion":"22.13.1","_npmVersion":"11.4.1","dist":{"integrity":"sha512-pNG8cUmg7LcbaHKNapKjpYOUYt/kWzM6lI/aeeUQXK+iSYGQNzsbh6LWJ0kVwkDjjPalBhbRLPJivXmN6gjO4g==","shasum":"28672fb1c9750151c274f5ec7b3ae1630101508d","tarball":"https://registry.npmjs.org/@afrokala/ads-sdk-vue/-/ads-sdk-vue-0.1.0.tgz","fileCount":8,"unpackedSize":58428,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIA+CdOuqos9gnP68anpycMNfF9nyjDzYERPsEzgxfDGTAiBoQzZtX/6/DiGp/zd84rWAsnzNwhBfu4vD/eWQTxrhmw=="}]},"_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-vue_0.1.0_1785172109522_0.785001261313004"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-27T17:08:29.385Z","0.1.0":"2026-07-27T17:08:29.683Z","modified":"2026-07-27T17:08:29.905Z"},"maintainers":[{"name":"kumbiraibenjamin","email":"kbdeve@gmail.com"}],"description":"Afrokala Ads SDK — Vue 3 bindings. AfrokalaAds plugin, <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-vue"},"bugs":{"url":"https://github.com/kumbiraibenjamin/afrokala-ads-sdk/issues"},"license":"UNLICENSED","readme":"# @afrokala/ads-sdk-vue\r\n\r\nVue 3 bindings for the Afrokala Ads SDK: the `AfrokalaAds` plugin, `<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/composable\r\nis a mount/lifecycle wrapper over the core `AdsClient` (peer dep `vue >= 3.4`).\r\n\r\n## Install\r\n\r\n```bash\r\npnpm add @afrokala/ads-sdk-vue\r\n```\r\n\r\n## Quick start\r\n\r\nInstall the plugin → one banner, in under 10 lines:\r\n\r\n```ts\r\nimport { createApp } from \"vue\";\r\nimport { AfrokalaAds, AdBanner } from \"@afrokala/ads-sdk-vue\";\r\nimport App from \"./App.vue\";\r\n\r\ncreateApp(App)\r\n  .use(AfrokalaAds, { appId: \"your-app-id\", endpointBase: \"https://serve.afrokala.example\" })\r\n  .mount(\"#app\");\r\n```\r\n\r\n```vue\r\n<template>\r\n  <AdBanner unit-id=\"home_banner\" />\r\n</template>\r\n\r\n<script setup>\r\nimport { AdBanner } from \"@afrokala/ads-sdk-vue\";\r\n</script>\r\n```\r\n\r\n`app.use(AfrokalaAds, options)` takes every `AdsClientOptions` field from the core package\r\n(`onError`, `onOpenUrl`, `testMode`, `prefetch`, `storage`, …).\r\n\r\n## Components + composables\r\n\r\n```vue\r\n<script setup>\r\nimport { AdBanner, AdInline, useInterstitial, useRewardedAd } from \"@afrokala/ads-sdk-vue\";\r\n\r\nconst interstitial = useInterstitial(\"interstitial_unit\");\r\nconst rewarded = useRewardedAd(\"rewarded_unit\");\r\n\r\nrewarded.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\nrewarded.onClose((info) => console.log(\"closed\", info.state, \"rewarded(advisory)=\", info.rewarded));\r\n</script>\r\n\r\n<template>\r\n  <!-- Inline (in-feed) unit — `mode` is an advisory render hint (\"block\" | \"interstitial\"). -->\r\n  <AdInline unit-id=\"feed_slot\" mode=\"block\" />\r\n\r\n  <button :disabled=\"interstitial.state.value === 'loading' || interstitial.state.value === 'showing'\"\r\n          @click=\"interstitial.show()\">\r\n    Show interstitial\r\n  </button>\r\n  <p>{{ interstitial.state.value }}</p>\r\n\r\n  <button v-if=\"rewarded.state.value === 'idle'\" @click=\"rewarded.load()\">Load rewarded ad</button>\r\n  <button v-else-if=\"rewarded.state.value === 'loaded'\" @click=\"rewarded.show()\">Watch for a reward</button>\r\n  <p v-else>{{ rewarded.state.value }}</p>\r\n</template>\r\n```\r\n\r\n- `<AdBanner unit-id sectionId?>` / `<AdInline unit-id mode? sectionId?>` render into an owned\r\n  `<div>`, mount on the root element existing, and fully tear down (impression observer, refresh\r\n  timer, DOM) on unmount or when `unitId`/`mode`/`sectionId` changes. `class`/`style` fall through\r\n  to the root element — Vue's default single-root attribute inheritance — so no dedicated props are\r\n  needed for them (unlike the React package, which takes explicit `className`/`style` props).\r\n- `useInterstitial(unitId)` → `{ state, show, close }`, `state` a `Ref<\"idle\" | \"loading\" | \"showing\"\r\n  | \"closed\" | \"no-fill\">`. `show()` requests a decision and displays the full-screen overlay in one\r\n  call; the composable's owning component unmounting mid-load or while showing tears the overlay down.\r\n- `useRewardedAd(unitId)` → `{ state, serveId, load, show, onReward, onClose }`, `state`/`serveId`\r\n  are `Ref`s mirroring the core state machine (`\"idle\" | \"loading\" | \"loaded\" | \"showing\" |\r\n  \"completed\" | \"skipped\" | \"closed\" | \"error\"`). Call `load()` to start loading, `show()` once\r\n  `state.value === \"loaded\"`. `serveId.value` is `null` until a fill loads (and stays `null` on a\r\n  no-fill) — an attribution HINT for binding a reward intent to the exact serve, not proof of\r\n  anything: SSV remains the only money-grade signal.\r\n- `unitId` accepts a plain `string` or a `Ref`/getter (`MaybeRefOrGetter<string>`) — pass a ref to\r\n  swap units on the same composable instance instead of re-mounting.\r\n\r\n## Nuxt / SSR\r\n\r\nNothing in this package touches `window`/`document` at import time. Install the plugin in a Nuxt\r\nplugin file (`plugins/ads-sdk.client.ts` for client-only, or a universal plugin if you want the\r\nprovider available during SSR render — the underlying `AdsClient` itself guards every DOM access):\r\n\r\n```ts\r\n// plugins/ads-sdk.ts\r\nimport { AfrokalaAds } from \"@afrokala/ads-sdk-vue\";\r\n\r\nexport default defineNuxtPlugin((nuxtApp) => {\r\n  nuxtApp.vueApp.use(AfrokalaAds, {\r\n    appId: \"your-app-id\",\r\n    endpointBase: \"https://serve.afrokala.example\",\r\n  });\r\n});\r\n```\r\n\r\nNuxt creates and tears down one Vue app per SSR request; `AfrokalaAds` wraps `app.unmount` to stop\r\nthe client's background event-outbox drain timer/online listener first, so nothing outlives its\r\nrequest. `app.use(AfrokalaAds, …)` called twice on the same app (e.g. HMR, a duplicated plugin\r\nregistration) is a no-op past the first call — only one `AdsClient` is ever constructed per app.\r\n\r\nIn 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```ts\r\nimport { Browser } from \"@capacitor/browser\";\r\n\r\napp.use(AfrokalaAds, {\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\r\n## Scripts\r\n\r\n| Script | What it does |\r\n|---|---|\r\n| `build` | `tsup` — emits ESM + CJS (`dist/index.{js,cjs}`) |\r\n| `test` | `vitest run` (jsdom + `@vue/test-utils`) |\r\n| `typecheck` | `tsc --noEmit` — also statically checks `src/type-surface.test.ts`'s API-contract assertions |\r\n| `lint` | `eslint .` |\r\n","readmeFilename":"README.md","_rev":"1-7c120511e83b05f3596b11b916e16146"}