@servicetitan/journey 1.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/README.md +7 -0
- package/dist/__mocks__/test-runtime.d.ts +16 -0
- package/dist/__mocks__/test-runtime.d.ts.map +1 -0
- package/dist/__tests__/ambient.test.d.ts +2 -0
- package/dist/__tests__/ambient.test.d.ts.map +1 -0
- package/dist/__tests__/axios.test.d.ts +2 -0
- package/dist/__tests__/axios.test.d.ts.map +1 -0
- package/dist/__tests__/config.test.d.ts +2 -0
- package/dist/__tests__/config.test.d.ts.map +1 -0
- package/dist/__tests__/context.test.d.ts +2 -0
- package/dist/__tests__/context.test.d.ts.map +1 -0
- package/dist/__tests__/datadog.test.d.ts +2 -0
- package/dist/__tests__/datadog.test.d.ts.map +1 -0
- package/dist/__tests__/define-journey.test.d.ts +2 -0
- package/dist/__tests__/define-journey.test.d.ts.map +1 -0
- package/dist/__tests__/expose-app-journey.test.d.ts +2 -0
- package/dist/__tests__/expose-app-journey.test.d.ts.map +1 -0
- package/dist/__tests__/fetch.test.d.ts +2 -0
- package/dist/__tests__/fetch.test.d.ts.map +1 -0
- package/dist/__tests__/jquery.test.d.ts +2 -0
- package/dist/__tests__/jquery.test.d.ts.map +1 -0
- package/dist/__tests__/registry.test.d.ts +2 -0
- package/dist/__tests__/registry.test.d.ts.map +1 -0
- package/dist/__tests__/request-key.test.d.ts +2 -0
- package/dist/__tests__/request-key.test.d.ts.map +1 -0
- package/dist/__tests__/requests.test.d.ts +2 -0
- package/dist/__tests__/requests.test.d.ts.map +1 -0
- package/dist/__tests__/runtime.test.d.ts +2 -0
- package/dist/__tests__/runtime.test.d.ts.map +1 -0
- package/dist/__tests__/scope.test.d.ts +2 -0
- package/dist/__tests__/scope.test.d.ts.map +1 -0
- package/dist/__tests__/sinks.test.d.ts +2 -0
- package/dist/__tests__/sinks.test.d.ts.map +1 -0
- package/dist/__tests__/step.test.d.ts +2 -0
- package/dist/__tests__/step.test.d.ts.map +1 -0
- package/dist/__tests__/timeouts.test.d.ts +2 -0
- package/dist/__tests__/timeouts.test.d.ts.map +1 -0
- package/dist/config.d.ts +42 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +46 -0
- package/dist/config.js.map +1 -0
- package/dist/core/index.d.ts +6 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +5 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/registry.d.ts +50 -0
- package/dist/core/registry.d.ts.map +1 -0
- package/dist/core/registry.js +102 -0
- package/dist/core/registry.js.map +1 -0
- package/dist/core/runtime.d.ts +51 -0
- package/dist/core/runtime.d.ts.map +1 -0
- package/dist/core/runtime.js +401 -0
- package/dist/core/runtime.js.map +1 -0
- package/dist/core/step-tag.d.ts +16 -0
- package/dist/core/step-tag.d.ts.map +1 -0
- package/dist/core/step-tag.js +35 -0
- package/dist/core/step-tag.js.map +1 -0
- package/dist/core/types.d.ts +143 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +3 -0
- package/dist/core/types.js.map +1 -0
- package/dist/endpoint-policy.d.ts +29 -0
- package/dist/endpoint-policy.d.ts.map +1 -0
- package/dist/endpoint-policy.js +39 -0
- package/dist/endpoint-policy.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/integrations/axios.d.ts +23 -0
- package/dist/integrations/axios.d.ts.map +1 -0
- package/dist/integrations/axios.js +51 -0
- package/dist/integrations/axios.js.map +1 -0
- package/dist/integrations/fetch.d.ts +21 -0
- package/dist/integrations/fetch.d.ts.map +1 -0
- package/dist/integrations/fetch.js +63 -0
- package/dist/integrations/fetch.js.map +1 -0
- package/dist/integrations/jquery/index.d.ts +22 -0
- package/dist/integrations/jquery/index.d.ts.map +1 -0
- package/dist/integrations/jquery/index.js +27 -0
- package/dist/integrations/jquery/index.js.map +1 -0
- package/dist/integrations/jquery/instrument.d.ts +18 -0
- package/dist/integrations/jquery/instrument.d.ts.map +1 -0
- package/dist/integrations/jquery/instrument.js +44 -0
- package/dist/integrations/jquery/instrument.js.map +1 -0
- package/dist/integrations/react/context.d.ts +6 -0
- package/dist/integrations/react/context.d.ts.map +1 -0
- package/dist/integrations/react/context.js +14 -0
- package/dist/integrations/react/context.js.map +1 -0
- package/dist/integrations/react/scope.d.ts +13 -0
- package/dist/integrations/react/scope.d.ts.map +1 -0
- package/dist/integrations/react/scope.js +27 -0
- package/dist/integrations/react/scope.js.map +1 -0
- package/dist/integrations/request-key.d.ts +17 -0
- package/dist/integrations/request-key.d.ts.map +1 -0
- package/dist/integrations/request-key.js +39 -0
- package/dist/integrations/request-key.js.map +1 -0
- package/dist/sinks/datadog.d.ts +6 -0
- package/dist/sinks/datadog.d.ts.map +1 -0
- package/dist/sinks/datadog.js +64 -0
- package/dist/sinks/datadog.js.map +1 -0
- package/package.json +44 -0
- package/src/__mocks__/test-runtime.ts +37 -0
- package/src/__tests__/ambient.test.ts +101 -0
- package/src/__tests__/axios.test.ts +365 -0
- package/src/__tests__/config.test.ts +261 -0
- package/src/__tests__/context.test.tsx +84 -0
- package/src/__tests__/datadog.test.ts +160 -0
- package/src/__tests__/define-journey.test.ts +176 -0
- package/src/__tests__/expose-app-journey.test.ts +149 -0
- package/src/__tests__/fetch.test.ts +264 -0
- package/src/__tests__/jquery.test.ts +327 -0
- package/src/__tests__/registry.test.ts +265 -0
- package/src/__tests__/request-key.test.ts +81 -0
- package/src/__tests__/requests.test.ts +337 -0
- package/src/__tests__/runtime.test.ts +273 -0
- package/src/__tests__/scope.test.tsx +128 -0
- package/src/__tests__/sinks.test.ts +99 -0
- package/src/__tests__/step.test.ts +305 -0
- package/src/__tests__/timeouts.test.ts +226 -0
- package/src/config.ts +87 -0
- package/src/core/index.ts +39 -0
- package/src/core/registry.ts +162 -0
- package/src/core/runtime.ts +489 -0
- package/src/core/step-tag.ts +24 -0
- package/src/core/types.ts +160 -0
- package/src/endpoint-policy.ts +66 -0
- package/src/index.ts +51 -0
- package/src/integrations/axios.ts +85 -0
- package/src/integrations/fetch.ts +97 -0
- package/src/integrations/jquery/index.ts +62 -0
- package/src/integrations/jquery/instrument.ts +84 -0
- package/src/integrations/react/context.ts +17 -0
- package/src/integrations/react/scope.tsx +32 -0
- package/src/integrations/request-key.ts +46 -0
- package/src/sinks/datadog.ts +71 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/core/types.ts"],"sourcesContent":["import type { EndpointPolicy } from '../endpoint-policy';\n\n/** Arbitrary tag values a developer can attach. */\nexport type TagValue = string | number | boolean;\n\n/** Config for one journey — supplied by the caller (typically `<JourneyScope>` props). */\nexport interface JourneyDef {\n /** Journey name — lifecycle key, event field, and concurrency map key. */\n name: string;\n /** Owner team (required tag). */\n team: string;\n /** Functional area, e.g. \"sales\" (required tag). */\n group: string;\n /** Business component label, e.g. \"checkout\" — not the Datadog RUM service. */\n service: string;\n /** Whole-journey budget in ms; omit / 0 to disable. */\n timeoutMs?: number;\n /** Default per-step timeout in ms; per-call option overrides. Omit / 0 to disable. */\n stepTimeoutMs?: number;\n /** Slow-request threshold for this journey; falls back to app-wide default. */\n requestTimeoutMs?: number;\n /** Per-endpoint overrides for this journey (longest prefix wins over app-wide). */\n endpoints?: readonly EndpointPolicy[];\n /** Optional expected step names (rides as `expected` on the event). */\n steps?: readonly string[];\n /** Custom tags on every event of this journey. */\n tags?: Record<string, TagValue>;\n}\n\nexport type Outcome = 'good' | 'bad' | 'excluded';\n\n/** Handle passed to each step function. */\nexport interface StepHandle {\n /** Resolved journey name for this step, or null if untraced. */\n readonly name: string | null;\n setAttribute(key: string, value: string | number | boolean): void;\n /** Journey-level tags without closing. */\n setTags(tags: Record<string, TagValue>): void;\n /** Apply optional tags then completeJourney. No-op if name is null. */\n complete(tags?: Record<string, TagValue>): void;\n /** Soft business Bad without throw. No-op if name is null. */\n fail(reason: string): void;\n /**\n * Bind this step to a request explicitly (spread into axios config / fetch init /\n * jQuery ajax settings). Needed when requests fire after an await or while steps\n * overlap — see docs soft ambient. Untraced (noop) steps omit `journeyStep`.\n *\n * The value is a non-plain {@link JourneyStepTag} so jQuery/axios deep-merge will\n * not recurse into the circular StepRecord graph.\n */\n tag(): { journeyStep?: unknown };\n}\n\n/** A journey name, or anything with a `name` (e.g. a JourneyHandle / JourneyDef). */\nexport type JourneyNameLike = string | { readonly name: string };\n\n/** First argument to journeyStep / journeyMountStep. */\nexport type JourneyStepTarget = JourneyNameLike | null | readonly JourneyNameLike[];\n\n/** Per-call options for journeyStep. */\nexport interface JourneyStepOptions {\n /** Timeout for this step in ms; overrides journey stepTimeoutMs. Omit / 0 to disable. */\n timeoutMs?: number;\n}\n\nexport interface JourneyState {\n name: string;\n team: string;\n group: string;\n service: string;\n verdict: Outcome;\n startedAt: number;\n timeoutMs: number;\n stepTimeoutMs?: number;\n /**\n * Why the journey closed as bad, else null.\n * Engine: request-error | request-latency | journey-timeout | step-timeout | step-error.\n * Also any custom business reason (e.g. call-not-associated).\n */\n reason: string | null;\n steps: StepRecord[];\n expected: string[] | null;\n tags: Record<string, TagValue>;\n requestTimeoutMs?: number;\n endpoints?: readonly EndpointPolicy[];\n timer: ReturnType<typeof setTimeout> | null;\n closed: boolean;\n}\n\nexport interface StepRecord {\n name: string;\n startedAt: number;\n durationMs: number;\n outcome: 'good' | 'bad';\n reason?: string;\n httpStatus?: number;\n attributes: Record<string, string | number | boolean>;\n journey: JourneyState;\n}\n\n/** Opaque handle to a step, captured at request initiation for response attribution. */\nexport type JourneyStepRef = StepRecord;\n\nexport interface JourneyStepEvent {\n name: string;\n /** Offset from the journey start, ms. */\n startMs: number;\n durationMs: number;\n outcome: 'good' | 'bad';\n reason?: string;\n httpStatus?: number;\n attributes?: Record<string, TagValue>;\n}\n\n/** Neutral journey event payload (journey-specific fields only; session context is host RUM globals). */\nexport interface JourneyEvent {\n journey: {\n name: string;\n team: string;\n group: string;\n service: string;\n outcome: Outcome;\n reason?: string;\n durationMs: number;\n steps: JourneyStepEvent[];\n expected?: string[];\n tags?: Record<string, TagValue>;\n };\n}\n\n/** Destination for a terminal journey event. */\nexport type JourneySink = (event: JourneyEvent) => void;\n\n/** Callable journey — config plus lifecycle helpers bound to `name`. Prefer this over free helpers. */\nexport interface JourneyHandle extends JourneyDef {\n /** Open this journey (restarts if already open). */\n start(tags?: Record<string, TagValue>): void;\n /**\n * Record a step. Opens the journey first when it isn't already open\n * (one-shot store actions); no-op start when a `<JourneyScope>` already opened it.\n */\n step<T>(\n stepName: string,\n fn: (step: StepHandle) => T | Promise<T>,\n opts?: JourneyStepOptions\n ): Promise<T>;\n /**\n * Like `step`, deferred one microtask for mount-effect use under `<JourneyScope>`\n * (React runs child effects before parent). Also auto-starts if not already open.\n */\n mountStep<T>(\n stepName: string,\n fn: (step: StepHandle) => T | Promise<T>,\n opts?: JourneyStepOptions\n ): Promise<T>;\n complete(tags?: Record<string, TagValue>): void;\n fail(reason: string): void;\n exclude(): void;\n setTags(tags: Record<string, TagValue>): void;\n}\n"],"names":[],"mappings":"AAqIA,qGAAqG,GACrG,WAyBC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/** Per-endpoint request policy (app-wide or per-journey). Longest matching prefix wins. */
|
|
2
|
+
export interface EndpointPolicy {
|
|
3
|
+
/**
|
|
4
|
+
* Path/host prefix against the request key (`"/path"` same-origin, `"host/path"` cross-domain).
|
|
5
|
+
* Match requires an exact hit or a `/` boundary after the prefix — `/api/user` matches
|
|
6
|
+
* `/api/user` and `/api/user/42`, but not `/api/user-preferences`. A trailing `/` on
|
|
7
|
+
* `match` already supplies the boundary.
|
|
8
|
+
*/
|
|
9
|
+
match: string;
|
|
10
|
+
/** Custom slow-request threshold in ms; omit / 0 falls through. */
|
|
11
|
+
timeoutMs?: number;
|
|
12
|
+
/** When true, errors and slow responses never mark the journey Bad. */
|
|
13
|
+
ignore?: boolean;
|
|
14
|
+
}
|
|
15
|
+
/** App-wide slow-request threshold fallback (not an axios abort). */
|
|
16
|
+
export interface AppRequestTimeouts {
|
|
17
|
+
/** Fallback threshold when no endpoint or journey override applies. */
|
|
18
|
+
defaultMs: number;
|
|
19
|
+
/** App-wide endpoint overrides; journey-specific ones belong on JourneyDef.endpoints. */
|
|
20
|
+
endpoints?: readonly EndpointPolicy[];
|
|
21
|
+
}
|
|
22
|
+
/** Copy sorted longest-match-first so lookup can return on the first hit. */
|
|
23
|
+
export declare function sortEndpointsByLongestMatch(endpoints: readonly EndpointPolicy[] | undefined): EndpointPolicy[] | undefined;
|
|
24
|
+
/**
|
|
25
|
+
* Longest-prefix match of an endpoint list against a request key.
|
|
26
|
+
* Expects `endpoints` sorted longest-match-first (see `sortEndpointsByLongestMatch`).
|
|
27
|
+
*/
|
|
28
|
+
export declare function longestEndpointMatch(endpoints: readonly EndpointPolicy[] | undefined, key: string): EndpointPolicy | undefined;
|
|
29
|
+
//# sourceMappingURL=endpoint-policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"endpoint-policy.d.ts","sourceRoot":"","sources":["../src/endpoint-policy.ts"],"names":[],"mappings":"AAAA,2FAA2F;AAC3F,MAAM,WAAW,cAAc;IAC3B;;;;;OAKG;IACH,KAAK,EAAE,MAAM,CAAC;IACd,mEAAmE;IACnE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uEAAuE;IACvE,MAAM,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,qEAAqE;AACrE,MAAM,WAAW,kBAAkB;IAC/B,uEAAuE;IACvE,SAAS,EAAE,MAAM,CAAC;IAClB,yFAAyF;IACzF,SAAS,CAAC,EAAE,SAAS,cAAc,EAAE,CAAC;CACzC;AAED,6EAA6E;AAC7E,wBAAgB,2BAA2B,CACvC,SAAS,EAAE,SAAS,cAAc,EAAE,GAAG,SAAS,GACjD,cAAc,EAAE,GAAG,SAAS,CAQ9B;AAiBD;;;GAGG;AACH,wBAAgB,oBAAoB,CAChC,SAAS,EAAE,SAAS,cAAc,EAAE,GAAG,SAAS,EAChD,GAAG,EAAE,MAAM,GACZ,cAAc,GAAG,SAAS,CAO5B"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/** Per-endpoint request policy (app-wide or per-journey). Longest matching prefix wins. */ /** Copy sorted longest-match-first so lookup can return on the first hit. */ export function sortEndpointsByLongestMatch(endpoints) {
|
|
2
|
+
if (endpoints == null) {
|
|
3
|
+
return undefined;
|
|
4
|
+
}
|
|
5
|
+
if (endpoints.length <= 1) {
|
|
6
|
+
return endpoints.length === 0 ? [] : [
|
|
7
|
+
...endpoints
|
|
8
|
+
];
|
|
9
|
+
}
|
|
10
|
+
return [
|
|
11
|
+
...endpoints
|
|
12
|
+
].sort((a, b)=>b.match.length - a.match.length);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* True when `key` equals `match` or continues past a path boundary.
|
|
16
|
+
* `/api/user` matches `/api/user` and `/api/user/42`, not `/api/user-preferences`.
|
|
17
|
+
*/ function matchesEndpoint(key, match) {
|
|
18
|
+
if (!key.startsWith(match)) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
if (match.endsWith('/')) {
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
const next = key[match.length];
|
|
25
|
+
return next === undefined || next === '/';
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Longest-prefix match of an endpoint list against a request key.
|
|
29
|
+
* Expects `endpoints` sorted longest-match-first (see `sortEndpointsByLongestMatch`).
|
|
30
|
+
*/ export function longestEndpointMatch(endpoints, key) {
|
|
31
|
+
for (const e of endpoints !== null && endpoints !== void 0 ? endpoints : []){
|
|
32
|
+
if (matchesEndpoint(key, e.match)) {
|
|
33
|
+
return e;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
//# sourceMappingURL=endpoint-policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/endpoint-policy.ts"],"sourcesContent":["/** Per-endpoint request policy (app-wide or per-journey). Longest matching prefix wins. */\nexport interface EndpointPolicy {\n /**\n * Path/host prefix against the request key (`\"/path\"` same-origin, `\"host/path\"` cross-domain).\n * Match requires an exact hit or a `/` boundary after the prefix — `/api/user` matches\n * `/api/user` and `/api/user/42`, but not `/api/user-preferences`. A trailing `/` on\n * `match` already supplies the boundary.\n */\n match: string;\n /** Custom slow-request threshold in ms; omit / 0 falls through. */\n timeoutMs?: number;\n /** When true, errors and slow responses never mark the journey Bad. */\n ignore?: boolean;\n}\n\n/** App-wide slow-request threshold fallback (not an axios abort). */\nexport interface AppRequestTimeouts {\n /** Fallback threshold when no endpoint or journey override applies. */\n defaultMs: number;\n /** App-wide endpoint overrides; journey-specific ones belong on JourneyDef.endpoints. */\n endpoints?: readonly EndpointPolicy[];\n}\n\n/** Copy sorted longest-match-first so lookup can return on the first hit. */\nexport function sortEndpointsByLongestMatch(\n endpoints: readonly EndpointPolicy[] | undefined\n): EndpointPolicy[] | undefined {\n if (endpoints == null) {\n return undefined;\n }\n if (endpoints.length <= 1) {\n return endpoints.length === 0 ? [] : [...endpoints];\n }\n return [...endpoints].sort((a, b) => b.match.length - a.match.length);\n}\n\n/**\n * True when `key` equals `match` or continues past a path boundary.\n * `/api/user` matches `/api/user` and `/api/user/42`, not `/api/user-preferences`.\n */\nfunction matchesEndpoint(key: string, match: string): boolean {\n if (!key.startsWith(match)) {\n return false;\n }\n if (match.endsWith('/')) {\n return true;\n }\n const next = key[match.length];\n return next === undefined || next === '/';\n}\n\n/**\n * Longest-prefix match of an endpoint list against a request key.\n * Expects `endpoints` sorted longest-match-first (see `sortEndpointsByLongestMatch`).\n */\nexport function longestEndpointMatch(\n endpoints: readonly EndpointPolicy[] | undefined,\n key: string\n): EndpointPolicy | undefined {\n for (const e of endpoints ?? []) {\n if (matchesEndpoint(key, e.match)) {\n return e;\n }\n }\n return undefined;\n}\n"],"names":["sortEndpointsByLongestMatch","endpoints","undefined","length","sort","a","b","match","matchesEndpoint","key","startsWith","endsWith","next","longestEndpointMatch","e"],"mappings":"AAAA,yFAAyF,GAuBzF,2EAA2E,GAC3E,OAAO,SAASA,4BACZC,SAAgD;IAEhD,IAAIA,aAAa,MAAM;QACnB,OAAOC;IACX;IACA,IAAID,UAAUE,MAAM,IAAI,GAAG;QACvB,OAAOF,UAAUE,MAAM,KAAK,IAAI,EAAE,GAAG;eAAIF;SAAU;IACvD;IACA,OAAO;WAAIA;KAAU,CAACG,IAAI,CAAC,CAACC,GAAGC,IAAMA,EAAEC,KAAK,CAACJ,MAAM,GAAGE,EAAEE,KAAK,CAACJ,MAAM;AACxE;AAEA;;;CAGC,GACD,SAASK,gBAAgBC,GAAW,EAAEF,KAAa;IAC/C,IAAI,CAACE,IAAIC,UAAU,CAACH,QAAQ;QACxB,OAAO;IACX;IACA,IAAIA,MAAMI,QAAQ,CAAC,MAAM;QACrB,OAAO;IACX;IACA,MAAMC,OAAOH,GAAG,CAACF,MAAMJ,MAAM,CAAC;IAC9B,OAAOS,SAASV,aAAaU,SAAS;AAC1C;AAEA;;;CAGC,GACD,OAAO,SAASC,qBACZZ,SAAgD,EAChDQ,GAAW;IAEX,KAAK,MAAMK,KAAKb,sBAAAA,uBAAAA,YAAa,EAAE,CAAE;QAC7B,IAAIO,gBAAgBC,KAAKK,EAAEP,KAAK,GAAG;YAC/B,OAAOO;QACX;IACJ;IACA,OAAOZ;AACX"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import './config';
|
|
2
|
+
export { activeJourneyStep, completeJourney, defineJourney, excludeJourney, failJourney, journeyStep, reportBackendRequest, resolveJourneyStep, setJourneyTags, JourneyStepTag, type JourneyDef, type JourneyHandle, type JourneyNameLike, type JourneyStepOptions, type JourneyStepRef, type JourneyStepTarget, type StepHandle, } from './core';
|
|
3
|
+
export { configureJourney, type AppRequestTimeouts, type EndpointPolicy, type JourneyConfig, } from './config';
|
|
4
|
+
export type { JourneySink } from './core';
|
|
5
|
+
/** Test helper — clears open journeys / ambient steps on the default engine. */
|
|
6
|
+
export { resetJourney } from './core';
|
|
7
|
+
export { instrumentAxios } from './integrations/axios';
|
|
8
|
+
export { instrumentFetch } from './integrations/fetch';
|
|
9
|
+
export { exposeAppJourney, instrumentJquery } from './integrations/jquery';
|
|
10
|
+
export { requestKey, type JourneyTimedMeta } from './integrations/request-key';
|
|
11
|
+
export { sendToDatadog, setJourneyRum } from './sinks/datadog';
|
|
12
|
+
export type { JourneyEvent, JourneyStepEvent, TagValue } from './core';
|
|
13
|
+
export { useJourneyName, useOptionalJourneyName } from './integrations/react/context';
|
|
14
|
+
export { JourneyScope } from './integrations/react/scope';
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,UAAU,CAAC;AAElB,OAAO,EAEH,iBAAiB,EAEjB,eAAe,EACf,aAAa,EACb,cAAc,EACd,WAAW,EACX,WAAW,EACX,oBAAoB,EACpB,kBAAkB,EAClB,cAAc,EACd,cAAc,EACd,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,KAAK,iBAAiB,EACtB,KAAK,UAAU,GAClB,MAAM,QAAQ,CAAC;AAEhB,OAAO,EACH,gBAAgB,EAChB,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,KAAK,aAAa,GACrB,MAAM,UAAU,CAAC;AAElB,YAAY,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AAE1C,gFAAgF;AAChF,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAEtC,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC3E,OAAO,EAAE,UAAU,EAAE,KAAK,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC/E,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAE/D,YAAY,EAAE,YAAY,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAEvE,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AACtF,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Force-evaluate config so the default Datadog sink registers even when consumers only
|
|
3
|
+
* import core APIs (defineJourney, etc.). Paired with package.json "sideEffects" for
|
|
4
|
+
* config — otherwise bundlers with sideEffects:false would drop an unused re-export.
|
|
5
|
+
*/ import './config';
|
|
6
|
+
export { // Custom transport adapters only.
|
|
7
|
+
activeJourneyStep, // Prefer defineJourney(...).complete/fail/… — free helpers for name-from-context call sites.
|
|
8
|
+
completeJourney, defineJourney, excludeJourney, failJourney, journeyStep, reportBackendRequest, resolveJourneyStep, setJourneyTags, JourneyStepTag } from './core';
|
|
9
|
+
export { configureJourney } from './config';
|
|
10
|
+
/** Test helper — clears open journeys / ambient steps on the default engine. */ export { resetJourney } from './core';
|
|
11
|
+
export { instrumentAxios } from './integrations/axios';
|
|
12
|
+
export { instrumentFetch } from './integrations/fetch';
|
|
13
|
+
export { exposeAppJourney, instrumentJquery } from './integrations/jquery';
|
|
14
|
+
export { requestKey } from './integrations/request-key';
|
|
15
|
+
export { sendToDatadog, setJourneyRum } from './sinks/datadog';
|
|
16
|
+
export { useJourneyName, useOptionalJourneyName } from './integrations/react/context';
|
|
17
|
+
export { JourneyScope } from './integrations/react/scope';
|
|
18
|
+
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/*\n * Force-evaluate config so the default Datadog sink registers even when consumers only\n * import core APIs (defineJourney, etc.). Paired with package.json \"sideEffects\" for\n * config — otherwise bundlers with sideEffects:false would drop an unused re-export.\n */\nimport './config';\n\nexport {\n // Custom transport adapters only.\n activeJourneyStep,\n // Prefer defineJourney(...).complete/fail/… — free helpers for name-from-context call sites.\n completeJourney,\n defineJourney,\n excludeJourney,\n failJourney,\n journeyStep,\n reportBackendRequest,\n resolveJourneyStep,\n setJourneyTags,\n JourneyStepTag,\n type JourneyDef,\n type JourneyHandle,\n type JourneyNameLike,\n type JourneyStepOptions,\n type JourneyStepRef,\n type JourneyStepTarget,\n type StepHandle,\n} from './core';\n\nexport {\n configureJourney,\n type AppRequestTimeouts,\n type EndpointPolicy,\n type JourneyConfig,\n} from './config';\n\nexport type { JourneySink } from './core';\n\n/** Test helper — clears open journeys / ambient steps on the default engine. */\nexport { resetJourney } from './core';\n\nexport { instrumentAxios } from './integrations/axios';\nexport { instrumentFetch } from './integrations/fetch';\nexport { exposeAppJourney, instrumentJquery } from './integrations/jquery';\nexport { requestKey, type JourneyTimedMeta } from './integrations/request-key';\nexport { sendToDatadog, setJourneyRum } from './sinks/datadog';\n\nexport type { JourneyEvent, JourneyStepEvent, TagValue } from './core';\n\nexport { useJourneyName, useOptionalJourneyName } from './integrations/react/context';\nexport { JourneyScope } from './integrations/react/scope';\n"],"names":["activeJourneyStep","completeJourney","defineJourney","excludeJourney","failJourney","journeyStep","reportBackendRequest","resolveJourneyStep","setJourneyTags","JourneyStepTag","configureJourney","resetJourney","instrumentAxios","instrumentFetch","exposeAppJourney","instrumentJquery","requestKey","sendToDatadog","setJourneyRum","useJourneyName","useOptionalJourneyName","JourneyScope"],"mappings":"AAAA;;;;CAIC,GACD,OAAO,WAAW;AAElB,SACI,kCAAkC;AAClCA,iBAAiB,EACjB,6FAA6F;AAC7FC,eAAe,EACfC,aAAa,EACbC,cAAc,EACdC,WAAW,EACXC,WAAW,EACXC,oBAAoB,EACpBC,kBAAkB,EAClBC,cAAc,EACdC,cAAc,QAQX,SAAS;AAEhB,SACIC,gBAAgB,QAIb,WAAW;AAIlB,8EAA8E,GAC9E,SAASC,YAAY,QAAQ,SAAS;AAEtC,SAASC,eAAe,QAAQ,uBAAuB;AACvD,SAASC,eAAe,QAAQ,uBAAuB;AACvD,SAASC,gBAAgB,EAAEC,gBAAgB,QAAQ,wBAAwB;AAC3E,SAASC,UAAU,QAA+B,6BAA6B;AAC/E,SAASC,aAAa,EAAEC,aAAa,QAAQ,kBAAkB;AAI/D,SAASC,cAAc,EAAEC,sBAAsB,QAAQ,+BAA+B;AACtF,SAASC,YAAY,QAAQ,6BAA6B"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal structural axios surface. No axios dependency — works across 0.31 and 1.x.
|
|
3
|
+
*/
|
|
4
|
+
export interface AxiosLikeInstance {
|
|
5
|
+
defaults: {
|
|
6
|
+
baseURL?: string;
|
|
7
|
+
};
|
|
8
|
+
interceptors: {
|
|
9
|
+
request: {
|
|
10
|
+
use(onFulfilled: (config: any) => any): unknown;
|
|
11
|
+
};
|
|
12
|
+
response: {
|
|
13
|
+
use(onFulfilled: (response: any) => any, onRejected?: (error: any) => any): unknown;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Wire an axios instance into the journey engine (observation-only).
|
|
19
|
+
* Call once per instance (idempotent). Register any async request interceptors
|
|
20
|
+
* (e.g. auth) before this call so this one runs first.
|
|
21
|
+
*/
|
|
22
|
+
export declare function instrumentAxios(instance: AxiosLikeInstance): void;
|
|
23
|
+
//# sourceMappingURL=axios.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"axios.d.ts","sourceRoot":"","sources":["../../src/integrations/axios.ts"],"names":[],"mappings":"AAQA;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAC9B,QAAQ,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/B,YAAY,EAAE;QACV,OAAO,EAAE;YAAE,GAAG,CAAC,WAAW,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,GAAG,GAAG,OAAO,CAAA;SAAE,CAAC;QAC7D,QAAQ,EAAE;YACN,GAAG,CAAC,WAAW,EAAE,CAAC,QAAQ,EAAE,GAAG,KAAK,GAAG,EAAE,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,GAAG,GAAG,OAAO,CAAC;SACvF,CAAC;KACL,CAAC;CACL;AAoBD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI,CAwCjE"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { activeJourneyStep, JourneyStepTag, reportBackendRequest, resolveJourneyStep } from '../core';
|
|
2
|
+
import { requestKey } from './request-key';
|
|
3
|
+
function reportTiming(instance, config, status) {
|
|
4
|
+
var _config_journeyStart;
|
|
5
|
+
const step = resolveJourneyStep(config === null || config === void 0 ? void 0 : config.journeyStep);
|
|
6
|
+
if (!step || !config) {
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
const start = (_config_journeyStart = config.journeyStart) !== null && _config_journeyStart !== void 0 ? _config_journeyStart : globalThis.performance.now();
|
|
10
|
+
const key = requestKey(config.url, config.baseURL, instance.defaults.baseURL);
|
|
11
|
+
reportBackendRequest(step, status, globalThis.performance.now() - start, key);
|
|
12
|
+
}
|
|
13
|
+
const instrumented = new WeakSet();
|
|
14
|
+
/**
|
|
15
|
+
* Wire an axios instance into the journey engine (observation-only).
|
|
16
|
+
* Call once per instance (idempotent). Register any async request interceptors
|
|
17
|
+
* (e.g. auth) before this call so this one runs first.
|
|
18
|
+
*/ export function instrumentAxios(instance) {
|
|
19
|
+
if (instrumented.has(instance)) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
instrumented.add(instance);
|
|
23
|
+
instance.interceptors.request.use((config)=>{
|
|
24
|
+
const timed = config;
|
|
25
|
+
/*
|
|
26
|
+
* Prefer explicit step.tag(); else soft ambient (null when 0 or 2+ steps in flight).
|
|
27
|
+
* Box ambient steps in JourneyStepTag — raw StepRecord is circular and blows axios mergeConfig.
|
|
28
|
+
*/ if (!resolveJourneyStep(timed.journeyStep)) {
|
|
29
|
+
const step = activeJourneyStep();
|
|
30
|
+
if (step) {
|
|
31
|
+
timed.journeyStep = new JourneyStepTag(step);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
timed.journeyStart = globalThis.performance.now();
|
|
35
|
+
return config;
|
|
36
|
+
});
|
|
37
|
+
instance.interceptors.response.use((response)=>{
|
|
38
|
+
reportTiming(instance, response === null || response === void 0 ? void 0 : response.config, response === null || response === void 0 ? void 0 : response.status);
|
|
39
|
+
return response;
|
|
40
|
+
}, (error)=>{
|
|
41
|
+
var _axiosError_response;
|
|
42
|
+
const axiosError = error;
|
|
43
|
+
reportTiming(instance, axiosError === null || axiosError === void 0 ? void 0 : axiosError.config, axiosError === null || axiosError === void 0 ? void 0 : (_axiosError_response = axiosError.response) === null || _axiosError_response === void 0 ? void 0 : _axiosError_response.status);
|
|
44
|
+
/*
|
|
45
|
+
* Passthrough original reason (AxiosError or test doubles). Do not wrap —
|
|
46
|
+
* callers match on .response / AxiosError identity.
|
|
47
|
+
*/ return Promise.reject(error);
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
//# sourceMappingURL=axios.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/integrations/axios.ts"],"sourcesContent":["import {\n activeJourneyStep,\n JourneyStepTag,\n reportBackendRequest,\n resolveJourneyStep,\n} from '../core';\nimport { requestKey, type JourneyTimedMeta } from './request-key';\n\n/**\n * Minimal structural axios surface. No axios dependency — works across 0.31 and 1.x.\n */\nexport interface AxiosLikeInstance {\n defaults: { baseURL?: string };\n interceptors: {\n request: { use(onFulfilled: (config: any) => any): unknown };\n response: {\n use(onFulfilled: (response: any) => any, onRejected?: (error: any) => any): unknown;\n };\n };\n}\n\ntype TimedConfig = JourneyTimedMeta & { url?: string; baseURL?: string };\n\nfunction reportTiming(\n instance: AxiosLikeInstance,\n config: TimedConfig | undefined,\n status: number | undefined\n): void {\n const step = resolveJourneyStep(config?.journeyStep);\n if (!step || !config) {\n return;\n }\n const start = config.journeyStart ?? globalThis.performance.now();\n const key = requestKey(config.url, config.baseURL, instance.defaults.baseURL);\n reportBackendRequest(step, status, globalThis.performance.now() - start, key);\n}\n\nconst instrumented = new WeakSet<object>();\n\n/**\n * Wire an axios instance into the journey engine (observation-only).\n * Call once per instance (idempotent). Register any async request interceptors\n * (e.g. auth) before this call so this one runs first.\n */\nexport function instrumentAxios(instance: AxiosLikeInstance): void {\n if (instrumented.has(instance as object)) {\n return;\n }\n instrumented.add(instance as object);\n\n instance.interceptors.request.use(config => {\n const timed = config as TimedConfig;\n /*\n * Prefer explicit step.tag(); else soft ambient (null when 0 or 2+ steps in flight).\n * Box ambient steps in JourneyStepTag — raw StepRecord is circular and blows axios mergeConfig.\n */\n if (!resolveJourneyStep(timed.journeyStep)) {\n const step = activeJourneyStep();\n if (step) {\n timed.journeyStep = new JourneyStepTag(step);\n }\n }\n timed.journeyStart = globalThis.performance.now();\n return config;\n });\n\n instance.interceptors.response.use(\n response => {\n reportTiming(instance, response?.config as TimedConfig | undefined, response?.status);\n return response;\n },\n (error: unknown) => {\n const axiosError = error as {\n config?: TimedConfig;\n response?: { status?: number };\n };\n reportTiming(instance, axiosError?.config, axiosError?.response?.status);\n /*\n * Passthrough original reason (AxiosError or test doubles). Do not wrap —\n * callers match on .response / AxiosError identity.\n */\n return Promise.reject(error as Error);\n }\n );\n}\n"],"names":["activeJourneyStep","JourneyStepTag","reportBackendRequest","resolveJourneyStep","requestKey","reportTiming","instance","config","status","step","journeyStep","start","journeyStart","globalThis","performance","now","key","url","baseURL","defaults","instrumented","WeakSet","instrumentAxios","has","add","interceptors","request","use","timed","response","error","axiosError","Promise","reject"],"mappings":"AAAA,SACIA,iBAAiB,EACjBC,cAAc,EACdC,oBAAoB,EACpBC,kBAAkB,QACf,UAAU;AACjB,SAASC,UAAU,QAA+B,gBAAgB;AAiBlE,SAASC,aACLC,QAA2B,EAC3BC,MAA+B,EAC/BC,MAA0B;QAMZD;IAJd,MAAME,OAAON,mBAAmBI,mBAAAA,6BAAAA,OAAQG,WAAW;IACnD,IAAI,CAACD,QAAQ,CAACF,QAAQ;QAClB;IACJ;IACA,MAAMI,SAAQJ,uBAAAA,OAAOK,YAAY,cAAnBL,kCAAAA,uBAAuBM,WAAWC,WAAW,CAACC,GAAG;IAC/D,MAAMC,MAAMZ,WAAWG,OAAOU,GAAG,EAAEV,OAAOW,OAAO,EAAEZ,SAASa,QAAQ,CAACD,OAAO;IAC5EhB,qBAAqBO,MAAMD,QAAQK,WAAWC,WAAW,CAACC,GAAG,KAAKJ,OAAOK;AAC7E;AAEA,MAAMI,eAAe,IAAIC;AAEzB;;;;CAIC,GACD,OAAO,SAASC,gBAAgBhB,QAA2B;IACvD,IAAIc,aAAaG,GAAG,CAACjB,WAAqB;QACtC;IACJ;IACAc,aAAaI,GAAG,CAAClB;IAEjBA,SAASmB,YAAY,CAACC,OAAO,CAACC,GAAG,CAACpB,CAAAA;QAC9B,MAAMqB,QAAQrB;QACd;;;SAGC,GACD,IAAI,CAACJ,mBAAmByB,MAAMlB,WAAW,GAAG;YACxC,MAAMD,OAAOT;YACb,IAAIS,MAAM;gBACNmB,MAAMlB,WAAW,GAAG,IAAIT,eAAeQ;YAC3C;QACJ;QACAmB,MAAMhB,YAAY,GAAGC,WAAWC,WAAW,CAACC,GAAG;QAC/C,OAAOR;IACX;IAEAD,SAASmB,YAAY,CAACI,QAAQ,CAACF,GAAG,CAC9BE,CAAAA;QACIxB,aAAaC,UAAUuB,qBAAAA,+BAAAA,SAAUtB,MAAM,EAA6BsB,qBAAAA,+BAAAA,SAAUrB,MAAM;QACpF,OAAOqB;IACX,GACA,CAACC;YAK8CC;QAJ3C,MAAMA,aAAaD;QAInBzB,aAAaC,UAAUyB,uBAAAA,iCAAAA,WAAYxB,MAAM,EAAEwB,uBAAAA,kCAAAA,uBAAAA,WAAYF,QAAQ,cAApBE,2CAAAA,qBAAsBvB,MAAM;QACvE;;;aAGC,GACD,OAAOwB,QAAQC,MAAM,CAACH;IAC1B;AAER"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** Minimal structural fetch shape. */
|
|
2
|
+
export type FetchLike = (input: any, init?: any) => Promise<{
|
|
3
|
+
status: number;
|
|
4
|
+
}>;
|
|
5
|
+
/** Holder of a `fetch` property — globalThis by default, or a scoped object. */
|
|
6
|
+
export interface FetchTarget {
|
|
7
|
+
fetch: FetchLike;
|
|
8
|
+
}
|
|
9
|
+
export interface InstrumentFetchOptions {
|
|
10
|
+
/** Object whose `fetch` is wrapped. Defaults to globalThis. */
|
|
11
|
+
target?: FetchTarget;
|
|
12
|
+
/** Home API base URL for request-key origin resolution. */
|
|
13
|
+
baseURL?: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Wrap a target's fetch so requests inside a journeyStep are attributed and timed.
|
|
17
|
+
* Call once per target (idempotent — second call is a no-op). Returns a restore
|
|
18
|
+
* function that puts the original fetch back. Observation-only.
|
|
19
|
+
*/
|
|
20
|
+
export declare function instrumentFetch(options?: InstrumentFetchOptions): () => void;
|
|
21
|
+
//# sourceMappingURL=fetch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["../../src/integrations/fetch.ts"],"names":[],"mappings":"AAGA,sCAAsC;AACtC,MAAM,MAAM,SAAS,GAAG,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,CAAC,EAAE,GAAG,KAAK,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAEhF,gFAAgF;AAChF,MAAM,WAAW,WAAW;IACxB,KAAK,EAAE,SAAS,CAAC;CACpB;AAED,MAAM,WAAW,sBAAsB;IACnC,+DAA+D;IAC/D,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,2DAA2D;IAC3D,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB;AAkBD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,GAAE,sBAA2B,GAAG,MAAM,IAAI,CAyDhF"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { activeJourneyStep, reportBackendRequest, resolveJourneyStep } from '../core';
|
|
2
|
+
import { requestKey } from './request-key';
|
|
3
|
+
const instrumented = new WeakSet();
|
|
4
|
+
const originals = new WeakMap();
|
|
5
|
+
function resolveUrl(input) {
|
|
6
|
+
if (typeof input === 'string') {
|
|
7
|
+
return input;
|
|
8
|
+
}
|
|
9
|
+
if (input && typeof input.url === 'string') {
|
|
10
|
+
return input.url;
|
|
11
|
+
}
|
|
12
|
+
if (input && typeof input.href === 'string') {
|
|
13
|
+
return input.href;
|
|
14
|
+
}
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Wrap a target's fetch so requests inside a journeyStep are attributed and timed.
|
|
19
|
+
* Call once per target (idempotent — second call is a no-op). Returns a restore
|
|
20
|
+
* function that puts the original fetch back. Observation-only.
|
|
21
|
+
*/ export function instrumentFetch(options = {}) {
|
|
22
|
+
var _options_target;
|
|
23
|
+
const target = (_options_target = options.target) !== null && _options_target !== void 0 ? _options_target : globalThis;
|
|
24
|
+
const key = target;
|
|
25
|
+
if (instrumented.has(key)) {
|
|
26
|
+
return ()=>{};
|
|
27
|
+
}
|
|
28
|
+
const original = target.fetch;
|
|
29
|
+
originals.set(key, original);
|
|
30
|
+
instrumented.add(key);
|
|
31
|
+
// Call through `target` — native fetch throws "Illegal invocation" with the wrong receiver.
|
|
32
|
+
const wrapped = (input, init)=>{
|
|
33
|
+
// Prefer explicit step.tag(); else soft ambient.
|
|
34
|
+
const explicit = resolveJourneyStep(init === null || init === void 0 ? void 0 : init.journeyStep);
|
|
35
|
+
const step = explicit !== null && explicit !== void 0 ? explicit : activeJourneyStep();
|
|
36
|
+
if (!step) {
|
|
37
|
+
return original.call(target, input, init);
|
|
38
|
+
}
|
|
39
|
+
const start = globalThis.performance.now();
|
|
40
|
+
const endpointKey = requestKey(resolveUrl(input), undefined, options.baseURL);
|
|
41
|
+
const promise = original.call(target, input, init);
|
|
42
|
+
return promise.then((response)=>{
|
|
43
|
+
reportBackendRequest(step, response.status, globalThis.performance.now() - start, endpointKey);
|
|
44
|
+
return response;
|
|
45
|
+
}, (error)=>{
|
|
46
|
+
reportBackendRequest(step, undefined, globalThis.performance.now() - start, endpointKey);
|
|
47
|
+
// Passthrough original rejection reason; do not wrap (identity / AbortError).
|
|
48
|
+
return Promise.reject(error);
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
target.fetch = wrapped;
|
|
52
|
+
return ()=>{
|
|
53
|
+
var _originals_get;
|
|
54
|
+
if (!instrumented.has(key)) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
target.fetch = (_originals_get = originals.get(key)) !== null && _originals_get !== void 0 ? _originals_get : original;
|
|
58
|
+
instrumented.delete(key);
|
|
59
|
+
originals.delete(key);
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
//# sourceMappingURL=fetch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/integrations/fetch.ts"],"sourcesContent":["import { activeJourneyStep, reportBackendRequest, resolveJourneyStep } from '../core';\nimport { requestKey, type JourneyTimedMeta } from './request-key';\n\n/** Minimal structural fetch shape. */\nexport type FetchLike = (input: any, init?: any) => Promise<{ status: number }>;\n\n/** Holder of a `fetch` property — globalThis by default, or a scoped object. */\nexport interface FetchTarget {\n fetch: FetchLike;\n}\n\nexport interface InstrumentFetchOptions {\n /** Object whose `fetch` is wrapped. Defaults to globalThis. */\n target?: FetchTarget;\n /** Home API base URL for request-key origin resolution. */\n baseURL?: string;\n}\n\nconst instrumented = new WeakSet<object>();\nconst originals = new WeakMap<object, FetchLike>();\n\nfunction resolveUrl(input: any): string | undefined {\n if (typeof input === 'string') {\n return input;\n }\n if (input && typeof input.url === 'string') {\n return input.url;\n }\n if (input && typeof input.href === 'string') {\n return input.href;\n }\n return undefined;\n}\n\n/**\n * Wrap a target's fetch so requests inside a journeyStep are attributed and timed.\n * Call once per target (idempotent — second call is a no-op). Returns a restore\n * function that puts the original fetch back. Observation-only.\n */\nexport function instrumentFetch(options: InstrumentFetchOptions = {}): () => void {\n const target = options.target ?? (globalThis as unknown as FetchTarget);\n const key = target as object;\n\n if (instrumented.has(key)) {\n return () => {};\n }\n\n const original = target.fetch;\n originals.set(key, original);\n instrumented.add(key);\n\n // Call through `target` — native fetch throws \"Illegal invocation\" with the wrong receiver.\n const wrapped: FetchLike = (input, init) => {\n // Prefer explicit step.tag(); else soft ambient.\n const explicit = resolveJourneyStep((init as JourneyTimedMeta | undefined)?.journeyStep);\n const step = explicit ?? activeJourneyStep();\n if (!step) {\n return original.call(target, input, init);\n }\n\n const start = globalThis.performance.now();\n const endpointKey = requestKey(resolveUrl(input), undefined, options.baseURL);\n const promise = original.call(target, input, init);\n return promise.then(\n response => {\n reportBackendRequest(\n step,\n response.status,\n globalThis.performance.now() - start,\n endpointKey\n );\n return response;\n },\n (error: unknown) => {\n reportBackendRequest(\n step,\n undefined,\n globalThis.performance.now() - start,\n endpointKey\n );\n // Passthrough original rejection reason; do not wrap (identity / AbortError).\n return Promise.reject(error as Error);\n }\n );\n };\n\n target.fetch = wrapped;\n\n return () => {\n if (!instrumented.has(key)) {\n return;\n }\n target.fetch = originals.get(key) ?? original;\n instrumented.delete(key);\n originals.delete(key);\n };\n}\n"],"names":["activeJourneyStep","reportBackendRequest","resolveJourneyStep","requestKey","instrumented","WeakSet","originals","WeakMap","resolveUrl","input","url","href","undefined","instrumentFetch","options","target","globalThis","key","has","original","fetch","set","add","wrapped","init","explicit","journeyStep","step","call","start","performance","now","endpointKey","baseURL","promise","then","response","status","error","Promise","reject","get","delete"],"mappings":"AAAA,SAASA,iBAAiB,EAAEC,oBAAoB,EAAEC,kBAAkB,QAAQ,UAAU;AACtF,SAASC,UAAU,QAA+B,gBAAgB;AAiBlE,MAAMC,eAAe,IAAIC;AACzB,MAAMC,YAAY,IAAIC;AAEtB,SAASC,WAAWC,KAAU;IAC1B,IAAI,OAAOA,UAAU,UAAU;QAC3B,OAAOA;IACX;IACA,IAAIA,SAAS,OAAOA,MAAMC,GAAG,KAAK,UAAU;QACxC,OAAOD,MAAMC,GAAG;IACpB;IACA,IAAID,SAAS,OAAOA,MAAME,IAAI,KAAK,UAAU;QACzC,OAAOF,MAAME,IAAI;IACrB;IACA,OAAOC;AACX;AAEA;;;;CAIC,GACD,OAAO,SAASC,gBAAgBC,UAAkC,CAAC,CAAC;QACjDA;IAAf,MAAMC,UAASD,kBAAAA,QAAQC,MAAM,cAAdD,6BAAAA,kBAAmBE;IAClC,MAAMC,MAAMF;IAEZ,IAAIX,aAAac,GAAG,CAACD,MAAM;QACvB,OAAO,KAAO;IAClB;IAEA,MAAME,WAAWJ,OAAOK,KAAK;IAC7Bd,UAAUe,GAAG,CAACJ,KAAKE;IACnBf,aAAakB,GAAG,CAACL;IAEjB,4FAA4F;IAC5F,MAAMM,UAAqB,CAACd,OAAOe;QAC/B,iDAAiD;QACjD,MAAMC,WAAWvB,mBAAoBsB,iBAAAA,2BAAD,AAACA,KAAuCE,WAAW;QACvF,MAAMC,OAAOF,qBAAAA,sBAAAA,WAAYzB;QACzB,IAAI,CAAC2B,MAAM;YACP,OAAOR,SAASS,IAAI,CAACb,QAAQN,OAAOe;QACxC;QAEA,MAAMK,QAAQb,WAAWc,WAAW,CAACC,GAAG;QACxC,MAAMC,cAAc7B,WAAWK,WAAWC,QAAQG,WAAWE,QAAQmB,OAAO;QAC5E,MAAMC,UAAUf,SAASS,IAAI,CAACb,QAAQN,OAAOe;QAC7C,OAAOU,QAAQC,IAAI,CACfC,CAAAA;YACInC,qBACI0B,MACAS,SAASC,MAAM,EACfrB,WAAWc,WAAW,CAACC,GAAG,KAAKF,OAC/BG;YAEJ,OAAOI;QACX,GACA,CAACE;YACGrC,qBACI0B,MACAf,WACAI,WAAWc,WAAW,CAACC,GAAG,KAAKF,OAC/BG;YAEJ,8EAA8E;YAC9E,OAAOO,QAAQC,MAAM,CAACF;QAC1B;IAER;IAEAvB,OAAOK,KAAK,GAAGG;IAEf,OAAO;YAIYjB;QAHf,IAAI,CAACF,aAAac,GAAG,CAACD,MAAM;YACxB;QACJ;QACAF,OAAOK,KAAK,IAAGd,iBAAAA,UAAUmC,GAAG,CAACxB,kBAAdX,4BAAAA,iBAAsBa;QACrCf,aAAasC,MAAM,CAACzB;QACpBX,UAAUoC,MAAM,CAACzB;IACrB;AACJ"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type JourneyDef, type JourneyHandle, type JourneyStepOptions, type JourneyStepTarget, type StepHandle } from '../../core';
|
|
2
|
+
/**
|
|
3
|
+
* Knockout / desktop-legacy bridge on `window.App.Journey`.
|
|
4
|
+
* Prefer `defineJourney` handles; `journeyStep` / `firstOpenJourney` cover multi-journey steps.
|
|
5
|
+
*/
|
|
6
|
+
export interface AppJourneyApi {
|
|
7
|
+
defineJourney(def: JourneyDef): JourneyHandle;
|
|
8
|
+
journeyStep<T>(journey: JourneyStepTarget, stepName: string, fn: (step: StepHandle) => T | Promise<T>, opts?: JourneyStepOptions): Promise<T>;
|
|
9
|
+
firstOpenJourney(names: readonly string[]): string | null;
|
|
10
|
+
}
|
|
11
|
+
export type WindowWithAppJourney = Window & {
|
|
12
|
+
App?: {
|
|
13
|
+
Journey?: AppJourneyApi;
|
|
14
|
+
} & Record<string, unknown>;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Publish the Knockout bridge on window.App.Journey. Idempotent for the real window.
|
|
18
|
+
* Optional `target` is for tests.
|
|
19
|
+
*/
|
|
20
|
+
export declare function exposeAppJourney(target?: WindowWithAppJourney): AppJourneyApi;
|
|
21
|
+
export { instrumentJquery, type JqueryAjaxSettings, type JqueryStatic, type JqueryXHR, } from './instrument';
|
|
22
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/integrations/jquery/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAIH,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,UAAU,EAClB,MAAM,YAAY,CAAC;AAEpB;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC1B,aAAa,CAAC,GAAG,EAAE,UAAU,GAAG,aAAa,CAAC;IAC9C,WAAW,CAAC,CAAC,EACT,OAAO,EAAE,iBAAiB,EAC1B,QAAQ,EAAE,MAAM,EAChB,EAAE,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,EACxC,IAAI,CAAC,EAAE,kBAAkB,GAC1B,OAAO,CAAC,CAAC,CAAC,CAAC;IACd,gBAAgB,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI,CAAC;CAC7D;AAED,MAAM,MAAM,oBAAoB,GAAG,MAAM,GAAG;IACxC,GAAG,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,aAAa,CAAA;KAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/D,CAAC;AAKF;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,GAAE,oBAA6B,GAAG,aAAa,CAiBrF;AAED,OAAO,EACH,gBAAgB,EAChB,KAAK,kBAAkB,EACvB,KAAK,YAAY,EACjB,KAAK,SAAS,GACjB,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { defineJourney, firstOpenJourney, journeyStep } from '../../core';
|
|
2
|
+
let journeyExposed = false;
|
|
3
|
+
let windowJourneyApi;
|
|
4
|
+
/**
|
|
5
|
+
* Publish the Knockout bridge on window.App.Journey. Idempotent for the real window.
|
|
6
|
+
* Optional `target` is for tests.
|
|
7
|
+
*/ export function exposeAppJourney(target = window) {
|
|
8
|
+
var _target_App;
|
|
9
|
+
if (journeyExposed && target === window && windowJourneyApi) {
|
|
10
|
+
return windowJourneyApi;
|
|
11
|
+
}
|
|
12
|
+
const api = {
|
|
13
|
+
defineJourney,
|
|
14
|
+
journeyStep,
|
|
15
|
+
firstOpenJourney
|
|
16
|
+
};
|
|
17
|
+
target.App = (_target_App = target.App) !== null && _target_App !== void 0 ? _target_App : {};
|
|
18
|
+
target.App.Journey = api;
|
|
19
|
+
if (target === window) {
|
|
20
|
+
journeyExposed = true;
|
|
21
|
+
windowJourneyApi = api;
|
|
22
|
+
}
|
|
23
|
+
return api;
|
|
24
|
+
}
|
|
25
|
+
export { instrumentJquery } from './instrument';
|
|
26
|
+
|
|
27
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/integrations/jquery/index.ts"],"sourcesContent":["import {\n defineJourney,\n firstOpenJourney,\n journeyStep,\n type JourneyDef,\n type JourneyHandle,\n type JourneyStepOptions,\n type JourneyStepTarget,\n type StepHandle,\n} from '../../core';\n\n/**\n * Knockout / desktop-legacy bridge on `window.App.Journey`.\n * Prefer `defineJourney` handles; `journeyStep` / `firstOpenJourney` cover multi-journey steps.\n */\nexport interface AppJourneyApi {\n defineJourney(def: JourneyDef): JourneyHandle;\n journeyStep<T>(\n journey: JourneyStepTarget,\n stepName: string,\n fn: (step: StepHandle) => T | Promise<T>,\n opts?: JourneyStepOptions\n ): Promise<T>;\n firstOpenJourney(names: readonly string[]): string | null;\n}\n\nexport type WindowWithAppJourney = Window & {\n App?: { Journey?: AppJourneyApi } & Record<string, unknown>;\n};\n\nlet journeyExposed = false;\nlet windowJourneyApi: AppJourneyApi | undefined;\n\n/**\n * Publish the Knockout bridge on window.App.Journey. Idempotent for the real window.\n * Optional `target` is for tests.\n */\nexport function exposeAppJourney(target: WindowWithAppJourney = window): AppJourneyApi {\n if (journeyExposed && target === window && windowJourneyApi) {\n return windowJourneyApi;\n }\n\n const api: AppJourneyApi = {\n defineJourney,\n journeyStep,\n firstOpenJourney,\n };\n target.App = target.App ?? {};\n target.App.Journey = api;\n if (target === window) {\n journeyExposed = true;\n windowJourneyApi = api;\n }\n return api;\n}\n\nexport {\n instrumentJquery,\n type JqueryAjaxSettings,\n type JqueryStatic,\n type JqueryXHR,\n} from './instrument';\n"],"names":["defineJourney","firstOpenJourney","journeyStep","journeyExposed","windowJourneyApi","exposeAppJourney","target","window","api","App","Journey","instrumentJquery"],"mappings":"AAAA,SACIA,aAAa,EACbC,gBAAgB,EAChBC,WAAW,QAMR,aAAa;AAqBpB,IAAIC,iBAAiB;AACrB,IAAIC;AAEJ;;;CAGC,GACD,OAAO,SAASC,iBAAiBC,SAA+BC,MAAM;QAUrDD;IATb,IAAIH,kBAAkBG,WAAWC,UAAUH,kBAAkB;QACzD,OAAOA;IACX;IAEA,MAAMI,MAAqB;QACvBR;QACAE;QACAD;IACJ;IACAK,OAAOG,GAAG,IAAGH,cAAAA,OAAOG,GAAG,cAAVH,yBAAAA,cAAc,CAAC;IAC5BA,OAAOG,GAAG,CAACC,OAAO,GAAGF;IACrB,IAAIF,WAAWC,QAAQ;QACnBJ,iBAAiB;QACjBC,mBAAmBI;IACvB;IACA,OAAOA;AACX;AAEA,SACIG,gBAAgB,QAIb,eAAe"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface JqueryXHR {
|
|
2
|
+
status: number;
|
|
3
|
+
journeyStep?: unknown;
|
|
4
|
+
journeyStart?: number;
|
|
5
|
+
}
|
|
6
|
+
export interface JqueryAjaxSettings {
|
|
7
|
+
url?: string;
|
|
8
|
+
journeyStep?: unknown;
|
|
9
|
+
}
|
|
10
|
+
export interface JqueryStatic {
|
|
11
|
+
ajaxPrefilter(handler: (options: JqueryAjaxSettings, originalOptions: JqueryAjaxSettings, jqXHR: JqueryXHR) => void): void;
|
|
12
|
+
(selector: Document): {
|
|
13
|
+
ajaxComplete(handler: (event: unknown, jqXHR: JqueryXHR, settings: JqueryAjaxSettings) => void): void;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
/** Wire a jQuery static into the journey engine. Call once per $ (idempotent). Observation-only. */
|
|
17
|
+
export declare function instrumentJquery($: JqueryStatic): void;
|
|
18
|
+
//# sourceMappingURL=instrument.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instrument.d.ts","sourceRoot":"","sources":["../../../src/integrations/jquery/instrument.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,SAAS;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,kBAAkB;IAC/B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,YAAY;IACzB,aAAa,CACT,OAAO,EAAE,CACL,OAAO,EAAE,kBAAkB,EAC3B,eAAe,EAAE,kBAAkB,EACnC,KAAK,EAAE,SAAS,KACf,IAAI,GACV,IAAI,CAAC;IACR,CAAC,QAAQ,EAAE,QAAQ,GAAG;QAClB,YAAY,CACR,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,kBAAkB,KAAK,IAAI,GAClF,IAAI,CAAC;KACX,CAAC;CACL;AAoBD,oGAAoG;AACpG,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,YAAY,GAAG,IAAI,CA8BtD"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { activeJourneyStep, JourneyStepTag, reportBackendRequest, resolveJourneyStep } from '../../core';
|
|
2
|
+
import { requestKey } from '../request-key';
|
|
3
|
+
const instrumented = new WeakSet();
|
|
4
|
+
function reportTiming(jqXHR, settings) {
|
|
5
|
+
var _jqXHR_journeyStart;
|
|
6
|
+
const step = resolveJourneyStep(jqXHR.journeyStep);
|
|
7
|
+
if (!step) {
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
const start = (_jqXHR_journeyStart = jqXHR.journeyStart) !== null && _jqXHR_journeyStart !== void 0 ? _jqXHR_journeyStart : globalThis.performance.now();
|
|
11
|
+
// jQuery uses status 0 for network / abort failures — treat like a missing status.
|
|
12
|
+
const status = jqXHR.status === 0 ? undefined : jqXHR.status;
|
|
13
|
+
reportBackendRequest(step, status, globalThis.performance.now() - start, requestKey(settings.url, undefined, undefined));
|
|
14
|
+
}
|
|
15
|
+
/** Wire a jQuery static into the journey engine. Call once per $ (idempotent). Observation-only. */ export function instrumentJquery($) {
|
|
16
|
+
if (instrumented.has($)) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
instrumented.add($);
|
|
20
|
+
$.ajaxPrefilter((options, _originalOptions, jqXHR)=>{
|
|
21
|
+
/*
|
|
22
|
+
* Prefer explicit step.tag() (settings or XHR); else soft ambient.
|
|
23
|
+
* Box ambient steps in JourneyStepTag — raw StepRecord is circular and blows jQuery deep-merge.
|
|
24
|
+
*/ if (!jqXHR.journeyStep) {
|
|
25
|
+
const fromSettings = options.journeyStep;
|
|
26
|
+
if (fromSettings) {
|
|
27
|
+
jqXHR.journeyStep = fromSettings;
|
|
28
|
+
} else {
|
|
29
|
+
const step = activeJourneyStep();
|
|
30
|
+
if (step) {
|
|
31
|
+
jqXHR.journeyStep = new JourneyStepTag(step);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (resolveJourneyStep(jqXHR.journeyStep)) {
|
|
36
|
+
jqXHR.journeyStart = globalThis.performance.now();
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
$(document).ajaxComplete((_event, jqXHR, settings)=>{
|
|
40
|
+
reportTiming(jqXHR, settings);
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
//# sourceMappingURL=instrument.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/integrations/jquery/instrument.ts"],"sourcesContent":["import {\n activeJourneyStep,\n JourneyStepTag,\n reportBackendRequest,\n resolveJourneyStep,\n} from '../../core';\nimport { requestKey } from '../request-key';\n\nexport interface JqueryXHR {\n status: number;\n journeyStep?: unknown;\n journeyStart?: number;\n}\n\nexport interface JqueryAjaxSettings {\n url?: string;\n journeyStep?: unknown;\n}\n\nexport interface JqueryStatic {\n ajaxPrefilter(\n handler: (\n options: JqueryAjaxSettings,\n originalOptions: JqueryAjaxSettings,\n jqXHR: JqueryXHR\n ) => void\n ): void;\n (selector: Document): {\n ajaxComplete(\n handler: (event: unknown, jqXHR: JqueryXHR, settings: JqueryAjaxSettings) => void\n ): void;\n };\n}\n\nconst instrumented = new WeakSet<object>();\n\nfunction reportTiming(jqXHR: JqueryXHR, settings: JqueryAjaxSettings): void {\n const step = resolveJourneyStep(jqXHR.journeyStep);\n if (!step) {\n return;\n }\n const start = jqXHR.journeyStart ?? globalThis.performance.now();\n // jQuery uses status 0 for network / abort failures — treat like a missing status.\n const status = jqXHR.status === 0 ? undefined : jqXHR.status;\n reportBackendRequest(\n step,\n status,\n globalThis.performance.now() - start,\n requestKey(settings.url, undefined, undefined)\n );\n}\n\n/** Wire a jQuery static into the journey engine. Call once per $ (idempotent). Observation-only. */\nexport function instrumentJquery($: JqueryStatic): void {\n if (instrumented.has($ as object)) {\n return;\n }\n instrumented.add($ as object);\n\n $.ajaxPrefilter((options, _originalOptions, jqXHR) => {\n /*\n * Prefer explicit step.tag() (settings or XHR); else soft ambient.\n * Box ambient steps in JourneyStepTag — raw StepRecord is circular and blows jQuery deep-merge.\n */\n if (!jqXHR.journeyStep) {\n const fromSettings = options.journeyStep;\n if (fromSettings) {\n jqXHR.journeyStep = fromSettings;\n } else {\n const step = activeJourneyStep();\n if (step) {\n jqXHR.journeyStep = new JourneyStepTag(step);\n }\n }\n }\n if (resolveJourneyStep(jqXHR.journeyStep)) {\n jqXHR.journeyStart = globalThis.performance.now();\n }\n });\n\n $(document).ajaxComplete((_event, jqXHR, settings) => {\n reportTiming(jqXHR, settings);\n });\n}\n"],"names":["activeJourneyStep","JourneyStepTag","reportBackendRequest","resolveJourneyStep","requestKey","instrumented","WeakSet","reportTiming","jqXHR","settings","step","journeyStep","start","journeyStart","globalThis","performance","now","status","undefined","url","instrumentJquery","$","has","add","ajaxPrefilter","options","_originalOptions","fromSettings","document","ajaxComplete","_event"],"mappings":"AAAA,SACIA,iBAAiB,EACjBC,cAAc,EACdC,oBAAoB,EACpBC,kBAAkB,QACf,aAAa;AACpB,SAASC,UAAU,QAAQ,iBAAiB;AA4B5C,MAAMC,eAAe,IAAIC;AAEzB,SAASC,aAAaC,KAAgB,EAAEC,QAA4B;QAKlDD;IAJd,MAAME,OAAOP,mBAAmBK,MAAMG,WAAW;IACjD,IAAI,CAACD,MAAM;QACP;IACJ;IACA,MAAME,SAAQJ,sBAAAA,MAAMK,YAAY,cAAlBL,iCAAAA,sBAAsBM,WAAWC,WAAW,CAACC,GAAG;IAC9D,mFAAmF;IACnF,MAAMC,SAAST,MAAMS,MAAM,KAAK,IAAIC,YAAYV,MAAMS,MAAM;IAC5Df,qBACIQ,MACAO,QACAH,WAAWC,WAAW,CAACC,GAAG,KAAKJ,OAC/BR,WAAWK,SAASU,GAAG,EAAED,WAAWA;AAE5C;AAEA,kGAAkG,GAClG,OAAO,SAASE,iBAAiBC,CAAe;IAC5C,IAAIhB,aAAaiB,GAAG,CAACD,IAAc;QAC/B;IACJ;IACAhB,aAAakB,GAAG,CAACF;IAEjBA,EAAEG,aAAa,CAAC,CAACC,SAASC,kBAAkBlB;QACxC;;;SAGC,GACD,IAAI,CAACA,MAAMG,WAAW,EAAE;YACpB,MAAMgB,eAAeF,QAAQd,WAAW;YACxC,IAAIgB,cAAc;gBACdnB,MAAMG,WAAW,GAAGgB;YACxB,OAAO;gBACH,MAAMjB,OAAOV;gBACb,IAAIU,MAAM;oBACNF,MAAMG,WAAW,GAAG,IAAIV,eAAeS;gBAC3C;YACJ;QACJ;QACA,IAAIP,mBAAmBK,MAAMG,WAAW,GAAG;YACvCH,MAAMK,YAAY,GAAGC,WAAWC,WAAW,CAACC,GAAG;QACnD;IACJ;IAEAK,EAAEO,UAAUC,YAAY,CAAC,CAACC,QAAQtB,OAAOC;QACrCF,aAAaC,OAAOC;IACxB;AACJ"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare const JourneyNameContext: import("react").Context<string | null>;
|
|
2
|
+
/** Active journey name, or null outside a `<JourneyScope>` (steps run untraced). */
|
|
3
|
+
export declare function useOptionalJourneyName(): string | null;
|
|
4
|
+
/** Active journey name; throws outside a `<JourneyScope>`. */
|
|
5
|
+
export declare function useJourneyName(): string;
|
|
6
|
+
//# sourceMappingURL=context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../../src/integrations/react/context.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,kBAAkB,wCAAqC,CAAC;AAErE,oFAAoF;AACpF,wBAAgB,sBAAsB,IAAI,MAAM,GAAG,IAAI,CAEtD;AAED,8DAA8D;AAC9D,wBAAgB,cAAc,IAAI,MAAM,CAMvC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { createContext, useContext } from 'react';
|
|
2
|
+
export const JourneyNameContext = createContext(null);
|
|
3
|
+
/** Active journey name, or null outside a `<JourneyScope>` (steps run untraced). */ export function useOptionalJourneyName() {
|
|
4
|
+
return useContext(JourneyNameContext);
|
|
5
|
+
}
|
|
6
|
+
/** Active journey name; throws outside a `<JourneyScope>`. */ export function useJourneyName() {
|
|
7
|
+
const name = useContext(JourneyNameContext);
|
|
8
|
+
if (!name) {
|
|
9
|
+
throw new Error('useJourneyName must be used within a <JourneyScope>');
|
|
10
|
+
}
|
|
11
|
+
return name;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/integrations/react/context.ts"],"sourcesContent":["import { createContext, useContext } from 'react';\n\nexport const JourneyNameContext = createContext<string | null>(null);\n\n/** Active journey name, or null outside a `<JourneyScope>` (steps run untraced). */\nexport function useOptionalJourneyName(): string | null {\n return useContext(JourneyNameContext);\n}\n\n/** Active journey name; throws outside a `<JourneyScope>`. */\nexport function useJourneyName(): string {\n const name = useContext(JourneyNameContext);\n if (!name) {\n throw new Error('useJourneyName must be used within a <JourneyScope>');\n }\n return name;\n}\n"],"names":["createContext","useContext","JourneyNameContext","useOptionalJourneyName","useJourneyName","name","Error"],"mappings":"AAAA,SAASA,aAAa,EAAEC,UAAU,QAAQ,QAAQ;AAElD,OAAO,MAAMC,qBAAqBF,cAA6B,MAAM;AAErE,kFAAkF,GAClF,OAAO,SAASG;IACZ,OAAOF,WAAWC;AACtB;AAEA,4DAA4D,GAC5D,OAAO,SAASE;IACZ,MAAMC,OAAOJ,WAAWC;IACxB,IAAI,CAACG,MAAM;QACP,MAAM,IAAIC,MAAM;IACpB;IACA,OAAOD;AACX"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
import { type JourneyDef } from '../../core';
|
|
3
|
+
import type { TagValue } from '../../core/types';
|
|
4
|
+
/**
|
|
5
|
+
* Opens a journey while the subtree is mounted; Excludes on unmount.
|
|
6
|
+
* Config (timeouts, endpoints, tags, …) is captured when the journey opens;
|
|
7
|
+
* only a `name` change re-opens.
|
|
8
|
+
*/
|
|
9
|
+
export declare function JourneyScope({ tags, children, ...def }: JourneyDef & {
|
|
10
|
+
tags?: Record<string, TagValue>;
|
|
11
|
+
children: ReactNode;
|
|
12
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
//# sourceMappingURL=scope.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scope.d.ts","sourceRoot":"","sources":["../../../src/integrations/react/scope.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAElD,OAAO,EAAgD,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAC3F,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAGjD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,EACzB,IAAI,EACJ,QAAQ,EACR,GAAG,GAAG,EACT,EAAE,UAAU,GAAG;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAChC,QAAQ,EAAE,SAAS,CAAC;CACvB,2CAaA"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect } from 'react';
|
|
3
|
+
import { excludeJourney, setJourneyTags, startJourney } from '../../core';
|
|
4
|
+
import { JourneyNameContext } from './context';
|
|
5
|
+
/**
|
|
6
|
+
* Opens a journey while the subtree is mounted; Excludes on unmount.
|
|
7
|
+
* Config (timeouts, endpoints, tags, …) is captured when the journey opens;
|
|
8
|
+
* only a `name` change re-opens.
|
|
9
|
+
*/ export function JourneyScope({ tags, children, ...def }) {
|
|
10
|
+
const { name } = def;
|
|
11
|
+
useEffect(()=>{
|
|
12
|
+
startJourney(def);
|
|
13
|
+
if (tags) {
|
|
14
|
+
setJourneyTags(name, tags);
|
|
15
|
+
}
|
|
16
|
+
return ()=>excludeJourney(name);
|
|
17
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- freeze-on-mount; name is the lifecycle key
|
|
18
|
+
}, [
|
|
19
|
+
name
|
|
20
|
+
]);
|
|
21
|
+
return /*#__PURE__*/ _jsx(JourneyNameContext.Provider, {
|
|
22
|
+
value: name,
|
|
23
|
+
children: children
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
//# sourceMappingURL=scope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/integrations/react/scope.tsx"],"sourcesContent":["import { useEffect, type ReactNode } from 'react';\n\nimport { excludeJourney, setJourneyTags, startJourney, type JourneyDef } from '../../core';\nimport type { TagValue } from '../../core/types';\nimport { JourneyNameContext } from './context';\n\n/**\n * Opens a journey while the subtree is mounted; Excludes on unmount.\n * Config (timeouts, endpoints, tags, …) is captured when the journey opens;\n * only a `name` change re-opens.\n */\nexport function JourneyScope({\n tags,\n children,\n ...def\n}: JourneyDef & {\n tags?: Record<string, TagValue>;\n children: ReactNode;\n}) {\n const { name } = def;\n\n useEffect(() => {\n startJourney(def);\n if (tags) {\n setJourneyTags(name, tags);\n }\n return () => excludeJourney(name);\n // eslint-disable-next-line react-hooks/exhaustive-deps -- freeze-on-mount; name is the lifecycle key\n }, [name]);\n\n return <JourneyNameContext.Provider value={name}>{children}</JourneyNameContext.Provider>;\n}\n"],"names":["useEffect","excludeJourney","setJourneyTags","startJourney","JourneyNameContext","JourneyScope","tags","children","def","name","Provider","value"],"mappings":";AAAA,SAASA,SAAS,QAAwB,QAAQ;AAElD,SAASC,cAAc,EAAEC,cAAc,EAAEC,YAAY,QAAyB,aAAa;AAE3F,SAASC,kBAAkB,QAAQ,YAAY;AAE/C;;;;CAIC,GACD,OAAO,SAASC,aAAa,EACzBC,IAAI,EACJC,QAAQ,EACR,GAAGC,KAIN;IACG,MAAM,EAAEC,IAAI,EAAE,GAAGD;IAEjBR,UAAU;QACNG,aAAaK;QACb,IAAIF,MAAM;YACNJ,eAAeO,MAAMH;QACzB;QACA,OAAO,IAAML,eAAeQ;IAC5B,qGAAqG;IACzG,GAAG;QAACA;KAAK;IAET,qBAAO,KAACL,mBAAmBM,QAAQ;QAACC,OAAOF;kBAAOF;;AACtD"}
|