@rocapine/rocalytics-sdk 0.0.0-stage → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (161) hide show
  1. package/CHANGELOG.md +86 -0
  2. package/LICENSE +21 -0
  3. package/README.md +449 -2
  4. package/client/package.json +1 -0
  5. package/core/package.json +4 -0
  6. package/dist/client/client.d.ts +146 -0
  7. package/dist/client/client.d.ts.map +1 -0
  8. package/dist/client/client.js +376 -0
  9. package/dist/client/client.js.map +1 -0
  10. package/dist/client/index.d.ts +13 -0
  11. package/dist/client/index.d.ts.map +1 -0
  12. package/dist/client/index.js +35 -0
  13. package/dist/client/index.js.map +1 -0
  14. package/dist/client/native.d.ts +68 -0
  15. package/dist/client/native.d.ts.map +1 -0
  16. package/dist/client/native.js +64 -0
  17. package/dist/client/native.js.map +1 -0
  18. package/dist/client/onboardingSink.d.ts +63 -0
  19. package/dist/client/onboardingSink.d.ts.map +1 -0
  20. package/dist/client/onboardingSink.js +126 -0
  21. package/dist/client/onboardingSink.js.map +1 -0
  22. package/dist/client/paywallSink.d.ts +13 -0
  23. package/dist/client/paywallSink.d.ts.map +1 -0
  24. package/dist/client/paywallSink.js +26 -0
  25. package/dist/client/paywallSink.js.map +1 -0
  26. package/dist/client/requests.d.ts +66 -0
  27. package/dist/client/requests.d.ts.map +1 -0
  28. package/dist/client/requests.js +90 -0
  29. package/dist/client/requests.js.map +1 -0
  30. package/dist/client/types.d.ts +180 -0
  31. package/dist/client/types.d.ts.map +1 -0
  32. package/dist/client/types.js +4 -0
  33. package/dist/client/types.js.map +1 -0
  34. package/dist/core/context.d.ts +39 -0
  35. package/dist/core/context.d.ts.map +1 -0
  36. package/dist/core/context.js +45 -0
  37. package/dist/core/context.js.map +1 -0
  38. package/dist/core/delivery.d.ts +63 -0
  39. package/dist/core/delivery.d.ts.map +1 -0
  40. package/dist/core/delivery.js +133 -0
  41. package/dist/core/delivery.js.map +1 -0
  42. package/dist/core/diagnostics.d.ts +16 -0
  43. package/dist/core/diagnostics.d.ts.map +1 -0
  44. package/dist/core/diagnostics.js +24 -0
  45. package/dist/core/diagnostics.js.map +1 -0
  46. package/dist/core/httpSink.d.ts +35 -0
  47. package/dist/core/httpSink.d.ts.map +1 -0
  48. package/dist/core/httpSink.js +65 -0
  49. package/dist/core/httpSink.js.map +1 -0
  50. package/dist/core/ids.d.ts +16 -0
  51. package/dist/core/ids.d.ts.map +1 -0
  52. package/dist/core/ids.js +51 -0
  53. package/dist/core/ids.js.map +1 -0
  54. package/dist/core/index.d.ts +17 -0
  55. package/dist/core/index.d.ts.map +1 -0
  56. package/dist/core/index.js +32 -0
  57. package/dist/core/index.js.map +1 -0
  58. package/dist/core/sink.d.ts +39 -0
  59. package/dist/core/sink.d.ts.map +1 -0
  60. package/dist/core/sink.js +16 -0
  61. package/dist/core/sink.js.map +1 -0
  62. package/dist/core/storage.d.ts +52 -0
  63. package/dist/core/storage.d.ts.map +1 -0
  64. package/dist/core/storage.js +79 -0
  65. package/dist/core/storage.js.map +1 -0
  66. package/dist/core/text.d.ts +9 -0
  67. package/dist/core/text.d.ts.map +1 -0
  68. package/dist/core/text.js +47 -0
  69. package/dist/core/text.js.map +1 -0
  70. package/dist/core/time.d.ts +18 -0
  71. package/dist/core/time.d.ts.map +1 -0
  72. package/dist/core/time.js +18 -0
  73. package/dist/core/time.js.map +1 -0
  74. package/dist/onboarding/contract.d.ts +138 -0
  75. package/dist/onboarding/contract.d.ts.map +1 -0
  76. package/dist/onboarding/contract.js +11 -0
  77. package/dist/onboarding/contract.js.map +1 -0
  78. package/dist/onboarding/index.d.ts +15 -0
  79. package/dist/onboarding/index.d.ts.map +1 -0
  80. package/dist/onboarding/index.js +22 -0
  81. package/dist/onboarding/index.js.map +1 -0
  82. package/dist/onboarding/input.d.ts +102 -0
  83. package/dist/onboarding/input.d.ts.map +1 -0
  84. package/dist/onboarding/input.js +216 -0
  85. package/dist/onboarding/input.js.map +1 -0
  86. package/dist/onboarding/persisted.d.ts +20 -0
  87. package/dist/onboarding/persisted.d.ts.map +1 -0
  88. package/dist/onboarding/persisted.js +75 -0
  89. package/dist/onboarding/persisted.js.map +1 -0
  90. package/dist/onboarding/state.d.ts +65 -0
  91. package/dist/onboarding/state.d.ts.map +1 -0
  92. package/dist/onboarding/state.js +207 -0
  93. package/dist/onboarding/state.js.map +1 -0
  94. package/dist/onboarding/tracker.d.ts +135 -0
  95. package/dist/onboarding/tracker.d.ts.map +1 -0
  96. package/dist/onboarding/tracker.js +734 -0
  97. package/dist/onboarding/tracker.js.map +1 -0
  98. package/dist/paywall/contract.d.ts +67 -0
  99. package/dist/paywall/contract.d.ts.map +1 -0
  100. package/dist/paywall/contract.js +3 -0
  101. package/dist/paywall/contract.js.map +1 -0
  102. package/dist/paywall/index.d.ts +14 -0
  103. package/dist/paywall/index.d.ts.map +1 -0
  104. package/dist/paywall/index.js +19 -0
  105. package/dist/paywall/index.js.map +1 -0
  106. package/dist/paywall/observer.d.ts +38 -0
  107. package/dist/paywall/observer.d.ts.map +1 -0
  108. package/dist/paywall/observer.js +6 -0
  109. package/dist/paywall/observer.js.map +1 -0
  110. package/dist/paywall/state.d.ts +26 -0
  111. package/dist/paywall/state.d.ts.map +1 -0
  112. package/dist/paywall/state.js +132 -0
  113. package/dist/paywall/state.js.map +1 -0
  114. package/dist/paywall/tracker.d.ts +36 -0
  115. package/dist/paywall/tracker.d.ts.map +1 -0
  116. package/dist/paywall/tracker.js +180 -0
  117. package/dist/paywall/tracker.js.map +1 -0
  118. package/dist/version.d.ts +3 -0
  119. package/dist/version.d.ts.map +1 -0
  120. package/dist/version.js +6 -0
  121. package/dist/version.js.map +1 -0
  122. package/docs/onboarding-run-contract.md +1013 -0
  123. package/docs/onboarding-run.examples.ts +306 -0
  124. package/docs/onboarding-run.schema.json +224 -0
  125. package/docs/onboarding-run.types.ts +144 -0
  126. package/docs/paywall-presentation-contract.md +139 -0
  127. package/docs/paywall-presentation.examples.ts +42 -0
  128. package/docs/paywall-presentation.schema.json +268 -0
  129. package/docs/paywall-presentation.types.ts +73 -0
  130. package/onboarding/package.json +4 -0
  131. package/package.json +120 -4
  132. package/paywall/package.json +1 -0
  133. package/src/client/client.ts +417 -0
  134. package/src/client/index.ts +54 -0
  135. package/src/client/native.ts +109 -0
  136. package/src/client/onboardingSink.ts +121 -0
  137. package/src/client/paywallSink.ts +25 -0
  138. package/src/client/requests.ts +126 -0
  139. package/src/client/types.ts +198 -0
  140. package/src/core/context.ts +69 -0
  141. package/src/core/delivery.ts +181 -0
  142. package/src/core/diagnostics.ts +30 -0
  143. package/src/core/httpSink.ts +70 -0
  144. package/src/core/ids.ts +46 -0
  145. package/src/core/index.ts +20 -0
  146. package/src/core/sink.ts +46 -0
  147. package/src/core/storage.ts +112 -0
  148. package/src/core/text.ts +37 -0
  149. package/src/core/time.ts +26 -0
  150. package/src/onboarding/contract.ts +144 -0
  151. package/src/onboarding/index.ts +39 -0
  152. package/src/onboarding/input.ts +246 -0
  153. package/src/onboarding/persisted.ts +93 -0
  154. package/src/onboarding/state.ts +233 -0
  155. package/src/onboarding/tracker.ts +855 -0
  156. package/src/paywall/contract.ts +73 -0
  157. package/src/paywall/index.ts +36 -0
  158. package/src/paywall/observer.ts +43 -0
  159. package/src/paywall/state.ts +125 -0
  160. package/src/paywall/tracker.ts +200 -0
  161. package/src/version.ts +2 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"persisted.js","sourceRoot":"","sources":["../../src/onboarding/persisted.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,65 @@
1
+ import type { WireRunContext } from "../core/context";
2
+ import type { Answer, Manifest, OnboardingIdentity, OnboardingRunSnapshot, Properties, StepEntry, StudioLinks } from "./contract";
3
+ /** 256 KiB minus 1 KiB of headroom for what lands after the measure (D26). */
4
+ export declare const RECORDING_BUDGET = 261120;
5
+ /** The most entries a snapshot holds (D8). */
6
+ export declare const MAX_ENTRIES = 500;
7
+ export interface RunState {
8
+ runId: string;
9
+ /** The last `seq` assigned to a send. 0 before the first. */
10
+ lastSeq: number;
11
+ onboarding: OnboardingIdentity;
12
+ studio?: StudioLinks;
13
+ context: WireRunContext;
14
+ manifest: Manifest;
15
+ properties?: Properties;
16
+ /** Entries as recorded. The last one's exit may be provisional, see below. */
17
+ steps: StepEntry[];
18
+ /**
19
+ * The last entry's `exited_at` was set by exitStep while the run goes on.
20
+ * An in-progress snapshot of an untruncated run still sends it as null
21
+ * (rule 6: only the current screen is open), until the next entry closes it
22
+ * for good or completion replaces it with `completed_at` (rule 7).
23
+ */
24
+ provisionalExit: boolean;
25
+ truncated: boolean;
26
+ status: "in_progress" | "completed";
27
+ completedAt: string | null;
28
+ /** Last moment the app was known to be in the foreground on the current screen (3.2). Epoch ms. */
29
+ lastActiveAt: number;
30
+ /** A recorded change has not gone into a send yet (it is waiting on the debounce). */
31
+ dirty?: boolean;
32
+ }
33
+ /** What an operation did, for the tracker to report. */
34
+ export type Note = "truncated" | "too-many-answers";
35
+ export interface Result {
36
+ state: RunState;
37
+ changed: boolean;
38
+ notes: Note[];
39
+ }
40
+ /** The snapshot `state` sends with `seq` at `nowMs`, in the key order of the contract's examples. */
41
+ export declare function toSnapshot(state: RunState, seq: number, nowMs: number): OnboardingRunSnapshot;
42
+ /** Completion as the contract defines it: every open exit closed at `completed_at`, a truncated run's closed exit kept. */
43
+ export declare function completeState(state: RunState, nowMs: number): RunState;
44
+ /** Whether `state` stays within the recording budget, measured on its completion form with the next seq (D26). */
45
+ export declare function fits(state: RunState, nowMs: number): boolean;
46
+ /** A new screen is shown. */
47
+ export declare function enter(state: RunState, stepKey: string, nowMs: number): Result;
48
+ /**
49
+ * The user leaves the screen at `index` (the current entry, or the one just
50
+ * before it when the next screen was entered first), with what they answered.
51
+ */
52
+ export declare function exit(state: RunState, index: number, answers: Answer[], nowMs: number): Result;
53
+ /** A new or changed property set: `merged` is the whole map after the change. */
54
+ export declare function setProperties(state: RunState, merged: Properties, nowMs: number): Result;
55
+ /**
56
+ * Restore after relaunch (3.2): close a still-open pre-kill entry at
57
+ * last_active_at, or at the exit exitStep recorded if that is later (the
58
+ * user is known to have left then); never rewrite an exit already final. Then append a new
59
+ * entry for the restored screen at `nowMs`, unless the run is truncated or the
60
+ * entry would break a limit, in which case recording stops instead.
61
+ */
62
+ export declare function restore(state: RunState, nowMs: number): Result;
63
+ /** The latest moment recorded in the run, so a clock set backwards cannot make timestamps go back. */
64
+ export declare function floorMs(state: RunState): number;
65
+ //# sourceMappingURL=state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/onboarding/state.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,KAAK,EACV,MAAM,EACN,QAAQ,EACR,kBAAkB,EAClB,qBAAqB,EACrB,UAAU,EACV,SAAS,EACT,WAAW,EACZ,MAAM,YAAY,CAAC;AAGpB,8EAA8E;AAC9E,eAAO,MAAM,gBAAgB,SAAU,CAAC;AACxC,8CAA8C;AAC9C,eAAO,MAAM,WAAW,MAAM,CAAC;AAE/B,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,6DAA6D;IAC7D,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,kBAAkB,CAAC;IAC/B,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,OAAO,EAAE,cAAc,CAAC;IACxB,QAAQ,EAAE,QAAQ,CAAC;IACnB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,8EAA8E;IAC9E,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB;;;;;OAKG;IACH,eAAe,EAAE,OAAO,CAAC;IACzB,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,aAAa,GAAG,WAAW,CAAC;IACpC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,mGAAmG;IACnG,YAAY,EAAE,MAAM,CAAC;IACrB,sFAAsF;IACtF,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,wDAAwD;AACxD,MAAM,MAAM,IAAI,GAAG,WAAW,GAAG,kBAAkB,CAAC;AACpD,MAAM,WAAW,MAAM;IACrB,KAAK,EAAE,QAAQ,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,IAAI,EAAE,CAAC;CACf;AAID,qGAAqG;AACrG,wBAAgB,UAAU,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,qBAAqB,CAwB7F;AAED,2HAA2H;AAC3H,wBAAgB,aAAa,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,QAAQ,CAUtE;AAED,kHAAkH;AAClH,wBAAgB,IAAI,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAG5D;AAkBD,6BAA6B;AAC7B,wBAAgB,KAAK,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAW7E;AAED;;;GAGG;AACH,wBAAgB,IAAI,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CA6C7F;AAED,iFAAiF;AACjF,wBAAgB,aAAa,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAMxF;AAED;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAmB9D;AAED,sGAAsG;AACtG,wBAAgB,OAAO,CAAC,KAAK,EAAE,QAAQ,GAAG,MAAM,CAQ/C"}
@@ -0,0 +1,207 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MAX_ENTRIES = exports.RECORDING_BUDGET = void 0;
4
+ exports.toSnapshot = toSnapshot;
5
+ exports.completeState = completeState;
6
+ exports.fits = fits;
7
+ exports.enter = enter;
8
+ exports.exit = exit;
9
+ exports.setProperties = setProperties;
10
+ exports.restore = restore;
11
+ exports.floorMs = floorMs;
12
+ // The run as the tracker records it, and the pure operations on it. Every
13
+ // function returns a new state (or the same one when nothing changed); none
14
+ // reads the clock or does I/O, so each rule of the contract is testable here.
15
+ const text_1 = require("../core/text");
16
+ const time_1 = require("../core/time");
17
+ const input_1 = require("./input");
18
+ /** 256 KiB minus 1 KiB of headroom for what lands after the measure (D26). */
19
+ exports.RECORDING_BUDGET = 261120;
20
+ /** The most entries a snapshot holds (D8). */
21
+ exports.MAX_ENTRIES = 500;
22
+ const unchanged = (state, notes = []) => ({ state, changed: false, notes });
23
+ /** The snapshot `state` sends with `seq` at `nowMs`, in the key order of the contract's examples. */
24
+ function toSnapshot(state, seq, nowMs) {
25
+ var _a, _b;
26
+ const steps = state.steps.map((e) => ({ ...e, answers: e.answers.slice() }));
27
+ if (state.status === "in_progress" && !state.truncated && state.provisionalExit && steps.length) {
28
+ steps[steps.length - 1].exited_at = null;
29
+ }
30
+ const head = {
31
+ schema_version: 1,
32
+ run_id: state.runId,
33
+ seq,
34
+ };
35
+ const tail = {
36
+ sent_at: (0, time_1.toTimestamp)(nowMs),
37
+ onboarding: state.onboarding,
38
+ ...(state.studio ? { studio: state.studio } : {}),
39
+ context: state.context,
40
+ manifest: state.manifest,
41
+ ...(state.properties ? { properties: state.properties } : {}),
42
+ ...(state.truncated ? { truncated: true } : {}),
43
+ steps,
44
+ };
45
+ const started_at = (_b = (_a = steps[0]) === null || _a === void 0 ? void 0 : _a.entered_at) !== null && _b !== void 0 ? _b : (0, time_1.toTimestamp)(nowMs);
46
+ return state.status === "completed"
47
+ ? { ...head, status: "completed", started_at, completed_at: state.completedAt, ...tail }
48
+ : { ...head, status: "in_progress", started_at, completed_at: null, ...tail };
49
+ }
50
+ /** Completion as the contract defines it: every open exit closed at `completed_at`, a truncated run's closed exit kept. */
51
+ function completeState(state, nowMs) {
52
+ const completedAt = (0, time_1.toTimestamp)(nowMs);
53
+ const steps = state.steps.slice();
54
+ const lastIndex = steps.length - 1;
55
+ if (lastIndex >= 0) {
56
+ const last = steps[lastIndex];
57
+ const keepExit = state.truncated && last.exited_at !== null;
58
+ if (!keepExit)
59
+ steps[lastIndex] = { ...last, exited_at: completedAt };
60
+ }
61
+ return { ...state, steps, provisionalExit: false, status: "completed", completedAt };
62
+ }
63
+ /** Whether `state` stays within the recording budget, measured on its completion form with the next seq (D26). */
64
+ function fits(state, nowMs) {
65
+ const form = toSnapshot(completeState(state, nowMs), state.lastSeq + 1, nowMs);
66
+ return (0, text_1.utf8ByteLength)(JSON.stringify(form)) <= exports.RECORDING_BUDGET;
67
+ }
68
+ const lastOf = (s) => s.steps[s.steps.length - 1];
69
+ /** Closes the current entry for good: at its provisional exit if exitStep gave one, else at `at`. */
70
+ function closeCurrent(state, at) {
71
+ var _a;
72
+ const last = lastOf(state);
73
+ if (!last)
74
+ return state;
75
+ if (last.exited_at !== null && !state.provisionalExit)
76
+ return state;
77
+ const steps = state.steps.slice();
78
+ steps[steps.length - 1] = { ...last, exited_at: (_a = last.exited_at) !== null && _a !== void 0 ? _a : at };
79
+ return { ...state, steps, provisionalExit: false };
80
+ }
81
+ function stopRecording(state) {
82
+ return { ...state, truncated: true };
83
+ }
84
+ /** A new screen is shown. */
85
+ function enter(state, stepKey, nowMs) {
86
+ const at = (0, time_1.toTimestamp)(nowMs);
87
+ const closed = { ...closeCurrent(state, at), lastActiveAt: nowMs };
88
+ if (state.truncated)
89
+ return { state: closed, changed: closed.steps !== state.steps, notes: ["truncated"] };
90
+ if (state.steps.length >= exports.MAX_ENTRIES)
91
+ return { state: stopRecording(closed), changed: true, notes: ["truncated"] };
92
+ const next = {
93
+ ...closed,
94
+ steps: [...closed.steps, { step_key: stepKey, entered_at: at, exited_at: null, answers: [] }],
95
+ };
96
+ if (!fits(next, nowMs))
97
+ return { state: stopRecording(closed), changed: true, notes: ["truncated"] };
98
+ return { state: next, changed: true, notes: [] };
99
+ }
100
+ /**
101
+ * The user leaves the screen at `index` (the current entry, or the one just
102
+ * before it when the next screen was entered first), with what they answered.
103
+ */
104
+ function exit(state, index, answers, nowMs) {
105
+ const notes = [];
106
+ let current = state;
107
+ let changed = false;
108
+ const isLast = index === state.steps.length - 1;
109
+ if (current.truncated) {
110
+ if (answers.length)
111
+ notes.push("truncated");
112
+ }
113
+ else {
114
+ for (const answer of answers) {
115
+ const entry = current.steps[index];
116
+ const at = entry.answers.findIndex((a) => a.question_key === answer.question_key);
117
+ if (at < 0 && entry.answers.length >= input_1.MAX_ANSWERS) {
118
+ notes.push("too-many-answers");
119
+ continue;
120
+ }
121
+ const list = entry.answers.slice();
122
+ if (at < 0)
123
+ list.push(answer);
124
+ else
125
+ list[at] = answer;
126
+ const steps = current.steps.slice();
127
+ steps[index] = { ...entry, answers: list };
128
+ const next = { ...current, steps };
129
+ if (!fits(next, nowMs)) {
130
+ current = stopRecording(current);
131
+ notes.push("truncated");
132
+ changed = true;
133
+ break;
134
+ }
135
+ current = next;
136
+ changed = true;
137
+ }
138
+ }
139
+ // Record when the user left. In a truncated run that exit is final at once.
140
+ const entry = current.steps[index];
141
+ if (isLast && entry.exited_at === null) {
142
+ const steps = current.steps.slice();
143
+ steps[index] = { ...entry, exited_at: (0, time_1.toTimestamp)(nowMs) };
144
+ current = { ...current, steps, provisionalExit: !current.truncated };
145
+ changed = true;
146
+ }
147
+ else if (isLast && current.truncated && current.provisionalExit) {
148
+ current = { ...current, provisionalExit: false };
149
+ changed = true;
150
+ }
151
+ return changed ? { state: current, changed, notes } : unchanged(state, notes);
152
+ }
153
+ /** A new or changed property set: `merged` is the whole map after the change. */
154
+ function setProperties(state, merged, nowMs) {
155
+ var _a;
156
+ if (JSON.stringify(merged) === JSON.stringify((_a = state.properties) !== null && _a !== void 0 ? _a : {}))
157
+ return unchanged(state);
158
+ if (state.truncated)
159
+ return unchanged(state, ["truncated"]);
160
+ const next = { ...state, properties: Object.keys(merged).length ? merged : undefined };
161
+ if (!fits(next, nowMs))
162
+ return { state: stopRecording(state), changed: true, notes: ["truncated"] };
163
+ return { state: next, changed: true, notes: [] };
164
+ }
165
+ /**
166
+ * Restore after relaunch (3.2): close a still-open pre-kill entry at
167
+ * last_active_at, or at the exit exitStep recorded if that is later (the
168
+ * user is known to have left then); never rewrite an exit already final. Then append a new
169
+ * entry for the restored screen at `nowMs`, unless the run is truncated or the
170
+ * entry would break a limit, in which case recording stops instead.
171
+ */
172
+ function restore(state, nowMs) {
173
+ const last = lastOf(state);
174
+ if (!last)
175
+ return unchanged(state);
176
+ let current = state;
177
+ if (last.exited_at === null || (state.provisionalExit && !state.truncated)) {
178
+ const provisional = last.exited_at !== null ? Date.parse(last.exited_at) : -Infinity;
179
+ const steps = state.steps.slice();
180
+ steps[steps.length - 1] = { ...last, exited_at: (0, time_1.toTimestamp)(Math.max(state.lastActiveAt, provisional)) };
181
+ current = { ...state, steps, provisionalExit: false };
182
+ }
183
+ current = { ...current, lastActiveAt: nowMs };
184
+ if (current.truncated)
185
+ return { state: current, changed: true, notes: [] };
186
+ if (current.steps.length >= exports.MAX_ENTRIES)
187
+ return { state: stopRecording(current), changed: true, notes: ["truncated"] };
188
+ const next = {
189
+ ...current,
190
+ steps: [...current.steps, { step_key: last.step_key, entered_at: (0, time_1.toTimestamp)(nowMs), exited_at: null, answers: [] }],
191
+ };
192
+ if (!fits(next, nowMs))
193
+ return { state: stopRecording(current), changed: true, notes: ["truncated"] };
194
+ return { state: next, changed: true, notes: [] };
195
+ }
196
+ /** The latest moment recorded in the run, so a clock set backwards cannot make timestamps go back. */
197
+ function floorMs(state) {
198
+ const last = lastOf(state);
199
+ let floor = 0;
200
+ if (last) {
201
+ floor = Date.parse(last.entered_at);
202
+ if (last.exited_at)
203
+ floor = Math.max(floor, Date.parse(last.exited_at));
204
+ }
205
+ return floor;
206
+ }
207
+ //# sourceMappingURL=state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/onboarding/state.ts"],"names":[],"mappings":";;;AA4DA,gCAwBC;AAGD,sCAUC;AAGD,oBAGC;AAmBD,sBAWC;AAMD,oBA6CC;AAGD,sCAMC;AASD,0BAmBC;AAGD,0BAQC;AAxOD,0EAA0E;AAC1E,4EAA4E;AAC5E,8EAA8E;AAC9E,uCAA8C;AAC9C,uCAA2C;AAW3C,mCAAsC;AAEtC,8EAA8E;AACjE,QAAA,gBAAgB,GAAG,MAAO,CAAC;AACxC,8CAA8C;AACjC,QAAA,WAAW,GAAG,GAAG,CAAC;AAqC/B,MAAM,SAAS,GAAG,CAAC,KAAe,EAAE,QAAgB,EAAE,EAAU,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;AAEtG,qGAAqG;AACrG,SAAgB,UAAU,CAAC,KAAe,EAAE,GAAW,EAAE,KAAa;;IACpE,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC;IAC7E,IAAI,KAAK,CAAC,MAAM,KAAK,aAAa,IAAI,CAAC,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,eAAe,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QAChG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,SAAS,GAAG,IAAI,CAAC;IAC3C,CAAC;IACD,MAAM,IAAI,GAAG;QACX,cAAc,EAAE,CAAU;QAC1B,MAAM,EAAE,KAAK,CAAC,KAAK;QACnB,GAAG;KACJ,CAAC;IACF,MAAM,IAAI,GAAG;QACX,OAAO,EAAE,IAAA,kBAAW,EAAC,KAAK,CAAC;QAC3B,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACjD,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7D,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACxD,KAAK;KACN,CAAC;IACF,MAAM,UAAU,GAAG,MAAA,MAAA,KAAK,CAAC,CAAC,CAAC,0CAAE,UAAU,mCAAI,IAAA,kBAAW,EAAC,KAAK,CAAC,CAAC;IAC9D,OAAO,KAAK,CAAC,MAAM,KAAK,WAAW;QACjC,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,EAAE,KAAK,CAAC,WAAqB,EAAE,GAAG,IAAI,EAAE;QAClG,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE,YAAY,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,CAAC;AAClF,CAAC;AAED,2HAA2H;AAC3H,SAAgB,aAAa,CAAC,KAAe,EAAE,KAAa;IAC1D,MAAM,WAAW,GAAG,IAAA,kBAAW,EAAC,KAAK,CAAC,CAAC;IACvC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IAClC,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;IACnC,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;QACnB,MAAM,IAAI,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC;QAC9B,MAAM,QAAQ,GAAG,KAAK,CAAC,SAAS,IAAI,IAAI,CAAC,SAAS,KAAK,IAAI,CAAC;QAC5D,IAAI,CAAC,QAAQ;YAAE,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE,GAAG,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC;IACxE,CAAC;IACD,OAAO,EAAE,GAAG,KAAK,EAAE,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,CAAC;AACvF,CAAC;AAED,kHAAkH;AAClH,SAAgB,IAAI,CAAC,KAAe,EAAE,KAAa;IACjD,MAAM,IAAI,GAAG,UAAU,CAAC,aAAa,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,KAAK,CAAC,OAAO,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;IAC/E,OAAO,IAAA,qBAAc,EAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,IAAI,wBAAgB,CAAC;AAClE,CAAC;AAED,MAAM,MAAM,GAAG,CAAC,CAAW,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAA0B,CAAC;AAErF,qGAAqG;AACrG,SAAS,YAAY,CAAC,KAAe,EAAE,EAAU;;IAC/C,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC3B,IAAI,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC;IACxB,IAAI,IAAI,CAAC,SAAS,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,eAAe;QAAE,OAAO,KAAK,CAAC;IACpE,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IAClC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,IAAI,EAAE,SAAS,EAAE,MAAA,IAAI,CAAC,SAAS,mCAAI,EAAE,EAAE,CAAC;IACvE,OAAO,EAAE,GAAG,KAAK,EAAE,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,CAAC;AACrD,CAAC;AAED,SAAS,aAAa,CAAC,KAAe;IACpC,OAAO,EAAE,GAAG,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;AACvC,CAAC;AAED,6BAA6B;AAC7B,SAAgB,KAAK,CAAC,KAAe,EAAE,OAAe,EAAE,KAAa;IACnE,MAAM,EAAE,GAAG,IAAA,kBAAW,EAAC,KAAK,CAAC,CAAC;IAC9B,MAAM,MAAM,GAAG,EAAE,GAAG,YAAY,CAAC,KAAK,EAAE,EAAE,CAAC,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;IACnE,IAAI,KAAK,CAAC,SAAS;QAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,KAAK,KAAK,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC;IAC3G,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,IAAI,mBAAW;QAAE,OAAO,EAAE,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC;IACpH,MAAM,IAAI,GAAa;QACrB,GAAG,MAAM;QACT,KAAK,EAAE,CAAC,GAAG,MAAM,CAAC,KAAK,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;KAC9F,CAAC;IACF,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC;IACrG,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;AACnD,CAAC;AAED;;;GAGG;AACH,SAAgB,IAAI,CAAC,KAAe,EAAE,KAAa,EAAE,OAAiB,EAAE,KAAa;IACnF,MAAM,KAAK,GAAW,EAAE,CAAC;IACzB,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,MAAM,MAAM,GAAG,KAAK,KAAK,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;IAEhD,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;QACtB,IAAI,OAAO,CAAC,MAAM;YAAE,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAC9C,CAAC;SAAM,CAAC;QACN,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YACnC,MAAM,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,KAAK,MAAM,CAAC,YAAY,CAAC,CAAC;YAClF,IAAI,EAAE,GAAG,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,IAAI,mBAAW,EAAE,CAAC;gBAClD,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;gBAC/B,SAAS;YACX,CAAC;YACD,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YACnC,IAAI,EAAE,GAAG,CAAC;gBAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;;gBACzB,IAAI,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC;YACvB,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;YACpC,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;YAC3C,MAAM,IAAI,GAAG,EAAE,GAAG,OAAO,EAAE,KAAK,EAAE,CAAC;YACnC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC;gBACvB,OAAO,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;gBACjC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;gBACxB,OAAO,GAAG,IAAI,CAAC;gBACf,MAAM;YACR,CAAC;YACD,OAAO,GAAG,IAAI,CAAC;YACf,OAAO,GAAG,IAAI,CAAC;QACjB,CAAC;IACH,CAAC;IAED,4EAA4E;IAC5E,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACnC,IAAI,MAAM,IAAI,KAAK,CAAC,SAAS,KAAK,IAAI,EAAE,CAAC;QACvC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACpC,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,KAAK,EAAE,SAAS,EAAE,IAAA,kBAAW,EAAC,KAAK,CAAC,EAAE,CAAC;QAC3D,OAAO,GAAG,EAAE,GAAG,OAAO,EAAE,KAAK,EAAE,eAAe,EAAE,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;QACrE,OAAO,GAAG,IAAI,CAAC;IACjB,CAAC;SAAM,IAAI,MAAM,IAAI,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;QAClE,OAAO,GAAG,EAAE,GAAG,OAAO,EAAE,eAAe,EAAE,KAAK,EAAE,CAAC;QACjD,OAAO,GAAG,IAAI,CAAC;IACjB,CAAC;IACD,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;AAChF,CAAC;AAED,iFAAiF;AACjF,SAAgB,aAAa,CAAC,KAAe,EAAE,MAAkB,EAAE,KAAa;;IAC9E,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,MAAA,KAAK,CAAC,UAAU,mCAAI,EAAE,CAAC;QAAE,OAAO,SAAS,CAAC,KAAK,CAAC,CAAC;IAC/F,IAAI,KAAK,CAAC,SAAS;QAAE,OAAO,SAAS,CAAC,KAAK,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;IAC5D,MAAM,IAAI,GAAG,EAAE,GAAG,KAAK,EAAE,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC;IACvF,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,KAAK,EAAE,aAAa,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC;IACpG,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;AACnD,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,OAAO,CAAC,KAAe,EAAE,KAAa;IACpD,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC3B,IAAI,CAAC,IAAI;QAAE,OAAO,SAAS,CAAC,KAAK,CAAC,CAAC;IACnC,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,IAAI,IAAI,CAAC,SAAS,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,eAAe,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC;QAC3E,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;QACrF,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QAClC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,IAAI,EAAE,SAAS,EAAE,IAAA,kBAAW,EAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC,EAAE,CAAC;QACzG,OAAO,GAAG,EAAE,GAAG,KAAK,EAAE,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,CAAC;IACxD,CAAC;IACD,OAAO,GAAG,EAAE,GAAG,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;IAC9C,IAAI,OAAO,CAAC,SAAS;QAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;IAC3E,IAAI,OAAO,CAAC,KAAK,CAAC,MAAM,IAAI,mBAAW;QAAE,OAAO,EAAE,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC;IACvH,MAAM,IAAI,GAAa;QACrB,GAAG,OAAO;QACV,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC,KAAK,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,UAAU,EAAE,IAAA,kBAAW,EAAC,KAAK,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;KACrH,CAAC;IACF,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC;IACtG,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;AACnD,CAAC;AAED,sGAAsG;AACtG,SAAgB,OAAO,CAAC,KAAe;IACrC,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC3B,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,IAAI,EAAE,CAAC;QACT,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACpC,IAAI,IAAI,CAAC,SAAS;YAAE,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;IAC1E,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,135 @@
1
+ import { type RunContextInput } from "../core/context";
2
+ import { type RetryPolicy } from "../core/delivery";
3
+ import { type DiagnosticHandler } from "../core/diagnostics";
4
+ import type { Sink } from "../core/sink";
5
+ import { type KeyValueStorage } from "../core/storage";
6
+ import { type Clock, type Timers } from "../core/time";
7
+ import type { OnboardingRunSnapshot, Properties } from "./contract";
8
+ import { type AnswerInput, type StartOptions } from "./input";
9
+ export interface TrackerConfig {
10
+ /** Where snapshots go. `createHttpSink` is the stock one. */
11
+ sink: Sink<OnboardingRunSnapshot>;
12
+ /** Device and app facts, or a function returning them, read once per run at start. */
13
+ context: RunContextInput | (() => RunContextInput);
14
+ /**
15
+ * Persists the run so it can be resumed after the app is killed, and keeps an
16
+ * unsent snapshot across restarts. AsyncStorage fits as is. Without it,
17
+ * nothing survives a restart, and `resume()` resolves null unless a tracker
18
+ * disposed in this process on the same `storageKey` handed it a run.
19
+ */
20
+ storage?: KeyValueStorage;
21
+ /** Storage key. Default `rocalytics-sdk:onboarding-run`. One restorable run per key. */
22
+ storageKey?: string;
23
+ clock?: Clock;
24
+ timers?: Timers;
25
+ /** Run id minter. Must return a lowercase UUID. Default: UUIDv7. */
26
+ uuid?: () => string;
27
+ /**
28
+ * Changes within this window go out as one send. Default 500 ms. Completion
29
+ * and background skip the debounce, but with `storage` every send, these
30
+ * included, first waits for its snapshot to be written: up to
31
+ * `persistTimeoutMs` (default 1,000 ms) later.
32
+ */
33
+ debounceMs?: number;
34
+ retry?: RetryPolicy;
35
+ /** A send with no answer after this long is retried. Default 30,000 ms. */
36
+ attemptTimeoutMs?: number;
37
+ /**
38
+ * Each snapshot is stored (with its seq) before it is handed to the sink, so
39
+ * a kill in between can never make a resumed run reuse that seq for a
40
+ * different body. A storage slower than this does not hold the send back any
41
+ * longer: it goes out anyway, and only then can a kill in that window cost
42
+ * the guarantee. Default 1,000 ms. Ignored without `storage`.
43
+ */
44
+ persistTimeoutMs?: number;
45
+ /**
46
+ * How long a storage read may take before it is reported as slow. It does
47
+ * not cut `resume()` short: `resume()` waits for the read however long it
48
+ * takes. It bounds `idle()`, which waits at most this long for the read and
49
+ * as long again for queued writes, so up to about twice this; and with it,
50
+ * how long a tracker created after a `dispose()` on the same `storageKey`
51
+ * waits for the disposed one's writes before it reads. `start()` never waits
52
+ * for the read. Default 5,000 ms.
53
+ */
54
+ storageReadTimeoutMs?: number;
55
+ /** Receives what the tracker declined to do. Default: `console.warn`. */
56
+ onDiagnostic?: DiagnosticHandler;
57
+ }
58
+ export interface ExitOptions {
59
+ /** What was answered on this visit. Values are stable option keys, never displayed labels. */
60
+ answers?: AnswerInput[];
61
+ }
62
+ /** One pass through an onboarding. Every method is safe to call at any time and never throws. */
63
+ export interface OnboardingRun {
64
+ /** Lowercase UUID, minted when the run starts. */
65
+ readonly runId: string;
66
+ /**
67
+ * The step of the last RECORDED entry; null before the first step. In a
68
+ * truncated run recording has stopped, so this can be an earlier screen than
69
+ * the one the user was on: restore the position from the app's own
70
+ * navigation state, not from this.
71
+ */
72
+ readonly currentStepKey: string | null;
73
+ /** A screen is shown. Call it again for the same step after going back to it. */
74
+ enterStep(stepKey: string): void;
75
+ /** The user leaves a screen, with what they answered there. */
76
+ exitStep(stepKey: string, options?: ExitOptions): void;
77
+ /** Adds or changes run properties. */
78
+ setProperties(properties: Properties): void;
79
+ /** The onboarding is finished. Final: the run records nothing after it. */
80
+ complete(): void;
81
+ /** The app moved to the background: records the moment and sends now. */
82
+ background(): void;
83
+ }
84
+ export interface OnboardingRunTracker {
85
+ /** Starts a new run. A run already in progress is left as it is, and stays in progress (a replay is a new run). */
86
+ start(options: StartOptions): OnboardingRun;
87
+ /**
88
+ * Resumes the run that was in progress when the app was killed, or resolves
89
+ * null. Call it only when the app restores the user's position; otherwise
90
+ * call `start`. The restored screen is recorded as a new entry for the last
91
+ * recorded step. A truncated run is still returned (so it can complete) but
92
+ * records no new entry. Null once a run was started this session.
93
+ *
94
+ * After a reconfigure, the run is the one the disposed tracker on this
95
+ * `storageKey` was recording, in its newest state, with storage or without;
96
+ * null if that tracker completed it or started another.
97
+ *
98
+ * It waits for the stored state to be read, however long that takes: a
99
+ * storage that never answers the read means it never resolves. An app that
100
+ * cannot wait should race it with its own timeout and call `start` instead.
101
+ */
102
+ resume(): Promise<OnboardingRun | null>;
103
+ /** Resolves once queued storage writes are done. */
104
+ idle(): Promise<void>;
105
+ /**
106
+ * Stops recording without dropping what was recorded: a change on the
107
+ * debounce is sent, writes already queued land, and each unsent snapshot
108
+ * gets one last attempt (no retry timers). One the sink does not take is
109
+ * handed, in memory, to the next tracker created on the same `storageKey`
110
+ * (as `configure()` does), which sends it with its own sink and retries,
111
+ * with or without storage, provided its sink has the same `destination`
112
+ * (or, without one, is the same object). That tracker keeps this one's
113
+ * unsent snapshots in its writes from the start, sends none of them until
114
+ * these last attempts are answered, and drops any they delivered. A tracker
115
+ * disposed without a run of its own passes on what it was handed. With
116
+ * working storage the snapshot also stays stored for the next launch;
117
+ * without it, a snapshot is lost if the app is killed before a next tracker
118
+ * is created. Safe to call twice.
119
+ */
120
+ dispose(): void;
121
+ }
122
+ export declare function createOnboardingRunTracker(config: TrackerConfig): OnboardingRunTracker;
123
+ /**
124
+ * The app-wide tracker. Call `configure` once at startup, then `start` (or
125
+ * `resume`) for each run. Before `configure`, `start` returns a run that
126
+ * records nothing, and warns.
127
+ */
128
+ export declare const onboardingRun: {
129
+ configure(config: TrackerConfig): void;
130
+ start(options: StartOptions): OnboardingRun;
131
+ resume(): Promise<OnboardingRun | null>;
132
+ idle(): Promise<void>;
133
+ dispose(): void;
134
+ };
135
+ //# sourceMappingURL=tracker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tracker.d.ts","sourceRoot":"","sources":["../../src/onboarding/tracker.ts"],"names":[],"mappings":"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"}