@grafana/faro-web-sdk 1.7.3 → 1.8.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.
Files changed (92) hide show
  1. package/dist/bundle/faro-web-sdk.iife.js +1 -1
  2. package/dist/bundle/types/instrumentations/console/instrumentation.d.ts +1 -1
  3. package/dist/bundle/types/instrumentations/errors/instrumentation.d.ts +1 -1
  4. package/dist/bundle/types/instrumentations/instrumentationConstants.d.ts +1 -0
  5. package/dist/bundle/types/instrumentations/performance/instrumentation.d.ts +1 -1
  6. package/dist/bundle/types/instrumentations/performance/performanceConstants.d.ts +0 -1
  7. package/dist/bundle/types/instrumentations/performance/performanceUtils.d.ts +3 -0
  8. package/dist/bundle/types/instrumentations/session/instrumentation.d.ts +1 -1
  9. package/dist/bundle/types/instrumentations/session/sessionManager/sessionConstants.d.ts +3 -0
  10. package/dist/bundle/types/instrumentations/session/sessionManager/sessionManagerUtils.d.ts +7 -2
  11. package/dist/bundle/types/instrumentations/session/sessionManager/types.d.ts +3 -0
  12. package/dist/bundle/types/instrumentations/view/instrumentation.d.ts +1 -1
  13. package/dist/bundle/types/instrumentations/webVitals/instrumentation.d.ts +2 -9
  14. package/dist/bundle/types/instrumentations/webVitals/webVitalsBasic.d.ts +14 -0
  15. package/dist/bundle/types/instrumentations/webVitals/webVitalsWithAttribution.d.ts +16 -0
  16. package/dist/bundle/types/transports/console/transport.d.ts +1 -1
  17. package/dist/bundle/types/transports/fetch/transport.d.ts +2 -1
  18. package/dist/cjs/config/makeCoreConfig.js +8 -6
  19. package/dist/cjs/config/makeCoreConfig.js.map +1 -1
  20. package/dist/cjs/instrumentations/instrumentationConstants.js +5 -0
  21. package/dist/cjs/instrumentations/instrumentationConstants.js.map +1 -0
  22. package/dist/cjs/instrumentations/performance/navigation.js +7 -4
  23. package/dist/cjs/instrumentations/performance/navigation.js.map +1 -1
  24. package/dist/cjs/instrumentations/performance/performanceConstants.js +1 -2
  25. package/dist/cjs/instrumentations/performance/performanceConstants.js.map +1 -1
  26. package/dist/cjs/instrumentations/performance/performanceUtils.js +21 -1
  27. package/dist/cjs/instrumentations/performance/performanceUtils.js.map +1 -1
  28. package/dist/cjs/instrumentations/performance/performanceUtilsTestData.js +12 -1
  29. package/dist/cjs/instrumentations/performance/performanceUtilsTestData.js.map +1 -1
  30. package/dist/cjs/instrumentations/performance/resource.js +2 -1
  31. package/dist/cjs/instrumentations/performance/resource.js.map +1 -1
  32. package/dist/cjs/instrumentations/session/instrumentation.js +1 -2
  33. package/dist/cjs/instrumentations/session/instrumentation.js.map +1 -1
  34. package/dist/cjs/instrumentations/session/sessionManager/sessionConstants.js +4 -1
  35. package/dist/cjs/instrumentations/session/sessionManager/sessionConstants.js.map +1 -1
  36. package/dist/cjs/instrumentations/session/sessionManager/sessionManagerUtils.js +12 -6
  37. package/dist/cjs/instrumentations/session/sessionManager/sessionManagerUtils.js.map +1 -1
  38. package/dist/cjs/instrumentations/session/sessionManager/types.js.map +1 -1
  39. package/dist/cjs/instrumentations/webVitals/instrumentation.js +9 -21
  40. package/dist/cjs/instrumentations/webVitals/instrumentation.js.map +1 -1
  41. package/dist/cjs/instrumentations/webVitals/webVitalsBasic.js +35 -0
  42. package/dist/cjs/instrumentations/webVitals/webVitalsBasic.js.map +1 -0
  43. package/dist/cjs/instrumentations/webVitals/webVitalsWithAttribution.js +136 -0
  44. package/dist/cjs/instrumentations/webVitals/webVitalsWithAttribution.js.map +1 -0
  45. package/dist/cjs/transports/fetch/transport.js +32 -9
  46. package/dist/cjs/transports/fetch/transport.js.map +1 -1
  47. package/dist/esm/config/makeCoreConfig.js +9 -7
  48. package/dist/esm/config/makeCoreConfig.js.map +1 -1
  49. package/dist/esm/instrumentations/instrumentationConstants.js +2 -0
  50. package/dist/esm/instrumentations/instrumentationConstants.js.map +1 -0
  51. package/dist/esm/instrumentations/performance/navigation.js +7 -4
  52. package/dist/esm/instrumentations/performance/navigation.js.map +1 -1
  53. package/dist/esm/instrumentations/performance/performanceConstants.js +0 -1
  54. package/dist/esm/instrumentations/performance/performanceConstants.js.map +1 -1
  55. package/dist/esm/instrumentations/performance/performanceUtils.js +17 -0
  56. package/dist/esm/instrumentations/performance/performanceUtils.js.map +1 -1
  57. package/dist/esm/instrumentations/performance/performanceUtilsTestData.js +12 -1
  58. package/dist/esm/instrumentations/performance/performanceUtilsTestData.js.map +1 -1
  59. package/dist/esm/instrumentations/performance/resource.js +3 -2
  60. package/dist/esm/instrumentations/performance/resource.js.map +1 -1
  61. package/dist/esm/instrumentations/session/instrumentation.js +2 -3
  62. package/dist/esm/instrumentations/session/instrumentation.js.map +1 -1
  63. package/dist/esm/instrumentations/session/sessionManager/sessionConstants.js +4 -1
  64. package/dist/esm/instrumentations/session/sessionManager/sessionConstants.js.map +1 -1
  65. package/dist/esm/instrumentations/session/sessionManager/sessionManagerUtils.js +7 -3
  66. package/dist/esm/instrumentations/session/sessionManager/sessionManagerUtils.js.map +1 -1
  67. package/dist/esm/instrumentations/session/sessionManager/types.js.map +1 -1
  68. package/dist/esm/instrumentations/webVitals/instrumentation.js +10 -19
  69. package/dist/esm/instrumentations/webVitals/instrumentation.js.map +1 -1
  70. package/dist/esm/instrumentations/webVitals/webVitalsBasic.js +27 -0
  71. package/dist/esm/instrumentations/webVitals/webVitalsBasic.js.map +1 -0
  72. package/dist/esm/instrumentations/webVitals/webVitalsWithAttribution.js +124 -0
  73. package/dist/esm/instrumentations/webVitals/webVitalsWithAttribution.js.map +1 -0
  74. package/dist/esm/transports/fetch/transport.js +23 -3
  75. package/dist/esm/transports/fetch/transport.js.map +1 -1
  76. package/dist/types/instrumentations/console/instrumentation.d.ts +1 -1
  77. package/dist/types/instrumentations/errors/instrumentation.d.ts +1 -1
  78. package/dist/types/instrumentations/instrumentationConstants.d.ts +1 -0
  79. package/dist/types/instrumentations/performance/instrumentation.d.ts +1 -1
  80. package/dist/types/instrumentations/performance/performanceConstants.d.ts +0 -1
  81. package/dist/types/instrumentations/performance/performanceUtils.d.ts +3 -0
  82. package/dist/types/instrumentations/session/instrumentation.d.ts +1 -1
  83. package/dist/types/instrumentations/session/sessionManager/sessionConstants.d.ts +3 -0
  84. package/dist/types/instrumentations/session/sessionManager/sessionManagerUtils.d.ts +7 -2
  85. package/dist/types/instrumentations/session/sessionManager/types.d.ts +3 -0
  86. package/dist/types/instrumentations/view/instrumentation.d.ts +1 -1
  87. package/dist/types/instrumentations/webVitals/instrumentation.d.ts +2 -9
  88. package/dist/types/instrumentations/webVitals/webVitalsBasic.d.ts +14 -0
  89. package/dist/types/instrumentations/webVitals/webVitalsWithAttribution.d.ts +16 -0
  90. package/dist/types/transports/console/transport.d.ts +1 -1
  91. package/dist/types/transports/fetch/transport.d.ts +2 -1
  92. package/package.json +4 -4
@@ -1 +1 @@
1
- {"version":3,"file":"instrumentation.js","sourceRoot":"","sources":["../../../../src/instrumentations/session/instrumentation.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,OAAO,EACP,oBAAoB,EACpB,oBAAoB,EACpB,mBAAmB,EAGnB,OAAO,GACR,MAAM,oBAAoB,CAAC;AAI5B,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,OAAO,EAAwB,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACnE,OAAO,EAAE,yBAAyB,EAAE,MAAM,4CAA4C,CAAC;AACvF,OAAO,EAAE,uBAAuB,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AACnG,OAAO,EAAE,uBAAuB,EAAE,MAAM,yCAAyC,CAAC;AAKlF,MAAM,OAAO,sBAAuB,SAAQ,mBAAmB;IAA/D;;QACW,SAAI,GAAG,+CAA+C,CAAC;QACvD,YAAO,GAAG,OAAO,CAAC;IA8I7B,CAAC;IAxIS,qBAAqB,CAAC,IAAU;;QACtC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAE7B,IAAI,OAAO,IAAI,OAAO,CAAC,EAAE,MAAK,MAAA,IAAI,CAAC,eAAe,0CAAE,EAAE,CAAA,EAAE;YACtD,IAAI,IAAI,CAAC,eAAe,IAAI,IAAI,CAAC,eAAe,CAAC,EAAE,MAAK,MAAA,OAAO,CAAC,UAAU,0CAAG,iBAAiB,CAAC,CAAA,EAAE;gBAC/F,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,oBAAoB,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC9E,IAAI,CAAC,eAAe,GAAG,OAAO,CAAC;gBAC/B,OAAO;aACR;YAED,IAAI,CAAC,eAAe,GAAG,OAAO,CAAC;YAC/B,8EAA8E;YAC9E,gBAAgB;YAChB,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,mBAAmB,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;SAC9E;IACH,CAAC;IAEO,oBAAoB,CAC1B,cAA8B,EAC9B,cAAmD;;QAKnD,IAAI,WAAW,GAA2B,cAAc,CAAC,gBAAgB,EAAE,CAAC;QAE5E,IAAI,cAAc,CAAC,UAAU,IAAI,cAAc,CAAC,yBAAyB,IAAI,WAAW,EAAE;YACxF,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC;YACtB,MAAM,4BAA4B,GAAG,WAAW,CAAC,YAAY,GAAG,GAAG,GAAG,cAAc,CAAC,yBAAyB,CAAC;YAE/G,IAAI,4BAA4B,EAAE;gBAChC,yBAAyB,CAAC,iBAAiB,EAAE,CAAC;gBAC9C,WAAW,GAAG,IAAI,CAAC;aACpB;SACF;QAED,IAAI,aAA4B,CAAC;QACjC,IAAI,cAA+B,CAAC;QAEpC,IAAI,kBAAkB,CAAC,WAAW,CAAC,EAAE;YACnC,MAAM,SAAS,GAAG,WAAW,aAAX,WAAW,uBAAX,WAAW,CAAE,SAAS,CAAC;YAEzC,cAAc,GAAG,uBAAuB,CAAC;gBACvC,SAAS;gBACT,SAAS,EAAE,WAAY,CAAC,SAAS,IAAI,KAAK;gBAC1C,OAAO,EAAE,WAAW,aAAX,WAAW,uBAAX,WAAW,CAAE,OAAO;aAC9B,CAAC,CAAC;YAEH,cAAc,CAAC,WAAW,GAAG;gBAC3B,EAAE,EAAE,SAAS;gBACb,UAAU,gDACL,MAAA,cAAc,CAAC,OAAO,0CAAE,UAAU,GAClC,MAAA,WAAW,aAAX,WAAW,uBAAX,WAAW,CAAE,WAAW,0CAAE,UAAU;oBACvC,qGAAqG;oBACrG,SAAS,EAAE,cAAc,CAAC,SAAS,CAAC,QAAQ,EAAE,GAC/C;aACF,CAAC;YAEF,aAAa,GAAG,oBAAoB,CAAC;SACtC;aAAM;YACL,MAAM,SAAS,GAAG,MAAA,MAAA,cAAc,CAAC,OAAO,0CAAE,EAAE,mCAAI,aAAa,EAAE,CAAC,EAAE,CAAC;YAEnE,cAAc,GAAG,uBAAuB,CAAC;gBACvC,SAAS;gBACT,SAAS,EAAE,SAAS,EAAE;aACvB,CAAC,CAAC;YAEH,cAAc,CAAC,WAAW,GAAG;gBAC3B,EAAE,EAAE,SAAS;gBACb,UAAU,kBACR,SAAS,EAAE,cAAc,CAAC,SAAS,CAAC,QAAQ,EAAE,IAC3C,MAAA,cAAc,CAAC,OAAO,0CAAE,UAAU,CACtC;aACF,CAAC;YAEF,aAAa,GAAG,mBAAmB,CAAC;SACrC;QAED,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,CAAC;IAC3C,CAAC;IAEO,sBAAsB,CAAC,cAA8B;;QAC3D,MAAM,EAAE,aAAa,EAAE,GAAG,IAAI,cAAc,EAAE,CAAC;QAE/C,MAAA,IAAI,CAAC,UAAU,0CAAE,kBAAkB,CAAC,CAAC,IAAI,EAAE,EAAE;;YAC3C,aAAa,EAAE,CAAC;YAEhB,MAAM,UAAU,GAAG,MAAA,IAAI,CAAC,IAAI,CAAC,OAAO,0CAAE,UAAU,CAAC;YAEjD,IAAI,UAAU,IAAI,CAAA,UAAU,aAAV,UAAU,uBAAV,UAAU,CAAG,WAAW,CAAC,MAAK,MAAM,EAAE;gBACtD,IAAI,OAAO,GAAkB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;gBAE9D,MAAM,aAAa,GAAG,MAAA,OAAO,CAAC,IAAI,CAAC,OAAO,0CAAE,UAAU,CAAC;gBAChD,aAAa,aAAb,aAAa,4BAAb,aAAa,CAAG,WAAW,CAAC,CAAC;gBAEpC,IAAI,MAAM,CAAC,IAAI,CAAC,aAAa,aAAb,aAAa,cAAb,aAAa,GAAI,EAAE,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE;oBAC1C,MAAA,OAAO,CAAC,IAAI,CAAC,OAAO,+CAAE,UAAU,CAAC;iBACzC;gBAED,OAAO,OAAO,CAAC;aAChB;YAED,OAAO,IAAI,CAAC;QACd,CAAC,CAAC,CAAC;IACL,CAAC;IAED,UAAU;QACR,IAAI,CAAC,QAAQ,CAAC,8BAA8B,CAAC,CAAC;QAE9C,MAAM,qBAAqB,GAAG,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC;QAE1D,IAAI,qBAAqB,aAArB,qBAAqB,uBAArB,qBAAqB,CAAE,OAAO,EAAE;YAClC,MAAM,cAAc,GAAG,CAAA,qBAAqB,aAArB,qBAAqB,uBAArB,qBAAqB,CAAE,UAAU,EAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAC,uBAAuB,CAAC;YAE/G,IAAI,CAAC,sBAAsB,CAAC,cAAc,CAAC,CAAC;YAE5C,MAAM,EAAE,cAAc,EAAE,aAAa,EAAE,GAAG,IAAI,CAAC,oBAAoB,CAAC,cAAc,EAAE,qBAAqB,CAAC,CAAC;YAE3G,cAAc,CAAC,gBAAgB,CAAC,cAAc,CAAC,CAAC;YAEhD,MAAM,kBAAkB,GAAG,cAAc,CAAC,WAAW,CAAC;YAEtD,IAAI,CAAC,eAAe,GAAG,kBAAkB,CAAC;YAC1C,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,kBAAkB,CAAC,CAAC;YAExC,IAAI,aAAa,KAAK,mBAAmB,EAAE;gBACzC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,mBAAmB,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;aAC9E;YAED,IAAI,aAAa,KAAK,oBAAoB,EAAE;gBAC1C,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,oBAAoB,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;aAC/E;SACF;QAED,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAChE,CAAC;CACF","sourcesContent":["import {\n BaseInstrumentation,\n dateNow,\n EVENT_SESSION_EXTEND,\n EVENT_SESSION_RESUME,\n EVENT_SESSION_START,\n Meta,\n MetaSession,\n VERSION,\n} from '@grafana/faro-core';\nimport type { Config } from '@grafana/faro-core';\n\nimport type { TransportItem } from '../..';\nimport { createSession } from '../../metas';\n\nimport { type FaroUserSession, isSampled } from './sessionManager';\nimport { PersistentSessionsManager } from './sessionManager/PersistentSessionsManager';\nimport { createUserSessionObject, isUserSessionValid } from './sessionManager/sessionManagerUtils';\nimport { VolatileSessionsManager } from './sessionManager/VolatileSessionManager';\n\ntype LifecycleType = typeof EVENT_SESSION_RESUME | typeof EVENT_SESSION_START;\ntype SessionManager = typeof VolatileSessionsManager | typeof PersistentSessionsManager;\n\nexport class SessionInstrumentation extends BaseInstrumentation {\n readonly name = '@grafana/faro-web-sdk:instrumentation-session';\n readonly version = VERSION;\n\n // previously notified session, to ensure we don't send session start\n // event twice for the same session\n private notifiedSession: MetaSession | undefined;\n\n private sendSessionStartEvent(meta: Meta): void {\n const session = meta.session;\n\n if (session && session.id !== this.notifiedSession?.id) {\n if (this.notifiedSession && this.notifiedSession.id === session.attributes?.['previousSession']) {\n this.api.pushEvent(EVENT_SESSION_EXTEND, {}, undefined, { skipDedupe: true });\n this.notifiedSession = session;\n return;\n }\n\n this.notifiedSession = session;\n // no need to add attributes and session id, they are included as part of meta\n // automatically\n this.api.pushEvent(EVENT_SESSION_START, {}, undefined, { skipDedupe: true });\n }\n }\n\n private createInitialSession(\n SessionManager: SessionManager,\n sessionsConfig: Required<Config>['sessionTracking']\n ): {\n initialSession: FaroUserSession;\n lifecycleType: LifecycleType;\n } {\n let userSession: FaroUserSession | null = SessionManager.fetchUserSession();\n\n if (sessionsConfig.persistent && sessionsConfig.maxSessionPersistenceTime && userSession) {\n const now = dateNow();\n const shouldClearPersistentSession = userSession.lastActivity < now - sessionsConfig.maxSessionPersistenceTime;\n\n if (shouldClearPersistentSession) {\n PersistentSessionsManager.removeUserSession();\n userSession = null;\n }\n }\n\n let lifecycleType: LifecycleType;\n let initialSession: FaroUserSession;\n\n if (isUserSessionValid(userSession)) {\n const sessionId = userSession?.sessionId;\n\n initialSession = createUserSessionObject({\n sessionId,\n isSampled: userSession!.isSampled || false,\n started: userSession?.started,\n });\n\n initialSession.sessionMeta = {\n id: sessionId,\n attributes: {\n ...sessionsConfig.session?.attributes,\n ...userSession?.sessionMeta?.attributes,\n // For valid resumed sessions we do not want to recalculate the sampling decision on each init phase.\n isSampled: initialSession.isSampled.toString(),\n },\n };\n\n lifecycleType = EVENT_SESSION_RESUME;\n } else {\n const sessionId = sessionsConfig.session?.id ?? createSession().id;\n\n initialSession = createUserSessionObject({\n sessionId,\n isSampled: isSampled(),\n });\n\n initialSession.sessionMeta = {\n id: sessionId,\n attributes: {\n isSampled: initialSession.isSampled.toString(),\n ...sessionsConfig.session?.attributes,\n },\n };\n\n lifecycleType = EVENT_SESSION_START;\n }\n\n return { initialSession, lifecycleType };\n }\n\n private registerBeforeSendHook(SessionManager: SessionManager) {\n const { updateSession } = new SessionManager();\n\n this.transports?.addBeforeSendHooks((item) => {\n updateSession();\n\n const attributes = item.meta.session?.attributes;\n\n if (attributes && attributes?.['isSampled'] === 'true') {\n let newItem: TransportItem = JSON.parse(JSON.stringify(item));\n\n const newAttributes = newItem.meta.session?.attributes;\n delete newAttributes?.['isSampled'];\n\n if (Object.keys(newAttributes ?? {}).length === 0) {\n delete newItem.meta.session?.attributes;\n }\n\n return newItem;\n }\n\n return null;\n });\n }\n\n initialize() {\n this.logDebug('init session instrumentation');\n\n const sessionTrackingConfig = this.config.sessionTracking;\n\n if (sessionTrackingConfig?.enabled) {\n const SessionManager = sessionTrackingConfig?.persistent ? PersistentSessionsManager : VolatileSessionsManager;\n\n this.registerBeforeSendHook(SessionManager);\n\n const { initialSession, lifecycleType } = this.createInitialSession(SessionManager, sessionTrackingConfig);\n\n SessionManager.storeUserSession(initialSession);\n\n const initialSessionMeta = initialSession.sessionMeta;\n\n this.notifiedSession = initialSessionMeta;\n this.api.setSession(initialSessionMeta);\n\n if (lifecycleType === EVENT_SESSION_START) {\n this.api.pushEvent(EVENT_SESSION_START, {}, undefined, { skipDedupe: true });\n }\n\n if (lifecycleType === EVENT_SESSION_RESUME) {\n this.api.pushEvent(EVENT_SESSION_RESUME, {}, undefined, { skipDedupe: true });\n }\n }\n\n this.metas.addListener(this.sendSessionStartEvent.bind(this));\n }\n}\n"]}
1
+ {"version":3,"file":"instrumentation.js","sourceRoot":"","sources":["../../../../src/instrumentations/session/instrumentation.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n BaseInstrumentation,\n dateNow,\n EVENT_SESSION_EXTEND,\n EVENT_SESSION_RESUME,\n EVENT_SESSION_START,\n Meta,\n MetaSession,\n VERSION,\n} from '@grafana/faro-core';\nimport type { Config } from '@grafana/faro-core';\n\nimport type { TransportItem } from '../..';\nimport { createSession } from '../../metas';\n\nimport { type FaroUserSession, isSampled } from './sessionManager';\nimport { PersistentSessionsManager } from './sessionManager/PersistentSessionsManager';\nimport {\n createUserSessionObject,\n getSessionManagerByConfig,\n isUserSessionValid,\n} from './sessionManager/sessionManagerUtils';\nimport type { SessionManager } from './sessionManager/types';\n\ntype LifecycleType = typeof EVENT_SESSION_RESUME | typeof EVENT_SESSION_START;\n\nexport class SessionInstrumentation extends BaseInstrumentation {\n readonly name = '@grafana/faro-web-sdk:instrumentation-session';\n readonly version = VERSION;\n\n // previously notified session, to ensure we don't send session start\n // event twice for the same session\n private notifiedSession: MetaSession | undefined;\n\n private sendSessionStartEvent(meta: Meta): void {\n const session = meta.session;\n\n if (session && session.id !== this.notifiedSession?.id) {\n if (this.notifiedSession && this.notifiedSession.id === session.attributes?.['previousSession']) {\n this.api.pushEvent(EVENT_SESSION_EXTEND, {}, undefined, { skipDedupe: true });\n this.notifiedSession = session;\n return;\n }\n\n this.notifiedSession = session;\n // no need to add attributes and session id, they are included as part of meta\n // automatically\n this.api.pushEvent(EVENT_SESSION_START, {}, undefined, { skipDedupe: true });\n }\n }\n\n private createInitialSession(\n SessionManager: SessionManager,\n sessionsConfig: Required<Config>['sessionTracking']\n ): {\n initialSession: FaroUserSession;\n lifecycleType: LifecycleType;\n } {\n let userSession: FaroUserSession | null = SessionManager.fetchUserSession();\n\n if (sessionsConfig.persistent && sessionsConfig.maxSessionPersistenceTime && userSession) {\n const now = dateNow();\n const shouldClearPersistentSession = userSession.lastActivity < now - sessionsConfig.maxSessionPersistenceTime;\n\n if (shouldClearPersistentSession) {\n PersistentSessionsManager.removeUserSession();\n userSession = null;\n }\n }\n\n let lifecycleType: LifecycleType;\n let initialSession: FaroUserSession;\n\n if (isUserSessionValid(userSession)) {\n const sessionId = userSession?.sessionId;\n\n initialSession = createUserSessionObject({\n sessionId,\n isSampled: userSession!.isSampled || false,\n started: userSession?.started,\n });\n\n initialSession.sessionMeta = {\n id: sessionId,\n attributes: {\n ...sessionsConfig.session?.attributes,\n ...userSession?.sessionMeta?.attributes,\n // For valid resumed sessions we do not want to recalculate the sampling decision on each init phase.\n isSampled: initialSession.isSampled.toString(),\n },\n };\n\n lifecycleType = EVENT_SESSION_RESUME;\n } else {\n const sessionId = sessionsConfig.session?.id ?? createSession().id;\n\n initialSession = createUserSessionObject({\n sessionId,\n isSampled: isSampled(),\n });\n\n initialSession.sessionMeta = {\n id: sessionId,\n attributes: {\n isSampled: initialSession.isSampled.toString(),\n ...sessionsConfig.session?.attributes,\n },\n };\n\n lifecycleType = EVENT_SESSION_START;\n }\n\n return { initialSession, lifecycleType };\n }\n\n private registerBeforeSendHook(SessionManager: SessionManager) {\n const { updateSession } = new SessionManager();\n\n this.transports?.addBeforeSendHooks((item) => {\n updateSession();\n\n const attributes = item.meta.session?.attributes;\n\n if (attributes && attributes?.['isSampled'] === 'true') {\n let newItem: TransportItem = JSON.parse(JSON.stringify(item));\n\n const newAttributes = newItem.meta.session?.attributes;\n delete newAttributes?.['isSampled'];\n\n if (Object.keys(newAttributes ?? {}).length === 0) {\n delete newItem.meta.session?.attributes;\n }\n\n return newItem;\n }\n\n return null;\n });\n }\n\n initialize() {\n this.logDebug('init session instrumentation');\n\n const sessionTrackingConfig = this.config.sessionTracking;\n\n if (sessionTrackingConfig?.enabled) {\n const SessionManager = getSessionManagerByConfig(sessionTrackingConfig);\n\n this.registerBeforeSendHook(SessionManager);\n\n const { initialSession, lifecycleType } = this.createInitialSession(SessionManager, sessionTrackingConfig);\n\n SessionManager.storeUserSession(initialSession);\n\n const initialSessionMeta = initialSession.sessionMeta;\n\n this.notifiedSession = initialSessionMeta;\n this.api.setSession(initialSessionMeta);\n\n if (lifecycleType === EVENT_SESSION_START) {\n this.api.pushEvent(EVENT_SESSION_START, {}, undefined, { skipDedupe: true });\n }\n\n if (lifecycleType === EVENT_SESSION_RESUME) {\n this.api.pushEvent(EVENT_SESSION_RESUME, {}, undefined, { skipDedupe: true });\n }\n }\n\n this.metas.addListener(this.sendSessionStartEvent.bind(this));\n }\n}\n"]}
@@ -2,8 +2,11 @@ export const STORAGE_KEY = 'com.grafana.faro.session';
2
2
  export const SESSION_EXPIRATION_TIME = 4 * 60 * 60 * 1000; // hrs
3
3
  export const SESSION_INACTIVITY_TIME = 15 * 60 * 1000; // minutes
4
4
  export const STORAGE_UPDATE_DELAY = 1 * 1000; // seconds
5
+ /**
6
+ * @deprecated MAX_SESSION_PERSISTENCE_TIME_BUFFER is not used anymore. The constant will be removed in the future
7
+ */
5
8
  export const MAX_SESSION_PERSISTENCE_TIME_BUFFER = 1 * 60 * 1000;
6
- export const MAX_SESSION_PERSISTENCE_TIME = SESSION_INACTIVITY_TIME + MAX_SESSION_PERSISTENCE_TIME_BUFFER;
9
+ export const MAX_SESSION_PERSISTENCE_TIME = SESSION_INACTIVITY_TIME;
7
10
  export const defaultSessionTrackingConfig = {
8
11
  enabled: true,
9
12
  persistent: false,
@@ -1 +1 @@
1
- {"version":3,"file":"sessionConstants.js","sourceRoot":"","sources":["../../../../../src/instrumentations/session/sessionManager/sessionConstants.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,WAAW,GAAG,0BAA0B,CAAC;AACtD,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,MAAM;AACjE,MAAM,CAAC,MAAM,uBAAuB,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,UAAU;AACjE,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,UAAU;AAExD,MAAM,CAAC,MAAM,mCAAmC,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;AACjE,MAAM,CAAC,MAAM,4BAA4B,GAAG,uBAAuB,GAAG,mCAAmC,CAAC;AAE1G,MAAM,CAAC,MAAM,4BAA4B,GAA8B;IACrE,OAAO,EAAE,IAAI;IACb,UAAU,EAAE,KAAK;IACjB,yBAAyB,EAAE,4BAA4B;CAC/C,CAAC","sourcesContent":["import type { Config } from '@grafana/faro-core';\n\nexport const STORAGE_KEY = 'com.grafana.faro.session';\nexport const SESSION_EXPIRATION_TIME = 4 * 60 * 60 * 1000; // hrs\nexport const SESSION_INACTIVITY_TIME = 15 * 60 * 1000; // minutes\nexport const STORAGE_UPDATE_DELAY = 1 * 1000; // seconds\n\nexport const MAX_SESSION_PERSISTENCE_TIME_BUFFER = 1 * 60 * 1000;\nexport const MAX_SESSION_PERSISTENCE_TIME = SESSION_INACTIVITY_TIME + MAX_SESSION_PERSISTENCE_TIME_BUFFER;\n\nexport const defaultSessionTrackingConfig: Config['sessionTracking'] = {\n enabled: true,\n persistent: false,\n maxSessionPersistenceTime: MAX_SESSION_PERSISTENCE_TIME,\n} as const;\n"]}
1
+ {"version":3,"file":"sessionConstants.js","sourceRoot":"","sources":["../../../../../src/instrumentations/session/sessionManager/sessionConstants.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,WAAW,GAAG,0BAA0B,CAAC;AACtD,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,MAAM;AACjE,MAAM,CAAC,MAAM,uBAAuB,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,UAAU;AACjE,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,UAAU;AAExD;;GAEG;AACH,MAAM,CAAC,MAAM,mCAAmC,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;AACjE,MAAM,CAAC,MAAM,4BAA4B,GAAG,uBAAuB,CAAC;AAEpE,MAAM,CAAC,MAAM,4BAA4B,GAA8B;IACrE,OAAO,EAAE,IAAI;IACb,UAAU,EAAE,KAAK;IACjB,yBAAyB,EAAE,4BAA4B;CAC/C,CAAC","sourcesContent":["import type { Config } from '@grafana/faro-core';\n\nexport const STORAGE_KEY = 'com.grafana.faro.session';\nexport const SESSION_EXPIRATION_TIME = 4 * 60 * 60 * 1000; // hrs\nexport const SESSION_INACTIVITY_TIME = 15 * 60 * 1000; // minutes\nexport const STORAGE_UPDATE_DELAY = 1 * 1000; // seconds\n\n/**\n * @deprecated MAX_SESSION_PERSISTENCE_TIME_BUFFER is not used anymore. The constant will be removed in the future\n */\nexport const MAX_SESSION_PERSISTENCE_TIME_BUFFER = 1 * 60 * 1000;\nexport const MAX_SESSION_PERSISTENCE_TIME = SESSION_INACTIVITY_TIME;\n\nexport const defaultSessionTrackingConfig: Config['sessionTracking'] = {\n enabled: true,\n persistent: false,\n maxSessionPersistenceTime: MAX_SESSION_PERSISTENCE_TIME,\n} as const;\n"]}
@@ -1,5 +1,6 @@
1
1
  import { dateNow, faro, genShortID } from '@grafana/faro-core';
2
2
  import { isLocalStorageAvailable, isSessionStorageAvailable } from '../../../utils';
3
+ import { PersistentSessionsManager, VolatileSessionsManager } from '.';
3
4
  import { isSampled } from './sampling';
4
5
  import { SESSION_EXPIRATION_TIME, SESSION_INACTIVITY_TIME } from './sessionConstants';
5
6
  export function createUserSessionObject({ sessionId, started, lastActivity, isSampled = true, } = {}) {
@@ -28,8 +29,8 @@ export function isUserSessionValid(session) {
28
29
  const inactivityPeriodValid = now - session.lastActivity < SESSION_INACTIVITY_TIME;
29
30
  return inactivityPeriodValid;
30
31
  }
31
- export function getUserSessionUpdater({ fetchUserSession, storeUserSession }) {
32
- return function updateSession() {
32
+ export function getUserSessionUpdater({ fetchUserSession, storeUserSession, }) {
33
+ return function updateSession({ forceSessionExtend } = { forceSessionExtend: false }) {
33
34
  var _a, _b, _c;
34
35
  if (!fetchUserSession || !storeUserSession) {
35
36
  return;
@@ -40,7 +41,7 @@ export function getUserSessionUpdater({ fetchUserSession, storeUserSession }) {
40
41
  return;
41
42
  }
42
43
  const sessionFromStorage = fetchUserSession();
43
- if (isUserSessionValid(sessionFromStorage)) {
44
+ if (forceSessionExtend === false && isUserSessionValid(sessionFromStorage)) {
44
45
  storeUserSession(Object.assign(Object.assign({}, sessionFromStorage), { lastActivity: dateNow() }));
45
46
  }
46
47
  else {
@@ -59,4 +60,7 @@ export function addSessionMetadataToNextSession(newSession, previousSession) {
59
60
  } });
60
61
  return sessionWithMeta;
61
62
  }
63
+ export function getSessionManagerByConfig(sessionTrackingConfig) {
64
+ return (sessionTrackingConfig === null || sessionTrackingConfig === void 0 ? void 0 : sessionTrackingConfig.persistent) ? PersistentSessionsManager : VolatileSessionsManager;
65
+ }
62
66
  //# sourceMappingURL=sessionManagerUtils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"sessionManagerUtils.js","sourceRoot":"","sources":["../../../../../src/instrumentations/session/sessionManager/sessionManagerUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAE/D,OAAO,EAAE,uBAAuB,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AAEpF,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,uBAAuB,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAUtF,MAAM,UAAU,uBAAuB,CAAC,EACtC,SAAS,EACT,OAAO,EACP,YAAY,EACZ,SAAS,GAAG,IAAI,MACiB,EAAE;;IACnC,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC;IAEtB,MAAM,iBAAiB,GAAG,MAAA,MAAA,IAAI,CAAC,MAAM,0CAAE,eAAe,0CAAE,iBAAiB,CAAC;IAE1E,IAAI,SAAS,IAAI,IAAI,EAAE;QACrB,SAAS,GAAG,OAAO,iBAAiB,KAAK,UAAU,CAAC,CAAC,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC;KAC1F;IAED,OAAO;QACL,SAAS;QACT,YAAY,EAAE,YAAY,aAAZ,YAAY,cAAZ,YAAY,GAAI,GAAG;QACjC,OAAO,EAAE,OAAO,aAAP,OAAO,cAAP,OAAO,GAAI,GAAG;QACvB,SAAS,EAAE,SAAS;KACrB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,OAA+B;IAChE,IAAI,OAAO,IAAI,IAAI,EAAE;QACnB,OAAO,KAAK,CAAC;KACd;IAED,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC;IACtB,MAAM,aAAa,GAAG,GAAG,GAAG,OAAO,CAAC,OAAO,GAAG,uBAAuB,CAAC;IAEtE,IAAI,CAAC,aAAa,EAAE;QAClB,OAAO,KAAK,CAAC;KACd;IAED,MAAM,qBAAqB,GAAG,GAAG,GAAG,OAAO,CAAC,YAAY,GAAG,uBAAuB,CAAC;IACnF,OAAO,qBAAqB,CAAC;AAC/B,CAAC;AAOD,MAAM,UAAU,qBAAqB,CAAC,EAAE,gBAAgB,EAAE,gBAAgB,EAA+B;IACvG,OAAO,SAAS,aAAa;;QAC3B,IAAI,CAAC,gBAAgB,IAAI,CAAC,gBAAgB,EAAE;YAC1C,OAAO;SACR;QAED,MAAM,qBAAqB,GAAG,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC;QAC1D,MAAM,oBAAoB,GAAG,qBAAqB,aAArB,qBAAqB,uBAArB,qBAAqB,CAAE,UAAU,CAAC;QAE/D,IAAI,CAAC,oBAAoB,IAAI,CAAC,uBAAuB,CAAC,IAAI,CAAC,CAAC,oBAAoB,IAAI,CAAC,yBAAyB,CAAC,EAAE;YAC/G,OAAO;SACR;QAED,MAAM,kBAAkB,GAAG,gBAAgB,EAAE,CAAC;QAE9C,IAAI,kBAAkB,CAAC,kBAAkB,CAAC,EAAE;YAC1C,gBAAgB,iCAAM,kBAAmB,KAAE,YAAY,EAAE,OAAO,EAAE,IAAG,CAAC;SACvE;aAAM;YACL,IAAI,UAAU,GAAG,+BAA+B,CAC9C,uBAAuB,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE,CAAC,EACnD,kBAAkB,CACnB,CAAC;YAEF,gBAAgB,CAAC,UAAU,CAAC,CAAC;YAE7B,MAAA,IAAI,CAAC,GAAG,0CAAE,UAAU,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;YAC7C,MAAA,qBAAqB,aAArB,qBAAqB,uBAArB,qBAAqB,CAAE,eAAe,sEAAG,MAAA,kBAAkB,aAAlB,kBAAkB,uBAAlB,kBAAkB,CAAE,WAAW,mCAAI,IAAI,EAAE,UAAU,CAAC,WAAY,CAAC,CAAC;SAC5G;IACH,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,+BAA+B,CAAC,UAA2B,EAAE,eAAuC;;IAClH,MAAM,eAAe,mCAChB,UAAU,KACb,WAAW,EAAE;YACX,EAAE,EAAE,UAAU,CAAC,SAAS;YACxB,UAAU,8DACL,MAAA,MAAA,IAAI,CAAC,MAAM,CAAC,eAAe,0CAAE,OAAO,0CAAE,UAAU,GAChD,CAAC,MAAA,MAAA,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,0CAAE,UAAU,mCAAI,EAAE,CAAC,GAC5C,CAAC,eAAe,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,eAAe,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAClF,SAAS,EAAE,UAAU,CAAC,SAAS,CAAC,QAAQ,EAAE,GAC3C;SACF,GACF,CAAC;IAEF,OAAO,eAAe,CAAC;AACzB,CAAC","sourcesContent":["import { dateNow, faro, genShortID } from '@grafana/faro-core';\n\nimport { isLocalStorageAvailable, isSessionStorageAvailable } from '../../../utils';\n\nimport { isSampled } from './sampling';\nimport { SESSION_EXPIRATION_TIME, SESSION_INACTIVITY_TIME } from './sessionConstants';\nimport type { FaroUserSession } from './types';\n\ntype CreateUserSessionObjectParams = {\n sessionId?: string;\n started?: number;\n lastActivity?: number;\n isSampled?: boolean;\n};\n\nexport function createUserSessionObject({\n sessionId,\n started,\n lastActivity,\n isSampled = true,\n}: CreateUserSessionObjectParams = {}): FaroUserSession {\n const now = dateNow();\n\n const generateSessionId = faro.config?.sessionTracking?.generateSessionId;\n\n if (sessionId == null) {\n sessionId = typeof generateSessionId === 'function' ? generateSessionId() : genShortID();\n }\n\n return {\n sessionId,\n lastActivity: lastActivity ?? now,\n started: started ?? now,\n isSampled: isSampled,\n };\n}\n\nexport function isUserSessionValid(session: FaroUserSession | null): boolean {\n if (session == null) {\n return false;\n }\n\n const now = dateNow();\n const lifetimeValid = now - session.started < SESSION_EXPIRATION_TIME;\n\n if (!lifetimeValid) {\n return false;\n }\n\n const inactivityPeriodValid = now - session.lastActivity < SESSION_INACTIVITY_TIME;\n return inactivityPeriodValid;\n}\n\ntype GetUserSessionUpdaterParams = {\n storeUserSession: (session: FaroUserSession) => void;\n fetchUserSession: () => FaroUserSession | null;\n};\n\nexport function getUserSessionUpdater({ fetchUserSession, storeUserSession }: GetUserSessionUpdaterParams): () => void {\n return function updateSession(): void {\n if (!fetchUserSession || !storeUserSession) {\n return;\n }\n\n const sessionTrackingConfig = faro.config.sessionTracking;\n const isPersistentSessions = sessionTrackingConfig?.persistent;\n\n if ((isPersistentSessions && !isLocalStorageAvailable) || (!isPersistentSessions && !isSessionStorageAvailable)) {\n return;\n }\n\n const sessionFromStorage = fetchUserSession();\n\n if (isUserSessionValid(sessionFromStorage)) {\n storeUserSession({ ...sessionFromStorage!, lastActivity: dateNow() });\n } else {\n let newSession = addSessionMetadataToNextSession(\n createUserSessionObject({ isSampled: isSampled() }),\n sessionFromStorage\n );\n\n storeUserSession(newSession);\n\n faro.api?.setSession(newSession.sessionMeta);\n sessionTrackingConfig?.onSessionChange?.(sessionFromStorage?.sessionMeta ?? null, newSession.sessionMeta!);\n }\n };\n}\n\nexport function addSessionMetadataToNextSession(newSession: FaroUserSession, previousSession: FaroUserSession | null) {\n const sessionWithMeta: Required<FaroUserSession> = {\n ...newSession,\n sessionMeta: {\n id: newSession.sessionId,\n attributes: {\n ...faro.config.sessionTracking?.session?.attributes,\n ...(faro.metas.value.session?.attributes ?? {}),\n ...(previousSession != null ? { previousSession: previousSession.sessionId } : {}),\n isSampled: newSession.isSampled.toString(),\n },\n },\n };\n\n return sessionWithMeta;\n}\n"]}
1
+ {"version":3,"file":"sessionManagerUtils.js","sourceRoot":"","sources":["../../../../../src/instrumentations/session/sessionManager/sessionManagerUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAG/D,OAAO,EAAE,uBAAuB,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AAEpF,OAAO,EAAE,yBAAyB,EAAE,uBAAuB,EAAE,MAAM,GAAG,CAAC;AACvE,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,uBAAuB,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAUtF,MAAM,UAAU,uBAAuB,CAAC,EACtC,SAAS,EACT,OAAO,EACP,YAAY,EACZ,SAAS,GAAG,IAAI,MACiB,EAAE;;IACnC,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC;IAEtB,MAAM,iBAAiB,GAAG,MAAA,MAAA,IAAI,CAAC,MAAM,0CAAE,eAAe,0CAAE,iBAAiB,CAAC;IAE1E,IAAI,SAAS,IAAI,IAAI,EAAE;QACrB,SAAS,GAAG,OAAO,iBAAiB,KAAK,UAAU,CAAC,CAAC,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC;KAC1F;IAED,OAAO;QACL,SAAS;QACT,YAAY,EAAE,YAAY,aAAZ,YAAY,cAAZ,YAAY,GAAI,GAAG;QACjC,OAAO,EAAE,OAAO,aAAP,OAAO,cAAP,OAAO,GAAI,GAAG;QACvB,SAAS,EAAE,SAAS;KACrB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,OAA+B;IAChE,IAAI,OAAO,IAAI,IAAI,EAAE;QACnB,OAAO,KAAK,CAAC;KACd;IAED,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC;IACtB,MAAM,aAAa,GAAG,GAAG,GAAG,OAAO,CAAC,OAAO,GAAG,uBAAuB,CAAC;IAEtE,IAAI,CAAC,aAAa,EAAE;QAClB,OAAO,KAAK,CAAC;KACd;IAED,MAAM,qBAAqB,GAAG,GAAG,GAAG,OAAO,CAAC,YAAY,GAAG,uBAAuB,CAAC;IACnF,OAAO,qBAAqB,CAAC;AAC/B,CAAC;AASD,MAAM,UAAU,qBAAqB,CAAC,EACpC,gBAAgB,EAChB,gBAAgB,GACY;IAC5B,OAAO,SAAS,aAAa,CAAC,EAAE,kBAAkB,EAAE,GAAG,EAAE,kBAAkB,EAAE,KAAK,EAAE;;QAClF,IAAI,CAAC,gBAAgB,IAAI,CAAC,gBAAgB,EAAE;YAC1C,OAAO;SACR;QAED,MAAM,qBAAqB,GAAG,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC;QAC1D,MAAM,oBAAoB,GAAG,qBAAqB,aAArB,qBAAqB,uBAArB,qBAAqB,CAAE,UAAU,CAAC;QAE/D,IAAI,CAAC,oBAAoB,IAAI,CAAC,uBAAuB,CAAC,IAAI,CAAC,CAAC,oBAAoB,IAAI,CAAC,yBAAyB,CAAC,EAAE;YAC/G,OAAO;SACR;QAED,MAAM,kBAAkB,GAAG,gBAAgB,EAAE,CAAC;QAE9C,IAAI,kBAAkB,KAAK,KAAK,IAAI,kBAAkB,CAAC,kBAAkB,CAAC,EAAE;YAC1E,gBAAgB,iCAAM,kBAAmB,KAAE,YAAY,EAAE,OAAO,EAAE,IAAG,CAAC;SACvE;aAAM;YACL,IAAI,UAAU,GAAG,+BAA+B,CAC9C,uBAAuB,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE,CAAC,EACnD,kBAAkB,CACnB,CAAC;YAEF,gBAAgB,CAAC,UAAU,CAAC,CAAC;YAE7B,MAAA,IAAI,CAAC,GAAG,0CAAE,UAAU,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;YAC7C,MAAA,qBAAqB,aAArB,qBAAqB,uBAArB,qBAAqB,CAAE,eAAe,sEAAG,MAAA,kBAAkB,aAAlB,kBAAkB,uBAAlB,kBAAkB,CAAE,WAAW,mCAAI,IAAI,EAAE,UAAU,CAAC,WAAY,CAAC,CAAC;SAC5G;IACH,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,+BAA+B,CAAC,UAA2B,EAAE,eAAuC;;IAClH,MAAM,eAAe,mCAChB,UAAU,KACb,WAAW,EAAE;YACX,EAAE,EAAE,UAAU,CAAC,SAAS;YACxB,UAAU,8DACL,MAAA,MAAA,IAAI,CAAC,MAAM,CAAC,eAAe,0CAAE,OAAO,0CAAE,UAAU,GAChD,CAAC,MAAA,MAAA,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,0CAAE,UAAU,mCAAI,EAAE,CAAC,GAC5C,CAAC,eAAe,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,eAAe,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAClF,SAAS,EAAE,UAAU,CAAC,SAAS,CAAC,QAAQ,EAAE,GAC3C;SACF,GACF,CAAC;IAEF,OAAO,eAAe,CAAC;AACzB,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,qBAAgD;IACxF,OAAO,CAAA,qBAAqB,aAArB,qBAAqB,uBAArB,qBAAqB,CAAE,UAAU,EAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAC,uBAAuB,CAAC;AACjG,CAAC","sourcesContent":["import { dateNow, faro, genShortID } from '@grafana/faro-core';\nimport type { Config } from '@grafana/faro-core';\n\nimport { isLocalStorageAvailable, isSessionStorageAvailable } from '../../../utils';\n\nimport { PersistentSessionsManager, VolatileSessionsManager } from '.';\nimport { isSampled } from './sampling';\nimport { SESSION_EXPIRATION_TIME, SESSION_INACTIVITY_TIME } from './sessionConstants';\nimport type { FaroUserSession, SessionManager } from './types';\n\ntype CreateUserSessionObjectParams = {\n sessionId?: string;\n started?: number;\n lastActivity?: number;\n isSampled?: boolean;\n};\n\nexport function createUserSessionObject({\n sessionId,\n started,\n lastActivity,\n isSampled = true,\n}: CreateUserSessionObjectParams = {}): FaroUserSession {\n const now = dateNow();\n\n const generateSessionId = faro.config?.sessionTracking?.generateSessionId;\n\n if (sessionId == null) {\n sessionId = typeof generateSessionId === 'function' ? generateSessionId() : genShortID();\n }\n\n return {\n sessionId,\n lastActivity: lastActivity ?? now,\n started: started ?? now,\n isSampled: isSampled,\n };\n}\n\nexport function isUserSessionValid(session: FaroUserSession | null): boolean {\n if (session == null) {\n return false;\n }\n\n const now = dateNow();\n const lifetimeValid = now - session.started < SESSION_EXPIRATION_TIME;\n\n if (!lifetimeValid) {\n return false;\n }\n\n const inactivityPeriodValid = now - session.lastActivity < SESSION_INACTIVITY_TIME;\n return inactivityPeriodValid;\n}\n\ntype GetUserSessionUpdaterParams = {\n storeUserSession: (session: FaroUserSession) => void;\n fetchUserSession: () => FaroUserSession | null;\n};\n\ntype UpdateSessionParams = { forceSessionExtend: boolean };\n\nexport function getUserSessionUpdater({\n fetchUserSession,\n storeUserSession,\n}: GetUserSessionUpdaterParams): (options?: UpdateSessionParams) => void {\n return function updateSession({ forceSessionExtend } = { forceSessionExtend: false }): void {\n if (!fetchUserSession || !storeUserSession) {\n return;\n }\n\n const sessionTrackingConfig = faro.config.sessionTracking;\n const isPersistentSessions = sessionTrackingConfig?.persistent;\n\n if ((isPersistentSessions && !isLocalStorageAvailable) || (!isPersistentSessions && !isSessionStorageAvailable)) {\n return;\n }\n\n const sessionFromStorage = fetchUserSession();\n\n if (forceSessionExtend === false && isUserSessionValid(sessionFromStorage)) {\n storeUserSession({ ...sessionFromStorage!, lastActivity: dateNow() });\n } else {\n let newSession = addSessionMetadataToNextSession(\n createUserSessionObject({ isSampled: isSampled() }),\n sessionFromStorage\n );\n\n storeUserSession(newSession);\n\n faro.api?.setSession(newSession.sessionMeta);\n sessionTrackingConfig?.onSessionChange?.(sessionFromStorage?.sessionMeta ?? null, newSession.sessionMeta!);\n }\n };\n}\n\nexport function addSessionMetadataToNextSession(newSession: FaroUserSession, previousSession: FaroUserSession | null) {\n const sessionWithMeta: Required<FaroUserSession> = {\n ...newSession,\n sessionMeta: {\n id: newSession.sessionId,\n attributes: {\n ...faro.config.sessionTracking?.session?.attributes,\n ...(faro.metas.value.session?.attributes ?? {}),\n ...(previousSession != null ? { previousSession: previousSession.sessionId } : {}),\n isSampled: newSession.isSampled.toString(),\n },\n },\n };\n\n return sessionWithMeta;\n}\n\nexport function getSessionManagerByConfig(sessionTrackingConfig: Config['sessionTracking']): SessionManager {\n return sessionTrackingConfig?.persistent ? PersistentSessionsManager : VolatileSessionsManager;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../../src/instrumentations/session/sessionManager/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { MetaSession } from '@grafana/faro-core';\n\nexport interface FaroUserSession {\n sessionId: string;\n lastActivity: number;\n started: number;\n isSampled: boolean;\n sessionMeta?: MetaSession;\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../../src/instrumentations/session/sessionManager/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { MetaSession } from '@grafana/faro-core';\n\nimport type { PersistentSessionsManager } from './PersistentSessionsManager';\nimport type { VolatileSessionsManager } from './VolatileSessionManager';\n\nexport interface FaroUserSession {\n sessionId: string;\n lastActivity: number;\n started: number;\n isSampled: boolean;\n sessionMeta?: MetaSession;\n}\n\nexport type SessionManager = typeof VolatileSessionsManager | typeof PersistentSessionsManager;\n"]}
@@ -1,5 +1,6 @@
1
- import { onCLS, onFCP, onFID, onINP, onLCP, onTTFB } from 'web-vitals';
2
1
  import { BaseInstrumentation, VERSION } from '@grafana/faro-core';
2
+ import { WebVitalsBasic } from './webVitalsBasic';
3
+ import { WebVitalsWithAttribution } from './webVitalsWithAttribution';
3
4
  export class WebVitalsInstrumentation extends BaseInstrumentation {
4
5
  constructor() {
5
6
  super(...arguments);
@@ -8,24 +9,14 @@ export class WebVitalsInstrumentation extends BaseInstrumentation {
8
9
  }
9
10
  initialize() {
10
11
  this.logDebug('Initializing');
11
- Object.entries(WebVitalsInstrumentation.mapping).forEach(([indicator, executor]) => {
12
- executor((metric) => {
13
- this.api.pushMeasurement({
14
- type: 'web-vitals',
15
- values: {
16
- [indicator]: metric.value,
17
- },
18
- });
19
- });
20
- });
12
+ const webVitals = this.intializeWebVitalsInstrumentation();
13
+ webVitals.initialize();
14
+ }
15
+ intializeWebVitalsInstrumentation() {
16
+ if (this.config.trackWebVitalsAttribution) {
17
+ return new WebVitalsWithAttribution(this.api.pushMeasurement);
18
+ }
19
+ return new WebVitalsBasic(this.api.pushMeasurement);
21
20
  }
22
21
  }
23
- WebVitalsInstrumentation.mapping = {
24
- cls: onCLS,
25
- fcp: onFCP,
26
- fid: onFID,
27
- inp: onINP,
28
- lcp: onLCP,
29
- ttfb: onTTFB,
30
- };
31
22
  //# sourceMappingURL=instrumentation.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"instrumentation.js","sourceRoot":"","sources":["../../../../src/instrumentations/webVitals/instrumentation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEvE,OAAO,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAElE,MAAM,OAAO,wBAAyB,SAAQ,mBAAmB;IAAjE;;QACW,SAAI,GAAG,kDAAkD,CAAC;QAC1D,YAAO,GAAG,OAAO,CAAC;IA0B7B,CAAC;IAfC,UAAU;QACR,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;QAE9B,MAAM,CAAC,OAAO,CAAC,wBAAwB,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,EAAE,QAAQ,CAAC,EAAE,EAAE;YACjF,QAAQ,CAAC,CAAC,MAAM,EAAE,EAAE;gBAClB,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC;oBACvB,IAAI,EAAE,YAAY;oBAElB,MAAM,EAAE;wBACN,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC,KAAK;qBAC1B;iBACF,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;;AAvBM,gCAAO,GAAG;IACf,GAAG,EAAE,KAAK;IACV,GAAG,EAAE,KAAK;IACV,GAAG,EAAE,KAAK;IACV,GAAG,EAAE,KAAK;IACV,GAAG,EAAE,KAAK;IACV,IAAI,EAAE,MAAM;CACb,CAAC","sourcesContent":["import { onCLS, onFCP, onFID, onINP, onLCP, onTTFB } from 'web-vitals';\n\nimport { BaseInstrumentation, VERSION } from '@grafana/faro-core';\n\nexport class WebVitalsInstrumentation extends BaseInstrumentation {\n readonly name = '@grafana/faro-web-sdk:instrumentation-web-vitals';\n readonly version = VERSION;\n\n static mapping = {\n cls: onCLS,\n fcp: onFCP,\n fid: onFID,\n inp: onINP,\n lcp: onLCP,\n ttfb: onTTFB,\n };\n\n initialize(): void {\n this.logDebug('Initializing');\n\n Object.entries(WebVitalsInstrumentation.mapping).forEach(([indicator, executor]) => {\n executor((metric) => {\n this.api.pushMeasurement({\n type: 'web-vitals',\n\n values: {\n [indicator]: metric.value,\n },\n });\n });\n });\n }\n}\n"]}
1
+ {"version":3,"file":"instrumentation.js","sourceRoot":"","sources":["../../../../src/instrumentations/webVitals/instrumentation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAElE,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AAEtE,MAAM,OAAO,wBAAyB,SAAQ,mBAAmB;IAAjE;;QACW,SAAI,GAAG,kDAAkD,CAAC;QAC1D,YAAO,GAAG,OAAO,CAAC;IAc7B,CAAC;IAZC,UAAU;QACR,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;QAC9B,MAAM,SAAS,GAAG,IAAI,CAAC,iCAAiC,EAAE,CAAC;QAC3D,SAAS,CAAC,UAAU,EAAE,CAAC;IACzB,CAAC;IAEO,iCAAiC;QACvC,IAAI,IAAI,CAAC,MAAM,CAAC,yBAAyB,EAAE;YACzC,OAAO,IAAI,wBAAwB,CAAC,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;SAC/D;QACD,OAAO,IAAI,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;IACtD,CAAC;CACF","sourcesContent":["import { BaseInstrumentation, VERSION } from '@grafana/faro-core';\n\nimport { WebVitalsBasic } from './webVitalsBasic';\nimport { WebVitalsWithAttribution } from './webVitalsWithAttribution';\n\nexport class WebVitalsInstrumentation extends BaseInstrumentation {\n readonly name = '@grafana/faro-web-sdk:instrumentation-web-vitals';\n readonly version = VERSION;\n\n initialize(): void {\n this.logDebug('Initializing');\n const webVitals = this.intializeWebVitalsInstrumentation();\n webVitals.initialize();\n }\n\n private intializeWebVitalsInstrumentation() {\n if (this.config.trackWebVitalsAttribution) {\n return new WebVitalsWithAttribution(this.api.pushMeasurement);\n }\n return new WebVitalsBasic(this.api.pushMeasurement);\n }\n}\n"]}
@@ -0,0 +1,27 @@
1
+ import { onCLS, onFCP, onFID, onINP, onLCP, onTTFB } from 'web-vitals';
2
+ export class WebVitalsBasic {
3
+ constructor(pushMeasurement) {
4
+ this.pushMeasurement = pushMeasurement;
5
+ }
6
+ initialize() {
7
+ Object.entries(WebVitalsBasic.mapping).forEach(([indicator, executor]) => {
8
+ executor((metric) => {
9
+ this.pushMeasurement({
10
+ type: 'web-vitals',
11
+ values: {
12
+ [indicator]: metric.value,
13
+ },
14
+ });
15
+ });
16
+ });
17
+ }
18
+ }
19
+ WebVitalsBasic.mapping = {
20
+ cls: onCLS,
21
+ fcp: onFCP,
22
+ fid: onFID,
23
+ inp: onINP,
24
+ lcp: onLCP,
25
+ ttfb: onTTFB,
26
+ };
27
+ //# sourceMappingURL=webVitalsBasic.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webVitalsBasic.js","sourceRoot":"","sources":["../../../../src/instrumentations/webVitals/webVitalsBasic.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAIvE,MAAM,OAAO,cAAc;IAUzB,YAAoB,eAAmD;QAAnD,oBAAe,GAAf,eAAe,CAAoC;IAAG,CAAC;IAE3E,UAAU;QACR,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,EAAE,QAAQ,CAAC,EAAE,EAAE;YACvE,QAAQ,CAAC,CAAC,MAAM,EAAE,EAAE;gBAClB,IAAI,CAAC,eAAe,CAAC;oBACnB,IAAI,EAAE,YAAY;oBAElB,MAAM,EAAE;wBACN,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC,KAAK;qBAC1B;iBACF,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;;AAvBM,sBAAO,GAAG;IACf,GAAG,EAAE,KAAK;IACV,GAAG,EAAE,KAAK;IACV,GAAG,EAAE,KAAK;IACV,GAAG,EAAE,KAAK;IACV,GAAG,EAAE,KAAK;IACV,IAAI,EAAE,MAAM;CACb,CAAC","sourcesContent":["import { onCLS, onFCP, onFID, onINP, onLCP, onTTFB } from 'web-vitals';\n\nimport type { MeasurementsAPI } from '@grafana/faro-core';\n\nexport class WebVitalsBasic {\n static mapping = {\n cls: onCLS,\n fcp: onFCP,\n fid: onFID,\n inp: onINP,\n lcp: onLCP,\n ttfb: onTTFB,\n };\n\n constructor(private pushMeasurement: MeasurementsAPI['pushMeasurement']) {}\n\n initialize(): void {\n Object.entries(WebVitalsBasic.mapping).forEach(([indicator, executor]) => {\n executor((metric) => {\n this.pushMeasurement({\n type: 'web-vitals',\n\n values: {\n [indicator]: metric.value,\n },\n });\n });\n });\n }\n}\n"]}
@@ -0,0 +1,124 @@
1
+ import { onCLS, onFCP, onFID, onINP, onLCP, onTTFB } from 'web-vitals/attribution';
2
+ import { getItem, webStorageType } from '../../utils';
3
+ import { NAVIGATION_ID_STORAGE_KEY } from '../instrumentationConstants';
4
+ // duplicate keys saved in variables to save bundle size
5
+ // refs: https://github.com/grafana/faro-web-sdk/pull/595#discussion_r1615833968
6
+ const loadStateKey = 'load_state';
7
+ const timeToFirstByteKey = 'time_to_first_byte';
8
+ export class WebVitalsWithAttribution {
9
+ constructor(corePushMeasurement) {
10
+ this.corePushMeasurement = corePushMeasurement;
11
+ }
12
+ initialize() {
13
+ this.measureCLS();
14
+ this.measureFCP();
15
+ this.measureFID();
16
+ this.measureINP();
17
+ this.measureLCP();
18
+ this.measureTTFB();
19
+ }
20
+ measureCLS() {
21
+ onCLS((metric) => {
22
+ const { loadState, largestShiftValue, largestShiftTime, largestShiftTarget } = metric.attribution;
23
+ const values = this.buildInitialValues(metric);
24
+ this.addIfPresent(values, 'largest_shift_value', largestShiftValue);
25
+ this.addIfPresent(values, 'largest_shift_time', largestShiftTime);
26
+ const context = this.buildInitialContext(metric);
27
+ this.addIfPresent(context, loadStateKey, loadState);
28
+ this.addIfPresent(context, 'largest_shift_target', largestShiftTarget);
29
+ this.pushMeasurement(values, context);
30
+ });
31
+ }
32
+ measureFCP() {
33
+ onFCP((metric) => {
34
+ const { firstByteToFCP, timeToFirstByte, loadState } = metric.attribution;
35
+ const values = this.buildInitialValues(metric);
36
+ this.addIfPresent(values, 'first_byte_to_fcp', firstByteToFCP);
37
+ this.addIfPresent(values, timeToFirstByteKey, timeToFirstByte);
38
+ const context = this.buildInitialContext(metric);
39
+ this.addIfPresent(context, loadStateKey, loadState);
40
+ this.pushMeasurement(values, context);
41
+ });
42
+ }
43
+ measureFID() {
44
+ onFID((metric) => {
45
+ const { eventTime, eventTarget, eventType, loadState } = metric.attribution;
46
+ const values = this.buildInitialValues(metric);
47
+ this.addIfPresent(values, 'event_time', eventTime);
48
+ const context = this.buildInitialContext(metric);
49
+ this.addIfPresent(context, 'event_target', eventTarget);
50
+ this.addIfPresent(context, 'event_type', eventType);
51
+ this.addIfPresent(context, loadStateKey, loadState);
52
+ this.pushMeasurement(values, context);
53
+ });
54
+ }
55
+ measureINP() {
56
+ onINP((metric) => {
57
+ const { interactionTime, presentationDelay, inputDelay, processingDuration, nextPaintTime, loadState, interactionTarget, interactionType, } = metric.attribution;
58
+ const values = this.buildInitialValues(metric);
59
+ this.addIfPresent(values, 'interaction_time', interactionTime);
60
+ this.addIfPresent(values, 'presentation_delay', presentationDelay);
61
+ this.addIfPresent(values, 'input_delay', inputDelay);
62
+ this.addIfPresent(values, 'processing_duration', processingDuration);
63
+ this.addIfPresent(values, 'next_paint_time', nextPaintTime);
64
+ const context = this.buildInitialContext(metric);
65
+ this.addIfPresent(context, loadStateKey, loadState);
66
+ this.addIfPresent(context, 'interaction_target', interactionTarget);
67
+ this.addIfPresent(context, 'interaction_type', interactionType);
68
+ this.pushMeasurement(values, context);
69
+ });
70
+ }
71
+ measureLCP() {
72
+ onLCP((metric) => {
73
+ const { elementRenderDelay, resourceLoadDelay, resourceLoadDuration, timeToFirstByte, element } = metric.attribution;
74
+ const values = this.buildInitialValues(metric);
75
+ this.addIfPresent(values, 'element_render_delay', elementRenderDelay);
76
+ this.addIfPresent(values, 'resource_load_delay', resourceLoadDelay);
77
+ this.addIfPresent(values, 'resource_load_duration', resourceLoadDuration);
78
+ this.addIfPresent(values, timeToFirstByteKey, timeToFirstByte);
79
+ const context = this.buildInitialContext(metric);
80
+ this.addIfPresent(context, 'element', element);
81
+ this.pushMeasurement(values, context);
82
+ });
83
+ }
84
+ measureTTFB() {
85
+ onTTFB((metric) => {
86
+ const { dnsDuration, connectionDuration, requestDuration, waitingDuration, cacheDuration } = metric.attribution;
87
+ const values = this.buildInitialValues(metric);
88
+ this.addIfPresent(values, 'dns_duration', dnsDuration);
89
+ this.addIfPresent(values, 'connection_duration', connectionDuration);
90
+ this.addIfPresent(values, 'request_duration', requestDuration);
91
+ this.addIfPresent(values, 'waiting_duration', waitingDuration);
92
+ this.addIfPresent(values, 'cache_duration', cacheDuration);
93
+ const context = this.buildInitialContext(metric);
94
+ this.pushMeasurement(values, context);
95
+ });
96
+ }
97
+ buildInitialValues(metric) {
98
+ const indicator = metric.name.toLowerCase();
99
+ return {
100
+ [indicator]: metric.value,
101
+ delta: metric.delta,
102
+ };
103
+ }
104
+ buildInitialContext(metric) {
105
+ var _a;
106
+ const navigationEntryId = (_a = getItem(NAVIGATION_ID_STORAGE_KEY, webStorageType.session)) !== null && _a !== void 0 ? _a : 'unknown';
107
+ return {
108
+ id: metric.id,
109
+ rating: metric.rating,
110
+ navigation_type: metric.navigationType,
111
+ navigation_entry_id: navigationEntryId,
112
+ };
113
+ }
114
+ pushMeasurement(values, context) {
115
+ const type = 'web-vitals';
116
+ this.corePushMeasurement({ type, values }, { context });
117
+ }
118
+ addIfPresent(source, key, metric) {
119
+ if (metric) {
120
+ source[key] = metric;
121
+ }
122
+ }
123
+ }
124
+ //# sourceMappingURL=webVitalsWithAttribution.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webVitalsWithAttribution.js","sourceRoot":"","sources":["../../../../src/instrumentations/webVitals/webVitalsWithAttribution.ts"],"names":[],"mappings":"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","sourcesContent":["import { onCLS, onFCP, onFID, onINP, onLCP, onTTFB } from 'web-vitals/attribution';\nimport type { Metric } from 'web-vitals/attribution';\n\nimport type { MeasurementEvent, MeasurementsAPI, PushMeasurementOptions } from '@grafana/faro-core';\n\nimport { getItem, webStorageType } from '../../utils';\nimport { NAVIGATION_ID_STORAGE_KEY } from '../instrumentationConstants';\n\ntype Values = MeasurementEvent['values'];\ntype Context = Required<PushMeasurementOptions>['context'];\n\n// duplicate keys saved in variables to save bundle size\n// refs: https://github.com/grafana/faro-web-sdk/pull/595#discussion_r1615833968\nconst loadStateKey = 'load_state';\nconst timeToFirstByteKey = 'time_to_first_byte';\n\nexport class WebVitalsWithAttribution {\n constructor(private corePushMeasurement: MeasurementsAPI['pushMeasurement']) {}\n\n initialize(): void {\n this.measureCLS();\n this.measureFCP();\n this.measureFID();\n this.measureINP();\n this.measureLCP();\n this.measureTTFB();\n }\n\n private measureCLS(): void {\n onCLS((metric) => {\n const { loadState, largestShiftValue, largestShiftTime, largestShiftTarget } = metric.attribution;\n\n const values = this.buildInitialValues(metric);\n this.addIfPresent(values, 'largest_shift_value', largestShiftValue);\n this.addIfPresent(values, 'largest_shift_time', largestShiftTime);\n\n const context = this.buildInitialContext(metric);\n this.addIfPresent(context, loadStateKey, loadState);\n this.addIfPresent(context, 'largest_shift_target', largestShiftTarget);\n\n this.pushMeasurement(values, context);\n });\n }\n\n private measureFCP(): void {\n onFCP((metric) => {\n const { firstByteToFCP, timeToFirstByte, loadState } = metric.attribution;\n\n const values = this.buildInitialValues(metric);\n this.addIfPresent(values, 'first_byte_to_fcp', firstByteToFCP);\n this.addIfPresent(values, timeToFirstByteKey, timeToFirstByte);\n\n const context = this.buildInitialContext(metric);\n this.addIfPresent(context, loadStateKey, loadState);\n\n this.pushMeasurement(values, context);\n });\n }\n\n private measureFID(): void {\n onFID((metric) => {\n const { eventTime, eventTarget, eventType, loadState } = metric.attribution;\n\n const values = this.buildInitialValues(metric);\n this.addIfPresent(values, 'event_time', eventTime);\n\n const context = this.buildInitialContext(metric);\n this.addIfPresent(context, 'event_target', eventTarget);\n this.addIfPresent(context, 'event_type', eventType);\n this.addIfPresent(context, loadStateKey, loadState);\n\n this.pushMeasurement(values, context);\n });\n }\n\n private measureINP(): void {\n onINP((metric) => {\n const {\n interactionTime,\n presentationDelay,\n inputDelay,\n processingDuration,\n nextPaintTime,\n loadState,\n interactionTarget,\n interactionType,\n } = metric.attribution;\n\n const values = this.buildInitialValues(metric);\n this.addIfPresent(values, 'interaction_time', interactionTime);\n this.addIfPresent(values, 'presentation_delay', presentationDelay);\n this.addIfPresent(values, 'input_delay', inputDelay);\n this.addIfPresent(values, 'processing_duration', processingDuration);\n this.addIfPresent(values, 'next_paint_time', nextPaintTime);\n\n const context = this.buildInitialContext(metric);\n this.addIfPresent(context, loadStateKey, loadState);\n this.addIfPresent(context, 'interaction_target', interactionTarget);\n this.addIfPresent(context, 'interaction_type', interactionType);\n\n this.pushMeasurement(values, context);\n });\n }\n\n private measureLCP(): void {\n onLCP((metric) => {\n const { elementRenderDelay, resourceLoadDelay, resourceLoadDuration, timeToFirstByte, element } =\n metric.attribution;\n\n const values = this.buildInitialValues(metric);\n this.addIfPresent(values, 'element_render_delay', elementRenderDelay);\n this.addIfPresent(values, 'resource_load_delay', resourceLoadDelay);\n this.addIfPresent(values, 'resource_load_duration', resourceLoadDuration);\n this.addIfPresent(values, timeToFirstByteKey, timeToFirstByte);\n\n const context = this.buildInitialContext(metric);\n this.addIfPresent(context, 'element', element);\n\n this.pushMeasurement(values, context);\n });\n }\n\n private measureTTFB(): void {\n onTTFB((metric) => {\n const { dnsDuration, connectionDuration, requestDuration, waitingDuration, cacheDuration } = metric.attribution;\n\n const values = this.buildInitialValues(metric);\n this.addIfPresent(values, 'dns_duration', dnsDuration);\n this.addIfPresent(values, 'connection_duration', connectionDuration);\n this.addIfPresent(values, 'request_duration', requestDuration);\n this.addIfPresent(values, 'waiting_duration', waitingDuration);\n this.addIfPresent(values, 'cache_duration', cacheDuration);\n\n const context = this.buildInitialContext(metric);\n\n this.pushMeasurement(values, context);\n });\n }\n\n private buildInitialValues(metric: Metric): Values {\n const indicator = metric.name.toLowerCase();\n return {\n [indicator]: metric.value,\n delta: metric.delta,\n };\n }\n\n private buildInitialContext(metric: Metric): Context {\n const navigationEntryId = getItem(NAVIGATION_ID_STORAGE_KEY, webStorageType.session) ?? 'unknown';\n\n return {\n id: metric.id,\n rating: metric.rating,\n navigation_type: metric.navigationType,\n navigation_entry_id: navigationEntryId,\n };\n }\n\n private pushMeasurement(values: Values, context: Context): void {\n const type = 'web-vitals';\n this.corePushMeasurement({ type, values }, { context });\n }\n\n private addIfPresent(source: Values | Context, key: string, metric?: number | string): void {\n if (metric) {\n source[key] = metric;\n }\n }\n}\n"]}
@@ -18,12 +18,14 @@ var __rest = (this && this.__rest) || function (s, e) {
18
18
  }
19
19
  return t;
20
20
  };
21
- import { BaseTransport, createPromiseBuffer, getTransportBody, noop, VERSION } from '@grafana/faro-core';
21
+ import { BaseTransport, createPromiseBuffer, getTransportBody, noop, VERSION, } from '@grafana/faro-core';
22
+ import { getSessionManagerByConfig, getUserSessionUpdater, } from '../../instrumentations/session/sessionManager/sessionManagerUtils';
22
23
  const DEFAULT_BUFFER_SIZE = 30;
23
24
  const DEFAULT_CONCURRENCY = 5; // chrome supports 10 total, firefox 17
24
25
  const DEFAULT_RATE_LIMIT_BACKOFF_MS = 5000;
25
26
  const BEACON_BODY_SIZE_LIMIT = 60000;
26
27
  const TOO_MANY_REQUESTS = 429;
28
+ const ACCEPTED = 202;
27
29
  export class FetchTransport extends BaseTransport {
28
30
  constructor(options) {
29
31
  var _a, _b, _c, _d;
@@ -56,7 +58,13 @@ export class FetchTransport extends BaseTransport {
56
58
  sessionId = sessionMeta.id;
57
59
  }
58
60
  return fetch(url, Object.assign({ method: 'POST', headers: Object.assign(Object.assign(Object.assign({ 'Content-Type': 'application/json' }, (headers !== null && headers !== void 0 ? headers : {})), (apiKey ? { 'x-api-key': apiKey } : {})), (sessionId ? { 'x-faro-session-id': sessionId } : {})), body, keepalive: body.length <= BEACON_BODY_SIZE_LIMIT }, (restOfRequestOptions !== null && restOfRequestOptions !== void 0 ? restOfRequestOptions : {})))
59
- .then((response) => {
61
+ .then((response) => __awaiter(this, void 0, void 0, function* () {
62
+ if (response.status === ACCEPTED) {
63
+ const sessionExpired = response.headers.get('X-Faro-Session-Status') === 'invalid';
64
+ if (sessionExpired) {
65
+ this.extendFaroSession(this.config, this.logDebug);
66
+ }
67
+ }
60
68
  if (response.status === TOO_MANY_REQUESTS) {
61
69
  this.disabledUntil = this.getRetryAfterDate(response);
62
70
  this.logWarn(`Too many requests, backing off until ${this.disabledUntil}`);
@@ -64,7 +72,7 @@ export class FetchTransport extends BaseTransport {
64
72
  // read the body so the connection can be closed
65
73
  response.text().catch(noop);
66
74
  return response;
67
- })
75
+ }))
68
76
  .catch((err) => {
69
77
  this.logError('Failed sending payload to the receiver\n', JSON.parse(body), err);
70
78
  });
@@ -97,5 +105,17 @@ export class FetchTransport extends BaseTransport {
97
105
  }
98
106
  return new Date(now + this.rateLimitBackoffMs);
99
107
  }
108
+ extendFaroSession(config, logDebug) {
109
+ const SessionExpiredString = `Session expired`;
110
+ const sessionTrackingConfig = config.sessionTracking;
111
+ if (sessionTrackingConfig === null || sessionTrackingConfig === void 0 ? void 0 : sessionTrackingConfig.enabled) {
112
+ const { fetchUserSession, storeUserSession } = getSessionManagerByConfig(sessionTrackingConfig);
113
+ getUserSessionUpdater({ fetchUserSession, storeUserSession })({ forceSessionExtend: true });
114
+ logDebug(`${SessionExpiredString} created new session.`);
115
+ }
116
+ else {
117
+ logDebug(`${SessionExpiredString}.`);
118
+ }
119
+ }
100
120
  }
101
121
  //# sourceMappingURL=transport.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"transport.js","sourceRoot":"","sources":["../../../../src/transports/fetch/transport.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,IAAI,EAAiB,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAKxH,MAAM,mBAAmB,GAAG,EAAE,CAAC;AAC/B,MAAM,mBAAmB,GAAG,CAAC,CAAC,CAAC,uCAAuC;AACtE,MAAM,6BAA6B,GAAG,IAAI,CAAC;AAE3C,MAAM,sBAAsB,GAAG,KAAK,CAAC;AACrC,MAAM,iBAAiB,GAAG,GAAG,CAAC;AAE9B,MAAM,OAAO,cAAe,SAAQ,aAAa;IAU/C,YAAoB,OAA8B;;QAChD,KAAK,EAAE,CAAC;QADU,YAAO,GAAP,OAAO,CAAuB;QATzC,SAAI,GAAG,uCAAuC,CAAC;QAC/C,YAAO,GAAG,OAAO,CAAC;QAMnB,kBAAa,GAAS,IAAI,IAAI,EAAE,CAAC;QAKvC,IAAI,CAAC,kBAAkB,GAAG,MAAA,OAAO,CAAC,yBAAyB,mCAAI,6BAA6B,CAAC;QAC7F,IAAI,CAAC,MAAM,GAAG,MAAA,OAAO,CAAC,MAAM,mCAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;QAEnD,IAAI,CAAC,aAAa,GAAG,mBAAmB,CAAC;YACvC,IAAI,EAAE,MAAA,OAAO,CAAC,UAAU,mCAAI,mBAAmB;YAC/C,WAAW,EAAE,MAAA,OAAO,CAAC,WAAW,mCAAI,mBAAmB;SACxD,CAAC,CAAC;IACL,CAAC;IAEK,IAAI,CAAC,KAAsB;;YAC/B,IAAI;gBACF,IAAI,IAAI,CAAC,aAAa,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE;oBAChD,IAAI,CAAC,OAAO,CAAC,mEAAmE,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC;oBAEtG,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;iBAC1B;gBAED,MAAM,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,EAAE;oBAChC,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC;oBAErD,MAAM,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC;oBAErD,MAAM,KAAuC,cAAc,aAAd,cAAc,cAAd,cAAc,GAAI,EAAE,EAA3D,EAAE,OAAO,OAAkD,EAA7C,oBAAoB,cAAlC,WAAoC,CAAuB,CAAC;oBAElE,IAAI,SAAS,CAAC;oBACd,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC;oBAC7C,IAAI,WAAW,IAAI,IAAI,EAAE;wBACvB,SAAS,GAAG,WAAW,CAAC,EAAE,CAAC;qBAC5B;oBAED,OAAO,KAAK,CAAC,GAAG,kBACd,MAAM,EAAE,MAAM,EACd,OAAO,8CACL,cAAc,EAAE,kBAAkB,IAC/B,CAAC,OAAO,aAAP,OAAO,cAAP,OAAO,GAAI,EAAE,CAAC,GACf,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GACvC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,mBAAmB,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GAE1D,IAAI,EACJ,SAAS,EAAE,IAAI,CAAC,MAAM,IAAI,sBAAsB,IAC7C,CAAC,oBAAoB,aAApB,oBAAoB,cAApB,oBAAoB,GAAI,EAAE,CAAC,EAC/B;yBACC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE;wBACjB,IAAI,QAAQ,CAAC,MAAM,KAAK,iBAAiB,EAAE;4BACzC,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC;4BACtD,IAAI,CAAC,OAAO,CAAC,wCAAwC,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC;yBAC5E;wBACD,gDAAgD;wBAChD,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;wBAE5B,OAAO,QAAQ,CAAC;oBAClB,CAAC,CAAC;yBACD,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;wBACb,IAAI,CAAC,QAAQ,CAAC,0CAA0C,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;oBACnF,CAAC,CAAC,CAAC;gBACP,CAAC,CAAC,CAAC;aACJ;YAAC,OAAO,GAAG,EAAE;gBACZ,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;aACpB;QACH,CAAC;KAAA;IAEQ,aAAa;;QACpB,OAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAc,CAAC,MAAM,CAAC,MAAA,IAAI,CAAC,MAAM,CAAC,UAAU,mCAAI,EAAE,CAAC,CAAC;IAC/E,CAAC;IAEQ,SAAS;QAChB,OAAO,IAAI,CAAC;IACd,CAAC;IAEO,iBAAiB,CAAC,QAAkB;QAC1C,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QAC1B,MAAM,gBAAgB,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QAE7D,IAAI,gBAAgB,EAAE;YACpB,MAAM,KAAK,GAAG,MAAM,CAAC,gBAAgB,CAAC,CAAC;YAEvC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE;gBACjB,OAAO,IAAI,IAAI,CAAC,KAAK,GAAG,IAAI,GAAG,GAAG,CAAC,CAAC;aACrC;YAED,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;YAE1C,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE;gBAChB,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC;aACvB;SACF;QAED,OAAO,IAAI,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,kBAAkB,CAAC,CAAC;IACjD,CAAC;CACF","sourcesContent":["import { BaseTransport, createPromiseBuffer, getTransportBody, noop, PromiseBuffer, VERSION } from '@grafana/faro-core';\nimport type { Patterns, TransportItem } from '@grafana/faro-core';\n\nimport type { FetchTransportOptions } from './types';\n\nconst DEFAULT_BUFFER_SIZE = 30;\nconst DEFAULT_CONCURRENCY = 5; // chrome supports 10 total, firefox 17\nconst DEFAULT_RATE_LIMIT_BACKOFF_MS = 5000;\n\nconst BEACON_BODY_SIZE_LIMIT = 60000;\nconst TOO_MANY_REQUESTS = 429;\n\nexport class FetchTransport extends BaseTransport {\n readonly name = '@grafana/faro-web-sdk:transport-fetch';\n readonly version = VERSION;\n\n promiseBuffer: PromiseBuffer<Response | void>;\n\n private readonly rateLimitBackoffMs: number;\n private readonly getNow: () => number;\n private disabledUntil: Date = new Date();\n\n constructor(private options: FetchTransportOptions) {\n super();\n\n this.rateLimitBackoffMs = options.defaultRateLimitBackoffMs ?? DEFAULT_RATE_LIMIT_BACKOFF_MS;\n this.getNow = options.getNow ?? (() => Date.now());\n\n this.promiseBuffer = createPromiseBuffer({\n size: options.bufferSize ?? DEFAULT_BUFFER_SIZE,\n concurrency: options.concurrency ?? DEFAULT_CONCURRENCY,\n });\n }\n\n async send(items: TransportItem[]): Promise<void> {\n try {\n if (this.disabledUntil > new Date(this.getNow())) {\n this.logWarn(`Dropping transport item due to too many requests. Backoff until ${this.disabledUntil}`);\n\n return Promise.resolve();\n }\n\n await this.promiseBuffer.add(() => {\n const body = JSON.stringify(getTransportBody(items));\n\n const { url, requestOptions, apiKey } = this.options;\n\n const { headers, ...restOfRequestOptions } = requestOptions ?? {};\n\n let sessionId;\n const sessionMeta = this.metas.value.session;\n if (sessionMeta != null) {\n sessionId = sessionMeta.id;\n }\n\n return fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(headers ?? {}),\n ...(apiKey ? { 'x-api-key': apiKey } : {}),\n ...(sessionId ? { 'x-faro-session-id': sessionId } : {}),\n },\n body,\n keepalive: body.length <= BEACON_BODY_SIZE_LIMIT,\n ...(restOfRequestOptions ?? {}),\n })\n .then((response) => {\n if (response.status === TOO_MANY_REQUESTS) {\n this.disabledUntil = this.getRetryAfterDate(response);\n this.logWarn(`Too many requests, backing off until ${this.disabledUntil}`);\n }\n // read the body so the connection can be closed\n response.text().catch(noop);\n\n return response;\n })\n .catch((err) => {\n this.logError('Failed sending payload to the receiver\\n', JSON.parse(body), err);\n });\n });\n } catch (err) {\n this.logError(err);\n }\n }\n\n override getIgnoreUrls(): Patterns {\n return ([this.options.url] as Patterns).concat(this.config.ignoreUrls ?? []);\n }\n\n override isBatched(): boolean {\n return true;\n }\n\n private getRetryAfterDate(response: Response): Date {\n const now = this.getNow();\n const retryAfterHeader = response.headers.get('Retry-After');\n\n if (retryAfterHeader) {\n const delay = Number(retryAfterHeader);\n\n if (!isNaN(delay)) {\n return new Date(delay * 1000 + now);\n }\n\n const date = Date.parse(retryAfterHeader);\n\n if (!isNaN(date)) {\n return new Date(date);\n }\n }\n\n return new Date(now + this.rateLimitBackoffMs);\n }\n}\n"]}
1
+ {"version":3,"file":"transport.js","sourceRoot":"","sources":["../../../../src/transports/fetch/transport.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n BaseExtension,\n BaseTransport,\n createPromiseBuffer,\n getTransportBody,\n noop,\n PromiseBuffer,\n VERSION,\n} from '@grafana/faro-core';\nimport type { Config, Patterns, TransportItem } from '@grafana/faro-core';\n\nimport {\n getSessionManagerByConfig,\n getUserSessionUpdater,\n} from '../../instrumentations/session/sessionManager/sessionManagerUtils';\n\nimport type { FetchTransportOptions } from './types';\n\nconst DEFAULT_BUFFER_SIZE = 30;\nconst DEFAULT_CONCURRENCY = 5; // chrome supports 10 total, firefox 17\nconst DEFAULT_RATE_LIMIT_BACKOFF_MS = 5000;\n\nconst BEACON_BODY_SIZE_LIMIT = 60000;\nconst TOO_MANY_REQUESTS = 429;\nconst ACCEPTED = 202;\n\nexport class FetchTransport extends BaseTransport {\n readonly name = '@grafana/faro-web-sdk:transport-fetch';\n readonly version = VERSION;\n\n promiseBuffer: PromiseBuffer<Response | void>;\n\n private readonly rateLimitBackoffMs: number;\n private readonly getNow: () => number;\n private disabledUntil: Date = new Date();\n\n constructor(private options: FetchTransportOptions) {\n super();\n\n this.rateLimitBackoffMs = options.defaultRateLimitBackoffMs ?? DEFAULT_RATE_LIMIT_BACKOFF_MS;\n this.getNow = options.getNow ?? (() => Date.now());\n\n this.promiseBuffer = createPromiseBuffer({\n size: options.bufferSize ?? DEFAULT_BUFFER_SIZE,\n concurrency: options.concurrency ?? DEFAULT_CONCURRENCY,\n });\n }\n\n async send(items: TransportItem[]): Promise<void> {\n try {\n if (this.disabledUntil > new Date(this.getNow())) {\n this.logWarn(`Dropping transport item due to too many requests. Backoff until ${this.disabledUntil}`);\n\n return Promise.resolve();\n }\n\n await this.promiseBuffer.add(() => {\n const body = JSON.stringify(getTransportBody(items));\n\n const { url, requestOptions, apiKey } = this.options;\n\n const { headers, ...restOfRequestOptions } = requestOptions ?? {};\n\n let sessionId;\n const sessionMeta = this.metas.value.session;\n if (sessionMeta != null) {\n sessionId = sessionMeta.id;\n }\n\n return fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(headers ?? {}),\n ...(apiKey ? { 'x-api-key': apiKey } : {}),\n ...(sessionId ? { 'x-faro-session-id': sessionId } : {}),\n },\n body,\n keepalive: body.length <= BEACON_BODY_SIZE_LIMIT,\n ...(restOfRequestOptions ?? {}),\n })\n .then(async (response) => {\n if (response.status === ACCEPTED) {\n const sessionExpired = response.headers.get('X-Faro-Session-Status') === 'invalid';\n\n if (sessionExpired) {\n this.extendFaroSession(this.config, this.logDebug);\n }\n }\n\n if (response.status === TOO_MANY_REQUESTS) {\n this.disabledUntil = this.getRetryAfterDate(response);\n this.logWarn(`Too many requests, backing off until ${this.disabledUntil}`);\n }\n\n // read the body so the connection can be closed\n response.text().catch(noop);\n return response;\n })\n .catch((err) => {\n this.logError('Failed sending payload to the receiver\\n', JSON.parse(body), err);\n });\n });\n } catch (err) {\n this.logError(err);\n }\n }\n\n override getIgnoreUrls(): Patterns {\n return ([this.options.url] as Patterns).concat(this.config.ignoreUrls ?? []);\n }\n\n override isBatched(): boolean {\n return true;\n }\n\n private getRetryAfterDate(response: Response): Date {\n const now = this.getNow();\n const retryAfterHeader = response.headers.get('Retry-After');\n\n if (retryAfterHeader) {\n const delay = Number(retryAfterHeader);\n\n if (!isNaN(delay)) {\n return new Date(delay * 1000 + now);\n }\n\n const date = Date.parse(retryAfterHeader);\n\n if (!isNaN(date)) {\n return new Date(date);\n }\n }\n\n return new Date(now + this.rateLimitBackoffMs);\n }\n\n private extendFaroSession(config: Config, logDebug: BaseExtension['logDebug']) {\n const SessionExpiredString = `Session expired`;\n\n const sessionTrackingConfig = config.sessionTracking;\n\n if (sessionTrackingConfig?.enabled) {\n const { fetchUserSession, storeUserSession } = getSessionManagerByConfig(sessionTrackingConfig);\n\n getUserSessionUpdater({ fetchUserSession, storeUserSession })({ forceSessionExtend: true });\n\n logDebug(`${SessionExpiredString} created new session.`);\n } else {\n logDebug(`${SessionExpiredString}.`);\n }\n }\n}\n"]}
@@ -3,7 +3,7 @@ import type { ConsoleInstrumentationOptions } from './types';
3
3
  export declare class ConsoleInstrumentation extends BaseInstrumentation {
4
4
  private options;
5
5
  readonly name = "@grafana/faro-web-sdk:instrumentation-console";
6
- readonly version = "1.7.3";
6
+ readonly version = "1.8.0";
7
7
  static defaultDisabledLevels: LogLevel[];
8
8
  constructor(options?: ConsoleInstrumentationOptions);
9
9
  initialize(): void;
@@ -1,6 +1,6 @@
1
1
  import { BaseInstrumentation } from '@grafana/faro-core';
2
2
  export declare class ErrorsInstrumentation extends BaseInstrumentation {
3
3
  readonly name = "@grafana/faro-web-sdk:instrumentation-errors";
4
- readonly version = "1.7.3";
4
+ readonly version = "1.8.0";
5
5
  initialize(): void;
6
6
  }
@@ -0,0 +1 @@
1
+ export declare const NAVIGATION_ID_STORAGE_KEY = "com.grafana.faro.lastNavigationId";
@@ -1,7 +1,7 @@
1
1
  import { BaseInstrumentation } from '@grafana/faro-core';
2
2
  export declare class PerformanceInstrumentation extends BaseInstrumentation {
3
3
  readonly name = "@grafana/faro-web-sdk:instrumentation-performance";
4
- readonly version = "1.7.3";
4
+ readonly version = "1.8.0";
5
5
  initialize(): void;
6
6
  private getIgnoreUrls;
7
7
  }
@@ -1,3 +1,2 @@
1
- export declare const NAVIGATION_ID_STORAGE_KEY = "com.grafana.faro.lastNavigationId";
2
1
  export declare const NAVIGATION_ENTRY = "navigation";
3
2
  export declare const RESOURCE_ENTRY = "resource";
@@ -1,4 +1,7 @@
1
+ import { type PushEventOptions } from '@grafana/faro-core';
1
2
  import type { FaroNavigationTiming, FaroResourceTiming } from './types';
3
+ type SpanContext = PushEventOptions['spanContext'];
4
+ export declare function getSpanContextFromServerTiming(serverTimings?: PerformanceServerTiming[]): SpanContext | undefined;
2
5
  export declare function performanceObserverSupported(): boolean;
3
6
  export declare function entryUrlIsIgnored(ignoredUrls: (string | RegExp)[] | undefined, entryName: string): boolean;
4
7
  export declare function onDocumentReady(handleReady: () => void): void;
@@ -1,7 +1,7 @@
1
1
  import { BaseInstrumentation } from '@grafana/faro-core';
2
2
  export declare class SessionInstrumentation extends BaseInstrumentation {
3
3
  readonly name = "@grafana/faro-web-sdk:instrumentation-session";
4
- readonly version = "1.7.3";
4
+ readonly version = "1.8.0";
5
5
  private notifiedSession;
6
6
  private sendSessionStartEvent;
7
7
  private createInitialSession;
@@ -3,6 +3,9 @@ export declare const STORAGE_KEY = "com.grafana.faro.session";
3
3
  export declare const SESSION_EXPIRATION_TIME: number;
4
4
  export declare const SESSION_INACTIVITY_TIME: number;
5
5
  export declare const STORAGE_UPDATE_DELAY: number;
6
+ /**
7
+ * @deprecated MAX_SESSION_PERSISTENCE_TIME_BUFFER is not used anymore. The constant will be removed in the future
8
+ */
6
9
  export declare const MAX_SESSION_PERSISTENCE_TIME_BUFFER: number;
7
10
  export declare const MAX_SESSION_PERSISTENCE_TIME: number;
8
11
  export declare const defaultSessionTrackingConfig: Config['sessionTracking'];
@@ -1,4 +1,5 @@
1
- import type { FaroUserSession } from './types';
1
+ import type { Config } from '@grafana/faro-core';
2
+ import type { FaroUserSession, SessionManager } from './types';
2
3
  type CreateUserSessionObjectParams = {
3
4
  sessionId?: string;
4
5
  started?: number;
@@ -11,6 +12,10 @@ type GetUserSessionUpdaterParams = {
11
12
  storeUserSession: (session: FaroUserSession) => void;
12
13
  fetchUserSession: () => FaroUserSession | null;
13
14
  };
14
- export declare function getUserSessionUpdater({ fetchUserSession, storeUserSession }: GetUserSessionUpdaterParams): () => void;
15
+ type UpdateSessionParams = {
16
+ forceSessionExtend: boolean;
17
+ };
18
+ export declare function getUserSessionUpdater({ fetchUserSession, storeUserSession, }: GetUserSessionUpdaterParams): (options?: UpdateSessionParams) => void;
15
19
  export declare function addSessionMetadataToNextSession(newSession: FaroUserSession, previousSession: FaroUserSession | null): Required<FaroUserSession>;
20
+ export declare function getSessionManagerByConfig(sessionTrackingConfig: Config['sessionTracking']): SessionManager;
16
21
  export {};
@@ -1,4 +1,6 @@
1
1
  import type { MetaSession } from '@grafana/faro-core';
2
+ import type { PersistentSessionsManager } from './PersistentSessionsManager';
3
+ import type { VolatileSessionsManager } from './VolatileSessionManager';
2
4
  export interface FaroUserSession {
3
5
  sessionId: string;
4
6
  lastActivity: number;
@@ -6,3 +8,4 @@ export interface FaroUserSession {
6
8
  isSampled: boolean;
7
9
  sessionMeta?: MetaSession;
8
10
  }
11
+ export type SessionManager = typeof VolatileSessionsManager | typeof PersistentSessionsManager;
@@ -1,7 +1,7 @@
1
1
  import { BaseInstrumentation } from '@grafana/faro-core';
2
2
  export declare class ViewInstrumentation extends BaseInstrumentation {
3
3
  readonly name = "@grafana/faro-web-sdk:instrumentation-view";
4
- readonly version = "1.7.3";
4
+ readonly version = "1.8.0";
5
5
  private notifiedView;
6
6
  private sendViewChangedEvent;
7
7
  initialize(): void;