@wireai/activation 0.10.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/AGENTS.md +51 -0
  2. package/CHANGELOG.md +111 -1
  3. package/INTEGRATION_PROMPT.md +13 -1
  4. package/README.md +106 -4
  5. package/dist/analytics/index.d.mts +35 -6
  6. package/dist/analytics/index.d.ts +35 -6
  7. package/dist/analytics/index.js +222 -94
  8. package/dist/analytics/index.js.map +1 -1
  9. package/dist/analytics/index.mjs +214 -95
  10. package/dist/analytics/index.mjs.map +1 -1
  11. package/dist/{currentSession-D0Vq7_VE.d.ts → currentSession-D6RiVtc8.d.ts} +187 -29
  12. package/dist/{currentSession-DdDkprpM.d.mts → currentSession-DsSDHqor.d.mts} +187 -29
  13. package/dist/index.d.mts +236 -82
  14. package/dist/index.d.ts +236 -82
  15. package/dist/index.js +330 -60
  16. package/dist/index.js.map +1 -1
  17. package/dist/index.mjs +314 -61
  18. package/dist/index.mjs.map +1 -1
  19. package/dist/questionnaire/index.d.mts +1 -1
  20. package/dist/questionnaire/index.d.ts +1 -1
  21. package/dist/questionnaire/index.js +59 -8
  22. package/dist/questionnaire/index.js.map +1 -1
  23. package/dist/questionnaire/index.mjs +59 -8
  24. package/dist/questionnaire/index.mjs.map +1 -1
  25. package/dist/reviews/index.d.mts +2 -2
  26. package/dist/reviews/index.d.ts +2 -2
  27. package/dist/reviews/index.js +97 -17
  28. package/dist/reviews/index.js.map +1 -1
  29. package/dist/reviews/index.mjs +97 -17
  30. package/dist/reviews/index.mjs.map +1 -1
  31. package/dist/{transport-Bzb-bcB2.d.mts → transport-CF_eHwzC.d.mts} +15 -16
  32. package/dist/{transport-B31G0Cib.d.ts → transport-DsRe4epC.d.ts} +15 -16
  33. package/llms.txt +9 -0
  34. package/package.json +1 -1
  35. package/src/activation/useWireActivation.ts +12 -1
  36. package/src/activation/wireActivation.ts +36 -24
  37. package/src/analytics/analyticsFacade.ts +113 -29
  38. package/src/analytics/currentSession.ts +83 -0
  39. package/src/analytics/eventQueue.ts +20 -11
  40. package/src/analytics/index.ts +29 -1
  41. package/src/analytics/reportClientEvent.ts +50 -2
  42. package/src/analytics/screenTracking.ts +6 -1
  43. package/src/analytics/useAnalytics.ts +22 -1
  44. package/src/context/deviceId.ts +109 -0
  45. package/src/context/userContext.ts +73 -0
  46. package/src/identity/userIdentity.ts +10 -0
  47. package/src/index.ts +50 -2
  48. package/src/questionnaire/runtime.ts +12 -2
  49. package/src/questionnaire/transport.ts +5 -1
  50. package/src/questionnaire/useQuestionnaireGate.ts +9 -7
  51. package/src/revenuecat/index.ts +55 -0
  52. package/src/revenuecat/purchaseEvents.ts +167 -0
  53. package/src/revenuecat/revenueCatBridge.ts +221 -0
  54. package/src/revenuecat/types.ts +95 -0
  55. package/src/reviews/decision.ts +8 -1
  56. package/src/reviews/runtime.ts +92 -1
  57. package/src/reviews/transport.ts +27 -10
  58. package/src/reviews/useReviewGate.ts +12 -7
  59. package/src/session-analytics/lifecycle.ts +15 -13
  60. package/src/session-analytics/reportSessionStart.ts +15 -4
  61. package/src/session-analytics/useLifecycleEvents.ts +68 -28
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as React from 'react';
2
2
  import React__default, { ReactNode } from 'react';
3
- import { q as WireOnboardingProps, u as WireOnboardingConfig, O as OnboardingResult, S as StepValidator, v as OnboardingEvent, w as OnboardingCopy, a as ClientEventTarget, D as DeviceContext, W as WireUserContext, C as ClientEvent, e as EnvelopeSource } from './currentSession-D0Vq7_VE.js';
4
- export { A as AnalyticsEvent, b as ClientEventType, x as DeviceFormFactor, y as EXTRA_KEY_PREFIX, z as OnboardingProgress, R as RESERVED_USER_CONTEXT_KEYS, B as ResolveUserContextOptions, F as ResolvedUserContext, g as WIRE_ONBOARDING_EVENTS, h as WireOnboardingEventName, G as collectDeviceContext, k as getCurrentSessionId, H as hashEmailFnv1a, I as isWireScalar, m as makeSessionId, J as namespaceExtra, r as reportClientEvent, l as reportClientEventAwait, n as reportClientEvents, o as reportClientEventsAwait, p as resetCurrentSessionId, K as resolveUserContext, s as setCurrentSessionId, t as toAnalyticsEvent } from './currentSession-D0Vq7_VE.js';
3
+ import { H as WireOnboardingProps, I as WireOnboardingConfig, O as OnboardingResult, S as StepValidator, J as OnboardingEvent, K as OnboardingCopy, c as ClientEventTarget, L as DeviceContext, W as WireUserContext, b as ClientEvent, g as EnvelopeSource } from './currentSession-D6RiVtc8.js';
4
+ export { A as AUTO_DEVICE_ID_PREFIX, a as AnalyticsEvent, C as ClearUserContextOptions, d as ClientEventType, M as DeviceFormFactor, D as DeviceKeyStorage, N as EXTRA_KEY_PREFIX, P as IdentifyOnboardingOptions, Q as OnboardingProgress, T as RESERVED_USER_CONTEXT_KEYS, R as ResolveAutoDeviceKeyOptions, U as ResolveUserContextOptions, V as ResolvedUserContext, X as USER_ID_MAX_LENGTH, i as WIRE_ONBOARDING_EVENTS, j as WireOnboardingEventName, Y as activationJoinContext, k as analyticsUserIdStorageKey, m as clearPiiFromContext, n as clearUserContext, Z as collectDeviceContext, p as deviceIdStorageKey, q as ensureCurrentSessionId, r as getCurrentSessionId, _ as hashEmailFnv1a, $ as identifyOnboarding, a0 as isWireScalar, s as looksLikeEmail, t as makeSessionId, a1 as mintDeviceId, a2 as namespaceExtra, u as reportClientEvent, v as reportClientEventAwait, w as reportClientEvents, x as reportClientEventsAwait, y as resetAutoDeviceKeys, z as resetCurrentSessionId, B as resolveAutoDeviceKey, a3 as resolveUserContext, a4 as sanitizeUserId, F as setCurrentSessionId, G as toAnalyticsEvent } from './currentSession-D6RiVtc8.js';
5
5
  import { O as OnboardingTheme } from './types-BKfpdZzX.js';
6
6
  export { a as OnboardingButtonStyle, b as OnboardingColors, c as OnboardingFonts, d as OnboardingRadius, e as OnboardingSpacing } from './types-BKfpdZzX.js';
7
7
  export { C as CenteredModal, a as CenteredModalHandle, b as CenteredModalProps } from './CenteredModal-Cdgns6--.js';
@@ -1436,83 +1436,6 @@ type OptionalRequire = (moduleName: string) => unknown;
1436
1436
  */
1437
1437
  declare const detectNativeModel: (requireModule?: OptionalRequire) => string | undefined;
1438
1438
 
1439
- /** Max accepted user-id length. Longer strings are truncated (never rejected). Keep in sync
1440
- * with the server's `USER_ID_MAX_LENGTH` (analytics/events.py). */
1441
- declare const USER_ID_MAX_LENGTH = 128;
1442
- /**
1443
- * Normalize a host-supplied user id: trim, drop empty, and cap at {@link USER_ID_MAX_LENGTH}.
1444
- * Returns `undefined` for a missing/blank/non-string value so callers can `if (id)`-gate.
1445
- * PII is a host concern — this only bounds length, it does not (and cannot) detect an email.
1446
- */
1447
- declare const sanitizeUserId: (raw: unknown) => string | undefined;
1448
- /** Options for {@link identifyOnboarding}. */
1449
- type IdentifyOnboardingOptions = {
1450
- /** Tenant transport, same shape as `WireOnboardingConfig` (only these two fields are used). */
1451
- config: {
1452
- serverUrl: string;
1453
- apiKey: string;
1454
- };
1455
- /** The host's opaque user id to bind. Trimmed + capped; NO PII. */
1456
- userId: string;
1457
- /**
1458
- * The onboarding session id to bind to (the A2A contextId) — the `contextId` field carried on
1459
- * the `started`/`resumed` `onEvent`. Pass this when you captured it there. Required after the
1460
- * flow COMPLETED, since completion clears the persisted session. Wins over the storage lookup.
1461
- */
1462
- contextId?: string;
1463
- /**
1464
- * The SAME host storage you passed to `<WireOnboarding storage={…} />`. When `contextId` is
1465
- * omitted, the helper reads the persisted contextId from it (works while the session is still
1466
- * persisted — i.e. dropped or mid-flow, before completion clears it).
1467
- */
1468
- storage?: WireOnboardingStorage;
1469
- /** App id, to derive the default storage key `wireai:session:<appId>` when reading from storage. */
1470
- appId?: string;
1471
- /** Storage key override — pass the same `persistKey` you gave `<WireOnboarding>`, if any. */
1472
- persistKey?: string;
1473
- };
1474
- /**
1475
- * Attach a host user id to an onboarding session AFTER the fact (post-registration), by sending
1476
- * an `identify` client event to `/v1/events`. Resolves the contextId from an explicit
1477
- * `contextId` or, failing that, from the persisted session in the host `storage`.
1478
- *
1479
- * Fire-and-forget under the hood (never throws, never blocks onboarding). Resolves to `true`
1480
- * when an identify event was dispatched, `false` when it couldn't (no user id, no server url,
1481
- * or no resolvable contextId).
1482
- */
1483
- declare const identifyOnboarding: (opts: IdentifyOnboardingOptions) => Promise<boolean>;
1484
-
1485
- /**
1486
- * deviceId — mint a stable, NON-PII, per-install device id the kit owns when the host supplies
1487
- * none. This is the headline of "device fully automatic": the analytics façade auto-mints ONE id,
1488
- * persists it via the host's `storage` abstraction, and reuses it on every subsequent open — so
1489
- * `user_context.device_key` is ALWAYS present and the server's review/questionnaire gating +
1490
- * A/B stickiness (both key on `device_key`) work out of the box, with zero host wiring.
1491
- *
1492
- * WHY it is NOT PII and adds NO dependency (the kit's hard rules):
1493
- * The id is a random token generated from `Date.now()` + `Math.random()` — it carries NO hardware
1494
- * identifier, NO IDFA/GAID, NO fingerprint. It is a first-party per-install correlation key, the
1495
- * same privacy category as a first-party cookie: it groups a single install's sessions and cannot
1496
- * identify a person or be joined across apps. There is NO `uuid` (or any) dependency — a
1497
- * time+random scheme is sufficient because the id is minted ONCE and then persisted, so global
1498
- * uniqueness across the fleet is not required (a per-install collision is astronomically unlikely
1499
- * and inconsequential — worst case two installs share a bucket).
1500
- *
1501
- * A host that wants its OWN device id still wins: pass `WireUserContext.deviceKey` and the kit uses
1502
- * that verbatim and never mints/persists an auto id.
1503
- */
1504
- /** Prefix so an auto-minted id is visibly the kit's (distinguishable from a host-supplied `deviceKey`). */
1505
- declare const AUTO_DEVICE_ID_PREFIX = "wdev_";
1506
- /** The storage key the façade persists the auto-minted id under (namespaced per `appId`). */
1507
- declare const deviceIdStorageKey: (appId?: string) => string;
1508
- /**
1509
- * Mint a fresh per-install device id. Dependency-free (`Date.now()` + `Math.random()`), never
1510
- * throws, and returns a NEW value on every call — the façade mints ONCE and persists, so this is
1511
- * called at most once per install (then the persisted value is reused). Two random chunks plus the
1512
- * timestamp keep the token wide enough that a per-install collision is not a practical concern.
1513
- */
1514
- declare const mintDeviceId: () => string;
1515
-
1516
1439
  /**
1517
1440
  * Tenant transport + context inputs for {@link createWireActivation}. `serverUrl`/`apiKey` are the
1518
1441
  * SAME creds as onboarding (never a second key); everything else is optional.
@@ -1546,8 +1469,14 @@ type WireActivation = {
1546
1469
  /**
1547
1470
  * Awaitable action report: POST `event_type='app_event'`, `question_key=<name>`, optional `meta`,
1548
1471
  * under the CURRENT session id + `user_context.device_key`. Resolves `true` once the server has
1549
- * stored it (2xx) and THEN bumps decision revalidation; resolves `false` (no bump) when there is no
1550
- * current session, a blank name, or the POST fails. Never throws.
1472
+ * stored it (2xx) and THEN bumps decision revalidation; resolves `false` (no bump) for a blank
1473
+ * name or a failed POST. Never throws.
1474
+ *
1475
+ * It no longer refuses when no app-open has been registered: the session id is resolved through
1476
+ * `ensureCurrentSessionId()`, which mints and registers one in that case (the server requires a
1477
+ * non-empty `session_id` and silently drops an event without one, so bailing lost the action
1478
+ * entirely). A host that fires `reportSessionStart` / `useLifecycleEvents` first is unaffected —
1479
+ * the real per-open id is already registered and gets used exactly as before.
1551
1480
  */
1552
1481
  track(name: string, meta?: Record<string, unknown>): Promise<boolean>;
1553
1482
  /** The CURRENT per-open session id (the kit's canonical `getCurrentSessionId()`), or `undefined`. */
@@ -1626,6 +1555,231 @@ declare const getActivationRevalidationVersion: () => number;
1626
1555
  /** Test-only: reset the shared store between cases (clears version + listeners). */
1627
1556
  declare const resetActivationRevalidation: () => void;
1628
1557
 
1558
+ /**
1559
+ * types - STRUCTURAL mirrors of the `react-native-purchases` shapes this adapter READS.
1560
+ *
1561
+ * WHY structural and not an import: `react-native-purchases` is a NATIVE module. Importing it
1562
+ * (even as an optional peer) would put a native rebuild in the kit's dependency story, which the
1563
+ * kit's hard rule forbids. Every field below is a subset of the real 9.6.x typings
1564
+ * (`@revenuecat/purchases-typescript-internal`: `CustomerInfo`, `PurchasesEntitlementInfo`,
1565
+ * `PurchasesPackage`, `PurchasesStoreProduct`, `PurchasesError`), declared as plain `string` /
1566
+ * `number` / `boolean` so a host can pass its REAL RevenueCat objects straight in: RevenueCat's
1567
+ * `Store`, `PACKAGE_TYPE`, `PERIOD_TYPE` and `PURCHASES_ERROR_CODE` are all STRING enums, and a
1568
+ * string enum member is assignable to `string`.
1569
+ *
1570
+ * The adapter only ever reads. It never constructs a RevenueCat object and never calls the SDK.
1571
+ */
1572
+ /** One entitlement as RevenueCat reports it (subset of `PurchasesEntitlementInfo`). */
1573
+ interface RevenueCatEntitlementLike {
1574
+ /** The entitlement identifier configured in the RevenueCat dashboard, e.g. `"pro"`. */
1575
+ readonly identifier: string;
1576
+ /** True while the customer has access. */
1577
+ readonly isActive: boolean;
1578
+ /** `"NORMAL" | "INTRO" | "TRIAL" | "PREPAID"` on the real type; compared case-insensitively. */
1579
+ readonly periodType?: string;
1580
+ /** True when the underlying subscription renews at the end of the period. */
1581
+ readonly willRenew?: boolean;
1582
+ /** The store the entitlement was unlocked from, e.g. `"APP_STORE"`. */
1583
+ readonly store?: string;
1584
+ /** The product id that unlocked the entitlement. */
1585
+ readonly productIdentifier?: string;
1586
+ /** False when the purchase is a production one. */
1587
+ readonly isSandbox?: boolean;
1588
+ }
1589
+ /** The customer snapshot RevenueCat returns from a purchase, a restore, or `getCustomerInfo`. */
1590
+ interface RevenueCatCustomerInfoLike {
1591
+ readonly entitlements: {
1592
+ /** Active entitlements keyed by identifier. Missing key means "not entitled". */
1593
+ readonly active: {
1594
+ readonly [key: string]: RevenueCatEntitlementLike | undefined;
1595
+ };
1596
+ };
1597
+ /** Product ids of the customer's active subscriptions. */
1598
+ readonly activeSubscriptions?: readonly string[];
1599
+ }
1600
+ /** The purchasable product on a package (subset of `PurchasesStoreProduct`). */
1601
+ interface RevenueCatProductLike {
1602
+ readonly identifier: string;
1603
+ /** Price in the local currency, as a number. */
1604
+ readonly price?: number;
1605
+ /** ISO currency code of `price`, e.g. `"EUR"`. */
1606
+ readonly currencyCode?: string;
1607
+ }
1608
+ /** One offering package (subset of `PurchasesPackage`). */
1609
+ interface RevenueCatPackageLike {
1610
+ readonly identifier: string;
1611
+ /** `"ANNUAL" | "MONTHLY" | ...` on the real type. */
1612
+ readonly packageType?: string;
1613
+ readonly product: RevenueCatProductLike;
1614
+ /** The offering this package belongs to. */
1615
+ readonly offeringIdentifier?: string;
1616
+ }
1617
+ /** The current offering a paywall renders (subset of `PurchasesOffering`). */
1618
+ interface RevenueCatOfferingLike {
1619
+ readonly identifier?: string;
1620
+ readonly availablePackages?: readonly RevenueCatPackageLike[];
1621
+ }
1622
+ /** The rejected value of a RevenueCat purchase call (subset of `PurchasesError`). */
1623
+ interface RevenueCatErrorLike {
1624
+ /** `PURCHASES_ERROR_CODE`, a STRING enum; `"1"` is `PURCHASE_CANCELLED_ERROR`. */
1625
+ readonly code?: string;
1626
+ readonly message?: string;
1627
+ /** Deprecated on the real type but still populated by 9.6.x. */
1628
+ readonly userCancelled?: boolean | null;
1629
+ }
1630
+ /**
1631
+ * The Wire sink the bridge reports through. Deliberately STRUCTURAL so BOTH kit surfaces satisfy
1632
+ * it with no adapter of their own:
1633
+ * - `createAnalytics(...)` (offline-first queue) matches `track` + `setUserContext`;
1634
+ * - `createWireActivation(...)` (awaitable `wire.track`) matches `track`.
1635
+ *
1636
+ * Both auto-mint and stamp `user_context.device_key` on every event, which is the join key this
1637
+ * adapter's whole design rests on (see `joinKey.md` in the module docs / the README section).
1638
+ */
1639
+ interface RevenueCatSink {
1640
+ /** Report an in-app event. Returns `void` (queued) or `Promise<boolean>` (awaited POST). */
1641
+ track(event: string, props?: Record<string, unknown>): void | Promise<boolean>;
1642
+ /**
1643
+ * Optional: update the bound user context. Present on `createAnalytics`, absent on
1644
+ * `createWireActivation` (its config is captured immutably), so entitlement sync is a no-op there.
1645
+ */
1646
+ setUserContext?(partial: {
1647
+ extra?: Record<string, string | number | boolean>;
1648
+ }): void;
1649
+ }
1650
+
1651
+ /**
1652
+ * purchaseEvents - the canonical Wire names for a subscription funnel, plus the PURE mappers that
1653
+ * turn a RevenueCat snapshot into small, non-PII event props.
1654
+ *
1655
+ * Same job `analyticsEvent.ts` does for the onboarding funnel: every app was naming these events
1656
+ * itself (`PURCHASE`, `purchase_success`, `AI_PAYWALL_VIEW`), so the same funnel read differently
1657
+ * per tenant and no cross-app report was possible. These are the ONE set of names; the mappers are
1658
+ * the ONE definition of which RevenueCat fields are safe to send.
1659
+ *
1660
+ * PURE + dependency-free: no React, no React Native, no `react-native-purchases`, no transport.
1661
+ * Every function tolerates a malformed or absent snapshot and returns a defined value instead of
1662
+ * throwing, because a paywall must never break on an analytics mapping.
1663
+ */
1664
+
1665
+ /**
1666
+ * The canonical purchase-funnel event names. These are `app_event` `question_key` values on the
1667
+ * wire, so they are ALSO the exact strings a review / questionnaire firing trigger matches on.
1668
+ * Never rename one: a rename silently unfires every trigger configured against the old string.
1669
+ */
1670
+ declare const WIRE_PURCHASE_EVENTS: {
1671
+ /** The paywall became visible (offerings loaded). */
1672
+ readonly paywallShown: "wire_paywall_shown";
1673
+ /** The user tapped buy; the store sheet is about to open. */
1674
+ readonly checkoutStarted: "wire_checkout_started";
1675
+ /** The store confirmed the purchase AND the entitlement is now active. */
1676
+ readonly purchased: "wire_purchase_completed";
1677
+ /** The purchase did not land: a user cancel or a real store/network error (see `reason`). */
1678
+ readonly purchaseFailed: "wire_purchase_failed";
1679
+ /** A restore ran (whether or not it produced an entitlement; see `plan_tier`). */
1680
+ readonly restored: "wire_purchase_restored";
1681
+ };
1682
+ type WirePurchaseEventName = (typeof WIRE_PURCHASE_EVENTS)[keyof typeof WIRE_PURCHASE_EVENTS];
1683
+ /**
1684
+ * The user-context key the bridge writes the tier to. It lands NAMESPACED as
1685
+ * `user_context["custom.plan_tier"]` (host extras are always prefixed), which is the flattened
1686
+ * dimension the server report can break the funnel down by.
1687
+ */
1688
+ declare const PLAN_TIER_CONTEXT_KEY = "plan_tier";
1689
+ /** The three tiers the kit models. Anything richer belongs in the host's own analytics. */
1690
+ type PlanTier = "paid" | "trial" | "free";
1691
+ /**
1692
+ * The ACTIVE entitlement matching `entitlementId`, or `undefined`. Returns `undefined` for a
1693
+ * missing key, an explicitly inactive entry, and any malformed snapshot.
1694
+ */
1695
+ declare const activeEntitlement: (info: RevenueCatCustomerInfoLike | undefined, entitlementId: string) => RevenueCatEntitlementLike | undefined;
1696
+ /** `paid` / `trial` / `free` for the configured entitlement. Never throws. */
1697
+ declare const resolvePlanTier: (info: RevenueCatCustomerInfoLike | undefined, entitlementId: string) => PlanTier;
1698
+ /**
1699
+ * Non-PII props for an offering package: which package, which product, what it costs. Every field
1700
+ * is optional on the wire, so a missing one is OMITTED rather than sent empty or invented.
1701
+ */
1702
+ declare const describePackage: (pkg: RevenueCatPackageLike | undefined) => Record<string, string | number>;
1703
+ /**
1704
+ * Non-PII props for the entitlement state after a purchase or a restore. Always carries
1705
+ * `entitlement` + `plan_tier` so a "restore that granted nothing" is still a queryable row; the
1706
+ * rest of the fields only appear when the entitlement is actually active.
1707
+ */
1708
+ declare const describeEntitlement: (info: RevenueCatCustomerInfoLike | undefined, entitlementId: string) => Record<string, string | number | boolean>;
1709
+ /**
1710
+ * True when the rejection is the user backing out of the store sheet rather than a real failure.
1711
+ * Reads BOTH signals the SDK exposes: the current `code` and the deprecated-but-still-populated
1712
+ * `userCancelled` flag. Anything else (including a plain `Error`) is a genuine failure.
1713
+ */
1714
+ declare const isUserCancelled: (error: unknown) => boolean;
1715
+ /**
1716
+ * A short, stable, non-PII failure descriptor. The store's `message` is DELIBERATELY dropped: it is
1717
+ * localized, unbounded, and occasionally echoes the account it failed for, so it is not something
1718
+ * the kit forwards to a shared analytics backend. The RevenueCat `code` is the stable handle.
1719
+ */
1720
+ declare const describeFailure: (error: unknown) => {
1721
+ reason: string;
1722
+ code: string;
1723
+ };
1724
+
1725
+ /** Small, non-PII extras a host merges onto a purchase event (paywall variant, entry point, ...). */
1726
+ type PurchaseProps = Record<string, string | number | boolean>;
1727
+ /** Inputs for {@link createRevenueCatBridge}. */
1728
+ interface RevenueCatBridgeConfig {
1729
+ /**
1730
+ * Where events go: the `createAnalytics(...)` instance (offline-first queue) or the
1731
+ * `createWireActivation(...)` instance (awaitable POST). Both already carry the `device_key` this
1732
+ * funnel joins on, so pass the one the app already holds rather than creating a second.
1733
+ */
1734
+ analytics: RevenueCatSink;
1735
+ /**
1736
+ * The entitlement identifier that means "paid" in THIS app, exactly as configured in the
1737
+ * RevenueCat dashboard (e.g. `"pro"`). The bridge reads `customerInfo.entitlements.active[id]`.
1738
+ */
1739
+ entitlementId: string;
1740
+ /** Non-PII props merged into EVERY event from this bridge. A per-call prop of the same name wins. */
1741
+ commonProps?: PurchaseProps;
1742
+ /**
1743
+ * Whether entitlement changes also update the bound user context with `plan_tier`
1744
+ * (`user_context["custom.plan_tier"]`), so the whole funnel can be sliced paid vs trial vs free.
1745
+ * Default `true`. Requires a sink with `setUserContext` (`createAnalytics`); a no-op otherwise.
1746
+ */
1747
+ writePlanTier?: boolean;
1748
+ }
1749
+ /** The bridge surface. Every method is fire-and-forget and never throws. */
1750
+ interface RevenueCatBridge {
1751
+ /**
1752
+ * The paywall became visible. Pass the RevenueCat offering you just loaded and the bridge derives
1753
+ * `offering_id` + `packages_count`. Fires even with no offering, because a paywall that reached
1754
+ * the user with nothing to sell is exactly the failure you want in the funnel.
1755
+ */
1756
+ paywallShown(offering?: RevenueCatOfferingLike, props?: PurchaseProps): void;
1757
+ /** The user tapped buy and the store sheet is opening. */
1758
+ checkoutStarted(pkg: RevenueCatPackageLike, props?: PurchaseProps): void;
1759
+ /**
1760
+ * The store returned from a purchase. Fires `wire_purchase_completed` when the configured
1761
+ * entitlement is now active, and `wire_purchase_failed` with `reason: "not_entitled"` when the
1762
+ * store confirmed but nothing was granted (the case hosts usually drop on the floor). Syncs
1763
+ * `plan_tier` either way. Returns whether the user is entitled now, so the caller can navigate.
1764
+ */
1765
+ purchaseCompleted(customerInfo: RevenueCatCustomerInfoLike | undefined, pkg?: RevenueCatPackageLike, props?: PurchaseProps): boolean;
1766
+ /** The purchase call rejected. Separates a user cancel from a real store error via `reason`. */
1767
+ purchaseFailed(error: unknown, pkg?: RevenueCatPackageLike, props?: PurchaseProps): void;
1768
+ /** A restore finished. Reports the resulting tier and returns whether the user is entitled now. */
1769
+ purchasesRestored(customerInfo: RevenueCatCustomerInfoLike | undefined, props?: PurchaseProps): boolean;
1770
+ /**
1771
+ * Write the current tier to the bound user context WITHOUT emitting an event. Call it once at
1772
+ * launch with a `getCustomerInfo()` snapshot so returning subscribers are segmented correctly
1773
+ * from their first event of the session. Returns the tier it resolved.
1774
+ */
1775
+ syncPlanTier(customerInfo: RevenueCatCustomerInfoLike | undefined): PlanTier;
1776
+ }
1777
+ /**
1778
+ * Create a bridge bound to one sink and one entitlement. Pure, React-free, and safe to create at
1779
+ * module scope next to the paywall.
1780
+ */
1781
+ declare const createRevenueCatBridge: (config: RevenueCatBridgeConfig) => RevenueCatBridge;
1782
+
1629
1783
  /** The canonical event name for an app-open. A trigger keys off this exact string. */
1630
1784
  declare const SESSION_STARTED_EVENT: "app.session_started";
1631
1785
  /** Options for {@link reportSessionStart}. Everything except `target` is optional so a pre-auth
@@ -1852,4 +2006,4 @@ interface UseLifecycleEventsOptions {
1852
2006
  */
1853
2007
  declare const useLifecycleEvents: (config: LifecycleConfig | undefined, options?: UseLifecycleEventsOptions) => void;
1854
2008
 
1855
- export { AUTO_DEVICE_ID_PREFIX, AnimatedSparkle, BACKGROUND_SESSION_MS, type CachedFeatures, CardGridSelectCard, CardHandoff, type CardHandoffProps, type CardHandoffVariant, type CardOption, ChipSelectCard, ClientEvent, ClientEventTarget, CompletionView, DEFAULT_FEATURES_TTL_MS, DemoOnboarding, type DemoOnboardingProps, DeviceContext, DoneBlock, ErrorBlock, FIRST_OPEN_EVENT, IconRegistryProvider, type IdentifyOnboardingOptions, IllustrationProvider, type IllustrationRegistry, InterstitialCard, type LifecycleConfig, type LifecycleEventInput, LoadingBlock, LoadingScreen, NumberStepperCard, type OnboardingAttribution, Button as OnboardingButton, OnboardingCopy, OnboardingEvent, type OnboardingFlagOptions, OnboardingFlow, OnboardingResult, OnboardingScaffold, OnboardingTheme, OnboardingThemeProvider, type ReportFirstOpenOptions, type ReportSessionStartOptions, type ResolveFeaturesOptions, SESSION_STARTED_EVENT, SelectionCard, type SessionStartConfig, StatusCard, StepProgress, StepValidator, TextInputCard, type ThemeFromBrandInput, USER_ID_MAX_LENGTH, type UseLifecycleEventsOptions, type UseSessionStartOptions, type UseWireActivation, WIRE_ICON_GLYPHS, WIRE_ICON_NAMES, type WireActivation, type WireActivationConfig, type WireConfigOverrides, WireFeatures, WireFeaturesConfig, WireFeaturesProvider, type WireFeaturesProviderProps, WireIcon, type WireIconFamily, type WireIconGlyph, type WireIconName, type WireIconProps, type WireIconRegistry, type WireLifecycleOptions, WireOnboarding, WireOnboardingConfig, WireOnboardingProps, WireOnboardingStorage, WireUserContext, attributionMetadata, bumpActivationRevalidation, createWireActivation, defaultIllustrations, defaultOnboardingTheme, defaultWireFeatures, deriveAnswers, detectAppVersion, detectNativeModel, deviceIdStorageKey, featuresCacheKey, featuresEqual, fetchWireFeatures, firstOpenStorageKey, getActivationRevalidationVersion, identifyOnboarding, isFeaturesFresh, isOnboardingEnabled, lookupIconGlyph, mergeTheme, mintDeviceId, motionSpec, onboardingComponents, parseWireFeatures, readCachedFeatures, readProgress, reportFirstOpen, reportSessionStart, resetActivationRevalidation, resetFirstOpenLatch, resetSessionStartGuard, sanitizeUserId, subscribeActivationRevalidation, themeFromBrand, useActivationRevalidation, useHostIcon, useIllustration, useLifecycleEvents, useOnboardingTheme, useReducedMotion, useResolvedFeatures, useSessionStart, useWireActivation, useWireFeatures, useWireFeaturesContext, wireConfigFromEnv, wireLifecycleEvents, writeCachedFeatures };
2009
+ export { AnimatedSparkle, BACKGROUND_SESSION_MS, type CachedFeatures, CardGridSelectCard, CardHandoff, type CardHandoffProps, type CardHandoffVariant, type CardOption, ChipSelectCard, ClientEvent, ClientEventTarget, CompletionView, DEFAULT_FEATURES_TTL_MS, DemoOnboarding, type DemoOnboardingProps, DeviceContext, DoneBlock, ErrorBlock, FIRST_OPEN_EVENT, IconRegistryProvider, IllustrationProvider, type IllustrationRegistry, InterstitialCard, type LifecycleConfig, type LifecycleEventInput, LoadingBlock, LoadingScreen, NumberStepperCard, type OnboardingAttribution, Button as OnboardingButton, OnboardingCopy, OnboardingEvent, type OnboardingFlagOptions, OnboardingFlow, OnboardingResult, OnboardingScaffold, OnboardingTheme, OnboardingThemeProvider, PLAN_TIER_CONTEXT_KEY, type PlanTier, type PurchaseProps, type ReportFirstOpenOptions, type ReportSessionStartOptions, type ResolveFeaturesOptions, type RevenueCatBridge, type RevenueCatBridgeConfig, type RevenueCatCustomerInfoLike, type RevenueCatEntitlementLike, type RevenueCatErrorLike, type RevenueCatOfferingLike, type RevenueCatPackageLike, type RevenueCatProductLike, type RevenueCatSink, SESSION_STARTED_EVENT, SelectionCard, type SessionStartConfig, StatusCard, StepProgress, StepValidator, TextInputCard, type ThemeFromBrandInput, type UseLifecycleEventsOptions, type UseSessionStartOptions, type UseWireActivation, WIRE_ICON_GLYPHS, WIRE_ICON_NAMES, WIRE_PURCHASE_EVENTS, type WireActivation, type WireActivationConfig, type WireConfigOverrides, WireFeatures, WireFeaturesConfig, WireFeaturesProvider, type WireFeaturesProviderProps, WireIcon, type WireIconFamily, type WireIconGlyph, type WireIconName, type WireIconProps, type WireIconRegistry, type WireLifecycleOptions, WireOnboarding, WireOnboardingConfig, WireOnboardingProps, WireOnboardingStorage, type WirePurchaseEventName, WireUserContext, activeEntitlement, attributionMetadata, bumpActivationRevalidation, createRevenueCatBridge, createWireActivation, defaultIllustrations, defaultOnboardingTheme, defaultWireFeatures, deriveAnswers, describeEntitlement, describeFailure, describePackage, detectAppVersion, detectNativeModel, featuresCacheKey, featuresEqual, fetchWireFeatures, firstOpenStorageKey, getActivationRevalidationVersion, isFeaturesFresh, isOnboardingEnabled, isUserCancelled, lookupIconGlyph, mergeTheme, motionSpec, onboardingComponents, parseWireFeatures, readCachedFeatures, readProgress, reportFirstOpen, reportSessionStart, resetActivationRevalidation, resetFirstOpenLatch, resetSessionStartGuard, resolvePlanTier, subscribeActivationRevalidation, themeFromBrand, useActivationRevalidation, useHostIcon, useIllustration, useLifecycleEvents, useOnboardingTheme, useReducedMotion, useResolvedFeatures, useSessionStart, useWireActivation, useWireFeatures, useWireFeaturesContext, wireConfigFromEnv, wireLifecycleEvents, writeCachedFeatures };