@servicetitan/log-service 37.0.2 → 38.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.
@@ -6,19 +6,26 @@ function _define_property(obj, key, value) {
6
6
  configurable: true,
7
7
  writable: true
8
8
  });
9
- } else {
10
- obj[key] = value;
11
- }
9
+ } else obj[key] = value;
12
10
  return obj;
13
11
  }
14
12
  function _ts_decorate(decorators, target, key, desc) {
15
13
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
16
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
17
- else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
14
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
15
+ r = Reflect.decorate(decorators, target, key, desc);
16
+ } else {
17
+ for(var i = decorators.length - 1; i >= 0; i--){
18
+ if (d = decorators[i]) {
19
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
20
+ }
21
+ }
22
+ }
18
23
  return c > 3 && r && Object.defineProperty(target, key, r), r;
19
24
  }
20
- function _ts_metadata(k, v) {
21
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
25
+ function _ts_metadata(metadataKey, metadataValue) {
26
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
27
+ return Reflect.metadata(metadataKey, metadataValue);
28
+ }
22
29
  }
23
30
  import { injectable } from '@servicetitan/react-ioc';
24
31
  import { action, makeObservable, observable } from 'mobx';
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/connection-service.ts"],"sourcesContent":["import { injectable } from '@servicetitan/react-ioc';\nimport { action, makeObservable, observable } from 'mobx';\n\n@injectable()\nexport class ConnectionService {\n @observable\n online: boolean = window.navigator.onLine;\n\n constructor() {\n makeObservable(this);\n\n window.addEventListener('online', () => this.setOnline(true));\n window.addEventListener('offline', () => this.setOnline(false));\n }\n\n @action\n setOnline(status: boolean) {\n this.online = status;\n }\n}\n"],"names":["injectable","action","makeObservable","observable","ConnectionService","setOnline","status","online","window","navigator","onLine","addEventListener"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAAA,SAASA,UAAU,QAAQ,0BAA0B;AACrD,SAASC,MAAM,EAAEC,cAAc,EAAEC,UAAU,QAAQ,OAAO;AAG1D,OAAO,MAAMC;IAYTC,UAAUC,MAAe,EAAE;QACvB,IAAI,CAACC,MAAM,GAAGD;IAClB;IAVA,aAAc;QAHd,uBACAC,UAAkBC,OAAOC,SAAS,CAACC,MAAM;QAGrCR,eAAe,IAAI;QAEnBM,OAAOG,gBAAgB,CAAC,UAAU,IAAM,IAAI,CAACN,SAAS,CAAC;QACvDG,OAAOG,gBAAgB,CAAC,WAAW,IAAM,IAAI,CAACN,SAAS,CAAC;IAC5D;AAMJ"}
1
+ {"version":3,"sources":["../src/connection-service.ts"],"sourcesContent":["import { injectable } from '@servicetitan/react-ioc';\nimport { action, makeObservable, observable } from 'mobx';\n\n@injectable()\nexport class ConnectionService {\n @observable\n online: boolean = window.navigator.onLine;\n\n constructor() {\n makeObservable(this);\n\n window.addEventListener('online', () => this.setOnline(true));\n window.addEventListener('offline', () => this.setOnline(false));\n }\n\n @action\n setOnline(status: boolean) {\n this.online = status;\n }\n}\n"],"names":["injectable","action","makeObservable","observable","ConnectionService","setOnline","status","online","window","navigator","onLine","addEventListener"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAASA,UAAU,QAAQ,0BAA0B;AACrD,SAASC,MAAM,EAAEC,cAAc,EAAEC,UAAU,QAAQ,OAAO;AAG1D,OAAO,MAAMC;IAYTC,UAAUC,MAAe,EAAE;QACvB,IAAI,CAACC,MAAM,GAAGD;IAClB;IAVA,aAAc;QAHd,uBACAC,UAAkBC,OAAOC,SAAS,CAACC,MAAM;QAGrCR,eAAe,IAAI;QAEnBM,OAAOG,gBAAgB,CAAC,UAAU,IAAM,IAAI,CAACN,SAAS,CAAC;QACvDG,OAAOG,gBAAgB,CAAC,WAAW,IAAM,IAAI,CAACN,SAAS,CAAC;IAC5D;AAMJ"}
@@ -6,19 +6,26 @@ function _define_property(obj, key, value) {
6
6
  configurable: true,
7
7
  writable: true
8
8
  });
9
- } else {
10
- obj[key] = value;
11
- }
9
+ } else obj[key] = value;
12
10
  return obj;
13
11
  }
14
12
  function _ts_decorate(decorators, target, key, desc) {
15
13
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
16
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
17
- else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
14
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
15
+ r = Reflect.decorate(decorators, target, key, desc);
16
+ } else {
17
+ for(var i = decorators.length - 1; i >= 0; i--){
18
+ if (d = decorators[i]) {
19
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
20
+ }
21
+ }
22
+ }
18
23
  return c > 3 && r && Object.defineProperty(target, key, r), r;
19
24
  }
20
- function _ts_metadata(k, v) {
21
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
25
+ function _ts_metadata(metadataKey, metadataValue) {
26
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
27
+ return Reflect.metadata(metadataKey, metadataValue);
28
+ }
22
29
  }
23
30
  function _ts_param(paramIndex, decorator) {
24
31
  return function(target, key) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/global-error-handler.ts"],"sourcesContent":["import { inject, injectable } from '@servicetitan/react-ioc';\nimport { ArbitraryData, Log } from './log';\nimport { serializeWithMetadata } from './serialize-with-metadata';\n\ninterface ExtendedError extends Error {\n category?: string;\n code?: string;\n data?: ArbitraryData;\n stack?: string;\n}\n\n@injectable()\nexport class GlobalErrorHandler {\n constructor(@inject(Log) private readonly logService: Log) {}\n\n instrument(window: Window) {\n consolidate(window, 'onerror', this.onError);\n consolidate(window, 'onunhandledrejection', this.onReject);\n }\n\n onError = (\n message: string,\n url?: string,\n line?: number,\n column?: number,\n error?: Error,\n isUnhandled = true\n ) => {\n try {\n if (this.isIgnorable(message)) {\n return;\n }\n let msg = '';\n if (typeof message === 'string') {\n msg = message;\n } else {\n /*\n * By specification message is always a string\n * this condition covers manual nonuniform window.onerror call\n */\n msg = serializeWithMetadata(message);\n }\n\n let err: ExtendedError;\n if (error instanceof Error) {\n err = error;\n } else {\n const errorMessage = `Message - ${msg}${\n error ? ';Error - ' + serializeWithMetadata(error) : ''\n }`;\n err = new Error(errorMessage);\n err.stack += `\\n\\tat somewhere (${url}:${line}:${column})`;\n err.code = 'NonUniform';\n }\n if (isUnhandled) {\n err.category ??= 'UnhandledError';\n err.code ??= 'UnhandledError';\n }\n\n this.dispatch(err);\n } catch (e) {\n // eslint-disable-next-line no-console\n console.error('@log-service/onError/failsafe', message);\n // eslint-disable-next-line no-console\n console.error('@log-service/onError/failsafe', e);\n }\n };\n\n onReject = (event: { reason: unknown }) => {\n try {\n const error = event.reason;\n let err: ExtendedError;\n if (error instanceof Error) {\n err = error;\n } else {\n const errorMessage = `Unhandled rejection - ${serializeWithMetadata(error)}`;\n err = new Error(errorMessage);\n err.code = 'NonUniform';\n }\n\n this.dispatch(err);\n } catch (e) {\n // eslint-disable-next-line no-console\n console.error('@log-service/onReject/failsafe', e);\n }\n };\n\n private dispatch(error: ExtendedError) {\n this.logService.error(\n {\n error,\n category: error.category,\n code: error.code,\n message: error.message,\n data: error.data,\n },\n { skipConsole: true }\n );\n }\n\n private isIgnorable(message: string) {\n if (typeof message !== 'string') {\n return false;\n }\n\n const ignoreSubstrings = [\n // 'Script error.', // cross-domain\n 'gCrWeb',\n 'Geolocation',\n 'kCLErrorDomain',\n 'The last location provider was disabled',\n 'Location services are disabled',\n ];\n\n return ignoreSubstrings.some(sub => message.includes(sub));\n }\n}\n\nfunction consolidate(object: { [key: string]: any }, methodName: string, fn: Function) {\n if (typeof object[methodName] === 'function') {\n const fnPrev = object[methodName];\n\n object[methodName] = (...args: unknown[]) => {\n try {\n fn(...args);\n } finally {\n fnPrev(...args);\n }\n };\n return;\n }\n if (object[methodName] != null) {\n throw new TypeError('attempt to instrument non-function value');\n }\n\n object[methodName] = fn;\n}\n"],"names":["inject","injectable","Log","serializeWithMetadata","GlobalErrorHandler","instrument","window","consolidate","onError","onReject","dispatch","error","logService","category","code","message","data","skipConsole","isIgnorable","ignoreSubstrings","some","sub","includes","url","line","column","isUnhandled","msg","err","Error","errorMessage","stack","e","console","event","reason","object","methodName","fn","fnPrev","args","TypeError"],"mappings":"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"}
1
+ {"version":3,"sources":["../src/global-error-handler.ts"],"sourcesContent":["import { inject, injectable } from '@servicetitan/react-ioc';\nimport { ArbitraryData, Log } from './log';\nimport { serializeWithMetadata } from './serialize-with-metadata';\n\ninterface ExtendedError extends Error {\n category?: string;\n code?: string;\n data?: ArbitraryData;\n stack?: string;\n}\n\n@injectable()\nexport class GlobalErrorHandler {\n constructor(@inject(Log) private readonly logService: Log) {}\n\n instrument(window: Window) {\n consolidate(window, 'onerror', this.onError);\n consolidate(window, 'onunhandledrejection', this.onReject);\n }\n\n onError = (\n message: string,\n url?: string,\n line?: number,\n column?: number,\n error?: Error,\n isUnhandled = true\n ) => {\n try {\n if (this.isIgnorable(message)) {\n return;\n }\n let msg = '';\n if (typeof message === 'string') {\n msg = message;\n } else {\n /*\n * By specification message is always a string\n * this condition covers manual nonuniform window.onerror call\n */\n msg = serializeWithMetadata(message);\n }\n\n let err: ExtendedError;\n if (error instanceof Error) {\n err = error;\n } else {\n const errorMessage = `Message - ${msg}${\n error ? ';Error - ' + serializeWithMetadata(error) : ''\n }`;\n err = new Error(errorMessage);\n err.stack += `\\n\\tat somewhere (${url}:${line}:${column})`;\n err.code = 'NonUniform';\n }\n if (isUnhandled) {\n err.category ??= 'UnhandledError';\n err.code ??= 'UnhandledError';\n }\n\n this.dispatch(err);\n } catch (e) {\n // eslint-disable-next-line no-console\n console.error('@log-service/onError/failsafe', message);\n // eslint-disable-next-line no-console\n console.error('@log-service/onError/failsafe', e);\n }\n };\n\n onReject = (event: { reason: unknown }) => {\n try {\n const error = event.reason;\n let err: ExtendedError;\n if (error instanceof Error) {\n err = error;\n } else {\n const errorMessage = `Unhandled rejection - ${serializeWithMetadata(error)}`;\n err = new Error(errorMessage);\n err.code = 'NonUniform';\n }\n\n this.dispatch(err);\n } catch (e) {\n // eslint-disable-next-line no-console\n console.error('@log-service/onReject/failsafe', e);\n }\n };\n\n private dispatch(error: ExtendedError) {\n this.logService.error(\n {\n error,\n category: error.category,\n code: error.code,\n message: error.message,\n data: error.data,\n },\n { skipConsole: true }\n );\n }\n\n private isIgnorable(message: string) {\n if (typeof message !== 'string') {\n return false;\n }\n\n const ignoreSubstrings = [\n // 'Script error.', // cross-domain\n 'gCrWeb',\n 'Geolocation',\n 'kCLErrorDomain',\n 'The last location provider was disabled',\n 'Location services are disabled',\n ];\n\n return ignoreSubstrings.some(sub => message.includes(sub));\n }\n}\n\nfunction consolidate(object: { [key: string]: any }, methodName: string, fn: Function) {\n if (typeof object[methodName] === 'function') {\n const fnPrev = object[methodName];\n\n object[methodName] = (...args: unknown[]) => {\n try {\n fn(...args);\n } finally {\n fnPrev(...args);\n }\n };\n return;\n }\n if (object[methodName] != null) {\n throw new TypeError('attempt to instrument non-function value');\n }\n\n object[methodName] = fn;\n}\n"],"names":["inject","injectable","Log","serializeWithMetadata","GlobalErrorHandler","instrument","window","consolidate","onError","onReject","dispatch","error","logService","category","code","message","data","skipConsole","isIgnorable","ignoreSubstrings","some","sub","includes","url","line","column","isUnhandled","msg","err","Error","errorMessage","stack","e","console","event","reason","object","methodName","fn","fnPrev","args","TypeError"],"mappings":"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"}
@@ -6,19 +6,26 @@ function _define_property(obj, key, value) {
6
6
  configurable: true,
7
7
  writable: true
8
8
  });
9
- } else {
10
- obj[key] = value;
11
- }
9
+ } else obj[key] = value;
12
10
  return obj;
13
11
  }
14
12
  function _ts_decorate(decorators, target, key, desc) {
15
13
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
16
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
17
- else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
14
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
15
+ r = Reflect.decorate(decorators, target, key, desc);
16
+ } else {
17
+ for(var i = decorators.length - 1; i >= 0; i--){
18
+ if (d = decorators[i]) {
19
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
20
+ }
21
+ }
22
+ }
18
23
  return c > 3 && r && Object.defineProperty(target, key, r), r;
19
24
  }
20
- function _ts_metadata(k, v) {
21
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
25
+ function _ts_metadata(metadataKey, metadataValue) {
26
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
27
+ return Reflect.metadata(metadataKey, metadataValue);
28
+ }
22
29
  }
23
30
  function _ts_param(paramIndex, decorator) {
24
31
  return function(target, key) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/log-sender.ts"],"sourcesContent":["import { inject, injectable, Store } from '@servicetitan/react-ioc';\nimport axios from 'axios';\nimport { IReactionDisposer, reaction } from 'mobx';\nimport { ConnectionService } from './connection-service';\nimport type { LogConfig } from './log';\nimport { Log, LOG_CONFIG_TOKEN } from './log';\nimport { lastId, LogStorage, StorageItem } from './log-storage';\n\nconst SECOND = 1000;\nconst DEFAULT_SEND_INTERVAL = 60 * SECOND;\nconst INITIAL_RETRY_INTERVAL = SECOND;\nconst MAX_RETRY_INTERVAL = INITIAL_RETRY_INTERVAL * 512;\nconst BATCH_SIZE = 128;\n\n@injectable()\nexport class LogSender extends Store {\n private inSendFailedScenario = false;\n private isSending = false;\n private onItemsChangedDisposer?: IReactionDisposer;\n private sendInterval = DEFAULT_SEND_INTERVAL;\n private intervalId?: number;\n\n constructor(\n @inject(ConnectionService) readonly connectionService: ConnectionService,\n @inject(LogStorage) readonly logStorage: LogStorage,\n @inject(LOG_CONFIG_TOKEN) private readonly logConfig: LogConfig,\n @inject(Log) readonly log: Log\n ) {\n super();\n this.setRegularSendScenario();\n }\n\n dispose() {\n window.clearInterval(this.intervalId);\n }\n\n private onItemsChanged(items: StorageItem[]) {\n if (items.length >= BATCH_SIZE) {\n this.send();\n }\n }\n\n private setSendInterval(interval: number) {\n this.sendInterval = interval;\n window.clearInterval(this.intervalId);\n this.intervalId = window.setInterval(() => {\n if (this.logStorage.items.length > 0) {\n this.send();\n }\n }, interval);\n }\n\n private send() {\n // If offline, punt\n if (!this.connectionService.online) {\n return;\n }\n\n /*\n * Using Web Locks API to prevent multiple tabs from simultaneously\n * sending previously saved items. If the API isn't available, ¯\\_(ツ)_/¯\n */\n if (!('locks' in globalThis.navigator)) {\n this.sendEvents();\n return;\n }\n\n // eslint-disable-next-line no-restricted-globals\n navigator.locks.request(this.logConfig.storageKey, { ifAvailable: true }, async lock => {\n if (lock) {\n await this.sendEvents();\n }\n });\n }\n\n private async sendEvents() {\n if (this.isSending) {\n return;\n }\n\n this.isSending = true;\n try {\n const logEvents = this.logStorage.loadBatch(BATCH_SIZE);\n if (logEvents.length) {\n await axios.post(this.logConfig.endpoint, logEvents);\n this.logStorage.deleteToId(lastId(logEvents));\n\n if (this.inSendFailedScenario) {\n this.setRegularSendScenario();\n }\n }\n } catch (e) {\n this.setFailedSendScenario();\n /* istanbul ignore next */\n if (process.env.NODE_ENV !== 'test') {\n throw e;\n }\n } finally {\n this.isSending = false;\n }\n }\n\n private setRegularSendScenario() {\n this.inSendFailedScenario = false;\n this.setSendInterval(DEFAULT_SEND_INTERVAL);\n this.onItemsChangedDisposer = reaction(\n () => this.logStorage.items,\n items => this.onItemsChanged(items)\n );\n }\n\n private setFailedSendScenario() {\n if (this.inSendFailedScenario) {\n this.increaseSendInterval();\n return;\n }\n\n this.inSendFailedScenario = true;\n this.setSendInterval(INITIAL_RETRY_INTERVAL);\n this.onItemsChangedDisposer?.();\n }\n\n private increaseSendInterval() {\n if (this.sendInterval < MAX_RETRY_INTERVAL) {\n this.setSendInterval(this.sendInterval * 2);\n }\n }\n}\n"],"names":["inject","injectable","Store","axios","reaction","ConnectionService","Log","LOG_CONFIG_TOKEN","lastId","LogStorage","SECOND","DEFAULT_SEND_INTERVAL","INITIAL_RETRY_INTERVAL","MAX_RETRY_INTERVAL","BATCH_SIZE","LogSender","dispose","window","clearInterval","intervalId","onItemsChanged","items","length","send","setSendInterval","interval","sendInterval","setInterval","logStorage","connectionService","online","globalThis","navigator","sendEvents","locks","request","logConfig","storageKey","ifAvailable","lock","isSending","logEvents","loadBatch","post","endpoint","deleteToId","inSendFailedScenario","setRegularSendScenario","e","setFailedSendScenario","process","env","NODE_ENV","onItemsChangedDisposer","increaseSendInterval","log"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAASA,MAAM,EAAEC,UAAU,EAAEC,KAAK,QAAQ,0BAA0B;AACpE,OAAOC,WAAW,QAAQ;AAC1B,SAA4BC,QAAQ,QAAQ,OAAO;AACnD,SAASC,iBAAiB,QAAQ,uBAAuB;AAEzD,SAASC,GAAG,EAAEC,gBAAgB,QAAQ,QAAQ;AAC9C,SAASC,MAAM,EAAEC,UAAU,QAAqB,gBAAgB;AAEhE,MAAMC,SAAS;AACf,MAAMC,wBAAwB,KAAKD;AACnC,MAAME,yBAAyBF;AAC/B,MAAMG,qBAAqBD,yBAAyB;AACpD,MAAME,aAAa;AAGnB,OAAO,MAAMC,kBAAkBb;IAiB3Bc,UAAU;QACNC,OAAOC,aAAa,CAAC,IAAI,CAACC,UAAU;IACxC;IAEQC,eAAeC,KAAoB,EAAE;QACzC,IAAIA,MAAMC,MAAM,IAAIR,YAAY;YAC5B,IAAI,CAACS,IAAI;QACb;IACJ;IAEQC,gBAAgBC,QAAgB,EAAE;QACtC,IAAI,CAACC,YAAY,GAAGD;QACpBR,OAAOC,aAAa,CAAC,IAAI,CAACC,UAAU;QACpC,IAAI,CAACA,UAAU,GAAGF,OAAOU,WAAW,CAAC;YACjC,IAAI,IAAI,CAACC,UAAU,CAACP,KAAK,CAACC,MAAM,GAAG,GAAG;gBAClC,IAAI,CAACC,IAAI;YACb;QACJ,GAAGE;IACP;IAEQF,OAAO;QACX,mBAAmB;QACnB,IAAI,CAAC,IAAI,CAACM,iBAAiB,CAACC,MAAM,EAAE;YAChC;QACJ;QAEA;;;SAGC,GACD,IAAI,CAAE,CAAA,WAAWC,WAAWC,SAAS,AAAD,GAAI;YACpC,IAAI,CAACC,UAAU;YACf;QACJ;QAEA,iDAAiD;QACjDD,UAAUE,KAAK,CAACC,OAAO,CAAC,IAAI,CAACC,SAAS,CAACC,UAAU,EAAE;YAAEC,aAAa;QAAK,GAAG,OAAMC;YAC5E,IAAIA,MAAM;gBACN,MAAM,IAAI,CAACN,UAAU;YACzB;QACJ;IACJ;IAEA,MAAcA,aAAa;QACvB,IAAI,IAAI,CAACO,SAAS,EAAE;YAChB;QACJ;QAEA,IAAI,CAACA,SAAS,GAAG;QACjB,IAAI;YACA,MAAMC,YAAY,IAAI,CAACb,UAAU,CAACc,SAAS,CAAC5B;YAC5C,IAAI2B,UAAUnB,MAAM,EAAE;gBAClB,MAAMnB,MAAMwC,IAAI,CAAC,IAAI,CAACP,SAAS,CAACQ,QAAQ,EAAEH;gBAC1C,IAAI,CAACb,UAAU,CAACiB,UAAU,CAACrC,OAAOiC;gBAElC,IAAI,IAAI,CAACK,oBAAoB,EAAE;oBAC3B,IAAI,CAACC,sBAAsB;gBAC/B;YACJ;QACJ,EAAE,OAAOC,GAAG;YACR,IAAI,CAACC,qBAAqB;YAC1B,wBAAwB,GACxB,IAAIC,QAAQC,GAAG,CAACC,QAAQ,KAAK,QAAQ;gBACjC,MAAMJ;YACV;QACJ,SAAU;YACN,IAAI,CAACR,SAAS,GAAG;QACrB;IACJ;IAEQO,yBAAyB;QAC7B,IAAI,CAACD,oBAAoB,GAAG;QAC5B,IAAI,CAACtB,eAAe,CAACb;QACrB,IAAI,CAAC0C,sBAAsB,GAAGjD,SAC1B,IAAM,IAAI,CAACwB,UAAU,CAACP,KAAK,EAC3BA,CAAAA,QAAS,IAAI,CAACD,cAAc,CAACC;IAErC;IAEQ4B,wBAAwB;YAQ5B,8BAAA;QAPA,IAAI,IAAI,CAACH,oBAAoB,EAAE;YAC3B,IAAI,CAACQ,oBAAoB;YACzB;QACJ;QAEA,IAAI,CAACR,oBAAoB,GAAG;QAC5B,IAAI,CAACtB,eAAe,CAACZ;SACrB,+BAAA,CAAA,QAAA,IAAI,EAACyC,sBAAsB,cAA3B,mDAAA,kCAAA;IACJ;IAEQC,uBAAuB;QAC3B,IAAI,IAAI,CAAC5B,YAAY,GAAGb,oBAAoB;YACxC,IAAI,CAACW,eAAe,CAAC,IAAI,CAACE,YAAY,GAAG;QAC7C;IACJ;IAxGA,YACI,AAAoCG,iBAAoC,EACxE,AAA6BD,UAAsB,EACnD,AAA2CQ,SAAoB,EAC/D,AAAsBmB,GAAQ,CAChC;QACE,KAAK,2LAZT,uBAAQT,wBAAR,KAAA,IACA,uBAAQN,aAAR,KAAA,IACA,uBAAQa,0BAAR,KAAA,IACA,uBAAQ3B,gBAAR,KAAA,IACA,uBAAQP,cAAR,KAAA,SAGwCU,oBAAAA,wBACPD,aAAAA,iBACcQ,YAAAA,gBACrBmB,MAAAA,UAVlBT,uBAAuB,YACvBN,YAAY,YAEZd,eAAef;QAUnB,IAAI,CAACoC,sBAAsB;IAC/B;AAiGJ"}
1
+ {"version":3,"sources":["../src/log-sender.ts"],"sourcesContent":["import { inject, injectable, Store } from '@servicetitan/react-ioc';\nimport axios from 'axios';\nimport { IReactionDisposer, reaction } from 'mobx';\nimport { ConnectionService } from './connection-service';\nimport type { LogConfig } from './log';\nimport { Log, LOG_CONFIG_TOKEN } from './log';\nimport { lastId, LogStorage, StorageItem } from './log-storage';\n\nconst SECOND = 1000;\nconst DEFAULT_SEND_INTERVAL = 60 * SECOND;\nconst INITIAL_RETRY_INTERVAL = SECOND;\nconst MAX_RETRY_INTERVAL = INITIAL_RETRY_INTERVAL * 512;\nconst BATCH_SIZE = 128;\n\n@injectable()\nexport class LogSender extends Store {\n private inSendFailedScenario = false;\n private isSending = false;\n private onItemsChangedDisposer?: IReactionDisposer;\n private sendInterval = DEFAULT_SEND_INTERVAL;\n private intervalId?: number;\n\n constructor(\n @inject(ConnectionService) readonly connectionService: ConnectionService,\n @inject(LogStorage) readonly logStorage: LogStorage,\n @inject(LOG_CONFIG_TOKEN) private readonly logConfig: LogConfig,\n @inject(Log) readonly log: Log\n ) {\n super();\n this.setRegularSendScenario();\n }\n\n dispose() {\n window.clearInterval(this.intervalId);\n }\n\n private onItemsChanged(items: StorageItem[]) {\n if (items.length >= BATCH_SIZE) {\n this.send();\n }\n }\n\n private setSendInterval(interval: number) {\n this.sendInterval = interval;\n window.clearInterval(this.intervalId);\n this.intervalId = window.setInterval(() => {\n if (this.logStorage.items.length > 0) {\n this.send();\n }\n }, interval);\n }\n\n private send() {\n // If offline, punt\n if (!this.connectionService.online) {\n return;\n }\n\n /*\n * Using Web Locks API to prevent multiple tabs from simultaneously\n * sending previously saved items. If the API isn't available, ¯\\_(ツ)_/¯\n */\n if (!('locks' in globalThis.navigator)) {\n this.sendEvents();\n return;\n }\n\n // eslint-disable-next-line no-restricted-globals\n navigator.locks.request(this.logConfig.storageKey, { ifAvailable: true }, async lock => {\n if (lock) {\n await this.sendEvents();\n }\n });\n }\n\n private async sendEvents() {\n if (this.isSending) {\n return;\n }\n\n this.isSending = true;\n try {\n const logEvents = this.logStorage.loadBatch(BATCH_SIZE);\n if (logEvents.length) {\n await axios.post(this.logConfig.endpoint, logEvents);\n this.logStorage.deleteToId(lastId(logEvents));\n\n if (this.inSendFailedScenario) {\n this.setRegularSendScenario();\n }\n }\n } catch (e) {\n this.setFailedSendScenario();\n /* istanbul ignore next */\n if (process.env.NODE_ENV !== 'test') {\n throw e;\n }\n } finally {\n this.isSending = false;\n }\n }\n\n private setRegularSendScenario() {\n this.inSendFailedScenario = false;\n this.setSendInterval(DEFAULT_SEND_INTERVAL);\n this.onItemsChangedDisposer = reaction(\n () => this.logStorage.items,\n items => this.onItemsChanged(items)\n );\n }\n\n private setFailedSendScenario() {\n if (this.inSendFailedScenario) {\n this.increaseSendInterval();\n return;\n }\n\n this.inSendFailedScenario = true;\n this.setSendInterval(INITIAL_RETRY_INTERVAL);\n this.onItemsChangedDisposer?.();\n }\n\n private increaseSendInterval() {\n if (this.sendInterval < MAX_RETRY_INTERVAL) {\n this.setSendInterval(this.sendInterval * 2);\n }\n }\n}\n"],"names":["inject","injectable","Store","axios","reaction","ConnectionService","Log","LOG_CONFIG_TOKEN","lastId","LogStorage","SECOND","DEFAULT_SEND_INTERVAL","INITIAL_RETRY_INTERVAL","MAX_RETRY_INTERVAL","BATCH_SIZE","LogSender","dispose","window","clearInterval","intervalId","onItemsChanged","items","length","send","setSendInterval","interval","sendInterval","setInterval","logStorage","connectionService","online","globalThis","navigator","sendEvents","locks","request","logConfig","storageKey","ifAvailable","lock","isSending","logEvents","loadBatch","post","endpoint","deleteToId","inSendFailedScenario","setRegularSendScenario","e","setFailedSendScenario","process","env","NODE_ENV","onItemsChangedDisposer","increaseSendInterval","log"],"mappings":"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"}
@@ -6,19 +6,26 @@ function _define_property(obj, key, value) {
6
6
  configurable: true,
7
7
  writable: true
8
8
  });
9
- } else {
10
- obj[key] = value;
11
- }
9
+ } else obj[key] = value;
12
10
  return obj;
13
11
  }
14
12
  function _ts_decorate(decorators, target, key, desc) {
15
13
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
16
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
17
- else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
14
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
15
+ r = Reflect.decorate(decorators, target, key, desc);
16
+ } else {
17
+ for(var i = decorators.length - 1; i >= 0; i--){
18
+ if (d = decorators[i]) {
19
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
20
+ }
21
+ }
22
+ }
18
23
  return c > 3 && r && Object.defineProperty(target, key, r), r;
19
24
  }
20
- function _ts_metadata(k, v) {
21
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
25
+ function _ts_metadata(metadataKey, metadataValue) {
26
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
27
+ return Reflect.metadata(metadataKey, metadataValue);
28
+ }
22
29
  }
23
30
  function _ts_param(paramIndex, decorator) {
24
31
  return function(target, key) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/log-storage.ts"],"sourcesContent":["import { inject, injectable, Store } from '@servicetitan/react-ioc';\nimport { action, makeObservable, observable, toJS } from 'mobx';\nimport { EntryComplete, Nullable } from './log';\nimport type { LogConfig } from './log-config';\nimport { LOG_CONFIG_TOKEN } from './log-config';\n\nexport interface StorageItem {\n id: number;\n type: string;\n category: Nullable<string>;\n code: Nullable<string>;\n message: Nullable<string>;\n data: string;\n exception: string;\n}\n\nenum EventType {\n Delete = 'delete',\n}\n\ninterface DeleteEvent {\n type: EventType;\n items: StorageItem[];\n}\n\n@injectable()\nexport class LogStorage extends Store {\n @observable\n items: StorageItem[] = [];\n\n private readonly maxLogSize = 1000;\n private readonly version = 1;\n\n private nextItemId: number;\n private channel?: BroadcastChannel;\n\n constructor(@inject(LOG_CONFIG_TOKEN) private readonly logConfig: LogConfig) {\n super();\n makeObservable(this);\n\n const version = window.parseInt(localStorage.getItem(this.storageVersionKey) as string);\n if (version !== this.version) {\n localStorage.removeItem(this.storageKey);\n localStorage.setItem(this.storageVersionKey, String(this.version));\n }\n\n this.loadSavedItems();\n this.nextItemId = lastId(this.items) + 1;\n\n /*\n * Use the BroadcastChannel API to prevent different tabs from processing\n * the saved items. The first one to process the items sends a \"delete\" event\n * that causes all other instances to discard them from memory.\n */\n if ('BroadcastChannel' in globalThis) {\n this.channel = new BroadcastChannel(logConfig.storageKey);\n this.channel.addEventListener('message', ({ data }: MessageEvent<DeleteEvent>) =>\n this.handleDeleteEvent(data)\n );\n }\n }\n\n dispose() {\n this.channel?.close();\n }\n\n get config(): LogConfig {\n return this.logConfig;\n }\n\n store(entry: EntryComplete) {\n const item: StorageItem = {\n id: this.nextItemId++,\n type: entry.type,\n category: entry.category,\n code: entry.code,\n message: entry.message,\n data: JSON.stringify(entry.data),\n exception: this.stringifyError(entry.error),\n };\n\n let items = [...this.items, item];\n items = items.slice(-this.maxLogSize);\n this.setItems(items);\n }\n\n deleteToId(id: number) {\n const deletedItems: StorageItem[] = [];\n const items = this.items.filter(item => {\n if (item.id > id) {\n return true;\n }\n deletedItems.push(item);\n return false;\n });\n\n this.setItems(items);\n this.postDeleteEvent(deletedItems);\n }\n\n loadBatch(batchSize: number) {\n return this.items.slice(0, batchSize);\n }\n\n private loadSavedItems() {\n try {\n const items = JSON.parse(localStorage.getItem(this.storageKey) as string) ?? [];\n\n /* migrate error -> exception */\n items.forEach((item: StorageItem & { error?: string }) => {\n if (typeof item.error === 'string') {\n item.exception = item.error;\n delete item.error;\n }\n });\n this.setItems(items);\n } catch {\n this.setItems([]);\n }\n }\n\n private postDeleteEvent(items: StorageItem[]) {\n if (this.channel) {\n const event: DeleteEvent = {\n type: EventType.Delete,\n items: items.map(item => toJS(item)),\n };\n this.channel.postMessage(event);\n }\n }\n\n private handleDeleteEvent(event: DeleteEvent) {\n /* istanbul ignore next: because there's only one event type */\n if (event.type !== EventType.Delete) {\n return;\n }\n\n // Map item id to object for fast lookup\n const map = new Map<number, StorageItem>(event.items.map(item => [item.id, item]));\n\n // Discard deleted items\n const items = this.items.filter(item => !isEqual(item, map.get(item.id)));\n this.setItems(items);\n\n // If no more items, close channel; all saved items have been processed\n if (items.length === 0 && this.channel) {\n this.channel.close();\n delete this.channel;\n }\n }\n\n @action\n private setItems(items: StorageItem[]) {\n this.items = [...items];\n localStorage.setItem(this.storageKey, JSON.stringify(this.items));\n }\n\n private get storageKey() {\n return this.logConfig.storageKey;\n }\n\n private get storageVersionKey() {\n return `${this.storageKey}Version`;\n }\n\n private stringifyError(error: Nullable<Error>) {\n const detail = error ? { message: error.message.toString(), stack: error.stack } : null;\n return JSON.stringify(detail);\n }\n}\n\nfunction isEqual(a: StorageItem, b?: StorageItem) {\n return b && Object.keys(a).every((key: keyof StorageItem) => a[key] === b[key]);\n}\n\nexport function lastId(items: StorageItem[]): number {\n if (!items.length) {\n return 0;\n }\n const item = items[items.length - 1];\n return item.id;\n}\n"],"names":["inject","injectable","Store","action","makeObservable","observable","toJS","LOG_CONFIG_TOKEN","EventType","LogStorage","dispose","channel","close","config","logConfig","store","entry","item","id","nextItemId","type","category","code","message","data","JSON","stringify","exception","stringifyError","error","items","slice","maxLogSize","setItems","deleteToId","deletedItems","filter","push","postDeleteEvent","loadBatch","batchSize","loadSavedItems","parse","localStorage","getItem","storageKey","forEach","event","map","postMessage","handleDeleteEvent","Map","isEqual","get","length","setItem","storageVersionKey","detail","toString","stack","version","window","parseInt","removeItem","String","lastId","globalThis","BroadcastChannel","addEventListener","a","b","Object","keys","every","key"],"mappings":"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"}
1
+ {"version":3,"sources":["../src/log-storage.ts"],"sourcesContent":["import { inject, injectable, Store } from '@servicetitan/react-ioc';\nimport { action, makeObservable, observable, toJS } from 'mobx';\nimport { EntryComplete, Nullable } from './log';\nimport type { LogConfig } from './log-config';\nimport { LOG_CONFIG_TOKEN } from './log-config';\n\nexport interface StorageItem {\n id: number;\n type: string;\n category: Nullable<string>;\n code: Nullable<string>;\n message: Nullable<string>;\n data: string;\n exception: string;\n}\n\nenum EventType {\n Delete = 'delete',\n}\n\ninterface DeleteEvent {\n type: EventType;\n items: StorageItem[];\n}\n\n@injectable()\nexport class LogStorage extends Store {\n @observable\n items: StorageItem[] = [];\n\n private readonly maxLogSize = 1000;\n private readonly version = 1;\n\n private nextItemId: number;\n private channel?: BroadcastChannel;\n\n constructor(@inject(LOG_CONFIG_TOKEN) private readonly logConfig: LogConfig) {\n super();\n makeObservable(this);\n\n const version = window.parseInt(localStorage.getItem(this.storageVersionKey) as string);\n if (version !== this.version) {\n localStorage.removeItem(this.storageKey);\n localStorage.setItem(this.storageVersionKey, String(this.version));\n }\n\n this.loadSavedItems();\n this.nextItemId = lastId(this.items) + 1;\n\n /*\n * Use the BroadcastChannel API to prevent different tabs from processing\n * the saved items. The first one to process the items sends a \"delete\" event\n * that causes all other instances to discard them from memory.\n */\n if ('BroadcastChannel' in globalThis) {\n this.channel = new BroadcastChannel(logConfig.storageKey);\n this.channel.addEventListener('message', ({ data }: MessageEvent<DeleteEvent>) =>\n this.handleDeleteEvent(data)\n );\n }\n }\n\n dispose() {\n this.channel?.close();\n }\n\n get config(): LogConfig {\n return this.logConfig;\n }\n\n store(entry: EntryComplete) {\n const item: StorageItem = {\n id: this.nextItemId++,\n type: entry.type,\n category: entry.category,\n code: entry.code,\n message: entry.message,\n data: JSON.stringify(entry.data),\n exception: this.stringifyError(entry.error),\n };\n\n let items = [...this.items, item];\n items = items.slice(-this.maxLogSize);\n this.setItems(items);\n }\n\n deleteToId(id: number) {\n const deletedItems: StorageItem[] = [];\n const items = this.items.filter(item => {\n if (item.id > id) {\n return true;\n }\n deletedItems.push(item);\n return false;\n });\n\n this.setItems(items);\n this.postDeleteEvent(deletedItems);\n }\n\n loadBatch(batchSize: number) {\n return this.items.slice(0, batchSize);\n }\n\n private loadSavedItems() {\n try {\n const items = JSON.parse(localStorage.getItem(this.storageKey) as string) ?? [];\n\n /* migrate error -> exception */\n items.forEach((item: StorageItem & { error?: string }) => {\n if (typeof item.error === 'string') {\n item.exception = item.error;\n delete item.error;\n }\n });\n this.setItems(items);\n } catch {\n this.setItems([]);\n }\n }\n\n private postDeleteEvent(items: StorageItem[]) {\n if (this.channel) {\n const event: DeleteEvent = {\n type: EventType.Delete,\n items: items.map(item => toJS(item)),\n };\n this.channel.postMessage(event);\n }\n }\n\n private handleDeleteEvent(event: DeleteEvent) {\n /* istanbul ignore next: because there's only one event type */\n if (event.type !== EventType.Delete) {\n return;\n }\n\n // Map item id to object for fast lookup\n const map = new Map<number, StorageItem>(event.items.map(item => [item.id, item]));\n\n // Discard deleted items\n const items = this.items.filter(item => !isEqual(item, map.get(item.id)));\n this.setItems(items);\n\n // If no more items, close channel; all saved items have been processed\n if (items.length === 0 && this.channel) {\n this.channel.close();\n delete this.channel;\n }\n }\n\n @action\n private setItems(items: StorageItem[]) {\n this.items = [...items];\n localStorage.setItem(this.storageKey, JSON.stringify(this.items));\n }\n\n private get storageKey() {\n return this.logConfig.storageKey;\n }\n\n private get storageVersionKey() {\n return `${this.storageKey}Version`;\n }\n\n private stringifyError(error: Nullable<Error>) {\n const detail = error ? { message: error.message.toString(), stack: error.stack } : null;\n return JSON.stringify(detail);\n }\n}\n\nfunction isEqual(a: StorageItem, b?: StorageItem) {\n return b && Object.keys(a).every((key: keyof StorageItem) => a[key] === b[key]);\n}\n\nexport function lastId(items: StorageItem[]): number {\n if (!items.length) {\n return 0;\n }\n const item = items[items.length - 1];\n return item.id;\n}\n"],"names":["inject","injectable","Store","action","makeObservable","observable","toJS","LOG_CONFIG_TOKEN","EventType","LogStorage","dispose","channel","close","config","logConfig","store","entry","item","id","nextItemId","type","category","code","message","data","JSON","stringify","exception","stringifyError","error","items","slice","maxLogSize","setItems","deleteToId","deletedItems","filter","push","postDeleteEvent","loadBatch","batchSize","loadSavedItems","parse","localStorage","getItem","storageKey","forEach","event","map","postMessage","handleDeleteEvent","Map","isEqual","get","length","setItem","storageVersionKey","detail","toString","stack","version","window","parseInt","removeItem","String","lastId","globalThis","BroadcastChannel","addEventListener","a","b","Object","keys","every","key"],"mappings":"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"}
package/dist/log.js CHANGED
@@ -6,19 +6,26 @@ function _define_property(obj, key, value) {
6
6
  configurable: true,
7
7
  writable: true
8
8
  });
9
- } else {
10
- obj[key] = value;
11
- }
9
+ } else obj[key] = value;
12
10
  return obj;
13
11
  }
14
12
  function _ts_decorate(decorators, target, key, desc) {
15
13
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
16
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
17
- else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
14
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
15
+ r = Reflect.decorate(decorators, target, key, desc);
16
+ } else {
17
+ for(var i = decorators.length - 1; i >= 0; i--){
18
+ if (d = decorators[i]) {
19
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
20
+ }
21
+ }
22
+ }
18
23
  return c > 3 && r && Object.defineProperty(target, key, r), r;
19
24
  }
20
- function _ts_metadata(k, v) {
21
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
25
+ function _ts_metadata(metadataKey, metadataValue) {
26
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
27
+ return Reflect.metadata(metadataKey, metadataValue);
28
+ }
22
29
  }
23
30
  function _ts_param(paramIndex, decorator) {
24
31
  return function(target, key) {
package/dist/log.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/log.ts"],"sourcesContent":["import { inject, injectable, optional, symbolToken } from '@servicetitan/react-ioc';\nimport throttle from 'lodash.throttle';\nimport { defaultLogConfig } from './log-config';\nimport { LogStorage } from './log-storage';\nimport { serializeWithMetadata } from './serialize-with-metadata';\n\nexport { LOG_CONFIG_TOKEN } from './log-config';\nexport type { LogConfig } from './log-config';\n\nexport interface ArbitraryData extends Record<string, boolean | number | string | Date> {}\n\nexport interface LogEntry {\n category?: string;\n code?: string;\n message?: string;\n data?: ArbitraryData;\n}\n\nexport interface LogInfo extends LogEntry {}\n\nexport interface LogWarning extends LogEntry {}\n\nexport interface LogError extends LogEntry {\n error: unknown;\n}\n\nexport interface ErrorOptions {\n skipConsole?: boolean;\n}\n\nexport interface ILog {\n info(entry: LogInfo): void;\n warning(entry: LogWarning): void;\n error(entry: LogError, options?: ErrorOptions): void;\n}\n\nexport enum LogEntryType {\n Info = 'Info',\n Warning = 'Warning',\n Error = 'Error',\n}\n\nexport type Nullable<T> = T | null;\n\nexport interface EntryComplete {\n type: LogEntryType;\n category: Nullable<string>;\n code: Nullable<string>;\n message: Nullable<string>;\n data: ArbitraryData;\n error: Nullable<Error>;\n}\n\nexport type EntryCompleteError = EntryComplete & {\n error: Error;\n};\n\nexport const LOG_PARENT_TOKEN = symbolToken<Log>('LOG_PARENT_TOKEN');\n\nfunction ensureError(error: unknown): Error {\n if (error instanceof Error) {\n return error;\n }\n if (typeof error === 'string') {\n return new Error(error);\n }\n return new Error(serializeWithMetadata(error));\n}\n\n@injectable()\nexport class Log implements ILog {\n private errorLogHandler: ErrorLogHandler;\n\n constructor(\n @inject(LogStorage) private readonly logStorage: LogStorage,\n @inject(LOG_PARENT_TOKEN) @optional() private readonly parent?: Log\n ) {\n this.validate();\n this.errorLogHandler = new ErrorLogHandler(this, this.logStorage);\n }\n\n info(entry: LogInfo): void {\n this.parent?.info(entry);\n return this.store(this.expand(LogEntryType.Info, entry));\n }\n\n warning(entry: LogWarning): void {\n this.parent?.warning(entry);\n return this.store(this.expand(LogEntryType.Warning, entry));\n }\n\n error(entry: LogError, { skipConsole = false } = {}): void {\n this.parent?.error(entry);\n if (!skipConsole) {\n // eslint-disable-next-line no-console\n console.error(\n '@log-service/error',\n entry,\n ensureError(entry?.error ?? entry?.message ?? 'Undefined entry')\n );\n }\n return this.errorLogHandler.handle(this.expandError(entry)); // with errorLogHandler throttling\n }\n\n private store(entry: EntryComplete) {\n return this.logStorage.store(entry);\n }\n\n private expand(type: LogEntryType, entry: LogEntry): EntryComplete {\n const data = {\n ...entry.data,\n ...this.dataDefault(),\n };\n\n return {\n type,\n category: null,\n message: null,\n code: null,\n ...entry,\n error: null,\n data,\n };\n }\n\n private expandError(entry: LogError): EntryCompleteError {\n let error: Error;\n if (entry.error instanceof Error) {\n error = entry.error;\n } else {\n error = new Error(serializeWithMetadata(entry.error));\n }\n\n const { message, ...rest } = this.expand(LogEntryType.Error, entry);\n\n return {\n message: message ?? error.message,\n ...rest,\n error,\n };\n }\n\n private dataDefault() {\n return {\n CreatedOn: new Date(),\n Online: window.navigator.onLine,\n Url: window.location.toString(),\n UserAgent: window.navigator.userAgent,\n Source: 'Frontend',\n Plugins: plugins(),\n ...timezoneInfo(),\n };\n }\n\n private validate() {\n if (!this.parent) {\n return;\n }\n\n const { endpoint, storageKey } = this.logStorage.config;\n if (endpoint === defaultLogConfig.endpoint || storageKey === defaultLogConfig.storageKey) {\n throw new Error('nested Log cannot use default configuration');\n }\n }\n}\n\nclass ErrorLogHandler {\n private logService: Log;\n private logStorage: LogStorage;\n\n private logTable = new HashTable<EntryCompleteError>();\n private repetitiveLogsCache = new HashTable<boolean>();\n\n private readonly cacheFlushDuration = 30000;\n private readonly throttleLogsDuration = 2000;\n\n private flushThrottled = throttle(() => this.flush(), this.throttleLogsDuration, {\n leading: false,\n trailing: true,\n });\n\n constructor(logService: Log, logStorage: LogStorage) {\n this.logService = logService;\n this.logStorage = logStorage;\n\n setInterval(() => this.repetitiveLogsCache.clear(), this.cacheFlushDuration);\n }\n\n handle(entry: EntryCompleteError) {\n this.add(entry);\n this.flushThrottled();\n }\n\n private add(entry: EntryCompleteError) {\n const key = this.keyFor(entry);\n if (this.repetitiveLogsCache.get(key)) {\n /* error is a repetitive error and has been reported, we don't need to report it again */\n return;\n }\n\n if (this.logTable.get(key) == null) {\n this.logTable.set(key, entry);\n } else {\n /* present in entry table, hence a duplicate, don't set, rather increase count */\n const entry = this.logTable.get(key) as EntryCompleteError & {\n data: { count?: number };\n };\n if (typeof entry.data.count === 'number') {\n entry.data.count++;\n } else {\n entry.data.count = 2;\n }\n this.logTable.set(key, entry);\n }\n }\n\n private keyFor(entry: EntryCompleteError) {\n return {\n message: entry.error.message,\n stack: entry.error.stack ?? '',\n };\n }\n\n private flush() {\n const hashes = this.logTable.getHashes();\n for (const key of hashes) {\n const entry = this.logTable.get(key);\n\n if ('count' in entry.data) {\n /* insert into cache if it is a repetitive error */\n this.repetitiveLogsCache.set(key, true);\n }\n\n this.logStorage.store(entry);\n }\n\n this.logTable.clear();\n }\n}\n\nclass HashTable<T> {\n private hashes: Record<string, T> = {};\n\n set(key: { message: string; stack: string }, value: T) {\n this.hashes[JSON.stringify(key)] = value;\n }\n\n get(key: { message: string; stack: string }): T {\n return this.hashes[JSON.stringify(key)];\n }\n\n getHashes() {\n return Object.keys(this.hashes).map(value => JSON.parse(value));\n }\n\n clear() {\n this.hashes = {};\n }\n}\n\nfunction plugins() {\n try {\n return Array.prototype.slice\n .call(window.navigator.plugins)\n .map(p => [p.name, p.filename, p.description].join(','))\n .join('/');\n } catch {\n return 'unknown';\n }\n}\n\nfunction timezoneInfo() {\n // https://stackoverflow.com/questions/11887934/how-to-check-if-dst-daylight-saving-time-is-in-effect-and-if-so-the-offset\n\n const now = new Date();\n const jan = new Date(now.getFullYear(), 0, 1);\n const jul = new Date(now.getFullYear(), 6, 1);\n\n const TzOffset = now.getTimezoneOffset();\n const IsDst = TzOffset < Math.max(jan.getTimezoneOffset(), jul.getTimezoneOffset());\n const IsDstSubject = jan.getTimezoneOffset() !== jul.getTimezoneOffset();\n\n return {\n TzOffset,\n IsDst,\n IsDstSubject,\n };\n}\n"],"names":["inject","injectable","optional","symbolToken","throttle","defaultLogConfig","LogStorage","serializeWithMetadata","LOG_CONFIG_TOKEN","LogEntryType","LOG_PARENT_TOKEN","ensureError","error","Error","Log","info","entry","parent","store","expand","warning","skipConsole","console","message","errorLogHandler","handle","expandError","logStorage","type","data","dataDefault","category","code","rest","CreatedOn","Date","Online","window","navigator","onLine","Url","location","toString","UserAgent","userAgent","Source","Plugins","plugins","timezoneInfo","validate","endpoint","storageKey","config","ErrorLogHandler","add","flushThrottled","key","keyFor","repetitiveLogsCache","get","logTable","set","count","stack","flush","hashes","getHashes","clear","logService","HashTable","cacheFlushDuration","throttleLogsDuration","leading","trailing","setInterval","value","JSON","stringify","Object","keys","map","parse","Array","prototype","slice","call","p","name","filename","description","join","now","jan","getFullYear","jul","TzOffset","getTimezoneOffset","IsDst","Math","max","IsDstSubject"],"mappings":"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"}
1
+ {"version":3,"sources":["../src/log.ts"],"sourcesContent":["import { inject, injectable, optional, symbolToken } from '@servicetitan/react-ioc';\nimport throttle from 'lodash.throttle';\nimport { defaultLogConfig } from './log-config';\nimport { LogStorage } from './log-storage';\nimport { serializeWithMetadata } from './serialize-with-metadata';\n\nexport { LOG_CONFIG_TOKEN } from './log-config';\nexport type { LogConfig } from './log-config';\n\nexport interface ArbitraryData extends Record<string, boolean | number | string | Date> {}\n\nexport interface LogEntry {\n category?: string;\n code?: string;\n message?: string;\n data?: ArbitraryData;\n}\n\nexport interface LogInfo extends LogEntry {}\n\nexport interface LogWarning extends LogEntry {}\n\nexport interface LogError extends LogEntry {\n error: unknown;\n}\n\nexport interface ErrorOptions {\n skipConsole?: boolean;\n}\n\nexport interface ILog {\n info(entry: LogInfo): void;\n warning(entry: LogWarning): void;\n error(entry: LogError, options?: ErrorOptions): void;\n}\n\nexport enum LogEntryType {\n Info = 'Info',\n Warning = 'Warning',\n Error = 'Error',\n}\n\nexport type Nullable<T> = T | null;\n\nexport interface EntryComplete {\n type: LogEntryType;\n category: Nullable<string>;\n code: Nullable<string>;\n message: Nullable<string>;\n data: ArbitraryData;\n error: Nullable<Error>;\n}\n\nexport type EntryCompleteError = EntryComplete & {\n error: Error;\n};\n\nexport const LOG_PARENT_TOKEN = symbolToken<Log>('LOG_PARENT_TOKEN');\n\nfunction ensureError(error: unknown): Error {\n if (error instanceof Error) {\n return error;\n }\n if (typeof error === 'string') {\n return new Error(error);\n }\n return new Error(serializeWithMetadata(error));\n}\n\n@injectable()\nexport class Log implements ILog {\n private errorLogHandler: ErrorLogHandler;\n\n constructor(\n @inject(LogStorage) private readonly logStorage: LogStorage,\n @inject(LOG_PARENT_TOKEN) @optional() private readonly parent?: Log\n ) {\n this.validate();\n this.errorLogHandler = new ErrorLogHandler(this, this.logStorage);\n }\n\n info(entry: LogInfo): void {\n this.parent?.info(entry);\n return this.store(this.expand(LogEntryType.Info, entry));\n }\n\n warning(entry: LogWarning): void {\n this.parent?.warning(entry);\n return this.store(this.expand(LogEntryType.Warning, entry));\n }\n\n error(entry: LogError, { skipConsole = false } = {}): void {\n this.parent?.error(entry);\n if (!skipConsole) {\n // eslint-disable-next-line no-console\n console.error(\n '@log-service/error',\n entry,\n ensureError(entry?.error ?? entry?.message ?? 'Undefined entry')\n );\n }\n return this.errorLogHandler.handle(this.expandError(entry)); // with errorLogHandler throttling\n }\n\n private store(entry: EntryComplete) {\n return this.logStorage.store(entry);\n }\n\n private expand(type: LogEntryType, entry: LogEntry): EntryComplete {\n const data = {\n ...entry.data,\n ...this.dataDefault(),\n };\n\n return {\n type,\n category: null,\n message: null,\n code: null,\n ...entry,\n error: null,\n data,\n };\n }\n\n private expandError(entry: LogError): EntryCompleteError {\n let error: Error;\n if (entry.error instanceof Error) {\n error = entry.error;\n } else {\n error = new Error(serializeWithMetadata(entry.error));\n }\n\n const { message, ...rest } = this.expand(LogEntryType.Error, entry);\n\n return {\n message: message ?? error.message,\n ...rest,\n error,\n };\n }\n\n private dataDefault() {\n return {\n CreatedOn: new Date(),\n Online: window.navigator.onLine,\n Url: window.location.toString(),\n UserAgent: window.navigator.userAgent,\n Source: 'Frontend',\n Plugins: plugins(),\n ...timezoneInfo(),\n };\n }\n\n private validate() {\n if (!this.parent) {\n return;\n }\n\n const { endpoint, storageKey } = this.logStorage.config;\n if (endpoint === defaultLogConfig.endpoint || storageKey === defaultLogConfig.storageKey) {\n throw new Error('nested Log cannot use default configuration');\n }\n }\n}\n\nclass ErrorLogHandler {\n private logService: Log;\n private logStorage: LogStorage;\n\n private logTable = new HashTable<EntryCompleteError>();\n private repetitiveLogsCache = new HashTable<boolean>();\n\n private readonly cacheFlushDuration = 30000;\n private readonly throttleLogsDuration = 2000;\n\n private flushThrottled = throttle(() => this.flush(), this.throttleLogsDuration, {\n leading: false,\n trailing: true,\n });\n\n constructor(logService: Log, logStorage: LogStorage) {\n this.logService = logService;\n this.logStorage = logStorage;\n\n setInterval(() => this.repetitiveLogsCache.clear(), this.cacheFlushDuration);\n }\n\n handle(entry: EntryCompleteError) {\n this.add(entry);\n this.flushThrottled();\n }\n\n private add(entry: EntryCompleteError) {\n const key = this.keyFor(entry);\n if (this.repetitiveLogsCache.get(key)) {\n /* error is a repetitive error and has been reported, we don't need to report it again */\n return;\n }\n\n if (this.logTable.get(key) == null) {\n this.logTable.set(key, entry);\n } else {\n /* present in entry table, hence a duplicate, don't set, rather increase count */\n const entry = this.logTable.get(key) as EntryCompleteError & {\n data: { count?: number };\n };\n if (typeof entry.data.count === 'number') {\n entry.data.count++;\n } else {\n entry.data.count = 2;\n }\n this.logTable.set(key, entry);\n }\n }\n\n private keyFor(entry: EntryCompleteError) {\n return {\n message: entry.error.message,\n stack: entry.error.stack ?? '',\n };\n }\n\n private flush() {\n const hashes = this.logTable.getHashes();\n for (const key of hashes) {\n const entry = this.logTable.get(key);\n\n if ('count' in entry.data) {\n /* insert into cache if it is a repetitive error */\n this.repetitiveLogsCache.set(key, true);\n }\n\n this.logStorage.store(entry);\n }\n\n this.logTable.clear();\n }\n}\n\nclass HashTable<T> {\n private hashes: Record<string, T> = {};\n\n set(key: { message: string; stack: string }, value: T) {\n this.hashes[JSON.stringify(key)] = value;\n }\n\n get(key: { message: string; stack: string }): T {\n return this.hashes[JSON.stringify(key)];\n }\n\n getHashes() {\n return Object.keys(this.hashes).map(value => JSON.parse(value));\n }\n\n clear() {\n this.hashes = {};\n }\n}\n\nfunction plugins() {\n try {\n return Array.prototype.slice\n .call(window.navigator.plugins)\n .map(p => [p.name, p.filename, p.description].join(','))\n .join('/');\n } catch {\n return 'unknown';\n }\n}\n\nfunction timezoneInfo() {\n // https://stackoverflow.com/questions/11887934/how-to-check-if-dst-daylight-saving-time-is-in-effect-and-if-so-the-offset\n\n const now = new Date();\n const jan = new Date(now.getFullYear(), 0, 1);\n const jul = new Date(now.getFullYear(), 6, 1);\n\n const TzOffset = now.getTimezoneOffset();\n const IsDst = TzOffset < Math.max(jan.getTimezoneOffset(), jul.getTimezoneOffset());\n const IsDstSubject = jan.getTimezoneOffset() !== jul.getTimezoneOffset();\n\n return {\n TzOffset,\n IsDst,\n IsDstSubject,\n };\n}\n"],"names":["inject","injectable","optional","symbolToken","throttle","defaultLogConfig","LogStorage","serializeWithMetadata","LOG_CONFIG_TOKEN","LogEntryType","LOG_PARENT_TOKEN","ensureError","error","Error","Log","info","entry","parent","store","expand","warning","skipConsole","console","message","errorLogHandler","handle","expandError","logStorage","type","data","dataDefault","category","code","rest","CreatedOn","Date","Online","window","navigator","onLine","Url","location","toString","UserAgent","userAgent","Source","Plugins","plugins","timezoneInfo","validate","endpoint","storageKey","config","ErrorLogHandler","add","flushThrottled","key","keyFor","repetitiveLogsCache","get","logTable","set","count","stack","flush","hashes","getHashes","clear","logService","HashTable","cacheFlushDuration","throttleLogsDuration","leading","trailing","setInterval","value","JSON","stringify","Object","keys","map","parse","Array","prototype","slice","call","p","name","filename","description","join","now","jan","getFullYear","jul","TzOffset","getTimezoneOffset","IsDst","Math","max","IsDstSubject"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@servicetitan/log-service",
3
- "version": "37.0.2",
3
+ "version": "38.1.0",
4
4
  "description": "Service to send events to Kibana logs via the backend log service",
5
5
  "homepage": "https://docs.st.dev/docs/frontend/uikit/log-service",
6
6
  "repository": {
@@ -16,7 +16,7 @@
16
16
  "src"
17
17
  ],
18
18
  "devDependencies": {
19
- "@servicetitan/react-ioc": "37.0.2",
19
+ "@servicetitan/react-ioc": "38.1.0",
20
20
  "@testing-library/dom": "^10.4.1",
21
21
  "@testing-library/react": "^16.3.2",
22
22
  "@types/lodash.throttle": "~4.1.6",
@@ -25,7 +25,7 @@
25
25
  "react": "~18.3.1"
26
26
  },
27
27
  "peerDependencies": {
28
- "@servicetitan/react-ioc": "37.0.2",
28
+ "@servicetitan/react-ioc": "38.1.0",
29
29
  "axios": ">=0.30.0 <1 || ^1.8.3",
30
30
  "mobx": ">=6.13.5",
31
31
  "react": ">=17.0.2"
@@ -39,5 +39,5 @@
39
39
  "cli": {
40
40
  "webpack": false
41
41
  },
42
- "gitHead": "d30a9eb850b4bdb98b6af7cc06fade1359fcc943"
42
+ "gitHead": "e8c601a26ad49ca0d6b0b84a9f530f3242d53c7f"
43
43
  }