npm package: @stedion/loyalty-sdk
Description: SDK supporting Stedion loyalty API. Supports Typescript.
Latest version: 0.2.0

# @stedion/loyalty-sdk

A lightweight TypeScript SDK for interacting with Stedion Loyalty API (integrated with Antavo). It provides typed helpers for auth headers, request handling, and response parsing.

## Requirements
- Node.js >= 18 (global `fetch` and `Response` available)
- ESM-only package (`type": "module"`)

## Installation

```sh
npm install @stedion/loyalty-sdk
```

## Getting Started

```ts
import { LoyaltySdk } from '@stedion/loyalty-sdk';

const sdk = new LoyaltySdk({
	access_token: '<JWT access token>',
	api_url: 'https://api.example.com',
	accept_lang: 'en',
});

// Example: fetch current user profile
const me = await sdk.getMyProfile();
console.log(me.email);
```

### Error handling
All SDK methods may throw:
- `Response` when the HTTP response is not ok (status != 200 series)
- `Error` for network/runtime issues

Typical pattern:
```ts
try {
	const activities = await sdk.getMyActivities();
} catch (e) {
	if (e instanceof Response) {
		console.error('HTTP', e.status, await e.text());
	} else if (e instanceof Error) {
		console.error('Error', e.message);
	} else {
		console.error('Unknown error', e);
	}
}
```

## Constructor

```ts
new LoyaltySdk(options: LoyaltySDKOptions)
```

Options:
- `access_token: string` – Bearer token (JWT)
- `api_url: string` – Base URL of the Stedion Loyalty API
- `accept_lang: string` – Preferred language (e.g., `en`)

Instance getters:
- `accept_lang: string`
- `api_url: string`
- `access_token: string`
- `decoded_token_payload: object` – parsed JWT payload
- `user_id: string` – `sub` from token payload

## Methods overview
Note: All methods throw `{Response|Error}` on failure.

- `getTiers(): Promise<TierGroup>`
- `getMyProfile(): Promise<User>`
- `getMyChallenges(): Promise<Challenge[]>`
- `getMyQuizzes(): Promise<Quiz[]>`
- `getQuizDetails(quizId: string): Promise<QuizDetails>`
- `answerQuiz(quizId: string, answerOrdinal: number): Promise<QuizEarnResponse>`
- `getMyRewards(): Promise<Reward[]>`
- `getMyClaimedRewards(fromCache?: boolean): Promise<Reward[]>`
- `claimReward(rewardId: string): Promise<RewardClaimResponse>`
- `getDownloadableReward(rewardId: string): Promise<Response>` – raw Response for download flows
- `optin(optin_data: OptinRequestBody): Promise<OptinResponse>`
- `visit(url: string, type: string): Promise<VisitResponse>`
- `getEntities(params: GetEntitiesParams, otherHeaders?: Record<string,string>): Promise<any[]>`
- `getMyContests(fields: string[]): Promise<Contest[]>`
- `enterContest(contestId: string, count: number): Promise<any>`
- `getMyActivities(params?: getMyActivitiesParams, otherHeaders?: Record<string,string>): Promise<ActivityHistory[]>`
- `getMyEvents(params: getMyEventsParams, otherHeaders?: Record<string,string>): Promise<Activity[]>`

Low-level:
- `get(path: string, queryParams?: Record<string,queryStringParam>, otherHeaders?: Record<string,string>): Promise<Response>` – throws `Response` if `!ok`
- `post(path: string, body?: string|object): Promise<Response>` – JSON by default

## Examples

List challenges:
```ts
const challenges = await sdk.getMyChallenges();
for (const ch of challenges) {
  console.log(ch.title, ch.points);
}
```

Claim a reward:
```ts
const claim = await sdk.claimReward('<reward-id>');
console.log('Coupon code:', claim.coupon.code);
```

Fetch events with filters:
```ts
const events = await sdk.getMyEvents({ actions: ['reward', 'quiz'], limit: 20, order: 'desc' });
console.log('Events:', events.length);
```

Get entities with type safety:
```ts
// Standard module/entity combinations with autocomplete
const challenges = await sdk.getEntities({ 
  module_entity: 'challenges/challenge', 
  limit: 10 
});

// Custom entities for flexible modules
const customData = await sdk.getEntities({ 
  module_entity: 'custom/user-preferences', 
  additional_queries: { filter: 'active' }
});
```

### Available Module/Entity Combinations

The `getEntities` method accepts the following `module_entity` values:

**Standard modules:**
- `'challenges/challenge'` - Challenge activities
- `'contests/contest'` - Contest activities  
- `'coupons/pool'` - Coupon pools
- `'core/transaction'` - Transaction records
- `'core/customer'` - Customer data
- `'core/customer-list'` - Customer lists
- `'profiling/flow'` - Profiling flows
- `'cards/card'` - Card entities
- `'offers/offer'` - Offer entities
- `'accounts/account'` - Account information
- `'prize-wheels/wheel'` - Prize wheel configurations
- `'products/product'` - Product catalog
- `'rewards/reward'` - Reward entities
- `'stores/store'` - Store locations
- `'tiers/tier'` - Tier configurations

**Custom module:**
- `'custom/{entity_name}'` - Any custom entity name (e.g., `'custom/user-preferences'`, `'custom/survey-responses'`)

The `custom` module provides flexibility to retrieve any custom entities that may be defined in your loyalty platform configuration. This allows the SDK to work with platform-specific data structures while maintaining type safety through TypeScript's template literal types.

## Publishing
- ESM-only; compiled JS and types are emitted to package root
- `prepare` and `prepublishOnly` run `npm run build`
- Scoped package is configured for public publish (`publishConfig.access = public`)

## License
MIT