@thoughtspot/visual-embed-sdk 1.25.0 → 1.26.0-token-cache.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 (215) hide show
  1. package/README.md +1 -1
  2. package/cjs/package.json +1 -1
  3. package/cjs/src/auth.d.ts +0 -12
  4. package/cjs/src/auth.d.ts.map +1 -1
  5. package/cjs/src/auth.js +15 -54
  6. package/cjs/src/auth.js.map +1 -1
  7. package/cjs/src/auth.spec.d.ts.map +1 -1
  8. package/cjs/src/auth.spec.js +44 -5
  9. package/cjs/src/auth.spec.js.map +1 -1
  10. package/cjs/src/authToken.d.ts +4 -0
  11. package/cjs/src/authToken.d.ts.map +1 -0
  12. package/cjs/src/authToken.js +60 -0
  13. package/cjs/src/authToken.js.map +1 -0
  14. package/cjs/src/config.d.ts.map +1 -1
  15. package/cjs/src/config.js +3 -0
  16. package/cjs/src/config.js.map +1 -1
  17. package/cjs/src/config.spec.js +1 -1
  18. package/cjs/src/config.spec.js.map +1 -1
  19. package/cjs/src/embed/TsEmbed.d.ts +302 -0
  20. package/cjs/src/embed/TsEmbed.d.ts.map +1 -0
  21. package/cjs/src/embed/TsEmbed.js +851 -0
  22. package/cjs/src/embed/TsEmbed.js.map +1 -0
  23. package/cjs/src/embed/base.d.ts +0 -1
  24. package/cjs/src/embed/base.d.ts.map +1 -1
  25. package/cjs/src/embed/base.js +6 -5
  26. package/cjs/src/embed/base.js.map +1 -1
  27. package/cjs/src/embed/base.spec.js +7 -5
  28. package/cjs/src/embed/base.spec.js.map +1 -1
  29. package/cjs/src/embed/search.d.ts +0 -4
  30. package/cjs/src/embed/search.d.ts.map +1 -1
  31. package/cjs/src/embed/search.js +3 -2
  32. package/cjs/src/embed/search.js.map +1 -1
  33. package/cjs/src/embed/ts-embed.d.ts.map +1 -1
  34. package/cjs/src/embed/ts-embed.js +3 -2
  35. package/cjs/src/embed/ts-embed.js.map +1 -1
  36. package/cjs/src/embed/ts-embed.spec.js +48 -37
  37. package/cjs/src/embed/ts-embed.spec.js.map +1 -1
  38. package/cjs/src/react/index.spec.js +0 -12
  39. package/cjs/src/react/index.spec.js.map +1 -1
  40. package/cjs/src/tokenizedFetch.d.ts +2 -0
  41. package/cjs/src/tokenizedFetch.d.ts.map +1 -0
  42. package/cjs/src/tokenizedFetch.js +20 -0
  43. package/cjs/src/tokenizedFetch.js.map +1 -0
  44. package/cjs/src/types.d.ts +11 -1
  45. package/cjs/src/types.d.ts.map +1 -1
  46. package/cjs/src/types.js +7 -1
  47. package/cjs/src/types.js.map +1 -1
  48. package/cjs/src/utils/answerService.d.ts +10 -0
  49. package/cjs/src/utils/answerService.d.ts.map +1 -0
  50. package/cjs/src/utils/answerService.js +61 -0
  51. package/cjs/src/utils/answerService.js.map +1 -0
  52. package/cjs/src/utils/answerService.spec.d.ts +2 -0
  53. package/cjs/src/utils/answerService.spec.d.ts.map +1 -0
  54. package/cjs/src/utils/answerService.spec.js +31 -0
  55. package/cjs/src/utils/answerService.spec.js.map +1 -0
  56. package/cjs/src/utils/authService.d.ts +12 -1
  57. package/cjs/src/utils/authService.d.ts.map +1 -1
  58. package/cjs/src/utils/authService.js +32 -16
  59. package/cjs/src/utils/authService.js.map +1 -1
  60. package/cjs/src/utils/authService.spec.js +3 -4
  61. package/cjs/src/utils/authService.spec.js.map +1 -1
  62. package/cjs/src/utils/graphql/answerService/answerService.d.ts +1 -0
  63. package/cjs/src/utils/graphql/answerService/answerService.d.ts.map +1 -1
  64. package/cjs/src/utils/graphql/answerService/answerService.js +6 -2
  65. package/cjs/src/utils/graphql/answerService/answerService.js.map +1 -1
  66. package/cjs/src/utils/graphql/answerService/answerService.spec.js +18 -2
  67. package/cjs/src/utils/graphql/answerService/answerService.spec.js.map +1 -1
  68. package/cjs/src/utils/graphql/graphql-request.spec.d.ts +2 -0
  69. package/cjs/src/utils/graphql/graphql-request.spec.d.ts.map +1 -0
  70. package/cjs/src/utils/graphql/graphql-request.spec.js +39 -0
  71. package/cjs/src/utils/graphql/graphql-request.spec.js.map +1 -0
  72. package/cjs/src/utils/logger.d.ts +28 -0
  73. package/cjs/src/utils/logger.d.ts.map +1 -0
  74. package/cjs/src/utils/logger.js +82 -0
  75. package/cjs/src/utils/logger.js.map +1 -0
  76. package/cjs/src/utils/processData.d.ts.map +1 -1
  77. package/cjs/src/utils/processData.js +2 -2
  78. package/cjs/src/utils/processData.js.map +1 -1
  79. package/cjs/src/utils/processData.spec.js +2 -2
  80. package/cjs/src/utils/processData.spec.js.map +1 -1
  81. package/dist/src/auth.d.ts +0 -12
  82. package/dist/src/auth.d.ts.map +1 -1
  83. package/dist/src/auth.spec.d.ts.map +1 -1
  84. package/dist/src/authToken.d.ts +4 -0
  85. package/dist/src/authToken.d.ts.map +1 -0
  86. package/dist/src/config.d.ts.map +1 -1
  87. package/dist/src/embed/base.d.ts +0 -1
  88. package/dist/src/embed/base.d.ts.map +1 -1
  89. package/dist/src/embed/search.d.ts +0 -4
  90. package/dist/src/embed/search.d.ts.map +1 -1
  91. package/dist/src/embed/ts-embed.d.ts.map +1 -1
  92. package/dist/src/tokenizedFetch.d.ts +2 -0
  93. package/dist/src/tokenizedFetch.d.ts.map +1 -0
  94. package/dist/src/types.d.ts +11 -1
  95. package/dist/src/types.d.ts.map +1 -1
  96. package/dist/src/utils/answerService.d.ts +10 -0
  97. package/dist/src/utils/answerService.d.ts.map +1 -0
  98. package/dist/src/utils/answerService.spec.d.ts +2 -0
  99. package/dist/src/utils/answerService.spec.d.ts.map +1 -0
  100. package/dist/src/utils/authService.d.ts +12 -1
  101. package/dist/src/utils/authService.d.ts.map +1 -1
  102. package/dist/src/utils/graphql/answerService/answerService.d.ts +1 -0
  103. package/dist/src/utils/graphql/answerService/answerService.d.ts.map +1 -1
  104. package/dist/src/utils/graphql/graphql-request.spec.d.ts +2 -0
  105. package/dist/src/utils/graphql/graphql-request.spec.d.ts.map +1 -0
  106. package/dist/src/utils/logger.d.ts +28 -0
  107. package/dist/src/utils/logger.d.ts.map +1 -0
  108. package/dist/src/utils/processData.d.ts.map +1 -1
  109. package/dist/tsembed-react.es.js +2149 -2094
  110. package/dist/tsembed-react.js +2152 -2097
  111. package/dist/tsembed.es.js +6483 -6425
  112. package/dist/tsembed.js +6483 -6425
  113. package/dist/visual-embed-sdk-react-full.d.ts +12 -18
  114. package/dist/visual-embed-sdk-react.d.ts +12 -18
  115. package/dist/visual-embed-sdk.d.ts +12 -18
  116. package/lib/package.json +1 -1
  117. package/lib/src/auth.d.ts +0 -12
  118. package/lib/src/auth.d.ts.map +1 -1
  119. package/lib/src/auth.js +10 -48
  120. package/lib/src/auth.js.map +1 -1
  121. package/lib/src/auth.spec.d.ts.map +1 -1
  122. package/lib/src/auth.spec.js +44 -5
  123. package/lib/src/auth.spec.js.map +1 -1
  124. package/lib/src/authToken.d.ts +4 -0
  125. package/lib/src/authToken.d.ts.map +1 -0
  126. package/lib/src/authToken.js +55 -0
  127. package/lib/src/authToken.js.map +1 -0
  128. package/lib/src/config.d.ts.map +1 -1
  129. package/lib/src/config.js +3 -0
  130. package/lib/src/config.js.map +1 -1
  131. package/lib/src/config.spec.js +1 -1
  132. package/lib/src/config.spec.js.map +1 -1
  133. package/lib/src/embed/TsEmbed.d.ts +302 -0
  134. package/lib/src/embed/TsEmbed.d.ts.map +1 -0
  135. package/lib/src/embed/TsEmbed.js +847 -0
  136. package/lib/src/embed/TsEmbed.js.map +1 -0
  137. package/lib/src/embed/base.d.ts +0 -1
  138. package/lib/src/embed/base.d.ts.map +1 -1
  139. package/lib/src/embed/base.js +3 -2
  140. package/lib/src/embed/base.js.map +1 -1
  141. package/lib/src/embed/base.spec.js +7 -5
  142. package/lib/src/embed/base.spec.js.map +1 -1
  143. package/lib/src/embed/search.d.ts +0 -4
  144. package/lib/src/embed/search.d.ts.map +1 -1
  145. package/lib/src/embed/search.js +3 -2
  146. package/lib/src/embed/search.js.map +1 -1
  147. package/lib/src/embed/ts-embed.d.ts.map +1 -1
  148. package/lib/src/embed/ts-embed.js +2 -1
  149. package/lib/src/embed/ts-embed.js.map +1 -1
  150. package/lib/src/embed/ts-embed.spec.js +48 -37
  151. package/lib/src/embed/ts-embed.spec.js.map +1 -1
  152. package/lib/src/react/index.spec.js +0 -12
  153. package/lib/src/react/index.spec.js.map +1 -1
  154. package/lib/src/tokenizedFetch.d.ts +2 -0
  155. package/lib/src/tokenizedFetch.d.ts.map +1 -0
  156. package/lib/src/tokenizedFetch.js +16 -0
  157. package/lib/src/tokenizedFetch.js.map +1 -0
  158. package/lib/src/types.d.ts +11 -1
  159. package/lib/src/types.d.ts.map +1 -1
  160. package/lib/src/types.js +7 -1
  161. package/lib/src/types.js.map +1 -1
  162. package/lib/src/utils/answerService.d.ts +10 -0
  163. package/lib/src/utils/answerService.d.ts.map +1 -0
  164. package/lib/src/utils/answerService.js +57 -0
  165. package/lib/src/utils/answerService.js.map +1 -0
  166. package/lib/src/utils/answerService.spec.d.ts +2 -0
  167. package/lib/src/utils/answerService.spec.d.ts.map +1 -0
  168. package/lib/src/utils/answerService.spec.js +29 -0
  169. package/lib/src/utils/answerService.spec.js.map +1 -0
  170. package/lib/src/utils/authService.d.ts +12 -1
  171. package/lib/src/utils/authService.d.ts.map +1 -1
  172. package/lib/src/utils/authService.js +26 -10
  173. package/lib/src/utils/authService.js.map +1 -1
  174. package/lib/src/utils/authService.spec.js +1 -2
  175. package/lib/src/utils/authService.spec.js.map +1 -1
  176. package/lib/src/utils/graphql/answerService/answerService.d.ts +1 -0
  177. package/lib/src/utils/graphql/answerService/answerService.d.ts.map +1 -1
  178. package/lib/src/utils/graphql/answerService/answerService.js +6 -2
  179. package/lib/src/utils/graphql/answerService/answerService.js.map +1 -1
  180. package/lib/src/utils/graphql/answerService/answerService.spec.js +17 -2
  181. package/lib/src/utils/graphql/answerService/answerService.spec.js.map +1 -1
  182. package/lib/src/utils/graphql/graphql-request.spec.d.ts +2 -0
  183. package/lib/src/utils/graphql/graphql-request.spec.d.ts.map +1 -0
  184. package/lib/src/utils/graphql/graphql-request.spec.js +36 -0
  185. package/lib/src/utils/graphql/graphql-request.spec.js.map +1 -0
  186. package/lib/src/utils/logger.d.ts +28 -0
  187. package/lib/src/utils/logger.d.ts.map +1 -0
  188. package/lib/src/utils/logger.js +75 -0
  189. package/lib/src/utils/logger.js.map +1 -0
  190. package/lib/src/utils/processData.d.ts.map +1 -1
  191. package/lib/src/utils/processData.js +2 -2
  192. package/lib/src/utils/processData.js.map +1 -1
  193. package/lib/src/utils/processData.spec.js +2 -2
  194. package/lib/src/utils/processData.spec.js.map +1 -1
  195. package/lib/src/visual-embed-sdk.d.ts +12 -18
  196. package/package.json +1 -1
  197. package/src/auth.spec.ts +47 -7
  198. package/src/auth.ts +9 -50
  199. package/src/authToken.ts +60 -0
  200. package/src/config.spec.ts +1 -1
  201. package/src/config.ts +3 -0
  202. package/src/embed/base.spec.ts +7 -6
  203. package/src/embed/base.ts +2 -3
  204. package/src/embed/search.ts +2 -6
  205. package/src/embed/ts-embed.spec.ts +54 -40
  206. package/src/embed/ts-embed.ts +2 -1
  207. package/src/react/index.spec.tsx +0 -29
  208. package/src/tokenizedFetch.ts +16 -0
  209. package/src/types.ts +12 -2
  210. package/src/utils/authService.spec.ts +1 -2
  211. package/src/utils/authService.ts +29 -10
  212. package/src/utils/graphql/answerService/answerService.spec.ts +27 -3
  213. package/src/utils/graphql/answerService/answerService.ts +7 -2
  214. package/src/utils/processData.spec.ts +2 -2
  215. package/src/utils/processData.ts +2 -1
@@ -1146,11 +1146,17 @@ var EmbedEvent;
1146
1146
  */
1147
1147
  EmbedEvent["SageWorksheetUpdated"] = "sageWorksheetUpdated";
1148
1148
  /**
1149
- * Emitten when a user updates a connection in Data tab
1149
+ * Emitted when a user updates a connection in Data tab
1150
1150
  *
1151
1151
  * @version SDK : 1.27.0 | Thoughtspot: 9.8.0.cl
1152
1152
  */
1153
1153
  EmbedEvent["UpdateConnection"] = "updateConnection";
1154
+ /**
1155
+ * Emitted when a user updates a connection in Data tab
1156
+ *
1157
+ * @version SDK : 1.27.0 | Thoughtspot: 9.8.0.cl
1158
+ */
1159
+ EmbedEvent["CreateConnection"] = "createConnection";
1154
1160
  /**
1155
1161
  * Emitted when name, status (private or public) or filter values of a
1156
1162
  * PersonalisedView is updated.
@@ -5106,384 +5112,543 @@ function isEqual(value, other) {
5106
5112
 
5107
5113
  var isEqual_1 = isEqual;
5108
5114
 
5115
+ const EndPoints = {
5116
+ AUTH_VERIFICATION: '/callosum/v1/session/info',
5117
+ SAML_LOGIN_TEMPLATE: (targetUrl) => `/callosum/v1/saml/login?targetURLPath=${targetUrl}`,
5118
+ OIDC_LOGIN_TEMPLATE: (targetUrl) => `/callosum/v1/oidc/login?targetURLPath=${targetUrl}`,
5119
+ TOKEN_LOGIN: '/callosum/v1/session/login/token',
5120
+ BASIC_LOGIN: '/callosum/v1/session/login',
5121
+ LOGOUT: '/callosum/v1/session/logout',
5122
+ EXECUTE_TML: '/api/rest/2.0/metadata/tml/import',
5123
+ EXPORT_TML: '/api/rest/2.0/metadata/tml/export',
5124
+ IS_ACTIVE: '/callosum/v1/session/isactive',
5125
+ };
5109
5126
  /**
5110
5127
  *
5111
- * @param root0
5112
- * @param root0.query
5113
- * @param root0.variables
5114
- * @param root0.thoughtSpotHost
5115
- * @param root0.isCompositeQuery
5128
+ * @param url
5129
+ * @param options
5116
5130
  */
5117
- async function graphqlQuery({ query, variables, thoughtSpotHost, isCompositeQuery = false, }) {
5118
- const operationName = getOperationNameFromQuery(query);
5131
+ function failureLoggedFetch(url, options = {}) {
5132
+ return fetch(url, options).then(async (r) => {
5133
+ var _a;
5134
+ if (!r.ok && r.type !== 'opaqueredirect' && r.type !== 'opaque') {
5135
+ console.error('Failure', await ((_a = r.text) === null || _a === void 0 ? void 0 : _a.call(r)));
5136
+ }
5137
+ return r;
5138
+ });
5139
+ }
5140
+ /**
5141
+ *
5142
+ * @param authVerificationUrl
5143
+ */
5144
+ function fetchSessionInfoService(authVerificationUrl) {
5145
+ return failureLoggedFetch(authVerificationUrl, {
5146
+ credentials: 'include',
5147
+ });
5148
+ }
5149
+ /**
5150
+ * Service to validate a auth token against a ThoughtSpot host.
5151
+ *
5152
+ * @param thoughtSpotHost : ThoughtSpot host to verify the token against.
5153
+ * @param authToken : Auth token to verify.
5154
+ */
5155
+ async function verifyTokenService(thoughtSpotHost, authToken) {
5156
+ const authVerificationUrl = `${thoughtSpotHost}${EndPoints.IS_ACTIVE}`;
5119
5157
  try {
5120
- const response = await fetch(`${thoughtSpotHost}/prism/?op=${operationName}`, {
5121
- method: 'POST',
5158
+ const res = await fetch(authVerificationUrl, {
5122
5159
  headers: {
5123
- 'content-type': 'application/json;charset=UTF-8',
5160
+ Authorization: `Bearer ${authToken}`,
5124
5161
  'x-requested-by': 'ThoughtSpot',
5125
- accept: '*/*',
5126
- 'accept-language': 'en-us',
5127
5162
  },
5128
- body: JSON.stringify({
5129
- operationName,
5130
- query,
5131
- variables,
5132
- }),
5133
- credentials: 'include',
5163
+ credentials: 'omit',
5134
5164
  });
5135
- const result = await response.json();
5136
- const dataValues = Object.values(result.data);
5137
- return (isCompositeQuery) ? result.data : dataValues[0];
5165
+ return res.ok;
5138
5166
  }
5139
- catch (error) {
5140
- return error;
5167
+ catch (e) {
5168
+ console.error(`Token Verification Service failed : ${e.message}`);
5141
5169
  }
5142
- }
5143
-
5144
- const getSourceDetailQuery = `
5145
- query GetSourceDetail($ids: [GUID!]!) {
5146
- getSourceDetailById(ids: $ids, type: LOGICAL_TABLE) {
5147
- id
5148
- name
5149
- description
5150
- authorName
5151
- authorDisplayName
5152
- isExternal
5153
- type
5154
- created
5155
- modified
5156
- columns {
5157
- id
5158
- name
5159
- author
5160
- authorDisplayName
5161
- description
5162
- dataType
5163
- type
5164
- modified
5165
- ownerName
5166
- owner
5167
- dataRecency
5168
- sources {
5169
- tableId
5170
- tableName
5171
- columnId
5172
- columnName
5173
- __typename
5174
- }
5175
- synonyms
5176
- cohortAnswerId
5177
- __typename
5178
- }
5179
- relationships
5180
- destinationRelationships
5181
- dataSourceId
5182
- __typename
5183
- }
5184
- }
5185
- `;
5186
- const sourceDetailCache = new Map();
5170
+ return false;
5171
+ }
5172
+ /**
5173
+ *
5174
+ * @param authEndpoint
5175
+ */
5176
+ async function fetchAuthTokenService(authEndpoint) {
5177
+ return fetch(authEndpoint);
5178
+ }
5187
5179
  /**
5188
5180
  *
5189
5181
  * @param thoughtSpotHost
5190
- * @param sourceId
5182
+ * @param username
5183
+ * @param authToken
5191
5184
  */
5192
- async function getSourceDetail(thoughtSpotHost, sourceId) {
5193
- if (sourceDetailCache.get(sourceId)) {
5194
- return sourceDetailCache.get(sourceId);
5195
- }
5196
- const details = await graphqlQuery({
5197
- query: getSourceDetailQuery,
5198
- variables: {
5199
- ids: [sourceId],
5185
+ async function fetchAuthService(thoughtSpotHost, username, authToken) {
5186
+ return failureLoggedFetch(`${thoughtSpotHost}${EndPoints.TOKEN_LOGIN}?username=${username}&auth_token=${authToken}`, {
5187
+ credentials: 'include',
5188
+ // We do not want to follow the redirect, as it starts giving a CORS
5189
+ // error
5190
+ redirect: 'manual',
5191
+ });
5192
+ }
5193
+ /**
5194
+ *
5195
+ * @param thoughtSpotHost
5196
+ * @param username
5197
+ * @param authToken
5198
+ */
5199
+ async function fetchAuthPostService(thoughtSpotHost, username, authToken) {
5200
+ return failureLoggedFetch(`${thoughtSpotHost}${EndPoints.TOKEN_LOGIN}`, {
5201
+ method: 'POST',
5202
+ headers: {
5203
+ 'content-type': 'application/x-www-form-urlencoded',
5204
+ 'x-requested-by': 'ThoughtSpot',
5200
5205
  },
5201
- thoughtSpotHost,
5206
+ body: `username=${encodeURIComponent(username)}&auth_token=${encodeURIComponent(authToken)}`,
5207
+ credentials: 'include',
5208
+ // We do not want to follow the redirect, as it starts giving a CORS
5209
+ // error
5210
+ redirect: 'manual',
5211
+ });
5212
+ }
5213
+ /**
5214
+ *
5215
+ * @param thoughtSpotHost
5216
+ * @param username
5217
+ * @param password
5218
+ */
5219
+ async function fetchBasicAuthService(thoughtSpotHost, username, password) {
5220
+ return failureLoggedFetch(`${thoughtSpotHost}${EndPoints.BASIC_LOGIN}`, {
5221
+ method: 'POST',
5222
+ headers: {
5223
+ 'content-type': 'application/x-www-form-urlencoded',
5224
+ 'x-requested-by': 'ThoughtSpot',
5225
+ },
5226
+ body: `username=${encodeURIComponent(username)}&password=${encodeURIComponent(password)}`,
5227
+ credentials: 'include',
5202
5228
  });
5203
- const souceDetails = details[0];
5204
- if (souceDetails) {
5205
- sourceDetailCache.set(sourceId, souceDetails);
5206
- }
5207
- return souceDetails;
5208
5229
  }
5209
5230
 
5210
- const bachSessionId = `
5211
- id {
5212
- sessionId
5213
- genNo
5214
- acSession {
5215
- sessionId
5216
- genNo
5217
- }
5231
+ const DUPLICATE_TOKEN_ERR = 'Duplicate token, please issue a new token every time getAuthToken callback is called.'
5232
+ + 'See https://developers.thoughtspot.com/docs/?pageid=embed-auth#trusted-auth-embed for more details.';
5233
+ const INVALID_TOKEN_ERR = 'Invalid token received form token callback or authToken endpoint.';
5234
+ let cachedAuthToken = null;
5235
+ // This method can be used to get the authToken using the embedConfig
5236
+ const getAuthenticationToken = async (embedConfig) => {
5237
+ if (cachedAuthToken) {
5238
+ try {
5239
+ const isCachedTokenStillValid = await validateAuthToken(embedConfig, cachedAuthToken);
5240
+ if (isCachedTokenStillValid)
5241
+ return cachedAuthToken;
5242
+ }
5243
+ catch {
5244
+ // Continue to get a new token if validation fails
5245
+ }
5246
+ }
5247
+ const { authEndpoint, getAuthToken } = embedConfig;
5248
+ let authToken = null;
5249
+ if (getAuthToken) {
5250
+ authToken = await getAuthToken();
5251
+ }
5252
+ else {
5253
+ const response = await fetchAuthTokenService(authEndpoint);
5254
+ authToken = await response.text();
5255
+ }
5256
+ // this will throw error if the token is not valid
5257
+ await validateAuthToken(embedConfig, authToken);
5258
+ cachedAuthToken = authToken;
5259
+ return authToken;
5260
+ };
5261
+ const validateAuthToken = async (embedConfig, authToken) => {
5262
+ try {
5263
+ const isTokenValid = await verifyTokenService(embedConfig.thoughtSpotHost, authToken);
5264
+ if (isTokenValid)
5265
+ return true;
5266
+ }
5267
+ catch {
5268
+ return false;
5269
+ }
5270
+ if (cachedAuthToken && cachedAuthToken === authToken) {
5271
+ if (!embedConfig.suppressErrorAlerts) {
5272
+ // eslint-disable-next-line no-alert
5273
+ alert(DUPLICATE_TOKEN_ERR);
5274
+ }
5275
+ throw new Error(DUPLICATE_TOKEN_ERR);
5276
+ }
5277
+ else {
5278
+ throw new Error(INVALID_TOKEN_ERR);
5279
+ }
5280
+ };
5281
+
5282
+ var eventemitter3 = createCommonjsModule(function (module) {
5283
+
5284
+ var has = Object.prototype.hasOwnProperty
5285
+ , prefix = '~';
5286
+
5287
+ /**
5288
+ * Constructor to create a storage for our `EE` objects.
5289
+ * An `Events` instance is a plain object whose properties are event names.
5290
+ *
5291
+ * @constructor
5292
+ * @private
5293
+ */
5294
+ function Events() {}
5295
+
5296
+ //
5297
+ // We try to not inherit from `Object.prototype`. In some engines creating an
5298
+ // instance in this way is faster than calling `Object.create(null)` directly.
5299
+ // If `Object.create(null)` is not supported we prefix the event names with a
5300
+ // character to make sure that the built-in object properties are not
5301
+ // overridden or used as an attack vector.
5302
+ //
5303
+ if (Object.create) {
5304
+ Events.prototype = Object.create(null);
5305
+
5306
+ //
5307
+ // This hack is needed because the `__proto__` property is still inherited in
5308
+ // some old browsers like Android 4, iPhone 5.1, Opera 11 and Safari 5.
5309
+ //
5310
+ if (!new Events().__proto__) prefix = false;
5218
5311
  }
5219
- `;
5220
- const getUnaggregatedAnswerSession = `
5221
- mutation GetUnAggregatedAnswerSession($session: BachSessionIdInput!, $columns: [UserPointSelectionInput!]!) {
5222
- Answer__getUnaggregatedAnswer(session: $session, columns: $columns) {
5223
- ${bachSessionId}
5224
- answer {
5225
- visualizations {
5226
- ... on TableViz {
5227
- columns {
5228
- column {
5229
- id
5230
- name
5231
- referencedColumns {
5232
- guid
5233
- displayName
5234
- }
5235
- }
5236
- }
5237
- }
5238
- }
5239
- }
5240
- }
5241
- }
5242
- `;
5243
- const removeColumns = `
5244
- mutation RemoveColumns($session: BachSessionIdInput!, $logicalColumnIds: [GUID!], $columnIds: [GUID!]) {
5245
- Answer__removeColumns(
5246
- session: $session
5247
- logicalColumnIds: $logicalColumnIds
5248
- columnIds: $columnIds
5249
- ) {
5250
- ${bachSessionId}
5251
- }
5312
+
5313
+ /**
5314
+ * Representation of a single event listener.
5315
+ *
5316
+ * @param {Function} fn The listener function.
5317
+ * @param {*} context The context to invoke the listener with.
5318
+ * @param {Boolean} [once=false] Specify if the listener is a one-time listener.
5319
+ * @constructor
5320
+ * @private
5321
+ */
5322
+ function EE(fn, context, once) {
5323
+ this.fn = fn;
5324
+ this.context = context;
5325
+ this.once = once || false;
5252
5326
  }
5253
- `;
5254
- const addColumns = `
5255
- mutation AddColumns($session: BachSessionIdInput!, $columns: [AnswerColumnInfo!]!) {
5256
- Answer__addColumn(session: $session, columns: $columns) {
5257
- ${bachSessionId}
5258
- }
5327
+
5328
+ /**
5329
+ * Add a listener for a given event.
5330
+ *
5331
+ * @param {EventEmitter} emitter Reference to the `EventEmitter` instance.
5332
+ * @param {(String|Symbol)} event The event name.
5333
+ * @param {Function} fn The listener function.
5334
+ * @param {*} context The context to invoke the listener with.
5335
+ * @param {Boolean} once Specify if the listener is a one-time listener.
5336
+ * @returns {EventEmitter}
5337
+ * @private
5338
+ */
5339
+ function addListener(emitter, event, fn, context, once) {
5340
+ if (typeof fn !== 'function') {
5341
+ throw new TypeError('The listener must be a function');
5342
+ }
5343
+
5344
+ var listener = new EE(fn, context || emitter, once)
5345
+ , evt = prefix ? prefix + event : event;
5346
+
5347
+ if (!emitter._events[evt]) emitter._events[evt] = listener, emitter._eventsCount++;
5348
+ else if (!emitter._events[evt].fn) emitter._events[evt].push(listener);
5349
+ else emitter._events[evt] = [emitter._events[evt], listener];
5350
+
5351
+ return emitter;
5352
+ }
5353
+
5354
+ /**
5355
+ * Clear event by name.
5356
+ *
5357
+ * @param {EventEmitter} emitter Reference to the `EventEmitter` instance.
5358
+ * @param {(String|Symbol)} evt The Event name.
5359
+ * @private
5360
+ */
5361
+ function clearEvent(emitter, evt) {
5362
+ if (--emitter._eventsCount === 0) emitter._events = new Events();
5363
+ else delete emitter._events[evt];
5364
+ }
5365
+
5366
+ /**
5367
+ * Minimal `EventEmitter` interface that is molded against the Node.js
5368
+ * `EventEmitter` interface.
5369
+ *
5370
+ * @constructor
5371
+ * @public
5372
+ */
5373
+ function EventEmitter() {
5374
+ this._events = new Events();
5375
+ this._eventsCount = 0;
5376
+ }
5377
+
5378
+ /**
5379
+ * Return an array listing the events for which the emitter has registered
5380
+ * listeners.
5381
+ *
5382
+ * @returns {Array}
5383
+ * @public
5384
+ */
5385
+ EventEmitter.prototype.eventNames = function eventNames() {
5386
+ var names = []
5387
+ , events
5388
+ , name;
5389
+
5390
+ if (this._eventsCount === 0) return names;
5391
+
5392
+ for (name in (events = this._events)) {
5393
+ if (has.call(events, name)) names.push(prefix ? name.slice(1) : name);
5394
+ }
5395
+
5396
+ if (Object.getOwnPropertySymbols) {
5397
+ return names.concat(Object.getOwnPropertySymbols(events));
5398
+ }
5399
+
5400
+ return names;
5401
+ };
5402
+
5403
+ /**
5404
+ * Return the listeners registered for a given event.
5405
+ *
5406
+ * @param {(String|Symbol)} event The event name.
5407
+ * @returns {Array} The registered listeners.
5408
+ * @public
5409
+ */
5410
+ EventEmitter.prototype.listeners = function listeners(event) {
5411
+ var evt = prefix ? prefix + event : event
5412
+ , handlers = this._events[evt];
5413
+
5414
+ if (!handlers) return [];
5415
+ if (handlers.fn) return [handlers.fn];
5416
+
5417
+ for (var i = 0, l = handlers.length, ee = new Array(l); i < l; i++) {
5418
+ ee[i] = handlers[i].fn;
5419
+ }
5420
+
5421
+ return ee;
5422
+ };
5423
+
5424
+ /**
5425
+ * Return the number of listeners listening to a given event.
5426
+ *
5427
+ * @param {(String|Symbol)} event The event name.
5428
+ * @returns {Number} The number of listeners.
5429
+ * @public
5430
+ */
5431
+ EventEmitter.prototype.listenerCount = function listenerCount(event) {
5432
+ var evt = prefix ? prefix + event : event
5433
+ , listeners = this._events[evt];
5434
+
5435
+ if (!listeners) return 0;
5436
+ if (listeners.fn) return 1;
5437
+ return listeners.length;
5438
+ };
5439
+
5440
+ /**
5441
+ * Calls each of the listeners registered for a given event.
5442
+ *
5443
+ * @param {(String|Symbol)} event The event name.
5444
+ * @returns {Boolean} `true` if the event had listeners, else `false`.
5445
+ * @public
5446
+ */
5447
+ EventEmitter.prototype.emit = function emit(event, a1, a2, a3, a4, a5) {
5448
+ var evt = prefix ? prefix + event : event;
5449
+
5450
+ if (!this._events[evt]) return false;
5451
+
5452
+ var listeners = this._events[evt]
5453
+ , len = arguments.length
5454
+ , args
5455
+ , i;
5456
+
5457
+ if (listeners.fn) {
5458
+ if (listeners.once) this.removeListener(event, listeners.fn, undefined, true);
5459
+
5460
+ switch (len) {
5461
+ case 1: return listeners.fn.call(listeners.context), true;
5462
+ case 2: return listeners.fn.call(listeners.context, a1), true;
5463
+ case 3: return listeners.fn.call(listeners.context, a1, a2), true;
5464
+ case 4: return listeners.fn.call(listeners.context, a1, a2, a3), true;
5465
+ case 5: return listeners.fn.call(listeners.context, a1, a2, a3, a4), true;
5466
+ case 6: return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true;
5259
5467
  }
5260
- `;
5261
- const getAnswerData = `
5262
- query GetTableWithHeadlineData($session: BachSessionIdInput!, $deadline: Int!, $dataPaginationParams: DataPaginationParamsInput!) {
5263
- getAnswer(session: $session) {
5264
- ${bachSessionId}
5265
- answer {
5266
- id
5267
- visualizations {
5268
- id
5269
- ... on TableViz {
5270
- columns {
5271
- column {
5272
- id
5273
- name
5274
- type
5275
- aggregationType
5276
- dataType
5277
- }
5278
- }
5279
- data(deadline: $deadline, pagination: $dataPaginationParams)
5280
- }
5281
- }
5282
- }
5283
- }
5468
+
5469
+ for (i = 1, args = new Array(len -1); i < len; i++) {
5470
+ args[i - 1] = arguments[i];
5284
5471
  }
5285
- `;
5286
5472
 
5287
- // eslint-disable-next-line no-shadow
5288
- var OperationType;
5289
- (function (OperationType) {
5290
- OperationType["GetChartWithData"] = "GetChartWithData";
5291
- OperationType["GetTableWithHeadlineData"] = "GetTableWithHeadlineData";
5292
- })(OperationType || (OperationType = {}));
5293
- /**
5294
- * Class representing the answer service provided with the
5295
- * custom action payload. This service could be used to run
5296
- * graphql queries in the context of the answer on which the
5297
- * custom action was triggered.
5298
- *
5299
- * @example
5300
- * ```js
5301
- * embed.on(EmbedEvent.CustomAction, e => {
5302
- * const underlying = await e.answerService.getUnderlyingDataForPoint([
5303
- * 'col name 1'
5304
- * ]);
5305
- * const data = await underlying.fetchData(0, 100);
5306
- * })
5307
- * ```
5308
- * @version
5309
- * ThoughtSpot: 9.9.0.cl / SDK: 1.25.0
5310
- * @group Events
5311
- */
5312
- class AnswerService {
5313
- constructor(session, answer, thoughtSpotHost, selectedPoints) {
5314
- this.session = session;
5315
- this.answer = answer;
5316
- this.thoughtSpotHost = thoughtSpotHost;
5317
- this.selectedPoints = selectedPoints;
5318
- this.session = removeTypename(session);
5319
- }
5320
- async getSourceDetail() {
5321
- const sourceId = this.answer.sources[0].header.guid;
5322
- return getSourceDetail(this.thoughtSpotHost, sourceId);
5323
- }
5324
- async removeColumns(columnIds) {
5325
- return this.executeQuery(removeColumns, {
5326
- logicalColumnIds: columnIds,
5327
- });
5328
- }
5329
- async addColumns(columnIds) {
5330
- return this.executeQuery(addColumns, {
5331
- columns: columnIds.map((colId) => ({ logicalColumnId: colId })),
5332
- });
5333
- }
5334
- async fetchData(offset = 0, size = 1000) {
5335
- const { answer } = await this.executeQuery(getAnswerData, {
5336
- deadline: 0,
5337
- dataPaginationParams: {
5338
- isClientPaginated: true,
5339
- offset,
5340
- size,
5341
- },
5342
- });
5343
- const { columns, data } = answer.visualizations[0];
5344
- return {
5345
- columns,
5346
- data,
5347
- };
5348
- }
5349
- /**
5350
- *
5351
- * @param userLocale
5352
- * @param includeInfo Include the CSV header in the output
5353
- * @returns Response
5354
- */
5355
- async fetchCSVBlob(userLocale = 'en-us', includeInfo = false) {
5356
- const fetchUrl = `${this.thoughtSpotHost}/prism/download/answer/csv?sessionId=${this.session.sessionId}&genNo=${this.session.genNo}&userLocale=${userLocale}&exportFileName=data&hideCsvHeader=${!includeInfo}`;
5357
- return fetch(fetchUrl, {
5358
- credentials: 'include',
5359
- });
5360
- }
5361
- /**
5362
- * Get underlying data given a point and the output column names.
5363
- *
5364
- * @param outputColumnNames
5365
- * @param selectedPoints
5366
- * @example
5367
- * ```js
5368
- * embed.on(EmbedEvent.CustomAction, e => {
5369
- * const underlying = await e.answerService.getUnderlyingDataForPoint([
5370
- * 'col name 1' // The column should exist in the data source.
5371
- * ]);
5372
- * const data = await underlying.fetchData(0, 100);
5373
- * })
5374
- * ```
5375
- * @version
5376
- * ThoughtSpot: 9.9.0.cl / SDK: 1.25.0
5377
- */
5378
- async getUnderlyingDataForPoint(outputColumnNames, selectedPoints) {
5379
- if (!selectedPoints && !this.selectedPoints) {
5380
- throw new Error('Needs to be triggered in context of a point');
5381
- }
5382
- if (!selectedPoints) {
5383
- selectedPoints = getSelectedPointsForUnderlyingDataQuery(this.selectedPoints);
5384
- }
5385
- const sourceDetail = await this.getSourceDetail();
5386
- const ouputColumnGuids = getGuidsFromColumnNames(sourceDetail, outputColumnNames);
5387
- const unAggAnswer = await graphqlQuery({
5388
- query: getUnaggregatedAnswerSession,
5389
- variables: {
5390
- session: this.session,
5391
- columns: selectedPoints,
5392
- },
5393
- thoughtSpotHost: this.thoughtSpotHost,
5394
- });
5395
- const unaggAnswerSession = new AnswerService(unAggAnswer.id, unAggAnswer.answer, this.thoughtSpotHost);
5396
- const currentColumns = new Set(unAggAnswer.answer.visualizations[0].columns
5397
- .map((c) => c.column.referencedColumns[0].guid));
5398
- const columnsToAdd = [...ouputColumnGuids].filter((col) => !currentColumns.has(col));
5399
- if (columnsToAdd.length) {
5400
- await unaggAnswerSession.addColumns(columnsToAdd);
5401
- }
5402
- const columnsToRemove = [...currentColumns].filter((col) => !ouputColumnGuids.has(col));
5403
- if (columnsToRemove.length) {
5404
- await unaggAnswerSession.removeColumns(columnsToRemove);
5405
- }
5406
- return unaggAnswerSession;
5407
- }
5408
- async executeQuery(query, variables) {
5409
- const data = await graphqlQuery({
5410
- query,
5411
- variables: {
5412
- session: this.session,
5413
- ...variables,
5414
- },
5415
- thoughtSpotHost: this.thoughtSpotHost,
5416
- isCompositeQuery: false,
5417
- });
5418
- this.session = deepMerge(this.session, (data === null || data === void 0 ? void 0 : data.id) || {});
5419
- return data;
5420
- }
5421
- getSession() {
5422
- return this.session;
5423
- }
5424
- }
5425
- /**
5426
- *
5427
- * @param sourceDetail
5428
- * @param colNames
5429
- */
5430
- function getGuidsFromColumnNames(sourceDetail, colNames) {
5431
- const cols = sourceDetail.columns.reduce((colSet, col) => {
5432
- colSet[col.name] = col;
5433
- return colSet;
5434
- }, {});
5435
- return new Set(colNames.map((colName) => {
5436
- const col = cols[colName];
5437
- return col.id;
5438
- }));
5439
- }
5440
- /**
5441
- *
5442
- * @param selectedPoints
5443
- */
5444
- function getSelectedPointsForUnderlyingDataQuery(selectedPoints) {
5445
- const underlyingDataPoint = [];
5446
- /**
5447
- *
5448
- * @param colVal
5449
- */
5450
- function addPointFromColVal(colVal) {
5451
- var _a;
5452
- const dataType = colVal.column.dataType;
5453
- const id = colVal.column.id;
5454
- let dataValue;
5455
- if (dataType === 'DATE') {
5456
- if (Number.isFinite(colVal.value)) {
5457
- dataValue = [{
5458
- epochRange: {
5459
- startEpoch: colVal.value,
5460
- },
5461
- }];
5462
- // Case for custom calendar.
5463
- }
5464
- else if ((_a = colVal.value) === null || _a === void 0 ? void 0 : _a.v) {
5465
- dataValue = [{
5466
- epochRange: {
5467
- startEpoch: colVal.value.v.s,
5468
- endEpoch: colVal.value.v.e,
5469
- },
5470
- }];
5471
- }
5472
- }
5473
- else {
5474
- dataValue = [{ value: colVal.value }];
5475
- }
5476
- underlyingDataPoint.push({
5477
- columnId: colVal.column.id,
5478
- dataValue,
5479
- });
5480
- }
5481
- selectedPoints.forEach((p) => {
5482
- p.selectedAttributes.forEach(addPointFromColVal);
5483
- });
5484
- return underlyingDataPoint;
5473
+ listeners.fn.apply(listeners.context, args);
5474
+ } else {
5475
+ var length = listeners.length
5476
+ , j;
5477
+
5478
+ for (i = 0; i < length; i++) {
5479
+ if (listeners[i].once) this.removeListener(event, listeners[i].fn, undefined, true);
5480
+
5481
+ switch (len) {
5482
+ case 1: listeners[i].fn.call(listeners[i].context); break;
5483
+ case 2: listeners[i].fn.call(listeners[i].context, a1); break;
5484
+ case 3: listeners[i].fn.call(listeners[i].context, a1, a2); break;
5485
+ case 4: listeners[i].fn.call(listeners[i].context, a1, a2, a3); break;
5486
+ default:
5487
+ if (!args) for (j = 1, args = new Array(len -1); j < len; j++) {
5488
+ args[j - 1] = arguments[j];
5489
+ }
5490
+
5491
+ listeners[i].fn.apply(listeners[i].context, args);
5492
+ }
5493
+ }
5494
+ }
5495
+
5496
+ return true;
5497
+ };
5498
+
5499
+ /**
5500
+ * Add a listener for a given event.
5501
+ *
5502
+ * @param {(String|Symbol)} event The event name.
5503
+ * @param {Function} fn The listener function.
5504
+ * @param {*} [context=this] The context to invoke the listener with.
5505
+ * @returns {EventEmitter} `this`.
5506
+ * @public
5507
+ */
5508
+ EventEmitter.prototype.on = function on(event, fn, context) {
5509
+ return addListener(this, event, fn, context, false);
5510
+ };
5511
+
5512
+ /**
5513
+ * Add a one-time listener for a given event.
5514
+ *
5515
+ * @param {(String|Symbol)} event The event name.
5516
+ * @param {Function} fn The listener function.
5517
+ * @param {*} [context=this] The context to invoke the listener with.
5518
+ * @returns {EventEmitter} `this`.
5519
+ * @public
5520
+ */
5521
+ EventEmitter.prototype.once = function once(event, fn, context) {
5522
+ return addListener(this, event, fn, context, true);
5523
+ };
5524
+
5525
+ /**
5526
+ * Remove the listeners of a given event.
5527
+ *
5528
+ * @param {(String|Symbol)} event The event name.
5529
+ * @param {Function} fn Only remove the listeners that match this function.
5530
+ * @param {*} context Only remove the listeners that have this context.
5531
+ * @param {Boolean} once Only remove one-time listeners.
5532
+ * @returns {EventEmitter} `this`.
5533
+ * @public
5534
+ */
5535
+ EventEmitter.prototype.removeListener = function removeListener(event, fn, context, once) {
5536
+ var evt = prefix ? prefix + event : event;
5537
+
5538
+ if (!this._events[evt]) return this;
5539
+ if (!fn) {
5540
+ clearEvent(this, evt);
5541
+ return this;
5542
+ }
5543
+
5544
+ var listeners = this._events[evt];
5545
+
5546
+ if (listeners.fn) {
5547
+ if (
5548
+ listeners.fn === fn &&
5549
+ (!once || listeners.once) &&
5550
+ (!context || listeners.context === context)
5551
+ ) {
5552
+ clearEvent(this, evt);
5553
+ }
5554
+ } else {
5555
+ for (var i = 0, events = [], length = listeners.length; i < length; i++) {
5556
+ if (
5557
+ listeners[i].fn !== fn ||
5558
+ (once && !listeners[i].once) ||
5559
+ (context && listeners[i].context !== context)
5560
+ ) {
5561
+ events.push(listeners[i]);
5562
+ }
5563
+ }
5564
+
5565
+ //
5566
+ // Reset the array, or remove it completely if we have no more listeners.
5567
+ //
5568
+ if (events.length) this._events[evt] = events.length === 1 ? events[0] : events;
5569
+ else clearEvent(this, evt);
5570
+ }
5571
+
5572
+ return this;
5573
+ };
5574
+
5575
+ /**
5576
+ * Remove all listeners, or those of the specified event.
5577
+ *
5578
+ * @param {(String|Symbol)} [event] The event name.
5579
+ * @returns {EventEmitter} `this`.
5580
+ * @public
5581
+ */
5582
+ EventEmitter.prototype.removeAllListeners = function removeAllListeners(event) {
5583
+ var evt;
5584
+
5585
+ if (event) {
5586
+ evt = prefix ? prefix + event : event;
5587
+ if (this._events[evt]) clearEvent(this, evt);
5588
+ } else {
5589
+ this._events = new Events();
5590
+ this._eventsCount = 0;
5591
+ }
5592
+
5593
+ return this;
5594
+ };
5595
+
5596
+ //
5597
+ // Alias methods names because people roll like that.
5598
+ //
5599
+ EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
5600
+ EventEmitter.prototype.addListener = EventEmitter.prototype.on;
5601
+
5602
+ //
5603
+ // Expose the prefix.
5604
+ //
5605
+ EventEmitter.prefixed = prefix;
5606
+
5607
+ //
5608
+ // Allow `EventEmitter` to be imported as module namespace.
5609
+ //
5610
+ EventEmitter.EventEmitter = EventEmitter;
5611
+
5612
+ //
5613
+ // Expose the module.
5614
+ //
5615
+ {
5616
+ module.exports = EventEmitter;
5617
+ }
5618
+ });
5619
+
5620
+ /**
5621
+ * This method returns `undefined`.
5622
+ *
5623
+ * @static
5624
+ * @memberOf _
5625
+ * @since 2.3.0
5626
+ * @category Util
5627
+ * @example
5628
+ *
5629
+ * _.times(2, _.noop);
5630
+ * // => [undefined, undefined]
5631
+ */
5632
+ function noop() {
5633
+ // No operation performed.
5485
5634
  }
5486
5635
 
5636
+ var noop_1 = noop;
5637
+
5638
+ /** Used as references for various `Number` constants. */
5639
+ var INFINITY = 1 / 0;
5640
+
5641
+ /**
5642
+ * Creates a set object of `values`.
5643
+ *
5644
+ * @private
5645
+ * @param {Array} values The values to add to the set.
5646
+ * @returns {Object} Returns the new set.
5647
+ */
5648
+ var createSet = !(_Set && (1 / _setToArray(new _Set([,-0]))[1]) == INFINITY) ? noop_1 : function(values) {
5649
+ return new _Set(values);
5650
+ };
5651
+
5487
5652
  const ERROR_MESSAGE = {
5488
5653
  INVALID_THOUGHTSPOT_HOST: 'Error parsing ThoughtSpot host. Please provide a valid URL.',
5489
5654
  LIVEBOARD_VIZ_ID_VALIDATION: 'Please provide either liveboardId or pinboardId',
@@ -5514,6 +5679,9 @@ const urlRegex = new RegExp([
5514
5679
  * @param config
5515
5680
  */
5516
5681
  const getThoughtSpotHost = (config) => {
5682
+ if (!config.thoughtSpotHost) {
5683
+ throw new Error(ERROR_MESSAGE.INVALID_THOUGHTSPOT_HOST);
5684
+ }
5517
5685
  const urlParts = config.thoughtSpotHost.match(urlRegex);
5518
5686
  if (!urlParts) {
5519
5687
  throw new Error(ERROR_MESSAGE.INVALID_THOUGHTSPOT_HOST);
@@ -10474,1611 +10642,1142 @@ MixpanelLib.prototype.remove_group = addOptOutCheckMixpanelLib(function(group_ke
10474
10642
  * @param {Object=} groups An object mapping group name keys to one or more values
10475
10643
  * @param {Function} [callback] If provided, the callback will be called after tracking the event.
10476
10644
  */
10477
- MixpanelLib.prototype.track_with_groups = addOptOutCheckMixpanelLib(function(event_name, properties, groups, callback) {
10478
- var tracking_props = _.extend({}, properties || {});
10479
- _.each(groups, function(v, k) {
10480
- if (v !== null && v !== undefined) {
10481
- tracking_props[k] = v;
10482
- }
10483
- });
10484
- return this.track(event_name, tracking_props, callback);
10485
- });
10486
-
10487
- MixpanelLib.prototype._create_map_key = function (group_key, group_id) {
10488
- return group_key + '_' + JSON.stringify(group_id);
10489
- };
10490
-
10491
- MixpanelLib.prototype._remove_group_from_cache = function (group_key, group_id) {
10492
- delete this._cached_groups[this._create_map_key(group_key, group_id)];
10493
- };
10494
-
10495
- /**
10496
- * Look up reference to a Mixpanel group
10497
- *
10498
- * ### Usage:
10499
- *
10500
- * mixpanel.get_group(group_key, group_id)
10501
- *
10502
- * @param {String} group_key Group key
10503
- * @param {Object} group_id A valid Mixpanel property type
10504
- * @returns {Object} A MixpanelGroup identifier
10505
- */
10506
- MixpanelLib.prototype.get_group = function (group_key, group_id) {
10507
- var map_key = this._create_map_key(group_key, group_id);
10508
- var group = this._cached_groups[map_key];
10509
- if (group === undefined || group._group_key !== group_key || group._group_id !== group_id) {
10510
- group = new MixpanelGroup();
10511
- group._init(this, group_key, group_id);
10512
- this._cached_groups[map_key] = group;
10513
- }
10514
- return group;
10515
- };
10516
-
10517
- /**
10518
- * Track mp_page_view event. This is now ignored by the server.
10519
- *
10520
- * @param {String} [page] The url of the page to record. If you don't include this, it defaults to the current url.
10521
- * @deprecated
10522
- */
10523
- MixpanelLib.prototype.track_pageview = function(page) {
10524
- if (_.isUndefined(page)) {
10525
- page = document$1.location.href;
10526
- }
10527
- this.track('mp_page_view', _.info.pageviewInfo(page));
10528
- };
10529
-
10530
- /**
10531
- * Track clicks on a set of document elements. Selector must be a
10532
- * valid query. Elements must exist on the page at the time track_links is called.
10533
- *
10534
- * ### Usage:
10535
- *
10536
- * // track click for link id #nav
10537
- * mixpanel.track_links('#nav', 'Clicked Nav Link');
10538
- *
10539
- * ### Notes:
10540
- *
10541
- * This function will wait up to 300 ms for the Mixpanel
10542
- * servers to respond. If they have not responded by that time
10543
- * it will head to the link without ensuring that your event
10544
- * has been tracked. To configure this timeout please see the
10545
- * set_config() documentation below.
10546
- *
10547
- * If you pass a function in as the properties argument, the
10548
- * function will receive the DOMElement that triggered the
10549
- * event as an argument. You are expected to return an object
10550
- * from the function; any properties defined on this object
10551
- * will be sent to mixpanel as event properties.
10552
- *
10553
- * @type {Function}
10554
- * @param {Object|String} query A valid DOM query, element or jQuery-esque list
10555
- * @param {String} event_name The name of the event to track
10556
- * @param {Object|Function} [properties] A properties object or function that returns a dictionary of properties when passed a DOMElement
10557
- */
10558
- MixpanelLib.prototype.track_links = function() {
10559
- return this._track_dom.call(this, LinkTracker, arguments);
10560
- };
10561
-
10562
- /**
10563
- * Track form submissions. Selector must be a valid query.
10564
- *
10565
- * ### Usage:
10566
- *
10567
- * // track submission for form id 'register'
10568
- * mixpanel.track_forms('#register', 'Created Account');
10569
- *
10570
- * ### Notes:
10571
- *
10572
- * This function will wait up to 300 ms for the mixpanel
10573
- * servers to respond, if they have not responded by that time
10574
- * it will head to the link without ensuring that your event
10575
- * has been tracked. To configure this timeout please see the
10576
- * set_config() documentation below.
10577
- *
10578
- * If you pass a function in as the properties argument, the
10579
- * function will receive the DOMElement that triggered the
10580
- * event as an argument. You are expected to return an object
10581
- * from the function; any properties defined on this object
10582
- * will be sent to mixpanel as event properties.
10583
- *
10584
- * @type {Function}
10585
- * @param {Object|String} query A valid DOM query, element or jQuery-esque list
10586
- * @param {String} event_name The name of the event to track
10587
- * @param {Object|Function} [properties] This can be a set of properties, or a function that returns a set of properties after being passed a DOMElement
10588
- */
10589
- MixpanelLib.prototype.track_forms = function() {
10590
- return this._track_dom.call(this, FormTracker, arguments);
10591
- };
10592
-
10593
- /**
10594
- * Time an event by including the time between this call and a
10595
- * later 'track' call for the same event in the properties sent
10596
- * with the event.
10597
- *
10598
- * ### Usage:
10599
- *
10600
- * // time an event named 'Registered'
10601
- * mixpanel.time_event('Registered');
10602
- * mixpanel.track('Registered', {'Gender': 'Male', 'Age': 21});
10603
- *
10604
- * When called for a particular event name, the next track call for that event
10605
- * name will include the elapsed time between the 'time_event' and 'track'
10606
- * calls. This value is stored as seconds in the '$duration' property.
10607
- *
10608
- * @param {String} event_name The name of the event.
10609
- */
10610
- MixpanelLib.prototype.time_event = function(event_name) {
10611
- if (_.isUndefined(event_name)) {
10612
- this.report_error('No event name provided to mixpanel.time_event');
10613
- return;
10614
- }
10615
-
10616
- if (this._event_is_disabled(event_name)) {
10617
- return;
10618
- }
10619
-
10620
- this['persistence'].set_event_timer(event_name, new Date().getTime());
10621
- };
10622
-
10623
- var REGISTER_DEFAULTS = {
10624
- 'persistent': true
10625
- };
10626
- /**
10627
- * Helper to parse options param for register methods, maintaining
10628
- * legacy support for plain "days" param instead of options object
10629
- * @param {Number|Object} [days_or_options] 'days' option (Number), or Options object for register methods
10630
- * @returns {Object} options object
10631
- */
10632
- var options_for_register = function(days_or_options) {
10633
- var options;
10634
- if (_.isObject(days_or_options)) {
10635
- options = days_or_options;
10636
- } else if (!_.isUndefined(days_or_options)) {
10637
- options = {'days': days_or_options};
10638
- } else {
10639
- options = {};
10640
- }
10641
- return _.extend({}, REGISTER_DEFAULTS, options);
10642
- };
10643
-
10644
- /**
10645
- * Register a set of super properties, which are included with all
10646
- * events. This will overwrite previous super property values.
10647
- *
10648
- * ### Usage:
10649
- *
10650
- * // register 'Gender' as a super property
10651
- * mixpanel.register({'Gender': 'Female'});
10652
- *
10653
- * // register several super properties when a user signs up
10654
- * mixpanel.register({
10655
- * 'Email': 'jdoe@example.com',
10656
- * 'Account Type': 'Free'
10657
- * });
10658
- *
10659
- * // register only for the current pageload
10660
- * mixpanel.register({'Name': 'Pat'}, {persistent: false});
10661
- *
10662
- * @param {Object} properties An associative array of properties to store about the user
10663
- * @param {Number|Object} [days_or_options] Options object or number of days since the user's last visit to store the super properties (only valid for persisted props)
10664
- * @param {boolean} [days_or_options.days] - number of days since the user's last visit to store the super properties (only valid for persisted props)
10665
- * @param {boolean} [days_or_options.persistent=true] - whether to put in persistent storage (cookie/localStorage)
10666
- */
10667
- MixpanelLib.prototype.register = function(props, days_or_options) {
10668
- var options = options_for_register(days_or_options);
10669
- if (options['persistent']) {
10670
- this['persistence'].register(props, options['days']);
10671
- } else {
10672
- _.extend(this.unpersisted_superprops, props);
10673
- }
10674
- };
10675
-
10676
- /**
10677
- * Register a set of super properties only once. This will not
10678
- * overwrite previous super property values, unlike register().
10679
- *
10680
- * ### Usage:
10681
- *
10682
- * // register a super property for the first time only
10683
- * mixpanel.register_once({
10684
- * 'First Login Date': new Date().toISOString()
10685
- * });
10686
- *
10687
- * // register once, only for the current pageload
10688
- * mixpanel.register_once({
10689
- * 'First interaction time': new Date().toISOString()
10690
- * }, 'None', {persistent: false});
10691
- *
10692
- * ### Notes:
10693
- *
10694
- * If default_value is specified, current super properties
10695
- * with that value will be overwritten.
10696
- *
10697
- * @param {Object} properties An associative array of properties to store about the user
10698
- * @param {*} [default_value] Value to override if already set in super properties (ex: 'False') Default: 'None'
10699
- * @param {Number|Object} [days_or_options] Options object or number of days since the user's last visit to store the super properties (only valid for persisted props)
10700
- * @param {boolean} [days_or_options.days] - number of days since the user's last visit to store the super properties (only valid for persisted props)
10701
- * @param {boolean} [days_or_options.persistent=true] - whether to put in persistent storage (cookie/localStorage)
10702
- */
10703
- MixpanelLib.prototype.register_once = function(props, default_value, days_or_options) {
10704
- var options = options_for_register(days_or_options);
10705
- if (options['persistent']) {
10706
- this['persistence'].register_once(props, default_value, options['days']);
10707
- } else {
10708
- if (typeof(default_value) === 'undefined') {
10709
- default_value = 'None';
10710
- }
10711
- _.each(props, function(val, prop) {
10712
- if (!this.unpersisted_superprops.hasOwnProperty(prop) || this.unpersisted_superprops[prop] === default_value) {
10713
- this.unpersisted_superprops[prop] = val;
10714
- }
10715
- }, this);
10716
- }
10717
- };
10718
-
10719
- /**
10720
- * Delete a super property stored with the current user.
10721
- *
10722
- * @param {String} property The name of the super property to remove
10723
- * @param {Object} [options]
10724
- * @param {boolean} [options.persistent=true] - whether to look in persistent storage (cookie/localStorage)
10725
- */
10726
- MixpanelLib.prototype.unregister = function(property, options) {
10727
- options = options_for_register(options);
10728
- if (options['persistent']) {
10729
- this['persistence'].unregister(property);
10730
- } else {
10731
- delete this.unpersisted_superprops[property];
10732
- }
10645
+ MixpanelLib.prototype.track_with_groups = addOptOutCheckMixpanelLib(function(event_name, properties, groups, callback) {
10646
+ var tracking_props = _.extend({}, properties || {});
10647
+ _.each(groups, function(v, k) {
10648
+ if (v !== null && v !== undefined) {
10649
+ tracking_props[k] = v;
10650
+ }
10651
+ });
10652
+ return this.track(event_name, tracking_props, callback);
10653
+ });
10654
+
10655
+ MixpanelLib.prototype._create_map_key = function (group_key, group_id) {
10656
+ return group_key + '_' + JSON.stringify(group_id);
10733
10657
  };
10734
10658
 
10735
- MixpanelLib.prototype._register_single = function(prop, value) {
10736
- var props = {};
10737
- props[prop] = value;
10738
- this.register(props);
10659
+ MixpanelLib.prototype._remove_group_from_cache = function (group_key, group_id) {
10660
+ delete this._cached_groups[this._create_map_key(group_key, group_id)];
10739
10661
  };
10740
10662
 
10741
10663
  /**
10742
- * Identify a user with a unique ID to track user activity across
10743
- * devices, tie a user to their events, and create a user profile.
10744
- * If you never call this method, unique visitors are tracked using
10745
- * a UUID generated the first time they visit the site.
10746
- *
10747
- * Call identify when you know the identity of the current user,
10748
- * typically after login or signup. We recommend against using
10749
- * identify for anonymous visitors to your site.
10664
+ * Look up reference to a Mixpanel group
10750
10665
  *
10751
- * ### Notes:
10752
- * If your project has
10753
- * <a href="https://help.mixpanel.com/hc/en-us/articles/360039133851">ID Merge</a>
10754
- * enabled, the identify method will connect pre- and
10755
- * post-authentication events when appropriate.
10666
+ * ### Usage:
10756
10667
  *
10757
- * If your project does not have ID Merge enabled, identify will
10758
- * change the user's local distinct_id to the unique ID you pass.
10759
- * Events tracked prior to authentication will not be connected
10760
- * to the same user identity. If ID Merge is disabled, alias can
10761
- * be used to connect pre- and post-registration events.
10668
+ * mixpanel.get_group(group_key, group_id)
10762
10669
  *
10763
- * @param {String} [unique_id] A string that uniquely identifies a user. If not provided, the distinct_id currently in the persistent store (cookie or localStorage) will be used.
10670
+ * @param {String} group_key Group key
10671
+ * @param {Object} group_id A valid Mixpanel property type
10672
+ * @returns {Object} A MixpanelGroup identifier
10764
10673
  */
10765
- MixpanelLib.prototype.identify = function(
10766
- new_distinct_id, _set_callback, _add_callback, _append_callback, _set_once_callback, _union_callback, _unset_callback, _remove_callback
10767
- ) {
10768
- // Optional Parameters
10769
- // _set_callback:function A callback to be run if and when the People set queue is flushed
10770
- // _add_callback:function A callback to be run if and when the People add queue is flushed
10771
- // _append_callback:function A callback to be run if and when the People append queue is flushed
10772
- // _set_once_callback:function A callback to be run if and when the People set_once queue is flushed
10773
- // _union_callback:function A callback to be run if and when the People union queue is flushed
10774
- // _unset_callback:function A callback to be run if and when the People unset queue is flushed
10775
-
10776
- var previous_distinct_id = this.get_distinct_id();
10777
- this.register({'$user_id': new_distinct_id});
10778
-
10779
- if (!this.get_property('$device_id')) {
10780
- // The persisted distinct id might not actually be a device id at all
10781
- // it might be a distinct id of the user from before
10782
- var device_id = previous_distinct_id;
10783
- this.register_once({
10784
- '$had_persisted_distinct_id': true,
10785
- '$device_id': device_id
10786
- }, '');
10787
- }
10788
-
10789
- // identify only changes the distinct id if it doesn't match either the existing or the alias;
10790
- // if it's new, blow away the alias as well.
10791
- if (new_distinct_id !== previous_distinct_id && new_distinct_id !== this.get_property(ALIAS_ID_KEY)) {
10792
- this.unregister(ALIAS_ID_KEY);
10793
- this.register({'distinct_id': new_distinct_id});
10794
- }
10795
- this._flags.identify_called = true;
10796
- // Flush any queued up people requests
10797
- this['people']._flush(_set_callback, _add_callback, _append_callback, _set_once_callback, _union_callback, _unset_callback, _remove_callback);
10798
-
10799
- // send an $identify event any time the distinct_id is changing - logic on the server
10800
- // will determine whether or not to do anything with it.
10801
- if (new_distinct_id !== previous_distinct_id) {
10802
- this.track('$identify', {
10803
- 'distinct_id': new_distinct_id,
10804
- '$anon_distinct_id': previous_distinct_id
10805
- }, {skip_hooks: true});
10674
+ MixpanelLib.prototype.get_group = function (group_key, group_id) {
10675
+ var map_key = this._create_map_key(group_key, group_id);
10676
+ var group = this._cached_groups[map_key];
10677
+ if (group === undefined || group._group_key !== group_key || group._group_id !== group_id) {
10678
+ group = new MixpanelGroup();
10679
+ group._init(this, group_key, group_id);
10680
+ this._cached_groups[map_key] = group;
10806
10681
  }
10682
+ return group;
10807
10683
  };
10808
10684
 
10809
10685
  /**
10810
- * Clears super properties and generates a new random distinct_id for this instance.
10811
- * Useful for clearing data when a user logs out.
10686
+ * Track mp_page_view event. This is now ignored by the server.
10687
+ *
10688
+ * @param {String} [page] The url of the page to record. If you don't include this, it defaults to the current url.
10689
+ * @deprecated
10812
10690
  */
10813
- MixpanelLib.prototype.reset = function() {
10814
- this['persistence'].clear();
10815
- this._flags.identify_called = false;
10816
- var uuid = _.UUID();
10817
- this.register_once({
10818
- 'distinct_id': uuid,
10819
- '$device_id': uuid
10820
- }, '');
10691
+ MixpanelLib.prototype.track_pageview = function(page) {
10692
+ if (_.isUndefined(page)) {
10693
+ page = document$1.location.href;
10694
+ }
10695
+ this.track('mp_page_view', _.info.pageviewInfo(page));
10821
10696
  };
10822
10697
 
10823
10698
  /**
10824
- * Returns the current distinct id of the user. This is either the id automatically
10825
- * generated by the library or the id that has been passed by a call to identify().
10699
+ * Track clicks on a set of document elements. Selector must be a
10700
+ * valid query. Elements must exist on the page at the time track_links is called.
10701
+ *
10702
+ * ### Usage:
10703
+ *
10704
+ * // track click for link id #nav
10705
+ * mixpanel.track_links('#nav', 'Clicked Nav Link');
10826
10706
  *
10827
10707
  * ### Notes:
10828
10708
  *
10829
- * get_distinct_id() can only be called after the Mixpanel library has finished loading.
10830
- * init() has a loaded function available to handle this automatically. For example:
10709
+ * This function will wait up to 300 ms for the Mixpanel
10710
+ * servers to respond. If they have not responded by that time
10711
+ * it will head to the link without ensuring that your event
10712
+ * has been tracked. To configure this timeout please see the
10713
+ * set_config() documentation below.
10831
10714
  *
10832
- * // set distinct_id after the mixpanel library has loaded
10833
- * mixpanel.init('YOUR PROJECT TOKEN', {
10834
- * loaded: function(mixpanel) {
10835
- * distinct_id = mixpanel.get_distinct_id();
10836
- * }
10837
- * });
10715
+ * If you pass a function in as the properties argument, the
10716
+ * function will receive the DOMElement that triggered the
10717
+ * event as an argument. You are expected to return an object
10718
+ * from the function; any properties defined on this object
10719
+ * will be sent to mixpanel as event properties.
10720
+ *
10721
+ * @type {Function}
10722
+ * @param {Object|String} query A valid DOM query, element or jQuery-esque list
10723
+ * @param {String} event_name The name of the event to track
10724
+ * @param {Object|Function} [properties] A properties object or function that returns a dictionary of properties when passed a DOMElement
10838
10725
  */
10839
- MixpanelLib.prototype.get_distinct_id = function() {
10840
- return this.get_property('distinct_id');
10726
+ MixpanelLib.prototype.track_links = function() {
10727
+ return this._track_dom.call(this, LinkTracker, arguments);
10841
10728
  };
10842
10729
 
10843
10730
  /**
10844
- * The alias method creates an alias which Mixpanel will use to
10845
- * remap one id to another. Multiple aliases can point to the
10846
- * same identifier.
10731
+ * Track form submissions. Selector must be a valid query.
10847
10732
  *
10848
- * The following is a valid use of alias:
10733
+ * ### Usage:
10849
10734
  *
10850
- * mixpanel.alias('new_id', 'existing_id');
10851
- * // You can add multiple id aliases to the existing ID
10852
- * mixpanel.alias('newer_id', 'existing_id');
10735
+ * // track submission for form id 'register'
10736
+ * mixpanel.track_forms('#register', 'Created Account');
10853
10737
  *
10854
- * Aliases can also be chained - the following is a valid example:
10738
+ * ### Notes:
10855
10739
  *
10856
- * mixpanel.alias('new_id', 'existing_id');
10857
- * // chain newer_id - new_id - existing_id
10858
- * mixpanel.alias('newer_id', 'new_id');
10740
+ * This function will wait up to 300 ms for the mixpanel
10741
+ * servers to respond, if they have not responded by that time
10742
+ * it will head to the link without ensuring that your event
10743
+ * has been tracked. To configure this timeout please see the
10744
+ * set_config() documentation below.
10859
10745
  *
10860
- * Aliases cannot point to multiple identifiers - the following
10861
- * example will not work:
10746
+ * If you pass a function in as the properties argument, the
10747
+ * function will receive the DOMElement that triggered the
10748
+ * event as an argument. You are expected to return an object
10749
+ * from the function; any properties defined on this object
10750
+ * will be sent to mixpanel as event properties.
10862
10751
  *
10863
- * mixpanel.alias('new_id', 'existing_id');
10864
- * // this is invalid as 'new_id' already points to 'existing_id'
10865
- * mixpanel.alias('new_id', 'newer_id');
10752
+ * @type {Function}
10753
+ * @param {Object|String} query A valid DOM query, element or jQuery-esque list
10754
+ * @param {String} event_name The name of the event to track
10755
+ * @param {Object|Function} [properties] This can be a set of properties, or a function that returns a set of properties after being passed a DOMElement
10756
+ */
10757
+ MixpanelLib.prototype.track_forms = function() {
10758
+ return this._track_dom.call(this, FormTracker, arguments);
10759
+ };
10760
+
10761
+ /**
10762
+ * Time an event by including the time between this call and a
10763
+ * later 'track' call for the same event in the properties sent
10764
+ * with the event.
10866
10765
  *
10867
- * ### Notes:
10766
+ * ### Usage:
10868
10767
  *
10869
- * If your project does not have
10870
- * <a href="https://help.mixpanel.com/hc/en-us/articles/360039133851">ID Merge</a>
10871
- * enabled, the best practice is to call alias once when a unique
10872
- * ID is first created for a user (e.g., when a user first registers
10873
- * for an account). Do not use alias multiple times for a single
10874
- * user without ID Merge enabled.
10768
+ * // time an event named 'Registered'
10769
+ * mixpanel.time_event('Registered');
10770
+ * mixpanel.track('Registered', {'Gender': 'Male', 'Age': 21});
10875
10771
  *
10876
- * @param {String} alias A unique identifier that you want to use for this user in the future.
10877
- * @param {String} [original] The current identifier being used for this user.
10772
+ * When called for a particular event name, the next track call for that event
10773
+ * name will include the elapsed time between the 'time_event' and 'track'
10774
+ * calls. This value is stored as seconds in the '$duration' property.
10775
+ *
10776
+ * @param {String} event_name The name of the event.
10878
10777
  */
10879
- MixpanelLib.prototype.alias = function(alias, original) {
10880
- // If the $people_distinct_id key exists in persistence, there has been a previous
10881
- // mixpanel.people.identify() call made for this user. It is VERY BAD to make an alias with
10882
- // this ID, as it will duplicate users.
10883
- if (alias === this.get_property(PEOPLE_DISTINCT_ID_KEY)) {
10884
- this.report_error('Attempting to create alias for existing People user - aborting.');
10885
- return -2;
10778
+ MixpanelLib.prototype.time_event = function(event_name) {
10779
+ if (_.isUndefined(event_name)) {
10780
+ this.report_error('No event name provided to mixpanel.time_event');
10781
+ return;
10886
10782
  }
10887
10783
 
10888
- var _this = this;
10889
- if (_.isUndefined(original)) {
10890
- original = this.get_distinct_id();
10784
+ if (this._event_is_disabled(event_name)) {
10785
+ return;
10891
10786
  }
10892
- if (alias !== original) {
10893
- this._register_single(ALIAS_ID_KEY, alias);
10894
- return this.track('$create_alias', {
10895
- 'alias': alias,
10896
- 'distinct_id': original
10897
- }, {
10898
- skip_hooks: true
10899
- }, function() {
10900
- // Flush the people queue
10901
- _this.identify(alias);
10902
- });
10787
+
10788
+ this['persistence'].set_event_timer(event_name, new Date().getTime());
10789
+ };
10790
+
10791
+ var REGISTER_DEFAULTS = {
10792
+ 'persistent': true
10793
+ };
10794
+ /**
10795
+ * Helper to parse options param for register methods, maintaining
10796
+ * legacy support for plain "days" param instead of options object
10797
+ * @param {Number|Object} [days_or_options] 'days' option (Number), or Options object for register methods
10798
+ * @returns {Object} options object
10799
+ */
10800
+ var options_for_register = function(days_or_options) {
10801
+ var options;
10802
+ if (_.isObject(days_or_options)) {
10803
+ options = days_or_options;
10804
+ } else if (!_.isUndefined(days_or_options)) {
10805
+ options = {'days': days_or_options};
10903
10806
  } else {
10904
- this.report_error('alias matches current distinct_id - skipping api call.');
10905
- this.identify(alias);
10906
- return -1;
10807
+ options = {};
10907
10808
  }
10809
+ return _.extend({}, REGISTER_DEFAULTS, options);
10908
10810
  };
10909
10811
 
10910
10812
  /**
10911
- * Provide a string to recognize the user by. The string passed to
10912
- * this method will appear in the Mixpanel Streams product rather
10913
- * than an automatically generated name. Name tags do not have to
10914
- * be unique.
10813
+ * Register a set of super properties, which are included with all
10814
+ * events. This will overwrite previous super property values.
10915
10815
  *
10916
- * This value will only be included in Streams data.
10816
+ * ### Usage:
10917
10817
  *
10918
- * @param {String} name_tag A human readable name for the user
10919
- * @deprecated
10818
+ * // register 'Gender' as a super property
10819
+ * mixpanel.register({'Gender': 'Female'});
10820
+ *
10821
+ * // register several super properties when a user signs up
10822
+ * mixpanel.register({
10823
+ * 'Email': 'jdoe@example.com',
10824
+ * 'Account Type': 'Free'
10825
+ * });
10826
+ *
10827
+ * // register only for the current pageload
10828
+ * mixpanel.register({'Name': 'Pat'}, {persistent: false});
10829
+ *
10830
+ * @param {Object} properties An associative array of properties to store about the user
10831
+ * @param {Number|Object} [days_or_options] Options object or number of days since the user's last visit to store the super properties (only valid for persisted props)
10832
+ * @param {boolean} [days_or_options.days] - number of days since the user's last visit to store the super properties (only valid for persisted props)
10833
+ * @param {boolean} [days_or_options.persistent=true] - whether to put in persistent storage (cookie/localStorage)
10920
10834
  */
10921
- MixpanelLib.prototype.name_tag = function(name_tag) {
10922
- this._register_single('mp_name_tag', name_tag);
10835
+ MixpanelLib.prototype.register = function(props, days_or_options) {
10836
+ var options = options_for_register(days_or_options);
10837
+ if (options['persistent']) {
10838
+ this['persistence'].register(props, options['days']);
10839
+ } else {
10840
+ _.extend(this.unpersisted_superprops, props);
10841
+ }
10923
10842
  };
10924
10843
 
10925
10844
  /**
10926
- * Update the configuration of a mixpanel library instance.
10927
- *
10928
- * The default config is:
10929
- *
10930
- * {
10931
- * // HTTP method for tracking requests
10932
- * api_method: 'POST'
10933
- *
10934
- * // transport for sending requests ('XHR' or 'sendBeacon')
10935
- * // NB: sendBeacon should only be used for scenarios such as
10936
- * // page unload where a "best-effort" attempt to send is
10937
- * // acceptable; the sendBeacon API does not support callbacks
10938
- * // or any way to know the result of the request. Mixpanel
10939
- * // tracking via sendBeacon will not support any event-
10940
- * // batching or retry mechanisms.
10941
- * api_transport: 'XHR'
10942
- *
10943
- * // turn on request-batching/queueing/retry
10944
- * batch_requests: false,
10945
- *
10946
- * // maximum number of events/updates to send in a single
10947
- * // network request
10948
- * batch_size: 50,
10949
- *
10950
- * // milliseconds to wait between sending batch requests
10951
- * batch_flush_interval_ms: 5000,
10952
- *
10953
- * // milliseconds to wait for network responses to batch requests
10954
- * // before they are considered timed-out and retried
10955
- * batch_request_timeout_ms: 90000,
10956
- *
10957
- * // override value for cookie domain, only useful for ensuring
10958
- * // correct cross-subdomain cookies on unusual domains like
10959
- * // subdomain.mainsite.avocat.fr; NB this cannot be used to
10960
- * // set cookies on a different domain than the current origin
10961
- * cookie_domain: ''
10962
- *
10963
- * // super properties cookie expiration (in days)
10964
- * cookie_expiration: 365
10965
- *
10966
- * // if true, cookie will be set with SameSite=None; Secure
10967
- * // this is only useful in special situations, like embedded
10968
- * // 3rd-party iframes that set up a Mixpanel instance
10969
- * cross_site_cookie: false
10970
- *
10971
- * // super properties span subdomains
10972
- * cross_subdomain_cookie: true
10973
- *
10974
- * // debug mode
10975
- * debug: false
10976
- *
10977
- * // if this is true, the mixpanel cookie or localStorage entry
10978
- * // will be deleted, and no user persistence will take place
10979
- * disable_persistence: false
10980
- *
10981
- * // if this is true, Mixpanel will automatically determine
10982
- * // City, Region and Country data using the IP address of
10983
- * //the client
10984
- * ip: true
10985
- *
10986
- * // opt users out of tracking by this Mixpanel instance by default
10987
- * opt_out_tracking_by_default: false
10988
- *
10989
- * // opt users out of browser data storage by this Mixpanel instance by default
10990
- * opt_out_persistence_by_default: false
10991
- *
10992
- * // persistence mechanism used by opt-in/opt-out methods - cookie
10993
- * // or localStorage - falls back to cookie if localStorage is unavailable
10994
- * opt_out_tracking_persistence_type: 'localStorage'
10845
+ * Register a set of super properties only once. This will not
10846
+ * overwrite previous super property values, unlike register().
10995
10847
  *
10996
- * // customize the name of cookie/localStorage set by opt-in/opt-out methods
10997
- * opt_out_tracking_cookie_prefix: null
10848
+ * ### Usage:
10998
10849
  *
10999
- * // type of persistent store for super properties (cookie/
11000
- * // localStorage) if set to 'localStorage', any existing
11001
- * // mixpanel cookie value with the same persistence_name
11002
- * // will be transferred to localStorage and deleted
11003
- * persistence: 'cookie'
10850
+ * // register a super property for the first time only
10851
+ * mixpanel.register_once({
10852
+ * 'First Login Date': new Date().toISOString()
10853
+ * });
11004
10854
  *
11005
- * // name for super properties persistent store
11006
- * persistence_name: ''
10855
+ * // register once, only for the current pageload
10856
+ * mixpanel.register_once({
10857
+ * 'First interaction time': new Date().toISOString()
10858
+ * }, 'None', {persistent: false});
11007
10859
  *
11008
- * // names of properties/superproperties which should never
11009
- * // be sent with track() calls
11010
- * property_blacklist: []
10860
+ * ### Notes:
11011
10861
  *
11012
- * // if this is true, mixpanel cookies will be marked as
11013
- * // secure, meaning they will only be transmitted over https
11014
- * secure_cookie: false
10862
+ * If default_value is specified, current super properties
10863
+ * with that value will be overwritten.
11015
10864
  *
11016
- * // the amount of time track_links will
11017
- * // wait for Mixpanel's servers to respond
11018
- * track_links_timeout: 300
10865
+ * @param {Object} properties An associative array of properties to store about the user
10866
+ * @param {*} [default_value] Value to override if already set in super properties (ex: 'False') Default: 'None'
10867
+ * @param {Number|Object} [days_or_options] Options object or number of days since the user's last visit to store the super properties (only valid for persisted props)
10868
+ * @param {boolean} [days_or_options.days] - number of days since the user's last visit to store the super properties (only valid for persisted props)
10869
+ * @param {boolean} [days_or_options.persistent=true] - whether to put in persistent storage (cookie/localStorage)
10870
+ */
10871
+ MixpanelLib.prototype.register_once = function(props, default_value, days_or_options) {
10872
+ var options = options_for_register(days_or_options);
10873
+ if (options['persistent']) {
10874
+ this['persistence'].register_once(props, default_value, options['days']);
10875
+ } else {
10876
+ if (typeof(default_value) === 'undefined') {
10877
+ default_value = 'None';
10878
+ }
10879
+ _.each(props, function(val, prop) {
10880
+ if (!this.unpersisted_superprops.hasOwnProperty(prop) || this.unpersisted_superprops[prop] === default_value) {
10881
+ this.unpersisted_superprops[prop] = val;
10882
+ }
10883
+ }, this);
10884
+ }
10885
+ };
10886
+
10887
+ /**
10888
+ * Delete a super property stored with the current user.
11019
10889
  *
11020
- * // if you set upgrade to be true, the library will check for
11021
- * // a cookie from our old js library and import super
11022
- * // properties from it, then the old cookie is deleted
11023
- * // The upgrade config option only works in the initialization,
11024
- * // so make sure you set it when you create the library.
11025
- * upgrade: false
10890
+ * @param {String} property The name of the super property to remove
10891
+ * @param {Object} [options]
10892
+ * @param {boolean} [options.persistent=true] - whether to look in persistent storage (cookie/localStorage)
10893
+ */
10894
+ MixpanelLib.prototype.unregister = function(property, options) {
10895
+ options = options_for_register(options);
10896
+ if (options['persistent']) {
10897
+ this['persistence'].unregister(property);
10898
+ } else {
10899
+ delete this.unpersisted_superprops[property];
10900
+ }
10901
+ };
10902
+
10903
+ MixpanelLib.prototype._register_single = function(prop, value) {
10904
+ var props = {};
10905
+ props[prop] = value;
10906
+ this.register(props);
10907
+ };
10908
+
10909
+ /**
10910
+ * Identify a user with a unique ID to track user activity across
10911
+ * devices, tie a user to their events, and create a user profile.
10912
+ * If you never call this method, unique visitors are tracked using
10913
+ * a UUID generated the first time they visit the site.
11026
10914
  *
11027
- * // extra HTTP request headers to set for each API request, in
11028
- * // the format {'Header-Name': value}
11029
- * xhr_headers: {}
10915
+ * Call identify when you know the identity of the current user,
10916
+ * typically after login or signup. We recommend against using
10917
+ * identify for anonymous visitors to your site.
11030
10918
  *
11031
- * // whether to ignore or respect the web browser's Do Not Track setting
11032
- * ignore_dnt: false
11033
- * }
10919
+ * ### Notes:
10920
+ * If your project has
10921
+ * <a href="https://help.mixpanel.com/hc/en-us/articles/360039133851">ID Merge</a>
10922
+ * enabled, the identify method will connect pre- and
10923
+ * post-authentication events when appropriate.
11034
10924
  *
10925
+ * If your project does not have ID Merge enabled, identify will
10926
+ * change the user's local distinct_id to the unique ID you pass.
10927
+ * Events tracked prior to authentication will not be connected
10928
+ * to the same user identity. If ID Merge is disabled, alias can
10929
+ * be used to connect pre- and post-registration events.
11035
10930
  *
11036
- * @param {Object} config A dictionary of new configuration values to update
10931
+ * @param {String} [unique_id] A string that uniquely identifies a user. If not provided, the distinct_id currently in the persistent store (cookie or localStorage) will be used.
11037
10932
  */
11038
- MixpanelLib.prototype.set_config = function(config) {
11039
- if (_.isObject(config)) {
11040
- _.extend(this['config'], config);
10933
+ MixpanelLib.prototype.identify = function(
10934
+ new_distinct_id, _set_callback, _add_callback, _append_callback, _set_once_callback, _union_callback, _unset_callback, _remove_callback
10935
+ ) {
10936
+ // Optional Parameters
10937
+ // _set_callback:function A callback to be run if and when the People set queue is flushed
10938
+ // _add_callback:function A callback to be run if and when the People add queue is flushed
10939
+ // _append_callback:function A callback to be run if and when the People append queue is flushed
10940
+ // _set_once_callback:function A callback to be run if and when the People set_once queue is flushed
10941
+ // _union_callback:function A callback to be run if and when the People union queue is flushed
10942
+ // _unset_callback:function A callback to be run if and when the People unset queue is flushed
11041
10943
 
11042
- var new_batch_size = config['batch_size'];
11043
- if (new_batch_size) {
11044
- _.each(this.request_batchers, function(batcher) {
11045
- batcher.resetBatchSize();
11046
- });
11047
- }
10944
+ var previous_distinct_id = this.get_distinct_id();
10945
+ this.register({'$user_id': new_distinct_id});
11048
10946
 
11049
- if (!this.get_config('persistence_name')) {
11050
- this['config']['persistence_name'] = this['config']['cookie_name'];
11051
- }
11052
- if (!this.get_config('disable_persistence')) {
11053
- this['config']['disable_persistence'] = this['config']['disable_cookie'];
11054
- }
10947
+ if (!this.get_property('$device_id')) {
10948
+ // The persisted distinct id might not actually be a device id at all
10949
+ // it might be a distinct id of the user from before
10950
+ var device_id = previous_distinct_id;
10951
+ this.register_once({
10952
+ '$had_persisted_distinct_id': true,
10953
+ '$device_id': device_id
10954
+ }, '');
10955
+ }
11055
10956
 
11056
- if (this['persistence']) {
11057
- this['persistence'].update_config(this['config']);
11058
- }
11059
- Config.DEBUG = Config.DEBUG || this.get_config('debug');
10957
+ // identify only changes the distinct id if it doesn't match either the existing or the alias;
10958
+ // if it's new, blow away the alias as well.
10959
+ if (new_distinct_id !== previous_distinct_id && new_distinct_id !== this.get_property(ALIAS_ID_KEY)) {
10960
+ this.unregister(ALIAS_ID_KEY);
10961
+ this.register({'distinct_id': new_distinct_id});
11060
10962
  }
11061
- };
10963
+ this._flags.identify_called = true;
10964
+ // Flush any queued up people requests
10965
+ this['people']._flush(_set_callback, _add_callback, _append_callback, _set_once_callback, _union_callback, _unset_callback, _remove_callback);
11062
10966
 
11063
- /**
11064
- * returns the current config object for the library.
11065
- */
11066
- MixpanelLib.prototype.get_config = function(prop_name) {
11067
- return this['config'][prop_name];
10967
+ // send an $identify event any time the distinct_id is changing - logic on the server
10968
+ // will determine whether or not to do anything with it.
10969
+ if (new_distinct_id !== previous_distinct_id) {
10970
+ this.track('$identify', {
10971
+ 'distinct_id': new_distinct_id,
10972
+ '$anon_distinct_id': previous_distinct_id
10973
+ }, {skip_hooks: true});
10974
+ }
11068
10975
  };
11069
10976
 
11070
10977
  /**
11071
- * Fetch a hook function from config, with safe default, and run it
11072
- * against the given arguments
11073
- * @param {string} hook_name which hook to retrieve
11074
- * @returns {any|null} return value of user-provided hook, or null if nothing was returned
10978
+ * Clears super properties and generates a new random distinct_id for this instance.
10979
+ * Useful for clearing data when a user logs out.
11075
10980
  */
11076
- MixpanelLib.prototype._run_hook = function(hook_name) {
11077
- var ret = (this['config']['hooks'][hook_name] || IDENTITY_FUNC).apply(this, slice.call(arguments, 1));
11078
- if (typeof ret === 'undefined') {
11079
- this.report_error(hook_name + ' hook did not return a value');
11080
- ret = null;
11081
- }
11082
- return ret;
10981
+ MixpanelLib.prototype.reset = function() {
10982
+ this['persistence'].clear();
10983
+ this._flags.identify_called = false;
10984
+ var uuid = _.UUID();
10985
+ this.register_once({
10986
+ 'distinct_id': uuid,
10987
+ '$device_id': uuid
10988
+ }, '');
11083
10989
  };
11084
10990
 
11085
10991
  /**
11086
- * Returns the value of the super property named property_name. If no such
11087
- * property is set, get_property() will return the undefined value.
10992
+ * Returns the current distinct id of the user. This is either the id automatically
10993
+ * generated by the library or the id that has been passed by a call to identify().
11088
10994
  *
11089
10995
  * ### Notes:
11090
10996
  *
11091
- * get_property() can only be called after the Mixpanel library has finished loading.
10997
+ * get_distinct_id() can only be called after the Mixpanel library has finished loading.
11092
10998
  * init() has a loaded function available to handle this automatically. For example:
11093
10999
  *
11094
- * // grab value for 'user_id' after the mixpanel library has loaded
11000
+ * // set distinct_id after the mixpanel library has loaded
11095
11001
  * mixpanel.init('YOUR PROJECT TOKEN', {
11096
11002
  * loaded: function(mixpanel) {
11097
- * user_id = mixpanel.get_property('user_id');
11003
+ * distinct_id = mixpanel.get_distinct_id();
11098
11004
  * }
11099
11005
  * });
11100
- *
11101
- * @param {String} property_name The name of the super property you want to retrieve
11102
- */
11103
- MixpanelLib.prototype.get_property = function(property_name) {
11104
- return this['persistence']['props'][property_name];
11105
- };
11106
-
11107
- MixpanelLib.prototype.toString = function() {
11108
- var name = this.get_config('name');
11109
- if (name !== PRIMARY_INSTANCE_NAME) {
11110
- name = PRIMARY_INSTANCE_NAME + '.' + name;
11111
- }
11112
- return name;
11113
- };
11114
-
11115
- MixpanelLib.prototype._event_is_disabled = function(event_name) {
11116
- return _.isBlockedUA(userAgent) ||
11117
- this._flags.disable_all_events ||
11118
- _.include(this.__disabled_events, event_name);
11119
- };
11120
-
11121
- // perform some housekeeping around GDPR opt-in/out state
11122
- MixpanelLib.prototype._gdpr_init = function() {
11123
- var is_localStorage_requested = this.get_config('opt_out_tracking_persistence_type') === 'localStorage';
11124
-
11125
- // try to convert opt-in/out cookies to localStorage if possible
11126
- if (is_localStorage_requested && _.localStorage.is_supported()) {
11127
- if (!this.has_opted_in_tracking() && this.has_opted_in_tracking({'persistence_type': 'cookie'})) {
11128
- this.opt_in_tracking({'enable_persistence': false});
11129
- }
11130
- if (!this.has_opted_out_tracking() && this.has_opted_out_tracking({'persistence_type': 'cookie'})) {
11131
- this.opt_out_tracking({'clear_persistence': false});
11132
- }
11133
- this.clear_opt_in_out_tracking({
11134
- 'persistence_type': 'cookie',
11135
- 'enable_persistence': false
11136
- });
11137
- }
11138
-
11139
- // check whether the user has already opted out - if so, clear & disable persistence
11140
- if (this.has_opted_out_tracking()) {
11141
- this._gdpr_update_persistence({'clear_persistence': true});
11142
-
11143
- // check whether we should opt out by default
11144
- // note: we don't clear persistence here by default since opt-out default state is often
11145
- // used as an initial state while GDPR information is being collected
11146
- } else if (!this.has_opted_in_tracking() && (
11147
- this.get_config('opt_out_tracking_by_default') || _.cookie.get('mp_optout')
11148
- )) {
11149
- _.cookie.remove('mp_optout');
11150
- this.opt_out_tracking({
11151
- 'clear_persistence': this.get_config('opt_out_persistence_by_default')
11152
- });
11153
- }
11154
- };
11155
-
11156
- /**
11157
- * Enable or disable persistence based on options
11158
- * only enable/disable if persistence is not already in this state
11159
- * @param {boolean} [options.clear_persistence] If true, will delete all data stored by the sdk in persistence and disable it
11160
- * @param {boolean} [options.enable_persistence] If true, will re-enable sdk persistence
11161
11006
  */
11162
- MixpanelLib.prototype._gdpr_update_persistence = function(options) {
11163
- var disabled;
11164
- if (options && options['clear_persistence']) {
11165
- disabled = true;
11166
- } else if (options && options['enable_persistence']) {
11167
- disabled = false;
11168
- } else {
11169
- return;
11170
- }
11171
-
11172
- if (!this.get_config('disable_persistence') && this['persistence'].disabled !== disabled) {
11173
- this['persistence'].set_disabled(disabled);
11174
- }
11175
-
11176
- if (disabled) {
11177
- _.each(this.request_batchers, function(batcher) {
11178
- batcher.clear();
11179
- });
11180
- }
11181
- };
11182
-
11183
- // call a base gdpr function after constructing the appropriate token and options args
11184
- MixpanelLib.prototype._gdpr_call_func = function(func, options) {
11185
- options = _.extend({
11186
- 'track': _.bind(this.track, this),
11187
- 'persistence_type': this.get_config('opt_out_tracking_persistence_type'),
11188
- 'cookie_prefix': this.get_config('opt_out_tracking_cookie_prefix'),
11189
- 'cookie_expiration': this.get_config('cookie_expiration'),
11190
- 'cross_site_cookie': this.get_config('cross_site_cookie'),
11191
- 'cross_subdomain_cookie': this.get_config('cross_subdomain_cookie'),
11192
- 'cookie_domain': this.get_config('cookie_domain'),
11193
- 'secure_cookie': this.get_config('secure_cookie'),
11194
- 'ignore_dnt': this.get_config('ignore_dnt')
11195
- }, options);
11196
-
11197
- // check if localStorage can be used for recording opt out status, fall back to cookie if not
11198
- if (!_.localStorage.is_supported()) {
11199
- options['persistence_type'] = 'cookie';
11200
- }
11201
-
11202
- return func(this.get_config('token'), {
11203
- track: options['track'],
11204
- trackEventName: options['track_event_name'],
11205
- trackProperties: options['track_properties'],
11206
- persistenceType: options['persistence_type'],
11207
- persistencePrefix: options['cookie_prefix'],
11208
- cookieDomain: options['cookie_domain'],
11209
- cookieExpiration: options['cookie_expiration'],
11210
- crossSiteCookie: options['cross_site_cookie'],
11211
- crossSubdomainCookie: options['cross_subdomain_cookie'],
11212
- secureCookie: options['secure_cookie'],
11213
- ignoreDnt: options['ignore_dnt']
11214
- });
11007
+ MixpanelLib.prototype.get_distinct_id = function() {
11008
+ return this.get_property('distinct_id');
11215
11009
  };
11216
11010
 
11217
11011
  /**
11218
- * Opt the user in to data tracking and cookies/localstorage for this Mixpanel instance
11012
+ * The alias method creates an alias which Mixpanel will use to
11013
+ * remap one id to another. Multiple aliases can point to the
11014
+ * same identifier.
11219
11015
  *
11220
- * ### Usage
11016
+ * The following is a valid use of alias:
11221
11017
  *
11222
- * // opt user in
11223
- * mixpanel.opt_in_tracking();
11018
+ * mixpanel.alias('new_id', 'existing_id');
11019
+ * // You can add multiple id aliases to the existing ID
11020
+ * mixpanel.alias('newer_id', 'existing_id');
11224
11021
  *
11225
- * // opt user in with specific event name, properties, cookie configuration
11226
- * mixpanel.opt_in_tracking({
11227
- * track_event_name: 'User opted in',
11228
- * track_event_properties: {
11229
- * 'Email': 'jdoe@example.com'
11230
- * },
11231
- * cookie_expiration: 30,
11232
- * secure_cookie: true
11233
- * });
11022
+ * Aliases can also be chained - the following is a valid example:
11234
11023
  *
11235
- * @param {Object} [options] A dictionary of config options to override
11236
- * @param {function} [options.track] Function used for tracking a Mixpanel event to record the opt-in action (default is this Mixpanel instance's track method)
11237
- * @param {string} [options.track_event_name=$opt_in] Event name to be used for tracking the opt-in action
11238
- * @param {Object} [options.track_properties] Set of properties to be tracked along with the opt-in action
11239
- * @param {boolean} [options.enable_persistence=true] If true, will re-enable sdk persistence
11240
- * @param {string} [options.persistence_type=localStorage] Persistence mechanism used - cookie or localStorage - falls back to cookie if localStorage is unavailable
11241
- * @param {string} [options.cookie_prefix=__mp_opt_in_out] Custom prefix to be used in the cookie/localstorage name
11242
- * @param {Number} [options.cookie_expiration] Number of days until the opt-in cookie expires (overrides value specified in this Mixpanel instance's config)
11243
- * @param {string} [options.cookie_domain] Custom cookie domain (overrides value specified in this Mixpanel instance's config)
11244
- * @param {boolean} [options.cross_site_cookie] Whether the opt-in cookie is set as cross-site-enabled (overrides value specified in this Mixpanel instance's config)
11245
- * @param {boolean} [options.cross_subdomain_cookie] Whether the opt-in cookie is set as cross-subdomain or not (overrides value specified in this Mixpanel instance's config)
11246
- * @param {boolean} [options.secure_cookie] Whether the opt-in cookie is set as secure or not (overrides value specified in this Mixpanel instance's config)
11247
- */
11248
- MixpanelLib.prototype.opt_in_tracking = function(options) {
11249
- options = _.extend({
11250
- 'enable_persistence': true
11251
- }, options);
11252
-
11253
- this._gdpr_call_func(optIn, options);
11254
- this._gdpr_update_persistence(options);
11255
- };
11256
-
11257
- /**
11258
- * Opt the user out of data tracking and cookies/localstorage for this Mixpanel instance
11024
+ * mixpanel.alias('new_id', 'existing_id');
11025
+ * // chain newer_id - new_id - existing_id
11026
+ * mixpanel.alias('newer_id', 'new_id');
11259
11027
  *
11260
- * ### Usage
11028
+ * Aliases cannot point to multiple identifiers - the following
11029
+ * example will not work:
11261
11030
  *
11262
- * // opt user out
11263
- * mixpanel.opt_out_tracking();
11031
+ * mixpanel.alias('new_id', 'existing_id');
11032
+ * // this is invalid as 'new_id' already points to 'existing_id'
11033
+ * mixpanel.alias('new_id', 'newer_id');
11264
11034
  *
11265
- * // opt user out with different cookie configuration from Mixpanel instance
11266
- * mixpanel.opt_out_tracking({
11267
- * cookie_expiration: 30,
11268
- * secure_cookie: true
11269
- * });
11035
+ * ### Notes:
11270
11036
  *
11271
- * @param {Object} [options] A dictionary of config options to override
11272
- * @param {boolean} [options.delete_user=true] If true, will delete the currently identified user's profile and clear all charges after opting the user out
11273
- * @param {boolean} [options.clear_persistence=true] If true, will delete all data stored by the sdk in persistence
11274
- * @param {string} [options.persistence_type=localStorage] Persistence mechanism used - cookie or localStorage - falls back to cookie if localStorage is unavailable
11275
- * @param {string} [options.cookie_prefix=__mp_opt_in_out] Custom prefix to be used in the cookie/localstorage name
11276
- * @param {Number} [options.cookie_expiration] Number of days until the opt-in cookie expires (overrides value specified in this Mixpanel instance's config)
11277
- * @param {string} [options.cookie_domain] Custom cookie domain (overrides value specified in this Mixpanel instance's config)
11278
- * @param {boolean} [options.cross_site_cookie] Whether the opt-in cookie is set as cross-site-enabled (overrides value specified in this Mixpanel instance's config)
11279
- * @param {boolean} [options.cross_subdomain_cookie] Whether the opt-in cookie is set as cross-subdomain or not (overrides value specified in this Mixpanel instance's config)
11280
- * @param {boolean} [options.secure_cookie] Whether the opt-in cookie is set as secure or not (overrides value specified in this Mixpanel instance's config)
11037
+ * If your project does not have
11038
+ * <a href="https://help.mixpanel.com/hc/en-us/articles/360039133851">ID Merge</a>
11039
+ * enabled, the best practice is to call alias once when a unique
11040
+ * ID is first created for a user (e.g., when a user first registers
11041
+ * for an account). Do not use alias multiple times for a single
11042
+ * user without ID Merge enabled.
11043
+ *
11044
+ * @param {String} alias A unique identifier that you want to use for this user in the future.
11045
+ * @param {String} [original] The current identifier being used for this user.
11281
11046
  */
11282
- MixpanelLib.prototype.opt_out_tracking = function(options) {
11283
- options = _.extend({
11284
- 'clear_persistence': true,
11285
- 'delete_user': true
11286
- }, options);
11287
-
11288
- // delete user and clear charges since these methods may be disabled by opt-out
11289
- if (options['delete_user'] && this['people'] && this['people']._identify_called()) {
11290
- this['people'].delete_user();
11291
- this['people'].clear_charges();
11047
+ MixpanelLib.prototype.alias = function(alias, original) {
11048
+ // If the $people_distinct_id key exists in persistence, there has been a previous
11049
+ // mixpanel.people.identify() call made for this user. It is VERY BAD to make an alias with
11050
+ // this ID, as it will duplicate users.
11051
+ if (alias === this.get_property(PEOPLE_DISTINCT_ID_KEY)) {
11052
+ this.report_error('Attempting to create alias for existing People user - aborting.');
11053
+ return -2;
11292
11054
  }
11293
11055
 
11294
- this._gdpr_call_func(optOut, options);
11295
- this._gdpr_update_persistence(options);
11056
+ var _this = this;
11057
+ if (_.isUndefined(original)) {
11058
+ original = this.get_distinct_id();
11059
+ }
11060
+ if (alias !== original) {
11061
+ this._register_single(ALIAS_ID_KEY, alias);
11062
+ return this.track('$create_alias', {
11063
+ 'alias': alias,
11064
+ 'distinct_id': original
11065
+ }, {
11066
+ skip_hooks: true
11067
+ }, function() {
11068
+ // Flush the people queue
11069
+ _this.identify(alias);
11070
+ });
11071
+ } else {
11072
+ this.report_error('alias matches current distinct_id - skipping api call.');
11073
+ this.identify(alias);
11074
+ return -1;
11075
+ }
11296
11076
  };
11297
11077
 
11298
11078
  /**
11299
- * Check whether the user has opted in to data tracking and cookies/localstorage for this Mixpanel instance
11300
- *
11301
- * ### Usage
11079
+ * Provide a string to recognize the user by. The string passed to
11080
+ * this method will appear in the Mixpanel Streams product rather
11081
+ * than an automatically generated name. Name tags do not have to
11082
+ * be unique.
11302
11083
  *
11303
- * var has_opted_in = mixpanel.has_opted_in_tracking();
11304
- * // use has_opted_in value
11084
+ * This value will only be included in Streams data.
11305
11085
  *
11306
- * @param {Object} [options] A dictionary of config options to override
11307
- * @param {string} [options.persistence_type=localStorage] Persistence mechanism used - cookie or localStorage - falls back to cookie if localStorage is unavailable
11308
- * @param {string} [options.cookie_prefix=__mp_opt_in_out] Custom prefix to be used in the cookie/localstorage name
11309
- * @returns {boolean} current opt-in status
11086
+ * @param {String} name_tag A human readable name for the user
11087
+ * @deprecated
11310
11088
  */
11311
- MixpanelLib.prototype.has_opted_in_tracking = function(options) {
11312
- return this._gdpr_call_func(hasOptedIn, options);
11089
+ MixpanelLib.prototype.name_tag = function(name_tag) {
11090
+ this._register_single('mp_name_tag', name_tag);
11313
11091
  };
11314
11092
 
11315
11093
  /**
11316
- * Check whether the user has opted out of data tracking and cookies/localstorage for this Mixpanel instance
11094
+ * Update the configuration of a mixpanel library instance.
11317
11095
  *
11318
- * ### Usage
11096
+ * The default config is:
11319
11097
  *
11320
- * var has_opted_out = mixpanel.has_opted_out_tracking();
11321
- * // use has_opted_out value
11098
+ * {
11099
+ * // HTTP method for tracking requests
11100
+ * api_method: 'POST'
11322
11101
  *
11323
- * @param {Object} [options] A dictionary of config options to override
11324
- * @param {string} [options.persistence_type=localStorage] Persistence mechanism used - cookie or localStorage - falls back to cookie if localStorage is unavailable
11325
- * @param {string} [options.cookie_prefix=__mp_opt_in_out] Custom prefix to be used in the cookie/localstorage name
11326
- * @returns {boolean} current opt-out status
11327
- */
11328
- MixpanelLib.prototype.has_opted_out_tracking = function(options) {
11329
- return this._gdpr_call_func(hasOptedOut, options);
11330
- };
11331
-
11332
- /**
11333
- * Clear the user's opt in/out status of data tracking and cookies/localstorage for this Mixpanel instance
11102
+ * // transport for sending requests ('XHR' or 'sendBeacon')
11103
+ * // NB: sendBeacon should only be used for scenarios such as
11104
+ * // page unload where a "best-effort" attempt to send is
11105
+ * // acceptable; the sendBeacon API does not support callbacks
11106
+ * // or any way to know the result of the request. Mixpanel
11107
+ * // tracking via sendBeacon will not support any event-
11108
+ * // batching or retry mechanisms.
11109
+ * api_transport: 'XHR'
11334
11110
  *
11335
- * ### Usage
11111
+ * // turn on request-batching/queueing/retry
11112
+ * batch_requests: false,
11336
11113
  *
11337
- * // clear user's opt-in/out status
11338
- * mixpanel.clear_opt_in_out_tracking();
11114
+ * // maximum number of events/updates to send in a single
11115
+ * // network request
11116
+ * batch_size: 50,
11339
11117
  *
11340
- * // clear user's opt-in/out status with specific cookie configuration - should match
11341
- * // configuration used when opt_in_tracking/opt_out_tracking methods were called.
11342
- * mixpanel.clear_opt_in_out_tracking({
11343
- * cookie_expiration: 30,
11344
- * secure_cookie: true
11345
- * });
11118
+ * // milliseconds to wait between sending batch requests
11119
+ * batch_flush_interval_ms: 5000,
11346
11120
  *
11347
- * @param {Object} [options] A dictionary of config options to override
11348
- * @param {boolean} [options.enable_persistence=true] If true, will re-enable sdk persistence
11349
- * @param {string} [options.persistence_type=localStorage] Persistence mechanism used - cookie or localStorage - falls back to cookie if localStorage is unavailable
11350
- * @param {string} [options.cookie_prefix=__mp_opt_in_out] Custom prefix to be used in the cookie/localstorage name
11351
- * @param {Number} [options.cookie_expiration] Number of days until the opt-in cookie expires (overrides value specified in this Mixpanel instance's config)
11352
- * @param {string} [options.cookie_domain] Custom cookie domain (overrides value specified in this Mixpanel instance's config)
11353
- * @param {boolean} [options.cross_site_cookie] Whether the opt-in cookie is set as cross-site-enabled (overrides value specified in this Mixpanel instance's config)
11354
- * @param {boolean} [options.cross_subdomain_cookie] Whether the opt-in cookie is set as cross-subdomain or not (overrides value specified in this Mixpanel instance's config)
11355
- * @param {boolean} [options.secure_cookie] Whether the opt-in cookie is set as secure or not (overrides value specified in this Mixpanel instance's config)
11356
- */
11357
- MixpanelLib.prototype.clear_opt_in_out_tracking = function(options) {
11358
- options = _.extend({
11359
- 'enable_persistence': true
11360
- }, options);
11361
-
11362
- this._gdpr_call_func(clearOptInOut, options);
11363
- this._gdpr_update_persistence(options);
11364
- };
11365
-
11366
- MixpanelLib.prototype.report_error = function(msg, err) {
11367
- console$1.error.apply(console$1.error, arguments);
11368
- try {
11369
- if (!err && !(msg instanceof Error)) {
11370
- msg = new Error(msg);
11371
- }
11372
- this.get_config('error_reporter')(msg, err);
11373
- } catch(err) {
11374
- console$1.error(err);
11375
- }
11376
- };
11377
-
11378
- // EXPORTS (for closure compiler)
11379
-
11380
- // MixpanelLib Exports
11381
- MixpanelLib.prototype['init'] = MixpanelLib.prototype.init;
11382
- MixpanelLib.prototype['reset'] = MixpanelLib.prototype.reset;
11383
- MixpanelLib.prototype['disable'] = MixpanelLib.prototype.disable;
11384
- MixpanelLib.prototype['time_event'] = MixpanelLib.prototype.time_event;
11385
- MixpanelLib.prototype['track'] = MixpanelLib.prototype.track;
11386
- MixpanelLib.prototype['track_links'] = MixpanelLib.prototype.track_links;
11387
- MixpanelLib.prototype['track_forms'] = MixpanelLib.prototype.track_forms;
11388
- MixpanelLib.prototype['track_pageview'] = MixpanelLib.prototype.track_pageview;
11389
- MixpanelLib.prototype['register'] = MixpanelLib.prototype.register;
11390
- MixpanelLib.prototype['register_once'] = MixpanelLib.prototype.register_once;
11391
- MixpanelLib.prototype['unregister'] = MixpanelLib.prototype.unregister;
11392
- MixpanelLib.prototype['identify'] = MixpanelLib.prototype.identify;
11393
- MixpanelLib.prototype['alias'] = MixpanelLib.prototype.alias;
11394
- MixpanelLib.prototype['name_tag'] = MixpanelLib.prototype.name_tag;
11395
- MixpanelLib.prototype['set_config'] = MixpanelLib.prototype.set_config;
11396
- MixpanelLib.prototype['get_config'] = MixpanelLib.prototype.get_config;
11397
- MixpanelLib.prototype['get_property'] = MixpanelLib.prototype.get_property;
11398
- MixpanelLib.prototype['get_distinct_id'] = MixpanelLib.prototype.get_distinct_id;
11399
- MixpanelLib.prototype['toString'] = MixpanelLib.prototype.toString;
11400
- MixpanelLib.prototype['opt_out_tracking'] = MixpanelLib.prototype.opt_out_tracking;
11401
- MixpanelLib.prototype['opt_in_tracking'] = MixpanelLib.prototype.opt_in_tracking;
11402
- MixpanelLib.prototype['has_opted_out_tracking'] = MixpanelLib.prototype.has_opted_out_tracking;
11403
- MixpanelLib.prototype['has_opted_in_tracking'] = MixpanelLib.prototype.has_opted_in_tracking;
11404
- MixpanelLib.prototype['clear_opt_in_out_tracking'] = MixpanelLib.prototype.clear_opt_in_out_tracking;
11405
- MixpanelLib.prototype['get_group'] = MixpanelLib.prototype.get_group;
11406
- MixpanelLib.prototype['set_group'] = MixpanelLib.prototype.set_group;
11407
- MixpanelLib.prototype['add_group'] = MixpanelLib.prototype.add_group;
11408
- MixpanelLib.prototype['remove_group'] = MixpanelLib.prototype.remove_group;
11409
- MixpanelLib.prototype['track_with_groups'] = MixpanelLib.prototype.track_with_groups;
11410
- MixpanelLib.prototype['start_batch_senders'] = MixpanelLib.prototype.start_batch_senders;
11411
- MixpanelLib.prototype['stop_batch_senders'] = MixpanelLib.prototype.stop_batch_senders;
11412
-
11413
- // MixpanelPersistence Exports
11414
- MixpanelPersistence.prototype['properties'] = MixpanelPersistence.prototype.properties;
11415
- MixpanelPersistence.prototype['update_search_keyword'] = MixpanelPersistence.prototype.update_search_keyword;
11416
- MixpanelPersistence.prototype['update_referrer_info'] = MixpanelPersistence.prototype.update_referrer_info;
11417
- MixpanelPersistence.prototype['get_cross_subdomain'] = MixpanelPersistence.prototype.get_cross_subdomain;
11418
- MixpanelPersistence.prototype['clear'] = MixpanelPersistence.prototype.clear;
11419
-
11420
-
11421
- var instances = {};
11422
- var extend_mp = function() {
11423
- // add all the sub mixpanel instances
11424
- _.each(instances, function(instance, name) {
11425
- if (name !== PRIMARY_INSTANCE_NAME) { mixpanel_master[name] = instance; }
11426
- });
11427
-
11428
- // add private functions as _
11429
- mixpanel_master['_'] = _;
11430
- };
11431
-
11432
- var override_mp_init_func = function() {
11433
- // we override the snippets init function to handle the case where a
11434
- // user initializes the mixpanel library after the script loads & runs
11435
- mixpanel_master['init'] = function(token, config, name) {
11436
- if (name) {
11437
- // initialize a sub library
11438
- if (!mixpanel_master[name]) {
11439
- mixpanel_master[name] = instances[name] = create_mplib(token, config, name);
11440
- mixpanel_master[name]._loaded();
11441
- }
11442
- return mixpanel_master[name];
11443
- } else {
11444
- var instance = mixpanel_master;
11445
-
11446
- if (instances[PRIMARY_INSTANCE_NAME]) {
11447
- // main mixpanel lib already initialized
11448
- instance = instances[PRIMARY_INSTANCE_NAME];
11449
- } else if (token) {
11450
- // intialize the main mixpanel lib
11451
- instance = create_mplib(token, config, PRIMARY_INSTANCE_NAME);
11452
- instance._loaded();
11453
- instances[PRIMARY_INSTANCE_NAME] = instance;
11454
- }
11455
-
11456
- mixpanel_master = instance;
11457
- if (init_type === INIT_SNIPPET) {
11458
- window$1[PRIMARY_INSTANCE_NAME] = mixpanel_master;
11459
- }
11460
- extend_mp();
11461
- }
11462
- };
11463
- };
11464
-
11465
- var add_dom_loaded_handler = function() {
11466
- // Cross browser DOM Loaded support
11467
- function dom_loaded_handler() {
11468
- // function flag since we only want to execute this once
11469
- if (dom_loaded_handler.done) { return; }
11470
- dom_loaded_handler.done = true;
11471
-
11472
- DOM_LOADED = true;
11473
- ENQUEUE_REQUESTS = false;
11474
-
11475
- _.each(instances, function(inst) {
11476
- inst._dom_loaded();
11477
- });
11478
- }
11121
+ * // milliseconds to wait for network responses to batch requests
11122
+ * // before they are considered timed-out and retried
11123
+ * batch_request_timeout_ms: 90000,
11124
+ *
11125
+ * // override value for cookie domain, only useful for ensuring
11126
+ * // correct cross-subdomain cookies on unusual domains like
11127
+ * // subdomain.mainsite.avocat.fr; NB this cannot be used to
11128
+ * // set cookies on a different domain than the current origin
11129
+ * cookie_domain: ''
11130
+ *
11131
+ * // super properties cookie expiration (in days)
11132
+ * cookie_expiration: 365
11133
+ *
11134
+ * // if true, cookie will be set with SameSite=None; Secure
11135
+ * // this is only useful in special situations, like embedded
11136
+ * // 3rd-party iframes that set up a Mixpanel instance
11137
+ * cross_site_cookie: false
11138
+ *
11139
+ * // super properties span subdomains
11140
+ * cross_subdomain_cookie: true
11141
+ *
11142
+ * // debug mode
11143
+ * debug: false
11144
+ *
11145
+ * // if this is true, the mixpanel cookie or localStorage entry
11146
+ * // will be deleted, and no user persistence will take place
11147
+ * disable_persistence: false
11148
+ *
11149
+ * // if this is true, Mixpanel will automatically determine
11150
+ * // City, Region and Country data using the IP address of
11151
+ * //the client
11152
+ * ip: true
11153
+ *
11154
+ * // opt users out of tracking by this Mixpanel instance by default
11155
+ * opt_out_tracking_by_default: false
11156
+ *
11157
+ * // opt users out of browser data storage by this Mixpanel instance by default
11158
+ * opt_out_persistence_by_default: false
11159
+ *
11160
+ * // persistence mechanism used by opt-in/opt-out methods - cookie
11161
+ * // or localStorage - falls back to cookie if localStorage is unavailable
11162
+ * opt_out_tracking_persistence_type: 'localStorage'
11163
+ *
11164
+ * // customize the name of cookie/localStorage set by opt-in/opt-out methods
11165
+ * opt_out_tracking_cookie_prefix: null
11166
+ *
11167
+ * // type of persistent store for super properties (cookie/
11168
+ * // localStorage) if set to 'localStorage', any existing
11169
+ * // mixpanel cookie value with the same persistence_name
11170
+ * // will be transferred to localStorage and deleted
11171
+ * persistence: 'cookie'
11172
+ *
11173
+ * // name for super properties persistent store
11174
+ * persistence_name: ''
11175
+ *
11176
+ * // names of properties/superproperties which should never
11177
+ * // be sent with track() calls
11178
+ * property_blacklist: []
11179
+ *
11180
+ * // if this is true, mixpanel cookies will be marked as
11181
+ * // secure, meaning they will only be transmitted over https
11182
+ * secure_cookie: false
11183
+ *
11184
+ * // the amount of time track_links will
11185
+ * // wait for Mixpanel's servers to respond
11186
+ * track_links_timeout: 300
11187
+ *
11188
+ * // if you set upgrade to be true, the library will check for
11189
+ * // a cookie from our old js library and import super
11190
+ * // properties from it, then the old cookie is deleted
11191
+ * // The upgrade config option only works in the initialization,
11192
+ * // so make sure you set it when you create the library.
11193
+ * upgrade: false
11194
+ *
11195
+ * // extra HTTP request headers to set for each API request, in
11196
+ * // the format {'Header-Name': value}
11197
+ * xhr_headers: {}
11198
+ *
11199
+ * // whether to ignore or respect the web browser's Do Not Track setting
11200
+ * ignore_dnt: false
11201
+ * }
11202
+ *
11203
+ *
11204
+ * @param {Object} config A dictionary of new configuration values to update
11205
+ */
11206
+ MixpanelLib.prototype.set_config = function(config) {
11207
+ if (_.isObject(config)) {
11208
+ _.extend(this['config'], config);
11479
11209
 
11480
- function do_scroll_check() {
11481
- try {
11482
- document$1.documentElement.doScroll('left');
11483
- } catch(e) {
11484
- setTimeout(do_scroll_check, 1);
11485
- return;
11210
+ var new_batch_size = config['batch_size'];
11211
+ if (new_batch_size) {
11212
+ _.each(this.request_batchers, function(batcher) {
11213
+ batcher.resetBatchSize();
11214
+ });
11486
11215
  }
11487
11216
 
11488
- dom_loaded_handler();
11489
- }
11490
-
11491
- if (document$1.addEventListener) {
11492
- if (document$1.readyState === 'complete') {
11493
- // safari 4 can fire the DOMContentLoaded event before loading all
11494
- // external JS (including this file). you will see some copypasta
11495
- // on the internet that checks for 'complete' and 'loaded', but
11496
- // 'loaded' is an IE thing
11497
- dom_loaded_handler();
11498
- } else {
11499
- document$1.addEventListener('DOMContentLoaded', dom_loaded_handler, false);
11217
+ if (!this.get_config('persistence_name')) {
11218
+ this['config']['persistence_name'] = this['config']['cookie_name'];
11500
11219
  }
11501
- } else if (document$1.attachEvent) {
11502
- // IE
11503
- document$1.attachEvent('onreadystatechange', dom_loaded_handler);
11504
-
11505
- // check to make sure we arn't in a frame
11506
- var toplevel = false;
11507
- try {
11508
- toplevel = window$1.frameElement === null;
11509
- } catch(e) {
11510
- // noop
11220
+ if (!this.get_config('disable_persistence')) {
11221
+ this['config']['disable_persistence'] = this['config']['disable_cookie'];
11511
11222
  }
11512
11223
 
11513
- if (document$1.documentElement.doScroll && toplevel) {
11514
- do_scroll_check();
11224
+ if (this['persistence']) {
11225
+ this['persistence'].update_config(this['config']);
11515
11226
  }
11227
+ Config.DEBUG = Config.DEBUG || this.get_config('debug');
11516
11228
  }
11517
-
11518
- // fallback handler, always will work
11519
- _.register_event(window$1, 'load', dom_loaded_handler, true);
11520
11229
  };
11521
11230
 
11522
- function init_as_module() {
11523
- init_type = INIT_MODULE;
11524
- mixpanel_master = new MixpanelLib();
11525
-
11526
- override_mp_init_func();
11527
- mixpanel_master['init']();
11528
- add_dom_loaded_handler();
11529
-
11530
- return mixpanel_master;
11531
- }
11532
-
11533
- var mixpanel = init_as_module();
11534
-
11535
- var mixpanel_cjs = mixpanel;
11536
-
11537
- var mixpanel$1 = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.assign(/*#__PURE__*/Object.create(null), mixpanel_cjs, {
11538
- 'default': mixpanel_cjs
11539
- }));
11540
-
11541
- // Needed to avoid error in CJS builds on some bundlers.
11542
- const mixpanelLib = mixpanel_cjs || mixpanel$1;
11543
- let mixpanelInstance;
11544
- const MIXPANEL_EVENT = {
11545
- VISUAL_SDK_RENDER_START: 'visual-sdk-render-start',
11546
- VISUAL_SDK_CALLED_INIT: 'visual-sdk-called-init',
11547
- VISUAL_SDK_RENDER_COMPLETE: 'visual-sdk-render-complete',
11548
- VISUAL_SDK_RENDER_FAILED: 'visual-sdk-render-failed',
11549
- VISUAL_SDK_TRIGGER: 'visual-sdk-trigger',
11550
- VISUAL_SDK_ON: 'visual-sdk-on',
11551
- VISUAL_SDK_IFRAME_LOAD_PERFORMANCE: 'visual-sdk-iframe-load-performance',
11552
- VISUAL_SDK_EMBED_CREATE: 'visual-sdk-embed-create',
11553
- };
11554
- let isMixpanelInitialized = false;
11555
- let eventQueue = [];
11556
- /**
11557
- * Pushes the event with its Property key-value map to mixpanel.
11558
- *
11559
- * @param eventId
11560
- * @param eventProps
11561
- */
11562
- function uploadMixpanelEvent(eventId, eventProps = {}) {
11563
- if (!isMixpanelInitialized) {
11564
- eventQueue.push({ eventId, eventProps });
11565
- return;
11566
- }
11567
- mixpanelInstance.track(eventId, eventProps);
11568
- }
11569
- /**
11570
- *
11571
- */
11572
- function emptyQueue() {
11573
- if (!isMixpanelInitialized) {
11574
- return;
11575
- }
11576
- eventQueue.forEach((event) => {
11577
- uploadMixpanelEvent(event.eventId, event.eventProps);
11578
- });
11579
- eventQueue = [];
11580
- }
11581
- /**
11582
- *
11583
- * @param sessionInfo
11584
- */
11585
- function initMixpanel(sessionInfo) {
11586
- var _a;
11587
- if (!sessionInfo || !sessionInfo.mixpanelToken) {
11588
- return;
11589
- }
11590
- // On a public cluster the user is anonymous, so don't set the identify to
11591
- // userGUID
11592
- const isPublicCluster = !!sessionInfo.isPublicUser;
11593
- const token = sessionInfo.mixpanelToken;
11594
- try {
11595
- if (token) {
11596
- mixpanelInstance = mixpanelLib.init(token, undefined, 'tsEmbed');
11597
- if (!isPublicCluster) {
11598
- mixpanelInstance.identify(sessionInfo.userGUID);
11599
- }
11600
- mixpanelInstance.register_once({
11601
- clusterId: sessionInfo.clusterId,
11602
- clusterName: sessionInfo.clusterName,
11603
- releaseVersion: sessionInfo.releaseVersion,
11604
- hostAppUrl: ((_a = window === null || window === void 0 ? void 0 : window.location) === null || _a === void 0 ? void 0 : _a.host) || '',
11605
- });
11606
- isMixpanelInitialized = true;
11607
- emptyQueue();
11608
- }
11609
- }
11610
- catch (e) {
11611
- console.error('Error initializing mixpanel', e);
11612
- }
11613
- }
11614
-
11615
- var eventemitter3 = createCommonjsModule(function (module) {
11616
-
11617
- var has = Object.prototype.hasOwnProperty
11618
- , prefix = '~';
11619
-
11620
11231
  /**
11621
- * Constructor to create a storage for our `EE` objects.
11622
- * An `Events` instance is a plain object whose properties are event names.
11623
- *
11624
- * @constructor
11625
- * @private
11232
+ * returns the current config object for the library.
11626
11233
  */
11627
- function Events() {}
11628
-
11629
- //
11630
- // We try to not inherit from `Object.prototype`. In some engines creating an
11631
- // instance in this way is faster than calling `Object.create(null)` directly.
11632
- // If `Object.create(null)` is not supported we prefix the event names with a
11633
- // character to make sure that the built-in object properties are not
11634
- // overridden or used as an attack vector.
11635
- //
11636
- if (Object.create) {
11637
- Events.prototype = Object.create(null);
11638
-
11639
- //
11640
- // This hack is needed because the `__proto__` property is still inherited in
11641
- // some old browsers like Android 4, iPhone 5.1, Opera 11 and Safari 5.
11642
- //
11643
- if (!new Events().__proto__) prefix = false;
11644
- }
11234
+ MixpanelLib.prototype.get_config = function(prop_name) {
11235
+ return this['config'][prop_name];
11236
+ };
11645
11237
 
11646
11238
  /**
11647
- * Representation of a single event listener.
11648
- *
11649
- * @param {Function} fn The listener function.
11650
- * @param {*} context The context to invoke the listener with.
11651
- * @param {Boolean} [once=false] Specify if the listener is a one-time listener.
11652
- * @constructor
11653
- * @private
11239
+ * Fetch a hook function from config, with safe default, and run it
11240
+ * against the given arguments
11241
+ * @param {string} hook_name which hook to retrieve
11242
+ * @returns {any|null} return value of user-provided hook, or null if nothing was returned
11654
11243
  */
11655
- function EE(fn, context, once) {
11656
- this.fn = fn;
11657
- this.context = context;
11658
- this.once = once || false;
11659
- }
11244
+ MixpanelLib.prototype._run_hook = function(hook_name) {
11245
+ var ret = (this['config']['hooks'][hook_name] || IDENTITY_FUNC).apply(this, slice.call(arguments, 1));
11246
+ if (typeof ret === 'undefined') {
11247
+ this.report_error(hook_name + ' hook did not return a value');
11248
+ ret = null;
11249
+ }
11250
+ return ret;
11251
+ };
11660
11252
 
11661
11253
  /**
11662
- * Add a listener for a given event.
11254
+ * Returns the value of the super property named property_name. If no such
11255
+ * property is set, get_property() will return the undefined value.
11663
11256
  *
11664
- * @param {EventEmitter} emitter Reference to the `EventEmitter` instance.
11665
- * @param {(String|Symbol)} event The event name.
11666
- * @param {Function} fn The listener function.
11667
- * @param {*} context The context to invoke the listener with.
11668
- * @param {Boolean} once Specify if the listener is a one-time listener.
11669
- * @returns {EventEmitter}
11670
- * @private
11257
+ * ### Notes:
11258
+ *
11259
+ * get_property() can only be called after the Mixpanel library has finished loading.
11260
+ * init() has a loaded function available to handle this automatically. For example:
11261
+ *
11262
+ * // grab value for 'user_id' after the mixpanel library has loaded
11263
+ * mixpanel.init('YOUR PROJECT TOKEN', {
11264
+ * loaded: function(mixpanel) {
11265
+ * user_id = mixpanel.get_property('user_id');
11266
+ * }
11267
+ * });
11268
+ *
11269
+ * @param {String} property_name The name of the super property you want to retrieve
11671
11270
  */
11672
- function addListener(emitter, event, fn, context, once) {
11673
- if (typeof fn !== 'function') {
11674
- throw new TypeError('The listener must be a function');
11675
- }
11271
+ MixpanelLib.prototype.get_property = function(property_name) {
11272
+ return this['persistence']['props'][property_name];
11273
+ };
11676
11274
 
11677
- var listener = new EE(fn, context || emitter, once)
11678
- , evt = prefix ? prefix + event : event;
11275
+ MixpanelLib.prototype.toString = function() {
11276
+ var name = this.get_config('name');
11277
+ if (name !== PRIMARY_INSTANCE_NAME) {
11278
+ name = PRIMARY_INSTANCE_NAME + '.' + name;
11279
+ }
11280
+ return name;
11281
+ };
11679
11282
 
11680
- if (!emitter._events[evt]) emitter._events[evt] = listener, emitter._eventsCount++;
11681
- else if (!emitter._events[evt].fn) emitter._events[evt].push(listener);
11682
- else emitter._events[evt] = [emitter._events[evt], listener];
11283
+ MixpanelLib.prototype._event_is_disabled = function(event_name) {
11284
+ return _.isBlockedUA(userAgent) ||
11285
+ this._flags.disable_all_events ||
11286
+ _.include(this.__disabled_events, event_name);
11287
+ };
11683
11288
 
11684
- return emitter;
11685
- }
11289
+ // perform some housekeeping around GDPR opt-in/out state
11290
+ MixpanelLib.prototype._gdpr_init = function() {
11291
+ var is_localStorage_requested = this.get_config('opt_out_tracking_persistence_type') === 'localStorage';
11686
11292
 
11687
- /**
11688
- * Clear event by name.
11689
- *
11690
- * @param {EventEmitter} emitter Reference to the `EventEmitter` instance.
11691
- * @param {(String|Symbol)} evt The Event name.
11692
- * @private
11693
- */
11694
- function clearEvent(emitter, evt) {
11695
- if (--emitter._eventsCount === 0) emitter._events = new Events();
11696
- else delete emitter._events[evt];
11697
- }
11293
+ // try to convert opt-in/out cookies to localStorage if possible
11294
+ if (is_localStorage_requested && _.localStorage.is_supported()) {
11295
+ if (!this.has_opted_in_tracking() && this.has_opted_in_tracking({'persistence_type': 'cookie'})) {
11296
+ this.opt_in_tracking({'enable_persistence': false});
11297
+ }
11298
+ if (!this.has_opted_out_tracking() && this.has_opted_out_tracking({'persistence_type': 'cookie'})) {
11299
+ this.opt_out_tracking({'clear_persistence': false});
11300
+ }
11301
+ this.clear_opt_in_out_tracking({
11302
+ 'persistence_type': 'cookie',
11303
+ 'enable_persistence': false
11304
+ });
11305
+ }
11698
11306
 
11699
- /**
11700
- * Minimal `EventEmitter` interface that is molded against the Node.js
11701
- * `EventEmitter` interface.
11702
- *
11703
- * @constructor
11704
- * @public
11705
- */
11706
- function EventEmitter() {
11707
- this._events = new Events();
11708
- this._eventsCount = 0;
11709
- }
11307
+ // check whether the user has already opted out - if so, clear & disable persistence
11308
+ if (this.has_opted_out_tracking()) {
11309
+ this._gdpr_update_persistence({'clear_persistence': true});
11310
+
11311
+ // check whether we should opt out by default
11312
+ // note: we don't clear persistence here by default since opt-out default state is often
11313
+ // used as an initial state while GDPR information is being collected
11314
+ } else if (!this.has_opted_in_tracking() && (
11315
+ this.get_config('opt_out_tracking_by_default') || _.cookie.get('mp_optout')
11316
+ )) {
11317
+ _.cookie.remove('mp_optout');
11318
+ this.opt_out_tracking({
11319
+ 'clear_persistence': this.get_config('opt_out_persistence_by_default')
11320
+ });
11321
+ }
11322
+ };
11710
11323
 
11711
11324
  /**
11712
- * Return an array listing the events for which the emitter has registered
11713
- * listeners.
11714
- *
11715
- * @returns {Array}
11716
- * @public
11325
+ * Enable or disable persistence based on options
11326
+ * only enable/disable if persistence is not already in this state
11327
+ * @param {boolean} [options.clear_persistence] If true, will delete all data stored by the sdk in persistence and disable it
11328
+ * @param {boolean} [options.enable_persistence] If true, will re-enable sdk persistence
11717
11329
  */
11718
- EventEmitter.prototype.eventNames = function eventNames() {
11719
- var names = []
11720
- , events
11721
- , name;
11330
+ MixpanelLib.prototype._gdpr_update_persistence = function(options) {
11331
+ var disabled;
11332
+ if (options && options['clear_persistence']) {
11333
+ disabled = true;
11334
+ } else if (options && options['enable_persistence']) {
11335
+ disabled = false;
11336
+ } else {
11337
+ return;
11338
+ }
11722
11339
 
11723
- if (this._eventsCount === 0) return names;
11340
+ if (!this.get_config('disable_persistence') && this['persistence'].disabled !== disabled) {
11341
+ this['persistence'].set_disabled(disabled);
11342
+ }
11724
11343
 
11725
- for (name in (events = this._events)) {
11726
- if (has.call(events, name)) names.push(prefix ? name.slice(1) : name);
11727
- }
11344
+ if (disabled) {
11345
+ _.each(this.request_batchers, function(batcher) {
11346
+ batcher.clear();
11347
+ });
11348
+ }
11349
+ };
11728
11350
 
11729
- if (Object.getOwnPropertySymbols) {
11730
- return names.concat(Object.getOwnPropertySymbols(events));
11731
- }
11351
+ // call a base gdpr function after constructing the appropriate token and options args
11352
+ MixpanelLib.prototype._gdpr_call_func = function(func, options) {
11353
+ options = _.extend({
11354
+ 'track': _.bind(this.track, this),
11355
+ 'persistence_type': this.get_config('opt_out_tracking_persistence_type'),
11356
+ 'cookie_prefix': this.get_config('opt_out_tracking_cookie_prefix'),
11357
+ 'cookie_expiration': this.get_config('cookie_expiration'),
11358
+ 'cross_site_cookie': this.get_config('cross_site_cookie'),
11359
+ 'cross_subdomain_cookie': this.get_config('cross_subdomain_cookie'),
11360
+ 'cookie_domain': this.get_config('cookie_domain'),
11361
+ 'secure_cookie': this.get_config('secure_cookie'),
11362
+ 'ignore_dnt': this.get_config('ignore_dnt')
11363
+ }, options);
11732
11364
 
11733
- return names;
11365
+ // check if localStorage can be used for recording opt out status, fall back to cookie if not
11366
+ if (!_.localStorage.is_supported()) {
11367
+ options['persistence_type'] = 'cookie';
11368
+ }
11369
+
11370
+ return func(this.get_config('token'), {
11371
+ track: options['track'],
11372
+ trackEventName: options['track_event_name'],
11373
+ trackProperties: options['track_properties'],
11374
+ persistenceType: options['persistence_type'],
11375
+ persistencePrefix: options['cookie_prefix'],
11376
+ cookieDomain: options['cookie_domain'],
11377
+ cookieExpiration: options['cookie_expiration'],
11378
+ crossSiteCookie: options['cross_site_cookie'],
11379
+ crossSubdomainCookie: options['cross_subdomain_cookie'],
11380
+ secureCookie: options['secure_cookie'],
11381
+ ignoreDnt: options['ignore_dnt']
11382
+ });
11734
11383
  };
11735
11384
 
11736
11385
  /**
11737
- * Return the listeners registered for a given event.
11386
+ * Opt the user in to data tracking and cookies/localstorage for this Mixpanel instance
11738
11387
  *
11739
- * @param {(String|Symbol)} event The event name.
11740
- * @returns {Array} The registered listeners.
11741
- * @public
11388
+ * ### Usage
11389
+ *
11390
+ * // opt user in
11391
+ * mixpanel.opt_in_tracking();
11392
+ *
11393
+ * // opt user in with specific event name, properties, cookie configuration
11394
+ * mixpanel.opt_in_tracking({
11395
+ * track_event_name: 'User opted in',
11396
+ * track_event_properties: {
11397
+ * 'Email': 'jdoe@example.com'
11398
+ * },
11399
+ * cookie_expiration: 30,
11400
+ * secure_cookie: true
11401
+ * });
11402
+ *
11403
+ * @param {Object} [options] A dictionary of config options to override
11404
+ * @param {function} [options.track] Function used for tracking a Mixpanel event to record the opt-in action (default is this Mixpanel instance's track method)
11405
+ * @param {string} [options.track_event_name=$opt_in] Event name to be used for tracking the opt-in action
11406
+ * @param {Object} [options.track_properties] Set of properties to be tracked along with the opt-in action
11407
+ * @param {boolean} [options.enable_persistence=true] If true, will re-enable sdk persistence
11408
+ * @param {string} [options.persistence_type=localStorage] Persistence mechanism used - cookie or localStorage - falls back to cookie if localStorage is unavailable
11409
+ * @param {string} [options.cookie_prefix=__mp_opt_in_out] Custom prefix to be used in the cookie/localstorage name
11410
+ * @param {Number} [options.cookie_expiration] Number of days until the opt-in cookie expires (overrides value specified in this Mixpanel instance's config)
11411
+ * @param {string} [options.cookie_domain] Custom cookie domain (overrides value specified in this Mixpanel instance's config)
11412
+ * @param {boolean} [options.cross_site_cookie] Whether the opt-in cookie is set as cross-site-enabled (overrides value specified in this Mixpanel instance's config)
11413
+ * @param {boolean} [options.cross_subdomain_cookie] Whether the opt-in cookie is set as cross-subdomain or not (overrides value specified in this Mixpanel instance's config)
11414
+ * @param {boolean} [options.secure_cookie] Whether the opt-in cookie is set as secure or not (overrides value specified in this Mixpanel instance's config)
11742
11415
  */
11743
- EventEmitter.prototype.listeners = function listeners(event) {
11744
- var evt = prefix ? prefix + event : event
11745
- , handlers = this._events[evt];
11416
+ MixpanelLib.prototype.opt_in_tracking = function(options) {
11417
+ options = _.extend({
11418
+ 'enable_persistence': true
11419
+ }, options);
11746
11420
 
11747
- if (!handlers) return [];
11748
- if (handlers.fn) return [handlers.fn];
11421
+ this._gdpr_call_func(optIn, options);
11422
+ this._gdpr_update_persistence(options);
11423
+ };
11749
11424
 
11750
- for (var i = 0, l = handlers.length, ee = new Array(l); i < l; i++) {
11751
- ee[i] = handlers[i].fn;
11752
- }
11425
+ /**
11426
+ * Opt the user out of data tracking and cookies/localstorage for this Mixpanel instance
11427
+ *
11428
+ * ### Usage
11429
+ *
11430
+ * // opt user out
11431
+ * mixpanel.opt_out_tracking();
11432
+ *
11433
+ * // opt user out with different cookie configuration from Mixpanel instance
11434
+ * mixpanel.opt_out_tracking({
11435
+ * cookie_expiration: 30,
11436
+ * secure_cookie: true
11437
+ * });
11438
+ *
11439
+ * @param {Object} [options] A dictionary of config options to override
11440
+ * @param {boolean} [options.delete_user=true] If true, will delete the currently identified user's profile and clear all charges after opting the user out
11441
+ * @param {boolean} [options.clear_persistence=true] If true, will delete all data stored by the sdk in persistence
11442
+ * @param {string} [options.persistence_type=localStorage] Persistence mechanism used - cookie or localStorage - falls back to cookie if localStorage is unavailable
11443
+ * @param {string} [options.cookie_prefix=__mp_opt_in_out] Custom prefix to be used in the cookie/localstorage name
11444
+ * @param {Number} [options.cookie_expiration] Number of days until the opt-in cookie expires (overrides value specified in this Mixpanel instance's config)
11445
+ * @param {string} [options.cookie_domain] Custom cookie domain (overrides value specified in this Mixpanel instance's config)
11446
+ * @param {boolean} [options.cross_site_cookie] Whether the opt-in cookie is set as cross-site-enabled (overrides value specified in this Mixpanel instance's config)
11447
+ * @param {boolean} [options.cross_subdomain_cookie] Whether the opt-in cookie is set as cross-subdomain or not (overrides value specified in this Mixpanel instance's config)
11448
+ * @param {boolean} [options.secure_cookie] Whether the opt-in cookie is set as secure or not (overrides value specified in this Mixpanel instance's config)
11449
+ */
11450
+ MixpanelLib.prototype.opt_out_tracking = function(options) {
11451
+ options = _.extend({
11452
+ 'clear_persistence': true,
11453
+ 'delete_user': true
11454
+ }, options);
11455
+
11456
+ // delete user and clear charges since these methods may be disabled by opt-out
11457
+ if (options['delete_user'] && this['people'] && this['people']._identify_called()) {
11458
+ this['people'].delete_user();
11459
+ this['people'].clear_charges();
11460
+ }
11753
11461
 
11754
- return ee;
11462
+ this._gdpr_call_func(optOut, options);
11463
+ this._gdpr_update_persistence(options);
11755
11464
  };
11756
11465
 
11757
11466
  /**
11758
- * Return the number of listeners listening to a given event.
11467
+ * Check whether the user has opted in to data tracking and cookies/localstorage for this Mixpanel instance
11759
11468
  *
11760
- * @param {(String|Symbol)} event The event name.
11761
- * @returns {Number} The number of listeners.
11762
- * @public
11469
+ * ### Usage
11470
+ *
11471
+ * var has_opted_in = mixpanel.has_opted_in_tracking();
11472
+ * // use has_opted_in value
11473
+ *
11474
+ * @param {Object} [options] A dictionary of config options to override
11475
+ * @param {string} [options.persistence_type=localStorage] Persistence mechanism used - cookie or localStorage - falls back to cookie if localStorage is unavailable
11476
+ * @param {string} [options.cookie_prefix=__mp_opt_in_out] Custom prefix to be used in the cookie/localstorage name
11477
+ * @returns {boolean} current opt-in status
11763
11478
  */
11764
- EventEmitter.prototype.listenerCount = function listenerCount(event) {
11765
- var evt = prefix ? prefix + event : event
11766
- , listeners = this._events[evt];
11767
-
11768
- if (!listeners) return 0;
11769
- if (listeners.fn) return 1;
11770
- return listeners.length;
11479
+ MixpanelLib.prototype.has_opted_in_tracking = function(options) {
11480
+ return this._gdpr_call_func(hasOptedIn, options);
11771
11481
  };
11772
11482
 
11773
11483
  /**
11774
- * Calls each of the listeners registered for a given event.
11484
+ * Check whether the user has opted out of data tracking and cookies/localstorage for this Mixpanel instance
11775
11485
  *
11776
- * @param {(String|Symbol)} event The event name.
11777
- * @returns {Boolean} `true` if the event had listeners, else `false`.
11778
- * @public
11486
+ * ### Usage
11487
+ *
11488
+ * var has_opted_out = mixpanel.has_opted_out_tracking();
11489
+ * // use has_opted_out value
11490
+ *
11491
+ * @param {Object} [options] A dictionary of config options to override
11492
+ * @param {string} [options.persistence_type=localStorage] Persistence mechanism used - cookie or localStorage - falls back to cookie if localStorage is unavailable
11493
+ * @param {string} [options.cookie_prefix=__mp_opt_in_out] Custom prefix to be used in the cookie/localstorage name
11494
+ * @returns {boolean} current opt-out status
11779
11495
  */
11780
- EventEmitter.prototype.emit = function emit(event, a1, a2, a3, a4, a5) {
11781
- var evt = prefix ? prefix + event : event;
11782
-
11783
- if (!this._events[evt]) return false;
11496
+ MixpanelLib.prototype.has_opted_out_tracking = function(options) {
11497
+ return this._gdpr_call_func(hasOptedOut, options);
11498
+ };
11784
11499
 
11785
- var listeners = this._events[evt]
11786
- , len = arguments.length
11787
- , args
11788
- , i;
11500
+ /**
11501
+ * Clear the user's opt in/out status of data tracking and cookies/localstorage for this Mixpanel instance
11502
+ *
11503
+ * ### Usage
11504
+ *
11505
+ * // clear user's opt-in/out status
11506
+ * mixpanel.clear_opt_in_out_tracking();
11507
+ *
11508
+ * // clear user's opt-in/out status with specific cookie configuration - should match
11509
+ * // configuration used when opt_in_tracking/opt_out_tracking methods were called.
11510
+ * mixpanel.clear_opt_in_out_tracking({
11511
+ * cookie_expiration: 30,
11512
+ * secure_cookie: true
11513
+ * });
11514
+ *
11515
+ * @param {Object} [options] A dictionary of config options to override
11516
+ * @param {boolean} [options.enable_persistence=true] If true, will re-enable sdk persistence
11517
+ * @param {string} [options.persistence_type=localStorage] Persistence mechanism used - cookie or localStorage - falls back to cookie if localStorage is unavailable
11518
+ * @param {string} [options.cookie_prefix=__mp_opt_in_out] Custom prefix to be used in the cookie/localstorage name
11519
+ * @param {Number} [options.cookie_expiration] Number of days until the opt-in cookie expires (overrides value specified in this Mixpanel instance's config)
11520
+ * @param {string} [options.cookie_domain] Custom cookie domain (overrides value specified in this Mixpanel instance's config)
11521
+ * @param {boolean} [options.cross_site_cookie] Whether the opt-in cookie is set as cross-site-enabled (overrides value specified in this Mixpanel instance's config)
11522
+ * @param {boolean} [options.cross_subdomain_cookie] Whether the opt-in cookie is set as cross-subdomain or not (overrides value specified in this Mixpanel instance's config)
11523
+ * @param {boolean} [options.secure_cookie] Whether the opt-in cookie is set as secure or not (overrides value specified in this Mixpanel instance's config)
11524
+ */
11525
+ MixpanelLib.prototype.clear_opt_in_out_tracking = function(options) {
11526
+ options = _.extend({
11527
+ 'enable_persistence': true
11528
+ }, options);
11789
11529
 
11790
- if (listeners.fn) {
11791
- if (listeners.once) this.removeListener(event, listeners.fn, undefined, true);
11530
+ this._gdpr_call_func(clearOptInOut, options);
11531
+ this._gdpr_update_persistence(options);
11532
+ };
11792
11533
 
11793
- switch (len) {
11794
- case 1: return listeners.fn.call(listeners.context), true;
11795
- case 2: return listeners.fn.call(listeners.context, a1), true;
11796
- case 3: return listeners.fn.call(listeners.context, a1, a2), true;
11797
- case 4: return listeners.fn.call(listeners.context, a1, a2, a3), true;
11798
- case 5: return listeners.fn.call(listeners.context, a1, a2, a3, a4), true;
11799
- case 6: return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true;
11534
+ MixpanelLib.prototype.report_error = function(msg, err) {
11535
+ console$1.error.apply(console$1.error, arguments);
11536
+ try {
11537
+ if (!err && !(msg instanceof Error)) {
11538
+ msg = new Error(msg);
11539
+ }
11540
+ this.get_config('error_reporter')(msg, err);
11541
+ } catch(err) {
11542
+ console$1.error(err);
11800
11543
  }
11544
+ };
11801
11545
 
11802
- for (i = 1, args = new Array(len -1); i < len; i++) {
11803
- args[i - 1] = arguments[i];
11804
- }
11546
+ // EXPORTS (for closure compiler)
11805
11547
 
11806
- listeners.fn.apply(listeners.context, args);
11807
- } else {
11808
- var length = listeners.length
11809
- , j;
11548
+ // MixpanelLib Exports
11549
+ MixpanelLib.prototype['init'] = MixpanelLib.prototype.init;
11550
+ MixpanelLib.prototype['reset'] = MixpanelLib.prototype.reset;
11551
+ MixpanelLib.prototype['disable'] = MixpanelLib.prototype.disable;
11552
+ MixpanelLib.prototype['time_event'] = MixpanelLib.prototype.time_event;
11553
+ MixpanelLib.prototype['track'] = MixpanelLib.prototype.track;
11554
+ MixpanelLib.prototype['track_links'] = MixpanelLib.prototype.track_links;
11555
+ MixpanelLib.prototype['track_forms'] = MixpanelLib.prototype.track_forms;
11556
+ MixpanelLib.prototype['track_pageview'] = MixpanelLib.prototype.track_pageview;
11557
+ MixpanelLib.prototype['register'] = MixpanelLib.prototype.register;
11558
+ MixpanelLib.prototype['register_once'] = MixpanelLib.prototype.register_once;
11559
+ MixpanelLib.prototype['unregister'] = MixpanelLib.prototype.unregister;
11560
+ MixpanelLib.prototype['identify'] = MixpanelLib.prototype.identify;
11561
+ MixpanelLib.prototype['alias'] = MixpanelLib.prototype.alias;
11562
+ MixpanelLib.prototype['name_tag'] = MixpanelLib.prototype.name_tag;
11563
+ MixpanelLib.prototype['set_config'] = MixpanelLib.prototype.set_config;
11564
+ MixpanelLib.prototype['get_config'] = MixpanelLib.prototype.get_config;
11565
+ MixpanelLib.prototype['get_property'] = MixpanelLib.prototype.get_property;
11566
+ MixpanelLib.prototype['get_distinct_id'] = MixpanelLib.prototype.get_distinct_id;
11567
+ MixpanelLib.prototype['toString'] = MixpanelLib.prototype.toString;
11568
+ MixpanelLib.prototype['opt_out_tracking'] = MixpanelLib.prototype.opt_out_tracking;
11569
+ MixpanelLib.prototype['opt_in_tracking'] = MixpanelLib.prototype.opt_in_tracking;
11570
+ MixpanelLib.prototype['has_opted_out_tracking'] = MixpanelLib.prototype.has_opted_out_tracking;
11571
+ MixpanelLib.prototype['has_opted_in_tracking'] = MixpanelLib.prototype.has_opted_in_tracking;
11572
+ MixpanelLib.prototype['clear_opt_in_out_tracking'] = MixpanelLib.prototype.clear_opt_in_out_tracking;
11573
+ MixpanelLib.prototype['get_group'] = MixpanelLib.prototype.get_group;
11574
+ MixpanelLib.prototype['set_group'] = MixpanelLib.prototype.set_group;
11575
+ MixpanelLib.prototype['add_group'] = MixpanelLib.prototype.add_group;
11576
+ MixpanelLib.prototype['remove_group'] = MixpanelLib.prototype.remove_group;
11577
+ MixpanelLib.prototype['track_with_groups'] = MixpanelLib.prototype.track_with_groups;
11578
+ MixpanelLib.prototype['start_batch_senders'] = MixpanelLib.prototype.start_batch_senders;
11579
+ MixpanelLib.prototype['stop_batch_senders'] = MixpanelLib.prototype.stop_batch_senders;
11810
11580
 
11811
- for (i = 0; i < length; i++) {
11812
- if (listeners[i].once) this.removeListener(event, listeners[i].fn, undefined, true);
11581
+ // MixpanelPersistence Exports
11582
+ MixpanelPersistence.prototype['properties'] = MixpanelPersistence.prototype.properties;
11583
+ MixpanelPersistence.prototype['update_search_keyword'] = MixpanelPersistence.prototype.update_search_keyword;
11584
+ MixpanelPersistence.prototype['update_referrer_info'] = MixpanelPersistence.prototype.update_referrer_info;
11585
+ MixpanelPersistence.prototype['get_cross_subdomain'] = MixpanelPersistence.prototype.get_cross_subdomain;
11586
+ MixpanelPersistence.prototype['clear'] = MixpanelPersistence.prototype.clear;
11813
11587
 
11814
- switch (len) {
11815
- case 1: listeners[i].fn.call(listeners[i].context); break;
11816
- case 2: listeners[i].fn.call(listeners[i].context, a1); break;
11817
- case 3: listeners[i].fn.call(listeners[i].context, a1, a2); break;
11818
- case 4: listeners[i].fn.call(listeners[i].context, a1, a2, a3); break;
11819
- default:
11820
- if (!args) for (j = 1, args = new Array(len -1); j < len; j++) {
11821
- args[j - 1] = arguments[j];
11822
- }
11823
11588
 
11824
- listeners[i].fn.apply(listeners[i].context, args);
11825
- }
11826
- }
11827
- }
11589
+ var instances = {};
11590
+ var extend_mp = function() {
11591
+ // add all the sub mixpanel instances
11592
+ _.each(instances, function(instance, name) {
11593
+ if (name !== PRIMARY_INSTANCE_NAME) { mixpanel_master[name] = instance; }
11594
+ });
11828
11595
 
11829
- return true;
11596
+ // add private functions as _
11597
+ mixpanel_master['_'] = _;
11830
11598
  };
11831
11599
 
11832
- /**
11833
- * Add a listener for a given event.
11834
- *
11835
- * @param {(String|Symbol)} event The event name.
11836
- * @param {Function} fn The listener function.
11837
- * @param {*} [context=this] The context to invoke the listener with.
11838
- * @returns {EventEmitter} `this`.
11839
- * @public
11840
- */
11841
- EventEmitter.prototype.on = function on(event, fn, context) {
11842
- return addListener(this, event, fn, context, false);
11843
- };
11600
+ var override_mp_init_func = function() {
11601
+ // we override the snippets init function to handle the case where a
11602
+ // user initializes the mixpanel library after the script loads & runs
11603
+ mixpanel_master['init'] = function(token, config, name) {
11604
+ if (name) {
11605
+ // initialize a sub library
11606
+ if (!mixpanel_master[name]) {
11607
+ mixpanel_master[name] = instances[name] = create_mplib(token, config, name);
11608
+ mixpanel_master[name]._loaded();
11609
+ }
11610
+ return mixpanel_master[name];
11611
+ } else {
11612
+ var instance = mixpanel_master;
11844
11613
 
11845
- /**
11846
- * Add a one-time listener for a given event.
11847
- *
11848
- * @param {(String|Symbol)} event The event name.
11849
- * @param {Function} fn The listener function.
11850
- * @param {*} [context=this] The context to invoke the listener with.
11851
- * @returns {EventEmitter} `this`.
11852
- * @public
11853
- */
11854
- EventEmitter.prototype.once = function once(event, fn, context) {
11855
- return addListener(this, event, fn, context, true);
11856
- };
11614
+ if (instances[PRIMARY_INSTANCE_NAME]) {
11615
+ // main mixpanel lib already initialized
11616
+ instance = instances[PRIMARY_INSTANCE_NAME];
11617
+ } else if (token) {
11618
+ // intialize the main mixpanel lib
11619
+ instance = create_mplib(token, config, PRIMARY_INSTANCE_NAME);
11620
+ instance._loaded();
11621
+ instances[PRIMARY_INSTANCE_NAME] = instance;
11622
+ }
11857
11623
 
11858
- /**
11859
- * Remove the listeners of a given event.
11860
- *
11861
- * @param {(String|Symbol)} event The event name.
11862
- * @param {Function} fn Only remove the listeners that match this function.
11863
- * @param {*} context Only remove the listeners that have this context.
11864
- * @param {Boolean} once Only remove one-time listeners.
11865
- * @returns {EventEmitter} `this`.
11866
- * @public
11867
- */
11868
- EventEmitter.prototype.removeListener = function removeListener(event, fn, context, once) {
11869
- var evt = prefix ? prefix + event : event;
11624
+ mixpanel_master = instance;
11625
+ if (init_type === INIT_SNIPPET) {
11626
+ window$1[PRIMARY_INSTANCE_NAME] = mixpanel_master;
11627
+ }
11628
+ extend_mp();
11629
+ }
11630
+ };
11631
+ };
11870
11632
 
11871
- if (!this._events[evt]) return this;
11872
- if (!fn) {
11873
- clearEvent(this, evt);
11874
- return this;
11875
- }
11633
+ var add_dom_loaded_handler = function() {
11634
+ // Cross browser DOM Loaded support
11635
+ function dom_loaded_handler() {
11636
+ // function flag since we only want to execute this once
11637
+ if (dom_loaded_handler.done) { return; }
11638
+ dom_loaded_handler.done = true;
11876
11639
 
11877
- var listeners = this._events[evt];
11640
+ DOM_LOADED = true;
11641
+ ENQUEUE_REQUESTS = false;
11878
11642
 
11879
- if (listeners.fn) {
11880
- if (
11881
- listeners.fn === fn &&
11882
- (!once || listeners.once) &&
11883
- (!context || listeners.context === context)
11884
- ) {
11885
- clearEvent(this, evt);
11886
- }
11887
- } else {
11888
- for (var i = 0, events = [], length = listeners.length; i < length; i++) {
11889
- if (
11890
- listeners[i].fn !== fn ||
11891
- (once && !listeners[i].once) ||
11892
- (context && listeners[i].context !== context)
11893
- ) {
11894
- events.push(listeners[i]);
11895
- }
11643
+ _.each(instances, function(inst) {
11644
+ inst._dom_loaded();
11645
+ });
11896
11646
  }
11897
11647
 
11898
- //
11899
- // Reset the array, or remove it completely if we have no more listeners.
11900
- //
11901
- if (events.length) this._events[evt] = events.length === 1 ? events[0] : events;
11902
- else clearEvent(this, evt);
11903
- }
11904
-
11905
- return this;
11906
- };
11648
+ function do_scroll_check() {
11649
+ try {
11650
+ document$1.documentElement.doScroll('left');
11651
+ } catch(e) {
11652
+ setTimeout(do_scroll_check, 1);
11653
+ return;
11654
+ }
11907
11655
 
11908
- /**
11909
- * Remove all listeners, or those of the specified event.
11910
- *
11911
- * @param {(String|Symbol)} [event] The event name.
11912
- * @returns {EventEmitter} `this`.
11913
- * @public
11914
- */
11915
- EventEmitter.prototype.removeAllListeners = function removeAllListeners(event) {
11916
- var evt;
11656
+ dom_loaded_handler();
11657
+ }
11917
11658
 
11918
- if (event) {
11919
- evt = prefix ? prefix + event : event;
11920
- if (this._events[evt]) clearEvent(this, evt);
11921
- } else {
11922
- this._events = new Events();
11923
- this._eventsCount = 0;
11924
- }
11659
+ if (document$1.addEventListener) {
11660
+ if (document$1.readyState === 'complete') {
11661
+ // safari 4 can fire the DOMContentLoaded event before loading all
11662
+ // external JS (including this file). you will see some copypasta
11663
+ // on the internet that checks for 'complete' and 'loaded', but
11664
+ // 'loaded' is an IE thing
11665
+ dom_loaded_handler();
11666
+ } else {
11667
+ document$1.addEventListener('DOMContentLoaded', dom_loaded_handler, false);
11668
+ }
11669
+ } else if (document$1.attachEvent) {
11670
+ // IE
11671
+ document$1.attachEvent('onreadystatechange', dom_loaded_handler);
11925
11672
 
11926
- return this;
11927
- };
11673
+ // check to make sure we arn't in a frame
11674
+ var toplevel = false;
11675
+ try {
11676
+ toplevel = window$1.frameElement === null;
11677
+ } catch(e) {
11678
+ // noop
11679
+ }
11928
11680
 
11929
- //
11930
- // Alias methods names because people roll like that.
11931
- //
11932
- EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
11933
- EventEmitter.prototype.addListener = EventEmitter.prototype.on;
11681
+ if (document$1.documentElement.doScroll && toplevel) {
11682
+ do_scroll_check();
11683
+ }
11684
+ }
11934
11685
 
11935
- //
11936
- // Expose the prefix.
11937
- //
11938
- EventEmitter.prefixed = prefix;
11686
+ // fallback handler, always will work
11687
+ _.register_event(window$1, 'load', dom_loaded_handler, true);
11688
+ };
11939
11689
 
11940
- //
11941
- // Allow `EventEmitter` to be imported as module namespace.
11942
- //
11943
- EventEmitter.EventEmitter = EventEmitter;
11690
+ function init_as_module() {
11691
+ init_type = INIT_MODULE;
11692
+ mixpanel_master = new MixpanelLib();
11944
11693
 
11945
- //
11946
- // Expose the module.
11947
- //
11948
- {
11949
- module.exports = EventEmitter;
11950
- }
11951
- });
11694
+ override_mp_init_func();
11695
+ mixpanel_master['init']();
11696
+ add_dom_loaded_handler();
11952
11697
 
11953
- /**
11954
- * This method returns `undefined`.
11955
- *
11956
- * @static
11957
- * @memberOf _
11958
- * @since 2.3.0
11959
- * @category Util
11960
- * @example
11961
- *
11962
- * _.times(2, _.noop);
11963
- * // => [undefined, undefined]
11964
- */
11965
- function noop() {
11966
- // No operation performed.
11698
+ return mixpanel_master;
11967
11699
  }
11968
11700
 
11969
- var noop_1 = noop;
11701
+ var mixpanel = init_as_module();
11970
11702
 
11971
- /** Used as references for various `Number` constants. */
11972
- var INFINITY = 1 / 0;
11703
+ var mixpanel_cjs = mixpanel;
11973
11704
 
11974
- /**
11975
- * Creates a set object of `values`.
11976
- *
11977
- * @private
11978
- * @param {Array} values The values to add to the set.
11979
- * @returns {Object} Returns the new set.
11980
- */
11981
- var createSet = !(_Set && (1 / _setToArray(new _Set([,-0]))[1]) == INFINITY) ? noop_1 : function(values) {
11982
- return new _Set(values);
11983
- };
11705
+ var mixpanel$1 = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.assign(/*#__PURE__*/Object.create(null), mixpanel_cjs, {
11706
+ 'default': mixpanel_cjs
11707
+ }));
11984
11708
 
11985
- // eslint-disable-next-line import/no-cycle
11986
- /**
11987
- *
11988
- * @param url
11989
- * @param options
11990
- */
11991
- function failureLoggedFetch(url, options = {}) {
11992
- return fetch(url, options).then(async (r) => {
11993
- var _a;
11994
- if (!r.ok && r.type !== 'opaqueredirect' && r.type !== 'opaque') {
11995
- console.error('Failure', await ((_a = r.text) === null || _a === void 0 ? void 0 : _a.call(r)));
11996
- }
11997
- return r;
11998
- });
11999
- }
12000
- /**
12001
- *
12002
- * @param authVerificationUrl
12003
- */
12004
- function fetchSessionInfoService(authVerificationUrl) {
12005
- return failureLoggedFetch(authVerificationUrl, {
12006
- credentials: 'include',
12007
- });
12008
- }
12009
- /**
12010
- * Service to validate a auth token against a ThoughtSpot host.
12011
- *
12012
- * @param thoughtSpotHost : ThoughtSpot host to verify the token against.
12013
- * @param authToken : Auth token to verify.
12014
- */
12015
- function verifyTokenService(thoughtSpotHost, authToken) {
12016
- const authVerificationUrl = `${thoughtSpotHost}${EndPoints.IS_ACTIVE}`;
12017
- return fetch(authVerificationUrl, {
12018
- headers: {
12019
- Authorization: `Bearer ${authToken}`,
12020
- 'x-requested-by': 'ThoughtSpot',
12021
- },
12022
- credentials: 'omit',
12023
- });
12024
- }
12025
- /**
12026
- *
12027
- * @param authEndpoint
12028
- */
12029
- async function fetchAuthTokenService(authEndpoint) {
12030
- return fetch(authEndpoint);
12031
- }
11709
+ // Needed to avoid error in CJS builds on some bundlers.
11710
+ const mixpanelLib = mixpanel_cjs || mixpanel$1;
11711
+ let mixpanelInstance;
11712
+ const MIXPANEL_EVENT = {
11713
+ VISUAL_SDK_RENDER_START: 'visual-sdk-render-start',
11714
+ VISUAL_SDK_CALLED_INIT: 'visual-sdk-called-init',
11715
+ VISUAL_SDK_RENDER_COMPLETE: 'visual-sdk-render-complete',
11716
+ VISUAL_SDK_RENDER_FAILED: 'visual-sdk-render-failed',
11717
+ VISUAL_SDK_TRIGGER: 'visual-sdk-trigger',
11718
+ VISUAL_SDK_ON: 'visual-sdk-on',
11719
+ VISUAL_SDK_IFRAME_LOAD_PERFORMANCE: 'visual-sdk-iframe-load-performance',
11720
+ VISUAL_SDK_EMBED_CREATE: 'visual-sdk-embed-create',
11721
+ };
11722
+ let isMixpanelInitialized = false;
11723
+ let eventQueue = [];
12032
11724
  /**
11725
+ * Pushes the event with its Property key-value map to mixpanel.
12033
11726
  *
12034
- * @param thoughtSpotHost
12035
- * @param username
12036
- * @param authToken
11727
+ * @param eventId
11728
+ * @param eventProps
12037
11729
  */
12038
- async function fetchAuthService(thoughtSpotHost, username, authToken) {
12039
- return failureLoggedFetch(`${thoughtSpotHost}${EndPoints.TOKEN_LOGIN}?username=${username}&auth_token=${authToken}`, {
12040
- credentials: 'include',
12041
- // We do not want to follow the redirect, as it starts giving a CORS
12042
- // error
12043
- redirect: 'manual',
12044
- });
11730
+ function uploadMixpanelEvent(eventId, eventProps = {}) {
11731
+ if (!isMixpanelInitialized) {
11732
+ eventQueue.push({ eventId, eventProps });
11733
+ return;
11734
+ }
11735
+ mixpanelInstance.track(eventId, eventProps);
12045
11736
  }
12046
11737
  /**
12047
11738
  *
12048
- * @param thoughtSpotHost
12049
- * @param username
12050
- * @param authToken
12051
11739
  */
12052
- async function fetchAuthPostService(thoughtSpotHost, username, authToken) {
12053
- return failureLoggedFetch(`${thoughtSpotHost}${EndPoints.TOKEN_LOGIN}`, {
12054
- method: 'POST',
12055
- headers: {
12056
- 'content-type': 'application/x-www-form-urlencoded',
12057
- 'x-requested-by': 'ThoughtSpot',
12058
- },
12059
- body: `username=${encodeURIComponent(username)}&auth_token=${encodeURIComponent(authToken)}`,
12060
- credentials: 'include',
12061
- // We do not want to follow the redirect, as it starts giving a CORS
12062
- // error
12063
- redirect: 'manual',
11740
+ function emptyQueue() {
11741
+ if (!isMixpanelInitialized) {
11742
+ return;
11743
+ }
11744
+ eventQueue.forEach((event) => {
11745
+ uploadMixpanelEvent(event.eventId, event.eventProps);
12064
11746
  });
11747
+ eventQueue = [];
12065
11748
  }
12066
11749
  /**
12067
11750
  *
12068
- * @param thoughtSpotHost
12069
- * @param username
12070
- * @param password
12071
- */
12072
- async function fetchBasicAuthService(thoughtSpotHost, username, password) {
12073
- return failureLoggedFetch(`${thoughtSpotHost}${EndPoints.BASIC_LOGIN}`, {
12074
- method: 'POST',
12075
- headers: {
12076
- 'content-type': 'application/x-www-form-urlencoded',
12077
- 'x-requested-by': 'ThoughtSpot',
12078
- },
12079
- body: `username=${encodeURIComponent(username)}&password=${encodeURIComponent(password)}`,
12080
- credentials: 'include',
12081
- });
11751
+ * @param sessionInfo
11752
+ */
11753
+ function initMixpanel(sessionInfo) {
11754
+ var _a;
11755
+ if (!sessionInfo || !sessionInfo.mixpanelToken) {
11756
+ return;
11757
+ }
11758
+ // On a public cluster the user is anonymous, so don't set the identify to
11759
+ // userGUID
11760
+ const isPublicCluster = !!sessionInfo.isPublicUser;
11761
+ const token = sessionInfo.mixpanelToken;
11762
+ try {
11763
+ if (token) {
11764
+ mixpanelInstance = mixpanelLib.init(token, undefined, 'tsEmbed');
11765
+ if (!isPublicCluster) {
11766
+ mixpanelInstance.identify(sessionInfo.userGUID);
11767
+ }
11768
+ mixpanelInstance.register_once({
11769
+ clusterId: sessionInfo.clusterId,
11770
+ clusterName: sessionInfo.clusterName,
11771
+ releaseVersion: sessionInfo.releaseVersion,
11772
+ hostAppUrl: ((_a = window === null || window === void 0 ? void 0 : window.location) === null || _a === void 0 ? void 0 : _a.host) || '',
11773
+ });
11774
+ isMixpanelInitialized = true;
11775
+ emptyQueue();
11776
+ }
11777
+ }
11778
+ catch (e) {
11779
+ console.error('Error initializing mixpanel', e);
11780
+ }
12082
11781
  }
12083
11782
 
12084
11783
  // eslint-disable-next-line import/no-mutable-exports
@@ -12094,17 +11793,6 @@ const sessionInfoPromise = new Promise((resolve) => {
12094
11793
  });
12095
11794
  let releaseVersion = '';
12096
11795
  const SSO_REDIRECTION_MARKER_GUID = '5e16222e-ef02-43e9-9fbd-24226bf3ce5b';
12097
- const EndPoints = {
12098
- AUTH_VERIFICATION: '/callosum/v1/session/info',
12099
- SAML_LOGIN_TEMPLATE: (targetUrl) => `/callosum/v1/saml/login?targetURLPath=${targetUrl}`,
12100
- OIDC_LOGIN_TEMPLATE: (targetUrl) => `/callosum/v1/oidc/login?targetURLPath=${targetUrl}`,
12101
- TOKEN_LOGIN: '/callosum/v1/session/login/token',
12102
- BASIC_LOGIN: '/callosum/v1/session/login',
12103
- LOGOUT: '/callosum/v1/session/logout',
12104
- EXECUTE_TML: '/api/rest/2.0/metadata/tml/import',
12105
- EXPORT_TML: '/api/rest/2.0/metadata/tml/export',
12106
- IS_ACTIVE: '/callosum/v1/session/isactive',
12107
- };
12108
11796
  /**
12109
11797
  * Enum for auth failure types. This is the parameter passed to the listner
12110
11798
  * of {@link AuthStatus.FAILURE}.
@@ -12171,382 +11859,748 @@ function notifyAuthSDKSuccess() {
12171
11859
  console.error('SDK not initialized');
12172
11860
  return;
12173
11861
  }
12174
- }
12175
- /**
12176
- *
12177
- */
12178
- function notifyAuthSuccess() {
12179
- {
12180
- console.error('SDK not initialized');
11862
+ }
11863
+ /**
11864
+ *
11865
+ */
11866
+ function notifyAuthSuccess() {
11867
+ {
11868
+ console.error('SDK not initialized');
11869
+ return;
11870
+ }
11871
+ }
11872
+ /**
11873
+ *
11874
+ * @param failureType
11875
+ */
11876
+ function notifyAuthFailure(failureType) {
11877
+ {
11878
+ console.error('SDK not initialized');
11879
+ return;
11880
+ }
11881
+ }
11882
+ /**
11883
+ *
11884
+ */
11885
+ function notifyLogout() {
11886
+ {
11887
+ console.error('SDK not initialized');
11888
+ return;
11889
+ }
11890
+ }
11891
+ const initSession = (sessionDetails) => {
11892
+ if (sessionInfo == null) {
11893
+ sessionInfo = sessionDetails;
11894
+ initMixpanel(sessionInfo);
11895
+ sessionInfoResolver(sessionInfo);
11896
+ }
11897
+ };
11898
+ const getSessionDetails = (sessionInfoResp) => {
11899
+ console.log('helloooo');
11900
+ const devMixpanelToken = sessionInfoResp.configInfo.mixpanelConfig.devSdkKey;
11901
+ const prodMixpanelToken = sessionInfoResp.configInfo.mixpanelConfig.prodSdkKey;
11902
+ const mixpanelToken = sessionInfoResp.configInfo.mixpanelConfig.production
11903
+ ? prodMixpanelToken
11904
+ : devMixpanelToken;
11905
+ return {
11906
+ userGUID: sessionInfoResp.userGUID,
11907
+ mixpanelToken,
11908
+ isPublicUser: sessionInfoResp.configInfo.isPublicUser,
11909
+ releaseVersion: sessionInfoResp.releaseVersion,
11910
+ clusterId: sessionInfoResp.configInfo.selfClusterId,
11911
+ clusterName: sessionInfoResp.configInfo.selfClusterName,
11912
+ ...sessionInfoResp,
11913
+ };
11914
+ };
11915
+ /**
11916
+ * Check if we are logged into the ThoughtSpot cluster
11917
+ *
11918
+ * @param thoughtSpotHost The ThoughtSpot cluster hostname or IP
11919
+ */
11920
+ async function isLoggedIn(thoughtSpotHost) {
11921
+ const authVerificationUrl = `${thoughtSpotHost}${EndPoints.AUTH_VERIFICATION}`;
11922
+ let response = null;
11923
+ try {
11924
+ response = await fetchSessionInfoService(authVerificationUrl);
11925
+ const sessionInfoResp = await response.json();
11926
+ const sessionDetails = getSessionDetails(sessionInfoResp);
11927
+ // Store user session details from session info
11928
+ initSession(sessionDetails);
11929
+ releaseVersion = sessionInfoResp.releaseVersion;
11930
+ }
11931
+ catch (e) {
11932
+ return false;
11933
+ }
11934
+ return response.status === 200;
11935
+ }
11936
+ /**
11937
+ * Return releaseVersion if available
11938
+ */
11939
+ function getReleaseVersion() {
11940
+ return releaseVersion;
11941
+ }
11942
+ /**
11943
+ * Check if we are stuck at the SSO redirect URL
11944
+ */
11945
+ function isAtSSORedirectUrl() {
11946
+ return window.location.href.indexOf(SSO_REDIRECTION_MARKER_GUID) >= 0;
11947
+ }
11948
+ /**
11949
+ * Remove the SSO redirect URL marker
11950
+ */
11951
+ function removeSSORedirectUrlMarker() {
11952
+ // Note (sunny): This will leave a # around even if it was not in the URL
11953
+ // to begin with. Trying to remove the hash by changing window.location will
11954
+ // reload the page which we don't want. We'll live with adding an
11955
+ // unnecessary hash to the parent page URL until we find any use case where
11956
+ // that creates an issue.
11957
+ window.location.hash = window.location.hash.replace(SSO_REDIRECTION_MARKER_GUID, '');
11958
+ }
11959
+ /**
11960
+ * Perform token based authentication
11961
+ *
11962
+ * @param embedConfig The embed configuration
11963
+ */
11964
+ const doTokenAuth = async (embedConfig) => {
11965
+ const { thoughtSpotHost, username, authEndpoint, getAuthToken, } = embedConfig;
11966
+ if (!authEndpoint && !getAuthToken) {
11967
+ throw new Error('Either auth endpoint or getAuthToken function must be provided');
11968
+ }
11969
+ loggedInStatus = await isLoggedIn(thoughtSpotHost);
11970
+ if (!loggedInStatus) {
11971
+ const authToken = await getAuthenticationToken(embedConfig);
11972
+ let resp;
11973
+ try {
11974
+ resp = await fetchAuthPostService(thoughtSpotHost, username, authToken);
11975
+ }
11976
+ catch (e) {
11977
+ resp = await fetchAuthService(thoughtSpotHost, username, authToken);
11978
+ }
11979
+ // token login issues a 302 when successful
11980
+ loggedInStatus = resp.ok || resp.type === 'opaqueredirect';
11981
+ if (loggedInStatus && embedConfig.detectCookieAccessSlow) {
11982
+ // When 3rd party cookie access is blocked, this will fail because
11983
+ // cookies will not be sent with the call.
11984
+ loggedInStatus = await isLoggedIn(thoughtSpotHost);
11985
+ }
11986
+ }
11987
+ return loggedInStatus;
11988
+ };
11989
+ /**
11990
+ * Validate embedConfig parameters required for cookielessTokenAuth
11991
+ *
11992
+ * @param embedConfig The embed configuration
11993
+ */
11994
+ const doCookielessTokenAuth = async (embedConfig) => {
11995
+ const { authEndpoint, getAuthToken } = embedConfig;
11996
+ if (!authEndpoint && !getAuthToken) {
11997
+ throw new Error('Either auth endpoint or getAuthToken function must be provided');
11998
+ }
11999
+ try {
12000
+ const authToken = await getAuthenticationToken(embedConfig);
12001
+ if (authToken)
12002
+ return true;
12003
+ }
12004
+ catch {
12005
+ // return false if getAuthenticationToken fails
12006
+ }
12007
+ return false;
12008
+ };
12009
+ /**
12010
+ * Perform basic authentication to the ThoughtSpot cluster using the cluster
12011
+ * credentials.
12012
+ *
12013
+ * Warning: This feature is primarily intended for developer testing. It is
12014
+ * strongly advised not to use this authentication method in production.
12015
+ *
12016
+ * @param embedConfig The embed configuration
12017
+ */
12018
+ const doBasicAuth = async (embedConfig) => {
12019
+ const { thoughtSpotHost, username, password } = embedConfig;
12020
+ const loggedIn = await isLoggedIn(thoughtSpotHost);
12021
+ if (!loggedIn) {
12022
+ const response = await fetchBasicAuthService(thoughtSpotHost, username, password);
12023
+ loggedInStatus = response.ok;
12024
+ if (embedConfig.detectCookieAccessSlow) {
12025
+ loggedInStatus = await isLoggedIn(thoughtSpotHost);
12026
+ }
12027
+ }
12028
+ else {
12029
+ loggedInStatus = true;
12030
+ }
12031
+ return loggedInStatus;
12032
+ };
12033
+ /**
12034
+ *
12035
+ * @param ssoURL
12036
+ * @param triggerContainer
12037
+ * @param triggerText
12038
+ */
12039
+ async function samlPopupFlow(ssoURL, triggerContainer, triggerText) {
12040
+ const openPopup = () => {
12041
+ if (samlAuthWindow === null || samlAuthWindow.closed) {
12042
+ samlAuthWindow = window.open(ssoURL, '_blank', 'location=no,height=570,width=520,scrollbars=yes,status=yes');
12043
+ }
12044
+ else {
12045
+ samlAuthWindow.focus();
12046
+ }
12047
+ };
12048
+ const containerEl = getDOMNode(triggerContainer);
12049
+ if (containerEl) {
12050
+ containerEl.innerHTML = '<button id="ts-auth-btn" class="ts-auth-btn" style="margin: auto;"></button>';
12051
+ const authElem = document.getElementById('ts-auth-btn');
12052
+ authElem.textContent = triggerText;
12053
+ authElem.addEventListener('click', openPopup, { once: true });
12054
+ }
12055
+ samlCompletionPromise = samlCompletionPromise
12056
+ || new Promise((resolve, reject) => {
12057
+ window.addEventListener('message', (e) => {
12058
+ if (e.data.type === EmbedEvent.SAMLComplete) {
12059
+ e.source.close();
12060
+ resolve();
12061
+ }
12062
+ });
12063
+ });
12064
+ return samlCompletionPromise;
12065
+ }
12066
+ /**
12067
+ * Perform SAML authentication
12068
+ *
12069
+ * @param embedConfig The embed configuration
12070
+ * @param ssoEndPoint
12071
+ */
12072
+ const doSSOAuth = async (embedConfig, ssoEndPoint) => {
12073
+ const { thoughtSpotHost } = embedConfig;
12074
+ const loggedIn = await isLoggedIn(thoughtSpotHost);
12075
+ if (loggedIn) {
12076
+ if (isAtSSORedirectUrl()) {
12077
+ removeSSORedirectUrlMarker();
12078
+ }
12079
+ loggedInStatus = true;
12080
+ return;
12081
+ }
12082
+ // we have already tried authentication and it did not succeed, restore
12083
+ // the current URL to the original one and invoke the callback.
12084
+ if (isAtSSORedirectUrl()) {
12085
+ removeSSORedirectUrlMarker();
12086
+ loggedInStatus = false;
12087
+ return;
12088
+ }
12089
+ const ssoURL = `${thoughtSpotHost}${ssoEndPoint}`;
12090
+ if (embedConfig.inPopup) {
12091
+ await samlPopupFlow(ssoURL, embedConfig.authTriggerContainer, embedConfig.authTriggerText);
12092
+ loggedInStatus = await isLoggedIn(thoughtSpotHost);
12181
12093
  return;
12182
12094
  }
12183
- }
12095
+ window.location.href = ssoURL;
12096
+ };
12097
+ const doSamlAuth = async (embedConfig) => {
12098
+ const { thoughtSpotHost } = embedConfig;
12099
+ // redirect for SSO, when the SSO authentication is done, this page will be
12100
+ // loaded again and the same JS will execute again.
12101
+ const ssoRedirectUrl = embedConfig.inPopup
12102
+ ? `${thoughtSpotHost}/v2/#/embed/saml-complete`
12103
+ : getRedirectUrl(window.location.href, SSO_REDIRECTION_MARKER_GUID, embedConfig.redirectPath);
12104
+ // bring back the page to the same URL
12105
+ const ssoEndPoint = `${EndPoints.SAML_LOGIN_TEMPLATE(encodeURIComponent(ssoRedirectUrl))}`;
12106
+ await doSSOAuth(embedConfig, ssoEndPoint);
12107
+ return loggedInStatus;
12108
+ };
12109
+ const doOIDCAuth = async (embedConfig) => {
12110
+ const { thoughtSpotHost } = embedConfig;
12111
+ // redirect for SSO, when the SSO authentication is done, this page will be
12112
+ // loaded again and the same JS will execute again.
12113
+ const ssoRedirectUrl = embedConfig.noRedirect || embedConfig.inPopup
12114
+ ? `${thoughtSpotHost}/v2/#/embed/saml-complete`
12115
+ : getRedirectUrl(window.location.href, SSO_REDIRECTION_MARKER_GUID, embedConfig.redirectPath);
12116
+ // bring back the page to the same URL
12117
+ const ssoEndPoint = `${EndPoints.OIDC_LOGIN_TEMPLATE(encodeURIComponent(ssoRedirectUrl))}`;
12118
+ await doSSOAuth(embedConfig, ssoEndPoint);
12119
+ return loggedInStatus;
12120
+ };
12184
12121
  /**
12122
+ * Perform authentication on the ThoughtSpot cluster
12185
12123
  *
12186
- * @param failureType
12124
+ * @param embedConfig The embed configuration
12187
12125
  */
12188
- function notifyAuthFailure(failureType) {
12189
- {
12190
- console.error('SDK not initialized');
12191
- return;
12126
+ const authenticate = async (embedConfig) => {
12127
+ const { authType } = embedConfig;
12128
+ switch (authType) {
12129
+ case AuthType.SSO:
12130
+ case AuthType.SAMLRedirect:
12131
+ case AuthType.SAML:
12132
+ return doSamlAuth(embedConfig);
12133
+ case AuthType.OIDC:
12134
+ case AuthType.OIDCRedirect:
12135
+ return doOIDCAuth(embedConfig);
12136
+ case AuthType.AuthServer:
12137
+ case AuthType.TrustedAuthToken:
12138
+ return doTokenAuth(embedConfig);
12139
+ case AuthType.TrustedAuthTokenCookieless:
12140
+ return doCookielessTokenAuth(embedConfig);
12141
+ case AuthType.Basic:
12142
+ return doBasicAuth(embedConfig);
12143
+ default:
12144
+ return Promise.resolve(true);
12192
12145
  }
12193
- }
12146
+ };
12147
+
12148
+ /* eslint-disable camelcase */
12149
+ let config = {};
12150
+ const CONFIG_DEFAULTS = {
12151
+ loginFailedMessage: 'Not logged in',
12152
+ authTriggerText: 'Authorize',
12153
+ authType: AuthType.None,
12154
+ };
12155
+ let authPromise;
12194
12156
  /**
12157
+ * Gets the configuration embed was initialized with.
12195
12158
  *
12159
+ * @returns {@link EmbedConfig} The configuration embed was initialized with.
12160
+ * @version SDK: 1.19.0 | ThoughtSpot: *
12161
+ * @group Global methods
12196
12162
  */
12197
- function notifyLogout() {
12198
- {
12199
- console.error('SDK not initialized');
12200
- return;
12201
- }
12202
- }
12203
- const initSession = (sessionDetails) => {
12204
- if (sessionInfo == null) {
12205
- sessionInfo = sessionDetails;
12206
- initMixpanel(sessionInfo);
12207
- sessionInfoResolver(sessionInfo);
12208
- }
12163
+ const getEmbedConfig = () => config;
12164
+ const getAuthPromise = () => authPromise;
12165
+ /**
12166
+ * Perform authentication on the ThoughtSpot app as applicable.
12167
+ */
12168
+ const handleAuth = () => {
12169
+ authPromise = authenticate(config);
12170
+ authPromise.then((isLoggedIn) => {
12171
+ if (!isLoggedIn) {
12172
+ notifyAuthFailure(AuthFailureType.SDK);
12173
+ }
12174
+ else {
12175
+ notifyAuthSDKSuccess();
12176
+ }
12177
+ }, () => {
12178
+ notifyAuthFailure(AuthFailureType.SDK);
12179
+ });
12180
+ return authPromise;
12209
12181
  };
12210
- const getSessionDetails = (sessionInfoResp) => {
12211
- const devMixpanelToken = sessionInfoResp.configInfo.mixpanelConfig.devSdkKey;
12212
- const prodMixpanelToken = sessionInfoResp.configInfo.mixpanelConfig.prodSdkKey;
12213
- const mixpanelToken = sessionInfoResp.configInfo.mixpanelConfig.production
12214
- ? prodMixpanelToken
12215
- : devMixpanelToken;
12216
- return {
12217
- userGUID: sessionInfoResp.userGUID,
12218
- mixpanelToken,
12219
- isPublicUser: sessionInfoResp.configInfo.isPublicUser,
12220
- releaseVersion: sessionInfoResp.releaseVersion,
12221
- clusterId: sessionInfoResp.configInfo.selfClusterId,
12222
- clusterName: sessionInfoResp.configInfo.selfClusterName,
12223
- ...sessionInfoResp,
12224
- };
12182
+ const hostUrlToFeatureUrl = {
12183
+ [PrefetchFeatures.SearchEmbed]: (url) => `${url}v2/#/embed/answer`,
12184
+ [PrefetchFeatures.LiveboardEmbed]: (url) => url,
12185
+ [PrefetchFeatures.FullApp]: (url) => url,
12186
+ [PrefetchFeatures.VizEmbed]: (url) => url,
12225
12187
  };
12226
12188
  /**
12227
- * Check if we are logged into the ThoughtSpot cluster
12228
12189
  *
12229
- * @param thoughtSpotHost The ThoughtSpot cluster hostname or IP
12230
- */
12231
- async function isLoggedIn(thoughtSpotHost) {
12232
- const authVerificationUrl = `${thoughtSpotHost}${EndPoints.AUTH_VERIFICATION}`;
12233
- let response = null;
12234
- try {
12235
- response = await fetchSessionInfoService(authVerificationUrl);
12236
- const sessionInfoResp = await response.json();
12237
- const sessionDetails = getSessionDetails(sessionInfoResp);
12238
- // Store user session details from session info
12239
- initSession(sessionDetails);
12240
- releaseVersion = sessionInfoResp.releaseVersion;
12241
- }
12242
- catch (e) {
12243
- return false;
12244
- }
12245
- return response.status === 200;
12246
- }
12247
- /**
12248
- * Return releaseVersion if available
12249
12190
  */
12250
- function getReleaseVersion() {
12251
- return releaseVersion;
12191
+ function disableAutoLogin() {
12192
+ config.autoLogin = false;
12252
12193
  }
12253
- const DUPLICATE_TOKEN_ERR = 'Duplicate token, please issue a new token every time getAuthToken callback is called.'
12254
- + 'See https://developers.thoughtspot.com/docs/?pageid=embed-auth#trusted-auth-embed for more details.';
12255
- let prevAuthToken = null;
12194
+ let renderQueue = Promise.resolve();
12256
12195
  /**
12196
+ * Renders functions in a queue, resolves to next function only after the callback next
12197
+ * is called
12257
12198
  *
12258
- * @param authtoken
12199
+ * @param fn The function being registered
12259
12200
  */
12260
- function alertForDuplicateToken(authtoken) {
12261
- if (prevAuthToken === authtoken) {
12262
- // eslint-disable-next-line no-alert
12263
- alert(DUPLICATE_TOKEN_ERR);
12264
- throw new Error(DUPLICATE_TOKEN_ERR);
12201
+ const renderInQueue = (fn) => {
12202
+ const { queueMultiRenders = false } = config;
12203
+ if (queueMultiRenders) {
12204
+ renderQueue = renderQueue.then(() => new Promise((res) => fn(res)));
12205
+ return renderQueue;
12265
12206
  }
12266
- prevAuthToken = authtoken;
12267
- }
12207
+ // Sending an empty function to keep it consistent with the above usage.
12208
+ return fn(() => { }); // eslint-disable-line @typescript-eslint/no-empty-function
12209
+ };
12210
+
12211
+ const tokenizedFetch = async (input, init) => {
12212
+ const req = new Request(input, init);
12213
+ const embedConfig = getEmbedConfig();
12214
+ if (embedConfig.authType !== AuthType.TrustedAuthTokenCookieless) {
12215
+ return fetch(req);
12216
+ }
12217
+ const authToken = await getAuthenticationToken(embedConfig);
12218
+ if (authToken) {
12219
+ req.headers.append('Authorization', `Bearer ${authToken}`);
12220
+ }
12221
+ return fetch(req);
12222
+ };
12223
+
12268
12224
  /**
12269
- * Check if we are stuck at the SSO redirect URL
12225
+ *
12226
+ * @param root0
12227
+ * @param root0.query
12228
+ * @param root0.variables
12229
+ * @param root0.thoughtSpotHost
12230
+ * @param root0.isCompositeQuery
12270
12231
  */
12271
- function isAtSSORedirectUrl() {
12272
- return window.location.href.indexOf(SSO_REDIRECTION_MARKER_GUID) >= 0;
12273
- }
12232
+ async function graphqlQuery({ query, variables, thoughtSpotHost, isCompositeQuery = false, }) {
12233
+ const operationName = getOperationNameFromQuery(query);
12234
+ try {
12235
+ const response = await fetch(`${thoughtSpotHost}/prism/?op=${operationName}`, {
12236
+ method: 'POST',
12237
+ headers: {
12238
+ 'content-type': 'application/json;charset=UTF-8',
12239
+ 'x-requested-by': 'ThoughtSpot',
12240
+ accept: '*/*',
12241
+ 'accept-language': 'en-us',
12242
+ },
12243
+ body: JSON.stringify({
12244
+ operationName,
12245
+ query,
12246
+ variables,
12247
+ }),
12248
+ credentials: 'include',
12249
+ });
12250
+ const result = await response.json();
12251
+ const dataValues = Object.values(result.data);
12252
+ return (isCompositeQuery) ? result.data : dataValues[0];
12253
+ }
12254
+ catch (error) {
12255
+ return error;
12256
+ }
12257
+ }
12258
+
12259
+ const getSourceDetailQuery = `
12260
+ query GetSourceDetail($ids: [GUID!]!) {
12261
+ getSourceDetailById(ids: $ids, type: LOGICAL_TABLE) {
12262
+ id
12263
+ name
12264
+ description
12265
+ authorName
12266
+ authorDisplayName
12267
+ isExternal
12268
+ type
12269
+ created
12270
+ modified
12271
+ columns {
12272
+ id
12273
+ name
12274
+ author
12275
+ authorDisplayName
12276
+ description
12277
+ dataType
12278
+ type
12279
+ modified
12280
+ ownerName
12281
+ owner
12282
+ dataRecency
12283
+ sources {
12284
+ tableId
12285
+ tableName
12286
+ columnId
12287
+ columnName
12288
+ __typename
12289
+ }
12290
+ synonyms
12291
+ cohortAnswerId
12292
+ __typename
12293
+ }
12294
+ relationships
12295
+ destinationRelationships
12296
+ dataSourceId
12297
+ __typename
12298
+ }
12299
+ }
12300
+ `;
12301
+ const sourceDetailCache = new Map();
12274
12302
  /**
12275
- * Remove the SSO redirect URL marker
12303
+ *
12304
+ * @param thoughtSpotHost
12305
+ * @param sourceId
12276
12306
  */
12277
- function removeSSORedirectUrlMarker() {
12278
- // Note (sunny): This will leave a # around even if it was not in the URL
12279
- // to begin with. Trying to remove the hash by changing window.location will
12280
- // reload the page which we don't want. We'll live with adding an
12281
- // unnecessary hash to the parent page URL until we find any use case where
12282
- // that creates an issue.
12283
- window.location.hash = window.location.hash.replace(SSO_REDIRECTION_MARKER_GUID, '');
12284
- }
12285
- const getAuthenticationToken = async (embedConfig) => {
12286
- const { authEndpoint, getAuthToken } = embedConfig;
12287
- let authToken = null;
12288
- if (getAuthToken) {
12289
- authToken = await getAuthToken();
12290
- alertForDuplicateToken(authToken);
12307
+ async function getSourceDetail(thoughtSpotHost, sourceId) {
12308
+ if (sourceDetailCache.get(sourceId)) {
12309
+ return sourceDetailCache.get(sourceId);
12291
12310
  }
12292
- else {
12293
- const response = await fetchAuthTokenService(authEndpoint);
12294
- authToken = await response.text();
12311
+ const details = await graphqlQuery({
12312
+ query: getSourceDetailQuery,
12313
+ variables: {
12314
+ ids: [sourceId],
12315
+ },
12316
+ thoughtSpotHost,
12317
+ });
12318
+ const souceDetails = details[0];
12319
+ if (souceDetails) {
12320
+ sourceDetailCache.set(sourceId, souceDetails);
12295
12321
  }
12296
- return authToken;
12297
- };
12322
+ return souceDetails;
12323
+ }
12324
+
12325
+ const bachSessionId = `
12326
+ id {
12327
+ sessionId
12328
+ genNo
12329
+ acSession {
12330
+ sessionId
12331
+ genNo
12332
+ }
12333
+ }
12334
+ `;
12335
+ const getUnaggregatedAnswerSession = `
12336
+ mutation GetUnAggregatedAnswerSession($session: BachSessionIdInput!, $columns: [UserPointSelectionInput!]!) {
12337
+ Answer__getUnaggregatedAnswer(session: $session, columns: $columns) {
12338
+ ${bachSessionId}
12339
+ answer {
12340
+ visualizations {
12341
+ ... on TableViz {
12342
+ columns {
12343
+ column {
12344
+ id
12345
+ name
12346
+ referencedColumns {
12347
+ guid
12348
+ displayName
12349
+ }
12350
+ }
12351
+ }
12352
+ }
12353
+ }
12354
+ }
12355
+ }
12356
+ }
12357
+ `;
12358
+ const removeColumns = `
12359
+ mutation RemoveColumns($session: BachSessionIdInput!, $logicalColumnIds: [GUID!], $columnIds: [GUID!]) {
12360
+ Answer__removeColumns(
12361
+ session: $session
12362
+ logicalColumnIds: $logicalColumnIds
12363
+ columnIds: $columnIds
12364
+ ) {
12365
+ ${bachSessionId}
12366
+ }
12367
+ }
12368
+ `;
12369
+ const addColumns = `
12370
+ mutation AddColumns($session: BachSessionIdInput!, $columns: [AnswerColumnInfo!]!) {
12371
+ Answer__addColumn(session: $session, columns: $columns) {
12372
+ ${bachSessionId}
12373
+ }
12374
+ }
12375
+ `;
12376
+ const getAnswerData = `
12377
+ query GetTableWithHeadlineData($session: BachSessionIdInput!, $deadline: Int!, $dataPaginationParams: DataPaginationParamsInput!) {
12378
+ getAnswer(session: $session) {
12379
+ ${bachSessionId}
12380
+ answer {
12381
+ id
12382
+ visualizations {
12383
+ id
12384
+ ... on TableViz {
12385
+ columns {
12386
+ column {
12387
+ id
12388
+ name
12389
+ type
12390
+ aggregationType
12391
+ dataType
12392
+ }
12393
+ }
12394
+ data(deadline: $deadline, pagination: $dataPaginationParams)
12395
+ }
12396
+ }
12397
+ }
12398
+ }
12399
+ }
12400
+ `;
12401
+
12402
+ // eslint-disable-next-line no-shadow
12403
+ var OperationType;
12404
+ (function (OperationType) {
12405
+ OperationType["GetChartWithData"] = "GetChartWithData";
12406
+ OperationType["GetTableWithHeadlineData"] = "GetTableWithHeadlineData";
12407
+ })(OperationType || (OperationType = {}));
12298
12408
  /**
12299
- * Perform token based authentication
12409
+ * Class representing the answer service provided with the
12410
+ * custom action payload. This service could be used to run
12411
+ * graphql queries in the context of the answer on which the
12412
+ * custom action was triggered.
12300
12413
  *
12301
- * @param embedConfig The embed configuration
12414
+ * @example
12415
+ * ```js
12416
+ * embed.on(EmbedEvent.CustomAction, e => {
12417
+ * const underlying = await e.answerService.getUnderlyingDataForPoint([
12418
+ * 'col name 1'
12419
+ * ]);
12420
+ * const data = await underlying.fetchData(0, 100);
12421
+ * })
12422
+ * ```
12423
+ * @version
12424
+ * ThoughtSpot: 9.9.0.cl / SDK: 1.25.0
12425
+ * @group Events
12302
12426
  */
12303
- const doTokenAuth = async (embedConfig) => {
12304
- const { thoughtSpotHost, username, authEndpoint, getAuthToken, } = embedConfig;
12305
- if (!authEndpoint && !getAuthToken) {
12306
- throw new Error('Either auth endpoint or getAuthToken function must be provided');
12427
+ class AnswerService {
12428
+ constructor(session, answer, thoughtSpotHost, selectedPoints) {
12429
+ this.session = session;
12430
+ this.answer = answer;
12431
+ this.thoughtSpotHost = thoughtSpotHost;
12432
+ this.selectedPoints = selectedPoints;
12433
+ this.session = removeTypename(session);
12307
12434
  }
12308
- loggedInStatus = await isLoggedIn(thoughtSpotHost);
12309
- if (!loggedInStatus) {
12310
- const authToken = await getAuthenticationToken(embedConfig);
12311
- let resp;
12312
- try {
12313
- resp = await fetchAuthPostService(thoughtSpotHost, username, authToken);
12314
- }
12315
- catch (e) {
12316
- resp = await fetchAuthService(thoughtSpotHost, username, authToken);
12317
- }
12318
- // token login issues a 302 when successful
12319
- loggedInStatus = resp.ok || resp.type === 'opaqueredirect';
12320
- if (loggedInStatus && embedConfig.detectCookieAccessSlow) {
12321
- // When 3rd party cookie access is blocked, this will fail because
12322
- // cookies will not be sent with the call.
12323
- loggedInStatus = await isLoggedIn(thoughtSpotHost);
12324
- }
12435
+ async getSourceDetail() {
12436
+ const sourceId = this.answer.sources[0].header.guid;
12437
+ return getSourceDetail(this.thoughtSpotHost, sourceId);
12325
12438
  }
12326
- return loggedInStatus;
12327
- };
12328
- /**
12329
- * Validate embedConfig parameters required for cookielessTokenAuth
12330
- *
12331
- * @param embedConfig The embed configuration
12332
- */
12333
- const doCookielessTokenAuth = async (embedConfig) => {
12334
- const { authEndpoint, getAuthToken } = embedConfig;
12335
- if (!authEndpoint && !getAuthToken) {
12336
- throw new Error('Either auth endpoint or getAuthToken function must be provided');
12439
+ async removeColumns(columnIds) {
12440
+ return this.executeQuery(removeColumns, {
12441
+ logicalColumnIds: columnIds,
12442
+ });
12337
12443
  }
12338
- try {
12339
- const authToken = await getAuthenticationToken(embedConfig);
12340
- const response = await verifyTokenService(embedConfig.thoughtSpotHost, authToken);
12341
- if (!response.ok)
12342
- return false;
12444
+ async addColumns(columnIds) {
12445
+ return this.executeQuery(addColumns, {
12446
+ columns: columnIds.map((colId) => ({ logicalColumnId: colId })),
12447
+ });
12343
12448
  }
12344
- catch (e) {
12345
- return false;
12449
+ async fetchData(offset = 0, size = 1000) {
12450
+ const { answer } = await this.executeQuery(getAnswerData, {
12451
+ deadline: 0,
12452
+ dataPaginationParams: {
12453
+ isClientPaginated: true,
12454
+ offset,
12455
+ size,
12456
+ },
12457
+ });
12458
+ const { columns, data } = answer.visualizations[0];
12459
+ return {
12460
+ columns,
12461
+ data,
12462
+ };
12346
12463
  }
12347
- return true;
12348
- };
12349
- /**
12350
- * Perform basic authentication to the ThoughtSpot cluster using the cluster
12351
- * credentials.
12352
- *
12353
- * Warning: This feature is primarily intended for developer testing. It is
12354
- * strongly advised not to use this authentication method in production.
12355
- *
12356
- * @param embedConfig The embed configuration
12357
- */
12358
- const doBasicAuth = async (embedConfig) => {
12359
- const { thoughtSpotHost, username, password } = embedConfig;
12360
- const loggedIn = await isLoggedIn(thoughtSpotHost);
12361
- if (!loggedIn) {
12362
- const response = await fetchBasicAuthService(thoughtSpotHost, username, password);
12363
- loggedInStatus = response.ok;
12364
- if (embedConfig.detectCookieAccessSlow) {
12365
- loggedInStatus = await isLoggedIn(thoughtSpotHost);
12366
- }
12464
+ /**
12465
+ *
12466
+ * @param userLocale
12467
+ * @param includeInfo Include the CSV header in the output
12468
+ * @returns Response
12469
+ */
12470
+ async fetchCSVBlob(userLocale = 'en-us', includeInfo = false) {
12471
+ const fetchUrl = this.getFetchCSVBlobUrl(userLocale, includeInfo);
12472
+ return tokenizedFetch(fetchUrl, {
12473
+ credentials: 'include',
12474
+ });
12367
12475
  }
12368
- else {
12369
- loggedInStatus = true;
12476
+ getFetchCSVBlobUrl(userLocale = 'en-us', includeInfo = false) {
12477
+ return `${this.thoughtSpotHost}/prism/download/answer/csv?sessionId=${this.session.sessionId}&genNo=${this.session.genNo}&userLocale=${userLocale}&exportFileName=data&hideCsvHeader=${!includeInfo}`;
12370
12478
  }
12371
- return loggedInStatus;
12372
- };
12373
- /**
12374
- *
12375
- * @param ssoURL
12376
- * @param triggerContainer
12377
- * @param triggerText
12378
- */
12379
- async function samlPopupFlow(ssoURL, triggerContainer, triggerText) {
12380
- const openPopup = () => {
12381
- if (samlAuthWindow === null || samlAuthWindow.closed) {
12382
- samlAuthWindow = window.open(ssoURL, '_blank', 'location=no,height=570,width=520,scrollbars=yes,status=yes');
12479
+ /**
12480
+ * Get underlying data given a point and the output column names.
12481
+ *
12482
+ * @param outputColumnNames
12483
+ * @param selectedPoints
12484
+ * @example
12485
+ * ```js
12486
+ * embed.on(EmbedEvent.CustomAction, e => {
12487
+ * const underlying = await e.answerService.getUnderlyingDataForPoint([
12488
+ * 'col name 1' // The column should exist in the data source.
12489
+ * ]);
12490
+ * const data = await underlying.fetchData(0, 100);
12491
+ * })
12492
+ * ```
12493
+ * @version
12494
+ * ThoughtSpot: 9.9.0.cl / SDK: 1.25.0
12495
+ */
12496
+ async getUnderlyingDataForPoint(outputColumnNames, selectedPoints) {
12497
+ if (!selectedPoints && !this.selectedPoints) {
12498
+ throw new Error('Needs to be triggered in context of a point');
12383
12499
  }
12384
- else {
12385
- samlAuthWindow.focus();
12500
+ if (!selectedPoints) {
12501
+ selectedPoints = getSelectedPointsForUnderlyingDataQuery(this.selectedPoints);
12386
12502
  }
12387
- };
12388
- const containerEl = getDOMNode(triggerContainer);
12389
- if (containerEl) {
12390
- containerEl.innerHTML = '<button id="ts-auth-btn" class="ts-auth-btn" style="margin: auto;"></button>';
12391
- const authElem = document.getElementById('ts-auth-btn');
12392
- authElem.textContent = triggerText;
12393
- authElem.addEventListener('click', openPopup, { once: true });
12394
- }
12395
- samlCompletionPromise = samlCompletionPromise
12396
- || new Promise((resolve, reject) => {
12397
- window.addEventListener('message', (e) => {
12398
- if (e.data.type === EmbedEvent.SAMLComplete) {
12399
- e.source.close();
12400
- resolve();
12401
- }
12402
- });
12503
+ const sourceDetail = await this.getSourceDetail();
12504
+ const ouputColumnGuids = getGuidsFromColumnNames(sourceDetail, outputColumnNames);
12505
+ const unAggAnswer = await graphqlQuery({
12506
+ query: getUnaggregatedAnswerSession,
12507
+ variables: {
12508
+ session: this.session,
12509
+ columns: selectedPoints,
12510
+ },
12511
+ thoughtSpotHost: this.thoughtSpotHost,
12403
12512
  });
12404
- return samlCompletionPromise;
12405
- }
12406
- /**
12407
- * Perform SAML authentication
12408
- *
12409
- * @param embedConfig The embed configuration
12410
- * @param ssoEndPoint
12411
- */
12412
- const doSSOAuth = async (embedConfig, ssoEndPoint) => {
12413
- const { thoughtSpotHost } = embedConfig;
12414
- const loggedIn = await isLoggedIn(thoughtSpotHost);
12415
- if (loggedIn) {
12416
- if (isAtSSORedirectUrl()) {
12417
- removeSSORedirectUrlMarker();
12513
+ const unaggAnswerSession = new AnswerService(unAggAnswer.id, unAggAnswer.answer, this.thoughtSpotHost);
12514
+ const currentColumns = new Set(unAggAnswer.answer.visualizations[0].columns
12515
+ .map((c) => c.column.referencedColumns[0].guid));
12516
+ const columnsToAdd = [...ouputColumnGuids].filter((col) => !currentColumns.has(col));
12517
+ if (columnsToAdd.length) {
12518
+ await unaggAnswerSession.addColumns(columnsToAdd);
12418
12519
  }
12419
- loggedInStatus = true;
12420
- return;
12520
+ const columnsToRemove = [...currentColumns].filter((col) => !ouputColumnGuids.has(col));
12521
+ if (columnsToRemove.length) {
12522
+ await unaggAnswerSession.removeColumns(columnsToRemove);
12523
+ }
12524
+ return unaggAnswerSession;
12421
12525
  }
12422
- // we have already tried authentication and it did not succeed, restore
12423
- // the current URL to the original one and invoke the callback.
12424
- if (isAtSSORedirectUrl()) {
12425
- removeSSORedirectUrlMarker();
12426
- loggedInStatus = false;
12427
- return;
12526
+ async executeQuery(query, variables) {
12527
+ const data = await graphqlQuery({
12528
+ query,
12529
+ variables: {
12530
+ session: this.session,
12531
+ ...variables,
12532
+ },
12533
+ thoughtSpotHost: this.thoughtSpotHost,
12534
+ isCompositeQuery: false,
12535
+ });
12536
+ this.session = deepMerge(this.session, (data === null || data === void 0 ? void 0 : data.id) || {});
12537
+ return data;
12428
12538
  }
12429
- const ssoURL = `${thoughtSpotHost}${ssoEndPoint}`;
12430
- if (embedConfig.inPopup) {
12431
- await samlPopupFlow(ssoURL, embedConfig.authTriggerContainer, embedConfig.authTriggerText);
12432
- loggedInStatus = await isLoggedIn(thoughtSpotHost);
12433
- return;
12539
+ getSession() {
12540
+ return this.session;
12434
12541
  }
12435
- window.location.href = ssoURL;
12436
- };
12437
- const doSamlAuth = async (embedConfig) => {
12438
- const { thoughtSpotHost } = embedConfig;
12439
- // redirect for SSO, when the SSO authentication is done, this page will be
12440
- // loaded again and the same JS will execute again.
12441
- const ssoRedirectUrl = embedConfig.inPopup
12442
- ? `${thoughtSpotHost}/v2/#/embed/saml-complete`
12443
- : getRedirectUrl(window.location.href, SSO_REDIRECTION_MARKER_GUID, embedConfig.redirectPath);
12444
- // bring back the page to the same URL
12445
- const ssoEndPoint = `${EndPoints.SAML_LOGIN_TEMPLATE(encodeURIComponent(ssoRedirectUrl))}`;
12446
- await doSSOAuth(embedConfig, ssoEndPoint);
12447
- return loggedInStatus;
12448
- };
12449
- const doOIDCAuth = async (embedConfig) => {
12450
- const { thoughtSpotHost } = embedConfig;
12451
- // redirect for SSO, when the SSO authentication is done, this page will be
12452
- // loaded again and the same JS will execute again.
12453
- const ssoRedirectUrl = embedConfig.noRedirect || embedConfig.inPopup
12454
- ? `${thoughtSpotHost}/v2/#/embed/saml-complete`
12455
- : getRedirectUrl(window.location.href, SSO_REDIRECTION_MARKER_GUID, embedConfig.redirectPath);
12456
- // bring back the page to the same URL
12457
- const ssoEndPoint = `${EndPoints.OIDC_LOGIN_TEMPLATE(encodeURIComponent(ssoRedirectUrl))}`;
12458
- await doSSOAuth(embedConfig, ssoEndPoint);
12459
- return loggedInStatus;
12460
- };
12542
+ }
12461
12543
  /**
12462
- * Perform authentication on the ThoughtSpot cluster
12463
12544
  *
12464
- * @param embedConfig The embed configuration
12545
+ * @param sourceDetail
12546
+ * @param colNames
12465
12547
  */
12466
- const authenticate = async (embedConfig) => {
12467
- const { authType } = embedConfig;
12468
- switch (authType) {
12469
- case AuthType.SSO:
12470
- case AuthType.SAMLRedirect:
12471
- case AuthType.SAML:
12472
- return doSamlAuth(embedConfig);
12473
- case AuthType.OIDC:
12474
- case AuthType.OIDCRedirect:
12475
- return doOIDCAuth(embedConfig);
12476
- case AuthType.AuthServer:
12477
- case AuthType.TrustedAuthToken:
12478
- return doTokenAuth(embedConfig);
12479
- case AuthType.TrustedAuthTokenCookieless:
12480
- return doCookielessTokenAuth(embedConfig);
12481
- case AuthType.Basic:
12482
- return doBasicAuth(embedConfig);
12483
- default:
12484
- return Promise.resolve(true);
12485
- }
12486
- };
12487
-
12488
- /* eslint-disable camelcase */
12489
- let config = {};
12490
- const CONFIG_DEFAULTS = {
12491
- loginFailedMessage: 'Not logged in',
12492
- authTriggerText: 'Authorize',
12493
- authType: AuthType.None,
12494
- };
12495
- let authPromise;
12548
+ function getGuidsFromColumnNames(sourceDetail, colNames) {
12549
+ const cols = sourceDetail.columns.reduce((colSet, col) => {
12550
+ colSet[col.name] = col;
12551
+ return colSet;
12552
+ }, {});
12553
+ return new Set(colNames.map((colName) => {
12554
+ const col = cols[colName];
12555
+ return col.id;
12556
+ }));
12557
+ }
12496
12558
  /**
12497
- * Gets the configuration embed was initialized with.
12498
12559
  *
12499
- * @returns {@link EmbedConfig} The configuration embed was initialized with.
12500
- * @version SDK: 1.19.0 | ThoughtSpot: *
12501
- * @group Global methods
12502
- */
12503
- const getEmbedConfig = () => config;
12504
- const getAuthPromise = () => authPromise;
12505
- /**
12506
- * Perform authentication on the ThoughtSpot app as applicable.
12560
+ * @param selectedPoints
12507
12561
  */
12508
- const handleAuth = () => {
12509
- authPromise = authenticate(config);
12510
- authPromise.then((isLoggedIn) => {
12511
- if (!isLoggedIn) {
12512
- notifyAuthFailure(AuthFailureType.SDK);
12562
+ function getSelectedPointsForUnderlyingDataQuery(selectedPoints) {
12563
+ const underlyingDataPoint = [];
12564
+ /**
12565
+ *
12566
+ * @param colVal
12567
+ */
12568
+ function addPointFromColVal(colVal) {
12569
+ var _a;
12570
+ const dataType = colVal.column.dataType;
12571
+ const id = colVal.column.id;
12572
+ let dataValue;
12573
+ if (dataType === 'DATE') {
12574
+ if (Number.isFinite(colVal.value)) {
12575
+ dataValue = [{
12576
+ epochRange: {
12577
+ startEpoch: colVal.value,
12578
+ },
12579
+ }];
12580
+ // Case for custom calendar.
12581
+ }
12582
+ else if ((_a = colVal.value) === null || _a === void 0 ? void 0 : _a.v) {
12583
+ dataValue = [{
12584
+ epochRange: {
12585
+ startEpoch: colVal.value.v.s,
12586
+ endEpoch: colVal.value.v.e,
12587
+ },
12588
+ }];
12589
+ }
12513
12590
  }
12514
12591
  else {
12515
- notifyAuthSDKSuccess();
12592
+ dataValue = [{ value: colVal.value }];
12516
12593
  }
12517
- }, () => {
12518
- notifyAuthFailure(AuthFailureType.SDK);
12519
- });
12520
- return authPromise;
12521
- };
12522
- const hostUrlToFeatureUrl = {
12523
- [PrefetchFeatures.SearchEmbed]: (url) => `${url}v2/#/embed/answer`,
12524
- [PrefetchFeatures.LiveboardEmbed]: (url) => url,
12525
- [PrefetchFeatures.FullApp]: (url) => url,
12526
- [PrefetchFeatures.VizEmbed]: (url) => url,
12527
- };
12528
- /**
12529
- *
12530
- */
12531
- function disableAutoLogin() {
12532
- config.autoLogin = false;
12533
- }
12534
- let renderQueue = Promise.resolve();
12535
- /**
12536
- * Renders functions in a queue, resolves to next function only after the callback next
12537
- * is called
12538
- *
12539
- * @param fn The function being registered
12540
- */
12541
- const renderInQueue = (fn) => {
12542
- const { queueMultiRenders = false } = config;
12543
- if (queueMultiRenders) {
12544
- renderQueue = renderQueue.then(() => new Promise((res) => fn(res)));
12545
- return renderQueue;
12594
+ underlyingDataPoint.push({
12595
+ columnId: colVal.column.id,
12596
+ dataValue,
12597
+ });
12546
12598
  }
12547
- // Sending an empty function to keep it consistent with the above usage.
12548
- return fn(() => { }); // eslint-disable-line @typescript-eslint/no-empty-function
12549
- };
12599
+ selectedPoints.forEach((p) => {
12600
+ p.selectedAttributes.forEach(addPointFromColVal);
12601
+ });
12602
+ return underlyingDataPoint;
12603
+ }
12550
12604
 
12551
12605
  /**
12552
12606
  *
@@ -12584,9 +12638,9 @@ function processAuthInit(e) {
12584
12638
  * @param containerEl
12585
12639
  */
12586
12640
  function processNoCookieAccess(e, containerEl) {
12587
- const { loginFailedMessage, suppressNoCookieAccessAlert, ignoreNoCookieAccess, } = getEmbedConfig();
12641
+ const { loginFailedMessage, suppressNoCookieAccessAlert, ignoreNoCookieAccess, suppressErrorAlerts, } = getEmbedConfig();
12588
12642
  if (!ignoreNoCookieAccess) {
12589
- if (!suppressNoCookieAccessAlert) {
12643
+ if (!suppressNoCookieAccessAlert && !suppressErrorAlerts) {
12590
12644
  // eslint-disable-next-line no-alert
12591
12645
  alert('Third party cookie access is blocked on this browser, please allow third party cookies for this to work properly. \nYou can use `suppressNoCookieAccessAlert` to suppress this message.');
12592
12646
  }
@@ -12704,7 +12758,7 @@ function processTrigger(iFrame, messageType, thoughtSpotHost, data) {
12704
12758
  });
12705
12759
  }
12706
12760
 
12707
- var name="@thoughtspot/visual-embed-sdk";var version="1.25.0";var description="ThoughtSpot Embed SDK";var module="lib/src/index.js";var main="dist/tsembed.js";var types="lib/src/index.d.ts";var files=["dist/**","lib/**","src/**","cjs/**"];var exports={".":{"import":"./lib/src/index.js",require:"./cjs/src/index.js",types:"./lib/src/index.d.ts"},"./react":{"import":"./lib/src/react/all-types-export.js",require:"./cjs/src/react/all-types-export.js",types:"./lib/src/react/all-types-export.d.ts"},"./lib/src/react":{"import":"./lib/src/react/all-types-export.js",require:"./cjs/src/react/all-types-export.js",types:"./lib/src/react/all-types-export.d.ts"}};var typesVersions={"*":{react:["./lib/src/react/all-types-export.d.ts"]}};var scripts={lint:"eslint 'src/**'","lint:fix":"eslint 'src/**/*.*' --fix",tsc:"tsc -p . --incremental false; tsc -p . --incremental false --module commonjs --outDir cjs",start:"gatsby develop","build:gatsby":"npm run clean:gatsby && gatsby build --prefix-paths","build:gatsby:noprefix":"npm run clean:gatsby && gatsby build","serve:gatsby":"gatsby serve","clean:gatsby":"gatsby clean","build-and-publish":"npm run build:gatsby && npm run publish","bundle-dts-file":"dts-bundle --name @thoughtspot/visual-embed-sdk --out visual-embed-sdk.d.ts --main lib/src/index.d.ts","bundle-dts":"dts-bundle --name ../../dist/visual-embed-sdk --main lib/src/index.d.ts --outputAsModuleFolder=true","bundle-dts-react":"dts-bundle --name ../../../dist/visual-embed-sdk-react --main lib/src/react/index.d.ts --outputAsModuleFolder=true","bundle-dts-react-full":"dts-bundle --name ../../../dist/visual-embed-sdk-react-full --main lib/src/react/all-types-export.d.ts --outputAsModuleFolder=true",build:"rollup -c",watch:"rollup -cw","docs-cmd":"node scripts/gatsby-commands.js",docgen:"typedoc --tsconfig tsconfig.json --theme typedoc-theme","test-sdk":"jest -c jest.config.sdk.js --runInBand","test-docs":"jest -c jest.config.docs.js",test:"npm run test-sdk && npm run test-docs",posttest:"cat ./coverage/sdk/lcov.info | coveralls","is-publish-allowed":"node scripts/is-publish-allowed.js",prepublishOnly:"npm run is-publish-allowed && npm run test && npm run tsc && npm run bundle-dts-file && npm run bundle-dts && npm run bundle-dts-react && npm run bundle-dts-react-full && npm run build","check-size":"npm run build && size-limit","publish-dev":"npm publish --tag dev","publish-prod":"npm publish --tag latest"};var peerDependencies={react:"> 16.8.0","react-dom":"> 16.8.0"};var dependencies={algoliasearch:"^4.10.5",classnames:"^2.3.1",dompurify:"^2.3.4","eslint-plugin-comment-length":"^0.9.2","eslint-plugin-jsdoc":"^40.1.0",eventemitter3:"^4.0.7","gatsby-plugin-vercel":"^1.0.3","html-react-parser":"^1.4.12",lodash:"^4.17.21","mixpanel-browser":"^2.45.0","ts-deepmerge":"^6.0.2",tslib:"^2.5.3","use-deep-compare-effect":"^1.8.1"};var devDependencies={"@mdx-js/mdx":"^1.6.22","@mdx-js/react":"^1.6.22","@react-icons/all-files":"^4.1.0","@rollup/plugin-commonjs":"^18.0.0","@rollup/plugin-json":"^4.1.0","@rollup/plugin-node-resolve":"^11.2.1","@rollup/plugin-replace":"^5.0.2","@size-limit/preset-big-lib":"^8.2.6","@testing-library/dom":"^7.31.0","@testing-library/jest-dom":"^5.14.1","@testing-library/react":"^11.2.7","@testing-library/user-event":"^13.1.8","@types/jest":"^22.2.3","@types/mixpanel-browser":"^2.35.6","@types/react-test-renderer":"^17.0.1","@typescript-eslint/eslint-plugin":"^4.6.0","@typescript-eslint/parser":"^4.6.0",asciidoctor:"^2.2.1","babel-jest":"^26.6.3","babel-preset-gatsby":"^1.10.0","command-line-args":"^5.1.1",coveralls:"^3.1.0","current-git-branch":"^1.1.0","dts-bundle":"^0.7.3",eslint:"^7.12.1","eslint-config-airbnb-base":"^14.2.0","eslint-config-prettier":"^6.15.0","eslint-import-resolver-typescript":"^2.3.0","eslint-plugin-import":"^2.22.1","eslint-plugin-prettier":"^3.1.4","eslint-plugin-react-hooks":"^4.2.0","fs-extra":"^10.0.0",gatsby:"3.13.1","gatsby-plugin-algolia":"^0.22.2","gatsby-plugin-catch-links":"^3.1.0","gatsby-plugin-env-variables":"^2.1.0","gatsby-plugin-intl":"^0.3.3","gatsby-plugin-manifest":"^3.2.0","gatsby-plugin-output":"^0.1.3","gatsby-plugin-sass":"6.7.0","gatsby-plugin-sitemap":"^4.10.0","gatsby-source-filesystem":"3.1.0","gatsby-transformer-asciidoc":"2.1.0","gatsby-transformer-rehype":"2.0.0","gh-pages":"^3.1.0","highlight.js":"^10.6.0","html-to-text":"^8.0.0","identity-obj-proxy":"^3.0.0","istanbul-merge":"^1.1.1",jest:"^26.6.3","jest-fetch-mock":"^3.0.3",jsdom:"^17.0.0","node-sass":"^8.0.0",prettier:"2.1.2",react:"^16.14.0","react-dom":"^16.14.0","react-resizable":"^1.11.0","react-resize-detector":"^6.6.0","react-test-renderer":"^17.0.2","react-use-flexsearch":"^0.1.1",rollup:"2.30.0","rollup-plugin-typescript2":"0.27.3","ts-jest":"^26.5.5","ts-loader":"8.0.4",typedoc:"0.21.6","typedoc-plugin-toc-group":"thoughtspot/typedoc-plugin-toc-group",typescript:"^4.9.4","url-search-params-polyfill":"^8.1.0",util:"^0.12.4"};var author="ThoughtSpot";var email="support@thoughtspot.com";var license="ThoughtSpot Development Tools End User License Agreement";var directories={lib:"lib"};var repository={type:"git",url:"git+https://github.com/thoughtspot/visual-embed-sdk.git"};var publishConfig={registry:"https://registry.npmjs.org"};var keywords=["thoughtspot","everywhere","embed","sdk","analytics"];var bugs={url:"https://github.com/thoughtspot/visual-embed-sdk/issues"};var homepage="https://github.com/thoughtspot/visual-embed-sdk#readme";var globals={window:{}};var pkgInfo = {name:name,version:version,description:description,module:module,main:main,types:types,files:files,exports:exports,typesVersions:typesVersions,"size-limit":[{path:"dist/tsembed.js",limit:"43 kB"}],scripts:scripts,peerDependencies:peerDependencies,dependencies:dependencies,devDependencies:devDependencies,author:author,email:email,license:license,directories:directories,repository:repository,publishConfig:publishConfig,keywords:keywords,bugs:bugs,homepage:homepage,globals:globals};
12761
+ var name="@thoughtspot/visual-embed-sdk";var version="1.26.0-token-cache.0";var description="ThoughtSpot Embed SDK";var module="lib/src/index.js";var main="dist/tsembed.js";var types="lib/src/index.d.ts";var files=["dist/**","lib/**","src/**","cjs/**"];var exports={".":{"import":"./lib/src/index.js",require:"./cjs/src/index.js",types:"./lib/src/index.d.ts"},"./react":{"import":"./lib/src/react/all-types-export.js",require:"./cjs/src/react/all-types-export.js",types:"./lib/src/react/all-types-export.d.ts"},"./lib/src/react":{"import":"./lib/src/react/all-types-export.js",require:"./cjs/src/react/all-types-export.js",types:"./lib/src/react/all-types-export.d.ts"}};var typesVersions={"*":{react:["./lib/src/react/all-types-export.d.ts"]}};var scripts={lint:"eslint 'src/**'","lint:fix":"eslint 'src/**/*.*' --fix",tsc:"tsc -p . --incremental false; tsc -p . --incremental false --module commonjs --outDir cjs",start:"gatsby develop","build:gatsby":"npm run clean:gatsby && gatsby build --prefix-paths","build:gatsby:noprefix":"npm run clean:gatsby && gatsby build","serve:gatsby":"gatsby serve","clean:gatsby":"gatsby clean","build-and-publish":"npm run build:gatsby && npm run publish","bundle-dts-file":"dts-bundle --name @thoughtspot/visual-embed-sdk --out visual-embed-sdk.d.ts --main lib/src/index.d.ts","bundle-dts":"dts-bundle --name ../../dist/visual-embed-sdk --main lib/src/index.d.ts --outputAsModuleFolder=true","bundle-dts-react":"dts-bundle --name ../../../dist/visual-embed-sdk-react --main lib/src/react/index.d.ts --outputAsModuleFolder=true","bundle-dts-react-full":"dts-bundle --name ../../../dist/visual-embed-sdk-react-full --main lib/src/react/all-types-export.d.ts --outputAsModuleFolder=true",build:"rollup -c",watch:"rollup -cw","docs-cmd":"node scripts/gatsby-commands.js",docgen:"typedoc --tsconfig tsconfig.json --theme typedoc-theme","test-sdk":"jest -c jest.config.sdk.js --runInBand","test-docs":"jest -c jest.config.docs.js",test:"npm run test-sdk && npm run test-docs",posttest:"cat ./coverage/sdk/lcov.info | coveralls","is-publish-allowed":"node scripts/is-publish-allowed.js",prepublishOnly:"npm run is-publish-allowed && npm run test && npm run tsc && npm run bundle-dts-file && npm run bundle-dts && npm run bundle-dts-react && npm run bundle-dts-react-full && npm run build","check-size":"npm run build && size-limit","publish-dev":"npm publish --tag dev","publish-prod":"npm publish --tag latest"};var peerDependencies={react:"> 16.8.0","react-dom":"> 16.8.0"};var dependencies={algoliasearch:"^4.10.5",classnames:"^2.3.1",dompurify:"^2.3.4","eslint-plugin-comment-length":"^0.9.2","eslint-plugin-jsdoc":"^40.1.0",eventemitter3:"^4.0.7","gatsby-plugin-vercel":"^1.0.3","html-react-parser":"^1.4.12",lodash:"^4.17.21","mixpanel-browser":"^2.45.0","ts-deepmerge":"^6.0.2",tslib:"^2.5.3","use-deep-compare-effect":"^1.8.1"};var devDependencies={"@mdx-js/mdx":"^1.6.22","@mdx-js/react":"^1.6.22","@react-icons/all-files":"^4.1.0","@rollup/plugin-commonjs":"^18.0.0","@rollup/plugin-json":"^4.1.0","@rollup/plugin-node-resolve":"^11.2.1","@rollup/plugin-replace":"^5.0.2","@size-limit/preset-big-lib":"^8.2.6","@testing-library/dom":"^7.31.0","@testing-library/jest-dom":"^5.14.1","@testing-library/react":"^11.2.7","@testing-library/user-event":"^13.1.8","@types/jest":"^22.2.3","@types/mixpanel-browser":"^2.35.6","@types/react-test-renderer":"^17.0.1","@typescript-eslint/eslint-plugin":"^4.6.0","@typescript-eslint/parser":"^4.6.0",asciidoctor:"^2.2.1","babel-jest":"^26.6.3","babel-preset-gatsby":"^1.10.0","command-line-args":"^5.1.1",coveralls:"^3.1.0","current-git-branch":"^1.1.0","dts-bundle":"^0.7.3",eslint:"^7.12.1","eslint-config-airbnb-base":"^14.2.0","eslint-config-prettier":"^6.15.0","eslint-import-resolver-typescript":"^2.3.0","eslint-plugin-import":"^2.22.1","eslint-plugin-prettier":"^3.1.4","eslint-plugin-react-hooks":"^4.2.0","fs-extra":"^10.0.0",gatsby:"3.13.1","gatsby-plugin-algolia":"^0.22.2","gatsby-plugin-catch-links":"^3.1.0","gatsby-plugin-env-variables":"^2.1.0","gatsby-plugin-intl":"^0.3.3","gatsby-plugin-manifest":"^3.2.0","gatsby-plugin-output":"^0.1.3","gatsby-plugin-sass":"6.7.0","gatsby-plugin-sitemap":"^4.10.0","gatsby-source-filesystem":"3.1.0","gatsby-transformer-asciidoc":"2.1.0","gatsby-transformer-rehype":"2.0.0","gh-pages":"^3.1.0","highlight.js":"^10.6.0","html-to-text":"^8.0.0","identity-obj-proxy":"^3.0.0","istanbul-merge":"^1.1.1",jest:"^26.6.3","jest-fetch-mock":"^3.0.3",jsdom:"^17.0.0","node-sass":"^8.0.0",prettier:"2.1.2",react:"^16.14.0","react-dom":"^16.14.0","react-resizable":"^1.11.0","react-resize-detector":"^6.6.0","react-test-renderer":"^17.0.2","react-use-flexsearch":"^0.1.1",rollup:"2.30.0","rollup-plugin-typescript2":"0.27.3","ts-jest":"^26.5.5","ts-loader":"8.0.4",typedoc:"0.21.6","typedoc-plugin-toc-group":"thoughtspot/typedoc-plugin-toc-group",typescript:"^4.9.4","url-search-params-polyfill":"^8.1.0",util:"^0.12.4"};var author="ThoughtSpot";var email="support@thoughtspot.com";var license="ThoughtSpot Development Tools End User License Agreement";var directories={lib:"lib"};var repository={type:"git",url:"git+https://github.com/thoughtspot/visual-embed-sdk.git"};var publishConfig={registry:"https://registry.npmjs.org"};var keywords=["thoughtspot","everywhere","embed","sdk","analytics"];var bugs={url:"https://github.com/thoughtspot/visual-embed-sdk/issues"};var homepage="https://github.com/thoughtspot/visual-embed-sdk#readme";var globals={window:{}};var pkgInfo = {name:name,version:version,description:description,module:module,main:main,types:types,files:files,exports:exports,typesVersions:typesVersions,"size-limit":[{path:"dist/tsembed.js",limit:"43 kB"}],scripts:scripts,peerDependencies:peerDependencies,dependencies:dependencies,devDependencies:devDependencies,author:author,email:email,license:license,directories:directories,repository:repository,publishConfig:publishConfig,keywords:keywords,bugs:bugs,homepage:homepage,globals:globals};
12708
12762
 
12709
12763
  /**
12710
12764
  * Copyright (c) 2022
@@ -13915,7 +13969,7 @@ class SearchEmbed extends TsEmbed {
13915
13969
  }
13916
13970
  getEmbedParams() {
13917
13971
  var _a;
13918
- const { hideResults, expandAllDataSource, enableSearchAssist, forceTable, searchOptions, runtimeFilters, dataSource, dataSources, excludeRuntimeFiltersfromURL, dataPanelV2 = false, useLastSelectedSources = false, runtimeParameters, } = this.viewConfig;
13972
+ const { hideResults, enableSearchAssist, forceTable, searchOptions, runtimeFilters, dataSource, dataSources, excludeRuntimeFiltersfromURL, dataPanelV2 = false, useLastSelectedSources = false, runtimeParameters, } = this.viewConfig;
13919
13973
  const queryParams = this.getBaseQueryParams();
13920
13974
  queryParams[Param.HideActions] = [
13921
13975
  ...((_a = queryParams[Param.HideActions]) !== null && _a !== void 0 ? _a : []),
@@ -13984,7 +14038,8 @@ class SearchEmbed extends TsEmbed {
13984
14038
  const src = this.getIFrameSrc(answerId);
13985
14039
  this.renderIFrame(src);
13986
14040
  getAuthPromise().then(() => {
13987
- if (checkReleaseVersionInBeta(getReleaseVersion(), getEmbedConfig().suppressSearchEmbedBetaWarning)) {
14041
+ if (checkReleaseVersionInBeta(getReleaseVersion(), getEmbedConfig().suppressSearchEmbedBetaWarning
14042
+ || getEmbedConfig().suppressErrorAlerts)) {
13988
14043
  alert(ERROR_MESSAGE.SEARCHEMBED_BETA_WRANING_MESSAGE);
13989
14044
  }
13990
14045
  });