UNPKG

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