session.js ➔ updateSession   F
last analyzed

Complexity

Conditions 20

Size

Total Lines 60
Code Lines 38

Duplication

Lines 60
Ratio 100 %

Importance

Changes 0
Metric Value
eloc 38
dl 60
loc 60
c 0
b 0
f 0
rs 0
cc 20

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like session.js ➔ updateSession often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

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