@workleap/logrocket 1.0.0 → 1.1.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.
@@ -1,4 +1,5 @@
1
- import { getBootstrappingStore, getTelemetryContext } from "@workleap/telemetry";
1
+ import { createCompositeLogger } from "@workleap/logging";
2
+ import { createBootstrappingStore, createTelemetryContext } from "@workleap/telemetry";
2
3
  import logrocket from "logrocket";
3
4
  import logrocket_fuzzy_search_sanitizer from "logrocket-fuzzy-search-sanitizer";
4
5
  import { applyTransformers } from "./applyTransformers.js";
@@ -8,6 +9,8 @@ import { createResponseSanitizer } from "./createResponseSanitizer.js";
8
9
  import { createUrlSanitizer } from "./createUrlSanitizer.js";
9
10
  import { HasExecutedGuard } from "./HasExecutedGuard.js";
10
11
 
12
+ ;// CONCATENATED MODULE: external "@workleap/logging"
13
+
11
14
  ;// CONCATENATED MODULE: external "@workleap/telemetry"
12
15
 
13
16
  ;// CONCATENATED MODULE: external "logrocket"
@@ -36,7 +39,8 @@ import { HasExecutedGuard } from "./HasExecutedGuard.js";
36
39
 
37
40
 
38
41
 
39
- const IsRegisteredFunctionName = "__WLP_LOGROCKET_INSTRUMENTATION_IS_REGISTERED__";
42
+
43
+ const IsRegisteredVariableName = "__WLP_LOGROCKET_INSTRUMENTATION_IS_REGISTERED__";
40
44
  const RegisterGetSessionUrlFunctionName = "__WLP_LOGROCKET_INSTRUMENTATION_REGISTER_GET_SESSION_URL_LISTENER__";
41
45
  const DefaultPrivateFieldNames = [
42
46
  "email",
@@ -57,8 +61,8 @@ const DefaultPrivateQueryParameterNames = [
57
61
  "password"
58
62
  ];
59
63
  // The function return type is mandatory, otherwise we got an error TS4058.
60
- function getLogRocketSdkOptions(options) {
61
- const { rootHostname = "workleap.com", privateFieldNames = [], privateQueryParameterNames = [], verbose = false, transformers = [] } = options;
64
+ function getLogRocketSdkOptions(userOptions, logger) {
65
+ const { rootHostname = "workleap.com", privateFieldNames = [], privateQueryParameterNames = [], verbose = false, transformers = [] } = userOptions;
62
66
  const mergedPrivateFieldNames = DefaultPrivateFieldNames.concat(privateFieldNames);
63
67
  const mergedPrivateQueryParameterNames = DefaultPrivateQueryParameterNames.concat(privateQueryParameterNames);
64
68
  // The "LogrocketFuzzySearch.setup" code is awkward. For now, we prefer to play it safe and call it once here, then forward the sanitize functions
@@ -69,6 +73,8 @@ function getLogRocketSdkOptions(options) {
69
73
  const { requestSanitizer: fuzzyRequestSanitizer, responseSanitizer: fuzzyResponseSanitizer } = logrocket_fuzzy_search_sanitizer.setup(mergedPrivateFieldNames);
70
74
  const sdkOptions = {
71
75
  console: {
76
+ // Prevent console logs from being visible in LogRocket session replays and leaking PII.
77
+ // To capture logs in a session replay, use the LogRocketLogger class.
72
78
  isEnabled: false
73
79
  },
74
80
  rootHostname,
@@ -86,7 +92,8 @@ function getLogRocketSdkOptions(options) {
86
92
  shouldDebugLog: verbose
87
93
  };
88
94
  return applyTransformers(sdkOptions, transformers, {
89
- verbose
95
+ verbose,
96
+ logger
90
97
  });
91
98
  }
92
99
  const registrationGuard = new HasExecutedGuard();
@@ -95,27 +102,24 @@ function __resetRegistrationGuard() {
95
102
  registrationGuard.reset();
96
103
  }
97
104
  /**
98
- * @see https://workleap.github.io/wl-telemetry
105
+ * @see {@link https://workleap.github.io/wl-telemetry}
99
106
  */ function registerLogRocketInstrumentation(appId, options = {}) {
100
- const { verbose = false } = options;
107
+ const { verbose = false, loggers = [] } = options;
108
+ const logger = createCompositeLogger(verbose, loggers);
101
109
  registrationGuard.throw("[logrocket] The LogRocket instrumentation has already been registered. Did you call the \"registerLogRocketInstrumentation\" function twice?");
102
- const sdkOptions = getLogRocketSdkOptions(options);
110
+ const sdkOptions = getLogRocketSdkOptions(options, logger);
103
111
  // Session starts anonymously when LogRocket.init() is called.
104
112
  logrocket.init(appId, sdkOptions);
105
- const telemetryContext = getTelemetryContext({
106
- verbose
107
- });
113
+ const telemetryContext = createTelemetryContext(logger);
108
114
  // LogRocket maintains the same session even if the user starts as anonymous and later becomes identified via LogRocket.identify().
109
115
  // If LogRocket.identify is called multiple times during a recording, you can search for any of the identified users in the session.
110
116
  logrocket.identify(telemetryContext.deviceId, {
111
117
  [DeviceIdTrait]: telemetryContext.deviceId,
112
118
  [TelemetryIdTrait]: telemetryContext.telemetryId
113
119
  });
114
- if (verbose) {
115
- logrocket.getSessionURL((url)=>{
116
- console.log("[logrocket] Session replay URL is now available:", url);
117
- });
118
- }
120
+ logrocket.getSessionURL((url)=>{
121
+ logger.withText("[logrocket] Session replay URL is now available:").withText(url).debug();
122
+ });
119
123
  // Indicates to the host applications that logrocket has been initialized.
120
124
  // It's useful in cases where an "add-on", like the platform widgets needs
121
125
  // to know whether or not the host application is using LogRocket.
@@ -124,7 +128,7 @@ function __resetRegistrationGuard() {
124
128
  // which is great for DX.
125
129
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
126
130
  // @ts-ignore
127
- globalThis[IsRegisteredFunctionName] = true;
131
+ globalThis[IsRegisteredVariableName] = true;
128
132
  // While consumers could directly call LogRocket.getSessionURL, by doing it this way,
129
133
  // it allow consumers to not take a direct dependency on the "logrocket" package.
130
134
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
@@ -132,15 +136,14 @@ function __resetRegistrationGuard() {
132
136
  globalThis[RegisterGetSessionUrlFunctionName] = (listener)=>{
133
137
  logrocket.getSessionURL(listener);
134
138
  };
139
+ const bootstrappingStore = createBootstrappingStore(logger);
135
140
  // Let the other telemetry libraries know that LogRocket instrumentation is ready.
136
- getBootstrappingStore().dispatch({
141
+ bootstrappingStore.dispatch({
137
142
  type: "logrocket-ready"
138
143
  });
139
- if (verbose) {
140
- console.log("[logrocket] LogRocket instrumentation is registered.");
141
- }
144
+ logger.debug("[logrocket] LogRocket instrumentation is registered.");
142
145
  }
143
146
 
144
- export { IsRegisteredFunctionName, RegisterGetSessionUrlFunctionName, __resetRegistrationGuard, getLogRocketSdkOptions, registerLogRocketInstrumentation };
147
+ export { IsRegisteredVariableName, RegisterGetSessionUrlFunctionName, __resetRegistrationGuard, getLogRocketSdkOptions, registerLogRocketInstrumentation };
145
148
 
146
149
  //# sourceMappingURL=registerLogRocketInstrumentation.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"registerLogRocketInstrumentation.js","sources":["webpack://@workleap/logrocket/./src/registerLogRocketInstrumentation.ts"],"sourcesContent":["import { getBootstrappingStore, getTelemetryContext } from \"@workleap/telemetry\";\nimport LogRocket from \"logrocket\";\nimport LogrocketFuzzySanitizer from \"logrocket-fuzzy-search-sanitizer\";\nimport { applyTransformers, type LogRocketSdkOptionsTransformer } from \"./applyTransformers.ts\";\nimport { DeviceIdTrait, TelemetryIdTrait } from \"./createDefaultUserTraits.ts\";\nimport { createRequestSanitizer } from \"./createRequestSanitizer.ts\";\nimport { createResponseSanitizer } from \"./createResponseSanitizer.ts\";\nimport { createUrlSanitizer } from \"./createUrlSanitizer.ts\";\nimport { HasExecutedGuard } from \"./HasExecutedGuard.ts\";\nimport type { LogRocketSdkOptions } from \"./logRocketTypes.ts\";\n\nexport const IsRegisteredFunctionName = \"__WLP_LOGROCKET_INSTRUMENTATION_IS_REGISTERED__\";\nexport const RegisterGetSessionUrlFunctionName = \"__WLP_LOGROCKET_INSTRUMENTATION_REGISTER_GET_SESSION_URL_LISTENER__\";\n\nconst DefaultPrivateFieldNames = [\n \"email\",\n \"personalEmail\",\n \"phoneNumber\",\n \"password\",\n \"firstName\",\n \"lastName\",\n \"givenName\",\n \"fullName\",\n \"gender\",\n \"timeZone\",\n \"birthday\"\n];\n\nconst DefaultPrivateQueryParameterNames = [\n \"token\",\n \"email\",\n \"password\"\n];\n\n/**\n * @see https://workleap.github.io/wl-telemetry\n */\nexport interface RegisterLogRocketInstrumentationOptions {\n // Set to capture traffic from all subdomains under one session: https://docs.logrocket.com/reference/roothostname.\n rootHostname?: LogRocketSdkOptions[\"rootHostname\"];\n privateFieldNames?: string[];\n privateQueryParameterNames?: string[];\n verbose?: boolean;\n transformers?: LogRocketSdkOptionsTransformer[];\n}\n\n// The function return type is mandatory, otherwise we got an error TS4058.\nexport function getLogRocketSdkOptions(options: RegisterLogRocketInstrumentationOptions): LogRocketSdkOptions {\n const {\n rootHostname = \"workleap.com\",\n privateFieldNames = [],\n privateQueryParameterNames = [],\n verbose = false,\n transformers = []\n } = options;\n\n const mergedPrivateFieldNames = DefaultPrivateFieldNames.concat(privateFieldNames);\n const mergedPrivateQueryParameterNames = DefaultPrivateQueryParameterNames.concat(privateQueryParameterNames);\n\n // The \"LogrocketFuzzySearch.setup\" code is awkward. For now, we prefer to play it safe and call it once here, then forward the sanitize functions\n // to the appropriate factories.\n // No clue why the \"setup\" method is not available. This package is shady.\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n const { requestSanitizer: fuzzyRequestSanitizer, responseSanitizer: fuzzyResponseSanitizer } = LogrocketFuzzySanitizer.setup(mergedPrivateFieldNames);\n\n const sdkOptions = {\n console: {\n isEnabled: false\n },\n rootHostname,\n dom: {\n textSanitizer: true,\n inputSanitizer: true\n },\n network: {\n requestSanitizer: createRequestSanitizer(fuzzyRequestSanitizer),\n responseSanitizer: createResponseSanitizer(fuzzyResponseSanitizer)\n },\n browser: {\n urlSanitizer: createUrlSanitizer(mergedPrivateQueryParameterNames)\n },\n shouldDebugLog: verbose\n } satisfies LogRocketSdkOptions;\n\n return applyTransformers(sdkOptions, transformers, {\n verbose\n });\n}\n\nconst registrationGuard = new HasExecutedGuard();\n\n// This function should only be used by tests.\nexport function __resetRegistrationGuard() {\n registrationGuard.reset();\n}\n\n/**\n * @see https://workleap.github.io/wl-telemetry\n */\nexport function registerLogRocketInstrumentation(appId: string, options: RegisterLogRocketInstrumentationOptions = {}) {\n const {\n verbose = false\n } = options;\n\n registrationGuard.throw(\"[logrocket] The LogRocket instrumentation has already been registered. Did you call the \\\"registerLogRocketInstrumentation\\\" function twice?\");\n\n const sdkOptions = getLogRocketSdkOptions(options);\n\n // Session starts anonymously when LogRocket.init() is called.\n LogRocket.init(appId, sdkOptions);\n\n const telemetryContext = getTelemetryContext({ verbose });\n\n // LogRocket maintains the same session even if the user starts as anonymous and later becomes identified via LogRocket.identify().\n // If LogRocket.identify is called multiple times during a recording, you can search for any of the identified users in the session.\n LogRocket.identify(telemetryContext.deviceId, {\n [DeviceIdTrait]: telemetryContext.deviceId,\n [TelemetryIdTrait]: telemetryContext.telemetryId\n });\n\n if (verbose) {\n LogRocket.getSessionURL(url => {\n console.log(\"[logrocket] Session replay URL is now available:\", url);\n });\n }\n\n // Indicates to the host applications that logrocket has been initialized.\n // It's useful in cases where an \"add-on\", like the platform widgets needs\n // to know whether or not the host application is using LogRocket.\n // While there are ways that the host application could tell to an \"add-on\" if\n // it's using LogRocket or not, doing it this way is transparent for the consumer,\n // which is great for DX.\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n globalThis[IsRegisteredFunctionName] = true;\n\n // While consumers could directly call LogRocket.getSessionURL, by doing it this way,\n // it allow consumers to not take a direct dependency on the \"logrocket\" package.\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n globalThis[RegisterGetSessionUrlFunctionName] = listener => {\n LogRocket.getSessionURL(listener);\n };\n\n // Let the other telemetry libraries know that LogRocket instrumentation is ready.\n getBootstrappingStore().dispatch({ type: \"logrocket-ready\" });\n\n if (verbose) {\n console.log(\"[logrocket] LogRocket instrumentation is registered.\");\n }\n}\n"],"names":["getBootstrappingStore","getTelemetryContext","LogRocket","LogrocketFuzzySanitizer","applyTransformers","DeviceIdTrait","TelemetryIdTrait","createRequestSanitizer","createResponseSanitizer","createUrlSanitizer","HasExecutedGuard","IsRegisteredFunctionName","RegisterGetSessionUrlFunctionName","DefaultPrivateFieldNames","DefaultPrivateQueryParameterNames","getLogRocketSdkOptions","options","rootHostname","privateFieldNames","privateQueryParameterNames","verbose","transformers","mergedPrivateFieldNames","mergedPrivateQueryParameterNames","fuzzyRequestSanitizer","fuzzyResponseSanitizer","sdkOptions","registrationGuard","__resetRegistrationGuard","registerLogRocketInstrumentation","appId","telemetryContext","url","console","globalThis","listener"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAiF;AAC/C;AACqC;AACyB;AACjB;AACV;AACE;AACV;AACJ;AAGlD,MAAMW,2BAA2B,kDAAkD;AACnF,MAAMC,oCAAoC,sEAAsE;AAEvH,MAAMC,2BAA2B;IAC7B;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;CACH;AAED,MAAMC,oCAAoC;IACtC;IACA;IACA;CACH;AAcD,2EAA2E;AACpE,SAASC,uBAAuBC,OAAgD;IACnF,MAAM,EACFC,eAAe,cAAc,EAC7BC,oBAAoB,EAAE,EACtBC,6BAA6B,EAAE,EAC/BC,UAAU,KAAK,EACfC,eAAe,EAAE,EACpB,GAAGL;IAEJ,MAAMM,0BAA0BT,yBAAyB,MAAM,CAACK;IAChE,MAAMK,mCAAmCT,kCAAkC,MAAM,CAACK;IAElF,kJAAkJ;IAClJ,gCAAgC;IAChC,0EAA0E;IAC1E,6DAA6D;IAC7D,aAAa;IACb,MAAM,EAAE,kBAAkBK,qBAAqB,EAAE,mBAAmBC,sBAAsB,EAAE,GAAGtB,sCAA6B,CAACmB;IAE7H,MAAMI,aAAa;QACf,SAAS;YACL,WAAW;QACf;QACAT;QACA,KAAK;YACD,eAAe;YACf,gBAAgB;QACpB;QACA,SAAS;YACL,kBAAkBV,sBAAsBA,CAACiB;YACzC,mBAAmBhB,uBAAuBA,CAACiB;QAC/C;QACA,SAAS;YACL,cAAchB,kBAAkBA,CAACc;QACrC;QACA,gBAAgBH;IACpB;IAEA,OAAOhB,iBAAiBA,CAACsB,YAAYL,cAAc;QAC/CD;IACJ;AACJ;AAEA,MAAMO,oBAAoB,IAAIjB,gBAAgBA;AAE9C,8CAA8C;AACvC,SAASkB;IACZD,kBAAkB,KAAK;AAC3B;AAEA;;CAEC,GACM,SAASE,iCAAiCC,KAAa,EAAEd,UAAmD,CAAC,CAAC;IACjH,MAAM,EACFI,UAAU,KAAK,EAClB,GAAGJ;IAEJW,kBAAkB,KAAK,CAAC;IAExB,MAAMD,aAAaX,uBAAuBC;IAE1C,8DAA8D;IAC9Dd,cAAc,CAAC4B,OAAOJ;IAEtB,MAAMK,mBAAmB9B,mBAAmBA,CAAC;QAAEmB;IAAQ;IAEvD,mIAAmI;IACnI,oIAAoI;IACpIlB,kBAAkB,CAAC6B,iBAAiB,QAAQ,EAAE;QAC1C,CAAC1B,aAAaA,CAAC,EAAE0B,iBAAiB,QAAQ;QAC1C,CAACzB,gBAAgBA,CAAC,EAAEyB,iBAAiB,WAAW;IACpD;IAEA,IAAIX,SAAS;QACTlB,uBAAuB,CAAC8B,CAAAA;YACpBC,QAAQ,GAAG,CAAC,oDAAoDD;QACpE;IACJ;IAEA,0EAA0E;IAC1E,0EAA0E;IAC1E,kEAAkE;IAClE,8EAA8E;IAC9E,kFAAkF;IAClF,yBAAyB;IACzB,6DAA6D;IAC7D,aAAa;IACbE,UAAU,CAACvB,yBAAyB,GAAG;IAEvC,qFAAqF;IACrF,iFAAiF;IACjF,6DAA6D;IAC7D,aAAa;IACbuB,UAAU,CAACtB,kCAAkC,GAAGuB,CAAAA;QAC5CjC,uBAAuB,CAACiC;IAC5B;IAEA,kFAAkF;IAClFnC,qBAAqBA,GAAG,QAAQ,CAAC;QAAE,MAAM;IAAkB;IAE3D,IAAIoB,SAAS;QACTa,QAAQ,GAAG,CAAC;IAChB;AACJ"}
1
+ {"version":3,"file":"registerLogRocketInstrumentation.js","sources":["webpack://@workleap/logrocket/./src/registerLogRocketInstrumentation.ts"],"sourcesContent":["import { createCompositeLogger, type RootLogger } from \"@workleap/logging\";\nimport { createBootstrappingStore, createTelemetryContext } from \"@workleap/telemetry\";\nimport LogRocket from \"logrocket\";\nimport LogrocketFuzzySanitizer from \"logrocket-fuzzy-search-sanitizer\";\nimport { applyTransformers, type LogRocketSdkOptionsTransformer } from \"./applyTransformers.ts\";\nimport { DeviceIdTrait, TelemetryIdTrait } from \"./createDefaultUserTraits.ts\";\nimport { createRequestSanitizer } from \"./createRequestSanitizer.ts\";\nimport { createResponseSanitizer } from \"./createResponseSanitizer.ts\";\nimport { createUrlSanitizer } from \"./createUrlSanitizer.ts\";\nimport { HasExecutedGuard } from \"./HasExecutedGuard.ts\";\nimport type { LogRocketSdkOptions } from \"./logRocketTypes.ts\";\n\nexport const IsRegisteredVariableName = \"__WLP_LOGROCKET_INSTRUMENTATION_IS_REGISTERED__\";\nexport const RegisterGetSessionUrlFunctionName = \"__WLP_LOGROCKET_INSTRUMENTATION_REGISTER_GET_SESSION_URL_LISTENER__\";\n\nconst DefaultPrivateFieldNames = [\n \"email\",\n \"personalEmail\",\n \"phoneNumber\",\n \"password\",\n \"firstName\",\n \"lastName\",\n \"givenName\",\n \"fullName\",\n \"gender\",\n \"timeZone\",\n \"birthday\"\n];\n\nconst DefaultPrivateQueryParameterNames = [\n \"token\",\n \"email\",\n \"password\"\n];\n\n/**\n * @see {@link https://workleap.github.io/wl-telemetry}\n */\nexport interface RegisterLogRocketInstrumentationOptions {\n /**\n * A root hostname to track sessions across subdomains. Set this option to capture traffic from all subdomains under one session: https://docs.logrocket.com/reference/roothostname.\n */\n rootHostname?: LogRocketSdkOptions[\"rootHostname\"];\n /**\n * Names of additional fields to exclude from session replays. These fields will be removed from network requests, responses using a fuzzy-matching algorithm.\n */\n privateFieldNames?: string[];\n /**\n * Names of additional fields to exclude from session replays. These fields will be removed from query parameters using a fuzzy-matching algorithm.\n */\n privateQueryParameterNames?: string[];\n /**\n * Indicates whether or not debug information should be logged to the console.\n */\n verbose?: boolean;\n /**\n * The logger instances that will output messages.\n */\n loggers?: RootLogger[];\n /**\n * Hooks to transform the resulting LogRocket SDK options.\n */\n transformers?: LogRocketSdkOptionsTransformer[];\n}\n\n// The function return type is mandatory, otherwise we got an error TS4058.\nexport function getLogRocketSdkOptions(userOptions: RegisterLogRocketInstrumentationOptions, logger: RootLogger): LogRocketSdkOptions {\n const {\n rootHostname = \"workleap.com\",\n privateFieldNames = [],\n privateQueryParameterNames = [],\n verbose = false,\n transformers = []\n } = userOptions;\n\n const mergedPrivateFieldNames = DefaultPrivateFieldNames.concat(privateFieldNames);\n const mergedPrivateQueryParameterNames = DefaultPrivateQueryParameterNames.concat(privateQueryParameterNames);\n\n // The \"LogrocketFuzzySearch.setup\" code is awkward. For now, we prefer to play it safe and call it once here, then forward the sanitize functions\n // to the appropriate factories.\n // No clue why the \"setup\" method is not available. This package is shady.\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n const { requestSanitizer: fuzzyRequestSanitizer, responseSanitizer: fuzzyResponseSanitizer } = LogrocketFuzzySanitizer.setup(mergedPrivateFieldNames);\n\n const sdkOptions = {\n console: {\n // Prevent console logs from being visible in LogRocket session replays and leaking PII.\n // To capture logs in a session replay, use the LogRocketLogger class.\n isEnabled: false\n },\n rootHostname,\n dom: {\n textSanitizer: true,\n inputSanitizer: true\n },\n network: {\n requestSanitizer: createRequestSanitizer(fuzzyRequestSanitizer),\n responseSanitizer: createResponseSanitizer(fuzzyResponseSanitizer)\n },\n browser: {\n urlSanitizer: createUrlSanitizer(mergedPrivateQueryParameterNames)\n },\n shouldDebugLog: verbose\n } satisfies LogRocketSdkOptions;\n\n return applyTransformers(sdkOptions, transformers, {\n verbose,\n logger\n });\n}\n\nconst registrationGuard = new HasExecutedGuard();\n\n// This function should only be used by tests.\nexport function __resetRegistrationGuard() {\n registrationGuard.reset();\n}\n\n/**\n * @see {@link https://workleap.github.io/wl-telemetry}\n */\nexport function registerLogRocketInstrumentation(appId: string, options: RegisterLogRocketInstrumentationOptions = {}) {\n const {\n verbose = false,\n loggers = []\n } = options;\n\n const logger = createCompositeLogger(verbose, loggers);\n\n registrationGuard.throw(\"[logrocket] The LogRocket instrumentation has already been registered. Did you call the \\\"registerLogRocketInstrumentation\\\" function twice?\");\n\n const sdkOptions = getLogRocketSdkOptions(options, logger);\n\n // Session starts anonymously when LogRocket.init() is called.\n LogRocket.init(appId, sdkOptions);\n\n const telemetryContext = createTelemetryContext(logger);\n\n // LogRocket maintains the same session even if the user starts as anonymous and later becomes identified via LogRocket.identify().\n // If LogRocket.identify is called multiple times during a recording, you can search for any of the identified users in the session.\n LogRocket.identify(telemetryContext.deviceId, {\n [DeviceIdTrait]: telemetryContext.deviceId,\n [TelemetryIdTrait]: telemetryContext.telemetryId\n });\n\n LogRocket.getSessionURL(url => {\n logger\n .withText(\"[logrocket] Session replay URL is now available:\")\n .withText(url)\n .debug();\n });\n\n // Indicates to the host applications that logrocket has been initialized.\n // It's useful in cases where an \"add-on\", like the platform widgets needs\n // to know whether or not the host application is using LogRocket.\n // While there are ways that the host application could tell to an \"add-on\" if\n // it's using LogRocket or not, doing it this way is transparent for the consumer,\n // which is great for DX.\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n globalThis[IsRegisteredVariableName] = true;\n\n // While consumers could directly call LogRocket.getSessionURL, by doing it this way,\n // it allow consumers to not take a direct dependency on the \"logrocket\" package.\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n globalThis[RegisterGetSessionUrlFunctionName] = listener => {\n LogRocket.getSessionURL(listener);\n };\n\n const bootstrappingStore = createBootstrappingStore(logger);\n // Let the other telemetry libraries know that LogRocket instrumentation is ready.\n bootstrappingStore.dispatch({ type: \"logrocket-ready\" });\n\n logger.debug(\"[logrocket] LogRocket instrumentation is registered.\");\n}\n"],"names":["createCompositeLogger","createBootstrappingStore","createTelemetryContext","LogRocket","LogrocketFuzzySanitizer","applyTransformers","DeviceIdTrait","TelemetryIdTrait","createRequestSanitizer","createResponseSanitizer","createUrlSanitizer","HasExecutedGuard","IsRegisteredVariableName","RegisterGetSessionUrlFunctionName","DefaultPrivateFieldNames","DefaultPrivateQueryParameterNames","getLogRocketSdkOptions","userOptions","logger","rootHostname","privateFieldNames","privateQueryParameterNames","verbose","transformers","mergedPrivateFieldNames","mergedPrivateQueryParameterNames","fuzzyRequestSanitizer","fuzzyResponseSanitizer","sdkOptions","registrationGuard","__resetRegistrationGuard","registerLogRocketInstrumentation","appId","options","loggers","telemetryContext","url","globalThis","listener","bootstrappingStore"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAA2E;AACY;AACrD;AACqC;AACyB;AACjB;AACV;AACE;AACV;AACJ;AAGlD,MAAMY,2BAA2B,kDAAkD;AACnF,MAAMC,oCAAoC,sEAAsE;AAEvH,MAAMC,2BAA2B;IAC7B;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;CACH;AAED,MAAMC,oCAAoC;IACtC;IACA;IACA;CACH;AAgCD,2EAA2E;AACpE,SAASC,uBAAuBC,WAAoD,EAAEC,MAAkB;IAC3G,MAAM,EACFC,eAAe,cAAc,EAC7BC,oBAAoB,EAAE,EACtBC,6BAA6B,EAAE,EAC/BC,UAAU,KAAK,EACfC,eAAe,EAAE,EACpB,GAAGN;IAEJ,MAAMO,0BAA0BV,yBAAyB,MAAM,CAACM;IAChE,MAAMK,mCAAmCV,kCAAkC,MAAM,CAACM;IAElF,kJAAkJ;IAClJ,gCAAgC;IAChC,0EAA0E;IAC1E,6DAA6D;IAC7D,aAAa;IACb,MAAM,EAAE,kBAAkBK,qBAAqB,EAAE,mBAAmBC,sBAAsB,EAAE,GAAGvB,sCAA6B,CAACoB;IAE7H,MAAMI,aAAa;QACf,SAAS;YACL,wFAAwF;YACxF,sEAAsE;YACtE,WAAW;QACf;QACAT;QACA,KAAK;YACD,eAAe;YACf,gBAAgB;QACpB;QACA,SAAS;YACL,kBAAkBX,sBAAsBA,CAACkB;YACzC,mBAAmBjB,uBAAuBA,CAACkB;QAC/C;QACA,SAAS;YACL,cAAcjB,kBAAkBA,CAACe;QACrC;QACA,gBAAgBH;IACpB;IAEA,OAAOjB,iBAAiBA,CAACuB,YAAYL,cAAc;QAC/CD;QACAJ;IACJ;AACJ;AAEA,MAAMW,oBAAoB,IAAIlB,gBAAgBA;AAE9C,8CAA8C;AACvC,SAASmB;IACZD,kBAAkB,KAAK;AAC3B;AAEA;;CAEC,GACM,SAASE,iCAAiCC,KAAa,EAAEC,UAAmD,CAAC,CAAC;IACjH,MAAM,EACFX,UAAU,KAAK,EACfY,UAAU,EAAE,EACf,GAAGD;IAEJ,MAAMf,SAASlB,qBAAqBA,CAACsB,SAASY;IAE9CL,kBAAkB,KAAK,CAAC;IAExB,MAAMD,aAAaZ,uBAAuBiB,SAASf;IAEnD,8DAA8D;IAC9Df,cAAc,CAAC6B,OAAOJ;IAEtB,MAAMO,mBAAmBjC,sBAAsBA,CAACgB;IAEhD,mIAAmI;IACnI,oIAAoI;IACpIf,kBAAkB,CAACgC,iBAAiB,QAAQ,EAAE;QAC1C,CAAC7B,aAAaA,CAAC,EAAE6B,iBAAiB,QAAQ;QAC1C,CAAC5B,gBAAgBA,CAAC,EAAE4B,iBAAiB,WAAW;IACpD;IAEAhC,uBAAuB,CAACiC,CAAAA;QACpBlB,OACK,QAAQ,CAAC,oDACT,QAAQ,CAACkB,KACT,KAAK;IACd;IAEA,0EAA0E;IAC1E,0EAA0E;IAC1E,kEAAkE;IAClE,8EAA8E;IAC9E,kFAAkF;IAClF,yBAAyB;IACzB,6DAA6D;IAC7D,aAAa;IACbC,UAAU,CAACzB,yBAAyB,GAAG;IAEvC,qFAAqF;IACrF,iFAAiF;IACjF,6DAA6D;IAC7D,aAAa;IACbyB,UAAU,CAACxB,kCAAkC,GAAGyB,CAAAA;QAC5CnC,uBAAuB,CAACmC;IAC5B;IAEA,MAAMC,qBAAqBtC,wBAAwBA,CAACiB;IACpD,kFAAkF;IAClFqB,mBAAmB,QAAQ,CAAC;QAAE,MAAM;IAAkB;IAEtDrB,OAAO,KAAK,CAAC;AACjB"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@workleap/logrocket",
3
3
  "author": "Workleap",
4
- "version": "1.0.0",
4
+ "version": "1.1.0",
5
5
  "description": "A package containing utilities for LogRocket.",
6
6
  "license": "Apache-2.0",
7
7
  "repository": {
@@ -28,11 +28,12 @@
28
28
  "README.md"
29
29
  ],
30
30
  "peerDependencies": {
31
- "logrocket": "^10.1.0",
32
- "@workleap/telemetry": "1.0.0"
31
+ "logrocket": "^10.1.0"
33
32
  },
34
33
  "dependencies": {
35
- "logrocket-fuzzy-search-sanitizer": "0.0.2"
34
+ "@workleap/logging": "^1.0.2",
35
+ "logrocket-fuzzy-search-sanitizer": "0.0.2",
36
+ "@workleap/telemetry": "1.1.0"
36
37
  },
37
38
  "devDependencies": {
38
39
  "@rsbuild/core": "1.4.6",
@@ -0,0 +1,353 @@
1
+ import { type Logger, type LoggerOptions, type LoggerScope, type LoggerScopeEndOptions, LogLevel, type LogOptions, type Segment } from "@workleap/logging";
2
+ import LogRocket from "logrocket";
3
+
4
+ type LogFunction = (...rest: unknown[]) => void;
5
+ type PendingLog = () => void;
6
+
7
+ function parseSegments(segments: Segment[]) {
8
+ return segments.reduce<unknown[]>((acc, x) => {
9
+ if (x.text) {
10
+ acc.push(x.text);
11
+ } else if (x.obj) {
12
+ acc.push(x.obj);
13
+ } else if (x.error) {
14
+ acc.push(x.error);
15
+ }
16
+
17
+ return acc;
18
+ }, []);
19
+ }
20
+
21
+ /**
22
+ * An scope implementation for the LogRocket logger.
23
+ * @see {@link https://workleap.github.io/wl-telemetry}
24
+ */
25
+ export class LogRocketLoggerScope implements LoggerScope {
26
+ readonly #logLevel: LogLevel;
27
+ readonly #label: string;
28
+
29
+ #segments: Segment[] = [];
30
+ #pendingLogs: PendingLog[] = [];
31
+ #hasEnded: boolean = false;
32
+
33
+ /**
34
+ * @see {@link https://workleap.github.io/wl-logging}
35
+ */
36
+ constructor(label: string, logLevel: LogLevel) {
37
+ this.#logLevel = logLevel;
38
+ this.#label = label;
39
+ }
40
+
41
+ #resetSegments() {
42
+ this.#segments = [];
43
+ }
44
+
45
+ #log(fct: LogFunction, threshold: LogLevel) {
46
+ if (this.#segments.length > 0) {
47
+ if (this.#logLevel <= threshold) {
48
+ // Required closure to preserved the current log items for when they will be formatted when the scope is ended.
49
+ const segments = this.#segments;
50
+
51
+ this.#pendingLogs.push(() => {
52
+ const parsedSegments = parseSegments(segments);
53
+ parsedSegments.unshift(`(${this.#label})`);
54
+
55
+ fct(...parsedSegments);
56
+ });
57
+ }
58
+
59
+ this.#resetSegments();
60
+ }
61
+ }
62
+
63
+ /**
64
+ * @see {@link https://workleap.github.io/wl-logging}
65
+ */
66
+ withText(text: string, options: LogOptions = {}) {
67
+ this.#segments.push({
68
+ text,
69
+ options
70
+ });
71
+
72
+ return this;
73
+ }
74
+
75
+ /**
76
+ * @see {@link https://workleap.github.io/wl-logging}
77
+ */
78
+ withError(error: Error) {
79
+ this.#segments.push({
80
+ error
81
+ });
82
+
83
+ return this;
84
+ }
85
+
86
+ /**
87
+ * @see {@link https://workleap.github.io/wl-logging}
88
+ */
89
+ withObject(obj: object) {
90
+ this.#segments.push({
91
+ obj
92
+ });
93
+
94
+ return this;
95
+ }
96
+
97
+ /**
98
+ * Write a debug log. The log will be processed only if the logger LogLevel is >= debug.
99
+ * @see {@link https://workleap.github.io/wl-logging}
100
+ */
101
+ debug(log?: string, options?: LogOptions) {
102
+ if (log) {
103
+ this.#segments.push({
104
+ text: log,
105
+ options
106
+ });
107
+ }
108
+
109
+ this.#log(LogRocket.log, LogLevel.debug);
110
+ }
111
+
112
+ /**
113
+ * Write an information log. The log will be processed only if the logger LogLevel is >= information.
114
+ * @see {@link https://workleap.github.io/wl-logging}
115
+ */
116
+ information(log?: string, options?: LogOptions) {
117
+ if (log) {
118
+ this.#segments.push({
119
+ text: log,
120
+ options
121
+ });
122
+ }
123
+
124
+ this.#log(LogRocket.log, LogLevel.information);
125
+ }
126
+
127
+ /**
128
+ * Write a warning log. The log will be processed only if the logger LogLevel is >= warning.
129
+ * @see {@link https://workleap.github.io/wl-logging}
130
+ */
131
+ warning(log?: string, options?: LogOptions) {
132
+ if (log) {
133
+ this.#segments.push({
134
+ text: log,
135
+ options
136
+ });
137
+ }
138
+
139
+ this.#log(LogRocket.warn, LogLevel.warning);
140
+ }
141
+
142
+ /**
143
+ * Write an error log. The log will be processed only if the logger LogLevel is >= error.
144
+ * @see {@link https://workleap.github.io/wl-logging}
145
+ */
146
+ error(log?: string, options?: LogOptions) {
147
+ if (log) {
148
+ this.#segments.push({
149
+ text: log,
150
+ options
151
+ });
152
+ }
153
+
154
+ this.#log(LogRocket.error, LogLevel.error);
155
+ }
156
+
157
+ /**
158
+ * Write a critical log. The log will be processed only if the logger LogLevel is >= critical.
159
+ * @see {@link https://workleap.github.io/wl-logging}
160
+ */
161
+ critical(log?: string, options?: LogOptions) {
162
+ if (log) {
163
+ this.#segments.push({
164
+ text: log,
165
+ options
166
+ });
167
+ }
168
+
169
+ this.#log(LogRocket.error, LogLevel.critical);
170
+ }
171
+
172
+ /**
173
+ * @see {@link https://workleap.github.io/wl-logging}
174
+ */
175
+ end(options: LoggerScopeEndOptions = {}) {
176
+ const {
177
+ dismiss = false
178
+ } = options;
179
+
180
+ if (!this.#hasEnded) {
181
+ this.#hasEnded = true;
182
+
183
+ if (!dismiss) {
184
+ if (this.#pendingLogs.length > 0) {
185
+ this.#pendingLogs.forEach(x => {
186
+ x();
187
+ });
188
+
189
+ this.#pendingLogs = [];
190
+ }
191
+ }
192
+ }
193
+ }
194
+ }
195
+
196
+ /**
197
+ * A logger implementation for LogRocket.
198
+ * @see {@link https://workleap.github.io/wl-telemetry}
199
+ */
200
+ export class LogRocketLogger implements Logger {
201
+ readonly #logLevel: LogLevel;
202
+ #segments: Segment[] = [];
203
+
204
+ /**
205
+ * @see {@link https://workleap.github.io/wl-logging}
206
+ */
207
+ constructor(options: LoggerOptions = {}) {
208
+ const {
209
+ logLevel = LogLevel.debug
210
+ } = options;
211
+
212
+ this.#logLevel = logLevel;
213
+ }
214
+
215
+ #resetSegments() {
216
+ this.#segments = [];
217
+ }
218
+
219
+ #log(fct: LogFunction, threshold: LogLevel) {
220
+ if (this.#segments.length > 0) {
221
+ if (this.#logLevel <= threshold) {
222
+ const parsedSegments = parseSegments(this.#segments);
223
+
224
+ fct(...parsedSegments);
225
+ }
226
+
227
+ this.#resetSegments();
228
+ }
229
+ }
230
+
231
+ /**
232
+ * @see {@link https://workleap.github.io/wl-logging}
233
+ */
234
+ getName() {
235
+ return LogRocketLogger.name;
236
+ }
237
+
238
+ /**
239
+ * @see {@link https://workleap.github.io/wl-logging}
240
+ */
241
+ withText(text: string, options: LogOptions = {}) {
242
+ this.#segments.push({
243
+ text,
244
+ options
245
+ });
246
+
247
+ return this;
248
+ }
249
+
250
+ /**
251
+ * @see {@link https://workleap.github.io/wl-logging}
252
+ */
253
+ withError(error: Error) {
254
+ this.#segments.push({
255
+ error
256
+ });
257
+
258
+ return this;
259
+ }
260
+
261
+ /**
262
+ * @see {@link https://workleap.github.io/wl-logging}
263
+ */
264
+ withObject(obj: object) {
265
+ this.#segments.push({
266
+ obj
267
+ });
268
+
269
+ return this;
270
+ }
271
+
272
+ /**
273
+ * Write a debug log. The log will be processed only if the logger LogLevel is >= debug.
274
+ * @see {@link https://workleap.github.io/wl-logging}
275
+ */
276
+ debug(log?: string, options?: LogOptions) {
277
+ if (log) {
278
+ this.#segments.push({
279
+ text: log,
280
+ options
281
+ });
282
+ }
283
+
284
+ this.#log(LogRocket.log, LogLevel.debug);
285
+ }
286
+
287
+ /**
288
+ * Write an information log. The log will be processed only if the logger LogLevel is >= information.
289
+ * @see {@link https://workleap.github.io/wl-logging}
290
+ */
291
+ information(log?: string, options?: LogOptions) {
292
+ if (log) {
293
+ this.#segments.push({
294
+ text: log,
295
+ options
296
+ });
297
+ }
298
+
299
+ this.#log(LogRocket.log, LogLevel.information);
300
+ }
301
+
302
+ /**
303
+ * Write a warning log. The log will be processed only if the logger LogLevel is >= warning.
304
+ * @see {@link https://workleap.github.io/wl-logging}
305
+ */
306
+ warning(log?: string, options?: LogOptions) {
307
+ if (log) {
308
+ this.#segments.push({
309
+ text: log,
310
+ options
311
+ });
312
+ }
313
+
314
+ this.#log(LogRocket.warn, LogLevel.warning);
315
+ }
316
+
317
+ /**
318
+ * Write an error log. The log will be processed only if the logger LogLevel is >= error.
319
+ * @see {@link https://workleap.github.io/wl-logging}
320
+ */
321
+ error(log?: string, options?: LogOptions) {
322
+ if (log) {
323
+ this.#segments.push({
324
+ text: log,
325
+ options
326
+ });
327
+ }
328
+
329
+ this.#log(LogRocket.error, LogLevel.error);
330
+ }
331
+
332
+ /**
333
+ * Write a critical log. The log will be processed only if the logger LogLevel is >= critical.
334
+ * @see {@link https://workleap.github.io/wl-logging}
335
+ */
336
+ critical(log?: string, options?: LogOptions) {
337
+ if (log) {
338
+ this.#segments.push({
339
+ text: log,
340
+ options
341
+ });
342
+ }
343
+
344
+ this.#log(LogRocket.error, LogLevel.critical);
345
+ }
346
+
347
+ /**
348
+ * @see {@link https://workleap.github.io/wl-logging}
349
+ */
350
+ startScope(label: string) {
351
+ return new LogRocketLoggerScope(label, this.#logLevel);
352
+ }
353
+ }
@@ -1,12 +1,18 @@
1
+ import type { RootLogger } from "@workleap/logging";
1
2
  import type { LogRocketSdkOptions } from "./logRocketTypes.ts";
2
3
 
3
4
  /**
4
- * @see https://workleap.github.io/wl-telemetry
5
+ * @see {@link https://workleap.github.io/wl-telemetry}
5
6
  */
6
7
  export interface LogRocketSdkOptionsTransformerContext {
7
8
  verbose: boolean;
9
+ logger: RootLogger;
8
10
  }
9
11
 
12
+ /**
13
+ * Hook to transform the resulting LogRocket SDK options.
14
+ * @see {@link https://workleap.github.io/wl-telemetry}
15
+ */
10
16
  export type LogRocketSdkOptionsTransformer = (options: LogRocketSdkOptions, context: LogRocketSdkOptionsTransformerContext) => LogRocketSdkOptions;
11
17
 
12
18
  // The function return type is mandatory, otherwise we got an error TS4058.
@@ -2,7 +2,7 @@ import { getTelemetryContext } from "@workleap/telemetry";
2
2
  import { isDefined } from "./assertions.ts";
3
3
 
4
4
  /**
5
- * @see https://workleap.github.io/wl-telemetry
5
+ * @see {@link https://workleap.github.io/wl-telemetry}
6
6
  */
7
7
  export interface LogRocketIdentification {
8
8
  userId: string;
@@ -40,7 +40,7 @@ export interface LogRocketIdentification {
40
40
  }
41
41
 
42
42
  /**
43
- * @see https://workleap.github.io/wl-telemetry
43
+ * @see {@link https://workleap.github.io/wl-telemetry}
44
44
  */
45
45
  export interface LogRocketUserTraits extends Record<string, unknown> {
46
46
  "User Id": string;
@@ -79,7 +79,8 @@ export const DeviceIdTrait = "Device Id";
79
79
  export const TelemetryIdTrait = "Telemetry Id";
80
80
 
81
81
  /**
82
- * @see https://workleap.github.io/wl-telemetry
82
+ * Create the default user traits for a WLP user.
83
+ * @see {@link https://workleap.github.io/wl-telemetry}
83
84
  */
84
85
  export function createDefaultUserTraits(identification: LogRocketIdentification) {
85
86
  const {
package/src/index.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export type { LogRocketSdkOptionsTransformer } from "./applyTransformers.ts";
2
2
  export { createDefaultUserTraits, type LogRocketIdentification, type LogRocketUserTraits } from "./createDefaultUserTraits.ts";
3
+ export { LogRocketLogger, LogRocketLoggerScope } from "./LogRocketLogger.ts";
3
4
  export type * from "./logRocketTypes.ts";
4
5
  export { registerLogRocketInstrumentation } from "./registerLogRocketInstrumentation.ts";
5
6