pulse-updates 1.3.6 → 1.3.8

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.
@@ -81,6 +81,33 @@ export interface AnonymousFirstOpenContext {
81
81
  isEmulator?: boolean;
82
82
  }
83
83
  export type AnonymousFirstOpenResult = 'matched' | 'no_match' | 'ineligible' | 'deterministic_pending' | 'already_completed' | 'backoff' | 'retry_scheduled' | 'terminal_error';
84
+ export type AnonymousFirstOpenTerminalStatus = 'FOUND' | 'NOT_FOUND' | 'FAILURE';
85
+ /** Explicit receiver decision for one terminal-delivery attempt. */
86
+ export type AnonymousFirstOpenTerminalDisposition = 'accepted' | 'retry' | 'drop';
87
+ export type AnonymousFirstOpenTerminalReason = 'matched' | 'unmatched' | 'ambiguous' | 'holdout' | 'low_confidence' | 'shadow_would_route' | 'shadow_attributed' | 'analytics_attributed' | 'target_revoked' | 'disabled' | 'expired_replay' | 'invalid_request' | 'invalid_response' | 'policy_rejected';
88
+ /**
89
+ * Sanitized terminal result of the anonymous first-open rail. It deliberately carries no
90
+ * install-attempt id, token, device signal or raw server error. A 204 is always `no_route` and
91
+ * can never make the client navigate, including when Encore reports a shadow observation.
92
+ */
93
+ export interface AnonymousFirstOpenTerminalOutcome {
94
+ /** Stable UUIDv4 for receiver-side deduplication of at-least-once delivery. */
95
+ eventId: string;
96
+ status: AnonymousFirstOpenTerminalStatus;
97
+ rail: 'fast_route' | 'no_route';
98
+ routed: boolean;
99
+ retryable: false;
100
+ reason: AnonymousFirstOpenTerminalReason;
101
+ occurredAt: string;
102
+ /** Present only for FOUND and copied from the already-normalized resolver result. */
103
+ matchBasis?: DeferredLinkMatchBasis;
104
+ /** Present only for FOUND, finite and clamped to [0, 1]. */
105
+ confidence?: number;
106
+ /** Optional FOUND-only campaign dimensions; strings are trimmed and bounded to 128 chars. */
107
+ campaignId?: string | null;
108
+ experimentId?: string | null;
109
+ variantId?: string | null;
110
+ }
84
111
  export type AndroidInstallReferrerStatus = 'OK' | 'NO_TOKEN' | 'FEATURE_NOT_SUPPORTED' | 'SERVICE_UNAVAILABLE' | 'DEVELOPER_ERROR' | 'SERVICE_DISCONNECTED';
85
112
  export interface AndroidInstallReferrerResult {
86
113
  status: AndroidInstallReferrerStatus;
@@ -101,7 +128,13 @@ export interface DeferredLinkClientOptions<Action extends string = DeferredLinkA
101
128
  allowedActions?: readonly Action[];
102
129
  /** Actions that require both a deterministic match and a stable signed-in account. */
103
130
  sensitiveActions?: readonly Action[];
131
+ /**
132
+ * Routing callbacks are irreversible commit boundaries: return `false` when no navigation
133
+ * happened. If a newer accepted capture arrives while a successful callback is pending, Pulse
134
+ * persists it but will not auto-route a second journey in the same client lifecycle.
135
+ */
104
136
  onDeepLink: (deepLink: string, link: ResolvedDeferredLink<Action>) => boolean | void | Promise<boolean | void>;
137
+ /** Same commit-boundary contract as `onDeepLink`. */
105
138
  onAction?: (link: ResolvedDeferredLink<Action>) => boolean | void | Promise<boolean | void>;
106
139
  accountBridge?: DeferredLinkAccountBridge<Action>;
107
140
  isAccountReady?: () => boolean;
@@ -117,11 +150,27 @@ export interface DeferredLinkClientOptions<Action extends string = DeferredLinkA
117
150
  requestTimeoutMs?: number;
118
151
  retryBaseMs?: number;
119
152
  retryMaxMs?: number;
153
+ /** Timeout for one terminal-result acknowledgement attempt. Defaults to requestTimeoutMs. */
154
+ terminalDeliveryTimeoutMs?: number;
120
155
  tokenMaxAgeMs?: number;
121
156
  recentInstallMaxAgeMs?: number;
122
157
  autoRetry?: boolean;
123
158
  reportResolverOutcomes?: boolean;
124
159
  onOutcome?: (event: DeferredLinkOutcomeEvent) => void | Promise<void>;
160
+ /**
161
+ * Synchronous privacy gate evaluated before a terminal record or eventId is created. A false
162
+ * result or throw completes first-open matching without retaining terminal metadata.
163
+ */
164
+ shouldQueueFirstOpenResult?: () => boolean;
165
+ /**
166
+ * Durable at-least-once terminal delivery. Return `accepted` (or legacy `true`) only after the
167
+ * stable eventId is durably accepted, `retry`/false to replay it, or `drop` to deliberately and
168
+ * durably discard it (for example after consent revocation). Throw, rejection and timeout retry
169
+ * the same eventId. `drop` is sticky: failed local deletion retries never re-enter the receiver.
170
+ * Receivers must deduplicate because a crash after acceptance can replay it. When this handler
171
+ * is absent no terminal record is created or retained.
172
+ */
173
+ onFirstOpenResult?: (outcome: AnonymousFirstOpenTerminalOutcome) => AnonymousFirstOpenTerminalDisposition | boolean | Promise<AnonymousFirstOpenTerminalDisposition | boolean>;
125
174
  onStateChange?: (state: DeferredLinkState) => void;
126
175
  onError?: (error: unknown) => void;
127
176
  now?: () => number;
@@ -1 +1 @@
1
- {"version":3,"file":"links.d.ts","sourceRoot":"","sources":["../../src/links.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9C,MAAM,MAAM,kBAAkB,GAC1B,WAAW,GACX,cAAc,GACd,qBAAqB,GACrB,qBAAqB,CAAC;AAE1B,MAAM,MAAM,sBAAsB,GAC9B,cAAc,GACd,0BAA0B,GAC1B,gBAAgB,GAChB,eAAe,GACf,sBAAsB,GACtB,WAAW,CAAC;AAEhB,MAAM,MAAM,wBAAwB,GAAG,OAAO,CAC5C,sBAAsB,EACtB,cAAc,GAAG,0BAA0B,GAAG,gBAAgB,CAC/D,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAC1B,MAAM,GACN,SAAS,GACT,WAAW,GACX,qBAAqB,GACrB,iBAAiB,GACjB,SAAS,GACT,gBAAgB,CAAC;AAErB,MAAM,MAAM,uBAAuB,GAC/B,oBAAoB,GACpB,wBAAwB,GACxB,gBAAgB,CAAC;AAErB,MAAM,WAAW,oBAAoB,CAAC,MAAM,SAAS,MAAM,GAAG,kBAAkB;IAC9E,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,sBAAsB,CAAC;IACnC,eAAe,EAAE,OAAO,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,wBAAwB;IACvC,8FAA8F;IAC9F,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,wBAAwB,CAAC;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,0BAA0B;IACzC,gGAAgG;IAChG,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,kBAAkB,CAAC;IAC3B,OAAO,EAAE,wBAAwB,GAAG,IAAI,CAAC;IACzC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,4CAA4C;IAC5C,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9B,SAAS,EAAE,0BAA0B,CAAC;CACvC;AAED,MAAM,WAAW,yBAAyB,CAAC,MAAM,SAAS,MAAM,GAAG,kBAAkB;IACnF,KAAK,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;IACpE,OAAO,IAAI,OAAO,CAAC,oBAAoB,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;CACzD;AAED,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,uBAAuB,CAAC;IAC9B,UAAU,EAAE,sBAAsB,CAAC;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,4BAA4B,GACpC,OAAO,GACP,QAAQ,GACR,IAAI,GACJ,SAAS,GACT,gBAAgB,GAChB,SAAS,CAAC;AAEd,MAAM,WAAW,yBAAyB;IACxC,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,KAAK,CAAC;IAChB,yFAAyF;IACzF,WAAW,EAAE,MAAM,CAAC;IACpB,yFAAyF;IACzF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wFAAwF;IACxF,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,UAAU,CAAC,EAAE,4BAA4B,CAAC;IAC1C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sFAAsF;IACtF,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,MAAM,wBAAwB,GAChC,SAAS,GACT,UAAU,GACV,YAAY,GACZ,uBAAuB,GACvB,mBAAmB,GACnB,SAAS,GACT,iBAAiB,GACjB,gBAAgB,CAAC;AAErB,MAAM,MAAM,4BAA4B,GACpC,IAAI,GACJ,UAAU,GACV,uBAAuB,GACvB,qBAAqB,GACrB,iBAAiB,GACjB,sBAAsB,CAAC;AAE3B,MAAM,WAAW,4BAA4B;IAC3C,MAAM,EAAE,4BAA4B,CAAC;IACrC,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,oEAAoE;AACpE,MAAM,WAAW,4BAA4B;IAC3C,kBAAkB,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;CACxC;AAED,MAAM,WAAW,yBAAyB,CAAC,MAAM,SAAS,MAAM,GAAG,kBAAkB;IACnF,qFAAqF;IACrF,eAAe,EAAE,MAAM,CAAC;IACxB,4EAA4E;IAC5E,uBAAuB,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C,oEAAoE;IACpE,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,sFAAsF;IACtF,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,UAAU,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,oBAAoB,CAAC,MAAM,CAAC,KAAK,OAAO,GAAG,IAAI,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;IAC/G,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,oBAAoB,CAAC,MAAM,CAAC,KAAK,OAAO,GAAG,IAAI,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;IAC5F,aAAa,CAAC,EAAE,yBAAyB,CAAC,MAAM,CAAC,CAAC;IAClD,cAAc,CAAC,EAAE,MAAM,OAAO,CAAC;IAC/B,6FAA6F;IAC7F,qBAAqB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC;IAC/D,+DAA+D;IAC/D,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,sGAAsG;IACtG,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sEAAsE;IACtE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,wBAAwB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtE,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACnD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACnC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,MAAM,CAAC;IAC1B,iGAAiG;IACjG,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;CAC5C;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,wBAAwB,GAAG,OAAO,CAAC;IACjE,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IACjC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACzB,cAAc,CAAC,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAAC;IACtF,6BAA6B,CAAC,MAAM,EAAE,4BAA4B,GAAG,OAAO,CAAC,4BAA4B,CAAC,CAAC;IAC3G,QAAQ,IAAI,iBAAiB,CAAC;IAC9B,SAAS,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IACpE,OAAO,IAAI,IAAI,CAAC;IAChB,mGAAmG;IACnG,KAAK,IAAI,IAAI,CAAC;CACf;AA6HD,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAEzE;AAED,wBAAgB,6BAA6B,CAC3C,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAC9B,gBAAgB,GAAE,SAAS,MAAM,EAAqB,GACrD,MAAM,GAAG,IAAI,CAUf;AAED,qFAAqF;AACrF,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA4BtE;AAED,4FAA4F;AAC5F,wBAAgB,qCAAqC,CAAC,GAAG,EAAE,OAAO,GAAG,4BAA4B,CAqBhG;AAED,wBAAgB,qBAAqB,CAAC,MAAM,SAAS,MAAM,GAAG,kBAAkB,EAC9E,OAAO,EAAE,yBAAyB,CAAC,MAAM,CAAC,GACzC,kBAAkB,CA2uBpB;AAED,0EAA0E;AAC1E,eAAO,MAAM,wBAAwB,8BAAwB,CAAC"}
1
+ {"version":3,"file":"links.d.ts","sourceRoot":"","sources":["../../src/links.ts"],"names":[],"mappings":"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"}
@@ -28,13 +28,24 @@ export interface TrackOptions {
28
28
  * app's registry and read as an empty metric on both sides.
29
29
  */
30
30
  url: string;
31
- /** The same context the config uses — identity travels with the batch, once. */
31
+ /**
32
+ * Request context shared with config. `context` identity mode reads deviceId/userId
33
+ * for backwards-compatible experiment metrics; `anonymous_installation` ignores
34
+ * them and reads only platform/appVersion.
35
+ */
32
36
  getContext?: () => ConfigContext;
37
+ /**
38
+ * `context` preserves the original experiment-event contract and sends the context
39
+ * deviceId/userId. `anonymous_installation` is an explicit privacy mode: it ignores
40
+ * both and sends only an SDK-minted app-scoped random UUID under the legacy wire
41
+ * field `deviceId`. Defaults to `context` for backwards compatibility.
42
+ */
43
+ identityMode?: 'context' | 'anonymous_installation';
33
44
  /** How often a non-empty queue is sent. Default 10s. */
34
45
  flushIntervalMs?: number;
35
46
  /** Events per request. The server refuses more than 100. */
36
47
  maxBatch?: number;
37
- /** Events held before the oldest are dropped. Default 500. */
48
+ /** Best-effort events held before the oldest are dropped. Durable idempotent rows are never evicted. Default 500. */
38
49
  maxQueue?: number;
39
50
  /** Persists the outbox across process death. Use the same storage passed to initPulse. */
40
51
  storage?: ConfigStorage;
@@ -42,9 +53,12 @@ export interface TrackOptions {
42
53
  storageKey?: string;
43
54
  /** Per-request timeout. Default 10s. */
44
55
  timeoutMs?: number;
45
- /** Maximum delivery attempts before an event is dropped. Default 10. */
56
+ /** Maximum delivery attempts before a best-effort event is dropped. Durable idempotent events retry until server ACK. Default 10. */
46
57
  maxAttempts?: number;
47
- /** Return false until analytics consent exists. No event is retained before consent. */
58
+ /**
59
+ * Return false until analytics consent exists. No event is retained before consent. Consent is
60
+ * sampled at enqueue; an event already durably accepted remains eligible for later delivery.
61
+ */
48
62
  hasConsent?: () => boolean;
49
63
  /** Only these property keys may leave the process. */
50
64
  propertyAllowlist?: readonly string[];
@@ -73,12 +87,20 @@ export declare function configureTracking(opts: TrackOptions): void;
73
87
  * caller has to wrap.
74
88
  */
75
89
  export declare function track(event: string, props?: TrackedEventInput['props'], time?: Date): void;
90
+ /**
91
+ * Durably enqueue one logical event with a caller-owned UUID. Replaying the same id is safe:
92
+ * Pulse's server/read model deduplicates it, while the local outbox avoids duplicate rows that
93
+ * are still pending. `true` means the event is present in persistent storage, not delivered yet;
94
+ * once acknowledged, Track keeps it in that outbox through retries and process restarts until a
95
+ * successful server response removes it transactionally.
96
+ */
97
+ export declare function trackIdempotent(eventId: string, event: string, props?: TrackedEventInput['props'], time?: Date): boolean;
76
98
  /**
77
99
  * Send what is queued. Returns how many events the server accepted.
78
100
  *
79
- * Failures put the batch back at the front of the queue rather than dropping it: the
80
- * usual cause is a network that is about to come back, and the usual moment is right
81
- * after launch, when the first events of a session are the ones a funnel needs most.
101
+ * The batch remains in the durable queue while HTTP is in flight and is removed only after a
102
+ * successful response is also persisted locally. This intentionally permits duplicate replay
103
+ * after a crash, while a caller-owned event id lets the server/read model deduplicate it.
82
104
  */
83
105
  export declare function flushEvents(): Promise<number>;
84
106
  /** How many events are waiting — for a caller that wants to flush before backgrounding. */
@@ -1 +1 @@
1
- {"version":3,"file":"track.d.ts","sourceRoot":"","sources":["../../src/track.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE7D,MAAM,WAAW,YAAY;IAC3B;;;;;OAKG;IACH,GAAG,EAAE,MAAM,CAAC;IAEZ,gFAAgF;IAChF,UAAU,CAAC,EAAE,MAAM,aAAa,CAAC;IAEjC,wDAAwD;IACxD,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,0FAA0F;IAC1F,OAAO,CAAC,EAAE,aAAa,CAAC;IAExB,wEAAwE;IACxE,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,wCAAwC;IACxC,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,wEAAwE;IACxE,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,wFAAwF;IACxF,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC;IAE3B,sDAAsD;IACtD,iBAAiB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAEtC,+DAA+D;IAC/D,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAErC,0EAA0E;IAC1E,QAAQ,CAAC,EAAE;QAAE,gBAAgB,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,KAAK;YAAE,MAAM,EAAE,MAAM,IAAI,CAAA;SAAE,CAAA;KAAE,CAAC;IAE9G,+DAA+D;IAC/D,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAEvC,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,cAAc,GAAG,YAAY,KAAK,IAAI,CAAC;IAE1F,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CACpC;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;IACrE,IAAI,CAAC,EAAE,IAAI,CAAC;CACb;AAiCD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI,CAS1D;AAED;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,iBAAiB,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CA2B1F;AAED;;;;;;GAMG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,MAAM,CAAC,CA8DnD;AAED,2FAA2F;AAC3F,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED,wBAAgB,eAAe,IAAI;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;CACvB,CAEA;AAED,qEAAqE;AACrE,wBAAgB,eAAe,IAAI,IAAI,CAStC;AAED,wBAAgB,YAAY,IAAI,IAAI,CAMnC"}
1
+ {"version":3,"file":"track.d.ts","sourceRoot":"","sources":["../../src/track.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE7D,MAAM,WAAW,YAAY;IAC3B;;;;;OAKG;IACH,GAAG,EAAE,MAAM,CAAC;IAEZ;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,aAAa,CAAC;IAEjC;;;;;OAKG;IACH,YAAY,CAAC,EAAE,SAAS,GAAG,wBAAwB,CAAC;IAEpD,wDAAwD;IACxD,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,qHAAqH;IACrH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,0FAA0F;IAC1F,OAAO,CAAC,EAAE,aAAa,CAAC;IAExB,wEAAwE;IACxE,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,wCAAwC;IACxC,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,qIAAqI;IACrI,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC;IAE3B,sDAAsD;IACtD,iBAAiB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAEtC,+DAA+D;IAC/D,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAErC,0EAA0E;IAC1E,QAAQ,CAAC,EAAE;QAAE,gBAAgB,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,KAAK;YAAE,MAAM,EAAE,MAAM,IAAI,CAAA;SAAE,CAAA;KAAE,CAAC;IAE9G,+DAA+D;IAC/D,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAEvC,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,cAAc,GAAG,YAAY,KAAK,IAAI,CAAC;IAE1F,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CACpC;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;IACrE,IAAI,CAAC,EAAE,IAAI,CAAC;CACb;AAuCD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI,CAY1D;AAED;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,iBAAiB,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAE1F;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,KAAK,CAAC,EAAE,iBAAiB,CAAC,OAAO,CAAC,EAClC,IAAI,CAAC,EAAE,IAAI,GACV,OAAO,CAIT;AA2GD;;;;;;GAMG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,MAAM,CAAC,CAiEnD;AAED,2FAA2F;AAC3F,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED,wBAAgB,eAAe,IAAI;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;CACvB,CAEA;AAED,qEAAqE;AACrE,wBAAgB,eAAe,IAAI,IAAI,CAStC;AAED,wBAAgB,YAAY,IAAI,IAAI,CAOnC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pulse-updates",
3
- "version": "1.3.6",
3
+ "version": "1.3.8",
4
4
  "description": "Pulse app-experience SDK for React Native: updates, config, experiments, events, decisions and first-party links",
5
5
  "main": "lib/commonjs/index.js",
6
6
  "module": "lib/module/index.js",
package/src/config.ts CHANGED
@@ -50,6 +50,12 @@ export type ConfigSignatureStatus = 'not-configured' | 'verified' | 'cached-veri
50
50
  export interface ConfigStorage {
51
51
  getString(key: string): string | null | undefined;
52
52
  set(key: string, value: string): void;
53
+ /**
54
+ * False when `set` only mirrors a write and schedules asynchronous persistence. Durable
55
+ * acknowledgement APIs must fail closed because process death may still lose that write.
56
+ * Omitted means the historical synchronous-storage contract.
57
+ */
58
+ readonly supportsDurableSyncWrites?: boolean;
53
59
  }
54
60
 
55
61
  /**
package/src/init.ts CHANGED
@@ -14,9 +14,10 @@
14
14
  * - the urls, from the base url and the slug, which is what stops the two halves
15
15
  * from ever addressing different apps;
16
16
  * - platform and OS version, from React Native;
17
- * - the device id, minted and persisted on first launch — an app that has a stable
18
- * identifier of its own (the vendor id, an installation id) should pass it, and an
19
- * app that has none should not have to invent one to be measurable.
17
+ * - the config/experiment id, minted and persisted on first launch — an app that has
18
+ * a stable identifier of its own may pass it. Event tracking keeps the original
19
+ * context identity by default; privacy-sensitive campaign events can explicitly
20
+ * opt into a separate random app-scoped analytics installation UUID.
20
21
  *
21
22
  * Deliberately not automatic: the app version. Nothing here can read the store build
22
23
  * reliably on both platforms, and a version guessed wrong aims a rollout at the wrong
@@ -44,6 +45,7 @@ import {
44
45
  flushEvents,
45
46
  getTrackingInfo,
46
47
  track,
48
+ trackIdempotent,
47
49
  type TrackedEventInput,
48
50
  } from './track';
49
51
 
@@ -92,6 +94,13 @@ export interface InitPulseOptions {
92
94
  eventPropertyAllowlist?: readonly string[];
93
95
  redactEventProperties?: readonly string[];
94
96
 
97
+ /**
98
+ * Event-envelope identity. Defaults to the backwards-compatible config context.
99
+ * Use `anonymous_installation` for events that carry their own experiment/variant
100
+ * dimensions and must never transmit the app's device or account identifier.
101
+ */
102
+ eventIdentityMode?: 'context' | 'anonymous_installation';
103
+
95
104
  /** Signed config uses the same Ed25519 public key as OTA updates. */
96
105
  signingPublicKey?: string;
97
106
  signingKeyId?: string;
@@ -132,6 +141,12 @@ export interface PulseClient {
132
141
  configUrl: string;
133
142
  trackUrl: string;
134
143
  track: (event: string, props?: TrackedEventInput['props'], time?: Date) => void;
144
+ trackIdempotent: (
145
+ eventId: string,
146
+ event: string,
147
+ props?: TrackedEventInput['props'],
148
+ time?: Date,
149
+ ) => boolean;
135
150
  flush: () => Promise<number>;
136
151
  setUser: (userId?: string, attributes?: Record<string, string>) => void;
137
152
  clearUser: () => void;
@@ -156,7 +171,7 @@ export interface AsyncPulseStorage {
156
171
  let activeClient: PulseClient | null = null;
157
172
  let stopActiveRefresh: (() => void) | null = null;
158
173
 
159
- /** Wires config and events, and returns the context the two share. */
174
+ /** Wires config and events with an explicit event-envelope identity policy. */
160
175
  export function initPulse(opts: InitPulseOptions): PulseClient {
161
176
  // Reconfiguration is synchronous. Calling the old async dispose without awaiting
162
177
  // it lets its eventual flush tear down the brand-new tracker — exactly the race a
@@ -216,6 +231,7 @@ export function initPulse(opts: InitPulseOptions): PulseClient {
216
231
  configureTracking({
217
232
  url: trackUrl,
218
233
  getContext,
234
+ identityMode: opts.eventIdentityMode,
219
235
  flushIntervalMs: opts.flushIntervalMs,
220
236
  storage: opts.storage,
221
237
  storageKey: `pulse.${slug}.events.v1`,
@@ -252,6 +268,7 @@ export function initPulse(opts: InitPulseOptions): PulseClient {
252
268
  configUrl,
253
269
  trackUrl,
254
270
  track,
271
+ trackIdempotent,
255
272
  flush: flushEvents,
256
273
  setUser: (nextUserId, attributes) => {
257
274
  userId = nextUserId?.trim() || undefined;
@@ -300,8 +317,9 @@ export function initPulse(opts: InitPulseOptions): PulseClient {
300
317
  }
301
318
 
302
319
  /**
303
- * AsyncStorage-friendly one-call setup. It preloads only Pulse's three app-scoped
304
- * records, then exposes the same synchronous hot-path API as initPulse.
320
+ * AsyncStorage-friendly one-call setup. It preloads only Pulse's app-scoped config,
321
+ * event, analytics-installation and exposure records, then exposes the same
322
+ * synchronous hot-path API as initPulse.
305
323
  */
306
324
  export async function initPulseAsync(
307
325
  opts: Omit<InitPulseOptions, 'storage'> & { storage: AsyncPulseStorage },
@@ -311,16 +329,24 @@ export async function initPulseAsync(
311
329
  `pulse.${slug}.device-id`,
312
330
  `pulse.${slug}.config.v1`,
313
331
  `pulse.${slug}.events.v1`,
332
+ `pulse.${slug}.events.v1.analytics-installation-id`,
314
333
  `pulse.${slug}.exposures.v1`,
315
334
  DEVICE_ID_KEY,
316
335
  ];
317
336
  const loaded = await Promise.all(keys.map(async (key) => [key, await opts.storage.getItem(key)] as const));
318
337
  const memory = new Map(loaded.filter((entry): entry is readonly [string, string] => entry[1] !== null));
319
338
  const storage: ConfigStorage = {
339
+ supportsDurableSyncWrites: false,
320
340
  getString: (key) => memory.get(key),
321
341
  set: (key, value) => {
322
342
  memory.set(key, value);
323
- void opts.storage.setItem(key, value);
343
+ try {
344
+ void Promise.resolve(opts.storage.setItem(key, value)).catch((error) => {
345
+ try { opts.onError?.(error); } catch { /* diagnostics never break persistence */ }
346
+ });
347
+ } catch (error) {
348
+ try { opts.onError?.(error); } catch { /* diagnostics never break persistence */ }
349
+ }
324
350
  },
325
351
  };
326
352
  return initPulse({ ...opts, storage });