@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.
- package/README.md +112 -40
- package/dist/cjs/index.cjs +1 -1
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/umd/encore.min.js +1 -1
- package/dist/umd/encore.min.js.map +1 -1
- package/embed/README.md +82 -367
- package/examples/ios-webview/EncoreURLBuilder.swift +179 -61
- package/examples/ios-webview/README.md +75 -354
- package/examples/ios-webview/SimpleEncoreView.swift +49 -36
- package/examples/ios-webview/SimpleExample.swift +30 -86
- package/package.json +3 -7
- package/types/analytics/DiagnosticsOutbox.d.ts +22 -0
- package/types/analytics/DiagnosticsOutbox.d.ts.map +1 -0
- package/types/analytics/ReliableOutbox.d.ts +40 -0
- package/types/analytics/ReliableOutbox.d.ts.map +1 -0
- package/types/analytics/events.d.ts +100 -0
- package/types/analytics/events.d.ts.map +1 -1
- package/types/analytics/placementResolved.d.ts +150 -0
- package/types/analytics/placementResolved.d.ts.map +1 -0
- package/types/api/APIClient.d.ts +10 -2
- package/types/api/APIClient.d.ts.map +1 -1
- package/types/api/errorReportLimits.d.ts +50 -0
- package/types/api/errorReportLimits.d.ts.map +1 -0
- package/types/api/generated/types.d.ts +54 -7
- package/types/api/generated/types.d.ts.map +1 -1
- package/types/core/Configuration.d.ts +5 -0
- package/types/core/Configuration.d.ts.map +1 -1
- package/types/core/Encore.d.ts +61 -2
- package/types/core/Encore.d.ts.map +1 -1
- package/types/core/OfferManager.d.ts +29 -3
- package/types/core/OfferManager.d.ts.map +1 -1
- package/types/core/PlacementBuilder.d.ts +26 -2
- package/types/core/PlacementBuilder.d.ts.map +1 -1
- package/types/core/StrictUnlock.d.ts +20 -0
- package/types/core/StrictUnlock.d.ts.map +1 -0
- package/types/core/StrictUnlockReconciler.d.ts +94 -0
- package/types/core/StrictUnlockReconciler.d.ts.map +1 -0
- package/types/core/TransactionStore.d.ts +57 -13
- package/types/core/TransactionStore.d.ts.map +1 -1
- package/types/core/VerificationPoller.d.ts.map +1 -1
- package/types/core/claimBehavior.d.ts +28 -0
- package/types/core/claimBehavior.d.ts.map +1 -0
- package/types/core/errorContext.d.ts +18 -0
- package/types/core/errorContext.d.ts.map +1 -0
- package/types/core/errorType.d.ts +59 -0
- package/types/core/errorType.d.ts.map +1 -0
- package/types/core/hostDisplay.d.ts +50 -0
- package/types/core/hostDisplay.d.ts.map +1 -0
- package/types/core/useCase.d.ts +21 -0
- package/types/core/useCase.d.ts.map +1 -1
- package/types/core/version.d.ts +1 -1
- package/types/experiments/ExposureOutbox.d.ts +4 -28
- package/types/experiments/ExposureOutbox.d.ts.map +1 -1
- package/types/types.d.ts +188 -3
- package/types/types.d.ts.map +1 -1
- package/types/ui/OfferCard.d.ts +3 -1
- package/types/ui/OfferCard.d.ts.map +1 -1
- package/types/ui/OfferCarousel.d.ts +5 -0
- package/types/ui/OfferCarousel.d.ts.map +1 -1
- package/types/ui/OfferModal.d.ts +20 -0
- package/types/ui/OfferModal.d.ts.map +1 -1
- package/types/ui/PrimerScreen.d.ts +18 -11
- package/types/ui/PrimerScreen.d.ts.map +1 -1
- package/types/ui/RedemptionScreen.d.ts +15 -19
- package/types/ui/RedemptionScreen.d.ts.map +1 -1
- package/types/ui/RewardActions.d.ts +35 -0
- package/types/ui/RewardActions.d.ts.map +1 -1
- package/types/ui/appearance.d.ts +14 -0
- package/types/ui/appearance.d.ts.map +1 -1
- package/types/ui/brandComponents.d.ts.map +1 -1
- package/types/ui/styles.d.ts.map +1 -1
- package/types/utils/logger.d.ts +11 -1
- package/types/utils/logger.d.ts.map +1 -1
- package/embed/index.html +0 -57
- package/embed/styles.css +0 -154
- package/examples/ios-webview/EncoreWebViewBridge.swift +0 -419
- 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
|
-
|
|
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
|
|
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
|
|
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;
|
|
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
|
|
5
|
-
*
|
|
6
|
-
* -
|
|
7
|
-
* -
|
|
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
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
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(
|
|
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
|
|
64
|
+
/** Resolve a transaction by exact id (any status). */
|
|
22
65
|
getByTransactionId(transactionId: string): Transaction | null;
|
|
23
66
|
/**
|
|
24
|
-
*
|
|
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
|
-
/**
|
|
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
|
|
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
|
|
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;
|
|
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"}
|
package/types/core/useCase.d.ts
CHANGED
|
@@ -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"}
|
package/types/core/version.d.ts
CHANGED
|
@@ -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
|
|
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
|
|
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"}
|