UNPKG

react-native-nami-sdk

Version:

React Native SDK for Nami - No-code paywall and onboarding flows with A/B testing.

529 lines (484 loc) 13.1 kB
export type NamiConfiguration = { appPlatformID: string; logLevel: string; namiCommands?: string[]; namiLanguageCode?: NamiLanguageCodes; initialConfig?: string; }; export type NamiLanguageCodes = | 'af' | 'ar' | 'ar-dz' | 'ast' | 'az' | 'bg' | 'be' | 'bn' | 'br' | 'bs' | 'ca' | 'cs' | 'cy' | 'da' | 'de' | 'dsb' | 'el' | 'en' | 'en-au' | 'en-gb' | 'eo' | 'es' | 'es-ar' | 'es-co' | 'es-mx' | 'es-ni' | 'es-ve' | 'et' | 'eu' | 'fa' | 'fi' | 'fr' | 'fy' | 'ga' | 'gd' | 'gl' | 'he' | 'hi' | 'hr' | 'hsb' | 'hu' | 'hy' | 'ia' | 'id' | 'ig' | 'io' | 'is' | 'it' | 'ja' | 'ka' | 'kab' | 'kk' | 'km' | 'kn' | 'ko' | 'ky' | 'lb' | 'lt' | 'lv' | 'mk' | 'ml' | 'mn' | 'mr' | 'my' | 'nb' | 'ne' | 'nl' | 'nn' | 'os' | 'pa' | 'pl' | 'pt' | 'pt-br' | 'ro' | 'ru' | 'sk' | 'sl' | 'sq' | 'sr' | 'sr-latn' | 'sv' | 'sw' | 'ta' | 'te' | 'tg' | 'th' | 'tk' | 'tr' | 'tt' | 'udm' | 'uk' | 'ur' | 'uz' | 'vi' | 'zh-hans' | 'zh-hant'; export type NamiSKU = { id: string; name?: string; skuId: string; appleProduct?: AppleProduct; googleProduct?: GoogleProduct; amazonProduct?: AmazonProduct; type: NamiSKUType; promoId?: string | null; promoToken?: string | null; promoOffer?: { [key: string]: string } | null; }; export enum NamiPurchaseState { PENDING = 'pending', PURCHASED = 'purchased', CONSUMED = 'consumed', RESUBSCRIBED = 'resubscribed', UNSUBSCRIBED = 'unsubscribed', DEFERRED = 'deferred', FAILED = 'failed', CANCELLED = 'cancelled', UNKNOWN = 'unknown', } export enum NamiRestorePurchasesState { STARTED = 'started', FINISHED = 'finished', ERROR = 'error', } export type NamiSKUType = 'unknown' | 'one_time_purchase' | 'subscription'; export type AppleProduct = { localizedDescription: string; localizedMultipliedPrice: string; localizedPrice: string; localizedTitle: string; price: string; priceCurrency: string; priceLanguage: string; }; export type GoogleProduct = Record<string, never>; export type AmazonProduct = Record<string, never>; // NamiCampaignManager export type NamiCampaign = { name: string; rule: string; segment: string; paywall: string; type: NamiCampaignRuleType; value?: string | null; form_factors: NamiFormFactor[]; external_segment: string | null; }; export enum NamiCampaignRuleType { DEFAULT = 'default', LABEL = 'label', UNKNOWN = 'unknown', URL = 'url', } type NamiFormFactor = { form_factor?: string; supports_portrait?: boolean; supports_landscape?: boolean; }; export enum LaunchCampaignError { DEFAULT_CAMPAIGN_NOT_FOUND = 0, LABELED_CAMPAIGN_NOT_FOUND = 1, CAMPAIGN_DATA_NOT_FOUND = 2, PAYWALL_ALREADY_DISPLAYED = 3, SDK_NOT_INITIALIZED = 4, PAYWALL_COULD_NOT_DISPLAY = 5, URL_CAMPAIGN_NOT_FOUND = 6, PRODUCT_DATA_NOT_FOUND = 7, PRODUCT_GROUPS_NOT_FOUND = 8, } export type NamiError = { domain: string; code: number; message: string; }; export enum LaunchCampaignResultAction { FAILURE = 'FAILURE', SUCCESS = 'SUCCESS', } export type FailureResultObject = { error: string; }; /** * Permitted value types for entries in {@link PaywallLaunchContext.customAttributes}. * * Values are matched strictly by type: the string "true" and the boolean true are * distinct values that never compare equal. A key present with any non-null value — * including false or "false" — is considered "set". Passing `null` (or omitting the * key) means the attribute is not set; the native bridge omits null values entirely. */ export type CustomAttributeValue = string | boolean | number | null; export type PaywallLaunchContext = { // Can contain multiple product group identifiers productGroups?: string[]; // Key-value pairs used to override template values customAttributes: { [key: string]: CustomAttributeValue; }; // Custom object used as data source for advanced paywall components customObject?: { [key: string]: unknown; }; }; export type CustomerJourneyState = { formerSubscriber: boolean; inGracePeriod: boolean; inTrialPeriod: boolean; inIntroOfferPeriod: boolean; isCancelled: boolean; inPause: boolean; inAccountHold: boolean; }; export type AccountStateAction = | 'login' | 'logout' | 'advertising_id_set' | 'vendor_id_set' | 'customer_data_platform_id_set' | 'nami_device_id_set' | 'advertising_id_cleared' | 'vendor_id_cleared' | 'customer_data_platform_id_cleared' | 'nami_device_id_cleared' | 'anonymous_mode_on' | 'anonymous_mode_off'; // NamiEntitlementManager export type NamiEntitlement = { activePurchases: NamiPurchase[]; desc: string; name: string; purchasedSkus: NamiSKU[]; referenceId: string; relatedSkus: NamiSKU[]; }; /** * Host-managed purchase payload handed back to the SDK on a successful * `buysku` handoff (`complete({ kind: 'purchase', result: 'success', details })`). * Fields are a superset across stores; the native bridge maps them onto the * platform's own `NamiPurchaseSuccess` (Apple flat class / Android sealed * GooglePlay|Amazon) at the boundary. Renamed from `NamiPurchaseDetails` for * cross-SDK naming consistency (NAM-1560 §2.3). */ export type NamiPurchaseSuccess = { product: NamiSKU; transactionID?: string; originalTransactionID?: string; orderId?: string; purchaseToken?: string; receiptId?: string; localizedPrice?: string; price?: string; currencyCode?: string; userId?: string; marketplace?: string; storeType?: string; // 'Apple', 'GooglePlay', 'Amazon' }; /** * @deprecated Renamed to {@link NamiPurchaseSuccess} for cross-SDK naming * consistency. Structurally identical; kept so existing host code keeps * compiling. Prefer `NamiPurchaseSuccess` in new code. */ export type NamiPurchaseDetails = NamiPurchaseSuccess; export type NamiPurchaseSuccessApple = { product: NamiSKU; transactionID: string; originalTransactionID: string; price: string; currencyCode: string; }; export type NamiPurchaseSuccessGooglePlay = { product: NamiSKU; orderId: string; purchaseToken: string; }; export type NamiPurchaseSuccessAmazon = { product: NamiSKU; receiptId: string; localizedPrice: string; userId: string; marketplace: string; }; export enum NamiPaywallAction { BUY_SKU = 'BUY_SKU', SELECT_SKU = 'SELECT_SKU', RESTORE_PURCHASES = 'RESTORE_PURCHASES', SIGN_IN = 'SIGN_IN', CLOSE_PAYWALL = 'CLOSE_PAYWALL', SHOW_PAYWALL = 'SHOW_PAYWALL', PURCHASE_SELECTED_SKU = 'PURCHASE_SELECTED_SKU', PURCHASE_SUCCESS = 'PURCHASE_SUCCESS', PURCHASE_FAILED = 'PURCHASE_FAILED', PURCHASE_CANCELLED = 'PURCHASE_CANCELLED', PURCHASE_PENDING = 'PURCHASE_PENDING', PURCHASE_UNKNOWN = 'PURCHASE_UNKNOWN', PURCHASE_DEFERRED = 'PURCHASE_DEFERRED', DEEPLINK = 'DEEPLINK', TOGGLE_CHANGE = 'TOGGLE_CHANGE', PAGE_CHANGE = 'PAGE_CHANGE', SLIDE_CHANGE = 'SLIDE_CHANGE', COLLAPSIBLE_DRAWER_OPEN = 'COLLAPSIBLE_DRAWER_OPEN', COLLAPSIBLE_DRAWER_CLOSE = 'COLLAPSIBLE_DRAWER_CLOSE', VIDEO_STARTED = 'VIDEO_STARTED', VIDEO_PAUSED = 'VIDEO_PAUSED', VIDEO_RESUMED = 'VIDEO_RESUMED', VIDEO_ENDED = 'VIDEO_ENDED', VIDEO_CHANGED = 'VIDEO_CHANGED', VIDEO_MUTED = 'VIDEO_MUTED', VIDEO_UNMUTED = 'VIDEO_UNMUTED', UNKNOWN = 'UNKNOWN', } // NamiPurchaseManager export type NamiPurchase = { sku?: NamiSKU; skuId: string; transactionIdentifier?: string; originalTransactionIdentifier?: string; purchaseToken?: string; expires?: Date; purchaseInitiatedTimestamp: Date; purchaseSource?: 'CAMPAIGN' | 'MARKETPLACE' | 'UNKNOWN'; }; export type NamiPurchaseFromBridge = { sku?: NamiSKU; skuId: string; transactionIdentifier?: string; originalTransactionIdentifier?: string; purchaseToken?: string; expires?: number; purchaseInitiatedTimestamp: number; purchaseSource?: 'CAMPAIGN' | 'MARKETPLACE' | 'UNKNOWN'; }; export type NamiPurchasesState = | 'pending' | 'purchased' | 'consumed' | 'resubscribed' | 'unsubscribed' | 'deferred' | 'failed' | 'cancelled' | 'unknown'; export type NamiPaywallEvent = { action: NamiPaywallAction; campaignId?: string; campaignName?: string; campaignType?: string; campaignLabel?: string; campaignUrl?: string; paywallId?: string; paywallName?: string; componentChange?: NamiPaywallComponentChange; segmentId?: string; externalSegmentId?: string; deeplinkUrl?: string; sku?: NamiSKU; purchaseError?: string; purchases?: NamiPurchase[]; videoMetadata?: NamiPaywallEventVideoMetadata; timeSpentOnPaywall?: number; }; export type NamiPaywallActionHandler = (event: NamiPaywallEvent) => void; export type NamiPaywallComponentChange = { id?: string; name?: string; }; export type NamiPaywallEventVideoMetadata = { id?: string; name?: string; url?: string; loopVideo: boolean; muteByDefault: boolean; autoplayVideo: boolean; contentTimecode?: number; contentDuration?: number; }; /** * Native → JS handoff delivery payload. `handoffId` correlates the eventual * `complete(outcome)` back to the native pending handoff (NAM-1560 §2.8). */ export type NamiFlowHandoffPayload = { handoffId: string; handoffTag: string; handoffData?: Record<string, unknown>; }; // --------------------------------------------------------------------------- // Variant D — structured handoff outcomes (NAM-1560). Mirrors the core TS // reference (sdk/core, NAM-1557 / PR #392). Keep the shapes in sync; the native // bridges decode these dicts into the platform `NamiHandoffOutcome`. // --------------------------------------------------------------------------- /** Open-ended host-asserted attribute values — primitives only (no nesting). */ export type NamiHandoffAttributeValue = string | number | boolean; /** * Host-asserted login result. Only `loginId` is required. `attributes` is * open-ended experience data (e.g. `{ subscriberStatus, subscribedTier }`) read * by branch conditions and smart text via `login.<hostKey>`; never merged into * Nami subscriber state and never touches entitlements. */ export type NamiLoginSuccess = { loginId: string; cdpId?: string; attributes?: Record<string, NamiHandoffAttributeValue>; }; /** Permission types reportable from a handoff. Tier-1 (push/location/tracking) * carry completion wire values natively; the rest are state/lifecycle only. */ export const NamiPermissionOutcome = { Push: 'push', Location: 'location', Tracking: 'tracking', Camera: 'camera', Microphone: 'microphone', Photos: 'photos', Contacts: 'contacts', Bluetooth: 'bluetooth', Calendar: 'calendar', Biometrics: 'biometrics', Health: 'health', Motion: 'motion', Speech: 'speech', LocalNetwork: 'localNetwork', } as const; export type NamiPermissionOutcome = (typeof NamiPermissionOutcome)[keyof typeof NamiPermissionOutcome]; /** Typed outcome reported by the host's `complete(...)`. Discriminated on `kind` * (purchase/login further discriminated on `result`). */ export type NamiHandoffOutcome = | { kind: 'done' } | { kind: 'permission'; permission: NamiPermissionOutcome; granted: boolean; detail?: string; } | { kind: 'purchase'; result: 'success'; details: NamiPurchaseSuccess } | { kind: 'purchase'; result: 'cancelled' } | { kind: 'purchase'; result: 'failed'; error?: unknown } | { kind: 'login'; result: 'success'; details: NamiLoginSuccess } | { kind: 'login'; result: 'cancelled' } | { kind: 'login'; result: 'failed'; error?: unknown }; /** Per-handoff completion callback. Bare `complete()` ≙ `complete({kind:'done'})`. */ export type NamiHandoffComplete = (outcome?: NamiHandoffOutcome) => void; /** The single handoff handler shape (NAM-1560 §2.1 — no dual registration). */ export type NamiFlowHandoffStepHandler = ( handoffTag: string, handoffData: Record<string, unknown> | undefined, complete: NamiHandoffComplete, ) => void; /** Closed-but-extensible handoff tag vocabulary (mirrors the builder's * `FlowHandoffTag`, minus `__*__` internals). Unknown future tags still pass. */ export const NamiHandoffTag = { Push: 'push', Location: 'location', Tracking: 'att', Deeplink: 'deeplink', Complete: 'complete', SignIn: 'signin', Restore: 'restore', SignInMvpd: 'signin_mvpd', BuySku: 'buysku', UserData: 'userdata', } as const; export type NamiKnownHandoffTag = (typeof NamiHandoffTag)[keyof typeof NamiHandoffTag]; // eslint-disable-next-line @typescript-eslint/ban-types export type NamiHandoffTagValue = NamiKnownHandoffTag | (string & {}); /** Outbound `userdata` envelope (Nami → customer) delivered with the `userdata` tag. */ export type NamiUserDataEnvelope = { form_id: string; step_id: string; /** ISO-8601 UTC timestamp of delivery. */ collected_at: string; fields: Record<string, boolean | string>; }; export type NamiAccountStateEvent = { action: AccountStateAction; success: boolean; error?: number; };