@sneat/logging 0.27.24 → 0.27.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,104 @@
1
+ # @sneat/logging
2
+
3
+ Angular providers and services for error reporting (Sentry), analytics, and a
4
+ few browser-runtime resilience handlers (chunk-load recovery).
5
+
6
+ ## Error logging
7
+
8
+ `ErrorLoggerService` (registered under the `ErrorLogger` token from
9
+ `@sneat/core`) is what app code calls to log a handled error:
10
+
11
+ ```ts
12
+ import { ErrorLogger } from '@sneat/core';
13
+
14
+ constructor(@Inject(ErrorLogger) private readonly errorLogger: IErrorLogger) {}
15
+
16
+ this.errorLogger.logError(e, 'Failed to save the record');
17
+ ```
18
+
19
+ Per call, `logError(e, message?, options?)` does three things, each gated by
20
+ its own `ILogErrorOptions` flag:
21
+
22
+ | Option | Default | Effect when true |
23
+ |---|---|---|
24
+ | `report` | `true` | Sends the error to Sentry (`captureException`) — skipped on `localhost`. |
25
+ | `feedback` | `true` | After a successful `report`, opens Sentry's **report dialog** (`showReportDialog`) so the user can describe what happened. |
26
+ | `show` | `true` | Shows an in-app Ionic toast with the error message. |
27
+ | `showDuration` | 7000ms | Toast duration. |
28
+
29
+ Wire it up with `provideErrorLogger()`, typically once at the app root (it's
30
+ also called internally by other bundles — see below):
31
+
32
+ ```ts
33
+ import { provideErrorLogger } from '@sneat/logging';
34
+
35
+ // providers: [provideErrorLogger(), ...]
36
+ ```
37
+
38
+ ### App-level defaults: `provideErrorLoggerDefaults()`
39
+
40
+ `ILogErrorOptions.feedback` (and `.show`) default to `true`, but a call site
41
+ rarely wants to opt out one call at a time — an app usually wants a blanket
42
+ policy. `provideErrorLoggerDefaults()` sets that policy once, and
43
+ `ErrorLoggerService` resolves each option as:
44
+
45
+ ```
46
+ options.<key> ?? defaults.<key> ?? <built-in default (true)>
47
+ ```
48
+
49
+ so an explicit per-call value always wins, an app-level default is the
50
+ fallback, and the pre-existing behaviour (dialog/toast shown) is what happens
51
+ when neither is set.
52
+
53
+ ```ts
54
+ import { provideErrorLoggerDefaults } from '@sneat/logging';
55
+
56
+ // providers: [provideErrorLoggerDefaults({ feedback: false }), ...]
57
+ ```
58
+
59
+ `provideErrorLogger()` also accepts the same shape as sugar for calling both
60
+ together:
61
+
62
+ ```ts
63
+ // providers: [provideErrorLogger({ feedback: false }), ...]
64
+ ```
65
+
66
+ **Why a separate token, not just an argument to `provideErrorLogger()`.**
67
+ Other bundles call `provideErrorLogger()` internally — e.g.
68
+ `@sneat/app-auth`'s `provideSneatAuthenticatedProviders()` — so a second,
69
+ unrelated `provideErrorLogger()` registration can land later in the same
70
+ providers array (Angular DI: the last provider for a token wins). If the
71
+ default lived only inside `provideErrorLogger()`'s own provider, that later,
72
+ plain call would silently reset it. `ERROR_LOGGER_DEFAULTS` is its own
73
+ token, provided once by `provideErrorLoggerDefaults()`, so it is unaffected
74
+ by how many more times `provideErrorLogger()` is subsequently called:
75
+
76
+ ```ts
77
+ providers: [
78
+ provideErrorLoggerDefaults({ feedback: false }), // app-level policy
79
+ ...
80
+ provideSneatAuthenticatedProviders(config), // calls provideErrorLogger() again internally — feedback: false still applies
81
+ ],
82
+ ```
83
+
84
+ ### Logged errors vs. uncaught exceptions
85
+
86
+ `feedback: false` only affects errors your own code chooses to `logError()`.
87
+ It does not touch Sentry's dialog for **uncaught** exceptions, which is a
88
+ separate handler wired up by `provideSentryAppInitializer()` via
89
+ `@sentry/angular`'s `createErrorHandler({ showDialog: true })`. A typical
90
+ policy is therefore:
91
+
92
+ ```ts
93
+ providers: [
94
+ // Never interrupt the user with a report dialog for errors the app already
95
+ // handled and surfaced its own way (toast, inline message, etc).
96
+ provideErrorLoggerDefaults({ feedback: false }),
97
+ provideSentryAppInitializer({ ... }), // still shows Sentry's dialog for genuinely uncaught exceptions
98
+ ],
99
+ ```
100
+
101
+ This is the DataTug use case: it wrapped `provideErrorLogger()` itself to
102
+ suppress the report dialog on every `logError()` call
103
+ (datatug/datatug-apps#128, #132) before `ERROR_LOGGER_DEFAULTS` existed —
104
+ that wrapper can be replaced with `provideErrorLoggerDefaults({ feedback: false })`.
package/esm2022/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  export * from './lib/sentry-setup';
2
2
  export * from './lib/chunk-load-error.handler';
3
3
  export * from './lib/sneat-logging.module';
4
+ export * from './lib/error-logger-defaults';
4
5
  export * from './lib/analytics';
5
6
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../libs/logging/src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,iBAAiB,CAAC","sourcesContent":["export * from './lib/sentry-setup';\nexport * from './lib/chunk-load-error.handler';\nexport * from './lib/sneat-logging.module';\nexport * from './lib/analytics';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../libs/logging/src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,iBAAiB,CAAC","sourcesContent":["export * from './lib/sentry-setup';\nexport * from './lib/chunk-load-error.handler';\nexport * from './lib/sneat-logging.module';\nexport * from './lib/error-logger-defaults';\nexport * from './lib/analytics';\n"]}
@@ -0,0 +1,35 @@
1
+ import { InjectionToken } from '@angular/core';
2
+ /**
3
+ * App-level defaults for {@link ErrorLoggerService}, applied whenever a
4
+ * per-call `ILogErrorOptions` does not specify the option itself.
5
+ * `ErrorLoggerService` resolves each supported option as
6
+ * `options.<key> ?? defaults.<key> ?? <built-in default>` — so an explicit
7
+ * per-call value always wins over the app-level default, which in turn wins
8
+ * over the built-in default.
9
+ *
10
+ * No provider registered means "use the built-in defaults" — e.g. Sentry's
11
+ * report dialog is shown for every reported error, matching the behaviour
12
+ * before this token existed.
13
+ */
14
+ export const ERROR_LOGGER_DEFAULTS = new InjectionToken('ERROR_LOGGER_DEFAULTS');
15
+ /**
16
+ * Registers app-level defaults for `ErrorLoggerService`. Typical use: never
17
+ * show Sentry's report dialog for errors logged via `logError()`, while still
18
+ * showing Sentry's own dialog for uncaught exceptions (handled separately by
19
+ * `createErrorHandler`, wired up by `provideSentryAppInitializer`):
20
+ *
21
+ * ```ts
22
+ * providers: [provideErrorLoggerDefaults({ feedback: false })]
23
+ * ```
24
+ *
25
+ * Provide this once, at the app level. It survives a later `provideErrorLogger()`
26
+ * registration performed by another bundle (e.g.
27
+ * `provideSneatAuthenticatedProviders()` from `@sneat/app-auth`, which calls
28
+ * `provideErrorLogger()` internally) because that call only re-provides
29
+ * `ErrorLogger` itself, never `ERROR_LOGGER_DEFAULTS` — so an app-level default
30
+ * wins regardless of provider registration order.
31
+ */
32
+ export function provideErrorLoggerDefaults(defaults) {
33
+ return { provide: ERROR_LOGGER_DEFAULTS, useValue: defaults };
34
+ }
35
+ //# sourceMappingURL=error-logger-defaults.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-logger-defaults.js","sourceRoot":"","sources":["../../../../../libs/logging/src/lib/error-logger-defaults.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAY,MAAM,eAAe,CAAC;AAGzD;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,IAAI,cAAc,CACrD,uBAAuB,CACxB,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,0BAA0B,CACxC,QAA0B;IAE1B,OAAO,EAAE,OAAO,EAAE,qBAAqB,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;AAChE,CAAC","sourcesContent":["import { InjectionToken, Provider } from '@angular/core';\nimport { ILogErrorOptions } from '@sneat/core';\n\n/**\n * App-level defaults for {@link ErrorLoggerService}, applied whenever a\n * per-call `ILogErrorOptions` does not specify the option itself.\n * `ErrorLoggerService` resolves each supported option as\n * `options.<key> ?? defaults.<key> ?? <built-in default>` — so an explicit\n * per-call value always wins over the app-level default, which in turn wins\n * over the built-in default.\n *\n * No provider registered means \"use the built-in defaults\" — e.g. Sentry's\n * report dialog is shown for every reported error, matching the behaviour\n * before this token existed.\n */\nexport const ERROR_LOGGER_DEFAULTS = new InjectionToken<ILogErrorOptions>(\n 'ERROR_LOGGER_DEFAULTS',\n);\n\n/**\n * Registers app-level defaults for `ErrorLoggerService`. Typical use: never\n * show Sentry's report dialog for errors logged via `logError()`, while still\n * showing Sentry's own dialog for uncaught exceptions (handled separately by\n * `createErrorHandler`, wired up by `provideSentryAppInitializer`):\n *\n * ```ts\n * providers: [provideErrorLoggerDefaults({ feedback: false })]\n * ```\n *\n * Provide this once, at the app level. It survives a later `provideErrorLogger()`\n * registration performed by another bundle (e.g.\n * `provideSneatAuthenticatedProviders()` from `@sneat/app-auth`, which calls\n * `provideErrorLogger()` internally) because that call only re-provides\n * `ErrorLogger` itself, never `ERROR_LOGGER_DEFAULTS` — so an app-level default\n * wins regardless of provider registration order.\n */\nexport function provideErrorLoggerDefaults(\n defaults: ILogErrorOptions,\n): Provider {\n return { provide: ERROR_LOGGER_DEFAULTS, useValue: defaults };\n}\n"]}
@@ -1,13 +1,15 @@
1
1
  import { HttpErrorResponse } from '@angular/common/http';
2
- import { Injectable, Optional } from '@angular/core';
2
+ import { Inject, Injectable, Optional } from '@angular/core';
3
3
  import { ToastController } from '@ionic/angular';
4
4
  import { captureException, showReportDialog } from '@sentry/angular';
5
+ import { ERROR_LOGGER_DEFAULTS } from './error-logger-defaults';
5
6
  import * as i0 from "@angular/core";
6
7
  import * as i1 from "@ionic/angular";
7
8
  const defaultErrorToastDuration = 7000;
8
9
  export class ErrorLoggerService {
9
- constructor(toastController) {
10
+ constructor(toastController, defaults) {
10
11
  this.toastController = toastController;
12
+ this.defaults = defaults;
11
13
  this.logErrorHandler = (message, options) => (e) => this.logError(e, message, options);
12
14
  this.logError = (e, message, options) => {
13
15
  // logError(e, message, options) is easy to call with `e` and `message`
@@ -45,7 +47,8 @@ export class ErrorLoggerService {
45
47
  ? captureException(message, { originalException: e })
46
48
  : captureException(e);
47
49
  // console.log('Captured error by Sentry with eventId:', eventId);
48
- if (options?.feedback === undefined || options.feedback) {
50
+ const feedback = options?.feedback ?? this.defaults?.feedback ?? true;
51
+ if (feedback) {
49
52
  showReportDialog({ eventId });
50
53
  }
51
54
  }
@@ -54,7 +57,8 @@ export class ErrorLoggerService {
54
57
  }
55
58
  }
56
59
  }
57
- if (options?.show || options?.show === undefined) {
60
+ const show = options?.show ?? this.defaults?.show ?? true;
61
+ if (show) {
58
62
  this.showError(e, options?.showDuration);
59
63
  }
60
64
  return; // return message ? { error: e, message } : e;
@@ -115,12 +119,17 @@ export class ErrorLoggerService {
115
119
  show: false,
116
120
  }));
117
121
  }
118
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: ErrorLoggerService, deps: [{ token: i1.ToastController, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
122
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: ErrorLoggerService, deps: [{ token: i1.ToastController, optional: true }, { token: ERROR_LOGGER_DEFAULTS, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
119
123
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: ErrorLoggerService }); }
120
124
  }
121
125
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: ErrorLoggerService, decorators: [{
122
126
  type: Injectable
123
127
  }], ctorParameters: () => [{ type: i1.ToastController, decorators: [{
124
128
  type: Optional
129
+ }] }, { type: undefined, decorators: [{
130
+ type: Optional
131
+ }, {
132
+ type: Inject,
133
+ args: [ERROR_LOGGER_DEFAULTS]
125
134
  }] }] });
126
135
  //# sourceMappingURL=error-logger.service.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"error-logger.service.js","sourceRoot":"","sources":["../../../../../libs/logging/src/lib/error-logger.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { HttpErrorResponse } from '@angular/common/http';\nimport { Injectable, Optional } from '@angular/core';\nimport { ToastController } from '@ionic/angular';\nimport { captureException, showReportDialog } from '@sentry/angular';\nimport { IErrorLogger, ILogErrorOptions } from '@sneat/core';\n\nconst defaultErrorToastDuration = 7000;\n\n@Injectable()\nexport class ErrorLoggerService implements IErrorLogger {\n constructor(@Optional() private readonly toastController: ToastController) {}\n\n public readonly logErrorHandler =\n (message?: string, options?: ILogErrorOptions) => (e: unknown) =>\n this.logError(e, message, options);\n\n public readonly logError = (\n e: unknown,\n message?: string,\n options?: ILogErrorOptions,\n ): void => {\n // logError(e, message, options) is easy to call with `e` and `message`\n // swapped (both a string and unknown/undefined are type-legal in either\n // slot, so the compiler can't catch it). A string `e` combined with a\n // non-string `message` is the tell-tale sign of that swap — e.g. a real\n // Error/HttpErrorResponse landing in `message`, where its fields (like\n // HttpErrorResponse's server-provided message) are never read. Warn\n // loudly so it isn't silently swallowed again.\n if (\n typeof e === 'string' &&\n message !== undefined &&\n typeof message !== 'string'\n ) {\n console.error(\n 'ErrorLoggerService.logError: arguments look swapped — got a string for `e` and a non-string for `message`. Expected logError(error: unknown, message?: string, options?).',\n { e, message },\n );\n }\n console.error(\n `ErrorLoggerService.logError: ${message || 'Error'}:`,\n e,\n '; Logging options:',\n options,\n );\n // Server rendering must record the error without invoking browser-only\n // Sentry feedback UI or Ionic toasts.\n if (typeof window === 'undefined') {\n return;\n }\n if (e === true || e === false) {\n try {\n // noinspection ExceptionCaughtLocallyJS\n throw new Error(`got boolean value as an error: ${e}: ${message}`);\n } catch (ex) {\n console.error('Argument exception at logError():', ex, options);\n return;\n }\n }\n if (options?.report === undefined || options.report) {\n if (window.location.hostname !== 'localhost') {\n try {\n const eventId = message\n ? captureException(message, { originalException: e })\n : captureException(e);\n\n // console.log('Captured error by Sentry with eventId:', eventId);\n if (options?.feedback === undefined || options.feedback) {\n showReportDialog({ eventId });\n }\n } catch (ex) {\n console.error(\n 'Sentry failed to capture or show error report dialog',\n ex,\n );\n }\n }\n }\n if (options?.show || options?.show === undefined) {\n this.showError(e, options?.showDuration);\n }\n return; // return message ? { error: e, message } : e;\n };\n\n public showError(e: unknown, duration?: number): void {\n let clientMessage: string | undefined;\n\n if ((e as { message?: string }).message) {\n clientMessage =\n (clientMessage &&\n `${clientMessage}: ${(e as { message?: string }).message}`) ||\n (e as { message?: string }).message;\n } else if (!clientMessage) {\n clientMessage = (e as object).toString();\n }\n if (!clientMessage) {\n throw new Error('showError() have not received a message to display');\n }\n if (duration && duration < 0) {\n throw new Error('showError received negative duration');\n }\n\n let message = clientMessage;\n\n let serverMessage: string | undefined;\n if (e instanceof HttpErrorResponse) {\n const e2 = e as HttpErrorResponse;\n serverMessage = e2.error?.error?.message;\n if (serverMessage) {\n message += `.\\n\\nServer returned error message: ${serverMessage}`;\n }\n }\n if (!this.toastController) {\n console.warn('ToastController not available, cannot show error toast');\n return;\n }\n this.toastController\n .create({\n message,\n duration: duration || defaultErrorToastDuration,\n keyboardClose: true,\n buttons: [\n {\n icon: 'close',\n side: 'end',\n handler: () =>\n this.toastController.dismiss().catch((e) =>\n this.logError(e, 'Failed to dismiss error dialog', {\n show: false,\n }),\n ),\n },\n ],\n color: 'danger',\n header: 'Something went wrong',\n position: 'top',\n })\n .then((toast) =>\n toast\n .present()\n .catch(\n this.logErrorHandler(\n 'Failed to present toast with error message:',\n { show: false },\n ),\n ),\n )\n .catch(\n this.logErrorHandler('Failed to create a toast with error message:', {\n show: false,\n }),\n );\n }\n}\n"]}
1
+ {"version":3,"file":"error-logger.service.js","sourceRoot":"","sources":["../../../../../libs/logging/src/lib/error-logger.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAErE,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;;;AAEhE,MAAM,yBAAyB,GAAG,IAAI,CAAC;AAGvC,MAAM,OAAO,kBAAkB;IAC7B,YAC+B,eAAgC,EAG5C,QAAiC;QAHrB,oBAAe,GAAf,eAAe,CAAiB;QAG5C,aAAQ,GAAR,QAAQ,CAAyB;QAGpC,oBAAe,GAC7B,CAAC,OAAgB,EAAE,OAA0B,EAAE,EAAE,CAAC,CAAC,CAAU,EAAE,EAAE,CAC/D,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QAEvB,aAAQ,GAAG,CACzB,CAAU,EACV,OAAgB,EAChB,OAA0B,EACpB,EAAE;YACR,uEAAuE;YACvE,wEAAwE;YACxE,sEAAsE;YACtE,wEAAwE;YACxE,uEAAuE;YACvE,oEAAoE;YACpE,+CAA+C;YAC/C,IACE,OAAO,CAAC,KAAK,QAAQ;gBACrB,OAAO,KAAK,SAAS;gBACrB,OAAO,OAAO,KAAK,QAAQ,EAC3B,CAAC;gBACD,OAAO,CAAC,KAAK,CACX,2KAA2K,EAC3K,EAAE,CAAC,EAAE,OAAO,EAAE,CACf,CAAC;YACJ,CAAC;YACD,OAAO,CAAC,KAAK,CACX,gCAAgC,OAAO,IAAI,OAAO,GAAG,EACrD,CAAC,EACD,oBAAoB,EACpB,OAAO,CACR,CAAC;YACF,uEAAuE;YACvE,sCAAsC;YACtC,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE,CAAC;gBAClC,OAAO;YACT,CAAC;YACD,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,KAAK,EAAE,CAAC;gBAC9B,IAAI,CAAC;oBACH,wCAAwC;oBACxC,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,KAAK,OAAO,EAAE,CAAC,CAAC;gBACrE,CAAC;gBAAC,OAAO,EAAE,EAAE,CAAC;oBACZ,OAAO,CAAC,KAAK,CAAC,mCAAmC,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;oBAChE,OAAO;gBACT,CAAC;YACH,CAAC;YACD,IAAI,OAAO,EAAE,MAAM,KAAK,SAAS,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;gBACpD,IAAI,MAAM,CAAC,QAAQ,CAAC,QAAQ,KAAK,WAAW,EAAE,CAAC;oBAC7C,IAAI,CAAC;wBACH,MAAM,OAAO,GAAG,OAAO;4BACrB,CAAC,CAAC,gBAAgB,CAAC,OAAO,EAAE,EAAE,iBAAiB,EAAE,CAAC,EAAE,CAAC;4BACrD,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC;wBAExB,kEAAkE;wBAClE,MAAM,QAAQ,GACZ,OAAO,EAAE,QAAQ,IAAI,IAAI,CAAC,QAAQ,EAAE,QAAQ,IAAI,IAAI,CAAC;wBACvD,IAAI,QAAQ,EAAE,CAAC;4BACb,gBAAgB,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC;wBAChC,CAAC;oBACH,CAAC;oBAAC,OAAO,EAAE,EAAE,CAAC;wBACZ,OAAO,CAAC,KAAK,CACX,uDAAuD,EACvD,EAAE,CACH,CAAC;oBACJ,CAAC;gBACH,CAAC;YACH,CAAC;YACD,MAAM,IAAI,GAAG,OAAO,EAAE,IAAI,IAAI,IAAI,CAAC,QAAQ,EAAE,IAAI,IAAI,IAAI,CAAC;YAC1D,IAAI,IAAI,EAAE,CAAC;gBACT,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,OAAO,EAAE,YAAY,CAAC,CAAC;YAC3C,CAAC;YACD,OAAO,CAAC,8CAA8C;QACxD,CAAC,CAAC;IA1EC,CAAC;IA4EG,SAAS,CAAC,CAAU,EAAE,QAAiB;QAC5C,IAAI,aAAiC,CAAC;QAEtC,IAAK,CAA0B,CAAC,OAAO,EAAE,CAAC;YACxC,aAAa;gBACX,CAAC,aAAa;oBACZ,GAAG,aAAa,KAAM,CAA0B,CAAC,OAAO,EAAE,CAAC;oBAC5D,CAA0B,CAAC,OAAO,CAAC;QACxC,CAAC;aAAM,IAAI,CAAC,aAAa,EAAE,CAAC;YAC1B,aAAa,GAAI,CAAY,CAAC,QAAQ,EAAE,CAAC;QAC3C,CAAC;QACD,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;QACxE,CAAC;QACD,IAAI,QAAQ,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;YAC7B,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;QAC1D,CAAC;QAED,IAAI,OAAO,GAAG,aAAa,CAAC;QAE5B,IAAI,aAAiC,CAAC;QACtC,IAAI,CAAC,YAAY,iBAAiB,EAAE,CAAC;YACnC,MAAM,EAAE,GAAG,CAAsB,CAAC;YAClC,aAAa,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC;YACzC,IAAI,aAAa,EAAE,CAAC;gBAClB,OAAO,IAAI,uCAAuC,aAAa,EAAE,CAAC;YACpE,CAAC;QACH,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC;YAC1B,OAAO,CAAC,IAAI,CAAC,wDAAwD,CAAC,CAAC;YACvE,OAAO;QACT,CAAC;QACD,IAAI,CAAC,eAAe;aACjB,MAAM,CAAC;YACN,OAAO;YACP,QAAQ,EAAE,QAAQ,IAAI,yBAAyB;YAC/C,aAAa,EAAE,IAAI;YACnB,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,OAAO;oBACb,IAAI,EAAE,KAAK;oBACX,OAAO,EAAE,GAAG,EAAE,CACZ,IAAI,CAAC,eAAe,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CACzC,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,gCAAgC,EAAE;wBACjD,IAAI,EAAE,KAAK;qBACZ,CAAC,CACH;iBACJ;aACF;YACD,KAAK,EAAE,QAAQ;YACf,MAAM,EAAE,sBAAsB;YAC9B,QAAQ,EAAE,KAAK;SAChB,CAAC;aACD,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CACd,KAAK;aACF,OAAO,EAAE;aACT,KAAK,CACJ,IAAI,CAAC,eAAe,CAClB,6CAA6C,EAC7C,EAAE,IAAI,EAAE,KAAK,EAAE,CAChB,CACF,CACJ;aACA,KAAK,CACJ,IAAI,CAAC,eAAe,CAAC,8CAA8C,EAAE;YACnE,IAAI,EAAE,KAAK;SACZ,CAAC,CACH,CAAC;IACN,CAAC;8GAtJU,kBAAkB,iEAInB,qBAAqB;kHAJpB,kBAAkB;;2FAAlB,kBAAkB;kBAD9B,UAAU;;0BAGN,QAAQ;;0BACR,QAAQ;;0BACR,MAAM;2BAAC,qBAAqB","sourcesContent":["import { HttpErrorResponse } from '@angular/common/http';\nimport { Inject, Injectable, Optional } from '@angular/core';\nimport { ToastController } from '@ionic/angular';\nimport { captureException, showReportDialog } from '@sentry/angular';\nimport { IErrorLogger, ILogErrorOptions } from '@sneat/core';\nimport { ERROR_LOGGER_DEFAULTS } from './error-logger-defaults';\n\nconst defaultErrorToastDuration = 7000;\n\n@Injectable()\nexport class ErrorLoggerService implements IErrorLogger {\n constructor(\n @Optional() private readonly toastController: ToastController,\n @Optional()\n @Inject(ERROR_LOGGER_DEFAULTS)\n private readonly defaults: ILogErrorOptions | null,\n ) {}\n\n public readonly logErrorHandler =\n (message?: string, options?: ILogErrorOptions) => (e: unknown) =>\n this.logError(e, message, options);\n\n public readonly logError = (\n e: unknown,\n message?: string,\n options?: ILogErrorOptions,\n ): void => {\n // logError(e, message, options) is easy to call with `e` and `message`\n // swapped (both a string and unknown/undefined are type-legal in either\n // slot, so the compiler can't catch it). A string `e` combined with a\n // non-string `message` is the tell-tale sign of that swap — e.g. a real\n // Error/HttpErrorResponse landing in `message`, where its fields (like\n // HttpErrorResponse's server-provided message) are never read. Warn\n // loudly so it isn't silently swallowed again.\n if (\n typeof e === 'string' &&\n message !== undefined &&\n typeof message !== 'string'\n ) {\n console.error(\n 'ErrorLoggerService.logError: arguments look swapped — got a string for `e` and a non-string for `message`. Expected logError(error: unknown, message?: string, options?).',\n { e, message },\n );\n }\n console.error(\n `ErrorLoggerService.logError: ${message || 'Error'}:`,\n e,\n '; Logging options:',\n options,\n );\n // Server rendering must record the error without invoking browser-only\n // Sentry feedback UI or Ionic toasts.\n if (typeof window === 'undefined') {\n return;\n }\n if (e === true || e === false) {\n try {\n // noinspection ExceptionCaughtLocallyJS\n throw new Error(`got boolean value as an error: ${e}: ${message}`);\n } catch (ex) {\n console.error('Argument exception at logError():', ex, options);\n return;\n }\n }\n if (options?.report === undefined || options.report) {\n if (window.location.hostname !== 'localhost') {\n try {\n const eventId = message\n ? captureException(message, { originalException: e })\n : captureException(e);\n\n // console.log('Captured error by Sentry with eventId:', eventId);\n const feedback =\n options?.feedback ?? this.defaults?.feedback ?? true;\n if (feedback) {\n showReportDialog({ eventId });\n }\n } catch (ex) {\n console.error(\n 'Sentry failed to capture or show error report dialog',\n ex,\n );\n }\n }\n }\n const show = options?.show ?? this.defaults?.show ?? true;\n if (show) {\n this.showError(e, options?.showDuration);\n }\n return; // return message ? { error: e, message } : e;\n };\n\n public showError(e: unknown, duration?: number): void {\n let clientMessage: string | undefined;\n\n if ((e as { message?: string }).message) {\n clientMessage =\n (clientMessage &&\n `${clientMessage}: ${(e as { message?: string }).message}`) ||\n (e as { message?: string }).message;\n } else if (!clientMessage) {\n clientMessage = (e as object).toString();\n }\n if (!clientMessage) {\n throw new Error('showError() have not received a message to display');\n }\n if (duration && duration < 0) {\n throw new Error('showError received negative duration');\n }\n\n let message = clientMessage;\n\n let serverMessage: string | undefined;\n if (e instanceof HttpErrorResponse) {\n const e2 = e as HttpErrorResponse;\n serverMessage = e2.error?.error?.message;\n if (serverMessage) {\n message += `.\\n\\nServer returned error message: ${serverMessage}`;\n }\n }\n if (!this.toastController) {\n console.warn('ToastController not available, cannot show error toast');\n return;\n }\n this.toastController\n .create({\n message,\n duration: duration || defaultErrorToastDuration,\n keyboardClose: true,\n buttons: [\n {\n icon: 'close',\n side: 'end',\n handler: () =>\n this.toastController.dismiss().catch((e) =>\n this.logError(e, 'Failed to dismiss error dialog', {\n show: false,\n }),\n ),\n },\n ],\n color: 'danger',\n header: 'Something went wrong',\n position: 'top',\n })\n .then((toast) =>\n toast\n .present()\n .catch(\n this.logErrorHandler(\n 'Failed to present toast with error message:',\n { show: false },\n ),\n ),\n )\n .catch(\n this.logErrorHandler('Failed to create a toast with error message:', {\n show: false,\n }),\n );\n }\n}\n"]}
@@ -1,12 +1,34 @@
1
1
  import { NgModule } from '@angular/core';
2
2
  import { ErrorLogger } from '@sneat/core';
3
3
  import { ErrorLoggerService } from './error-logger.service';
4
+ import { provideErrorLoggerDefaults } from './error-logger-defaults';
4
5
  import * as i0 from "@angular/core";
5
- export function provideErrorLogger() {
6
- return {
7
- provide: ErrorLogger,
8
- useClass: ErrorLoggerService,
9
- };
6
+ /**
7
+ * Registers `ErrorLoggerService` as the `ErrorLogger`. Pass `defaults` as
8
+ * sugar for also calling `provideErrorLoggerDefaults(defaults)` — equivalent
9
+ * to, but more convenient than, providing both separately:
10
+ *
11
+ * ```ts
12
+ * providers: [provideErrorLogger({ feedback: false })]
13
+ * ```
14
+ *
15
+ * Prefer a standalone `provideErrorLoggerDefaults(...)` at the app root when
16
+ * some other bundle (e.g. `@sneat/app-auth`'s
17
+ * `provideSneatAuthenticatedProviders()`) also calls `provideErrorLogger()` —
18
+ * see {@link provideErrorLoggerDefaults} for why the defaults still apply
19
+ * regardless of provider registration order.
20
+ */
21
+ export function provideErrorLogger(defaults) {
22
+ const providers = [
23
+ {
24
+ provide: ErrorLogger,
25
+ useClass: ErrorLoggerService,
26
+ },
27
+ ];
28
+ if (defaults) {
29
+ providers.push(provideErrorLoggerDefaults(defaults));
30
+ }
31
+ return providers;
10
32
  }
11
33
  export class SneatLoggingModule {
12
34
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SneatLoggingModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
@@ -1 +1 @@
1
- {"version":3,"file":"sneat-logging.module.js","sourceRoot":"","sources":["../../../../../libs/logging/src/lib/sneat-logging.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAY,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;;AAE5D,MAAM,UAAU,kBAAkB;IAChC,OAAO;QACL,OAAO,EAAE,WAAW;QACpB,QAAQ,EAAE,kBAAkB;KAC7B,CAAC;AACJ,CAAC;AAMD,MAAM,OAAO,kBAAkB;8GAAlB,kBAAkB;+GAAlB,kBAAkB;+GAAlB,kBAAkB,aAFlB,CAAC,kBAAkB,EAAE,CAAC;;2FAEtB,kBAAkB;kBAJ9B,QAAQ;mBAAC;oBACR,OAAO,EAAE,EAAE;oBACX,SAAS,EAAE,CAAC,kBAAkB,EAAE,CAAC;iBAClC","sourcesContent":["import { NgModule, Provider } from '@angular/core';\nimport { ErrorLogger } from '@sneat/core';\nimport { ErrorLoggerService } from './error-logger.service';\n\nexport function provideErrorLogger(): Provider {\n return {\n provide: ErrorLogger,\n useClass: ErrorLoggerService,\n };\n}\n\n@NgModule({\n imports: [],\n providers: [provideErrorLogger()],\n})\nexport class SneatLoggingModule {}\n"]}
1
+ {"version":3,"file":"sneat-logging.module.js","sourceRoot":"","sources":["../../../../../libs/logging/src/lib/sneat-logging.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAY,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,WAAW,EAAoB,MAAM,aAAa,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,0BAA0B,EAAE,MAAM,yBAAyB,CAAC;;AAErE;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,kBAAkB,CAAC,QAA2B;IAC5D,MAAM,SAAS,GAAe;QAC5B;YACE,OAAO,EAAE,WAAW;YACpB,QAAQ,EAAE,kBAAkB;SAC7B;KACF,CAAC;IACF,IAAI,QAAQ,EAAE,CAAC;QACb,SAAS,CAAC,IAAI,CAAC,0BAA0B,CAAC,QAAQ,CAAC,CAAC,CAAC;IACvD,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAMD,MAAM,OAAO,kBAAkB;8GAAlB,kBAAkB;+GAAlB,kBAAkB;+GAAlB,kBAAkB,aAFlB,CAAC,kBAAkB,EAAE,CAAC;;2FAEtB,kBAAkB;kBAJ9B,QAAQ;mBAAC;oBACR,OAAO,EAAE,EAAE;oBACX,SAAS,EAAE,CAAC,kBAAkB,EAAE,CAAC;iBAClC","sourcesContent":["import { NgModule, Provider } from '@angular/core';\nimport { ErrorLogger, ILogErrorOptions } from '@sneat/core';\nimport { ErrorLoggerService } from './error-logger.service';\nimport { provideErrorLoggerDefaults } from './error-logger-defaults';\n\n/**\n * Registers `ErrorLoggerService` as the `ErrorLogger`. Pass `defaults` as\n * sugar for also calling `provideErrorLoggerDefaults(defaults)` — equivalent\n * to, but more convenient than, providing both separately:\n *\n * ```ts\n * providers: [provideErrorLogger({ feedback: false })]\n * ```\n *\n * Prefer a standalone `provideErrorLoggerDefaults(...)` at the app root when\n * some other bundle (e.g. `@sneat/app-auth`'s\n * `provideSneatAuthenticatedProviders()`) also calls `provideErrorLogger()` —\n * see {@link provideErrorLoggerDefaults} for why the defaults still apply\n * regardless of provider registration order.\n */\nexport function provideErrorLogger(defaults?: ILogErrorOptions): Provider[] {\n const providers: Provider[] = [\n {\n provide: ErrorLogger,\n useClass: ErrorLoggerService,\n },\n ];\n if (defaults) {\n providers.push(provideErrorLoggerDefaults(defaults));\n }\n return providers;\n}\n\n@NgModule({\n imports: [],\n providers: [provideErrorLogger()],\n})\nexport class SneatLoggingModule {}\n"]}
package/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from './lib/sentry-setup';
2
2
  export * from './lib/chunk-load-error.handler';
3
3
  export * from './lib/sneat-logging.module';
4
+ export * from './lib/error-logger-defaults';
4
5
  export * from './lib/analytics';
@@ -0,0 +1,33 @@
1
+ import { InjectionToken, Provider } from '@angular/core';
2
+ import { ILogErrorOptions } from '@sneat/core';
3
+ /**
4
+ * App-level defaults for {@link ErrorLoggerService}, applied whenever a
5
+ * per-call `ILogErrorOptions` does not specify the option itself.
6
+ * `ErrorLoggerService` resolves each supported option as
7
+ * `options.<key> ?? defaults.<key> ?? <built-in default>` — so an explicit
8
+ * per-call value always wins over the app-level default, which in turn wins
9
+ * over the built-in default.
10
+ *
11
+ * No provider registered means "use the built-in defaults" — e.g. Sentry's
12
+ * report dialog is shown for every reported error, matching the behaviour
13
+ * before this token existed.
14
+ */
15
+ export declare const ERROR_LOGGER_DEFAULTS: InjectionToken<ILogErrorOptions>;
16
+ /**
17
+ * Registers app-level defaults for `ErrorLoggerService`. Typical use: never
18
+ * show Sentry's report dialog for errors logged via `logError()`, while still
19
+ * showing Sentry's own dialog for uncaught exceptions (handled separately by
20
+ * `createErrorHandler`, wired up by `provideSentryAppInitializer`):
21
+ *
22
+ * ```ts
23
+ * providers: [provideErrorLoggerDefaults({ feedback: false })]
24
+ * ```
25
+ *
26
+ * Provide this once, at the app level. It survives a later `provideErrorLogger()`
27
+ * registration performed by another bundle (e.g.
28
+ * `provideSneatAuthenticatedProviders()` from `@sneat/app-auth`, which calls
29
+ * `provideErrorLogger()` internally) because that call only re-provides
30
+ * `ErrorLogger` itself, never `ERROR_LOGGER_DEFAULTS` — so an app-level default
31
+ * wins regardless of provider registration order.
32
+ */
33
+ export declare function provideErrorLoggerDefaults(defaults: ILogErrorOptions): Provider;
@@ -3,10 +3,11 @@ import { IErrorLogger, ILogErrorOptions } from '@sneat/core';
3
3
  import * as i0 from "@angular/core";
4
4
  export declare class ErrorLoggerService implements IErrorLogger {
5
5
  private readonly toastController;
6
- constructor(toastController: ToastController);
6
+ private readonly defaults;
7
+ constructor(toastController: ToastController, defaults: ILogErrorOptions | null);
7
8
  readonly logErrorHandler: (message?: string, options?: ILogErrorOptions) => (e: unknown) => void;
8
9
  readonly logError: (e: unknown, message?: string, options?: ILogErrorOptions) => void;
9
10
  showError(e: unknown, duration?: number): void;
10
- static ɵfac: i0.ɵɵFactoryDeclaration<ErrorLoggerService, [{ optional: true; }]>;
11
+ static ɵfac: i0.ɵɵFactoryDeclaration<ErrorLoggerService, [{ optional: true; }, { optional: true; }]>;
11
12
  static ɵprov: i0.ɵɵInjectableDeclaration<ErrorLoggerService>;
12
13
  }
@@ -1,6 +1,22 @@
1
1
  import { Provider } from '@angular/core';
2
+ import { ILogErrorOptions } from '@sneat/core';
2
3
  import * as i0 from "@angular/core";
3
- export declare function provideErrorLogger(): Provider;
4
+ /**
5
+ * Registers `ErrorLoggerService` as the `ErrorLogger`. Pass `defaults` as
6
+ * sugar for also calling `provideErrorLoggerDefaults(defaults)` — equivalent
7
+ * to, but more convenient than, providing both separately:
8
+ *
9
+ * ```ts
10
+ * providers: [provideErrorLogger({ feedback: false })]
11
+ * ```
12
+ *
13
+ * Prefer a standalone `provideErrorLoggerDefaults(...)` at the app root when
14
+ * some other bundle (e.g. `@sneat/app-auth`'s
15
+ * `provideSneatAuthenticatedProviders()`) also calls `provideErrorLogger()` —
16
+ * see {@link provideErrorLoggerDefaults} for why the defaults still apply
17
+ * regardless of provider registration order.
18
+ */
19
+ export declare function provideErrorLogger(defaults?: ILogErrorOptions): Provider[];
4
20
  export declare class SneatLoggingModule {
5
21
  static ɵfac: i0.ɵɵFactoryDeclaration<SneatLoggingModule, never>;
6
22
  static ɵmod: i0.ɵɵNgModuleDeclaration<SneatLoggingModule, never, never, never>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sneat/logging",
3
- "version": "0.27.24",
3
+ "version": "0.27.26",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },