@servicetitan/journey 3.0.1 → 4.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.
- package/dist/__tests__/core/persist.test.d.ts +2 -0
- package/dist/__tests__/core/persist.test.d.ts.map +1 -0
- package/dist/core/api.d.ts +13 -1
- package/dist/core/api.d.ts.map +1 -1
- package/dist/core/api.js +14 -0
- package/dist/core/api.js.map +1 -1
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +1 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/persist.d.ts +19 -0
- package/dist/core/persist.d.ts.map +1 -0
- package/dist/core/persist.js +111 -0
- package/dist/core/persist.js.map +1 -0
- package/dist/core/runtime.d.ts +16 -1
- package/dist/core/runtime.d.ts.map +1 -1
- package/dist/core/runtime.js +56 -21
- package/dist/core/runtime.js.map +1 -1
- package/dist/core/types.d.ts +25 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/core/persist.test.ts +496 -0
- package/src/core/api.ts +19 -0
- package/src/core/index.ts +3 -0
- package/src/core/persist.ts +131 -0
- package/src/core/runtime.ts +62 -2
- package/src/core/types.ts +26 -0
- package/src/index.ts +3 -0
package/src/core/runtime.ts
CHANGED
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
sortEndpointsByLongestMatch,
|
|
12
12
|
type SlowRequestConfig,
|
|
13
13
|
} from './endpoint-policy';
|
|
14
|
+
import { deserializeJourneyState, projectJourneyState } from './persist';
|
|
14
15
|
import {
|
|
15
16
|
clampMaxSteps,
|
|
16
17
|
DEFAULT_MAX_STEPS,
|
|
@@ -36,6 +37,7 @@ import {
|
|
|
36
37
|
type JourneyStepOptions,
|
|
37
38
|
type JourneyStepTarget,
|
|
38
39
|
type Outcome,
|
|
40
|
+
type SerializedJourneyState,
|
|
39
41
|
type StepHandle,
|
|
40
42
|
type StepRecord,
|
|
41
43
|
type TagValue,
|
|
@@ -106,7 +108,8 @@ export interface JourneyRuntimeDebugSnapshot {
|
|
|
106
108
|
};
|
|
107
109
|
}
|
|
108
110
|
|
|
109
|
-
|
|
111
|
+
/** @internal Freeze a caller-supplied journey def + tags snapshot. */
|
|
112
|
+
export function freezeJourneyDef(config: JourneyDef, tags: Record<string, TagValue>): JourneyDef {
|
|
110
113
|
const endpoints = sortEndpointsByLongestMatch(config.endpoints);
|
|
111
114
|
return Object.freeze({
|
|
112
115
|
...config,
|
|
@@ -164,6 +167,17 @@ export interface JourneyRuntime {
|
|
|
164
167
|
completeJourneyState(journey: JourneyState, tags?: Record<string, TagValue>): void;
|
|
165
168
|
excludeJourney(journey: JourneyState): void;
|
|
166
169
|
updateOpenJourney(config: JourneyDef): void;
|
|
170
|
+
/**
|
|
171
|
+
* @internal Snapshot an open journey for cross-page transfer. Does NOT
|
|
172
|
+
* close the journey. Returns `null` when no journey is open under `name`.
|
|
173
|
+
*/
|
|
174
|
+
serializeJourneyState(name: string): SerializedJourneyState | null;
|
|
175
|
+
/**
|
|
176
|
+
* @internal Rehydrate a serialized journey onto this runtime. Returns
|
|
177
|
+
* `null` (after emitting a `bad` `journey-timeout` event) when the journey
|
|
178
|
+
* already exhausted its budget in transit.
|
|
179
|
+
*/
|
|
180
|
+
restoreJourney(serialized: SerializedJourneyState, config: JourneyDef): JourneyState | null;
|
|
167
181
|
|
|
168
182
|
activeJourneyStep(): StepRecord | null;
|
|
169
183
|
journeyStep<T>(
|
|
@@ -192,7 +206,8 @@ export interface JourneyRuntime {
|
|
|
192
206
|
reset(options?: JourneyRuntimeOptions): void;
|
|
193
207
|
}
|
|
194
208
|
|
|
195
|
-
|
|
209
|
+
/** @internal Bind the fail/exclude/report hooks for a journey's creating engine. */
|
|
210
|
+
export function bindJourneyEngine(
|
|
196
211
|
api: JourneyRuntime,
|
|
197
212
|
journey: JourneyState,
|
|
198
213
|
shouldIgnoreRequest: (target: JourneyState, key: string) => boolean
|
|
@@ -685,6 +700,51 @@ export function createJourneyRuntime(options: JourneyRuntimeOptions = {}): Journ
|
|
|
685
700
|
armCountdown(journey, remainingMs);
|
|
686
701
|
},
|
|
687
702
|
|
|
703
|
+
serializeJourneyState(name) {
|
|
704
|
+
const journey = journeys.get(name);
|
|
705
|
+
if (!journey || journey.closed) {
|
|
706
|
+
return null;
|
|
707
|
+
}
|
|
708
|
+
return projectJourneyState(journey);
|
|
709
|
+
},
|
|
710
|
+
|
|
711
|
+
restoreJourney(serialized, config) {
|
|
712
|
+
// Refuse double-registration: leave an existing journey under this name in place.
|
|
713
|
+
if (journeys.has(config.name)) {
|
|
714
|
+
return null;
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
const journey = deserializeJourneyState(serialized, config, api, defaultJourneyIdleMs);
|
|
718
|
+
|
|
719
|
+
if (journey.timeoutMs > 0) {
|
|
720
|
+
const elapsedMs = globalThis.performance.now() - journey.startedAt;
|
|
721
|
+
if (elapsedMs >= journey.timeoutMs) {
|
|
722
|
+
// journey not yet in journeys Map — finish() handles unregistered journeys gracefully.
|
|
723
|
+
if (journey.timeoutExplicit) {
|
|
724
|
+
finish(journey, 'bad', 'journey-timeout');
|
|
725
|
+
} else {
|
|
726
|
+
finish(
|
|
727
|
+
journey,
|
|
728
|
+
journey.verdict === 'bad' ? 'bad' : 'excluded',
|
|
729
|
+
'journey-idle-timeout'
|
|
730
|
+
);
|
|
731
|
+
}
|
|
732
|
+
return null;
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
journeys.set(config.name, journey);
|
|
736
|
+
|
|
737
|
+
const remainingMs = journey.timeoutMs - elapsedMs;
|
|
738
|
+
if (remainingMs > 0) {
|
|
739
|
+
armCountdown(journey, remainingMs);
|
|
740
|
+
}
|
|
741
|
+
} else {
|
|
742
|
+
journeys.set(config.name, journey);
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
return journey;
|
|
746
|
+
},
|
|
747
|
+
|
|
688
748
|
activeJourneyStep() {
|
|
689
749
|
if (!api.getAutoAttributeRequests()) {
|
|
690
750
|
return null;
|
package/src/core/types.ts
CHANGED
|
@@ -163,6 +163,32 @@ export interface JourneyStepEvent {
|
|
|
163
163
|
attributes?: Record<string, TagValue>;
|
|
164
164
|
}
|
|
165
165
|
|
|
166
|
+
/**
|
|
167
|
+
* Snapshot of an open journey that can survive a page navigation. Produced by
|
|
168
|
+
* `serializeJourneyState` and rehydrated by `restoreJourney`. Mirrors the
|
|
169
|
+
* `JourneyStepEvent` projection emitted by `finish()`, plus the wall-clock
|
|
170
|
+
* start time, verdict, reason, and tags needed to re-arm the countdown.
|
|
171
|
+
*/
|
|
172
|
+
export interface SerializedJourneyState {
|
|
173
|
+
/** `st_journey_id` tag — cross-page correlation key. Empty string when unset. */
|
|
174
|
+
stJourneyId: string;
|
|
175
|
+
/** Wall-clock epoch (Date.now()) when the journey started. */
|
|
176
|
+
startedAtEpoch: number;
|
|
177
|
+
verdict: 'good' | 'bad';
|
|
178
|
+
reason: string | null;
|
|
179
|
+
steps: {
|
|
180
|
+
name: string;
|
|
181
|
+
/** Offset from the journey start, ms. */
|
|
182
|
+
startMs: number;
|
|
183
|
+
durationMs: number;
|
|
184
|
+
outcome: 'good' | 'bad';
|
|
185
|
+
reason?: string;
|
|
186
|
+
httpStatus?: number;
|
|
187
|
+
attributes?: Record<string, TagValue>;
|
|
188
|
+
}[];
|
|
189
|
+
tags: Record<string, TagValue>;
|
|
190
|
+
}
|
|
191
|
+
|
|
166
192
|
/** Neutral journey event payload (journey-specific fields only; session context is host RUM globals). */
|
|
167
193
|
export interface JourneyEvent {
|
|
168
194
|
journey: {
|
package/src/index.ts
CHANGED
|
@@ -13,6 +13,8 @@ export {
|
|
|
13
13
|
excludeJourney,
|
|
14
14
|
failJourney,
|
|
15
15
|
journeyStep,
|
|
16
|
+
restoreJourney,
|
|
17
|
+
serializeJourneyState,
|
|
16
18
|
setJourneyTags,
|
|
17
19
|
// Custom transport adapters / request attribution.
|
|
18
20
|
singleInFlightJourneyStep,
|
|
@@ -23,6 +25,7 @@ export {
|
|
|
23
25
|
type JourneyNameLike,
|
|
24
26
|
type JourneyStepOptions,
|
|
25
27
|
type JourneyStepTarget,
|
|
28
|
+
type SerializedJourneyState,
|
|
26
29
|
type StepHandle,
|
|
27
30
|
} from './core';
|
|
28
31
|
|