@sneat/logging 0.26.6 → 0.27.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,12 +1,20 @@
1
1
  import { inject, Injectable } from '@angular/core';
2
- import { Analytics, logEvent, setUserId, setUserProperties, } from '@angular/fire/analytics';
3
- import { ErrorLogger } from '@sneat/core';
2
+ import { logEvent, setUserId, setUserProperties } from 'firebase/analytics';
3
+ import { ErrorLogger, SNEAT_FIREBASE_ANALYTICS, } from '@sneat/core';
4
4
  import * as i0 from "@angular/core";
5
5
  const logErrOptions = { show: false, feedback: false };
6
6
  export class FireAnalyticsService {
7
7
  constructor() {
8
8
  this.errorLogger = inject(ErrorLogger);
9
- this.analytics = inject(Analytics);
9
+ /**
10
+ * Nullable by contract: `SNEAT_FIREBASE_ANALYTICS` resolves to `null` — it
11
+ * never throws — when the app has no real `measurementId` or when
12
+ * `getAnalytics()` is unsupported in the host environment. Every method
13
+ * below therefore no-ops on `null` instead of reporting a failed SDK call
14
+ * on each event. Before 0.27.0 this injected `@angular/fire`'s `Analytics`
15
+ * token, which threw NullInjectorError in exactly those cases.
16
+ */
17
+ this.analytics = inject(SNEAT_FIREBASE_ANALYTICS);
10
18
  this.logError = (e, m) => this.errorLogger.logError(e, m, logErrOptions);
11
19
  if (!this.errorLogger) {
12
20
  console.error(`FireAnalyticsService() - !errorLogger`);
@@ -16,25 +24,34 @@ export class FireAnalyticsService {
16
24
  }
17
25
  }
18
26
  logEvent(eventName, eventParams, options) {
27
+ const analytics = this.analytics;
28
+ if (!analytics)
29
+ return;
19
30
  try {
20
- logEvent(this.analytics, eventName, eventParams, options);
31
+ logEvent(analytics, eventName, eventParams, options);
21
32
  }
22
33
  catch (e) {
23
34
  this.logError(e, 'Failed to log event to Firebase analytics');
24
35
  }
25
36
  }
26
37
  setCurrentScreen(screenName, options) {
38
+ const analytics = this.analytics;
39
+ if (!analytics)
40
+ return;
27
41
  try {
28
42
  const args = { screenName: screenName };
29
- logEvent(this.analytics, '$screen_view', args, options);
43
+ logEvent(analytics, '$screen_view', args, options);
30
44
  }
31
45
  catch (e) {
32
46
  this.logError(e, 'Failed to log screen view to Firebase analytics');
33
47
  }
34
48
  }
35
49
  identify(userID, userPropertiesToSet, userPropertiesToSetOnce) {
50
+ const analytics = this.analytics;
51
+ if (!analytics)
52
+ return;
36
53
  try {
37
- setUserId(this.analytics, userID);
54
+ setUserId(analytics, userID);
38
55
  }
39
56
  catch (e) {
40
57
  this.logError(e, 'Failed to set user id in Firebase analytics');
@@ -45,15 +62,18 @@ export class FireAnalyticsService {
45
62
  if (userPropertiesToSetOnce)
46
63
  Object.keys(userPropertiesToSetOnce).forEach((k) => (customProperties[k] = userPropertiesToSetOnce[k]));
47
64
  try {
48
- setUserProperties(this.analytics, customProperties);
65
+ setUserProperties(analytics, customProperties);
49
66
  }
50
67
  catch (e) {
51
68
  this.logError(e, 'Failed to set user props in Firebase analytics');
52
69
  }
53
70
  }
54
71
  loggedOut() {
72
+ const analytics = this.analytics;
73
+ if (!analytics)
74
+ return;
55
75
  try {
56
- setUserId(this.analytics, null);
76
+ setUserId(analytics, null);
57
77
  }
58
78
  catch (e) {
59
79
  this.logError(e, 'Failed to logout user from Firebase analytics');
@@ -1 +1 @@
1
- {"version":3,"file":"fire-analytics.service.js","sourceRoot":"","sources":["../../../../../../libs/logging/src/lib/analytics/fire-analytics.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EACL,SAAS,EACT,QAAQ,EACR,SAAS,EACT,iBAAiB,GAClB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,WAAW,EAAkC,MAAM,aAAa,CAAC;;AAO1E,MAAM,aAAa,GAAqB,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;AAGzE,MAAM,OAAO,oBAAoB;IAI/B;QAHiB,gBAAW,GAAG,MAAM,CAAe,WAAW,CAAC,CAAC;QAChD,cAAS,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;QAW9B,aAAQ,GAAG,CAAC,CAAU,EAAE,CAAS,EAAE,EAAE,CACpD,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,aAAa,CAAC,CAAC;QAT/C,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YACtB,OAAO,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC;QACzD,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;YACpB,OAAO,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAC;QACvD,CAAC;IACH,CAAC;IAKM,QAAQ,CACb,SAAiB,EACjB,WAAqC,EACrC,OAA+B;QAE/B,IAAI,CAAC;YACH,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC;QAC5D,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,2CAA2C,CAAC,CAAC;QAChE,CAAC;IACH,CAAC;IAEM,gBAAgB,CACrB,UAAkB,EAClB,OAA+B;QAE/B,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC;YACxC,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,cAAc,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;QAC1D,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,iDAAiD,CAAC,CAAC;QACtE,CAAC;IACH,CAAC;IAEM,QAAQ,CACb,MAAc,EACd,mBAAoC,EACpC,uBAAwC;QAExC,IAAI,CAAC;YACH,SAAS,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;QACpC,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,6CAA6C,CAAC,CAAC;QAClE,CAAC;QACD,MAAM,gBAAgB,GAA8B,EAAE,CAAC;QAEvD,IAAI,mBAAmB;YACrB,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,OAAO,CACtC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,GAAG,mBAAmB,CAAC,CAAC,CAAC,CAAC,CACtD,CAAC;QACJ,IAAI,uBAAuB;YACzB,MAAM,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC,OAAO,CAC1C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,GAAG,uBAAuB,CAAC,CAAC,CAAC,CAAC,CAC1D,CAAC;QACJ,IAAI,CAAC;YACH,iBAAiB,CAAC,IAAI,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;QACtD,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,gDAAgD,CAAC,CAAC;QACrE,CAAC;IACH,CAAC;IAEM,SAAS;QACd,IAAI,CAAC;YACH,SAAS,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;QAClC,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,+CAA+C,CAAC,CAAC;QACpE,CAAC;IACH,CAAC;8GAzEU,oBAAoB;kHAApB,oBAAoB;;2FAApB,oBAAoB;kBADhC,UAAU","sourcesContent":["import { inject, Injectable } from '@angular/core';\nimport {\n Analytics,\n logEvent,\n setUserId,\n setUserProperties,\n} from '@angular/fire/analytics';\nimport { ErrorLogger, IErrorLogger, ILogErrorOptions } from '@sneat/core';\nimport {\n IAnalyticsCallOptions,\n IAnalyticsService,\n UserProperties,\n} from '@sneat/core';\n\nconst logErrOptions: ILogErrorOptions = { show: false, feedback: false };\n\n@Injectable()\nexport class FireAnalyticsService implements IAnalyticsService {\n private readonly errorLogger = inject<IErrorLogger>(ErrorLogger);\n private readonly analytics = inject(Analytics);\n\n constructor() {\n if (!this.errorLogger) {\n console.error(`FireAnalyticsService() - !errorLogger`);\n }\n if (!this.analytics) {\n console.error(`FireAnalyticsService() - !analytics`);\n }\n }\n\n private readonly logError = (e: unknown, m: string) =>\n this.errorLogger.logError(e, m, logErrOptions);\n\n public logEvent(\n eventName: string,\n eventParams?: Record<string, unknown>,\n options?: IAnalyticsCallOptions,\n ): void {\n try {\n logEvent(this.analytics, eventName, eventParams, options);\n } catch (e) {\n this.logError(e, 'Failed to log event to Firebase analytics');\n }\n }\n\n public setCurrentScreen(\n screenName: string,\n options?: IAnalyticsCallOptions,\n ): void {\n try {\n const args = { screenName: screenName };\n logEvent(this.analytics, '$screen_view', args, options);\n } catch (e) {\n this.logError(e, 'Failed to log screen view to Firebase analytics');\n }\n }\n\n public identify(\n userID: string,\n userPropertiesToSet?: UserProperties,\n userPropertiesToSetOnce?: UserProperties,\n ): void {\n try {\n setUserId(this.analytics, userID);\n } catch (e) {\n this.logError(e, 'Failed to set user id in Firebase analytics');\n }\n const customProperties: { [id: string]: unknown } = {};\n\n if (userPropertiesToSet)\n Object.keys(userPropertiesToSet).forEach(\n (k) => (customProperties[k] = userPropertiesToSet[k]),\n );\n if (userPropertiesToSetOnce)\n Object.keys(userPropertiesToSetOnce).forEach(\n (k) => (customProperties[k] = userPropertiesToSetOnce[k]),\n );\n try {\n setUserProperties(this.analytics, customProperties);\n } catch (e) {\n this.logError(e, 'Failed to set user props in Firebase analytics');\n }\n }\n\n public loggedOut(): void {\n try {\n setUserId(this.analytics, null);\n } catch (e) {\n this.logError(e, 'Failed to logout user from Firebase analytics');\n }\n }\n}\n"]}
1
+ {"version":3,"file":"fire-analytics.service.js","sourceRoot":"","sources":["../../../../../../libs/logging/src/lib/analytics/fire-analytics.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { inject, Injectable } from '@angular/core';\nimport { logEvent, setUserId, setUserProperties } from 'firebase/analytics';\nimport {\n ErrorLogger,\n IErrorLogger,\n ILogErrorOptions,\n SNEAT_FIREBASE_ANALYTICS,\n} from '@sneat/core';\nimport {\n IAnalyticsCallOptions,\n IAnalyticsService,\n UserProperties,\n} from '@sneat/core';\n\nconst logErrOptions: ILogErrorOptions = { show: false, feedback: false };\n\n@Injectable()\nexport class FireAnalyticsService implements IAnalyticsService {\n private readonly errorLogger = inject<IErrorLogger>(ErrorLogger);\n\n /**\n * Nullable by contract: `SNEAT_FIREBASE_ANALYTICS` resolves to `null` — it\n * never throws — when the app has no real `measurementId` or when\n * `getAnalytics()` is unsupported in the host environment. Every method\n * below therefore no-ops on `null` instead of reporting a failed SDK call\n * on each event. Before 0.27.0 this injected `@angular/fire`'s `Analytics`\n * token, which threw NullInjectorError in exactly those cases.\n */\n private readonly analytics = inject(SNEAT_FIREBASE_ANALYTICS);\n\n constructor() {\n if (!this.errorLogger) {\n console.error(`FireAnalyticsService() - !errorLogger`);\n }\n if (!this.analytics) {\n console.error(`FireAnalyticsService() - !analytics`);\n }\n }\n\n private readonly logError = (e: unknown, m: string) =>\n this.errorLogger.logError(e, m, logErrOptions);\n\n public logEvent(\n eventName: string,\n eventParams?: Record<string, unknown>,\n options?: IAnalyticsCallOptions,\n ): void {\n const analytics = this.analytics;\n if (!analytics) return;\n try {\n logEvent(analytics, eventName, eventParams, options);\n } catch (e) {\n this.logError(e, 'Failed to log event to Firebase analytics');\n }\n }\n\n public setCurrentScreen(\n screenName: string,\n options?: IAnalyticsCallOptions,\n ): void {\n const analytics = this.analytics;\n if (!analytics) return;\n try {\n const args = { screenName: screenName };\n logEvent(analytics, '$screen_view', args, options);\n } catch (e) {\n this.logError(e, 'Failed to log screen view to Firebase analytics');\n }\n }\n\n public identify(\n userID: string,\n userPropertiesToSet?: UserProperties,\n userPropertiesToSetOnce?: UserProperties,\n ): void {\n const analytics = this.analytics;\n if (!analytics) return;\n try {\n setUserId(analytics, userID);\n } catch (e) {\n this.logError(e, 'Failed to set user id in Firebase analytics');\n }\n const customProperties: { [id: string]: unknown } = {};\n\n if (userPropertiesToSet)\n Object.keys(userPropertiesToSet).forEach(\n (k) => (customProperties[k] = userPropertiesToSet[k]),\n );\n if (userPropertiesToSetOnce)\n Object.keys(userPropertiesToSetOnce).forEach(\n (k) => (customProperties[k] = userPropertiesToSetOnce[k]),\n );\n try {\n setUserProperties(analytics, customProperties);\n } catch (e) {\n this.logError(e, 'Failed to set user props in Firebase analytics');\n }\n }\n\n public loggedOut(): void {\n const analytics = this.analytics;\n if (!analytics) return;\n try {\n setUserId(analytics, null);\n } catch (e) {\n this.logError(e, 'Failed to logout user from Firebase analytics');\n }\n }\n}\n"]}
@@ -1,11 +1,10 @@
1
- import { getAnalytics } from '@angular/fire/analytics';
2
- import { FirebaseApp } from '@angular/fire/app';
3
- import { AnalyticsService, } from '@sneat/core';
1
+ import { AnalyticsService, SNEAT_FIREBASE_ANALYTICS, } from '@sneat/core';
4
2
  import { ErrorLogger } from '@sneat/core';
5
3
  import { FireAnalyticsService } from './fire-analytics.service';
6
4
  import { GtagAnalyticsService } from './gtag-analytics.service';
7
5
  import { MultiAnalyticsService } from './multi-analytics.service';
8
6
  import { PosthogAnalyticsService } from './posthog-analytics.service';
7
+ import { Injector } from '@angular/core';
9
8
  function getAnalyticsConfig(environmentConfig) {
10
9
  const useAnalytics = location.host === 'sneat.app' || location.protocol === 'https:';
11
10
  const firebaseMeasurementId = environmentConfig.firebaseConfig?.measurementId;
@@ -21,12 +20,14 @@ function getAnalyticsConfig(environmentConfig) {
21
20
  export function provideSneatAnalytics(environmentConfig) {
22
21
  return {
23
22
  provide: AnalyticsService,
24
- deps: [
25
- ErrorLogger,
26
- FirebaseApp,
27
- // [new Optional(), Analytics], // TODO: The received Analytics instance does not have app property :(
28
- ],
29
- useFactory: (errorLogger, fbApp) => {
23
+ // `Injector` rather than `SNEAT_FIREBASE_ANALYTICS` directly: listing the
24
+ // token in `deps` would resolve it — and so initialize Firebase Analytics —
25
+ // on every app that injects `AnalyticsService`, including the ones where
26
+ // `addFirebaseAnalytics` is false (plain http, non-sneat.app host). Reading
27
+ // it through the injector inside the branch below keeps initialization as
28
+ // lazy as the pre-0.27.0 `getAnalytics(fbApp)` call it replaces.
29
+ deps: [ErrorLogger, Injector],
30
+ useFactory: (errorLogger, injector) => {
30
31
  const config = getAnalyticsConfig(environmentConfig);
31
32
  const as = [];
32
33
  if (config?.addPosthog) {
@@ -36,10 +37,12 @@ export function provideSneatAnalytics(environmentConfig) {
36
37
  as.push(new GtagAnalyticsService(config.googleAnalyticsMeasurementId));
37
38
  }
38
39
  if (config?.addFirebaseAnalytics) {
39
- const analytics = fbApp && getAnalytics(fbApp); // Ideally we would want to get it from the DI
40
+ const analytics = injector.get(SNEAT_FIREBASE_ANALYTICS, null);
40
41
  if (analytics) {
42
+ // Constructed inside this factory's injection context, so
43
+ // FireAnalyticsService's own inject(SNEAT_FIREBASE_ANALYTICS)
44
+ // resolves — to this same, already-instantiated instance.
41
45
  as.push(new FireAnalyticsService());
42
- // as.push(new FireAnalyticsService(errorLogger, analytics));
43
46
  }
44
47
  else {
45
48
  errorLogger.logError('addFirebaseAnalytics==true, but Firebase Analytics is not provided', undefined, { show: false, feedback: false });
@@ -1 +1 @@
1
- {"version":3,"file":"provide-sneat-analytics.js","sourceRoot":"","sources":["../../../../../../libs/logging/src/lib/analytics/provide-sneat-analytics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EACL,gBAAgB,GAGjB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,WAAW,EAAgB,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AAWtE,SAAS,kBAAkB,CACzB,iBAAqC;IAErC,MAAM,YAAY,GAChB,QAAQ,CAAC,IAAI,KAAK,WAAW,IAAI,QAAQ,CAAC,QAAQ,KAAK,QAAQ,CAAC;IAElE,MAAM,qBAAqB,GAAG,iBAAiB,CAAC,cAAc,EAAE,aAAa,CAAC;IAC9E,MAAM,eAAe,GAAG,iBAAiB,CAAC,eAAe,EAAE,aAAa,CAAC;IAEzE,OAAO;QACL,UAAU,EAAE,YAAY,IAAI,CAAC,CAAC,iBAAiB,CAAC,OAAO,EAAE,KAAK;QAC9D,oBAAoB,EAClB,YAAY;YACZ,CAAC,CAAC,qBAAqB;YACvB,qBAAqB,KAAK,qBAAqB;QACjD,4BAA4B,EAAE,YAAY,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,SAAS;KACzE,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,iBAAqC;IAErC,OAAO;QACL,OAAO,EAAE,gBAAgB;QACzB,IAAI,EAAE;YACJ,WAAW;YACX,WAAW;YACX,sGAAsG;SACvG;QACD,UAAU,EAAE,CAAC,WAAyB,EAAE,KAAkB,EAAE,EAAE;YAC5D,MAAM,MAAM,GAAG,kBAAkB,CAAC,iBAAiB,CAAC,CAAC;YACrD,MAAM,EAAE,GAAwB,EAAE,CAAC;YACnC,IAAI,MAAM,EAAE,UAAU,EAAE,CAAC;gBACvB,EAAE,CAAC,IAAI,CAAC,IAAI,uBAAuB,EAAE,CAAC,CAAC;YACzC,CAAC;YACD,IAAI,MAAM,EAAE,4BAA4B,EAAE,CAAC;gBACzC,EAAE,CAAC,IAAI,CAAC,IAAI,oBAAoB,CAAC,MAAM,CAAC,4BAA4B,CAAC,CAAC,CAAC;YACzE,CAAC;YACD,IAAI,MAAM,EAAE,oBAAoB,EAAE,CAAC;gBACjC,MAAM,SAAS,GAAc,KAAK,IAAI,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,8CAA8C;gBACzG,IAAI,SAAS,EAAE,CAAC;oBACd,EAAE,CAAC,IAAI,CAAC,IAAI,oBAAoB,EAAE,CAAC,CAAC;oBACpC,6DAA6D;gBAC/D,CAAC;qBAAM,CAAC;oBACN,WAAW,CAAC,QAAQ,CAClB,oEAAoE,EACpE,SAAS,EACT,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,CACjC,CAAC;gBACJ,CAAC;YACH,CAAC;YACD,OAAO,IAAI,qBAAqB,CAAC,EAAE,CAAC,CAAC;QACvC,CAAC;KACF,CAAC;AACJ,CAAC","sourcesContent":["import { Analytics, getAnalytics } from '@angular/fire/analytics';\nimport { FirebaseApp } from '@angular/fire/app';\nimport {\n AnalyticsService,\n IAnalyticsService,\n IEnvironmentConfig,\n} from '@sneat/core';\nimport { ErrorLogger, IErrorLogger } from '@sneat/core';\nimport { FireAnalyticsService } from './fire-analytics.service';\nimport { GtagAnalyticsService } from './gtag-analytics.service';\nimport { MultiAnalyticsService } from './multi-analytics.service';\nimport { PosthogAnalyticsService } from './posthog-analytics.service';\nimport { Provider } from '@angular/core';\n\nexport interface IAnalyticsConfig {\n addPosthog?: boolean;\n addFirebaseAnalytics?: boolean;\n // GA4 measurement ID for the app's own per-domain property (the same stream\n // its marketing landing uses). When set, a gtag-based GA4 backend is added.\n googleAnalyticsMeasurementId?: string;\n}\n\nfunction getAnalyticsConfig(\n environmentConfig: IEnvironmentConfig,\n): IAnalyticsConfig {\n const useAnalytics =\n location.host === 'sneat.app' || location.protocol === 'https:';\n\n const firebaseMeasurementId = environmentConfig.firebaseConfig?.measurementId;\n const gaMeasurementId = environmentConfig.googleAnalytics?.measurementId;\n\n return {\n addPosthog: useAnalytics && !!environmentConfig.posthog?.token,\n addFirebaseAnalytics:\n useAnalytics &&\n !!firebaseMeasurementId &&\n firebaseMeasurementId !== 'G-PROVIDE_IF_NEEDED',\n googleAnalyticsMeasurementId: useAnalytics ? gaMeasurementId : undefined,\n };\n}\n\nexport function provideSneatAnalytics(\n environmentConfig: IEnvironmentConfig,\n): Provider {\n return {\n provide: AnalyticsService,\n deps: [\n ErrorLogger,\n FirebaseApp,\n // [new Optional(), Analytics], // TODO: The received Analytics instance does not have app property :(\n ],\n useFactory: (errorLogger: IErrorLogger, fbApp: FirebaseApp) => {\n const config = getAnalyticsConfig(environmentConfig);\n const as: IAnalyticsService[] = [];\n if (config?.addPosthog) {\n as.push(new PosthogAnalyticsService());\n }\n if (config?.googleAnalyticsMeasurementId) {\n as.push(new GtagAnalyticsService(config.googleAnalyticsMeasurementId));\n }\n if (config?.addFirebaseAnalytics) {\n const analytics: Analytics = fbApp && getAnalytics(fbApp); // Ideally we would want to get it from the DI\n if (analytics) {\n as.push(new FireAnalyticsService());\n // as.push(new FireAnalyticsService(errorLogger, analytics));\n } else {\n errorLogger.logError(\n 'addFirebaseAnalytics==true, but Firebase Analytics is not provided',\n undefined,\n { show: false, feedback: false },\n );\n }\n }\n return new MultiAnalyticsService(as);\n },\n };\n}\n"]}
1
+ {"version":3,"file":"provide-sneat-analytics.js","sourceRoot":"","sources":["../../../../../../libs/logging/src/lib/analytics/provide-sneat-analytics.ts"],"names":[],"mappings":"AACA,OAAO,EACL,gBAAgB,EAGhB,wBAAwB,GACzB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,WAAW,EAAgB,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AACtE,OAAO,EAAE,QAAQ,EAAY,MAAM,eAAe,CAAC;AAUnD,SAAS,kBAAkB,CACzB,iBAAqC;IAErC,MAAM,YAAY,GAChB,QAAQ,CAAC,IAAI,KAAK,WAAW,IAAI,QAAQ,CAAC,QAAQ,KAAK,QAAQ,CAAC;IAElE,MAAM,qBAAqB,GAAG,iBAAiB,CAAC,cAAc,EAAE,aAAa,CAAC;IAC9E,MAAM,eAAe,GAAG,iBAAiB,CAAC,eAAe,EAAE,aAAa,CAAC;IAEzE,OAAO;QACL,UAAU,EAAE,YAAY,IAAI,CAAC,CAAC,iBAAiB,CAAC,OAAO,EAAE,KAAK;QAC9D,oBAAoB,EAClB,YAAY;YACZ,CAAC,CAAC,qBAAqB;YACvB,qBAAqB,KAAK,qBAAqB;QACjD,4BAA4B,EAAE,YAAY,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,SAAS;KACzE,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,iBAAqC;IAErC,OAAO;QACL,OAAO,EAAE,gBAAgB;QACzB,0EAA0E;QAC1E,4EAA4E;QAC5E,yEAAyE;QACzE,4EAA4E;QAC5E,0EAA0E;QAC1E,iEAAiE;QACjE,IAAI,EAAE,CAAC,WAAW,EAAE,QAAQ,CAAC;QAC7B,UAAU,EAAE,CAAC,WAAyB,EAAE,QAAkB,EAAE,EAAE;YAC5D,MAAM,MAAM,GAAG,kBAAkB,CAAC,iBAAiB,CAAC,CAAC;YACrD,MAAM,EAAE,GAAwB,EAAE,CAAC;YACnC,IAAI,MAAM,EAAE,UAAU,EAAE,CAAC;gBACvB,EAAE,CAAC,IAAI,CAAC,IAAI,uBAAuB,EAAE,CAAC,CAAC;YACzC,CAAC;YACD,IAAI,MAAM,EAAE,4BAA4B,EAAE,CAAC;gBACzC,EAAE,CAAC,IAAI,CAAC,IAAI,oBAAoB,CAAC,MAAM,CAAC,4BAA4B,CAAC,CAAC,CAAC;YACzE,CAAC;YACD,IAAI,MAAM,EAAE,oBAAoB,EAAE,CAAC;gBACjC,MAAM,SAAS,GAAqB,QAAQ,CAAC,GAAG,CAC9C,wBAAwB,EACxB,IAAI,CACL,CAAC;gBACF,IAAI,SAAS,EAAE,CAAC;oBACd,0DAA0D;oBAC1D,8DAA8D;oBAC9D,0DAA0D;oBAC1D,EAAE,CAAC,IAAI,CAAC,IAAI,oBAAoB,EAAE,CAAC,CAAC;gBACtC,CAAC;qBAAM,CAAC;oBACN,WAAW,CAAC,QAAQ,CAClB,oEAAoE,EACpE,SAAS,EACT,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,CACjC,CAAC;gBACJ,CAAC;YACH,CAAC;YACD,OAAO,IAAI,qBAAqB,CAAC,EAAE,CAAC,CAAC;QACvC,CAAC;KACF,CAAC;AACJ,CAAC","sourcesContent":["import type { Analytics } from 'firebase/analytics';\nimport {\n AnalyticsService,\n IAnalyticsService,\n IEnvironmentConfig,\n SNEAT_FIREBASE_ANALYTICS,\n} from '@sneat/core';\nimport { ErrorLogger, IErrorLogger } from '@sneat/core';\nimport { FireAnalyticsService } from './fire-analytics.service';\nimport { GtagAnalyticsService } from './gtag-analytics.service';\nimport { MultiAnalyticsService } from './multi-analytics.service';\nimport { PosthogAnalyticsService } from './posthog-analytics.service';\nimport { Injector, Provider } from '@angular/core';\n\nexport interface IAnalyticsConfig {\n addPosthog?: boolean;\n addFirebaseAnalytics?: boolean;\n // GA4 measurement ID for the app's own per-domain property (the same stream\n // its marketing landing uses). When set, a gtag-based GA4 backend is added.\n googleAnalyticsMeasurementId?: string;\n}\n\nfunction getAnalyticsConfig(\n environmentConfig: IEnvironmentConfig,\n): IAnalyticsConfig {\n const useAnalytics =\n location.host === 'sneat.app' || location.protocol === 'https:';\n\n const firebaseMeasurementId = environmentConfig.firebaseConfig?.measurementId;\n const gaMeasurementId = environmentConfig.googleAnalytics?.measurementId;\n\n return {\n addPosthog: useAnalytics && !!environmentConfig.posthog?.token,\n addFirebaseAnalytics:\n useAnalytics &&\n !!firebaseMeasurementId &&\n firebaseMeasurementId !== 'G-PROVIDE_IF_NEEDED',\n googleAnalyticsMeasurementId: useAnalytics ? gaMeasurementId : undefined,\n };\n}\n\nexport function provideSneatAnalytics(\n environmentConfig: IEnvironmentConfig,\n): Provider {\n return {\n provide: AnalyticsService,\n // `Injector` rather than `SNEAT_FIREBASE_ANALYTICS` directly: listing the\n // token in `deps` would resolve it — and so initialize Firebase Analytics —\n // on every app that injects `AnalyticsService`, including the ones where\n // `addFirebaseAnalytics` is false (plain http, non-sneat.app host). Reading\n // it through the injector inside the branch below keeps initialization as\n // lazy as the pre-0.27.0 `getAnalytics(fbApp)` call it replaces.\n deps: [ErrorLogger, Injector],\n useFactory: (errorLogger: IErrorLogger, injector: Injector) => {\n const config = getAnalyticsConfig(environmentConfig);\n const as: IAnalyticsService[] = [];\n if (config?.addPosthog) {\n as.push(new PosthogAnalyticsService());\n }\n if (config?.googleAnalyticsMeasurementId) {\n as.push(new GtagAnalyticsService(config.googleAnalyticsMeasurementId));\n }\n if (config?.addFirebaseAnalytics) {\n const analytics: Analytics | null = injector.get(\n SNEAT_FIREBASE_ANALYTICS,\n null,\n );\n if (analytics) {\n // Constructed inside this factory's injection context, so\n // FireAnalyticsService's own inject(SNEAT_FIREBASE_ANALYTICS)\n // resolves — to this same, already-instantiated instance.\n as.push(new FireAnalyticsService());\n } else {\n errorLogger.logError(\n 'addFirebaseAnalytics==true, but Firebase Analytics is not provided',\n undefined,\n { show: false, feedback: false },\n );\n }\n }\n return new MultiAnalyticsService(as);\n },\n };\n}\n"]}
@@ -10,6 +10,18 @@ export class ErrorLoggerService {
10
10
  this.toastController = toastController;
11
11
  this.logErrorHandler = (message, options) => (e) => this.logError(e, message, options);
12
12
  this.logError = (e, message, options) => {
13
+ // logError(e, message, options) is easy to call with `e` and `message`
14
+ // swapped (both a string and unknown/undefined are type-legal in either
15
+ // slot, so the compiler can't catch it). A string `e` combined with a
16
+ // non-string `message` is the tell-tale sign of that swap — e.g. a real
17
+ // Error/HttpErrorResponse landing in `message`, where its fields (like
18
+ // HttpErrorResponse's server-provided message) are never read. Warn
19
+ // loudly so it isn't silently swallowed again.
20
+ if (typeof e === 'string' &&
21
+ message !== undefined &&
22
+ typeof message !== 'string') {
23
+ console.error('ErrorLoggerService.logError: arguments look swapped — got a string for `e` and a non-string for `message`. Expected logError(error: unknown, message?: string, options?).', { e, message });
24
+ }
13
25
  console.error(`ErrorLoggerService.logError: ${message || 'Error'}:`, e, '; Logging options:', options);
14
26
  if (e === true || e === false) {
15
27
  try {
@@ -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 console.error(\n `ErrorLoggerService.logError: ${message || 'Error'}:`,\n e,\n '; Logging options:',\n options,\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":"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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 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"]}
@@ -2,6 +2,14 @@ import { IAnalyticsCallOptions, IAnalyticsService, UserProperties } from '@sneat
2
2
  import * as i0 from "@angular/core";
3
3
  export declare class FireAnalyticsService implements IAnalyticsService {
4
4
  private readonly errorLogger;
5
+ /**
6
+ * Nullable by contract: `SNEAT_FIREBASE_ANALYTICS` resolves to `null` — it
7
+ * never throws — when the app has no real `measurementId` or when
8
+ * `getAnalytics()` is unsupported in the host environment. Every method
9
+ * below therefore no-ops on `null` instead of reporting a failed SDK call
10
+ * on each event. Before 0.27.0 this injected `@angular/fire`'s `Analytics`
11
+ * token, which threw NullInjectorError in exactly those cases.
12
+ */
5
13
  private readonly analytics;
6
14
  constructor();
7
15
  private readonly logError;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sneat/logging",
3
- "version": "0.26.6",
3
+ "version": "0.27.1",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -8,10 +8,9 @@
8
8
  "@angular/common": ">=22.0.0 <23.0.0",
9
9
  "@angular/core": ">=22.0.0 <23.0.0",
10
10
  "@angular/router": ">=22.0.0 <23.0.0",
11
- "@angular/fire": ">=20",
12
11
  "@ionic/angular": ">=9.0.0 <10.0.0",
13
12
  "@sentry/angular": "*",
14
- "@sneat/core": "^0.26.0",
13
+ "@sneat/core": "^0.27.0",
15
14
  "firebase": "*",
16
15
  "posthog-js": "*",
17
16
  "rxjs": ">=7.8.0"