@servicetitan/journey 2.0.0 → 3.0.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 (233) hide show
  1. package/README.md +1 -1
  2. package/dist/__test-utils__/test-runtime.d.ts.map +1 -0
  3. package/dist/__test-utils__/test-runtime.js +54 -0
  4. package/dist/__test-utils__/test-runtime.js.map +1 -0
  5. package/dist/__tests__/core/ambient.test.d.ts.map +1 -0
  6. package/dist/__tests__/core/api.test.d.ts +2 -0
  7. package/dist/__tests__/core/api.test.d.ts.map +1 -0
  8. package/dist/__tests__/core/define-journey.test.d.ts.map +1 -0
  9. package/dist/__tests__/core/requests.test.d.ts.map +1 -0
  10. package/dist/__tests__/core/runtime.test.d.ts.map +1 -0
  11. package/dist/__tests__/core/sanitize.test.d.ts +2 -0
  12. package/dist/__tests__/core/sanitize.test.d.ts.map +1 -0
  13. package/dist/__tests__/core/step.test.d.ts.map +1 -0
  14. package/dist/__tests__/core/timeouts.test.d.ts.map +1 -0
  15. package/dist/__tests__/global.test.d.ts +3 -0
  16. package/dist/__tests__/global.test.d.ts.map +1 -0
  17. package/dist/__tests__/hardening.test.d.ts +2 -0
  18. package/dist/__tests__/hardening.test.d.ts.map +1 -0
  19. package/dist/__tests__/integrations/axios.test.d.ts.map +1 -0
  20. package/dist/__tests__/integrations/context.test.d.ts.map +1 -0
  21. package/dist/__tests__/integrations/expose-app-journey.test.d.ts.map +1 -0
  22. package/dist/__tests__/integrations/fetch.test.d.ts.map +1 -0
  23. package/dist/__tests__/integrations/host-mfe.test.d.ts +2 -0
  24. package/dist/__tests__/integrations/host-mfe.test.d.ts.map +1 -0
  25. package/dist/__tests__/integrations/jquery.test.d.ts.map +1 -0
  26. package/dist/__tests__/integrations/request-key.test.d.ts.map +1 -0
  27. package/dist/__tests__/integrations/scope.test.d.ts.map +1 -0
  28. package/dist/__tests__/integrations/use-journey-step.test.d.ts +2 -0
  29. package/dist/__tests__/integrations/use-journey-step.test.d.ts.map +1 -0
  30. package/dist/__tests__/sinks/console.test.d.ts +2 -0
  31. package/dist/__tests__/sinks/console.test.d.ts.map +1 -0
  32. package/dist/__tests__/sinks/datadog.test.d.ts.map +1 -0
  33. package/dist/__tests__/sinks/sinks.test.d.ts.map +1 -0
  34. package/dist/config.d.ts +61 -13
  35. package/dist/config.d.ts.map +1 -1
  36. package/dist/config.js +98 -29
  37. package/dist/config.js.map +1 -1
  38. package/dist/core/abort-error.d.ts +4 -0
  39. package/dist/core/abort-error.d.ts.map +1 -0
  40. package/dist/core/abort-error.js +22 -0
  41. package/dist/core/abort-error.js.map +1 -0
  42. package/dist/core/api.d.ts +43 -0
  43. package/dist/core/api.d.ts.map +1 -0
  44. package/dist/core/api.js +122 -0
  45. package/dist/core/api.js.map +1 -0
  46. package/dist/{endpoint-policy.d.ts → core/endpoint-policy.d.ts} +14 -4
  47. package/dist/core/endpoint-policy.d.ts.map +1 -0
  48. package/dist/core/endpoint-policy.js +70 -0
  49. package/dist/core/endpoint-policy.js.map +1 -0
  50. package/dist/core/index.d.ts +6 -5
  51. package/dist/core/index.d.ts.map +1 -1
  52. package/dist/core/index.js +4 -3
  53. package/dist/core/index.js.map +1 -1
  54. package/dist/core/limits.d.ts +29 -0
  55. package/dist/core/limits.d.ts.map +1 -0
  56. package/dist/core/limits.js +63 -0
  57. package/dist/core/limits.js.map +1 -0
  58. package/dist/core/request-policy.d.ts +39 -0
  59. package/dist/core/request-policy.d.ts.map +1 -0
  60. package/dist/core/request-policy.js +18 -0
  61. package/dist/core/request-policy.js.map +1 -0
  62. package/dist/core/runtime.d.ts +95 -17
  63. package/dist/core/runtime.d.ts.map +1 -1
  64. package/dist/core/runtime.js +435 -124
  65. package/dist/core/runtime.js.map +1 -1
  66. package/dist/core/sanitize.d.ts +23 -0
  67. package/dist/core/sanitize.d.ts.map +1 -0
  68. package/dist/core/sanitize.js +143 -0
  69. package/dist/core/sanitize.js.map +1 -0
  70. package/dist/core/step-tag.d.ts +31 -6
  71. package/dist/core/step-tag.d.ts.map +1 -1
  72. package/dist/core/step-tag.js +62 -9
  73. package/dist/core/step-tag.js.map +1 -1
  74. package/dist/core/types.d.ts +76 -26
  75. package/dist/core/types.d.ts.map +1 -1
  76. package/dist/core/types.js +4 -1
  77. package/dist/core/types.js.map +1 -1
  78. package/dist/global.d.ts +145 -0
  79. package/dist/global.d.ts.map +1 -0
  80. package/dist/global.js +326 -0
  81. package/dist/global.js.map +1 -0
  82. package/dist/index.d.ts +9 -5
  83. package/dist/index.d.ts.map +1 -1
  84. package/dist/index.js +9 -5
  85. package/dist/index.js.map +1 -1
  86. package/dist/integrations/axios.d.ts +5 -1
  87. package/dist/integrations/axios.d.ts.map +1 -1
  88. package/dist/integrations/axios.js +146 -34
  89. package/dist/integrations/axios.js.map +1 -1
  90. package/dist/integrations/fetch.d.ts +6 -4
  91. package/dist/integrations/fetch.d.ts.map +1 -1
  92. package/dist/integrations/fetch.js +105 -26
  93. package/dist/integrations/fetch.js.map +1 -1
  94. package/dist/integrations/http-report.d.ts +27 -0
  95. package/dist/integrations/http-report.d.ts.map +1 -0
  96. package/dist/integrations/http-report.js +123 -0
  97. package/dist/integrations/http-report.js.map +1 -0
  98. package/dist/integrations/jquery/index.d.ts +10 -6
  99. package/dist/integrations/jquery/index.d.ts.map +1 -1
  100. package/dist/integrations/jquery/index.js +28 -9
  101. package/dist/integrations/jquery/index.js.map +1 -1
  102. package/dist/integrations/jquery/instrument.d.ts +14 -5
  103. package/dist/integrations/jquery/instrument.d.ts.map +1 -1
  104. package/dist/integrations/jquery/instrument.js +111 -29
  105. package/dist/integrations/jquery/instrument.js.map +1 -1
  106. package/dist/integrations/react/context.d.ts +4 -1
  107. package/dist/integrations/react/context.d.ts.map +1 -1
  108. package/dist/integrations/react/context.js +4 -1
  109. package/dist/integrations/react/context.js.map +1 -1
  110. package/dist/integrations/react/scope.d.ts +14 -3
  111. package/dist/integrations/react/scope.d.ts.map +1 -1
  112. package/dist/integrations/react/scope.js +48 -9
  113. package/dist/integrations/react/scope.js.map +1 -1
  114. package/dist/integrations/react/stable-config-keys.d.ts +6 -0
  115. package/dist/integrations/react/stable-config-keys.d.ts.map +1 -0
  116. package/dist/integrations/react/stable-config-keys.js +21 -0
  117. package/dist/integrations/react/stable-config-keys.js.map +1 -0
  118. package/dist/integrations/react/use-journey-step.d.ts +11 -0
  119. package/dist/integrations/react/use-journey-step.d.ts.map +1 -0
  120. package/dist/integrations/react/use-journey-step.js +19 -0
  121. package/dist/integrations/react/use-journey-step.js.map +1 -0
  122. package/dist/integrations/request-key.d.ts +8 -3
  123. package/dist/integrations/request-key.d.ts.map +1 -1
  124. package/dist/integrations/request-key.js +10 -9
  125. package/dist/integrations/request-key.js.map +1 -1
  126. package/dist/integrations/soft-skip.d.ts +7 -0
  127. package/dist/integrations/soft-skip.d.ts.map +1 -0
  128. package/dist/integrations/soft-skip.js +30 -0
  129. package/dist/integrations/soft-skip.js.map +1 -0
  130. package/dist/sinks/console.d.ts +11 -0
  131. package/dist/sinks/console.d.ts.map +1 -0
  132. package/dist/sinks/console.js +19 -0
  133. package/dist/sinks/console.js.map +1 -0
  134. package/dist/sinks/datadog.d.ts +12 -1
  135. package/dist/sinks/datadog.d.ts.map +1 -1
  136. package/dist/sinks/datadog.js +42 -25
  137. package/dist/sinks/datadog.js.map +1 -1
  138. package/package.json +2 -2
  139. package/src/{__mocks__ → __test-utils__}/test-runtime.ts +15 -4
  140. package/src/__tests__/config.test.ts +158 -42
  141. package/src/__tests__/{ambient.test.ts → core/ambient.test.ts} +23 -16
  142. package/src/__tests__/{registry.test.ts → core/api.test.ts} +35 -30
  143. package/src/__tests__/{define-journey.test.ts → core/define-journey.test.ts} +33 -15
  144. package/src/__tests__/{requests.test.ts → core/requests.test.ts} +61 -39
  145. package/src/__tests__/{runtime.test.ts → core/runtime.test.ts} +84 -37
  146. package/src/__tests__/core/sanitize.test.ts +69 -0
  147. package/src/__tests__/{step.test.ts → core/step.test.ts} +146 -52
  148. package/src/__tests__/{timeouts.test.ts → core/timeouts.test.ts} +83 -13
  149. package/src/__tests__/global.test.ts +154 -0
  150. package/src/__tests__/hardening.test.ts +613 -0
  151. package/src/__tests__/integrations/axios.test.ts +616 -0
  152. package/src/__tests__/{context.test.tsx → integrations/context.test.tsx} +1 -1
  153. package/src/__tests__/{expose-app-journey.test.ts → integrations/expose-app-journey.test.ts} +11 -5
  154. package/src/__tests__/{fetch.test.ts → integrations/fetch.test.ts} +159 -25
  155. package/src/__tests__/integrations/host-mfe.test.ts +548 -0
  156. package/src/__tests__/integrations/jquery.test.ts +539 -0
  157. package/src/__tests__/{request-key.test.ts → integrations/request-key.test.ts} +1 -1
  158. package/src/__tests__/integrations/scope.test.tsx +286 -0
  159. package/src/__tests__/integrations/use-journey-step.test.tsx +43 -0
  160. package/src/__tests__/sinks/console.test.ts +103 -0
  161. package/src/__tests__/{datadog.test.ts → sinks/datadog.test.ts} +109 -5
  162. package/src/__tests__/{sinks.test.ts → sinks/sinks.test.ts} +13 -12
  163. package/src/config.ts +173 -41
  164. package/src/core/abort-error.ts +24 -0
  165. package/src/core/api.ts +159 -0
  166. package/src/{endpoint-policy.ts → core/endpoint-policy.ts} +46 -4
  167. package/src/core/index.ts +16 -17
  168. package/src/core/limits.ts +73 -0
  169. package/src/core/request-policy.ts +66 -0
  170. package/src/core/runtime.ts +560 -137
  171. package/src/core/sanitize.ts +177 -0
  172. package/src/core/step-tag.ts +90 -11
  173. package/src/core/types.ts +82 -26
  174. package/src/global.ts +466 -0
  175. package/src/index.ts +31 -18
  176. package/src/integrations/axios.ts +183 -45
  177. package/src/integrations/fetch.ts +127 -41
  178. package/src/integrations/http-report.ts +184 -0
  179. package/src/integrations/jquery/index.ts +37 -18
  180. package/src/integrations/jquery/instrument.ts +126 -42
  181. package/src/integrations/react/context.ts +4 -1
  182. package/src/integrations/react/scope.tsx +61 -10
  183. package/src/integrations/react/stable-config-keys.ts +28 -0
  184. package/src/integrations/react/use-journey-step.ts +31 -0
  185. package/src/integrations/request-key.ts +18 -10
  186. package/src/integrations/soft-skip.ts +35 -0
  187. package/src/sinks/console.ts +21 -0
  188. package/src/sinks/datadog.ts +52 -33
  189. package/dist/__mocks__/test-runtime.d.ts.map +0 -1
  190. package/dist/__tests__/ambient.test.d.ts.map +0 -1
  191. package/dist/__tests__/axios.test.d.ts.map +0 -1
  192. package/dist/__tests__/context.test.d.ts.map +0 -1
  193. package/dist/__tests__/datadog.test.d.ts.map +0 -1
  194. package/dist/__tests__/define-journey.test.d.ts.map +0 -1
  195. package/dist/__tests__/expose-app-journey.test.d.ts.map +0 -1
  196. package/dist/__tests__/fetch.test.d.ts.map +0 -1
  197. package/dist/__tests__/jquery.test.d.ts.map +0 -1
  198. package/dist/__tests__/registry.test.d.ts +0 -2
  199. package/dist/__tests__/registry.test.d.ts.map +0 -1
  200. package/dist/__tests__/request-key.test.d.ts.map +0 -1
  201. package/dist/__tests__/requests.test.d.ts.map +0 -1
  202. package/dist/__tests__/runtime.test.d.ts.map +0 -1
  203. package/dist/__tests__/scope.test.d.ts.map +0 -1
  204. package/dist/__tests__/sinks.test.d.ts.map +0 -1
  205. package/dist/__tests__/step.test.d.ts.map +0 -1
  206. package/dist/__tests__/timeouts.test.d.ts.map +0 -1
  207. package/dist/core/registry.d.ts +0 -50
  208. package/dist/core/registry.d.ts.map +0 -1
  209. package/dist/core/registry.js +0 -102
  210. package/dist/core/registry.js.map +0 -1
  211. package/dist/endpoint-policy.d.ts.map +0 -1
  212. package/dist/endpoint-policy.js +0 -39
  213. package/dist/endpoint-policy.js.map +0 -1
  214. package/src/__tests__/axios.test.ts +0 -365
  215. package/src/__tests__/jquery.test.ts +0 -327
  216. package/src/__tests__/scope.test.tsx +0 -128
  217. package/src/core/registry.ts +0 -162
  218. /package/dist/{__mocks__ → __test-utils__}/test-runtime.d.ts +0 -0
  219. /package/dist/__tests__/{ambient.test.d.ts → core/ambient.test.d.ts} +0 -0
  220. /package/dist/__tests__/{define-journey.test.d.ts → core/define-journey.test.d.ts} +0 -0
  221. /package/dist/__tests__/{requests.test.d.ts → core/requests.test.d.ts} +0 -0
  222. /package/dist/__tests__/{runtime.test.d.ts → core/runtime.test.d.ts} +0 -0
  223. /package/dist/__tests__/{step.test.d.ts → core/step.test.d.ts} +0 -0
  224. /package/dist/__tests__/{timeouts.test.d.ts → core/timeouts.test.d.ts} +0 -0
  225. /package/dist/__tests__/{axios.test.d.ts → integrations/axios.test.d.ts} +0 -0
  226. /package/dist/__tests__/{context.test.d.ts → integrations/context.test.d.ts} +0 -0
  227. /package/dist/__tests__/{expose-app-journey.test.d.ts → integrations/expose-app-journey.test.d.ts} +0 -0
  228. /package/dist/__tests__/{fetch.test.d.ts → integrations/fetch.test.d.ts} +0 -0
  229. /package/dist/__tests__/{jquery.test.d.ts → integrations/jquery.test.d.ts} +0 -0
  230. /package/dist/__tests__/{request-key.test.d.ts → integrations/request-key.test.d.ts} +0 -0
  231. /package/dist/__tests__/{scope.test.d.ts → integrations/scope.test.d.ts} +0 -0
  232. /package/dist/__tests__/{datadog.test.d.ts → sinks/datadog.test.d.ts} +0 -0
  233. /package/dist/__tests__/{sinks.test.d.ts → sinks/sinks.test.d.ts} +0 -0
@@ -0,0 +1,19 @@
1
+ import { useCallback } from 'react';
2
+ import { journeyStep } from '../../core';
3
+ import { useOptionalJourneyName } from './context';
4
+ /**
5
+ * Run a step on the active `<JourneyScope>` journey, an explicit name, or a handle.
6
+ * A handle auto-starts when the journey is not open; a bare name does not.
7
+ *
8
+ * @example
9
+ * const runStep = useJourneyStep();
10
+ * await runStep('load', async step => { await api.get('/x', { stamp: step.stamp() }); });
11
+ */ export function useJourneyStep(journey) {
12
+ const fromScope = useOptionalJourneyName();
13
+ const resolved = journey !== undefined ? journey : fromScope;
14
+ return useCallback((stepName, fn, opts)=>journeyStep(resolved, stepName, fn, opts), [
15
+ resolved
16
+ ]);
17
+ }
18
+
19
+ //# sourceMappingURL=use-journey-step.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/integrations/react/use-journey-step.ts"],"sourcesContent":["import { useCallback } from 'react';\n\nimport {\n journeyStep,\n type JourneyHandle,\n type JourneyStepOptions,\n type StepHandle,\n} from '../../core';\nimport { useOptionalJourneyName } from './context';\n\n/**\n * Run a step on the active `<JourneyScope>` journey, an explicit name, or a handle.\n * A handle auto-starts when the journey is not open; a bare name does not.\n *\n * @example\n * const runStep = useJourneyStep();\n * await runStep('load', async step => { await api.get('/x', { stamp: step.stamp() }); });\n */\nexport function useJourneyStep(journey?: string | JourneyHandle | null) {\n const fromScope = useOptionalJourneyName();\n const resolved = journey !== undefined ? journey : fromScope;\n\n return useCallback(\n <T>(\n stepName: string,\n fn: (step: StepHandle) => T | Promise<T>,\n opts?: JourneyStepOptions\n ): Promise<T> => journeyStep(resolved, stepName, fn, opts),\n [resolved]\n );\n}\n"],"names":["useCallback","journeyStep","useOptionalJourneyName","useJourneyStep","journey","fromScope","resolved","undefined","stepName","fn","opts"],"mappings":"AAAA,SAASA,WAAW,QAAQ,QAAQ;AAEpC,SACIC,WAAW,QAIR,aAAa;AACpB,SAASC,sBAAsB,QAAQ,YAAY;AAEnD;;;;;;;CAOC,GACD,OAAO,SAASC,eAAeC,OAAuC;IAClE,MAAMC,YAAYH;IAClB,MAAMI,WAAWF,YAAYG,YAAYH,UAAUC;IAEnD,OAAOL,YACH,CACIQ,UACAC,IACAC,OACaT,YAAYK,UAAUE,UAAUC,IAAIC,OACrD;QAACJ;KAAS;AAElB"}
@@ -2,12 +2,17 @@
2
2
  * Timing metadata stamped onto a request config so the response handler can attribute
3
3
  * and measure the round trip. Intersect with your transport's config type.
4
4
  *
5
- * `journeyStep` is a JourneyStepTag (from `step.tag()` or ambient instrumentation)
6
- * or, historically, a raw StepRecord. Adapters unwrap via `resolveJourneyStep`.
5
+ * `stamp` is a JourneyStepStamp from `step.stamp()` or ambient instrumentation.
7
6
  */
8
7
  export interface JourneyTimedMeta {
9
8
  journeyStart?: number;
10
- journeyStep?: unknown;
9
+ stamp?: unknown;
10
+ /** Skip attribution for this request (no ambient stamp, no scoring). */
11
+ ignore?: boolean;
12
+ /** Per-request override for aborted/cancelled HTTP policy. */
13
+ httpAbortedRequests?: 'continue' | 'bad' | 'exclude';
14
+ /** Per-request override for 4xx HTTP policy. */
15
+ httpClientErrorRequests?: 'continue' | 'bad' | 'exclude';
11
16
  }
12
17
  /**
13
18
  * Endpoint key for timeout / ignore lookup: PATH for same-origin (vs instance baseURL),
@@ -1 +1 @@
1
- {"version":3,"file":"request-key.d.ts","sourceRoot":"","sources":["../../src/integrations/request-key.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,WAAW,gBAAgB;IAC7B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,OAAO,CAAC;CACzB;AAUD;;;GAGG;AACH,wBAAgB,UAAU,CACtB,GAAG,EAAE,MAAM,GAAG,SAAS,EACvB,aAAa,EAAE,MAAM,GAAG,SAAS,EACjC,eAAe,EAAE,MAAM,GAAG,SAAS,GACpC,MAAM,CAiBR"}
1
+ {"version":3,"file":"request-key.d.ts","sourceRoot":"","sources":["../../src/integrations/request-key.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC7B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,wEAAwE;IACxE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,8DAA8D;IAC9D,mBAAmB,CAAC,EAAE,UAAU,GAAG,KAAK,GAAG,SAAS,CAAC;IACrD,gDAAgD;IAChD,uBAAuB,CAAC,EAAE,UAAU,GAAG,KAAK,GAAG,SAAS,CAAC;CAC5D;AAmBD;;;GAGG;AACH,wBAAgB,UAAU,CACtB,GAAG,EAAE,MAAM,GAAG,SAAS,EACvB,aAAa,EAAE,MAAM,GAAG,SAAS,EACjC,eAAe,EAAE,MAAM,GAAG,SAAS,GACpC,MAAM,CAWR"}
@@ -2,8 +2,7 @@
2
2
  * Timing metadata stamped onto a request config so the response handler can attribute
3
3
  * and measure the round trip. Intersect with your transport's config type.
4
4
  *
5
- * `journeyStep` is a JourneyStepTag (from `step.tag()` or ambient instrumentation)
6
- * or, historically, a raw StepRecord. Adapters unwrap via `resolveJourneyStep`.
5
+ * `stamp` is a JourneyStepStamp from `step.stamp()` or ambient instrumentation.
7
6
  */ function pageOrigin() {
8
7
  try {
9
8
  var _ref;
@@ -13,6 +12,14 @@
13
12
  return '';
14
13
  }
15
14
  }
15
+ function resolveHomeOrigin(instanceBaseURL, origin) {
16
+ try {
17
+ const homeBase = instanceBaseURL !== null && instanceBaseURL !== void 0 ? instanceBaseURL : origin;
18
+ return new URL(homeBase || 'http://localhost').origin;
19
+ } catch (unused) {
20
+ return origin;
21
+ }
22
+ }
16
23
  /**
17
24
  * Endpoint key for timeout / ignore lookup: PATH for same-origin (vs instance baseURL),
18
25
  * or "host/path" for cross-domain.
@@ -26,13 +33,7 @@
26
33
  } catch (unused) {
27
34
  return url !== null && url !== void 0 ? url : '';
28
35
  }
29
- let homeOrigin;
30
- try {
31
- const homeBase = instanceBaseURL !== null && instanceBaseURL !== void 0 ? instanceBaseURL : origin;
32
- homeOrigin = new URL(homeBase || 'http://localhost').origin;
33
- } catch (unused) {
34
- homeOrigin = origin;
35
- }
36
+ const homeOrigin = resolveHomeOrigin(instanceBaseURL, origin);
36
37
  return abs.origin === homeOrigin ? abs.pathname : abs.host + abs.pathname;
37
38
  }
38
39
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/integrations/request-key.ts"],"sourcesContent":["/**\n * Timing metadata stamped onto a request config so the response handler can attribute\n * and measure the round trip. Intersect with your transport's config type.\n *\n * `journeyStep` is a JourneyStepTag (from `step.tag()` or ambient instrumentation)\n * or, historically, a raw StepRecord. Adapters unwrap via `resolveJourneyStep`.\n */\nexport interface JourneyTimedMeta {\n journeyStart?: number;\n journeyStep?: unknown;\n}\n\nfunction pageOrigin(): string {\n try {\n return globalThis.location?.origin ?? '';\n } catch {\n return '';\n }\n}\n\n/**\n * Endpoint key for timeout / ignore lookup: PATH for same-origin (vs instance baseURL),\n * or \"host/path\" for cross-domain.\n */\nexport function requestKey(\n url: string | undefined,\n configBaseURL: string | undefined,\n instanceBaseURL: string | undefined\n): string {\n const origin = pageOrigin();\n const base = configBaseURL ?? instanceBaseURL ?? origin;\n let abs: URL;\n try {\n abs = new URL(url ?? '', base || undefined);\n } catch {\n return url ?? '';\n }\n let homeOrigin: string;\n try {\n const homeBase = instanceBaseURL ?? origin;\n homeOrigin = new URL(homeBase || 'http://localhost').origin;\n } catch {\n homeOrigin = origin;\n }\n return abs.origin === homeOrigin ? abs.pathname : abs.host + abs.pathname;\n}\n"],"names":["pageOrigin","globalThis","location","origin","requestKey","url","configBaseURL","instanceBaseURL","base","abs","URL","undefined","homeOrigin","homeBase","pathname","host"],"mappings":"AAAA;;;;;;CAMC,GAMD,SAASA;IACL,IAAI;;YACOC;QAAP,gBAAOA,uBAAAA,WAAWC,QAAQ,cAAnBD,2CAAAA,qBAAqBE,MAAM,uCAAI;IAC1C,EAAE,eAAM;QACJ,OAAO;IACX;AACJ;AAEA;;;CAGC,GACD,OAAO,SAASC,WACZC,GAAuB,EACvBC,aAAiC,EACjCC,eAAmC;QAGtBD;IADb,MAAMH,SAASH;IACf,MAAMQ,QAAOF,OAAAA,0BAAAA,2BAAAA,gBAAiBC,6BAAjBD,kBAAAA,OAAoCH;IACjD,IAAIM;IACJ,IAAI;QACAA,MAAM,IAAIC,IAAIL,gBAAAA,iBAAAA,MAAO,IAAIG,QAAQG;IACrC,EAAE,eAAM;QACJ,OAAON,gBAAAA,iBAAAA,MAAO;IAClB;IACA,IAAIO;IACJ,IAAI;QACA,MAAMC,WAAWN,4BAAAA,6BAAAA,kBAAmBJ;QACpCS,aAAa,IAAIF,IAAIG,YAAY,oBAAoBV,MAAM;IAC/D,EAAE,eAAM;QACJS,aAAaT;IACjB;IACA,OAAOM,IAAIN,MAAM,KAAKS,aAAaH,IAAIK,QAAQ,GAAGL,IAAIM,IAAI,GAAGN,IAAIK,QAAQ;AAC7E"}
1
+ {"version":3,"sources":["../../src/integrations/request-key.ts"],"sourcesContent":["/**\n * Timing metadata stamped onto a request config so the response handler can attribute\n * and measure the round trip. Intersect with your transport's config type.\n *\n * `stamp` is a JourneyStepStamp from `step.stamp()` or ambient instrumentation.\n */\nexport interface JourneyTimedMeta {\n journeyStart?: number;\n stamp?: unknown;\n /** Skip attribution for this request (no ambient stamp, no scoring). */\n ignore?: boolean;\n /** Per-request override for aborted/cancelled HTTP policy. */\n httpAbortedRequests?: 'continue' | 'bad' | 'exclude';\n /** Per-request override for 4xx HTTP policy. */\n httpClientErrorRequests?: 'continue' | 'bad' | 'exclude';\n}\n\nfunction pageOrigin(): string {\n try {\n return globalThis.location?.origin ?? '';\n } catch {\n return '';\n }\n}\n\nfunction resolveHomeOrigin(instanceBaseURL: string | undefined, origin: string): string {\n try {\n const homeBase = instanceBaseURL ?? origin;\n return new URL(homeBase || 'http://localhost').origin;\n } catch {\n return origin;\n }\n}\n\n/**\n * Endpoint key for timeout / ignore lookup: PATH for same-origin (vs instance baseURL),\n * or \"host/path\" for cross-domain.\n */\nexport function requestKey(\n url: string | undefined,\n configBaseURL: string | undefined,\n instanceBaseURL: string | undefined\n): string {\n const origin = pageOrigin();\n const base = configBaseURL ?? instanceBaseURL ?? origin;\n let abs: URL;\n try {\n abs = new URL(url ?? '', base || undefined);\n } catch {\n return url ?? '';\n }\n const homeOrigin = resolveHomeOrigin(instanceBaseURL, origin);\n return abs.origin === homeOrigin ? abs.pathname : abs.host + abs.pathname;\n}\n"],"names":["pageOrigin","globalThis","location","origin","resolveHomeOrigin","instanceBaseURL","homeBase","URL","requestKey","url","configBaseURL","base","abs","undefined","homeOrigin","pathname","host"],"mappings":"AAAA;;;;;CAKC,GAYD,SAASA;IACL,IAAI;;YACOC;QAAP,gBAAOA,uBAAAA,WAAWC,QAAQ,cAAnBD,2CAAAA,qBAAqBE,MAAM,uCAAI;IAC1C,EAAE,eAAM;QACJ,OAAO;IACX;AACJ;AAEA,SAASC,kBAAkBC,eAAmC,EAAEF,MAAc;IAC1E,IAAI;QACA,MAAMG,WAAWD,4BAAAA,6BAAAA,kBAAmBF;QACpC,OAAO,IAAII,IAAID,YAAY,oBAAoBH,MAAM;IACzD,EAAE,eAAM;QACJ,OAAOA;IACX;AACJ;AAEA;;;CAGC,GACD,OAAO,SAASK,WACZC,GAAuB,EACvBC,aAAiC,EACjCL,eAAmC;QAGtBK;IADb,MAAMP,SAASH;IACf,MAAMW,QAAOD,OAAAA,0BAAAA,2BAAAA,gBAAiBL,6BAAjBK,kBAAAA,OAAoCP;IACjD,IAAIS;IACJ,IAAI;QACAA,MAAM,IAAIL,IAAIE,gBAAAA,iBAAAA,MAAO,IAAIE,QAAQE;IACrC,EAAE,eAAM;QACJ,OAAOJ,gBAAAA,iBAAAA,MAAO;IAClB;IACA,MAAMK,aAAaV,kBAAkBC,iBAAiBF;IACtD,OAAOS,IAAIT,MAAM,KAAKW,aAAaF,IAAIG,QAAQ,GAAGH,IAAII,IAAI,GAAGJ,IAAIG,QAAQ;AAC7E"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Soft-accept an instrumentation target. Never throws.
3
+ * - `null` / `undefined` → `console.warn` and return `undefined`
4
+ * - fails `isValid` → `console.error` and return `undefined`
5
+ */
6
+ export declare function acceptInstrumentTarget<T>(kind: string, value: unknown, isValid: (value: unknown) => value is T): T | undefined;
7
+ //# sourceMappingURL=soft-skip.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"soft-skip.d.ts","sourceRoot":"","sources":["../../src/integrations/soft-skip.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,EACpC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,KAAK,IAAI,CAAC,GACxC,CAAC,GAAG,SAAS,CAcf"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Soft-accept an instrumentation target. Never throws.
3
+ * - `null` / `undefined` → `console.warn` and return `undefined`
4
+ * - fails `isValid` → `console.error` and return `undefined`
5
+ */ export function acceptInstrumentTarget(kind, value, isValid) {
6
+ if (value == null) {
7
+ // eslint-disable-next-line no-console -- soft-skip missing host wiring
8
+ console.warn(`[journey] instrument${kind}: skipped — missing`);
9
+ return undefined;
10
+ }
11
+ if (!isValid(value)) {
12
+ // eslint-disable-next-line no-console -- soft-skip invalid host wiring
13
+ console.error(`[journey] instrument${kind}: skipped — invalid shape (${describeTarget(value)})`);
14
+ return undefined;
15
+ }
16
+ return value;
17
+ }
18
+ function describeTarget(value) {
19
+ const kind = typeof value;
20
+ if (value != null && (kind === 'object' || kind === 'function')) {
21
+ var _value_constructor;
22
+ const name = (_value_constructor = value.constructor) === null || _value_constructor === void 0 ? void 0 : _value_constructor.name;
23
+ if (typeof name === 'string' && name !== '' && name !== 'Object') {
24
+ return `${kind} ${name}`;
25
+ }
26
+ }
27
+ return kind;
28
+ }
29
+
30
+ //# sourceMappingURL=soft-skip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/integrations/soft-skip.ts"],"sourcesContent":["/**\n * Soft-accept an instrumentation target. Never throws.\n * - `null` / `undefined` → `console.warn` and return `undefined`\n * - fails `isValid` → `console.error` and return `undefined`\n */\nexport function acceptInstrumentTarget<T>(\n kind: string,\n value: unknown,\n isValid: (value: unknown) => value is T\n): T | undefined {\n if (value == null) {\n // eslint-disable-next-line no-console -- soft-skip missing host wiring\n console.warn(`[journey] instrument${kind}: skipped — missing`);\n return undefined;\n }\n if (!isValid(value)) {\n // eslint-disable-next-line no-console -- soft-skip invalid host wiring\n console.error(\n `[journey] instrument${kind}: skipped — invalid shape (${describeTarget(value)})`\n );\n return undefined;\n }\n return value;\n}\n\nfunction describeTarget(value: unknown): string {\n const kind = typeof value;\n if (value != null && (kind === 'object' || kind === 'function')) {\n const name = (value as { constructor?: { name?: string } }).constructor?.name;\n if (typeof name === 'string' && name !== '' && name !== 'Object') {\n return `${kind} ${name}`;\n }\n }\n return kind;\n}\n"],"names":["acceptInstrumentTarget","kind","value","isValid","console","warn","undefined","error","describeTarget","name"],"mappings":"AAAA;;;;CAIC,GACD,OAAO,SAASA,uBACZC,IAAY,EACZC,KAAc,EACdC,OAAuC;IAEvC,IAAID,SAAS,MAAM;QACf,uEAAuE;QACvEE,QAAQC,IAAI,CAAC,CAAC,oBAAoB,EAAEJ,KAAK,mBAAmB,CAAC;QAC7D,OAAOK;IACX;IACA,IAAI,CAACH,QAAQD,QAAQ;QACjB,uEAAuE;QACvEE,QAAQG,KAAK,CACT,CAAC,oBAAoB,EAAEN,KAAK,2BAA2B,EAAEO,eAAeN,OAAO,CAAC,CAAC;QAErF,OAAOI;IACX;IACA,OAAOJ;AACX;AAEA,SAASM,eAAeN,KAAc;IAClC,MAAMD,OAAO,OAAOC;IACpB,IAAIA,SAAS,QAASD,CAAAA,SAAS,YAAYA,SAAS,UAAS,GAAI;YAChD;QAAb,MAAMQ,QAAO,qBAAA,AAACP,MAA8C,WAAW,cAA1D,yCAAA,mBAA4DO,IAAI;QAC7E,IAAI,OAAOA,SAAS,YAAYA,SAAS,MAAMA,SAAS,UAAU;YAC9D,OAAO,GAAGR,KAAK,CAAC,EAAEQ,MAAM;QAC5B;IACJ;IACA,OAAOR;AACX"}
@@ -0,0 +1,11 @@
1
+ import type { JourneyEvent } from '../core/types';
2
+ /**
3
+ * Log a terminal journey to the browser console when debugging is enabled.
4
+ * No-op unless `__stJourney.enableDebugging()` / `enableJourneyDebugging()` was used
5
+ * (reload after enabling from DevTools).
6
+ *
7
+ * There is no reliable cross-browser API to detect an open DevTools console;
8
+ * use the explicit debug flag instead.
9
+ */
10
+ export declare function sendToConsole(event: JourneyEvent): void;
11
+ //# sourceMappingURL=console.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"console.d.ts","sourceRoot":"","sources":["../../src/sinks/console.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CAQvD"}
@@ -0,0 +1,19 @@
1
+ import { isSanitizedJourneyEvent, sanitizeJourneyEvent } from '../core/sanitize';
2
+ import { isJourneyDebugEnabled } from '../global';
3
+ /**
4
+ * Log a terminal journey to the browser console when debugging is enabled.
5
+ * No-op unless `__stJourney.enableDebugging()` / `enableJourneyDebugging()` was used
6
+ * (reload after enabling from DevTools).
7
+ *
8
+ * There is no reliable cross-browser API to detect an open DevTools console;
9
+ * use the explicit debug flag instead.
10
+ */ export function sendToConsole(event) {
11
+ if (!isJourneyDebugEnabled()) {
12
+ return;
13
+ }
14
+ const j = isSanitizedJourneyEvent(event) ? event.journey : sanitizeJourneyEvent(event).journey;
15
+ // eslint-disable-next-line no-console -- intentional debug sink
16
+ console.debug(`[journey] ${j.name} → ${j.outcome}`, j);
17
+ }
18
+
19
+ //# sourceMappingURL=console.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/sinks/console.ts"],"sourcesContent":["import { isSanitizedJourneyEvent, sanitizeJourneyEvent } from '../core/sanitize';\nimport { isJourneyDebugEnabled } from '../global';\nimport type { JourneyEvent } from '../core/types';\n\n/**\n * Log a terminal journey to the browser console when debugging is enabled.\n * No-op unless `__stJourney.enableDebugging()` / `enableJourneyDebugging()` was used\n * (reload after enabling from DevTools).\n *\n * There is no reliable cross-browser API to detect an open DevTools console;\n * use the explicit debug flag instead.\n */\nexport function sendToConsole(event: JourneyEvent): void {\n if (!isJourneyDebugEnabled()) {\n return;\n }\n\n const j = isSanitizedJourneyEvent(event) ? event.journey : sanitizeJourneyEvent(event).journey;\n // eslint-disable-next-line no-console -- intentional debug sink\n console.debug(`[journey] ${j.name} → ${j.outcome}`, j);\n}\n"],"names":["isSanitizedJourneyEvent","sanitizeJourneyEvent","isJourneyDebugEnabled","sendToConsole","event","j","journey","console","debug","name","outcome"],"mappings":"AAAA,SAASA,uBAAuB,EAAEC,oBAAoB,QAAQ,mBAAmB;AACjF,SAASC,qBAAqB,QAAQ,YAAY;AAGlD;;;;;;;CAOC,GACD,OAAO,SAASC,cAAcC,KAAmB;IAC7C,IAAI,CAACF,yBAAyB;QAC1B;IACJ;IAEA,MAAMG,IAAIL,wBAAwBI,SAASA,MAAME,OAAO,GAAGL,qBAAqBG,OAAOE,OAAO;IAC9F,gEAAgE;IAChEC,QAAQC,KAAK,CAAC,CAAC,UAAU,EAAEH,EAAEI,IAAI,CAAC,GAAG,EAAEJ,EAAEK,OAAO,EAAE,EAAEL;AACxD"}
@@ -1,5 +1,16 @@
1
1
  import type { JourneyEvent } from '../core/types';
2
- /** Host-only: publish the initialized RUM instance so MFE bundles share the same session. */
2
+ export { normalizeTagValue } from '../core/sanitize';
3
+ /**
4
+ * Publish a RUM instance for MFE bundles to share — **only needed if
5
+ * `globalThis.DD_RUM` is not set**.
6
+ *
7
+ * Prefer exposing the initialized instance as `globalThis.DD_RUM` (ST host:
8
+ * `datadogGuard`). `sendToDatadog` resolves `DD_RUM` first, then `__stJourney.rum`
9
+ * (this fallback), then the bundle's imported `datadogRum`.
10
+ *
11
+ * Calling `setJourneyRum` while `globalThis.DD_RUM` is already set logs a warning —
12
+ * the call is redundant because `sendToDatadog` prefers `DD_RUM`.
13
+ */
3
14
  export declare function setJourneyRum(rum: unknown): void;
4
15
  /** Ship one terminal journey as a RUM custom action (`user_journey`). */
5
16
  export declare function sendToDatadog(payload: JourneyEvent): void;
@@ -1 +1 @@
1
- {"version":3,"file":"datadog.d.ts","sourceRoot":"","sources":["../../src/sinks/datadog.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAA8B,MAAM,eAAe,CAAC;AAM9E,6FAA6F;AAC7F,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAEhD;AAwCD,yEAAyE;AACzE,wBAAgB,aAAa,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI,CAkBzD"}
1
+ {"version":3,"file":"datadog.d.ts","sourceRoot":"","sources":["../../src/sinks/datadog.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAoB,MAAM,eAAe,CAAC;AAEpE,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAUrD;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAQhD;AA2BD,yEAAyE;AACzE,wBAAgB,aAAa,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI,CA0BzD"}
@@ -1,24 +1,36 @@
1
1
  import { datadogRum } from '@datadog/browser-rum';
2
+ import { isSanitizedJourneyEvent, sanitizeJourneyEvent } from '../core/sanitize';
3
+ import { getJourneyRumFallback, setJourneyRumFallback } from '../global';
4
+ export { normalizeTagValue } from '../core/sanitize';
2
5
  const JOURNEY_ACTION = 'user_journey';
3
- const RUM_GLOBAL_KEY = '__stJourneyRum';
4
- /** Host-only: publish the initialized RUM instance so MFE bundles share the same session. */ export function setJourneyRum(rum) {
5
- globalThis[RUM_GLOBAL_KEY] = rum;
6
+ const DD_RUM_KEY = 'DD_RUM';
7
+ function getDdRum() {
8
+ return globalThis[DD_RUM_KEY];
6
9
  }
7
- function resolveRum() {
8
- const shared = globalThis[RUM_GLOBAL_KEY];
9
- return shared !== null && shared !== void 0 ? shared : datadogRum;
10
- }
11
- // Match Datadog metric-tag value rules so RUM attributes join derived SLO tags.
12
- const MAX_TAG_VALUE_LEN = 200;
13
- function normalizeTagValue(value) {
14
- return value.toLowerCase().replace(/[^a-z0-9_\-:./]/g, '_').replace(/_+/g, '_').slice(0, MAX_TAG_VALUE_LEN).replace(/_+$/, '');
10
+ /**
11
+ * Publish a RUM instance for MFE bundles to share — **only needed if
12
+ * `globalThis.DD_RUM` is not set**.
13
+ *
14
+ * Prefer exposing the initialized instance as `globalThis.DD_RUM` (ST host:
15
+ * `datadogGuard`). `sendToDatadog` resolves `DD_RUM` first, then `__stJourney.rum`
16
+ * (this fallback), then the bundle's imported `datadogRum`.
17
+ *
18
+ * Calling `setJourneyRum` while `globalThis.DD_RUM` is already set logs a warning —
19
+ * the call is redundant because `sendToDatadog` prefers `DD_RUM`.
20
+ */ export function setJourneyRum(rum) {
21
+ if (getDdRum()) {
22
+ // eslint-disable-next-line no-console -- soft-deprecate redundant bridge use
23
+ console.warn('[journey] setJourneyRum() is unnecessary when globalThis.DD_RUM is set — sendToDatadog already prefers DD_RUM');
24
+ }
25
+ setJourneyRumFallback(rum);
15
26
  }
16
- function normalizeTags(tags) {
17
- const out = {};
18
- for (const [key, value] of Object.entries(tags)){
19
- out[key] = typeof value === 'string' ? normalizeTagValue(value) : value;
27
+ function resolveRum() {
28
+ const ddRum = getDdRum();
29
+ if (ddRum) {
30
+ return ddRum;
20
31
  }
21
- return out;
32
+ const shared = getJourneyRumFallback();
33
+ return shared !== null && shared !== void 0 ? shared : datadogRum;
22
34
  }
23
35
  function toDatadogStep(step) {
24
36
  /* eslint-disable @typescript-eslint/naming-convention -- Datadog RUM wire format (snake_case) */ return {
@@ -32,22 +44,27 @@ function toDatadogStep(step) {
32
44
  ...step.httpStatus !== undefined ? {
33
45
  http_status: step.httpStatus
34
46
  } : {},
35
- ...step.attributes ? {
47
+ ...step.attributes && Object.keys(step.attributes).length ? {
36
48
  attributes: step.attributes
37
49
  } : {}
38
50
  };
39
51
  /* eslint-enable @typescript-eslint/naming-convention */ }
40
52
  /** Ship one terminal journey as a RUM custom action (`user_journey`). */ export function sendToDatadog(payload) {
41
- const j = payload.journey;
42
- /* eslint-disable @typescript-eslint/naming-convention -- Datadog RUM wire format (snake_case) */ resolveRum().addAction(JOURNEY_ACTION, {
53
+ const rum = resolveRum();
54
+ // Skip bad/missing host stubs uninit RUM still buffers addAction safely.
55
+ if (typeof rum.addAction !== 'function') {
56
+ return;
57
+ }
58
+ const j = isSanitizedJourneyEvent(payload) ? payload.journey : sanitizeJourneyEvent(payload).journey;
59
+ /* eslint-disable @typescript-eslint/naming-convention -- Datadog RUM wire format (snake_case) */ rum.addAction(JOURNEY_ACTION, {
43
60
  journey: {
44
- name: normalizeTagValue(j.name),
45
- team: normalizeTagValue(j.team),
46
- group: normalizeTagValue(j.group),
47
- service: normalizeTagValue(j.service),
61
+ name: j.name,
62
+ team: j.team,
63
+ group: j.group,
64
+ service: j.service,
48
65
  outcome: j.outcome,
49
66
  ...j.reason ? {
50
- reason: normalizeTagValue(j.reason)
67
+ reason: j.reason
51
68
  } : {},
52
69
  duration_ms: j.durationMs,
53
70
  steps: j.steps.map(toDatadogStep),
@@ -55,7 +72,7 @@ function toDatadogStep(step) {
55
72
  expected: j.expected
56
73
  } : {},
57
74
  ...j.tags ? {
58
- tags: normalizeTags(j.tags)
75
+ tags: j.tags
59
76
  } : {}
60
77
  }
61
78
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/sinks/datadog.ts"],"sourcesContent":["import { datadogRum } from '@datadog/browser-rum';\n\nimport type { JourneyEvent, JourneyStepEvent, TagValue } from '../core/types';\n\nconst JOURNEY_ACTION = 'user_journey';\n\nconst RUM_GLOBAL_KEY = '__stJourneyRum';\n\n/** Host-only: publish the initialized RUM instance so MFE bundles share the same session. */\nexport function setJourneyRum(rum: unknown): void {\n (globalThis as Record<string, unknown>)[RUM_GLOBAL_KEY] = rum;\n}\n\nfunction resolveRum(): typeof datadogRum {\n const shared = (globalThis as Record<string, unknown>)[RUM_GLOBAL_KEY];\n return (shared as typeof datadogRum | undefined) ?? datadogRum;\n}\n\n// Match Datadog metric-tag value rules so RUM attributes join derived SLO tags.\nconst MAX_TAG_VALUE_LEN = 200;\nfunction normalizeTagValue(value: string): string {\n return value\n .toLowerCase()\n .replace(/[^a-z0-9_\\-:./]/g, '_')\n .replace(/_+/g, '_')\n .slice(0, MAX_TAG_VALUE_LEN)\n .replace(/_+$/, '');\n}\n\nfunction normalizeTags(tags: Record<string, TagValue>): Record<string, TagValue> {\n const out: Record<string, TagValue> = {};\n for (const [key, value] of Object.entries(tags)) {\n out[key] = typeof value === 'string' ? normalizeTagValue(value) : value;\n }\n return out;\n}\n\nfunction toDatadogStep(step: JourneyStepEvent) {\n /* eslint-disable @typescript-eslint/naming-convention -- Datadog RUM wire format (snake_case) */\n return {\n name: step.name,\n start_ms: step.startMs,\n duration_ms: step.durationMs,\n outcome: step.outcome,\n ...(step.reason ? { reason: step.reason } : {}),\n ...(step.httpStatus !== undefined ? { http_status: step.httpStatus } : {}),\n ...(step.attributes ? { attributes: step.attributes } : {}),\n };\n /* eslint-enable @typescript-eslint/naming-convention */\n}\n\n/** Ship one terminal journey as a RUM custom action (`user_journey`). */\nexport function sendToDatadog(payload: JourneyEvent): void {\n const j = payload.journey;\n /* eslint-disable @typescript-eslint/naming-convention -- Datadog RUM wire format (snake_case) */\n resolveRum().addAction(JOURNEY_ACTION, {\n journey: {\n name: normalizeTagValue(j.name),\n team: normalizeTagValue(j.team),\n group: normalizeTagValue(j.group),\n service: normalizeTagValue(j.service),\n outcome: j.outcome,\n ...(j.reason ? { reason: normalizeTagValue(j.reason) } : {}),\n duration_ms: j.durationMs,\n steps: j.steps.map(toDatadogStep),\n ...(j.expected ? { expected: j.expected } : {}),\n ...(j.tags ? { tags: normalizeTags(j.tags) } : {}),\n },\n });\n /* eslint-enable @typescript-eslint/naming-convention */\n}\n"],"names":["datadogRum","JOURNEY_ACTION","RUM_GLOBAL_KEY","setJourneyRum","rum","globalThis","resolveRum","shared","MAX_TAG_VALUE_LEN","normalizeTagValue","value","toLowerCase","replace","slice","normalizeTags","tags","out","key","Object","entries","toDatadogStep","step","name","start_ms","startMs","duration_ms","durationMs","outcome","reason","httpStatus","undefined","http_status","attributes","sendToDatadog","payload","j","journey","addAction","team","group","service","steps","map","expected"],"mappings":"AAAA,SAASA,UAAU,QAAQ,uBAAuB;AAIlD,MAAMC,iBAAiB;AAEvB,MAAMC,iBAAiB;AAEvB,2FAA2F,GAC3F,OAAO,SAASC,cAAcC,GAAY;IACrCC,UAAsC,CAACH,eAAe,GAAGE;AAC9D;AAEA,SAASE;IACL,MAAMC,SAAS,AAACF,UAAsC,CAACH,eAAe;IACtE,OAAQK,mBAAAA,oBAAAA,SAA4CP;AACxD;AAEA,gFAAgF;AAChF,MAAMQ,oBAAoB;AAC1B,SAASC,kBAAkBC,KAAa;IACpC,OAAOA,MACFC,WAAW,GACXC,OAAO,CAAC,oBAAoB,KAC5BA,OAAO,CAAC,OAAO,KACfC,KAAK,CAAC,GAAGL,mBACTI,OAAO,CAAC,OAAO;AACxB;AAEA,SAASE,cAAcC,IAA8B;IACjD,MAAMC,MAAgC,CAAC;IACvC,KAAK,MAAM,CAACC,KAAKP,MAAM,IAAIQ,OAAOC,OAAO,CAACJ,MAAO;QAC7CC,GAAG,CAACC,IAAI,GAAG,OAAOP,UAAU,WAAWD,kBAAkBC,SAASA;IACtE;IACA,OAAOM;AACX;AAEA,SAASI,cAAcC,IAAsB;IACzC,+FAA+F,GAC/F,OAAO;QACHC,MAAMD,KAAKC,IAAI;QACfC,UAAUF,KAAKG,OAAO;QACtBC,aAAaJ,KAAKK,UAAU;QAC5BC,SAASN,KAAKM,OAAO;QACrB,GAAIN,KAAKO,MAAM,GAAG;YAAEA,QAAQP,KAAKO,MAAM;QAAC,IAAI,CAAC,CAAC;QAC9C,GAAIP,KAAKQ,UAAU,KAAKC,YAAY;YAAEC,aAAaV,KAAKQ,UAAU;QAAC,IAAI,CAAC,CAAC;QACzE,GAAIR,KAAKW,UAAU,GAAG;YAAEA,YAAYX,KAAKW,UAAU;QAAC,IAAI,CAAC,CAAC;IAC9D;AACA,sDAAsD,GAC1D;AAEA,uEAAuE,GACvE,OAAO,SAASC,cAAcC,OAAqB;IAC/C,MAAMC,IAAID,QAAQE,OAAO;IACzB,+FAA+F,GAC/F9B,aAAa+B,SAAS,CAACpC,gBAAgB;QACnCmC,SAAS;YACLd,MAAMb,kBAAkB0B,EAAEb,IAAI;YAC9BgB,MAAM7B,kBAAkB0B,EAAEG,IAAI;YAC9BC,OAAO9B,kBAAkB0B,EAAEI,KAAK;YAChCC,SAAS/B,kBAAkB0B,EAAEK,OAAO;YACpCb,SAASQ,EAAER,OAAO;YAClB,GAAIQ,EAAEP,MAAM,GAAG;gBAAEA,QAAQnB,kBAAkB0B,EAAEP,MAAM;YAAE,IAAI,CAAC,CAAC;YAC3DH,aAAaU,EAAET,UAAU;YACzBe,OAAON,EAAEM,KAAK,CAACC,GAAG,CAACtB;YACnB,GAAIe,EAAEQ,QAAQ,GAAG;gBAAEA,UAAUR,EAAEQ,QAAQ;YAAC,IAAI,CAAC,CAAC;YAC9C,GAAIR,EAAEpB,IAAI,GAAG;gBAAEA,MAAMD,cAAcqB,EAAEpB,IAAI;YAAE,IAAI,CAAC,CAAC;QACrD;IACJ;AACA,sDAAsD,GAC1D"}
1
+ {"version":3,"sources":["../../src/sinks/datadog.ts"],"sourcesContent":["import { datadogRum } from '@datadog/browser-rum';\n\nimport { isSanitizedJourneyEvent, sanitizeJourneyEvent } from '../core/sanitize';\nimport { getJourneyRumFallback, setJourneyRumFallback } from '../global';\nimport type { JourneyEvent, JourneyStepEvent } from '../core/types';\n\nexport { normalizeTagValue } from '../core/sanitize';\n\nconst JOURNEY_ACTION = 'user_journey';\n\nconst DD_RUM_KEY = 'DD_RUM';\n\nfunction getDdRum(): typeof datadogRum | undefined {\n return (globalThis as Record<string, unknown>)[DD_RUM_KEY] as typeof datadogRum | undefined;\n}\n\n/**\n * Publish a RUM instance for MFE bundles to share — **only needed if\n * `globalThis.DD_RUM` is not set**.\n *\n * Prefer exposing the initialized instance as `globalThis.DD_RUM` (ST host:\n * `datadogGuard`). `sendToDatadog` resolves `DD_RUM` first, then `__stJourney.rum`\n * (this fallback), then the bundle's imported `datadogRum`.\n *\n * Calling `setJourneyRum` while `globalThis.DD_RUM` is already set logs a warning —\n * the call is redundant because `sendToDatadog` prefers `DD_RUM`.\n */\nexport function setJourneyRum(rum: unknown): void {\n if (getDdRum()) {\n // eslint-disable-next-line no-console -- soft-deprecate redundant bridge use\n console.warn(\n '[journey] setJourneyRum() is unnecessary when globalThis.DD_RUM is set — sendToDatadog already prefers DD_RUM'\n );\n }\n setJourneyRumFallback(rum);\n}\n\nfunction resolveRum(): typeof datadogRum {\n const ddRum = getDdRum();\n if (ddRum) {\n return ddRum;\n }\n const shared = getJourneyRumFallback();\n return (shared as typeof datadogRum | undefined) ?? datadogRum;\n}\n\nfunction toDatadogStep(step: JourneyStepEvent) {\n /* eslint-disable @typescript-eslint/naming-convention -- Datadog RUM wire format (snake_case) */\n return {\n name: step.name,\n start_ms: step.startMs,\n duration_ms: step.durationMs,\n outcome: step.outcome,\n ...(step.reason ? { reason: step.reason } : {}),\n ...(step.httpStatus !== undefined ? { http_status: step.httpStatus } : {}),\n ...(step.attributes && Object.keys(step.attributes).length\n ? { attributes: step.attributes }\n : {}),\n };\n /* eslint-enable @typescript-eslint/naming-convention */\n}\n\n/** Ship one terminal journey as a RUM custom action (`user_journey`). */\nexport function sendToDatadog(payload: JourneyEvent): void {\n const rum = resolveRum();\n // Skip bad/missing host stubs — uninit RUM still buffers addAction safely.\n if (typeof rum.addAction !== 'function') {\n return;\n }\n\n const j = isSanitizedJourneyEvent(payload)\n ? payload.journey\n : sanitizeJourneyEvent(payload).journey;\n /* eslint-disable @typescript-eslint/naming-convention -- Datadog RUM wire format (snake_case) */\n rum.addAction(JOURNEY_ACTION, {\n journey: {\n name: j.name,\n team: j.team,\n group: j.group,\n service: j.service,\n outcome: j.outcome,\n ...(j.reason ? { reason: j.reason } : {}),\n duration_ms: j.durationMs,\n steps: j.steps.map(toDatadogStep),\n ...(j.expected ? { expected: j.expected } : {}),\n ...(j.tags ? { tags: j.tags } : {}),\n },\n });\n /* eslint-enable @typescript-eslint/naming-convention */\n}\n"],"names":["datadogRum","isSanitizedJourneyEvent","sanitizeJourneyEvent","getJourneyRumFallback","setJourneyRumFallback","normalizeTagValue","JOURNEY_ACTION","DD_RUM_KEY","getDdRum","globalThis","setJourneyRum","rum","console","warn","resolveRum","ddRum","shared","toDatadogStep","step","name","start_ms","startMs","duration_ms","durationMs","outcome","reason","httpStatus","undefined","http_status","attributes","Object","keys","length","sendToDatadog","payload","addAction","j","journey","team","group","service","steps","map","expected","tags"],"mappings":"AAAA,SAASA,UAAU,QAAQ,uBAAuB;AAElD,SAASC,uBAAuB,EAAEC,oBAAoB,QAAQ,mBAAmB;AACjF,SAASC,qBAAqB,EAAEC,qBAAqB,QAAQ,YAAY;AAGzE,SAASC,iBAAiB,QAAQ,mBAAmB;AAErD,MAAMC,iBAAiB;AAEvB,MAAMC,aAAa;AAEnB,SAASC;IACL,OAAO,AAACC,UAAsC,CAACF,WAAW;AAC9D;AAEA;;;;;;;;;;CAUC,GACD,OAAO,SAASG,cAAcC,GAAY;IACtC,IAAIH,YAAY;QACZ,6EAA6E;QAC7EI,QAAQC,IAAI,CACR;IAER;IACAT,sBAAsBO;AAC1B;AAEA,SAASG;IACL,MAAMC,QAAQP;IACd,IAAIO,OAAO;QACP,OAAOA;IACX;IACA,MAAMC,SAASb;IACf,OAAQa,mBAAAA,oBAAAA,SAA4ChB;AACxD;AAEA,SAASiB,cAAcC,IAAsB;IACzC,+FAA+F,GAC/F,OAAO;QACHC,MAAMD,KAAKC,IAAI;QACfC,UAAUF,KAAKG,OAAO;QACtBC,aAAaJ,KAAKK,UAAU;QAC5BC,SAASN,KAAKM,OAAO;QACrB,GAAIN,KAAKO,MAAM,GAAG;YAAEA,QAAQP,KAAKO,MAAM;QAAC,IAAI,CAAC,CAAC;QAC9C,GAAIP,KAAKQ,UAAU,KAAKC,YAAY;YAAEC,aAAaV,KAAKQ,UAAU;QAAC,IAAI,CAAC,CAAC;QACzE,GAAIR,KAAKW,UAAU,IAAIC,OAAOC,IAAI,CAACb,KAAKW,UAAU,EAAEG,MAAM,GACpD;YAAEH,YAAYX,KAAKW,UAAU;QAAC,IAC9B,CAAC,CAAC;IACZ;AACA,sDAAsD,GAC1D;AAEA,uEAAuE,GACvE,OAAO,SAASI,cAAcC,OAAqB;IAC/C,MAAMvB,MAAMG;IACZ,2EAA2E;IAC3E,IAAI,OAAOH,IAAIwB,SAAS,KAAK,YAAY;QACrC;IACJ;IAEA,MAAMC,IAAInC,wBAAwBiC,WAC5BA,QAAQG,OAAO,GACfnC,qBAAqBgC,SAASG,OAAO;IAC3C,+FAA+F,GAC/F1B,IAAIwB,SAAS,CAAC7B,gBAAgB;QAC1B+B,SAAS;YACLlB,MAAMiB,EAAEjB,IAAI;YACZmB,MAAMF,EAAEE,IAAI;YACZC,OAAOH,EAAEG,KAAK;YACdC,SAASJ,EAAEI,OAAO;YAClBhB,SAASY,EAAEZ,OAAO;YAClB,GAAIY,EAAEX,MAAM,GAAG;gBAAEA,QAAQW,EAAEX,MAAM;YAAC,IAAI,CAAC,CAAC;YACxCH,aAAac,EAAEb,UAAU;YACzBkB,OAAOL,EAAEK,KAAK,CAACC,GAAG,CAACzB;YACnB,GAAImB,EAAEO,QAAQ,GAAG;gBAAEA,UAAUP,EAAEO,QAAQ;YAAC,IAAI,CAAC,CAAC;YAC9C,GAAIP,EAAEQ,IAAI,GAAG;gBAAEA,MAAMR,EAAEQ,IAAI;YAAC,IAAI,CAAC,CAAC;QACtC;IACJ;AACA,sDAAsD,GAC1D"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@servicetitan/journey",
3
- "version": "2.0.0",
3
+ "version": "3.0.0",
4
4
  "description": "Critical user journey monitoring — reports good/bad/excluded verdicts to Datadog RUM as a custom action",
5
5
  "homepage": "https://docs.st.dev/docs/frontend/journey",
6
6
  "repository": {
@@ -41,5 +41,5 @@
41
41
  "cli": {
42
42
  "webpack": false
43
43
  },
44
- "gitHead": "af4dee1e6d65f7b611a03a15771adf5a6fa6f45d"
44
+ "gitHead": "1ebcfc7b65a6b2979cbb89a93d411abe7144ca51"
45
45
  }
@@ -1,6 +1,11 @@
1
- import { resetJourney } from '../core';
1
+ import { resetJourney } from '../core/runtime';
2
+ import { resetSharedPolicies, setJourneyDefaultEnabled } from '../global';
3
+ import { sendToConsole } from '../sinks/console';
2
4
  import { sendToDatadog } from '../sinks/datadog';
3
5
 
6
+ /** Package default sinks installed by `config.ts` bootstrap. */
7
+ const DEFAULT_SINKS = [sendToDatadog, sendToConsole] as const;
8
+
4
9
  /** Standard journey def used across engine suites. */
5
10
  export const baseJourneyDef = {
6
11
  name: 'journey-under-test',
@@ -21,17 +26,23 @@ export function lastJourney(emitMock: jest.Mock) {
21
26
  */
22
27
  export function useJourneyTestRuntime(emitMock: jest.Mock) {
23
28
  beforeEach(() => {
29
+ setJourneyDefaultEnabled(true);
30
+ resetSharedPolicies();
24
31
  resetJourney({
25
32
  sinks: [emitMock],
26
- requestTimeouts: { defaultMs: 4_000, endpoints: [] },
33
+ slowRequests: { defaultMs: 4_000, endpoints: [] },
27
34
  });
28
35
  emitMock.mockClear();
29
36
  });
30
37
 
31
38
  afterEach(() => {
39
+ setJourneyDefaultEnabled(false);
40
+ localStorage.clear();
41
+ sessionStorage.clear();
42
+ resetSharedPolicies();
32
43
  resetJourney({
33
- sinks: [sendToDatadog],
34
- requestTimeouts: { defaultMs: 4_000, endpoints: [] },
44
+ sinks: [...DEFAULT_SINKS],
45
+ slowRequests: { defaultMs: 4_000, endpoints: [] },
35
46
  });
36
47
  });
37
48
  }