session.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. import { timestampInSeconds, uuid4, dropUndefinedKeys } from '@sentry/utils';
  2. /**
  3. * Creates a new `Session` object by setting certain default parameters. If optional @param context
  4. * is passed, the passed properties are applied to the session object.
  5. *
  6. * @param context (optional) additional properties to be applied to the returned session object
  7. *
  8. * @returns a new `Session` object
  9. */
  10. function makeSession(context) {
  11. // Both timestamp and started are in seconds since the UNIX epoch.
  12. const startingTime = timestampInSeconds();
  13. const session = {
  14. sid: uuid4(),
  15. init: true,
  16. timestamp: startingTime,
  17. started: startingTime,
  18. duration: 0,
  19. status: 'ok',
  20. errors: 0,
  21. ignoreDuration: false,
  22. toJSON: () => sessionToJSON(session),
  23. };
  24. if (context) {
  25. updateSession(session, context);
  26. }
  27. return session;
  28. }
  29. /**
  30. * Updates a session object with the properties passed in the context.
  31. *
  32. * Note that this function mutates the passed object and returns void.
  33. * (Had to do this instead of returning a new and updated session because closing and sending a session
  34. * makes an update to the session after it was passed to the sending logic.
  35. * @see BaseClient.captureSession )
  36. *
  37. * @param session the `Session` to update
  38. * @param context the `SessionContext` holding the properties that should be updated in @param session
  39. */
  40. // eslint-disable-next-line complexity
  41. function updateSession(session, context = {}) {
  42. if (context.user) {
  43. if (!session.ipAddress && context.user.ip_address) {
  44. session.ipAddress = context.user.ip_address;
  45. }
  46. if (!session.did && !context.did) {
  47. session.did = context.user.id || context.user.email || context.user.username;
  48. }
  49. }
  50. session.timestamp = context.timestamp || timestampInSeconds();
  51. if (context.abnormal_mechanism) {
  52. session.abnormal_mechanism = context.abnormal_mechanism;
  53. }
  54. if (context.ignoreDuration) {
  55. session.ignoreDuration = context.ignoreDuration;
  56. }
  57. if (context.sid) {
  58. // Good enough uuid validation. — Kamil
  59. session.sid = context.sid.length === 32 ? context.sid : uuid4();
  60. }
  61. if (context.init !== undefined) {
  62. session.init = context.init;
  63. }
  64. if (!session.did && context.did) {
  65. session.did = `${context.did}`;
  66. }
  67. if (typeof context.started === 'number') {
  68. session.started = context.started;
  69. }
  70. if (session.ignoreDuration) {
  71. session.duration = undefined;
  72. } else if (typeof context.duration === 'number') {
  73. session.duration = context.duration;
  74. } else {
  75. const duration = session.timestamp - session.started;
  76. session.duration = duration >= 0 ? duration : 0;
  77. }
  78. if (context.release) {
  79. session.release = context.release;
  80. }
  81. if (context.environment) {
  82. session.environment = context.environment;
  83. }
  84. if (!session.ipAddress && context.ipAddress) {
  85. session.ipAddress = context.ipAddress;
  86. }
  87. if (!session.userAgent && context.userAgent) {
  88. session.userAgent = context.userAgent;
  89. }
  90. if (typeof context.errors === 'number') {
  91. session.errors = context.errors;
  92. }
  93. if (context.status) {
  94. session.status = context.status;
  95. }
  96. }
  97. /**
  98. * Closes a session by setting its status and updating the session object with it.
  99. * Internally calls `updateSession` to update the passed session object.
  100. *
  101. * Note that this function mutates the passed session (@see updateSession for explanation).
  102. *
  103. * @param session the `Session` object to be closed
  104. * @param status the `SessionStatus` with which the session was closed. If you don't pass a status,
  105. * this function will keep the previously set status, unless it was `'ok'` in which case
  106. * it is changed to `'exited'`.
  107. */
  108. function closeSession(session, status) {
  109. let context = {};
  110. if (status) {
  111. context = { status };
  112. } else if (session.status === 'ok') {
  113. context = { status: 'exited' };
  114. }
  115. updateSession(session, context);
  116. }
  117. /**
  118. * Serializes a passed session object to a JSON object with a slightly different structure.
  119. * This is necessary because the Sentry backend requires a slightly different schema of a session
  120. * than the one the JS SDKs use internally.
  121. *
  122. * @param session the session to be converted
  123. *
  124. * @returns a JSON object of the passed session
  125. */
  126. function sessionToJSON(session) {
  127. return dropUndefinedKeys({
  128. sid: `${session.sid}`,
  129. init: session.init,
  130. // Make sure that sec is converted to ms for date constructor
  131. started: new Date(session.started * 1000).toISOString(),
  132. timestamp: new Date(session.timestamp * 1000).toISOString(),
  133. status: session.status,
  134. errors: session.errors,
  135. did: typeof session.did === 'number' || typeof session.did === 'string' ? `${session.did}` : undefined,
  136. duration: session.duration,
  137. abnormal_mechanism: session.abnormal_mechanism,
  138. attrs: {
  139. release: session.release,
  140. environment: session.environment,
  141. ip_address: session.ipAddress,
  142. user_agent: session.userAgent,
  143. },
  144. });
  145. }
  146. export { closeSession, makeSession, updateSession };
  147. //# sourceMappingURL=session.js.map