@alwaysmeticulous/recorder-loader 2.192.0 → 2.194.1

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/index.d.ts CHANGED
@@ -8,6 +8,14 @@ interface LoaderOptions {
8
8
  uploadIntervalMs?: number;
9
9
  snapshotLinkedStylesheets?: boolean;
10
10
  commitHash?: string;
11
+ /**
12
+ * If it takes more than the specified number of 'ms' to load the recorder,
13
+ * then the promise returned by tryLoadAndStartRecorder will return
14
+ * immediately (thereby unblocking the load of the application, but preventing
15
+ * Meticulous from recording a correct session, with all required network mocks).
16
+ *
17
+ * Defaults to 2000ms.
18
+ */
11
19
  maxMsToBlockFor?: number;
12
20
  snippetsBaseUrl?: string;
13
21
  isProduction?: boolean;
@@ -35,6 +43,15 @@ interface LoaderOptions {
35
43
  * Please see JSDoc on {@link RecorderMiddleware} before implementing custom middleware.
36
44
  */
37
45
  middleware?: RecorderMiddleware[];
46
+ /**
47
+ * Load a specific fixed version of the snippet. If not set will load the
48
+ * latest minor/patch version of the recorder. Bumping to a new major
49
+ * version requires a bump of your @alwaysmeticulous/recorder-loader
50
+ * dependency.
51
+ *
52
+ * Recommendation: leave this unset
53
+ */
54
+ version?: string;
38
55
  }
39
56
  interface Recorder {
40
57
  /**
@@ -54,11 +71,31 @@ export const tryLoadAndStartRecorder: (options: LoaderOptions) => Promise<Record
54
71
  *
55
72
  * Load and start the Meticulous Recorder
56
73
  */
57
- export const loadAndStartRecorder: ({ projectId, recordingToken, uploadIntervalMs, snapshotLinkedStylesheets, commitHash, maxMsToBlockFor: maxMsToBlockFor_, snippetsBaseUrl, forceRecording, middleware, responseSanitizers, isProduction, }: LoaderOptions) => Promise<Recorder>;
74
+ export const loadAndStartRecorder: ({ projectId, recordingToken, uploadIntervalMs, snapshotLinkedStylesheets, commitHash, maxMsToBlockFor: maxMsToBlockFor_, snippetsBaseUrl, forceRecording, middleware, responseSanitizers, isProduction, version, }: LoaderOptions) => Promise<Recorder>;
58
75
  interface Interceptor {
59
76
  startRecordingSession: (options: LoaderOptions) => Promise<Recorder>;
60
77
  stopIntercepting: () => Promise<void>;
61
78
  }
79
+ interface InterceptorOptions {
80
+ /**
81
+ * If it takes more than the specified number of 'ms' to load the interceptor,
82
+ * then the promise returned by tryInstallMeticulousIntercepts will return
83
+ * immediately (thereby unblocking the load of the application, but preventing
84
+ * Meticulous from recording a correct session, with all required network mocks).
85
+ *
86
+ * Defaults to 2000ms.
87
+ */
88
+ maxMsToBlockFor?: number;
89
+ /**
90
+ * Load a specific fixed version of the snippet. If not set will load the
91
+ * latest minor/patch version of the recorder. Bumping to a new major
92
+ * version requires a bump of your @alwaysmeticulous/recorder-loader
93
+ * dependency.
94
+ *
95
+ * Recommendation: leave this unset
96
+ */
97
+ version?: string;
98
+ }
62
99
  /**
63
100
  * Stores a copy of network requests and responses in memory, but doesn't send them to the
64
101
  * server, until the the main recorder is initialised.
@@ -90,9 +127,7 @@ interface Interceptor {
90
127
  * }
91
128
  * ```
92
129
  */
93
- export const tryInstallMeticulousIntercepts: (options?: {
94
- maxMsToBlockFor: number;
95
- }) => Promise<Interceptor>;
130
+ export const tryInstallMeticulousIntercepts: (options: InterceptorOptions) => Promise<Interceptor>;
96
131
  /**
97
132
  * If you add 'https://snippet.meticulous.ai/record/v1/network-recorder.bundle.js' as a script tag
98
133
  * then Meticulous will start off by recording any network requests in memory but not send the data to Meticulous’s
@@ -1 +1 @@
1
- {"mappings":";ACKA;IACE;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IAEvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB;;;;;;;;;OASG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IAEzB;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,wBAAwB,EAAE,CAAC;IAEhD;;;;;OAKG;IACH,UAAU,CAAC,EAAE,kBAAkB,EAAE,CAAC;CACnC;AEzCD;IACE;;;;;OAKG;IACH,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACpC;AAED;;GAEG;AACH,OAAO,MAAM,mCACF,aAAa,KACrB,QAAQ,QAAQ,CAqBlB,CAAC;AAiHF;;;;GAIG;AACH,OAAO,MAAM,kOAxGV,aAAa,KAAG,QAAQ,QAAQ,CAwG2B,CAAC;AC3J/D;IACE,qBAAqB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IACrE,gBAAgB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,OAAO,MAAM,2CACF;IAAE,eAAe,EAAE,MAAM,CAAA;CAAE,KACnC,QAAQ,WAAW,CAwDrB,CAAC;ACjGF;;;;;;;;;;;GAWG;AACH,OAAO,MAAM,qCAMZ,CAAC","sources":["packages/recorder-loader/src/src/constants.ts","packages/recorder-loader/src/src/loader.types.ts","packages/recorder-loader/src/src/private-window-api.ts","packages/recorder-loader/src/src/loader.ts","packages/recorder-loader/src/src/install-meticulous-intercepts.ts","packages/recorder-loader/src/src/early-network-recorder.ts","packages/recorder-loader/src/src/index.ts","packages/recorder-loader/src/index.ts"],"sourcesContent":[null,null,null,null,null,null,null,"export { loadAndStartRecorder, tryLoadAndStartRecorder } from \"./loader\";\nexport { tryInstallMeticulousIntercepts } from \"./install-meticulous-intercepts\";\nexport { stopIntercepting } from \"./early-network-recorder\";\n"],"names":[],"version":3,"file":"index.d.ts.map"}
1
+ {"mappings":";AEKA;IACE;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IAEvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;;;;;OAOG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB;;;;;;;;;OASG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IAEzB;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,wBAAwB,EAAE,CAAC;IAEhD;;;;;OAKG;IACH,UAAU,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAElC;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AE1DD;IACE;;;;;OAKG;IACH,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACpC;AAED;;GAEG;AACH,OAAO,MAAM,mCACF,aAAa,KACrB,QAAQ,QAAQ,CAqBlB,CAAC;AAuHF;;;;GAIG;AACH,OAAO,MAAM,2OA7GV,aAAa,KAAG,QAAQ,QAAQ,CA6G2B,CAAC;ACjK/D;IACE,qBAAqB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IACrE,gBAAgB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AAED;IACE;;;;;;;OAOG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAID;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,OAAO,MAAM,0CACF,kBAAkB,KAC1B,QAAQ,WAAW,CA4DrB,CAAC;AC9HF;;;;;;;;;;;GAWG;AACH,OAAO,MAAM,qCAMZ,CAAC","sources":["packages/recorder-loader/src/src/constants.ts","packages/recorder-loader/src/src/get-snippet-version-folder.ts","packages/recorder-loader/src/src/loader.types.ts","packages/recorder-loader/src/src/private-window-api.ts","packages/recorder-loader/src/src/loader.ts","packages/recorder-loader/src/src/install-meticulous-intercepts.ts","packages/recorder-loader/src/src/early-network-recorder.ts","packages/recorder-loader/src/src/index.ts","packages/recorder-loader/src/index.ts"],"sourcesContent":[null,null,null,null,null,null,null,null,"export { loadAndStartRecorder, tryLoadAndStartRecorder } from \"./loader\";\nexport { tryInstallMeticulousIntercepts } from \"./install-meticulous-intercepts\";\nexport { stopIntercepting } from \"./early-network-recorder\";\n"],"names":[],"version":3,"file":"index.d.ts.map"}
package/dist/index.js CHANGED
@@ -9,6 +9,12 @@ $parcel$export(module.exports, "stopIntercepting", () => $6795f29cc093eb86$expor
9
9
  const $d2f90b927d91d104$export$d16af6ab0c202bae = "https://snippet.meticulous.ai";
10
10
 
11
11
 
12
+ const $b0bd6ecf0d8b9152$export$1595d9c512db1389 = (version)=>{
13
+ if (version == null) return "v1";
14
+ return `v/${version}`;
15
+ };
16
+
17
+
12
18
  const $c97024bcb09807fa$var$DEFAULT_MAX_MS_TO_BLOCK_FOR = 2000;
13
19
  const $c97024bcb09807fa$export$f80553af9d70f9fd = async (options)=>{
14
20
  if (window.Meticulous?.isRunningAsTest) {
@@ -29,7 +35,7 @@ const $c97024bcb09807fa$export$f80553af9d70f9fd = async (options)=>{
29
35
  };
30
36
  });
31
37
  };
32
- const $c97024bcb09807fa$var$unsafeLoadAndStartRecorder = ({ projectId: projectId , recordingToken: recordingToken , uploadIntervalMs: uploadIntervalMs , snapshotLinkedStylesheets: snapshotLinkedStylesheets , commitHash: commitHash , maxMsToBlockFor: maxMsToBlockFor_ , snippetsBaseUrl: snippetsBaseUrl , forceRecording: forceRecording , middleware: middleware , responseSanitizers: responseSanitizers , isProduction: isProduction })=>{
38
+ const $c97024bcb09807fa$var$unsafeLoadAndStartRecorder = ({ projectId: projectId , recordingToken: recordingToken , uploadIntervalMs: uploadIntervalMs , snapshotLinkedStylesheets: snapshotLinkedStylesheets , commitHash: commitHash , maxMsToBlockFor: maxMsToBlockFor_ , snippetsBaseUrl: snippetsBaseUrl , forceRecording: forceRecording , middleware: middleware , responseSanitizers: responseSanitizers , isProduction: isProduction , version: version })=>{
33
39
  let abandoned = false;
34
40
  return new Promise((resolve, reject)=>{
35
41
  const maxMsToBlockFor = maxMsToBlockFor_ ?? $c97024bcb09807fa$var$DEFAULT_MAX_MS_TO_BLOCK_FOR;
@@ -44,7 +50,7 @@ const $c97024bcb09807fa$var$unsafeLoadAndStartRecorder = ({ projectId: projectId
44
50
  const script = document.createElement("script");
45
51
  script.type = "text/javascript";
46
52
  const baseSnippetsUrl = snippetsBaseUrl || (0, $d2f90b927d91d104$export$d16af6ab0c202bae);
47
- script.src = new URL("v1/meticulous-manual-init.js", baseSnippetsUrl).href;
53
+ script.src = new URL(`${version != null ? "record/" : ""}${(0, $b0bd6ecf0d8b9152$export$1595d9c512db1389)(version ?? null)}/meticulous-manual-init.js`, baseSnippetsUrl).href;
48
54
  // Setup configuration
49
55
  const typedWindow = window;
50
56
  typedWindow.METICULOUS_RECORDING_TOKEN = recordingToken ?? projectId;
@@ -91,9 +97,9 @@ const $c97024bcb09807fa$export$9da0cde53b499187 = $c97024bcb09807fa$var$unsafeLo
91
97
 
92
98
 
93
99
 
94
- const $f8da777fb815521f$export$c0c9d1ed5ecb2675 = async (options = {
95
- maxMsToBlockFor: 2000
96
- })=>{
100
+
101
+ const $f8da777fb815521f$var$DEFAULT_MAX_MS_TO_BLOCK_FOR = 2000;
102
+ const $f8da777fb815521f$export$c0c9d1ed5ecb2675 = async (options)=>{
97
103
  let requestedToStopIntercepting = false;
98
104
  let disposedEarlyNetworkRecorder = false;
99
105
  const stopIntercepting = async ()=>{
@@ -108,13 +114,14 @@ const $f8da777fb815521f$export$c0c9d1ed5ecb2675 = async (options = {
108
114
  startRecordingSession: (0, $c97024bcb09807fa$export$f80553af9d70f9fd),
109
115
  stopIntercepting: stopIntercepting
110
116
  };
117
+ const maxMsToBlockFor = options.maxMsToBlockFor ?? $f8da777fb815521f$var$DEFAULT_MAX_MS_TO_BLOCK_FOR;
111
118
  const promise = new Promise((resolve, reject)=>{
112
- const timeout = options.maxMsToBlockFor > 0 ? setTimeout(()=>{
119
+ const timeout = maxMsToBlockFor > 0 ? setTimeout(()=>{
113
120
  resolve(interceptor);
114
- }, options.maxMsToBlockFor) : null;
121
+ }, maxMsToBlockFor) : null;
115
122
  const script = document.createElement("script");
116
123
  script.type = "text/javascript";
117
- script.src = `${0, $d2f90b927d91d104$export$d16af6ab0c202bae}/record/v1/network-recorder.bundle.js`;
124
+ script.src = `${0, $d2f90b927d91d104$export$d16af6ab0c202bae}/record/${(0, $b0bd6ecf0d8b9152$export$1595d9c512db1389)(options.version ?? null)}/network-recorder.bundle.js`;
118
125
  script.onload = function() {
119
126
  if (timeout) window.clearTimeout(timeout);
120
127
  resolve(interceptor);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"mappings":"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","sources":["packages/recorder-loader/src/index.ts","packages/recorder-loader/src/loader.ts","packages/recorder-loader/src/constants.ts","packages/recorder-loader/src/install-meticulous-intercepts.ts","packages/recorder-loader/src/early-network-recorder.ts"],"sourcesContent":["export { loadAndStartRecorder, tryLoadAndStartRecorder } from \"./loader\";\nexport { tryInstallMeticulousIntercepts } from \"./install-meticulous-intercepts\";\nexport { stopIntercepting } from \"./early-network-recorder\";\n","import { SNIPPETS_BASE_URL } from \"./constants\";\nimport { LoaderOptions } from \"./loader.types\";\nimport { PrivateWindowApi } from \"./private-window-api\";\n\nconst DEFAULT_MAX_MS_TO_BLOCK_FOR = 2_000;\n\nexport interface Recorder {\n /**\n * Disables the recorder for the rest of the user session, and stops sending data to the Meticulous\n * servers.\n *\n * Once this method is called the recorder cannot be restarted (unless the page is reloaded).\n */\n stopRecording: () => Promise<void>;\n}\n\n/**\n * Load and start the Meticulous Recorder\n */\nexport const tryLoadAndStartRecorder = async (\n options: LoaderOptions\n): Promise<Recorder> => {\n if (window.Meticulous?.isRunningAsTest) {\n console.debug(\n \"Running as part of a Meticulous test case, so skipping loading the Meticulous recorder.\"\n );\n return {\n stopRecording: async () => {\n // No op\n },\n };\n }\n\n // Try to load the recorder and silence any initialisation error.\n return await unsafeLoadAndStartRecorder(options).catch((error) => {\n console.error(error);\n return {\n stopRecording: async () => {\n // No op\n },\n };\n });\n};\n\nconst unsafeLoadAndStartRecorder = ({\n projectId,\n recordingToken,\n uploadIntervalMs,\n snapshotLinkedStylesheets,\n commitHash,\n maxMsToBlockFor: maxMsToBlockFor_,\n snippetsBaseUrl,\n forceRecording,\n middleware,\n responseSanitizers,\n isProduction,\n}: LoaderOptions): Promise<Recorder> => {\n let abandoned = false;\n\n return new Promise<Recorder>((resolve, reject) => {\n const maxMsToBlockFor = maxMsToBlockFor_ ?? DEFAULT_MAX_MS_TO_BLOCK_FOR;\n\n if (maxMsToBlockFor > 0) {\n setTimeout(() => {\n abandoned = true;\n resolve({\n stopRecording: async () => {\n // No op: we never started recording\n },\n });\n }, maxMsToBlockFor);\n }\n\n const script = document.createElement(\"script\");\n script.type = \"text/javascript\";\n const baseSnippetsUrl = snippetsBaseUrl || SNIPPETS_BASE_URL;\n script.src = new URL(\"v1/meticulous-manual-init.js\", baseSnippetsUrl).href;\n\n // Setup configuration\n const typedWindow = window;\n typedWindow.METICULOUS_RECORDING_TOKEN = recordingToken ?? projectId;\n\n if (uploadIntervalMs !== undefined) {\n typedWindow.METICULOUS_UPLOAD_INTERVAL_MS = uploadIntervalMs;\n }\n\n if (commitHash !== undefined) {\n typedWindow.METICULOUS_APP_COMMIT_HASH = commitHash;\n }\n\n if (snapshotLinkedStylesheets !== undefined) {\n typedWindow.METICULOUS_SNAPSHOT_LINKED_STYLESHEETS =\n snapshotLinkedStylesheets;\n }\n\n if (forceRecording !== undefined) {\n typedWindow.METICULOUS_FORCE_RECORDING = forceRecording;\n }\n\n if (isProduction !== undefined) {\n typedWindow.METICULOUS_IS_PRODUCTION_ENVIRONMENT = isProduction;\n }\n\n if (responseSanitizers != null && responseSanitizers.length > 0) {\n typedWindow.METICULOUS_NETWORK_RESPONSE_SANITIZERS = responseSanitizers;\n }\n\n if (middleware != null && middleware.length > 0) {\n typedWindow.METICULOUS_RECORDER_MIDDLEWARE_V1 = middleware;\n }\n\n script.onload = function () {\n if (abandoned) {\n console.debug(\n \"Meticulous snippet abandoned due to max blocking time reached.\"\n );\n // At this point the promise has already resolved.\n return;\n }\n\n const initialiseRecorder = (window as PrivateWindowApi).__meticulous\n ?.initialiseRecorder;\n if (typeof initialiseRecorder !== \"function\") {\n reject(\"Meticulous recorder failed to initialise.\");\n return;\n }\n\n try {\n initialiseRecorder();\n } catch (error) {\n reject(error);\n }\n\n resolve({\n stopRecording: async () => {\n const stopRecording = (window as PrivateWindowApi).__meticulous\n ?.stopRecording;\n if (!stopRecording) {\n throw new Error(\n \"Recorder not initialised: window.__meticulous.stopRecording is not defined.\"\n );\n }\n await stopRecording();\n return;\n },\n });\n };\n script.onerror = () => {\n reject(\"Meticulous recorder failed to initialise.\");\n };\n\n document.head.appendChild(script);\n });\n};\n\n/**\n * @deprecated Use `tryLoadAndStartRecorder` instead.\n *\n * Load and start the Meticulous Recorder\n */\nexport const loadAndStartRecorder = unsafeLoadAndStartRecorder;\n","export const SNIPPETS_BASE_URL = \"https://snippet.meticulous.ai\";\n","import { SNIPPETS_BASE_URL } from \"./constants\";\nimport { Recorder, tryLoadAndStartRecorder } from \"./loader\";\nimport { LoaderOptions } from \"./loader.types\";\nimport { PrivateWindowApi } from \"./private-window-api\";\n\nexport interface Interceptor {\n startRecordingSession: (options: LoaderOptions) => Promise<Recorder>;\n stopIntercepting: () => Promise<void>;\n}\n\n/**\n * Stores a copy of network requests and responses in memory, but doesn't send them to the\n * server, until the the main recorder is initialised.\n *\n * This is useful if you only want to record sessions for certain users with certain attributes. In\n * this case you have an issue: you need to wait for the user information to load before you know whether\n * you can enable the recorder, but if you enable the recorder after the user information has loaded\n * then the recorder won't be able to capture the initial request & response to load the user information,\n * or other early network responses.\n *\n * The early network recorder solves this: load the early network recorder for all sessions,\n * but only load the main recorder for sessions that you want to record. If when you load the user data\n * you find out you don't want to record the session then you can call the stopRecording() method returned\n * by this method.\n *\n * Example usage:\n *\n * ```\n * // The below call should happen before your app makes any network requests,\n * // or executes any methods that may store a reference to window.fetch or XMLHttpRequest.\n * const interceptor = await tryInstallMeticulousIntercepts();\n *\n * // Later, when you have loaded user data...\n * const userData = await loadUserInfo();\n * if (shouldRecord(userData)) {\n * await interceptor.startRecordingSession({ ... });\n * } else {\n * interceptor.stopIntercepting();\n * }\n * ```\n */\nexport const tryInstallMeticulousIntercepts = async (\n options: { maxMsToBlockFor: number } = { maxMsToBlockFor: 2000 }\n): Promise<Interceptor> => {\n let requestedToStopIntercepting = false;\n let disposedEarlyNetworkRecorder = false;\n const stopIntercepting = async () => {\n requestedToStopIntercepting = true;\n const disposeFunction = (window as PrivateWindowApi)?.__meticulous\n ?.earlyNetworkRecorder?.dispose;\n if (disposeFunction && !disposedEarlyNetworkRecorder) {\n await disposeFunction();\n disposedEarlyNetworkRecorder = true;\n }\n };\n const interceptor = {\n startRecordingSession: tryLoadAndStartRecorder,\n stopIntercepting,\n };\n\n const promise = new Promise<Interceptor>((resolve, reject) => {\n const timeout =\n options.maxMsToBlockFor > 0\n ? setTimeout(() => {\n resolve(interceptor);\n }, options.maxMsToBlockFor)\n : null;\n\n const script = document.createElement(\"script\");\n script.type = \"text/javascript\";\n script.src = `${SNIPPETS_BASE_URL}/record/v1/network-recorder.bundle.js`;\n\n script.onload = function () {\n if (timeout) {\n window.clearTimeout(timeout);\n }\n resolve(interceptor);\n };\n script.onerror = () => {\n if (timeout) {\n window.clearTimeout(timeout);\n }\n reject(\"Meticulous early network recorder failed to initialise.\");\n };\n\n document.head.appendChild(script);\n });\n\n // Try to load the early network recorder and silence any initialisation error.\n return promise\n .catch((error) => {\n console.error(error);\n return interceptor;\n })\n .finally(() => {\n if (requestedToStopIntercepting) {\n void stopIntercepting();\n }\n });\n};\n","import { PrivateWindowApi } from \"./private-window-api\";\n\n/**\n * If you add 'https://snippet.meticulous.ai/record/v1/network-recorder.bundle.js' as a script tag\n * then Meticulous will start off by recording any network requests in memory but not send the data to Meticulous’s\n * servers. Once you have the information to determine whether you want to record and persist the session\n * you can then call {@link tryLoadAndStartRecorder} if you do want to record, or this stopIntercepting method\n * if you do not want to record. When you call stopIntercepting any network requests/responses stored in memory\n * will be dropped and Meticulous will be deactivated. No data will be sent to Meticulous's servers.\n *\n * Please note that if you've already started recording and sending data to Meticulous's services i.e.\n * loaded the main meticulous recorder script or called tryLoadAndStartRecorder then this method will\n * not stop the recording. For that you need to call the stopRecording method returned by tryLoadAndStartRecorder.\n */\nexport const stopIntercepting = async () => {\n const disposeFunction = (window as PrivateWindowApi)?.__meticulous\n ?.earlyNetworkRecorder?.dispose;\n if (disposeFunction) {\n await disposeFunction();\n }\n};\n"],"names":[],"version":3,"file":"index.js.map"}
1
+ {"mappings":"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","sources":["packages/recorder-loader/src/index.ts","packages/recorder-loader/src/loader.ts","packages/recorder-loader/src/constants.ts","packages/recorder-loader/src/get-snippet-version-folder.ts","packages/recorder-loader/src/install-meticulous-intercepts.ts","packages/recorder-loader/src/early-network-recorder.ts"],"sourcesContent":["export { loadAndStartRecorder, tryLoadAndStartRecorder } from \"./loader\";\nexport { tryInstallMeticulousIntercepts } from \"./install-meticulous-intercepts\";\nexport { stopIntercepting } from \"./early-network-recorder\";\n","import { SNIPPETS_BASE_URL } from \"./constants\";\nimport { getSnippetVersionFolder } from \"./get-snippet-version-folder\";\nimport { LoaderOptions } from \"./loader.types\";\nimport { PrivateWindowApi } from \"./private-window-api\";\n\nconst DEFAULT_MAX_MS_TO_BLOCK_FOR = 2_000;\n\nexport interface Recorder {\n /**\n * Disables the recorder for the rest of the user session, and stops sending data to the Meticulous\n * servers.\n *\n * Once this method is called the recorder cannot be restarted (unless the page is reloaded).\n */\n stopRecording: () => Promise<void>;\n}\n\n/**\n * Load and start the Meticulous Recorder\n */\nexport const tryLoadAndStartRecorder = async (\n options: LoaderOptions\n): Promise<Recorder> => {\n if (window.Meticulous?.isRunningAsTest) {\n console.debug(\n \"Running as part of a Meticulous test case, so skipping loading the Meticulous recorder.\"\n );\n return {\n stopRecording: async () => {\n // No op\n },\n };\n }\n\n // Try to load the recorder and silence any initialisation error.\n return await unsafeLoadAndStartRecorder(options).catch((error) => {\n console.error(error);\n return {\n stopRecording: async () => {\n // No op\n },\n };\n });\n};\n\nconst unsafeLoadAndStartRecorder = ({\n projectId,\n recordingToken,\n uploadIntervalMs,\n snapshotLinkedStylesheets,\n commitHash,\n maxMsToBlockFor: maxMsToBlockFor_,\n snippetsBaseUrl,\n forceRecording,\n middleware,\n responseSanitizers,\n isProduction,\n version,\n}: LoaderOptions): Promise<Recorder> => {\n let abandoned = false;\n\n return new Promise<Recorder>((resolve, reject) => {\n const maxMsToBlockFor = maxMsToBlockFor_ ?? DEFAULT_MAX_MS_TO_BLOCK_FOR;\n\n if (maxMsToBlockFor > 0) {\n setTimeout(() => {\n abandoned = true;\n resolve({\n stopRecording: async () => {\n // No op: we never started recording\n },\n });\n }, maxMsToBlockFor);\n }\n\n const script = document.createElement(\"script\");\n script.type = \"text/javascript\";\n const baseSnippetsUrl = snippetsBaseUrl || SNIPPETS_BASE_URL;\n script.src = new URL(\n `${version != null ? \"record/\" : \"\"}${getSnippetVersionFolder(\n version ?? null\n )}/meticulous-manual-init.js`,\n baseSnippetsUrl\n ).href;\n\n // Setup configuration\n const typedWindow = window;\n typedWindow.METICULOUS_RECORDING_TOKEN = recordingToken ?? projectId;\n\n if (uploadIntervalMs !== undefined) {\n typedWindow.METICULOUS_UPLOAD_INTERVAL_MS = uploadIntervalMs;\n }\n\n if (commitHash !== undefined) {\n typedWindow.METICULOUS_APP_COMMIT_HASH = commitHash;\n }\n\n if (snapshotLinkedStylesheets !== undefined) {\n typedWindow.METICULOUS_SNAPSHOT_LINKED_STYLESHEETS =\n snapshotLinkedStylesheets;\n }\n\n if (forceRecording !== undefined) {\n typedWindow.METICULOUS_FORCE_RECORDING = forceRecording;\n }\n\n if (isProduction !== undefined) {\n typedWindow.METICULOUS_IS_PRODUCTION_ENVIRONMENT = isProduction;\n }\n\n if (responseSanitizers != null && responseSanitizers.length > 0) {\n typedWindow.METICULOUS_NETWORK_RESPONSE_SANITIZERS = responseSanitizers;\n }\n\n if (middleware != null && middleware.length > 0) {\n typedWindow.METICULOUS_RECORDER_MIDDLEWARE_V1 = middleware;\n }\n\n script.onload = function () {\n if (abandoned) {\n console.debug(\n \"Meticulous snippet abandoned due to max blocking time reached.\"\n );\n // At this point the promise has already resolved.\n return;\n }\n\n const initialiseRecorder = (window as PrivateWindowApi).__meticulous\n ?.initialiseRecorder;\n if (typeof initialiseRecorder !== \"function\") {\n reject(\"Meticulous recorder failed to initialise.\");\n return;\n }\n\n try {\n initialiseRecorder();\n } catch (error) {\n reject(error);\n }\n\n resolve({\n stopRecording: async () => {\n const stopRecording = (window as PrivateWindowApi).__meticulous\n ?.stopRecording;\n if (!stopRecording) {\n throw new Error(\n \"Recorder not initialised: window.__meticulous.stopRecording is not defined.\"\n );\n }\n await stopRecording();\n return;\n },\n });\n };\n script.onerror = () => {\n reject(\"Meticulous recorder failed to initialise.\");\n };\n\n document.head.appendChild(script);\n });\n};\n\n/**\n * @deprecated Use `tryLoadAndStartRecorder` instead.\n *\n * Load and start the Meticulous Recorder\n */\nexport const loadAndStartRecorder = unsafeLoadAndStartRecorder;\n","export const SNIPPETS_BASE_URL = \"https://snippet.meticulous.ai\";\n","export const getSnippetVersionFolder = (version: string | null) => {\n if (version == null) {\n return \"v1\";\n }\n return `v/${version}`;\n};\n","import { SNIPPETS_BASE_URL } from \"./constants\";\nimport { getSnippetVersionFolder } from \"./get-snippet-version-folder\";\nimport { Recorder, tryLoadAndStartRecorder } from \"./loader\";\nimport { LoaderOptions } from \"./loader.types\";\nimport { PrivateWindowApi } from \"./private-window-api\";\n\nexport interface Interceptor {\n startRecordingSession: (options: LoaderOptions) => Promise<Recorder>;\n stopIntercepting: () => Promise<void>;\n}\n\nexport interface InterceptorOptions {\n /**\n * If it takes more than the specified number of 'ms' to load the interceptor,\n * then the promise returned by tryInstallMeticulousIntercepts will return\n * immediately (thereby unblocking the load of the application, but preventing\n * Meticulous from recording a correct session, with all required network mocks).\n *\n * Defaults to 2000ms.\n */\n maxMsToBlockFor?: number;\n\n /**\n * Load a specific fixed version of the snippet. If not set will load the\n * latest minor/patch version of the recorder. Bumping to a new major\n * version requires a bump of your @alwaysmeticulous/recorder-loader\n * dependency.\n *\n * Recommendation: leave this unset\n */\n version?: string;\n}\n\nconst DEFAULT_MAX_MS_TO_BLOCK_FOR = 2000;\n\n/**\n * Stores a copy of network requests and responses in memory, but doesn't send them to the\n * server, until the the main recorder is initialised.\n *\n * This is useful if you only want to record sessions for certain users with certain attributes. In\n * this case you have an issue: you need to wait for the user information to load before you know whether\n * you can enable the recorder, but if you enable the recorder after the user information has loaded\n * then the recorder won't be able to capture the initial request & response to load the user information,\n * or other early network responses.\n *\n * The early network recorder solves this: load the early network recorder for all sessions,\n * but only load the main recorder for sessions that you want to record. If when you load the user data\n * you find out you don't want to record the session then you can call the stopRecording() method returned\n * by this method.\n *\n * Example usage:\n *\n * ```\n * // The below call should happen before your app makes any network requests,\n * // or executes any methods that may store a reference to window.fetch or XMLHttpRequest.\n * const interceptor = await tryInstallMeticulousIntercepts();\n *\n * // Later, when you have loaded user data...\n * const userData = await loadUserInfo();\n * if (shouldRecord(userData)) {\n * await interceptor.startRecordingSession({ ... });\n * } else {\n * interceptor.stopIntercepting();\n * }\n * ```\n */\nexport const tryInstallMeticulousIntercepts = async (\n options: InterceptorOptions\n): Promise<Interceptor> => {\n let requestedToStopIntercepting = false;\n let disposedEarlyNetworkRecorder = false;\n const stopIntercepting = async () => {\n requestedToStopIntercepting = true;\n const disposeFunction = (window as PrivateWindowApi)?.__meticulous\n ?.earlyNetworkRecorder?.dispose;\n if (disposeFunction && !disposedEarlyNetworkRecorder) {\n await disposeFunction();\n disposedEarlyNetworkRecorder = true;\n }\n };\n const interceptor = {\n startRecordingSession: tryLoadAndStartRecorder,\n stopIntercepting,\n };\n\n const maxMsToBlockFor =\n options.maxMsToBlockFor ?? DEFAULT_MAX_MS_TO_BLOCK_FOR;\n const promise = new Promise<Interceptor>((resolve, reject) => {\n const timeout =\n maxMsToBlockFor > 0\n ? setTimeout(() => {\n resolve(interceptor);\n }, maxMsToBlockFor)\n : null;\n\n const script = document.createElement(\"script\");\n script.type = \"text/javascript\";\n script.src = `${SNIPPETS_BASE_URL}/record/${getSnippetVersionFolder(\n options.version ?? null\n )}/network-recorder.bundle.js`;\n\n script.onload = function () {\n if (timeout) {\n window.clearTimeout(timeout);\n }\n resolve(interceptor);\n };\n script.onerror = () => {\n if (timeout) {\n window.clearTimeout(timeout);\n }\n reject(\"Meticulous early network recorder failed to initialise.\");\n };\n\n document.head.appendChild(script);\n });\n\n // Try to load the early network recorder and silence any initialisation error.\n return promise\n .catch((error) => {\n console.error(error);\n return interceptor;\n })\n .finally(() => {\n if (requestedToStopIntercepting) {\n void stopIntercepting();\n }\n });\n};\n","import { PrivateWindowApi } from \"./private-window-api\";\n\n/**\n * If you add 'https://snippet.meticulous.ai/record/v1/network-recorder.bundle.js' as a script tag\n * then Meticulous will start off by recording any network requests in memory but not send the data to Meticulous’s\n * servers. Once you have the information to determine whether you want to record and persist the session\n * you can then call {@link tryLoadAndStartRecorder} if you do want to record, or this stopIntercepting method\n * if you do not want to record. When you call stopIntercepting any network requests/responses stored in memory\n * will be dropped and Meticulous will be deactivated. No data will be sent to Meticulous's servers.\n *\n * Please note that if you've already started recording and sending data to Meticulous's services i.e.\n * loaded the main meticulous recorder script or called tryLoadAndStartRecorder then this method will\n * not stop the recording. For that you need to call the stopRecording method returned by tryLoadAndStartRecorder.\n */\nexport const stopIntercepting = async () => {\n const disposeFunction = (window as PrivateWindowApi)?.__meticulous\n ?.earlyNetworkRecorder?.dispose;\n if (disposeFunction) {\n await disposeFunction();\n }\n};\n"],"names":[],"version":3,"file":"index.js.map"}
package/dist/module.js CHANGED
@@ -1,6 +1,12 @@
1
1
  const $7d7683134fbb8fec$export$d16af6ab0c202bae = "https://snippet.meticulous.ai";
2
2
 
3
3
 
4
+ const $01ff17ace345060a$export$1595d9c512db1389 = (version)=>{
5
+ if (version == null) return "v1";
6
+ return `v/${version}`;
7
+ };
8
+
9
+
4
10
  const $5d774bdb3a883001$var$DEFAULT_MAX_MS_TO_BLOCK_FOR = 2000;
5
11
  const $5d774bdb3a883001$export$f80553af9d70f9fd = async (options)=>{
6
12
  if (window.Meticulous?.isRunningAsTest) {
@@ -21,7 +27,7 @@ const $5d774bdb3a883001$export$f80553af9d70f9fd = async (options)=>{
21
27
  };
22
28
  });
23
29
  };
24
- const $5d774bdb3a883001$var$unsafeLoadAndStartRecorder = ({ projectId: projectId , recordingToken: recordingToken , uploadIntervalMs: uploadIntervalMs , snapshotLinkedStylesheets: snapshotLinkedStylesheets , commitHash: commitHash , maxMsToBlockFor: maxMsToBlockFor_ , snippetsBaseUrl: snippetsBaseUrl , forceRecording: forceRecording , middleware: middleware , responseSanitizers: responseSanitizers , isProduction: isProduction })=>{
30
+ const $5d774bdb3a883001$var$unsafeLoadAndStartRecorder = ({ projectId: projectId , recordingToken: recordingToken , uploadIntervalMs: uploadIntervalMs , snapshotLinkedStylesheets: snapshotLinkedStylesheets , commitHash: commitHash , maxMsToBlockFor: maxMsToBlockFor_ , snippetsBaseUrl: snippetsBaseUrl , forceRecording: forceRecording , middleware: middleware , responseSanitizers: responseSanitizers , isProduction: isProduction , version: version })=>{
25
31
  let abandoned = false;
26
32
  return new Promise((resolve, reject)=>{
27
33
  const maxMsToBlockFor = maxMsToBlockFor_ ?? $5d774bdb3a883001$var$DEFAULT_MAX_MS_TO_BLOCK_FOR;
@@ -36,7 +42,7 @@ const $5d774bdb3a883001$var$unsafeLoadAndStartRecorder = ({ projectId: projectId
36
42
  const script = document.createElement("script");
37
43
  script.type = "text/javascript";
38
44
  const baseSnippetsUrl = snippetsBaseUrl || (0, $7d7683134fbb8fec$export$d16af6ab0c202bae);
39
- script.src = new URL("v1/meticulous-manual-init.js", baseSnippetsUrl).href;
45
+ script.src = new URL(`${version != null ? "record/" : ""}${(0, $01ff17ace345060a$export$1595d9c512db1389)(version ?? null)}/meticulous-manual-init.js`, baseSnippetsUrl).href;
40
46
  // Setup configuration
41
47
  const typedWindow = window;
42
48
  typedWindow.METICULOUS_RECORDING_TOKEN = recordingToken ?? projectId;
@@ -83,9 +89,9 @@ const $5d774bdb3a883001$export$9da0cde53b499187 = $5d774bdb3a883001$var$unsafeLo
83
89
 
84
90
 
85
91
 
86
- const $d91c442ec5d010f4$export$c0c9d1ed5ecb2675 = async (options = {
87
- maxMsToBlockFor: 2000
88
- })=>{
92
+
93
+ const $d91c442ec5d010f4$var$DEFAULT_MAX_MS_TO_BLOCK_FOR = 2000;
94
+ const $d91c442ec5d010f4$export$c0c9d1ed5ecb2675 = async (options)=>{
89
95
  let requestedToStopIntercepting = false;
90
96
  let disposedEarlyNetworkRecorder = false;
91
97
  const stopIntercepting = async ()=>{
@@ -100,13 +106,14 @@ const $d91c442ec5d010f4$export$c0c9d1ed5ecb2675 = async (options = {
100
106
  startRecordingSession: (0, $5d774bdb3a883001$export$f80553af9d70f9fd),
101
107
  stopIntercepting: stopIntercepting
102
108
  };
109
+ const maxMsToBlockFor = options.maxMsToBlockFor ?? $d91c442ec5d010f4$var$DEFAULT_MAX_MS_TO_BLOCK_FOR;
103
110
  const promise = new Promise((resolve, reject)=>{
104
- const timeout = options.maxMsToBlockFor > 0 ? setTimeout(()=>{
111
+ const timeout = maxMsToBlockFor > 0 ? setTimeout(()=>{
105
112
  resolve(interceptor);
106
- }, options.maxMsToBlockFor) : null;
113
+ }, maxMsToBlockFor) : null;
107
114
  const script = document.createElement("script");
108
115
  script.type = "text/javascript";
109
- script.src = `${0, $7d7683134fbb8fec$export$d16af6ab0c202bae}/record/v1/network-recorder.bundle.js`;
116
+ script.src = `${0, $7d7683134fbb8fec$export$d16af6ab0c202bae}/record/${(0, $01ff17ace345060a$export$1595d9c512db1389)(options.version ?? null)}/network-recorder.bundle.js`;
110
117
  script.onload = function() {
111
118
  if (timeout) window.clearTimeout(timeout);
112
119
  resolve(interceptor);
@@ -1 +1 @@
1
- {"mappings":"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","sources":["packages/recorder-loader/src/index.ts","packages/recorder-loader/src/loader.ts","packages/recorder-loader/src/constants.ts","packages/recorder-loader/src/install-meticulous-intercepts.ts","packages/recorder-loader/src/early-network-recorder.ts"],"sourcesContent":["export { loadAndStartRecorder, tryLoadAndStartRecorder } from \"./loader\";\nexport { tryInstallMeticulousIntercepts } from \"./install-meticulous-intercepts\";\nexport { stopIntercepting } from \"./early-network-recorder\";\n","import { SNIPPETS_BASE_URL } from \"./constants\";\nimport { LoaderOptions } from \"./loader.types\";\nimport { PrivateWindowApi } from \"./private-window-api\";\n\nconst DEFAULT_MAX_MS_TO_BLOCK_FOR = 2_000;\n\nexport interface Recorder {\n /**\n * Disables the recorder for the rest of the user session, and stops sending data to the Meticulous\n * servers.\n *\n * Once this method is called the recorder cannot be restarted (unless the page is reloaded).\n */\n stopRecording: () => Promise<void>;\n}\n\n/**\n * Load and start the Meticulous Recorder\n */\nexport const tryLoadAndStartRecorder = async (\n options: LoaderOptions\n): Promise<Recorder> => {\n if (window.Meticulous?.isRunningAsTest) {\n console.debug(\n \"Running as part of a Meticulous test case, so skipping loading the Meticulous recorder.\"\n );\n return {\n stopRecording: async () => {\n // No op\n },\n };\n }\n\n // Try to load the recorder and silence any initialisation error.\n return await unsafeLoadAndStartRecorder(options).catch((error) => {\n console.error(error);\n return {\n stopRecording: async () => {\n // No op\n },\n };\n });\n};\n\nconst unsafeLoadAndStartRecorder = ({\n projectId,\n recordingToken,\n uploadIntervalMs,\n snapshotLinkedStylesheets,\n commitHash,\n maxMsToBlockFor: maxMsToBlockFor_,\n snippetsBaseUrl,\n forceRecording,\n middleware,\n responseSanitizers,\n isProduction,\n}: LoaderOptions): Promise<Recorder> => {\n let abandoned = false;\n\n return new Promise<Recorder>((resolve, reject) => {\n const maxMsToBlockFor = maxMsToBlockFor_ ?? DEFAULT_MAX_MS_TO_BLOCK_FOR;\n\n if (maxMsToBlockFor > 0) {\n setTimeout(() => {\n abandoned = true;\n resolve({\n stopRecording: async () => {\n // No op: we never started recording\n },\n });\n }, maxMsToBlockFor);\n }\n\n const script = document.createElement(\"script\");\n script.type = \"text/javascript\";\n const baseSnippetsUrl = snippetsBaseUrl || SNIPPETS_BASE_URL;\n script.src = new URL(\"v1/meticulous-manual-init.js\", baseSnippetsUrl).href;\n\n // Setup configuration\n const typedWindow = window;\n typedWindow.METICULOUS_RECORDING_TOKEN = recordingToken ?? projectId;\n\n if (uploadIntervalMs !== undefined) {\n typedWindow.METICULOUS_UPLOAD_INTERVAL_MS = uploadIntervalMs;\n }\n\n if (commitHash !== undefined) {\n typedWindow.METICULOUS_APP_COMMIT_HASH = commitHash;\n }\n\n if (snapshotLinkedStylesheets !== undefined) {\n typedWindow.METICULOUS_SNAPSHOT_LINKED_STYLESHEETS =\n snapshotLinkedStylesheets;\n }\n\n if (forceRecording !== undefined) {\n typedWindow.METICULOUS_FORCE_RECORDING = forceRecording;\n }\n\n if (isProduction !== undefined) {\n typedWindow.METICULOUS_IS_PRODUCTION_ENVIRONMENT = isProduction;\n }\n\n if (responseSanitizers != null && responseSanitizers.length > 0) {\n typedWindow.METICULOUS_NETWORK_RESPONSE_SANITIZERS = responseSanitizers;\n }\n\n if (middleware != null && middleware.length > 0) {\n typedWindow.METICULOUS_RECORDER_MIDDLEWARE_V1 = middleware;\n }\n\n script.onload = function () {\n if (abandoned) {\n console.debug(\n \"Meticulous snippet abandoned due to max blocking time reached.\"\n );\n // At this point the promise has already resolved.\n return;\n }\n\n const initialiseRecorder = (window as PrivateWindowApi).__meticulous\n ?.initialiseRecorder;\n if (typeof initialiseRecorder !== \"function\") {\n reject(\"Meticulous recorder failed to initialise.\");\n return;\n }\n\n try {\n initialiseRecorder();\n } catch (error) {\n reject(error);\n }\n\n resolve({\n stopRecording: async () => {\n const stopRecording = (window as PrivateWindowApi).__meticulous\n ?.stopRecording;\n if (!stopRecording) {\n throw new Error(\n \"Recorder not initialised: window.__meticulous.stopRecording is not defined.\"\n );\n }\n await stopRecording();\n return;\n },\n });\n };\n script.onerror = () => {\n reject(\"Meticulous recorder failed to initialise.\");\n };\n\n document.head.appendChild(script);\n });\n};\n\n/**\n * @deprecated Use `tryLoadAndStartRecorder` instead.\n *\n * Load and start the Meticulous Recorder\n */\nexport const loadAndStartRecorder = unsafeLoadAndStartRecorder;\n","export const SNIPPETS_BASE_URL = \"https://snippet.meticulous.ai\";\n","import { SNIPPETS_BASE_URL } from \"./constants\";\nimport { Recorder, tryLoadAndStartRecorder } from \"./loader\";\nimport { LoaderOptions } from \"./loader.types\";\nimport { PrivateWindowApi } from \"./private-window-api\";\n\nexport interface Interceptor {\n startRecordingSession: (options: LoaderOptions) => Promise<Recorder>;\n stopIntercepting: () => Promise<void>;\n}\n\n/**\n * Stores a copy of network requests and responses in memory, but doesn't send them to the\n * server, until the the main recorder is initialised.\n *\n * This is useful if you only want to record sessions for certain users with certain attributes. In\n * this case you have an issue: you need to wait for the user information to load before you know whether\n * you can enable the recorder, but if you enable the recorder after the user information has loaded\n * then the recorder won't be able to capture the initial request & response to load the user information,\n * or other early network responses.\n *\n * The early network recorder solves this: load the early network recorder for all sessions,\n * but only load the main recorder for sessions that you want to record. If when you load the user data\n * you find out you don't want to record the session then you can call the stopRecording() method returned\n * by this method.\n *\n * Example usage:\n *\n * ```\n * // The below call should happen before your app makes any network requests,\n * // or executes any methods that may store a reference to window.fetch or XMLHttpRequest.\n * const interceptor = await tryInstallMeticulousIntercepts();\n *\n * // Later, when you have loaded user data...\n * const userData = await loadUserInfo();\n * if (shouldRecord(userData)) {\n * await interceptor.startRecordingSession({ ... });\n * } else {\n * interceptor.stopIntercepting();\n * }\n * ```\n */\nexport const tryInstallMeticulousIntercepts = async (\n options: { maxMsToBlockFor: number } = { maxMsToBlockFor: 2000 }\n): Promise<Interceptor> => {\n let requestedToStopIntercepting = false;\n let disposedEarlyNetworkRecorder = false;\n const stopIntercepting = async () => {\n requestedToStopIntercepting = true;\n const disposeFunction = (window as PrivateWindowApi)?.__meticulous\n ?.earlyNetworkRecorder?.dispose;\n if (disposeFunction && !disposedEarlyNetworkRecorder) {\n await disposeFunction();\n disposedEarlyNetworkRecorder = true;\n }\n };\n const interceptor = {\n startRecordingSession: tryLoadAndStartRecorder,\n stopIntercepting,\n };\n\n const promise = new Promise<Interceptor>((resolve, reject) => {\n const timeout =\n options.maxMsToBlockFor > 0\n ? setTimeout(() => {\n resolve(interceptor);\n }, options.maxMsToBlockFor)\n : null;\n\n const script = document.createElement(\"script\");\n script.type = \"text/javascript\";\n script.src = `${SNIPPETS_BASE_URL}/record/v1/network-recorder.bundle.js`;\n\n script.onload = function () {\n if (timeout) {\n window.clearTimeout(timeout);\n }\n resolve(interceptor);\n };\n script.onerror = () => {\n if (timeout) {\n window.clearTimeout(timeout);\n }\n reject(\"Meticulous early network recorder failed to initialise.\");\n };\n\n document.head.appendChild(script);\n });\n\n // Try to load the early network recorder and silence any initialisation error.\n return promise\n .catch((error) => {\n console.error(error);\n return interceptor;\n })\n .finally(() => {\n if (requestedToStopIntercepting) {\n void stopIntercepting();\n }\n });\n};\n","import { PrivateWindowApi } from \"./private-window-api\";\n\n/**\n * If you add 'https://snippet.meticulous.ai/record/v1/network-recorder.bundle.js' as a script tag\n * then Meticulous will start off by recording any network requests in memory but not send the data to Meticulous’s\n * servers. Once you have the information to determine whether you want to record and persist the session\n * you can then call {@link tryLoadAndStartRecorder} if you do want to record, or this stopIntercepting method\n * if you do not want to record. When you call stopIntercepting any network requests/responses stored in memory\n * will be dropped and Meticulous will be deactivated. No data will be sent to Meticulous's servers.\n *\n * Please note that if you've already started recording and sending data to Meticulous's services i.e.\n * loaded the main meticulous recorder script or called tryLoadAndStartRecorder then this method will\n * not stop the recording. For that you need to call the stopRecording method returned by tryLoadAndStartRecorder.\n */\nexport const stopIntercepting = async () => {\n const disposeFunction = (window as PrivateWindowApi)?.__meticulous\n ?.earlyNetworkRecorder?.dispose;\n if (disposeFunction) {\n await disposeFunction();\n }\n};\n"],"names":[],"version":3,"file":"module.js.map"}
1
+ {"mappings":"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","sources":["packages/recorder-loader/src/index.ts","packages/recorder-loader/src/loader.ts","packages/recorder-loader/src/constants.ts","packages/recorder-loader/src/get-snippet-version-folder.ts","packages/recorder-loader/src/install-meticulous-intercepts.ts","packages/recorder-loader/src/early-network-recorder.ts"],"sourcesContent":["export { loadAndStartRecorder, tryLoadAndStartRecorder } from \"./loader\";\nexport { tryInstallMeticulousIntercepts } from \"./install-meticulous-intercepts\";\nexport { stopIntercepting } from \"./early-network-recorder\";\n","import { SNIPPETS_BASE_URL } from \"./constants\";\nimport { getSnippetVersionFolder } from \"./get-snippet-version-folder\";\nimport { LoaderOptions } from \"./loader.types\";\nimport { PrivateWindowApi } from \"./private-window-api\";\n\nconst DEFAULT_MAX_MS_TO_BLOCK_FOR = 2_000;\n\nexport interface Recorder {\n /**\n * Disables the recorder for the rest of the user session, and stops sending data to the Meticulous\n * servers.\n *\n * Once this method is called the recorder cannot be restarted (unless the page is reloaded).\n */\n stopRecording: () => Promise<void>;\n}\n\n/**\n * Load and start the Meticulous Recorder\n */\nexport const tryLoadAndStartRecorder = async (\n options: LoaderOptions\n): Promise<Recorder> => {\n if (window.Meticulous?.isRunningAsTest) {\n console.debug(\n \"Running as part of a Meticulous test case, so skipping loading the Meticulous recorder.\"\n );\n return {\n stopRecording: async () => {\n // No op\n },\n };\n }\n\n // Try to load the recorder and silence any initialisation error.\n return await unsafeLoadAndStartRecorder(options).catch((error) => {\n console.error(error);\n return {\n stopRecording: async () => {\n // No op\n },\n };\n });\n};\n\nconst unsafeLoadAndStartRecorder = ({\n projectId,\n recordingToken,\n uploadIntervalMs,\n snapshotLinkedStylesheets,\n commitHash,\n maxMsToBlockFor: maxMsToBlockFor_,\n snippetsBaseUrl,\n forceRecording,\n middleware,\n responseSanitizers,\n isProduction,\n version,\n}: LoaderOptions): Promise<Recorder> => {\n let abandoned = false;\n\n return new Promise<Recorder>((resolve, reject) => {\n const maxMsToBlockFor = maxMsToBlockFor_ ?? DEFAULT_MAX_MS_TO_BLOCK_FOR;\n\n if (maxMsToBlockFor > 0) {\n setTimeout(() => {\n abandoned = true;\n resolve({\n stopRecording: async () => {\n // No op: we never started recording\n },\n });\n }, maxMsToBlockFor);\n }\n\n const script = document.createElement(\"script\");\n script.type = \"text/javascript\";\n const baseSnippetsUrl = snippetsBaseUrl || SNIPPETS_BASE_URL;\n script.src = new URL(\n `${version != null ? \"record/\" : \"\"}${getSnippetVersionFolder(\n version ?? null\n )}/meticulous-manual-init.js`,\n baseSnippetsUrl\n ).href;\n\n // Setup configuration\n const typedWindow = window;\n typedWindow.METICULOUS_RECORDING_TOKEN = recordingToken ?? projectId;\n\n if (uploadIntervalMs !== undefined) {\n typedWindow.METICULOUS_UPLOAD_INTERVAL_MS = uploadIntervalMs;\n }\n\n if (commitHash !== undefined) {\n typedWindow.METICULOUS_APP_COMMIT_HASH = commitHash;\n }\n\n if (snapshotLinkedStylesheets !== undefined) {\n typedWindow.METICULOUS_SNAPSHOT_LINKED_STYLESHEETS =\n snapshotLinkedStylesheets;\n }\n\n if (forceRecording !== undefined) {\n typedWindow.METICULOUS_FORCE_RECORDING = forceRecording;\n }\n\n if (isProduction !== undefined) {\n typedWindow.METICULOUS_IS_PRODUCTION_ENVIRONMENT = isProduction;\n }\n\n if (responseSanitizers != null && responseSanitizers.length > 0) {\n typedWindow.METICULOUS_NETWORK_RESPONSE_SANITIZERS = responseSanitizers;\n }\n\n if (middleware != null && middleware.length > 0) {\n typedWindow.METICULOUS_RECORDER_MIDDLEWARE_V1 = middleware;\n }\n\n script.onload = function () {\n if (abandoned) {\n console.debug(\n \"Meticulous snippet abandoned due to max blocking time reached.\"\n );\n // At this point the promise has already resolved.\n return;\n }\n\n const initialiseRecorder = (window as PrivateWindowApi).__meticulous\n ?.initialiseRecorder;\n if (typeof initialiseRecorder !== \"function\") {\n reject(\"Meticulous recorder failed to initialise.\");\n return;\n }\n\n try {\n initialiseRecorder();\n } catch (error) {\n reject(error);\n }\n\n resolve({\n stopRecording: async () => {\n const stopRecording = (window as PrivateWindowApi).__meticulous\n ?.stopRecording;\n if (!stopRecording) {\n throw new Error(\n \"Recorder not initialised: window.__meticulous.stopRecording is not defined.\"\n );\n }\n await stopRecording();\n return;\n },\n });\n };\n script.onerror = () => {\n reject(\"Meticulous recorder failed to initialise.\");\n };\n\n document.head.appendChild(script);\n });\n};\n\n/**\n * @deprecated Use `tryLoadAndStartRecorder` instead.\n *\n * Load and start the Meticulous Recorder\n */\nexport const loadAndStartRecorder = unsafeLoadAndStartRecorder;\n","export const SNIPPETS_BASE_URL = \"https://snippet.meticulous.ai\";\n","export const getSnippetVersionFolder = (version: string | null) => {\n if (version == null) {\n return \"v1\";\n }\n return `v/${version}`;\n};\n","import { SNIPPETS_BASE_URL } from \"./constants\";\nimport { getSnippetVersionFolder } from \"./get-snippet-version-folder\";\nimport { Recorder, tryLoadAndStartRecorder } from \"./loader\";\nimport { LoaderOptions } from \"./loader.types\";\nimport { PrivateWindowApi } from \"./private-window-api\";\n\nexport interface Interceptor {\n startRecordingSession: (options: LoaderOptions) => Promise<Recorder>;\n stopIntercepting: () => Promise<void>;\n}\n\nexport interface InterceptorOptions {\n /**\n * If it takes more than the specified number of 'ms' to load the interceptor,\n * then the promise returned by tryInstallMeticulousIntercepts will return\n * immediately (thereby unblocking the load of the application, but preventing\n * Meticulous from recording a correct session, with all required network mocks).\n *\n * Defaults to 2000ms.\n */\n maxMsToBlockFor?: number;\n\n /**\n * Load a specific fixed version of the snippet. If not set will load the\n * latest minor/patch version of the recorder. Bumping to a new major\n * version requires a bump of your @alwaysmeticulous/recorder-loader\n * dependency.\n *\n * Recommendation: leave this unset\n */\n version?: string;\n}\n\nconst DEFAULT_MAX_MS_TO_BLOCK_FOR = 2000;\n\n/**\n * Stores a copy of network requests and responses in memory, but doesn't send them to the\n * server, until the the main recorder is initialised.\n *\n * This is useful if you only want to record sessions for certain users with certain attributes. In\n * this case you have an issue: you need to wait for the user information to load before you know whether\n * you can enable the recorder, but if you enable the recorder after the user information has loaded\n * then the recorder won't be able to capture the initial request & response to load the user information,\n * or other early network responses.\n *\n * The early network recorder solves this: load the early network recorder for all sessions,\n * but only load the main recorder for sessions that you want to record. If when you load the user data\n * you find out you don't want to record the session then you can call the stopRecording() method returned\n * by this method.\n *\n * Example usage:\n *\n * ```\n * // The below call should happen before your app makes any network requests,\n * // or executes any methods that may store a reference to window.fetch or XMLHttpRequest.\n * const interceptor = await tryInstallMeticulousIntercepts();\n *\n * // Later, when you have loaded user data...\n * const userData = await loadUserInfo();\n * if (shouldRecord(userData)) {\n * await interceptor.startRecordingSession({ ... });\n * } else {\n * interceptor.stopIntercepting();\n * }\n * ```\n */\nexport const tryInstallMeticulousIntercepts = async (\n options: InterceptorOptions\n): Promise<Interceptor> => {\n let requestedToStopIntercepting = false;\n let disposedEarlyNetworkRecorder = false;\n const stopIntercepting = async () => {\n requestedToStopIntercepting = true;\n const disposeFunction = (window as PrivateWindowApi)?.__meticulous\n ?.earlyNetworkRecorder?.dispose;\n if (disposeFunction && !disposedEarlyNetworkRecorder) {\n await disposeFunction();\n disposedEarlyNetworkRecorder = true;\n }\n };\n const interceptor = {\n startRecordingSession: tryLoadAndStartRecorder,\n stopIntercepting,\n };\n\n const maxMsToBlockFor =\n options.maxMsToBlockFor ?? DEFAULT_MAX_MS_TO_BLOCK_FOR;\n const promise = new Promise<Interceptor>((resolve, reject) => {\n const timeout =\n maxMsToBlockFor > 0\n ? setTimeout(() => {\n resolve(interceptor);\n }, maxMsToBlockFor)\n : null;\n\n const script = document.createElement(\"script\");\n script.type = \"text/javascript\";\n script.src = `${SNIPPETS_BASE_URL}/record/${getSnippetVersionFolder(\n options.version ?? null\n )}/network-recorder.bundle.js`;\n\n script.onload = function () {\n if (timeout) {\n window.clearTimeout(timeout);\n }\n resolve(interceptor);\n };\n script.onerror = () => {\n if (timeout) {\n window.clearTimeout(timeout);\n }\n reject(\"Meticulous early network recorder failed to initialise.\");\n };\n\n document.head.appendChild(script);\n });\n\n // Try to load the early network recorder and silence any initialisation error.\n return promise\n .catch((error) => {\n console.error(error);\n return interceptor;\n })\n .finally(() => {\n if (requestedToStopIntercepting) {\n void stopIntercepting();\n }\n });\n};\n","import { PrivateWindowApi } from \"./private-window-api\";\n\n/**\n * If you add 'https://snippet.meticulous.ai/record/v1/network-recorder.bundle.js' as a script tag\n * then Meticulous will start off by recording any network requests in memory but not send the data to Meticulous’s\n * servers. Once you have the information to determine whether you want to record and persist the session\n * you can then call {@link tryLoadAndStartRecorder} if you do want to record, or this stopIntercepting method\n * if you do not want to record. When you call stopIntercepting any network requests/responses stored in memory\n * will be dropped and Meticulous will be deactivated. No data will be sent to Meticulous's servers.\n *\n * Please note that if you've already started recording and sending data to Meticulous's services i.e.\n * loaded the main meticulous recorder script or called tryLoadAndStartRecorder then this method will\n * not stop the recording. For that you need to call the stopRecording method returned by tryLoadAndStartRecorder.\n */\nexport const stopIntercepting = async () => {\n const disposeFunction = (window as PrivateWindowApi)?.__meticulous\n ?.earlyNetworkRecorder?.dispose;\n if (disposeFunction) {\n await disposeFunction();\n }\n};\n"],"names":[],"version":3,"file":"module.js.map"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alwaysmeticulous/recorder-loader",
3
- "version": "2.192.0",
3
+ "version": "2.194.1",
4
4
  "license": "ISC",
5
5
  "source": "src/index.ts",
6
6
  "main": "dist/index.js",
@@ -21,7 +21,7 @@
21
21
  "depcheck": "depcheck --ignore-patterns=dist"
22
22
  },
23
23
  "dependencies": {
24
- "@alwaysmeticulous/sdk-bundles-api": "^2.192.0"
24
+ "@alwaysmeticulous/sdk-bundles-api": "^2.194.1"
25
25
  },
26
26
  "author": {
27
27
  "name": "The Meticulous Team",
@@ -37,5 +37,5 @@
37
37
  "bugs": {
38
38
  "url": "https://github.com/alwaysmeticulous/meticulous-sdk/issues"
39
39
  },
40
- "gitHead": "3fa1ccc14d7803319ea1f007eea51eead1085c6d"
40
+ "gitHead": "893ddda7fad918abd21e80c065289336f88d125f"
41
41
  }