{"_id":"@budgetree/rewards-sdk","name":"@budgetree/rewards-sdk","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@budgetree/rewards-sdk","version":"0.1.0","description":"Lightweight React Native client for rewards APIs (balance, catalog, earn, redeem).","main":"dist/index.js","module":"dist/index.js","types":"dist/index.d.ts","react-native":"src/index.ts","scripts":{"build":"tsc -p tsconfig.build.json","prepare":"npm run build","typecheck":"tsc -p tsconfig.json --noEmit"},"keywords":["react-native","rewards","loyalty","points"],"peerDependencies":{"react":">=18.0.0","react-native":">=0.72.0"},"devDependencies":{"@types/react":"^18.3.12","typescript":"^5.9.3"},"license":"MIT","gitHead":"d768c98b0cb03b641663edb3e356ba407a45145d","_id":"@budgetree/rewards-sdk@0.1.0","_nodeVersion":"24.15.0","_npmVersion":"11.12.1","dist":{"integrity":"sha512-GkTeUJ5NHIA+wKNikcF2MAiLqCug5YdZlNN0jSvM6RWuoGEPsPiWDz43vUFkCaZNQQG23/tp50gRe0PMz9uQpw==","shasum":"b1c5532deaa3414534cf6b360d5f48c85be8ffeb","tarball":"https://registry.npmjs.org/@budgetree/rewards-sdk/-/rewards-sdk-0.1.0.tgz","fileCount":31,"unpackedSize":75441,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCGl+6XJ/KB76nb1qw1oNWMA1QhKWfZg4H60g/G7woTwQIhANlYKWJ6iYy+QaQSRNmnOyZAKKHHb4VvhMwdbqmOhovh"}]},"_npmUser":{"name":"rajatv7865","email":"rajatv785v@gmail.com"},"directories":{},"maintainers":[{"name":"rajatv7865","email":"rajatv785v@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/rewards-sdk_0.1.0_1778899455098_0.3484437024500866"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-16T02:44:14.983Z","0.1.0":"2026-05-16T02:44:15.326Z","modified":"2026-05-16T02:44:15.597Z"},"maintainers":[{"name":"rajatv7865","email":"rajatv785v@gmail.com"}],"description":"Lightweight React Native client for rewards APIs (balance, catalog, earn, redeem).","keywords":["react-native","rewards","loyalty","points"],"license":"MIT","readme":"# react-native-rewards-sdk\n\nSmall TypeScript client for a **rewards REST API** in React Native: balance, catalog, transactions, earn events, and redemptions. Ships as a library you install into your app (this repo is not a standalone runnable app).\n\n## Requirements\n\n- React 18+\n- React Native 0.72+ (uses the global `fetch` available in modern RN)\n\n## Install\n\n### From a local folder (development)\n\nIn your React Native project:\n\n```bash\nnpm install /absolute/path/to/sdk\n```\n\nOr add to `package.json`:\n\n```json\n\"dependencies\": {\n  \"react-native-rewards-sdk\": \"file:../sdk\"\n}\n```\n\nThen install as usual. The package runs `prepare` on install, which builds `dist/`.\n\n### From this repo before publishing\n\n```bash\ncd /path/to/sdk\nnpm install\nnpm run build\n```\n\nUseful scripts:\n\n| Command        | Description                    |\n| -------------- | ------------------------------ |\n| `npm run build` | Compile `src/` → `dist/`      |\n| `npm run typecheck` | Typecheck without emitting |\n\n## Quick start\n\nWrap your app (or a subtree) with `RewardsProvider`. Pass your API base URL and how to attach auth headers.\n\n```tsx\nimport {\n  RewardsProvider,\n  useRewardBalance,\n  useRewardsActions,\n} from \"react-native-rewards-sdk\";\n\nexport function App() {\n  return (\n    <RewardsProvider\n      baseUrl=\"https://api.example.com\"\n      getHeaders={async () => ({\n        Authorization: `Bearer ${await getAccessToken()}`,\n      })}\n    >\n      <HomeScreen />\n    </RewardsProvider>\n  );\n}\n\nfunction HomeScreen() {\n  const { data, loading, error, refresh } = useRewardBalance();\n  const { earn, redeem, pending } = useRewardsActions();\n\n  if (loading && !data) return <Text>Loading…</Text>;\n  if (error) return <Text>{error.message}</Text>;\n  if (!data) return null;\n\n  return (\n    <>\n      <Text>Points: {data.points}</Text>\n      <Button title=\"Refresh\" onPress={refresh} />\n      <Button\n        title=\"Earn (example)\"\n        disabled={pending}\n        onPress={() => earn({ eventName: \"app_open\" }).then(() => refresh())}\n      />\n      <Button\n        title=\"Redeem (example)\"\n        disabled={pending}\n        onPress={() =>\n          redeem({ rewardId: \"reward_123\" }).then(() => refresh())\n        }\n      />\n    </>\n  );\n}\n```\n\nKeep `getHeaders` **stable** when possible (for example wrap it in `useCallback` in the parent) so you do not recreate the client on every render.\n\n## Hooks\n\n| Hook                     | Purpose |\n| ------------------------ | ------- |\n| `useRewardsClient()`     | Returns the shared `RewardsClient` (must be inside `RewardsProvider`). |\n| `useRewardBalance()`     | Loads balance: `{ data, loading, error, refresh }`. |\n| `useRewardCatalog()`     | Loads catalog array: same shape as balance hook. |\n| `useGiftCards()`         | Loads gift cards for `GiftCardsScreen`. |\n| `useOrders()`            | Loads `RewardOrder[]` for `OrdersScreen`. |\n| `useRewardTransactions(limit?)` | First page of transactions + `nextCursor` and `loadMore()`. |\n| `useRewardsActions()`    | `{ earn, redeem, pending }` for mutations without auto-refetch. |\n\n`AsyncState` from the package is `{ data, loading, error, refresh }`.\n\n## Using the client without React\n\n```ts\nimport { RewardsClient } from \"react-native-rewards-sdk\";\n\nconst client = new RewardsClient({\n  baseUrl: \"https://api.example.com\",\n  getHeaders: () => ({ Authorization: \"Bearer …\" }),\n});\n\nconst balance = await client.getBalance();\nawait client.earnEvent({ eventName: \"purchase\", properties: { sku: \"abc\" } });\n```\n\n## Default API shape\n\nThe client expects **JSON** responses. Default paths (all under `baseUrl`):\n\n| Method | Path | Notes |\n| ------ | ---- | ----- |\n| `GET`  | `/v1/rewards/balance` | `RewardBalance` |\n| `GET`  | `/v1/rewards/catalog` | `RewardCatalogItem[]` |\n| `GET`  | `/v1/rewards/gift-cards` | `GiftCard[]` |\n| `GET`  | `/v1/rewards/orders` | `RewardOrder[]` |\n| `GET`  | `/v1/rewards/transactions?limit&cursor` | `{ items: RewardTransaction[]; nextCursor?: string }` |\n| `POST` | `/v1/rewards/earn` | Body: `EarnEventInput`; response treated as `RewardBalance` |\n| `POST` | `/v1/rewards/redeem` | Body: `RedeemInput`; response: `RedeemResult` |\n\nTypes match the field names above (`points`, `costPoints`, `eventName`, `rewardId`, etc.). If your backend uses different URLs or JSON shapes, override `paths` and/or adapt your server to these types.\n\n### Custom paths\n\n```tsx\n<RewardsProvider\n  baseUrl=\"https://api.example.com\"\n  paths={{\n    balance: \"/api/me/points\",\n    catalog: \"/api/rewards/shop\",\n    giftCards: \"/api/rewards/gift-cards\",\n    orders: \"/api/me/orders\",\n    transactions: \"/api/me/history\",\n    earn: \"/api/events\",\n    redeem: \"/api/redeem\",\n  }}\n  getHeaders={getHeaders}\n>\n  {children}\n</RewardsProvider>\n```\n\nExport `defaultPaths` from the package if you want to spread and override only one segment.\n\n## Errors\n\nFailed responses throw `RewardsRequestError` (extends `Error`):\n\n- `status` — HTTP status code  \n- `message` — from JSON `message` when present, otherwise status text  \n- `body` — parsed JSON when possible  \n\n```ts\nimport { RewardsRequestError } from \"react-native-rewards-sdk\";\n\ntry {\n  await client.redeem({ rewardId: \"x\" });\n} catch (e) {\n  if (e instanceof RewardsRequestError) {\n    console.warn(e.status, e.body);\n  }\n}\n```\n\n## Testing\n\nPass a stub `fetchImpl` in config to avoid the network:\n\n```ts\nconst client = new RewardsClient({\n  baseUrl: \"https://example.com\",\n  fetchImpl: async () =>\n    new Response(JSON.stringify({ points: 100 }), { status: 200 }),\n});\n```\n\n## License\n\nMIT\n","readmeFilename":"README.md","_rev":"1-d71e0424356497fee39e2094ff2ef496"}