@encorekit/web-sdk 2.0.3 → 2.0.6

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 (79) hide show
  1. package/README.md +112 -40
  2. package/dist/cjs/index.cjs +1 -1
  3. package/dist/cjs/index.cjs.map +1 -1
  4. package/dist/esm/index.js +1 -1
  5. package/dist/esm/index.js.map +1 -1
  6. package/dist/umd/encore.min.js +1 -1
  7. package/dist/umd/encore.min.js.map +1 -1
  8. package/embed/README.md +82 -367
  9. package/examples/ios-webview/EncoreURLBuilder.swift +179 -61
  10. package/examples/ios-webview/README.md +75 -354
  11. package/examples/ios-webview/SimpleEncoreView.swift +49 -36
  12. package/examples/ios-webview/SimpleExample.swift +30 -86
  13. package/package.json +3 -7
  14. package/types/analytics/DiagnosticsOutbox.d.ts +22 -0
  15. package/types/analytics/DiagnosticsOutbox.d.ts.map +1 -0
  16. package/types/analytics/ReliableOutbox.d.ts +40 -0
  17. package/types/analytics/ReliableOutbox.d.ts.map +1 -0
  18. package/types/analytics/events.d.ts +100 -0
  19. package/types/analytics/events.d.ts.map +1 -1
  20. package/types/analytics/placementResolved.d.ts +150 -0
  21. package/types/analytics/placementResolved.d.ts.map +1 -0
  22. package/types/api/APIClient.d.ts +10 -2
  23. package/types/api/APIClient.d.ts.map +1 -1
  24. package/types/api/errorReportLimits.d.ts +50 -0
  25. package/types/api/errorReportLimits.d.ts.map +1 -0
  26. package/types/api/generated/types.d.ts +54 -7
  27. package/types/api/generated/types.d.ts.map +1 -1
  28. package/types/core/Configuration.d.ts +5 -0
  29. package/types/core/Configuration.d.ts.map +1 -1
  30. package/types/core/Encore.d.ts +61 -2
  31. package/types/core/Encore.d.ts.map +1 -1
  32. package/types/core/OfferManager.d.ts +29 -3
  33. package/types/core/OfferManager.d.ts.map +1 -1
  34. package/types/core/PlacementBuilder.d.ts +26 -2
  35. package/types/core/PlacementBuilder.d.ts.map +1 -1
  36. package/types/core/StrictUnlock.d.ts +20 -0
  37. package/types/core/StrictUnlock.d.ts.map +1 -0
  38. package/types/core/StrictUnlockReconciler.d.ts +94 -0
  39. package/types/core/StrictUnlockReconciler.d.ts.map +1 -0
  40. package/types/core/TransactionStore.d.ts +57 -13
  41. package/types/core/TransactionStore.d.ts.map +1 -1
  42. package/types/core/VerificationPoller.d.ts.map +1 -1
  43. package/types/core/claimBehavior.d.ts +28 -0
  44. package/types/core/claimBehavior.d.ts.map +1 -0
  45. package/types/core/errorContext.d.ts +18 -0
  46. package/types/core/errorContext.d.ts.map +1 -0
  47. package/types/core/errorType.d.ts +59 -0
  48. package/types/core/errorType.d.ts.map +1 -0
  49. package/types/core/hostDisplay.d.ts +50 -0
  50. package/types/core/hostDisplay.d.ts.map +1 -0
  51. package/types/core/useCase.d.ts +21 -0
  52. package/types/core/useCase.d.ts.map +1 -1
  53. package/types/core/version.d.ts +1 -1
  54. package/types/experiments/ExposureOutbox.d.ts +4 -28
  55. package/types/experiments/ExposureOutbox.d.ts.map +1 -1
  56. package/types/types.d.ts +188 -3
  57. package/types/types.d.ts.map +1 -1
  58. package/types/ui/OfferCard.d.ts +3 -1
  59. package/types/ui/OfferCard.d.ts.map +1 -1
  60. package/types/ui/OfferCarousel.d.ts +5 -0
  61. package/types/ui/OfferCarousel.d.ts.map +1 -1
  62. package/types/ui/OfferModal.d.ts +20 -0
  63. package/types/ui/OfferModal.d.ts.map +1 -1
  64. package/types/ui/PrimerScreen.d.ts +18 -11
  65. package/types/ui/PrimerScreen.d.ts.map +1 -1
  66. package/types/ui/RedemptionScreen.d.ts +15 -19
  67. package/types/ui/RedemptionScreen.d.ts.map +1 -1
  68. package/types/ui/RewardActions.d.ts +35 -0
  69. package/types/ui/RewardActions.d.ts.map +1 -1
  70. package/types/ui/appearance.d.ts +14 -0
  71. package/types/ui/appearance.d.ts.map +1 -1
  72. package/types/ui/brandComponents.d.ts.map +1 -1
  73. package/types/ui/styles.d.ts.map +1 -1
  74. package/types/utils/logger.d.ts +11 -1
  75. package/types/utils/logger.d.ts.map +1 -1
  76. package/embed/index.html +0 -57
  77. package/embed/styles.css +0 -154
  78. package/examples/ios-webview/EncoreWebViewBridge.swift +0 -419
  79. package/examples/ios-webview/ExampleViewController.swift +0 -233
@@ -10,17 +10,43 @@ export declare class OfferManager {
10
10
  #private;
11
11
  constructor(apiClient: APIClient, userId: string, analyticsClient?: AnalyticsClient);
12
12
  /**
13
- * Fetch offers from API with optional caching
13
+ * Fetch offers from API with optional caching.
14
+ *
15
+ * `maxPostbackTimeMs` (strict-unlock mode only) narrows the eligible set to
16
+ * campaigns whose postback latency fits the verification window. Because it
17
+ * changes WHICH offers come back, such a fetch neither reads nor writes the
18
+ * cache: a cached optimistic-mode set would leak unverifiable campaigns into a
19
+ * strict presentation, and caching the narrowed set would starve a later
20
+ * optimistic one. Matches iOS.
14
21
  */
15
- fetchOffers(userAttributes: UserAttributes, useCache?: boolean, placementId?: string): Promise<{
22
+ fetchOffers(userAttributes: UserAttributes, useCache?: boolean, placementId?: string, maxPostbackTimeMs?: number): Promise<{
16
23
  offers: OfferModel[];
17
24
  }>;
18
25
  /**
19
26
  * Begin a new presentation session. `variantId` is the SDUI variant this
20
27
  * presentation renders — stamped onto every event the session emits — and
21
28
  * `useCase` is retained so the page-lifecycle flush can stamp it too.
29
+ *
30
+ * `presentationId` is the ATTEMPT's id, minted by the caller before the flow
31
+ * started, so the events emitted here carry the same id as the ones emitted
32
+ * before a presentation session existed at all. Minting one here when the caller
33
+ * has none keeps this class usable standalone; Encore.ts always passes one.
34
+ */
35
+ /**
36
+ * `presentationId` is optional and the caller almost never passes it. `show()` mints
37
+ * the id before its first gate, so a presentation that never reaches this method
38
+ * still has one to report under; passing it here is what keeps that early id and the
39
+ * presentation's own id the same value. Absent a caller-supplied one this still mints,
40
+ * which is the behaviour every non-`show()` entry point relies on.
41
+ */
42
+ beginPresentation(variantId?: string, useCase?: UseCase, placementId?: string, presentationId?: string): string;
43
+ /**
44
+ * The live presentation's placement label, or undefined when the publisher gave
45
+ * none. Exposed for the strict-unlock pending record, which has to persist the
46
+ * dimension at claim time because the presentation holding it is gone by the time a
47
+ * cross-session verification lands.
22
48
  */
23
- beginPresentation(variantId?: string, useCase?: UseCase, placementId?: string): string;
49
+ get placementId(): string | undefined;
24
50
  /** The live presentation's id, or null between presentations. */
25
51
  get presentationId(): string | null;
26
52
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"OfferManager.d.ts","sourceRoot":"","sources":["../../src/core/OfferManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACxD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAMpE,qBAAa,YAAY;;gBAkDX,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,eAAe;IAOnF;;OAEG;IACG,WAAW,CACf,cAAc,EAAE,cAAc,EAC9B,QAAQ,UAAO,EACf,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC;QAAE,MAAM,EAAE,UAAU,EAAE,CAAA;KAAE,CAAC;IAmCpC;;;;OAIG;IACH,iBAAiB,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM;IAatF,iEAAiE;IACjE,IAAI,cAAc,IAAI,MAAM,GAAG,IAAI,CAElC;IAiBD;;OAEG;IACH,mBAAmB,CACjB,KAAK,EAAE,UAAU,EACjB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE,OAAO,GAChB,IAAI;IA8CP;;OAEG;IACH,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAQxC;;OAEG;IACH,iBAAiB,CACf,KAAK,EAAE,UAAU,EACjB,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE,OAAO,GAChB,IAAI;IAoBP;;OAEG;IACH,kBAAkB,CAChB,KAAK,EAAE,UAAU,EACjB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,aAAa,CAAC,EAAE,MAAM,EACtB,OAAO,CAAC,EAAE,OAAO,GAChB,IAAI;IAqBP;;OAEG;IACH,eAAe,CAAC,aAAa,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI;IA+FhE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAiCG;IACH,qBAAqB,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI;IAwCjE,kEAAkE;IAClE,OAAO,IAAI,IAAI;IAKf;;OAEG;IACG,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC;IAsB9E;;OAEG;IACH,UAAU,IAAI,IAAI;IAMlB;;OAEG;IACH,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;CAKhC"}
1
+ {"version":3,"file":"OfferManager.d.ts","sourceRoot":"","sources":["../../src/core/OfferManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACxD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAMpE,qBAAa,YAAY;;gBAkDX,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,eAAe;IAOnF;;;;;;;;;OASG;IACG,WAAW,CACf,cAAc,EAAE,cAAc,EAC9B,QAAQ,UAAO,EACf,WAAW,CAAC,EAAE,MAAM,EACpB,iBAAiB,CAAC,EAAE,MAAM,GACzB,OAAO,CAAC;QAAE,MAAM,EAAE,UAAU,EAAE,CAAA;KAAE,CAAC;IA8CpC;;;;;;;;;OASG;IACH;;;;;;OAMG;IACH,iBAAiB,CACf,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,OAAO,EACjB,WAAW,CAAC,EAAE,MAAM,EACpB,cAAc,CAAC,EAAE,MAAM,GACtB,MAAM;IAaT;;;;;OAKG;IACH,IAAI,WAAW,IAAI,MAAM,GAAG,SAAS,CAEpC;IAED,iEAAiE;IACjE,IAAI,cAAc,IAAI,MAAM,GAAG,IAAI,CAElC;IAiBD;;OAEG;IACH,mBAAmB,CACjB,KAAK,EAAE,UAAU,EACjB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE,OAAO,GAChB,IAAI;IA8CP;;OAEG;IACH,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAQxC;;OAEG;IACH,iBAAiB,CACf,KAAK,EAAE,UAAU,EACjB,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE,OAAO,GAChB,IAAI;IAoBP;;OAEG;IACH,kBAAkB,CAChB,KAAK,EAAE,UAAU,EACjB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,aAAa,CAAC,EAAE,MAAM,EACtB,OAAO,CAAC,EAAE,OAAO,GAChB,IAAI;IAqBP;;OAEG;IACH,eAAe,CAAC,aAAa,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI;IA+FhE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAiCG;IACH,qBAAqB,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI;IAwCjE,kEAAkE;IAClE,OAAO,IAAI,IAAI;IAKf;;OAEG;IACG,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC;IAsB9E;;OAEG;IACH,UAAU,IAAI,IAAI;IAMlB;;OAEG;IACH,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;CAKhC"}
@@ -2,16 +2,29 @@
2
2
  * Placement Builder
3
3
  * Fluent API for configuring and presenting offers
4
4
  */
5
- import type { PlacementBuilder as IPlacementBuilder, PlacementOptions, ShowResult, NotGrantedReason, UseCase } from '../types';
5
+ import type { PlacementBuilder as IPlacementBuilder, PlacementOptions, RedeemResult, ShowResult, NotGrantedReason, UseCase } from '../types';
6
6
  export type PresentationExecutor = (options?: PlacementOptions) => Promise<ShowResult>;
7
+ export type RedemptionExecutor = (placementId: string) => Promise<RedeemResult>;
7
8
  export declare class PlacementBuilder implements IPlacementBuilder {
8
9
  #private;
9
- constructor(id: string, executor: PresentationExecutor, options?: PlacementOptions);
10
+ constructor(id: string, executor: PresentationExecutor, options: PlacementOptions | undefined, redeemer: RedemptionExecutor);
10
11
  /**
11
12
  * Set this placement's use case (default `'reduceChurn'`) — the same `.useCase(...)` step
12
13
  * the native SDKs expose, so a cross-platform integration reads the same here.
13
14
  */
14
15
  useCase(useCase: UseCase): PlacementBuilder;
16
+ /**
17
+ * Override the sheet's headline for this presentation — the same
18
+ * `.headline(...)` step the native SDKs expose.
19
+ *
20
+ * Identical in effect to passing `headline` in {@link PlacementOptions}: the
21
+ * per-call override beats the backend-resolved copy, which beats the built-in
22
+ * fallback. A blank or whitespace-only value falls THROUGH to the resolved copy
23
+ * rather than blanking the sheet, so it can never erase shipped copy.
24
+ */
25
+ headline(text: string): PlacementBuilder;
26
+ /** Counterpart to {@link headline}: same precedence, same blank-falls-through rule. */
27
+ subheadline(text: string): PlacementBuilder;
15
28
  /**
16
29
  * Set callback for when user declines or offer not granted
17
30
  */
@@ -27,5 +40,16 @@ export declare class PlacementBuilder implements IPlacementBuilder {
27
40
  * PlacementOptions, supplied to `placement()` or through the builder steps.
28
41
  */
29
42
  show(): Promise<ShowResult>;
43
+ /**
44
+ * Redeem the claim made at this placement — phase 2 of the deferred flow.
45
+ *
46
+ * The id passed on is the builder's own; whether that SCOPES the lookup is the
47
+ * redeemer's call, because only a publisher-set id has claims filed under it (a
48
+ * minted one never reaches the wire). See {@link IPlacementBuilder.redeem}.
49
+ *
50
+ * Errors are already values on the redeem path, so there is nothing to catch —
51
+ * unlike show(), which wraps a whole presentation.
52
+ */
53
+ redeem(): Promise<RedeemResult>;
30
54
  }
31
55
  //# sourceMappingURL=PlacementBuilder.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"PlacementBuilder.d.ts","sourceRoot":"","sources":["../../src/core/PlacementBuilder.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EACV,gBAAgB,IAAI,iBAAiB,EACrC,gBAAgB,EAChB,UAAU,EACV,gBAAgB,EAChB,OAAO,EACR,MAAM,UAAU,CAAC;AAIlB,MAAM,MAAM,oBAAoB,GAAG,CAAC,OAAO,CAAC,EAAE,gBAAgB,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;AAEvF,qBAAa,gBAAiB,YAAW,iBAAiB;;gBAO5C,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,oBAAoB,EAAE,OAAO,CAAC,EAAE,gBAAgB;IAMlF;;;OAGG;IACH,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,gBAAgB;IAK3C;;OAEG;IACH,YAAY,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,GAAG,gBAAgB;IAK5E;;OAEG;IACH,oBAAoB,CAAC,QAAQ,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,IAAI,GAAG,gBAAgB;IAK9E;;;;;OAKG;IACG,IAAI,IAAI,OAAO,CAAC,UAAU,CAAC;CA6ClC"}
1
+ {"version":3,"file":"PlacementBuilder.d.ts","sourceRoot":"","sources":["../../src/core/PlacementBuilder.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EACV,gBAAgB,IAAI,iBAAiB,EACrC,gBAAgB,EAChB,YAAY,EACZ,UAAU,EACV,gBAAgB,EAChB,OAAO,EACR,MAAM,UAAU,CAAC;AAIlB,MAAM,MAAM,oBAAoB,GAAG,CAAC,OAAO,CAAC,EAAE,gBAAgB,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;AACvF,MAAM,MAAM,kBAAkB,GAAG,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;AAEhF,qBAAa,gBAAiB,YAAW,iBAAiB;;gBAatD,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,oBAAoB,EAC9B,OAAO,EAAE,gBAAgB,GAAG,SAAS,EACrC,QAAQ,EAAE,kBAAkB;IAQ9B;;;OAGG;IACH,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,gBAAgB;IAK3C;;;;;;;;OAQG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB;IAKxC,uFAAuF;IACvF,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB;IAK3C;;OAEG;IACH,YAAY,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,GAAG,gBAAgB;IAK5E;;OAEG;IACH,oBAAoB,CAAC,QAAQ,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,IAAI,GAAG,gBAAgB;IAK9E;;;;;OAKG;IACG,IAAI,IAAI,OAAO,CAAC,UAAU,CAAC;IA8CjC;;;;;;;;;OASG;IACG,MAAM,IAAI,OAAO,CAAC,YAAY,CAAC;CAItC"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Strict-unlock mode constants.
3
+ *
4
+ * One source of truth so the verification poll window and the `maxPostbackTimeMs`
5
+ * offer filter cannot drift apart — the same reason iOS ties them together in
6
+ * `StrictUnlock.swift`: serving an offer whose postback SLA cannot plausibly land
7
+ * inside the window the poller is willing to wait guarantees a claim that never
8
+ * verifies in session.
9
+ */
10
+ /** How long a verification poll waits before giving up. Mirrors iOS's 15s. */
11
+ export declare const POLL_TIMEOUT_MS = 15000;
12
+ /** Sent as `maxPostbackTimeMs` on `/offers/search` — strict mode only. */
13
+ export declare const MAX_POSTBACK_TIME_MS = 15000;
14
+ /**
15
+ * How long a pending claim is retried across sessions before it is dropped. Past
16
+ * this the campaign's postback window is long gone and the row will never verify.
17
+ * Mirrors iOS's `StrictUnlockReconciler.maxAge`.
18
+ */
19
+ export declare const RECONCILE_MAX_AGE_MS: number;
20
+ //# sourceMappingURL=StrictUnlock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StrictUnlock.d.ts","sourceRoot":"","sources":["../../src/core/StrictUnlock.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,8EAA8E;AAC9E,eAAO,MAAM,eAAe,QAAS,CAAC;AAEtC,0EAA0E;AAC1E,eAAO,MAAM,oBAAoB,QAAkB,CAAC;AAEpD;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,QAAuB,CAAC"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Strict Unlock Reconciler
3
+ *
4
+ * Owns the persistence and the poll primitive for a strict-mode claim awaiting
5
+ * advertiser verification. WHEN a pass runs (claim time, page load, foreground) is
6
+ * wired in Encore.ts — this class deliberately knows nothing about lifecycle, the
7
+ * same split iOS draws between `StrictUnlockReconciler` and its composition root.
8
+ *
9
+ * Persist-to-storage shape follows SignalManager's, applied to a single pending
10
+ * claim rather than a queue: only the MOST RECENT claim needs tracking, so a new
11
+ * notePending() simply overwrites — matching iOS, which keeps one pending id.
12
+ */
13
+ import type { StorageManager } from './StorageManager';
14
+ import type { APIClient } from '../api/APIClient';
15
+ import type { UseCase, VerificationStatus } from '../types';
16
+ export interface PendingClaim {
17
+ transactionId: string;
18
+ /** ISO 8601. */
19
+ recordedAt: string;
20
+ /**
21
+ * Whether verifying this claim should send the entitlement grant signal. Stored
22
+ * rather than recomputed because the reconcile pass runs on a page load that has
23
+ * no offer, no placement and no use case in scope — the claim's own record is the
24
+ * only thing that still knows. Absent on a record written before this field
25
+ * existed, and read as false: a missing grant is recoverable, an unearned one is
26
+ * not.
27
+ */
28
+ grantsEntitlement?: boolean;
29
+ /**
30
+ * The placement and use case the claim was made under, persisted for the same
31
+ * reason `grantsEntitlement` is: the sheet that knew them is gone by the time a
32
+ * cross-session verification lands, and the claim's own record is the only thing
33
+ * that still does.
34
+ *
35
+ * Without them the reconciled `sdk_offer_verified` is the ONE conversion signal
36
+ * that cannot be sliced — strict-mode verifications would sit outside every
37
+ * per-use-case and per-placement conversion split, which is precisely the
38
+ * comparison strict mode exists to be measured by. Mirrors iOS, which persists
39
+ * both beside the transaction id (swift#123, `StrictUnlockReconciler.notePending`).
40
+ *
41
+ * Both optional and both absent on a record written before this field existed.
42
+ * Absent stays absent on the event rather than being reconstructed — a guessed
43
+ * dimension is worse than a missing one, because it looks like coverage.
44
+ */
45
+ placementId?: string;
46
+ useCase?: UseCase;
47
+ }
48
+ export declare class StrictUnlockReconciler {
49
+ #private;
50
+ constructor(storage: StorageManager, apiClient: APIClient, userId: string);
51
+ /**
52
+ * Re-key onto a new identity, CARRYING the pending claim over.
53
+ *
54
+ * SignalManager, the sibling this class's persistence follows, drops its queue
55
+ * on the same event. This deliberately differs: identify() is an ALIAS on the
56
+ * backend (`identifyUser(previousUserId, userId)` — the anonymous id is merged
57
+ * into the real one, not replaced by a different person), so a claim made
58
+ * seconds earlier belongs to the very same user, and abandoning it would mean
59
+ * their unlock silently never lands. reset() is the destructive path, and it
60
+ * clears storage before this runs, so nothing carries over there.
61
+ */
62
+ setUserId(userId: string): void;
63
+ /**
64
+ * Record a claim as awaiting verification. Called as soon as the transaction id
65
+ * exists and BEFORE the advertiser redirect opens, so a tab closed one moment
66
+ * later is still recoverable on a later page load.
67
+ */
68
+ notePending(transactionId: string, options?: {
69
+ grantsEntitlement?: boolean;
70
+ placementId?: string;
71
+ useCase?: UseCase;
72
+ }): void;
73
+ /** Forget the pending claim — verified, dropped as stale, or malformed. */
74
+ clearPending(): void;
75
+ /**
76
+ * The pending claim, or null when there is none. A malformed record, an
77
+ * unusable id, or one older than {@link RECONCILE_MAX_AGE_MS} is DROPPED here
78
+ * rather than returned, so a bad record can never wedge the reconcile pass into
79
+ * re-reading it every foreground for a week.
80
+ *
81
+ * A `recordedAt` in the future is treated as unusable too: the clock it was
82
+ * written against is not the clock reading it (a device clock correction, a
83
+ * hand-edited value), and a negative age would otherwise never age out.
84
+ */
85
+ getPending(): PendingClaim | null;
86
+ /**
87
+ * Poll for verification, bounded by `timeoutMs` — defaulting to the shared
88
+ * {@link POLL_TIMEOUT_MS} so a claim-time poll and a reconcile-pass poll wait the
89
+ * same window unless a caller has a reason to differ. Never throws: a network
90
+ * failure reads as 'pending', i.e. try again next foreground.
91
+ */
92
+ verify(transactionId: string, timeoutMs?: number): Promise<VerificationStatus>;
93
+ }
94
+ //# sourceMappingURL=StrictUnlockReconciler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StrictUnlockReconciler.d.ts","sourceRoot":"","sources":["../../src/core/StrictUnlockReconciler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAIlD,OAAO,KAAK,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAa5D,MAAM,WAAW,YAAY;IAC3B,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB;;;;;;;OAOG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B;;;;;;;;;;;;;;;OAeG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,qBAAa,sBAAsB;;gBAKrB,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM;IAMzE;;;;;;;;;;OAUG;IACH,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAQ/B;;;;OAIG;IACH,WAAW,CACT,aAAa,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE;QAAE,iBAAiB,CAAC,EAAE,OAAO,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,GACjF,IAAI;IAgBP,2EAA2E;IAC3E,YAAY,IAAI,IAAI;IAKpB;;;;;;;;;OASG;IACH,UAAU,IAAI,YAAY,GAAG,IAAI;IAsCjC;;;;;OAKG;IACG,MAAM,CAAC,aAAa,EAAE,MAAM,EAAE,SAAS,GAAE,MAAwB,GAAG,OAAO,CAAC,kBAAkB,CAAC;CAiBtG"}
@@ -1,35 +1,79 @@
1
1
  /**
2
2
  * TransactionStore
3
3
  *
4
- * Local persistence for the two-phase (transaction -> redeem) flow. Backed by
5
- * StorageManager (localStorage-first), it holds:
6
- * - transactions: transactionId -> Transaction
7
- * - placements: placementId -> transactionId (the per-placement live-transaction map)
8
- * - latest: transactionId of the most recently created transaction
4
+ * Local record of claims awaiting redemption. Holds:
5
+ * - transactions: transactionId -> Transaction
6
+ * - placements: placementId -> transactionId (the per-placement live-claim map)
7
+ * - latest: the most recently created transaction
9
8
  *
10
- * This is the fast path; the server transaction record (keyed by app_account_id, carrying
11
- * placementId) is the durable source of truth for cross-page / post-localStorage-loss
12
- * recovery. Expired or redeemed transactions are filtered out of the lookups.
9
+ * The BACKING is injected, and that is the whole of the difference between the two
10
+ * deferred behaviours: `deferred` writes through StorageManager and survives a
11
+ * reload; `deferredWhileAlive` writes to a plain object that dies with the page.
12
+ * Both then resolve, prune and expire identically — one implementation, so the
13
+ * session-scoped mode cannot quietly drift from the durable one.
14
+ *
15
+ * The server transaction record (keyed by app_account_id) remains the durable
16
+ * source of truth for cross-device recovery; this is the fast path.
17
+ *
18
+ * Expired and redeemed claims are filtered out of the RESOLVING lookups —
19
+ * `getLatest` and `getByPlacement`, the two that answer "what can be redeemed
20
+ * now". `getByTransactionId` deliberately does not filter: it answers "what is on
21
+ * record for this exact id", so it can report that a claim was redeemed.
22
+ *
23
+ * That report is not durable, and callers must not treat it as one: `#prune` drops
24
+ * redeemed and expired entries on the NEXT write, so a redeemed claim is readable
25
+ * only until then. The store is a cache of what is still actionable, not a ledger.
13
26
  */
14
27
  import type { Transaction } from '../types';
15
28
  import type { StorageManager } from './StorageManager';
29
+ interface TransactionStoreState {
30
+ transactions: Record<string, Transaction>;
31
+ placements: Record<string, string>;
32
+ latest: string | null;
33
+ }
34
+ /** Where a store keeps its state. The only thing the two behaviours disagree on. */
35
+ export interface TransactionBacking {
36
+ read(): TransactionStoreState | null;
37
+ write(state: TransactionStoreState): void;
38
+ }
39
+ /**
40
+ * A claim's creation time in ms, with an unparseable one pinned to 0 (oldest).
41
+ *
42
+ * Sorting on a raw `getTime()` puts NaN into the comparator, and a comparator that
43
+ * returns NaN makes the whole ordering implementation-defined — so ONE undateable
44
+ * record could change which claim is picked as "latest" among perfectly good ones.
45
+ * Deterministic beats correct-looking here: this store already defends against
46
+ * corrupted state, and the ordering has to be defended in the same breath.
47
+ */
48
+ export declare function createdAtMs(transaction: {
49
+ createdAt: string;
50
+ }): number;
51
+ /** Durable: localStorage via StorageManager. Survives the page load. */
52
+ export declare function persistentBacking(storage: StorageManager): TransactionBacking;
53
+ /**
54
+ * Session-scoped: a closure. Deliberately touches NO storage API at all — not the
55
+ * key, not StorageManager — so `deferredWhileAlive` cannot leak a claim to disk
56
+ * through a shared code path.
57
+ */
58
+ export declare function ephemeralBacking(): TransactionBacking;
16
59
  export declare class TransactionStore {
17
60
  #private;
18
- constructor(storage: StorageManager);
61
+ constructor(backing: TransactionBacking);
19
62
  /** Persist a new transaction, updating the placement map and the latest pointer. */
20
63
  save(transaction: Transaction): void;
21
- /** Resolve a transaction by exact transaction id (any status). */
64
+ /** Resolve a transaction by exact id (any status). */
22
65
  getByTransactionId(transactionId: string): Transaction | null;
23
66
  /**
24
- * Resolve the LIVE transaction made at a placement. Returns null if none/expired/redeemed —
67
+ * The LIVE transaction claimed at a placement. Null if none/expired/redeemed —
25
68
  * never crosses to another placement's transaction.
26
69
  */
27
70
  getByPlacement(placementId: string): Transaction | null;
28
- /** Resolve the single most-recent LIVE transaction for this user (the flat redeem() fallback). */
71
+ /** The single most-recent LIVE transaction (the flat redeem() fallback). */
29
72
  getLatest(): Transaction | null;
30
73
  /** Mark a transaction redeemed (idempotent). Frees its placement slot. */
31
74
  markRedeemed(transactionId: string): void;
32
- /** Clear all transactions (used by reset()). */
75
+ /** Clear every transaction (reset()). */
33
76
  clear(): void;
34
77
  }
78
+ export {};
35
79
  //# sourceMappingURL=TransactionStore.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"TransactionStore.d.ts","sourceRoot":"","sources":["../../src/core/TransactionStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAavD,qBAAa,gBAAgB;;gBAGf,OAAO,EAAE,cAAc;IAwBnC,oFAAoF;IACpF,IAAI,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI;IAepC,kEAAkE;IAClE,kBAAkB,CAAC,aAAa,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI;IAI7D;;;OAGG;IACH,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI;IAQvD,kGAAkG;IAClG,SAAS,IAAI,WAAW,GAAG,IAAI;IAa/B,0EAA0E;IAC1E,YAAY,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI;IA8BzC,gDAAgD;IAChD,KAAK,IAAI,IAAI;CAGd"}
1
+ {"version":3,"file":"TransactionStore.d.ts","sourceRoot":"","sources":["../../src/core/TransactionStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAKvD,UAAU,qBAAqB;IAC7B,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAC1C,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED,oFAAoF;AACpF,MAAM,WAAW,kBAAkB;IACjC,IAAI,IAAI,qBAAqB,GAAG,IAAI,CAAC;IACrC,KAAK,CAAC,KAAK,EAAE,qBAAqB,GAAG,IAAI,CAAC;CAC3C;AAID;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,WAAW,EAAE;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAGtE;AA2BD,wEAAwE;AACxE,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,cAAc,GAAG,kBAAkB,CAK7E;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,kBAAkB,CAQrD;AAED,qBAAa,gBAAgB;;gBAGf,OAAO,EAAE,kBAAkB;IAwDvC,oFAAoF;IACpF,IAAI,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI;IAepC,sDAAsD;IACtD,kBAAkB,CAAC,aAAa,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI;IAI7D;;;OAGG;IACH,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI;IAQvD,4EAA4E;IAC5E,SAAS,IAAI,WAAW,GAAG,IAAI;IAa/B,0EAA0E;IAC1E,YAAY,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI;IA2BzC,yCAAyC;IACzC,KAAK,IAAI,IAAI;CAGd"}
@@ -1 +1 @@
1
- {"version":3,"file":"VerificationPoller.d.ts","sourceRoot":"","sources":["../../src/core/VerificationPoller.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAGnD,MAAM,WAAW,yBAAyB;IACxC,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;CACxB;AAED,qBAAa,kBAAkB;;gBAUjB,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,yBAAyB;IAMpE;;;OAGG;IACG,IAAI,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAkBzC;;OAEG;IACH,IAAI,IAAI,IAAI;CAkFb"}
1
+ {"version":3,"file":"VerificationPoller.d.ts","sourceRoot":"","sources":["../../src/core/VerificationPoller.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAInD,MAAM,WAAW,yBAAyB;IACxC,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;CACxB;AAED,qBAAa,kBAAkB;;gBAYjB,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,yBAAyB;IAMpE;;;OAGG;IACG,IAAI,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAkBzC;;OAEG;IACH,IAAI,IAAI,IAAI;CAqGb"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * `claimBehavior` — what a claim does with the advertiser handoff.
3
+ *
4
+ * 🔴 NOT A PUBLISHER OPTION. This is data on the VARIANT, the same way the reward
5
+ * sheet's copy and button actions are: `RewardActions.ts` tracks its variant's
6
+ * actions by symbol because web has no SDUI engine, and this file tracks the
7
+ * variant's claim behaviour the same way. It is deliberately absent from
8
+ * `PlacementOptions` and from `configure()` — 2.0.1's `redemptionMode` was a
9
+ * config knob, and making zero-config behaviour depend on a knob is what let a
10
+ * default flip break every integration that never set one.
11
+ *
12
+ * immediate redirect inside the click gesture; nothing is persisted.
13
+ * deferred persist the claim, hold the primer, redirect from redeem()
14
+ * — which may run on a LATER PAGE LOAD.
15
+ * deferredWhileAlive hold the claim in memory for this session only; never
16
+ * touch storage. Gone on reload, by design.
17
+ *
18
+ * The defaults below are the built-in variants' values and restore pre-2.0.2
19
+ * zero-config behaviour: `reduceChurn` is deferred (the host runs its own
20
+ * conversion, then redeems), `rewardUsers` is immediate (matching swift).
21
+ */
22
+ import type { UseCase } from '../types';
23
+ export type ClaimBehavior = 'immediate' | 'deferred' | 'deferredWhileAlive';
24
+ /** Whether a behaviour keeps the claim past the click — i.e. redeem() has work. */
25
+ export declare function isDeferred(behavior: ClaimBehavior): boolean;
26
+ /** The behaviour for a presentation: the variant's value, else the built-in default. */
27
+ export declare function claimBehaviorFor(useCase: UseCase, variantValues?: unknown): ClaimBehavior;
28
+ //# sourceMappingURL=claimBehavior.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claimBehavior.d.ts","sourceRoot":"","sources":["../../src/core/claimBehavior.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAExC,MAAM,MAAM,aAAa,GAAG,WAAW,GAAG,UAAU,GAAG,oBAAoB,CAAC;AAE5E,mFAAmF;AACnF,wBAAgB,UAAU,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAE3D;AAmCD,wFAAwF;AACxF,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,aAAa,CAAC,EAAE,OAAO,GAAG,aAAa,CAEzF"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Where an error happened, as the backend's error-reporting taxonomy.
3
+ *
4
+ * The eleven values are copied verbatim from the Swift and Android SDKs. The
5
+ * backend fingerprints an issue as `[errorType, context]`, so a value invented
6
+ * here would split one cross-platform defect into a separate issue per
7
+ * platform instead of grouping it.
8
+ *
9
+ * Before this, web sent free prose ('Show flow error', 'Offer flow error'),
10
+ * which fingerprinted against nothing the other two SDKs emit.
11
+ *
12
+ * Deliberately not exported from `index.ts`: it is an internal wire vocabulary,
13
+ * not something a publisher passes in. Add a value here only together with the
14
+ * same value in Swift and Android.
15
+ */
16
+ export declare const ERROR_CONTEXTS: readonly ["configuration", "present_offer_initialization", "fetch_offer_data", "start_transaction", "log_impression", "fetch_entitlements", "verify_transaction", "grant_signal", "api_request", "outbox", "analytics"];
17
+ export type ErrorContext = (typeof ERROR_CONTEXTS)[number];
18
+ //# sourceMappingURL=errorContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errorContext.d.ts","sourceRoot":"","sources":["../../src/core/errorContext.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,cAAc,yNAYjB,CAAC;AAEX,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * The `errorType` half of the error-report fingerprint.
3
+ *
4
+ * The backend groups a Sentry issue by `[errorType, context]`, so this value
5
+ * has to mean the same thing on every SDK. Swift and Android both emit it from
6
+ * a sealed `EncoreError` hierarchy via `typeIdentifier`. web reported
7
+ * `error.constructor.name` instead, which is `"Error"` for essentially
8
+ * everything, so web errors grouped by `context` alone and could never join
9
+ * their iOS and Android counterparts.
10
+ *
11
+ * What was missing was never a taxonomy. web already has `ErrorCode`, and
12
+ * `APIClient` already attaches it to the errors it throws. This maps that
13
+ * existing structure onto the shared wire vocabulary.
14
+ *
15
+ * Deliberately NOT a rewrite into a sealed hierarchy. That is still worth doing
16
+ * (it would make the type intrinsic to the error rather than derived at the
17
+ * boundary, so a throw from outside `APIClient` would carry it too), and it
18
+ * remains its own ticket. This closes the fingerprint gap without waiting for
19
+ * it.
20
+ */
21
+ /**
22
+ * The wire vocabulary, identical to Swift's and Android's `typeIdentifier`.
23
+ * A value invented here would split one defect into a separate issue per
24
+ * platform, which is the whole thing this exists to prevent.
25
+ */
26
+ export declare const ERROR_TYPES: readonly ["network_error", "persistence_error", "http_error", "api_error", "decoding_error", "not_configured", "invalid_api_key", "invalid_url", "domain_error"];
27
+ export type ErrorTypeIdentifier = (typeof ERROR_TYPES)[number];
28
+ /**
29
+ * The server's own error code and status, for a report's metadata.
30
+ *
31
+ * Grouping is canonical across platforms; this is how the detail survives that.
32
+ * A backend `UNAUTHORIZED` and a backend `OFFER_EXPIRED` both group as
33
+ * `api_error`, and stay distinguishable by this field in Cloud Logging, or as
34
+ * an indexed tag if the backend ever promotes it.
35
+ */
36
+ export declare function serverDetailOf(error: unknown): Record<string, string>;
37
+ /**
38
+ * Deliberately NOT mapped, and this is the subtle half.
39
+ *
40
+ * `UNAUTHORIZED` and `NOT_FOUND` arrive as `data.code` in a server error body,
41
+ * so they describe the SERVER's verdict, not a client-side condition. Swift and
42
+ * Android turn any intelligible server rejection into `api_error`, and reserve
43
+ * `invalid_api_key` for their own client-side key validation. Mapping them here
44
+ * made the same backend 401 fingerprint as `[invalid_api_key, api_request]` on
45
+ * web and `[api_error, api_request]` on mobile, which is precisely the split
46
+ * this vocabulary exists to prevent.
47
+ *
48
+ * They fall through to `api_error`. The server's own code is not lost: it is
49
+ * echoed into the report as `serverCode`, where it segments without changing
50
+ * how anything groups.
51
+ */
52
+ /**
53
+ * Resolves an unknown caught value to a shared `errorType`.
54
+ *
55
+ * Total by construction: anything unrecognised is `domain_error`, matching how
56
+ * Swift and Android wrap a foreign throwable. Reporting must never throw.
57
+ */
58
+ export declare function errorTypeOf(error: unknown): ErrorTypeIdentifier;
59
+ //# sourceMappingURL=errorType.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errorType.d.ts","sourceRoot":"","sources":["../../src/core/errorType.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAIH;;;;GAIG;AACH,eAAO,MAAM,WAAW,kKAUd,CAAC;AAEX,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAyB/D;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAWrE;AAED;;;;;;;;;;;;;;GAcG;AAEH;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,mBAAmB,CA8B/D"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Host display nouns + the deferred flow's composed copy.
3
+ *
4
+ * The nouns name the PUBLISHER's product (the host), as distinct from the
5
+ * advertiser on the offer. They are resolved fresh at each screen from the
6
+ * then-current remote config — nothing about them is persisted on a transaction,
7
+ * which stores transactional facts only.
8
+ *
9
+ * Everything the primer and redemption screens say is composed here. The screens
10
+ * never concatenate nouns themselves, so one sentence has one source.
11
+ *
12
+ * Absent nouns are NEVER an error. 2.0.1 failed the whole presentation with a
13
+ * CONFIGURATION_ERROR when the app icon was unset; an SDK that refuses to present
14
+ * because a logo is missing is worse than one that presents a quieter sentence.
15
+ * The screens degrade instead — see PrimerScreen's 'holding' variant.
16
+ */
17
+ export interface HostDisplay {
18
+ appDisplayName?: string;
19
+ /** Composed, display-only, e.g. "1 month". Never parsed back into a number. */
20
+ trialPeriod?: string;
21
+ logoUrl?: string;
22
+ }
23
+ /** The remote values the nouns resolve from. All optional — the fetch may not have landed. */
24
+ export interface RemoteHostSource {
25
+ appName?: string;
26
+ entitlementValue?: string;
27
+ entitlementUnit?: string;
28
+ /** `/config` `ui.values.media.appstoreIcon`. */
29
+ appIconUrl?: string;
30
+ /** `entitlements.native.durationDays` — the trial-end line's only input. */
31
+ trialDurationDays?: number;
32
+ }
33
+ /** Resolve the host nouns. Every field independently optional. */
34
+ export declare function resolveHostDisplay(source: RemoteHostSource): HostDisplay;
35
+ /** The deferred flow's sentences, each with exactly one definition. */
36
+ export declare const displayCopy: {
37
+ readonly primerTitle: (app: string, trial?: string) => string;
38
+ readonly primerSubtitle: (app: string) => string;
39
+ readonly primerCta: (app: string, trial?: string) => string;
40
+ /** The holding story: the host is unnamed, so the sentence is about the reward. */
41
+ readonly holdingTitle: () => string;
42
+ readonly holdingSubtitle: (advertiser?: string) => string;
43
+ readonly holdingCta: () => string;
44
+ readonly s2Title: (app: string, trial?: string) => string;
45
+ readonly s2Subtitle: (app: string) => string;
46
+ /** Host-row detail composed from the remote durationDays and the redemption moment. */
47
+ readonly s2HostDetail: (trialEnd: Date) => string;
48
+ readonly s2Cta: () => string;
49
+ };
50
+ //# sourceMappingURL=hostDisplay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hostDisplay.d.ts","sourceRoot":"","sources":["../../src/core/hostDisplay.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,WAAW,WAAW;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,+EAA+E;IAC/E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,8FAA8F;AAC9F,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gDAAgD;IAChD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4EAA4E;IAC5E,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AA+BD,kEAAkE;AAClE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,gBAAgB,GAAG,WAAW,CASxE;AAED,uEAAuE;AACvE,eAAO,MAAM,WAAW;gCACH,MAAM,UAAU,MAAM,KAAG,MAAM;mCAE5B,MAAM,KAAG,MAAM;8BAEpB,MAAM,UAAU,MAAM,KAAG,MAAM;IAEhD,mFAAmF;iCACjE,MAAM;4CACO,MAAM,KAAG,MAAM;+BAI9B,MAAM;4BACP,MAAM,UAAU,MAAM,KAAG,MAAM;+BAI5B,MAAM,KAAG,MAAM;IACjC,uFAAuF;sCAC9D,IAAI,KAAG,MAAM;0BAM3B,MAAM;CACT,CAAC"}
@@ -58,5 +58,26 @@ export declare function fromWireUseCase(wire: string | null | undefined): UseCas
58
58
  * resolved from the config response's `useCases` map at show()-time and fails closed
59
59
  * as `no_template`, not `INVALID_REQUEST`.
60
60
  */
61
+ /** Whether `value` is one of the recognised use cases. The allow-list, as a guard. */
62
+ export declare function isSupportedUseCase(value: unknown): value is UseCase;
63
+ /**
64
+ * The use case to REPORT for an attempt, given whatever the caller passed.
65
+ *
66
+ * `sdk_show_entered` is emitted at the very top of `show()`, above `checkUseCase`, so
67
+ * it is the one event that can see a value validation has not yet rejected. Its
68
+ * `use_case` feeds a closed cross-SDK enum dimension, and web must not be the SDK that
69
+ * widens it with a publisher's typo: a free-text value there does not error, it just
70
+ * creates a junk partition alongside the real ones in every per-use-case rollup.
71
+ *
72
+ * So an unrecognised value reports as the default, exactly as an omitted one does. The
73
+ * attempt is going to abort a few lines later either way, and the integration error is
74
+ * already reported through `onError`, the logger and `#reportError` — three channels
75
+ * that name the bad value, which the analytics dimension deliberately does not.
76
+ *
77
+ * Not a substitute for `checkUseCase`: this decides what to REPORT, that decides
78
+ * whether to PROCEED. Using this one to gate would silently serve the paywall for a
79
+ * typo, which is the exact fail-open `checkUseCase` exists to prevent.
80
+ */
81
+ export declare function reportableUseCase(value: unknown): UseCase;
61
82
  export declare function checkUseCase(value: unknown): EncoreError | null;
62
83
  //# sourceMappingURL=useCase.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useCase.d.ts","sourceRoot":"","sources":["../../src/core/useCase.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EAAa,KAAK,WAAW,EAAE,KAAK,OAAO,EAAE,MAAM,UAAU,CAAC;AAErE;;;;GAIG;AACH,MAAM,MAAM,WAAW,GAAG,oBAAoB,GAAG,oBAAoB,CAAC;AAuBtE,8EAA8E;AAC9E,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,WAAW,CAE3D;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,CAGpF;AAOD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,WAAW,GAAG,IAAI,CAS/D"}
1
+ {"version":3,"file":"useCase.d.ts","sourceRoot":"","sources":["../../src/core/useCase.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EAAa,KAAK,WAAW,EAAE,KAAK,OAAO,EAAE,MAAM,UAAU,CAAC;AAErE;;;;GAIG;AACH,MAAM,MAAM,WAAW,GAAG,oBAAoB,GAAG,oBAAoB,CAAC;AAuBtE,8EAA8E;AAC9E,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,WAAW,CAE3D;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,CAGpF;AAOD;;;;;;;;;;;;;;;;;GAiBG;AACH,sFAAsF;AACtF,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,OAAO,CAEnE;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAEzD;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,WAAW,GAAG,IAAI,CAS/D"}
@@ -1,3 +1,3 @@
1
1
  /** SDK version — single source of truth (also kept in sync with package.json via scripts/update-version.sh) */
2
- export declare const SDK_VERSION = "2.0.3";
2
+ export declare const SDK_VERSION = "2.0.6";
3
3
  //# sourceMappingURL=version.d.ts.map
@@ -2,36 +2,12 @@
2
2
  * Reliable delivery for the NCL exposure event — the A/B denominator.
3
3
  *
4
4
  * Exposure MUST survive tab-close, so unlike the fire-and-forget AnalyticsClient
5
- * this path is storage-backed and retried.
6
- *
7
- * Delivery primitive: `fetch(url, { keepalive: true })` — NOT `navigator.sendBeacon`.
8
- * The ingest endpoint authenticates on the `X-Analytics-Key` request header, and
9
- * sendBeacon cannot set headers (a beacon would arrive unauthenticated). keepalive
10
- * fetch survives document unload like a beacon AND carries the auth header.
11
- *
12
- * Reliability model:
13
- * - enqueue: persist the envelope, then keepalive-POST; remove on 2xx.
14
- * - flush: replay every persisted envelope (on SDK init + on pagehide /
15
- * visibilitychange:hidden) so a send that died with the tab retries.
16
- * - envelopes carry a STABLE event_id → retries are idempotent backend-side.
17
- * - an in-memory in-flight set avoids duplicate concurrent sends.
18
- * - all storage / window / document access is SSR- and failure-guarded (fail-open).
5
+ * this path is storage-backed and retried. See `ReliableOutbox` for the shared
6
+ * mechanism (keepalive fetch, persist-then-send, lifecycle-triggered flush).
19
7
  */
20
- import type { AnalyticsEvent } from '../analytics/models';
8
+ import { ReliableOutbox } from '../analytics/ReliableOutbox';
21
9
  import type { StorageManager } from '../core/StorageManager';
22
- export declare class ExposureOutbox {
23
- #private;
10
+ export declare class ExposureOutbox extends ReliableOutbox {
24
11
  constructor(apiKey: string, analyticsBaseURL: string, storage: StorageManager);
25
- /**
26
- * Persist an exposure event and attempt delivery. `eventId` must be stable for a
27
- * given (user, epoch) so retries de-duplicate backend-side. Returns whether the
28
- * envelope durably landed in the configured storage tier: a quota-driven
29
- * fallback-to-memory write is invisible to a fresh read, so the caller can avoid
30
- * marking the epoch logged (and re-enqueue on the next trigger) instead of
31
- * silently dropping the exposure.
32
- */
33
- enqueue(event: AnalyticsEvent, eventId: string): boolean;
34
- /** Replay every persisted envelope (init recovery + unload flush). */
35
- flush(): void;
36
12
  }
37
13
  //# sourceMappingURL=ExposureOutbox.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ExposureOutbox.d.ts","sourceRoot":"","sources":["../../src/experiments/ExposureOutbox.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAiB,MAAM,qBAAqB,CAAC;AAEzE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAK7D,qBAAa,cAAc;;gBAMb,MAAM,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc;IAO7E;;;;;;;OAOG;IACH,OAAO,CAAC,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO;IAaxD,sEAAsE;IACtE,KAAK,IAAI,IAAI;CAoDd"}
1
+ {"version":3,"file":"ExposureOutbox.d.ts","sourceRoot":"","sources":["../../src/experiments/ExposureOutbox.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAI7D,qBAAa,cAAe,SAAQ,cAAc;gBACpC,MAAM,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc;CAG9E"}