@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,68 @@
1
+ /** The members of `expo-application` the client reads. The module itself fits as is. */
2
+ export interface ApplicationModule {
3
+ readonly applicationId: string | null;
4
+ readonly applicationName: string | null;
5
+ readonly nativeApplicationVersion: string | null;
6
+ readonly nativeBuildVersion: string | null;
7
+ getIosIdForVendorAsync(): Promise<string | null>;
8
+ getAndroidId(): string;
9
+ getInstallationTimeAsync(): Promise<Date>;
10
+ }
11
+ /** The native capabilities the client uses, shaped like the Expo modules and react-native, which fit as they are. */
12
+ export interface RocalyticsModules {
13
+ application: ApplicationModule;
14
+ crypto: {
15
+ randomUUID(): string;
16
+ };
17
+ device: {
18
+ readonly brand: string | null;
19
+ readonly modelName: string | null;
20
+ readonly manufacturer: string | null;
21
+ readonly osName: string | null;
22
+ readonly osVersion: string | null;
23
+ };
24
+ network: {
25
+ getIpAddressAsync(): Promise<string>;
26
+ };
27
+ secureStore: {
28
+ getItemAsync(key: string): Promise<string | null>;
29
+ setItemAsync(key: string, value: string): Promise<void>;
30
+ };
31
+ /** react-native's `Platform`. */
32
+ platform: {
33
+ readonly OS: string;
34
+ readonly Version: string | number;
35
+ };
36
+ /** react-native's `Dimensions`. */
37
+ dimensions: {
38
+ get(dim: "screen"): {
39
+ width: number;
40
+ height: number;
41
+ scale: number;
42
+ };
43
+ };
44
+ }
45
+ /** How each package is loaded. Injected by tests; the defaults are the literal requires. */
46
+ export interface ExpoModuleLoaders {
47
+ core: () => unknown;
48
+ application: () => unknown;
49
+ crypto: () => unknown;
50
+ device: () => unknown;
51
+ network: () => unknown;
52
+ secureStore: () => unknown;
53
+ reactNative: () => unknown;
54
+ }
55
+ export type LoadResult = {
56
+ ok: true;
57
+ modules: RocalyticsModules;
58
+ } | {
59
+ ok: false;
60
+ reason: string;
61
+ };
62
+ /**
63
+ * Loads the Expo modules and react-native, or explains why it could not.
64
+ * Never throws: a missing package, a native module absent from the binary, or
65
+ * a wrapper that throws while loading all come back as `{ ok: false, reason }`.
66
+ */
67
+ export declare function loadExpoModules(loaders?: ExpoModuleLoaders): LoadResult;
68
+ //# sourceMappingURL=native.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native.d.ts","sourceRoot":"","sources":["../../src/client/native.ts"],"names":[],"mappings":"AAuBA,wFAAwF;AACxF,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,QAAQ,CAAC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IACxC,QAAQ,CAAC,wBAAwB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjD,QAAQ,CAAC,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3C,sBAAsB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACjD,YAAY,IAAI,MAAM,CAAC;IACvB,wBAAwB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3C;AAED,qHAAqH;AACrH,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,iBAAiB,CAAC;IAC/B,MAAM,EAAE;QAAE,UAAU,IAAI,MAAM,CAAA;KAAE,CAAC;IACjC,MAAM,EAAE;QACN,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;QAC9B,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;QAClC,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;QACrC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;QAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;KACnC,CAAC;IACF,OAAO,EAAE;QAAE,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC,CAAA;KAAE,CAAC;IAClD,WAAW,EAAE;QACX,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;QAClD,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;KACzD,CAAC;IACF,iCAAiC;IACjC,QAAQ,EAAE;QAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;IACrE,mCAAmC;IACnC,UAAU,EAAE;QAAE,GAAG,CAAC,GAAG,EAAE,QAAQ,GAAG;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC;CACtF;AAED,4FAA4F;AAC5F,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,OAAO,CAAC;IACpB,WAAW,EAAE,MAAM,OAAO,CAAC;IAC3B,MAAM,EAAE,MAAM,OAAO,CAAC;IACtB,MAAM,EAAE,MAAM,OAAO,CAAC;IACtB,OAAO,EAAE,MAAM,OAAO,CAAC;IACvB,WAAW,EAAE,MAAM,OAAO,CAAC;IAC3B,WAAW,EAAE,MAAM,OAAO,CAAC;CAC5B;AAED,MAAM,MAAM,UAAU,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,iBAAiB,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAelG;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,GAAE,iBAAmC,GAAG,UAAU,CAqBxF"}
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ // The one file in the package that loads another package.
3
+ //
4
+ // The Rocalytics client needs five Expo native modules and react-native. They
5
+ // are optional peer dependencies: an app that only uses /onboarding installs
6
+ // none of them, and nothing outside this file references them.
7
+ //
8
+ // They are loaded lazily, at client start, never at import time. An Expo
9
+ // module's JS wrapper calls `requireNativeModule("ExpoXxx")` when it is first
10
+ // evaluated, which throws when the app binary predates the module (a JS update
11
+ // shipped over the air onto an older build). So each native module is first
12
+ // probed through `requireOptionalNativeModule` (expo-modules-core), which
13
+ // returns null instead of throwing, and no wrapper is required unless every
14
+ // probe succeeds. The probe must not be `TurboModuleRegistry.get`: on the New
15
+ // Architecture, Expo modules are registered with the Expo modules registry,
16
+ // not the TurboModule registry, so that probe reports a linked module as
17
+ // missing.
18
+ //
19
+ // Every require is a string literal, so a bundler can see it. Metro resolves
20
+ // them at bundle time: an app that imports /client without installing a
21
+ // peer fails to bundle, rather than going inert at run time.
22
+ Object.defineProperty(exports, "__esModule", { value: true });
23
+ exports.loadExpoModules = loadExpoModules;
24
+ /** The native module names the wrappers pass to `requireNativeModule`. */
25
+ const NATIVE_MODULES = ["ExpoApplication", "ExpoCrypto", "ExpoDevice", "ExpoNetwork", "ExpoSecureStore"];
26
+ const DEFAULT_LOADERS = {
27
+ core: () => require("expo-modules-core"),
28
+ application: () => require("expo-application"),
29
+ crypto: () => require("expo-crypto"),
30
+ device: () => require("expo-device"),
31
+ network: () => require("expo-network"),
32
+ secureStore: () => require("expo-secure-store"),
33
+ reactNative: () => require("react-native"),
34
+ };
35
+ /**
36
+ * Loads the Expo modules and react-native, or explains why it could not.
37
+ * Never throws: a missing package, a native module absent from the binary, or
38
+ * a wrapper that throws while loading all come back as `{ ok: false, reason }`.
39
+ */
40
+ function loadExpoModules(loaders = DEFAULT_LOADERS) {
41
+ try {
42
+ const core = loaders.core();
43
+ const missing = NATIVE_MODULES.find((name) => core.requireOptionalNativeModule(name) == null);
44
+ if (missing)
45
+ return { ok: false, reason: `native module ${missing} is not in this binary` };
46
+ const reactNative = loaders.reactNative();
47
+ return {
48
+ ok: true,
49
+ modules: {
50
+ application: loaders.application(),
51
+ crypto: loaders.crypto(),
52
+ device: loaders.device(),
53
+ network: loaders.network(),
54
+ secureStore: loaders.secureStore(),
55
+ platform: reactNative.Platform,
56
+ dimensions: reactNative.Dimensions,
57
+ },
58
+ };
59
+ }
60
+ catch (error) {
61
+ return { ok: false, reason: error instanceof Error ? error.message : String(error) };
62
+ }
63
+ }
64
+ //# sourceMappingURL=native.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native.js","sourceRoot":"","sources":["../../src/client/native.ts"],"names":[],"mappings":";AAAA,0DAA0D;AAC1D,EAAE;AACF,8EAA8E;AAC9E,6EAA6E;AAC7E,+DAA+D;AAC/D,EAAE;AACF,yEAAyE;AACzE,8EAA8E;AAC9E,+EAA+E;AAC/E,4EAA4E;AAC5E,0EAA0E;AAC1E,4EAA4E;AAC5E,8EAA8E;AAC9E,4EAA4E;AAC5E,yEAAyE;AACzE,WAAW;AACX,EAAE;AACF,6EAA6E;AAC7E,wEAAwE;AACxE,6DAA6D;;AAoE7D,0CAqBC;AAvCD,0EAA0E;AAC1E,MAAM,cAAc,GAAG,CAAC,iBAAiB,EAAE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,iBAAiB,CAAC,CAAC;AAEzG,MAAM,eAAe,GAAsB;IACzC,IAAI,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,mBAAmB,CAAC;IACxC,WAAW,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,kBAAkB,CAAC;IAC9C,MAAM,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,aAAa,CAAC;IACpC,MAAM,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,aAAa,CAAC;IACpC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,cAAc,CAAC;IACtC,WAAW,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,mBAAmB,CAAC;IAC/C,WAAW,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,cAAc,CAAC;CAC3C,CAAC;AAEF;;;;GAIG;AACH,SAAgB,eAAe,CAAC,UAA6B,eAAe;IAC1E,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAA4D,CAAC;QACtF,MAAM,OAAO,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,2BAA2B,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC;QAC9F,IAAI,OAAO;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,iBAAiB,OAAO,wBAAwB,EAAE,CAAC;QAC5F,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,EAA8F,CAAC;QACtI,OAAO;YACL,EAAE,EAAE,IAAI;YACR,OAAO,EAAE;gBACP,WAAW,EAAE,OAAO,CAAC,WAAW,EAAsC;gBACtE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAiC;gBACvD,MAAM,EAAE,OAAO,CAAC,MAAM,EAAiC;gBACvD,OAAO,EAAE,OAAO,CAAC,OAAO,EAAkC;gBAC1D,WAAW,EAAE,OAAO,CAAC,WAAW,EAAsC;gBACtE,QAAQ,EAAE,WAAW,CAAC,QAAQ;gBAC9B,UAAU,EAAE,WAAW,CAAC,UAAU;aACnC;SACF,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;IACvF,CAAC;AACH,CAAC"}
@@ -0,0 +1,63 @@
1
+ import type { SinkResult, Sink } from "../core/sink";
2
+ import type { OnboardingRunSnapshot } from "../onboarding/contract";
3
+ import type { RocalyticsClient } from "./client";
4
+ import type { OnboardingResponsePayload } from "./types";
5
+ /**
6
+ * A v1 onboarding run snapshot in the pre-v1 `/onboarding-response` shape,
7
+ * which is the only onboarding payload the Rocalytics ingest reads. The keys
8
+ * follow docs/onboarding-run-contract.md, section 9, which is how the ingest
9
+ * reads such a payload back into a run.
10
+ *
11
+ * - Each entry is a response: `step_key` becomes `step_id`, timestamps are kept.
12
+ * - Answers become `{ [question_key]: value }`. A numeric answer's `unit` has
13
+ * no place in that shape and is dropped.
14
+ * - `onboarding_metadata` carries the keys section 9 reads: `onboardingId`
15
+ * (the Studio onboarding) or, with none, `onboarding_id` (the onboarding
16
+ * key, as a hand-coded sender sets it), `audienceId`, `deployment_id`,
17
+ * `locale` (from the run's context) and `draft: true` for a draft. It also
18
+ * carries `onboarding_key`, `onboarding_version`, `variant_key`, `run_id`
19
+ * and `seq`, which section 9 does not read.
20
+ * - `sent_at` is NOT the device's send time. The ingest keeps one snapshot
21
+ * per sender and replaces it only when the incoming `sent_at` is strictly
22
+ * later, answering 2xx either way, so two sends in one millisecond, or a
23
+ * device clock stepping back, would drop a snapshot (the completion
24
+ * included) while it reads as delivered. So `sent_at` is the run's latest
25
+ * recorded timestamp plus `seq` milliseconds. A snapshot only ever adds
26
+ * timestamps to the one before it and `seq` rises with every send, so this
27
+ * strictly increases across a run's sends whatever the device clock does.
28
+ * Only within a run: the ingest keeps one row per sender, so after the
29
+ * clock steps back between runs, a later run's snapshots can still be
30
+ * dropped while answered 2xx, as pre-v1 reporting already could.
31
+ * It depends on the snapshot alone, so a retry, even after a relaunch,
32
+ * resends the identical body.
33
+ */
34
+ export declare function toOnboardingResponsePayload(snapshot: OnboardingRunSnapshot): OnboardingResponsePayload;
35
+ /**
36
+ * Reads an `/onboarding-response` answer as a sink outcome. The endpoint
37
+ * answers success with a 2xx and no body, so a 2xx is accepted. Otherwise,
38
+ * as the contract's section 5 requires, only a body that says
39
+ * `{"outcome": "rejected"}` is permanent: every other status, whatever its
40
+ * body, is transient and the snapshot is retried.
41
+ */
42
+ export declare function rocalyticsOutcome(status: number, body?: unknown): SinkResult;
43
+ /**
44
+ * A sink for the onboarding run tracker (`@rocapine/rocalytics-sdk/onboarding`)
45
+ * that delivers each snapshot to Rocalytics through `client`, as the pre-v1
46
+ * onboarding payload (see `toOnboardingResponsePayload`).
47
+ *
48
+ * Once a completed snapshot is accepted, the sink also sends the
49
+ * `onboarding_completed` event, which is where consumers of the pre-v1 data
50
+ * read completion from. It is deduplicated per device, like any `track`
51
+ * event; if it fails, the send is transient, so the tracker's retry sends it.
52
+ *
53
+ * The ingest keeps one onboarding snapshot per roca id, so a new run replaces
54
+ * the previous one there, and an app should report a flow through this sink
55
+ * or through `client.trackOnboarding`, not both.
56
+ *
57
+ * While the client is inert every send is transient: the tracker keeps the
58
+ * snapshot, persisted when it has storage, for a launch where the client works.
59
+ *
60
+ * Its `destination` is the client's `onboardingRunDestination`.
61
+ */
62
+ export declare function createRocalyticsOnboardingSink(client: RocalyticsClient): Sink<OnboardingRunSnapshot>;
63
+ //# sourceMappingURL=onboardingSink.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"onboardingSink.d.ts","sourceRoot":"","sources":["../../src/client/onboardingSink.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,KAAK,EAAU,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC5E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AACjD,OAAO,KAAK,EAAsB,yBAAyB,EAAyB,MAAM,SAAS,CAAC;AAEpG;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,qBAAqB,GAAG,yBAAyB,CA2BtG;AAsBD;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,UAAU,CAO5E;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,8BAA8B,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAAC,qBAAqB,CAAC,CAEpG"}
@@ -0,0 +1,126 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toOnboardingResponsePayload = toOnboardingResponsePayload;
4
+ exports.rocalyticsOutcome = rocalyticsOutcome;
5
+ exports.createRocalyticsOnboardingSink = createRocalyticsOnboardingSink;
6
+ /**
7
+ * A v1 onboarding run snapshot in the pre-v1 `/onboarding-response` shape,
8
+ * which is the only onboarding payload the Rocalytics ingest reads. The keys
9
+ * follow docs/onboarding-run-contract.md, section 9, which is how the ingest
10
+ * reads such a payload back into a run.
11
+ *
12
+ * - Each entry is a response: `step_key` becomes `step_id`, timestamps are kept.
13
+ * - Answers become `{ [question_key]: value }`. A numeric answer's `unit` has
14
+ * no place in that shape and is dropped.
15
+ * - `onboarding_metadata` carries the keys section 9 reads: `onboardingId`
16
+ * (the Studio onboarding) or, with none, `onboarding_id` (the onboarding
17
+ * key, as a hand-coded sender sets it), `audienceId`, `deployment_id`,
18
+ * `locale` (from the run's context) and `draft: true` for a draft. It also
19
+ * carries `onboarding_key`, `onboarding_version`, `variant_key`, `run_id`
20
+ * and `seq`, which section 9 does not read.
21
+ * - `sent_at` is NOT the device's send time. The ingest keeps one snapshot
22
+ * per sender and replaces it only when the incoming `sent_at` is strictly
23
+ * later, answering 2xx either way, so two sends in one millisecond, or a
24
+ * device clock stepping back, would drop a snapshot (the completion
25
+ * included) while it reads as delivered. So `sent_at` is the run's latest
26
+ * recorded timestamp plus `seq` milliseconds. A snapshot only ever adds
27
+ * timestamps to the one before it and `seq` rises with every send, so this
28
+ * strictly increases across a run's sends whatever the device clock does.
29
+ * Only within a run: the ingest keeps one row per sender, so after the
30
+ * clock steps back between runs, a later run's snapshots can still be
31
+ * dropped while answered 2xx, as pre-v1 reporting already could.
32
+ * It depends on the snapshot alone, so a retry, even after a relaunch,
33
+ * resends the identical body.
34
+ */
35
+ function toOnboardingResponsePayload(snapshot) {
36
+ var _a, _b, _c;
37
+ const metadata = {};
38
+ const set = (key, value) => {
39
+ if (value !== undefined && value !== null)
40
+ metadata[key] = value;
41
+ };
42
+ const studioOnboardingId = (_a = snapshot.studio) === null || _a === void 0 ? void 0 : _a.onboarding_id;
43
+ if (studioOnboardingId != null)
44
+ set("onboardingId", studioOnboardingId);
45
+ else
46
+ set("onboarding_id", snapshot.onboarding.key);
47
+ set("audienceId", (_b = snapshot.studio) === null || _b === void 0 ? void 0 : _b.audience_id);
48
+ set("deployment_id", (_c = snapshot.studio) === null || _c === void 0 ? void 0 : _c.deployment_id);
49
+ set("locale", snapshot.context.locale);
50
+ if (snapshot.onboarding.version === "draft")
51
+ set("draft", true);
52
+ set("onboarding_key", snapshot.onboarding.key);
53
+ set("onboarding_version", snapshot.onboarding.version);
54
+ set("variant_key", snapshot.onboarding.variant_key);
55
+ set("run_id", snapshot.run_id);
56
+ set("seq", snapshot.seq);
57
+ return {
58
+ onboarding_metadata: metadata,
59
+ sent_at: new Date(latestRecorded(snapshot) + snapshot.seq).toISOString(),
60
+ responses: snapshot.steps.map((entry) => ({
61
+ step_id: entry.step_key,
62
+ entered_at: entry.entered_at,
63
+ exited_at: entry.exited_at,
64
+ answers: toAnswers(entry.answers),
65
+ })),
66
+ };
67
+ }
68
+ /** The latest timestamp the run has recorded: its start, entries, exits and completion. Not `sent_at`. */
69
+ function latestRecorded(snapshot) {
70
+ let latest = Date.parse(snapshot.started_at);
71
+ const consider = (ts) => {
72
+ if (ts !== null)
73
+ latest = Math.max(latest, Date.parse(ts));
74
+ };
75
+ for (const entry of snapshot.steps) {
76
+ consider(entry.entered_at);
77
+ consider(entry.exited_at);
78
+ }
79
+ consider(snapshot.completed_at);
80
+ return latest;
81
+ }
82
+ function toAnswers(answers) {
83
+ const out = {};
84
+ for (const answer of answers)
85
+ out[answer.question_key] = Array.isArray(answer.value) ? [...answer.value] : answer.value;
86
+ return out;
87
+ }
88
+ /**
89
+ * Reads an `/onboarding-response` answer as a sink outcome. The endpoint
90
+ * answers success with a 2xx and no body, so a 2xx is accepted. Otherwise,
91
+ * as the contract's section 5 requires, only a body that says
92
+ * `{"outcome": "rejected"}` is permanent: every other status, whatever its
93
+ * body, is transient and the snapshot is retried.
94
+ */
95
+ function rocalyticsOutcome(status, body) {
96
+ if (status >= 200 && status < 300)
97
+ return { outcome: "accepted" };
98
+ if (body && typeof body === "object" && body.outcome === "rejected") {
99
+ const reason = body.reason;
100
+ return typeof reason === "string" ? { outcome: "rejected", reason } : { outcome: "rejected" };
101
+ }
102
+ return { outcome: "transient", reason: `status ${status}` };
103
+ }
104
+ /**
105
+ * A sink for the onboarding run tracker (`@rocapine/rocalytics-sdk/onboarding`)
106
+ * that delivers each snapshot to Rocalytics through `client`, as the pre-v1
107
+ * onboarding payload (see `toOnboardingResponsePayload`).
108
+ *
109
+ * Once a completed snapshot is accepted, the sink also sends the
110
+ * `onboarding_completed` event, which is where consumers of the pre-v1 data
111
+ * read completion from. It is deduplicated per device, like any `track`
112
+ * event; if it fails, the send is transient, so the tracker's retry sends it.
113
+ *
114
+ * The ingest keeps one onboarding snapshot per roca id, so a new run replaces
115
+ * the previous one there, and an app should report a flow through this sink
116
+ * or through `client.trackOnboarding`, not both.
117
+ *
118
+ * While the client is inert every send is transient: the tracker keeps the
119
+ * snapshot, persisted when it has storage, for a launch where the client works.
120
+ *
121
+ * Its `destination` is the client's `onboardingRunDestination`.
122
+ */
123
+ function createRocalyticsOnboardingSink(client) {
124
+ return { destination: client.onboardingRunDestination, send: (snapshot) => client.sendOnboardingRun(snapshot) };
125
+ }
126
+ //# sourceMappingURL=onboardingSink.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"onboardingSink.js","sourceRoot":"","sources":["../../src/client/onboardingSink.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { Sink, SinkResult } from "../core/sink";
2
+ import type { PaywallPresentationSnapshot } from "../paywall/contract";
3
+ import type { RocalyticsClient } from "./client";
4
+ /**
5
+ * Reads a `/paywall-presentations` answer per the paywall contract's section 5
6
+ * (onboarding D27): the body's `outcome` decides. A rejected body is permanent
7
+ * whatever the status. Accepted or ignored counts only on a 2xx. Anything
8
+ * else, including a 2xx without an outcome, is transient and retried.
9
+ */
10
+ export declare function paywallIngestOutcome(status: number, body?: unknown): SinkResult;
11
+ /** Delivers the paywall tracker's snapshots to Rocalytics. Its `destination` is the client's `paywallPresentationDestination`. */
12
+ export declare function createRocalyticsPaywallSink(client: RocalyticsClient): Sink<PaywallPresentationSnapshot>;
13
+ //# sourceMappingURL=paywallSink.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paywallSink.d.ts","sourceRoot":"","sources":["../../src/client/paywallSink.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AACvE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAIjD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,UAAU,CAO/E;AAED,kIAAkI;AAClI,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAAC,2BAA2B,CAAC,CAEvG"}
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.paywallIngestOutcome = paywallIngestOutcome;
4
+ exports.createRocalyticsPaywallSink = createRocalyticsPaywallSink;
5
+ const OUTCOMES = new Set(["accepted", "ignored", "rejected"]);
6
+ /**
7
+ * Reads a `/paywall-presentations` answer per the paywall contract's section 5
8
+ * (onboarding D27): the body's `outcome` decides. A rejected body is permanent
9
+ * whatever the status. Accepted or ignored counts only on a 2xx. Anything
10
+ * else, including a 2xx without an outcome, is transient and retried.
11
+ */
12
+ function paywallIngestOutcome(status, body) {
13
+ const o = body && typeof body === "object" ? body : undefined;
14
+ const outcome = typeof (o === null || o === void 0 ? void 0 : o.outcome) === "string" && OUTCOMES.has(o.outcome) ? o.outcome : undefined;
15
+ const reason = typeof (o === null || o === void 0 ? void 0 : o.reason) === "string" ? o.reason : undefined;
16
+ if (outcome === "rejected")
17
+ return reason ? { outcome, reason } : { outcome };
18
+ if (outcome && status >= 200 && status < 300)
19
+ return { outcome };
20
+ return { outcome: "transient", reason: `status ${status}` };
21
+ }
22
+ /** Delivers the paywall tracker's snapshots to Rocalytics. Its `destination` is the client's `paywallPresentationDestination`. */
23
+ function createRocalyticsPaywallSink(client) {
24
+ return { destination: client.paywallPresentationDestination, send: (s) => client.sendPaywallPresentation(s) };
25
+ }
26
+ //# sourceMappingURL=paywallSink.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paywallSink.js","sourceRoot":"","sources":["../../src/client/paywallSink.ts"],"names":[],"mappings":";;AAYA,oDAOC;AAGD,kEAEC;AApBD,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,CAAC,UAAU,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC,CAAC;AAE9D;;;;;GAKG;AACH,SAAgB,oBAAoB,CAAC,MAAc,EAAE,IAAc;IACjE,MAAM,CAAC,GAAG,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAE,IAAgD,CAAC,CAAC,CAAC,SAAS,CAAC;IAC3G,MAAM,OAAO,GAAG,OAAO,CAAA,CAAC,aAAD,CAAC,uBAAD,CAAC,CAAE,OAAO,CAAA,KAAK,QAAQ,IAAI,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAE,CAAC,CAAC,OAA+C,CAAC,CAAC,CAAC,SAAS,CAAC;IAC3I,MAAM,MAAM,GAAG,OAAO,CAAA,CAAC,aAAD,CAAC,uBAAD,CAAC,CAAE,MAAM,CAAA,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;IACpE,IAAI,OAAO,KAAK,UAAU;QAAE,OAAO,MAAM,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC;IAC9E,IAAI,OAAO,IAAI,MAAM,IAAI,GAAG,IAAI,MAAM,GAAG,GAAG;QAAE,OAAO,EAAE,OAAO,EAAE,CAAC;IACjE,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,MAAM,EAAE,EAAE,CAAC;AAC9D,CAAC;AAED,kIAAkI;AAClI,SAAgB,2BAA2B,CAAC,MAAwB;IAClE,OAAO,EAAE,WAAW,EAAE,MAAM,CAAC,8BAA8B,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,uBAAuB,CAAC,CAAC,CAAC,EAAE,CAAC;AAChH,CAAC"}
@@ -0,0 +1,66 @@
1
+ import type { DemandScoreSignals, IdentifyParams, OnboardingResponsePayload } from "./types";
2
+ import type { PaywallPresentationSnapshot } from "../paywall/contract";
3
+ export declare const ROCALYTICS_API_BASE = "https://rocalytics-api.rocapine.io";
4
+ /** What every request carries: the device's roca id, the app id and the platform. There is no auth token. */
5
+ export interface RequestContext {
6
+ rocaId: string;
7
+ /** The app's bundle id or package name; sent as `unknown` when null. */
8
+ applicationId: string | null;
9
+ /** `Platform.OS`. */
10
+ platform: string;
11
+ /** Defaults to `ROCALYTICS_API_BASE`. */
12
+ baseUrl?: string;
13
+ }
14
+ /** A request, ready to hand to `fetch(url, init)`. */
15
+ export interface RocalyticsRequest {
16
+ url: string;
17
+ init: {
18
+ method: "POST";
19
+ headers: Record<string, string>;
20
+ body?: string;
21
+ };
22
+ }
23
+ export interface FetchResponseLike {
24
+ ok: boolean;
25
+ status: number;
26
+ json(): Promise<unknown>;
27
+ }
28
+ /** The subset of `fetch` the client uses. */
29
+ export type FetchLike = (url: string, init: RocalyticsRequest["init"]) => Promise<FetchResponseLike>;
30
+ export declare function rocalyticsHeaders(context: RequestContext): Record<string, string>;
31
+ /** `/identify`. The payload is sent as given: drop null identifiers first (the client does). */
32
+ export declare function buildIdentifyRequest(context: RequestContext, payload: Partial<IdentifyParams>): RocalyticsRequest;
33
+ export interface TrackRequestInput {
34
+ name: string;
35
+ properties: Record<string, unknown>;
36
+ deviceContext: Record<string, unknown> | null;
37
+ /** Defaults to `${rocaId}-${name}`. */
38
+ deduplicationId?: string;
39
+ /** A custom event is not stored as an analytics event: the API passes it on to drive automations. */
40
+ customEvent?: boolean;
41
+ }
42
+ /** `/track`. */
43
+ export declare function buildTrackRequest(context: RequestContext, input: TrackRequestInput): RocalyticsRequest;
44
+ /** `/onboarding-response`. */
45
+ export declare function buildOnboardingResponseRequest(context: RequestContext, payload: OnboardingResponsePayload): RocalyticsRequest;
46
+ /** `/demand-score`. The body is optional server-side, so none is sent without signals. */
47
+ export declare function buildDemandScoreRequest(context: RequestContext, signals?: DemandScoreSignals): RocalyticsRequest;
48
+ /**
49
+ * Sends a request and resolves its response, or rejects with
50
+ * `[ROCALYTICS] <endpoint> failed: <status>` (plus ` (<detail>)` when given)
51
+ * when the status is not 2xx.
52
+ */
53
+ export declare function sendRocalyticsRequest(fetch: FetchLike, request: RocalyticsRequest, endpoint: string, detail?: string): Promise<FetchResponseLike>;
54
+ /**
55
+ * The cross-network event id for an event, or `undefined` when its properties
56
+ * carry no transaction identifier: `${name}-${originalTransactionIdentifier}`.
57
+ *
58
+ * Use it as the `event_id` (Meta CAPI or Pixel, TikTok Events API) or
59
+ * `callback_id` (Adjust S2S) when the app also fires the conversion to those
60
+ * networks itself. Rocalytics derives the same id when it forwards the event,
61
+ * so the network deduplicates the two.
62
+ */
63
+ export declare function getEventId(name: string, properties?: Record<string, unknown> | null): string | undefined;
64
+ /** `/paywall-presentations` (I3): the body is the bare snapshot; identity is in the headers `post` sets. */
65
+ export declare function buildPaywallPresentationRequest(context: RequestContext, snapshot: PaywallPresentationSnapshot): RocalyticsRequest;
66
+ //# sourceMappingURL=requests.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"requests.d.ts","sourceRoot":"","sources":["../../src/client/requests.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,cAAc,EAAE,yBAAyB,EAAE,MAAM,SAAS,CAAC;AAC7F,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AAEvE,eAAO,MAAM,mBAAmB,uCAAuC,CAAC;AAExE,6GAA6G;AAC7G,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,wEAAwE;IACxE,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,qBAAqB;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,yCAAyC;IACzC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,sDAAsD;AACtD,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC1E;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;CAC1B;AAED,6CAA6C;AAC7C,MAAM,MAAM,SAAS,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,CAAC,MAAM,CAAC,KAAK,OAAO,CAAC,iBAAiB,CAAC,CAAC;AAErG,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAOjF;AAWD,gGAAgG;AAChG,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,iBAAiB,CAEjH;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC9C,uCAAuC;IACvC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,qGAAqG;IACrG,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,gBAAgB;AAChB,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,iBAAiB,GAAG,iBAAiB,CAQtG;AAED,8BAA8B;AAC9B,wBAAgB,8BAA8B,CAAC,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,yBAAyB,GAAG,iBAAiB,CAE7H;AAED,0FAA0F;AAC1F,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,iBAAiB,CAEhH;AAED;;;;GAIG;AACH,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,SAAS,EAChB,OAAO,EAAE,iBAAiB,EAC1B,QAAQ,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,iBAAiB,CAAC,CAM5B;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GAAG,MAAM,GAAG,SAAS,CAQxG;AAED,4GAA4G;AAC5G,wBAAgB,+BAA+B,CAAC,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,2BAA2B,GAAG,iBAAiB,CAEjI"}
@@ -0,0 +1,90 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ROCALYTICS_API_BASE = void 0;
4
+ exports.rocalyticsHeaders = rocalyticsHeaders;
5
+ exports.buildIdentifyRequest = buildIdentifyRequest;
6
+ exports.buildTrackRequest = buildTrackRequest;
7
+ exports.buildOnboardingResponseRequest = buildOnboardingResponseRequest;
8
+ exports.buildDemandScoreRequest = buildDemandScoreRequest;
9
+ exports.sendRocalyticsRequest = sendRocalyticsRequest;
10
+ exports.getEventId = getEventId;
11
+ exports.buildPaywallPresentationRequest = buildPaywallPresentationRequest;
12
+ exports.ROCALYTICS_API_BASE = "https://rocalytics-api.rocapine.io";
13
+ function rocalyticsHeaders(context) {
14
+ var _a;
15
+ return {
16
+ "Content-Type": "application/json",
17
+ "X-Roca-ID": context.rocaId,
18
+ "X-Application-ID": (_a = context.applicationId) !== null && _a !== void 0 ? _a : "unknown",
19
+ "X-Platform": context.platform,
20
+ };
21
+ }
22
+ const post = (context, endpoint, body) => {
23
+ var _a;
24
+ return ({
25
+ url: `${(_a = context.baseUrl) !== null && _a !== void 0 ? _a : exports.ROCALYTICS_API_BASE}/functions/v1/${endpoint}`,
26
+ init: {
27
+ method: "POST",
28
+ headers: rocalyticsHeaders(context),
29
+ ...(body === undefined ? {} : { body: JSON.stringify(body) }),
30
+ },
31
+ });
32
+ };
33
+ /** `/identify`. The payload is sent as given: drop null identifiers first (the client does). */
34
+ function buildIdentifyRequest(context, payload) {
35
+ return post(context, "identify", payload);
36
+ }
37
+ /** `/track`. */
38
+ function buildTrackRequest(context, input) {
39
+ var _a;
40
+ return post(context, "track", {
41
+ name: input.name,
42
+ deduplication_id: (_a = input.deduplicationId) !== null && _a !== void 0 ? _a : `${context.rocaId}-${input.name}`,
43
+ properties: input.properties,
44
+ device_context: input.deviceContext,
45
+ ...(input.customEvent ? { custom_event: true } : {}),
46
+ });
47
+ }
48
+ /** `/onboarding-response`. */
49
+ function buildOnboardingResponseRequest(context, payload) {
50
+ return post(context, "onboarding-response", payload);
51
+ }
52
+ /** `/demand-score`. The body is optional server-side, so none is sent without signals. */
53
+ function buildDemandScoreRequest(context, signals) {
54
+ return post(context, "demand-score", signals && Object.keys(signals).length > 0 ? signals : undefined);
55
+ }
56
+ /**
57
+ * Sends a request and resolves its response, or rejects with
58
+ * `[ROCALYTICS] <endpoint> failed: <status>` (plus ` (<detail>)` when given)
59
+ * when the status is not 2xx.
60
+ */
61
+ async function sendRocalyticsRequest(fetch, request, endpoint, detail) {
62
+ const response = await fetch(request.url, request.init);
63
+ if (!response.ok) {
64
+ throw new Error(`[ROCALYTICS] ${endpoint} failed: ${response.status}${detail ? ` (${detail})` : ""}`);
65
+ }
66
+ return response;
67
+ }
68
+ /**
69
+ * The cross-network event id for an event, or `undefined` when its properties
70
+ * carry no transaction identifier: `${name}-${originalTransactionIdentifier}`.
71
+ *
72
+ * Use it as the `event_id` (Meta CAPI or Pixel, TikTok Events API) or
73
+ * `callback_id` (Adjust S2S) when the app also fires the conversion to those
74
+ * networks itself. Rocalytics derives the same id when it forwards the event,
75
+ * so the network deduplicates the two.
76
+ */
77
+ function getEventId(name, properties) {
78
+ var _a, _b, _c;
79
+ if (!properties)
80
+ return undefined;
81
+ const txId = (_b = (_a = properties.original_transaction_identifier) !== null && _a !== void 0 ? _a : properties.originalTransactionIdentifier) !== null && _b !== void 0 ? _b : (_c = properties.transaction) === null || _c === void 0 ? void 0 : _c.originalTransactionIdentifier;
82
+ if (!txId)
83
+ return undefined;
84
+ return `${name}-${txId}`;
85
+ }
86
+ /** `/paywall-presentations` (I3): the body is the bare snapshot; identity is in the headers `post` sets. */
87
+ function buildPaywallPresentationRequest(context, snapshot) {
88
+ return post(context, "paywall-presentations", snapshot);
89
+ }
90
+ //# sourceMappingURL=requests.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"requests.js","sourceRoot":"","sources":["../../src/client/requests.ts"],"names":[],"mappings":"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"}