utneque 1.0.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 (431) hide show
  1. package/.editorconfig +10 -0
  2. package/.eslintrc.isomorphic.js +26 -0
  3. package/.eslintrc.js +86 -0
  4. package/.gitattributes +1 -0
  5. package/.github/workflows/ci.yml +33 -0
  6. package/.github/workflows/deploy-browser-cdn-candidate.yml +51 -0
  7. package/.github/workflows/deploy-releases.yml +178 -0
  8. package/.nvmrc +1 -0
  9. package/.prettierrc +7 -0
  10. package/.vscode/extensions.json +3 -0
  11. package/.vscode/launch.json +81 -0
  12. package/.vscode/settings.json +41 -0
  13. package/.yarn/plugins/@yarnpkg/plugin-constraints.cjs +52 -0
  14. package/.yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs +546 -0
  15. package/.yarn/plugins/@yarnpkg/plugin-typescript.cjs +9 -0
  16. package/.yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs +28 -0
  17. package/.yarn/releases/yarn-3.4.1.cjs +873 -0
  18. package/.yarnrc.yml +15 -0
  19. package/jest.config.js +18 -0
  20. package/package.json +59 -0
  21. package/packages/browser/.eslintrc.js +9 -0
  22. package/packages/browser/.lintstagedrc.js +1 -0
  23. package/packages/browser/ARCHITECTURE.md +48 -0
  24. package/packages/browser/LICENSE.MD +45 -0
  25. package/packages/browser/Makefile +64 -0
  26. package/packages/browser/README.md +227 -0
  27. package/packages/browser/e2e-tests/local-server.ts +28 -0
  28. package/packages/browser/e2e-tests/performance/ajs-perf-browser.test.ts +75 -0
  29. package/packages/browser/jest.config.js +15 -0
  30. package/packages/browser/jest.setup.js +10 -0
  31. package/packages/browser/package.json +106 -0
  32. package/packages/browser/qa/README.md +41 -0
  33. package/packages/browser/qa/__fixtures__/snippets.ts +148 -0
  34. package/packages/browser/qa/__tests__/backwards-compatibility.test.ts +180 -0
  35. package/packages/browser/qa/__tests__/destinations.test.ts +101 -0
  36. package/packages/browser/qa/__tests__/smoke.test.ts +170 -0
  37. package/packages/browser/qa/lib/benchmark.ts +36 -0
  38. package/packages/browser/qa/lib/browser.ts +28 -0
  39. package/packages/browser/qa/lib/jest-reporter.js +57 -0
  40. package/packages/browser/qa/lib/runner.ts +142 -0
  41. package/packages/browser/qa/lib/schema.ts +59 -0
  42. package/packages/browser/qa/lib/server.ts +54 -0
  43. package/packages/browser/qa/lib/stats.ts +52 -0
  44. package/packages/browser/scripts/build-prep.sh +7 -0
  45. package/packages/browser/scripts/ci.sh +15 -0
  46. package/packages/browser/scripts/release.js +121 -0
  47. package/packages/browser/scripts/release.sh +9 -0
  48. package/packages/browser/scripts/run.sh +8 -0
  49. package/packages/browser/src/browser/__tests__/analytics-lazy-init.integration.test.ts +51 -0
  50. package/packages/browser/src/browser/__tests__/analytics-pre-init.integration.test.ts +440 -0
  51. package/packages/browser/src/browser/__tests__/anon-id-and-reset.integration.test.ts +73 -0
  52. package/packages/browser/src/browser/__tests__/cdn.test.ts +53 -0
  53. package/packages/browser/src/browser/__tests__/csp-detection.test.ts +140 -0
  54. package/packages/browser/src/browser/__tests__/inspector.integration.test.ts +121 -0
  55. package/packages/browser/src/browser/__tests__/integration.test.ts +1213 -0
  56. package/packages/browser/src/browser/__tests__/integrations.integration.test.ts +260 -0
  57. package/packages/browser/src/browser/__tests__/page-enrichment.integration.test.ts +216 -0
  58. package/packages/browser/src/browser/__tests__/query-string.integration.test.ts +116 -0
  59. package/packages/browser/src/browser/__tests__/standalone-analytics.test.ts +303 -0
  60. package/packages/browser/src/browser/__tests__/standalone-errors.test.ts +136 -0
  61. package/packages/browser/src/browser/__tests__/standalone.test.ts +97 -0
  62. package/packages/browser/src/browser/__tests__/typedef-tests/analytics-browser.ts +150 -0
  63. package/packages/browser/src/browser/__tests__/update-cdn-settings.test.ts +71 -0
  64. package/packages/browser/src/browser/browser-umd.ts +19 -0
  65. package/packages/browser/src/browser/index.ts +486 -0
  66. package/packages/browser/src/browser/standalone-analytics.ts +62 -0
  67. package/packages/browser/src/browser/standalone-interface.ts +11 -0
  68. package/packages/browser/src/browser/standalone.ts +92 -0
  69. package/packages/browser/src/core/__tests__/track-form.test.ts +193 -0
  70. package/packages/browser/src/core/__tests__/track-link.test.ts +252 -0
  71. package/packages/browser/src/core/analytics/__tests__/integration.test.ts +334 -0
  72. package/packages/browser/src/core/analytics/__tests__/test-plugins.ts +94 -0
  73. package/packages/browser/src/core/analytics/index.ts +672 -0
  74. package/packages/browser/src/core/analytics/interfaces.ts +100 -0
  75. package/packages/browser/src/core/arguments-resolver/__tests__/index.test.ts +524 -0
  76. package/packages/browser/src/core/arguments-resolver/index.ts +200 -0
  77. package/packages/browser/src/core/auto-track.ts +152 -0
  78. package/packages/browser/src/core/buffer/__tests__/index.test.ts +455 -0
  79. package/packages/browser/src/core/buffer/index.ts +371 -0
  80. package/packages/browser/src/core/callback/index.ts +1 -0
  81. package/packages/browser/src/core/connection/__tests__/index.test.ts +25 -0
  82. package/packages/browser/src/core/connection/index.ts +13 -0
  83. package/packages/browser/src/core/constants/index.ts +1 -0
  84. package/packages/browser/src/core/context/__tests__/index.test.ts +201 -0
  85. package/packages/browser/src/core/context/index.ts +21 -0
  86. package/packages/browser/src/core/environment/index.ts +7 -0
  87. package/packages/browser/src/core/events/__tests__/index.test.ts +450 -0
  88. package/packages/browser/src/core/events/index.ts +280 -0
  89. package/packages/browser/src/core/events/interfaces.ts +36 -0
  90. package/packages/browser/src/core/inspector/index.ts +14 -0
  91. package/packages/browser/src/core/page/__tests__/index.test.ts +130 -0
  92. package/packages/browser/src/core/page/add-page-context.ts +33 -0
  93. package/packages/browser/src/core/page/get-page-context.ts +140 -0
  94. package/packages/browser/src/core/page/index.ts +2 -0
  95. package/packages/browser/src/core/plugin/index.ts +12 -0
  96. package/packages/browser/src/core/query-string/__tests__/gracefulDecodeURIComponent.test.ts +17 -0
  97. package/packages/browser/src/core/query-string/__tests__/index.test.ts +149 -0
  98. package/packages/browser/src/core/query-string/__tests__/pickPrefix.test.ts +31 -0
  99. package/packages/browser/src/core/query-string/__tests__/useQueryString.test.ts +60 -0
  100. package/packages/browser/src/core/query-string/gracefulDecodeURIComponent.ts +16 -0
  101. package/packages/browser/src/core/query-string/index.ts +64 -0
  102. package/packages/browser/src/core/query-string/pickPrefix.ts +20 -0
  103. package/packages/browser/src/core/queue/__tests__/event-queue.test.ts +82 -0
  104. package/packages/browser/src/core/queue/event-queue.ts +22 -0
  105. package/packages/browser/src/core/session/__tests__/index.test.ts +41 -0
  106. package/packages/browser/src/core/session/index.ts +107 -0
  107. package/packages/browser/src/core/stats/__tests__/index.test.ts +15 -0
  108. package/packages/browser/src/core/stats/__tests__/remote-metrics.test.ts +189 -0
  109. package/packages/browser/src/core/stats/index.ts +15 -0
  110. package/packages/browser/src/core/stats/remote-metrics.ts +144 -0
  111. package/packages/browser/src/core/storage/__tests__/cookieStorage.test.ts +58 -0
  112. package/packages/browser/src/core/storage/__tests__/localStorage.test.ts +70 -0
  113. package/packages/browser/src/core/storage/__tests__/test-helpers.ts +26 -0
  114. package/packages/browser/src/core/storage/__tests__/universalStorage.test.ts +167 -0
  115. package/packages/browser/src/core/storage/cookieStorage.ts +80 -0
  116. package/packages/browser/src/core/storage/index.ts +64 -0
  117. package/packages/browser/src/core/storage/localStorage.ts +45 -0
  118. package/packages/browser/src/core/storage/memoryStorage.ts +22 -0
  119. package/packages/browser/src/core/storage/settings.ts +23 -0
  120. package/packages/browser/src/core/storage/types.ts +49 -0
  121. package/packages/browser/src/core/storage/universalStorage.ts +78 -0
  122. package/packages/browser/src/core/user/__tests__/index.test.ts +922 -0
  123. package/packages/browser/src/core/user/__tests__/migrate.test.ts +101 -0
  124. package/packages/browser/src/core/user/__tests__/session.test.ts +136 -0
  125. package/packages/browser/src/core/user/__tests__/tld.test.ts +36 -0
  126. package/packages/browser/src/core/user/index.ts +399 -0
  127. package/packages/browser/src/core/user/migrate.ts +126 -0
  128. package/packages/browser/src/core/user/tld.ts +65 -0
  129. package/packages/browser/src/core/user/vendor/crypto-es/LICENSE +53 -0
  130. package/packages/browser/src/core/user/vendor/crypto-es/lib/aes.ts +302 -0
  131. package/packages/browser/src/core/user/vendor/crypto-es/lib/cipher-core.ts +922 -0
  132. package/packages/browser/src/core/user/vendor/crypto-es/lib/core.ts +806 -0
  133. package/packages/browser/src/core/user/vendor/crypto-es/lib/enc-base64.ts +110 -0
  134. package/packages/browser/src/core/user/vendor/crypto-es/lib/evpkdf.ts +110 -0
  135. package/packages/browser/src/core/user/vendor/crypto-es/lib/md5.ts +238 -0
  136. package/packages/browser/src/core/user/vendor/readme.md +7 -0
  137. package/packages/browser/src/generated/__tests__/version.test.ts +18 -0
  138. package/packages/browser/src/generated/version.ts +2 -0
  139. package/packages/browser/src/index.ts +13 -0
  140. package/packages/browser/src/lib/__tests__/embedded-write-key.test.ts +15 -0
  141. package/packages/browser/src/lib/__tests__/fetch.test.ts +35 -0
  142. package/packages/browser/src/lib/__tests__/get-process-env.test.ts +5 -0
  143. package/packages/browser/src/lib/__tests__/group-by.test.ts +96 -0
  144. package/packages/browser/src/lib/__tests__/is-plan-event-enabled.test.ts +36 -0
  145. package/packages/browser/src/lib/__tests__/is-thenable.test.ts +39 -0
  146. package/packages/browser/src/lib/__tests__/merged-options.test.ts +123 -0
  147. package/packages/browser/src/lib/__tests__/on-page-change.test.ts +74 -0
  148. package/packages/browser/src/lib/__tests__/parse-cdn.test.ts +88 -0
  149. package/packages/browser/src/lib/__tests__/pick.test.ts +34 -0
  150. package/packages/browser/src/lib/__tests__/pick.typedef.ts +39 -0
  151. package/packages/browser/src/lib/bind-all.ts +19 -0
  152. package/packages/browser/src/lib/browser-polyfill.ts +23 -0
  153. package/packages/browser/src/lib/client-hints/__tests__/index.test.ts +66 -0
  154. package/packages/browser/src/lib/client-hints/index.ts +16 -0
  155. package/packages/browser/src/lib/client-hints/interfaces.ts +42 -0
  156. package/packages/browser/src/lib/create-deferred.ts +16 -0
  157. package/packages/browser/src/lib/csp-detection.ts +8 -0
  158. package/packages/browser/src/lib/embedded-write-key.ts +24 -0
  159. package/packages/browser/src/lib/fetch.ts +10 -0
  160. package/packages/browser/src/lib/get-global.ts +16 -0
  161. package/packages/browser/src/lib/get-process-env.ts +11 -0
  162. package/packages/browser/src/lib/global-analytics-helper.ts +31 -0
  163. package/packages/browser/src/lib/group-by.ts +30 -0
  164. package/packages/browser/src/lib/is-plan-event-enabled.ts +20 -0
  165. package/packages/browser/src/lib/is-thenable.ts +9 -0
  166. package/packages/browser/src/lib/load-script.ts +66 -0
  167. package/packages/browser/src/lib/merged-options.ts +46 -0
  168. package/packages/browser/src/lib/on-page-change.ts +29 -0
  169. package/packages/browser/src/lib/p-while.ts +12 -0
  170. package/packages/browser/src/lib/parse-cdn.ts +56 -0
  171. package/packages/browser/src/lib/pick.ts +28 -0
  172. package/packages/browser/src/lib/priority-queue/__tests__/backoff.test.ts +23 -0
  173. package/packages/browser/src/lib/priority-queue/__tests__/index.test.ts +158 -0
  174. package/packages/browser/src/lib/priority-queue/__tests__/persisted.test.ts +228 -0
  175. package/packages/browser/src/lib/priority-queue/backoff.ts +24 -0
  176. package/packages/browser/src/lib/priority-queue/index.ts +6 -0
  177. package/packages/browser/src/lib/priority-queue/persisted.ts +127 -0
  178. package/packages/browser/src/lib/sleep.ts +4 -0
  179. package/packages/browser/src/lib/to-facade.ts +53 -0
  180. package/packages/browser/src/lib/version-type.ts +10 -0
  181. package/packages/browser/src/node/__tests__/node-integration.test.ts +19 -0
  182. package/packages/browser/src/node/index.ts +36 -0
  183. package/packages/browser/src/node/node.browser.ts +7 -0
  184. package/packages/browser/src/plugins/ajs-destination/__tests__/index.test.ts +834 -0
  185. package/packages/browser/src/plugins/ajs-destination/index.ts +392 -0
  186. package/packages/browser/src/plugins/ajs-destination/loader.ts +129 -0
  187. package/packages/browser/src/plugins/ajs-destination/types.ts +44 -0
  188. package/packages/browser/src/plugins/ajs-destination/utils.ts +32 -0
  189. package/packages/browser/src/plugins/analytics-node/__tests__/index.test.ts +69 -0
  190. package/packages/browser/src/plugins/analytics-node/index.ts +67 -0
  191. package/packages/browser/src/plugins/env-enrichment/__tests__/index.test.ts +421 -0
  192. package/packages/browser/src/plugins/env-enrichment/index.ts +208 -0
  193. package/packages/browser/src/plugins/hightouchio/__tests__/batched-dispatcher.test.ts +299 -0
  194. package/packages/browser/src/plugins/hightouchio/__tests__/index.test.ts +317 -0
  195. package/packages/browser/src/plugins/hightouchio/__tests__/normalize.test.ts +181 -0
  196. package/packages/browser/src/plugins/hightouchio/__tests__/retries.test.ts +82 -0
  197. package/packages/browser/src/plugins/hightouchio/batched-dispatcher.ts +127 -0
  198. package/packages/browser/src/plugins/hightouchio/fetch-dispatcher.ts +27 -0
  199. package/packages/browser/src/plugins/hightouchio/index.ts +147 -0
  200. package/packages/browser/src/plugins/hightouchio/normalize.ts +71 -0
  201. package/packages/browser/src/plugins/hightouchio/schedule-flush.ts +58 -0
  202. package/packages/browser/src/plugins/legacy-video-plugins/__tests__/index.test.ts +48 -0
  203. package/packages/browser/src/plugins/legacy-video-plugins/index.ts +16 -0
  204. package/packages/browser/src/plugins/middleware/__tests__/index.test.ts +268 -0
  205. package/packages/browser/src/plugins/middleware/index.ts +131 -0
  206. package/packages/browser/src/plugins/remote-loader/__tests__/index.test.ts +943 -0
  207. package/packages/browser/src/plugins/remote-loader/index.ts +256 -0
  208. package/packages/browser/src/plugins/remote-middleware/__tests__/index.test.ts +116 -0
  209. package/packages/browser/src/plugins/remote-middleware/index.ts +44 -0
  210. package/packages/browser/src/plugins/routing-middleware/__tests__/index.test.ts +64 -0
  211. package/packages/browser/src/plugins/routing-middleware/index.ts +37 -0
  212. package/packages/browser/src/plugins/schema-filter/__tests__/index.test.ts +520 -0
  213. package/packages/browser/src/plugins/schema-filter/index.ts +90 -0
  214. package/packages/browser/src/plugins/validation/__tests__/index.test.ts +78 -0
  215. package/packages/browser/src/plugins/validation/index.ts +44 -0
  216. package/packages/browser/src/test-helpers/browser-storage.ts +75 -0
  217. package/packages/browser/src/test-helpers/factories.ts +18 -0
  218. package/packages/browser/src/test-helpers/fetch-parse.ts +8 -0
  219. package/packages/browser/src/test-helpers/fixtures/cdn-settings.ts +301 -0
  220. package/packages/browser/src/test-helpers/fixtures/classic-destination.ts +25 -0
  221. package/packages/browser/src/test-helpers/fixtures/client-hints.ts +28 -0
  222. package/packages/browser/src/test-helpers/fixtures/create-fetch-method.ts +30 -0
  223. package/packages/browser/src/test-helpers/fixtures/index.ts +4 -0
  224. package/packages/browser/src/test-helpers/fixtures/page-context.ts +11 -0
  225. package/packages/browser/src/test-helpers/test-writekeys.ts +5 -0
  226. package/packages/browser/src/test-helpers/type-assertions.ts +11 -0
  227. package/packages/browser/src/tester/__fixtures__/hightouch-snippet.ts +64 -0
  228. package/packages/browser/src/tester/__fixtures__/index.html +8 -0
  229. package/packages/browser/src/tester/ajs-perf.ts +30 -0
  230. package/packages/browser/src/tester/ajs-tester.ts +119 -0
  231. package/packages/browser/src/tester/server.js +16 -0
  232. package/packages/browser/tsconfig.build.json +9 -0
  233. package/packages/browser/tsconfig.json +13 -0
  234. package/packages/browser/webpack.config.js +106 -0
  235. package/packages/config/package.json +10 -0
  236. package/packages/config/src/index.js +4 -0
  237. package/packages/config/src/jest/config.js +50 -0
  238. package/packages/config/src/jest/get-module-map.js +34 -0
  239. package/packages/config/src/lint-staged/config.js +4 -0
  240. package/packages/config-webpack/package.json +20 -0
  241. package/packages/config-webpack/webpack.config.common.js +75 -0
  242. package/packages/consent/consent-tools/.eslintrc.js +7 -0
  243. package/packages/consent/consent-tools/.lintstagedrc.js +1 -0
  244. package/packages/consent/consent-tools/LICENSE +45 -0
  245. package/packages/consent/consent-tools/README.md +104 -0
  246. package/packages/consent/consent-tools/jest.config.js +6 -0
  247. package/packages/consent/consent-tools/jest.setup.js +4 -0
  248. package/packages/consent/consent-tools/package.json +48 -0
  249. package/packages/consent/consent-tools/src/domain/__tests__/assertions/integrations-assertions.ts +37 -0
  250. package/packages/consent/consent-tools/src/domain/__tests__/consent-stamping.test.ts +45 -0
  251. package/packages/consent/consent-tools/src/domain/__tests__/create-wrapper.test.ts +816 -0
  252. package/packages/consent/consent-tools/src/domain/__tests__/typedef-tests.ts +21 -0
  253. package/packages/consent/consent-tools/src/domain/consent-changed.ts +51 -0
  254. package/packages/consent/consent-tools/src/domain/consent-stamping.ts +19 -0
  255. package/packages/consent/consent-tools/src/domain/create-wrapper.ts +238 -0
  256. package/packages/consent/consent-tools/src/domain/get-initialized-analytics.ts +25 -0
  257. package/packages/consent/consent-tools/src/domain/load-cancellation.ts +31 -0
  258. package/packages/consent/consent-tools/src/domain/validation/__tests__/options-validators.test.ts +77 -0
  259. package/packages/consent/consent-tools/src/domain/validation/__tests__/validation-error.test.ts +15 -0
  260. package/packages/consent/consent-tools/src/domain/validation/common-validators.ts +19 -0
  261. package/packages/consent/consent-tools/src/domain/validation/index.ts +1 -0
  262. package/packages/consent/consent-tools/src/domain/validation/options-validators.ts +74 -0
  263. package/packages/consent/consent-tools/src/domain/validation/validation-error.ts +11 -0
  264. package/packages/consent/consent-tools/src/index.ts +16 -0
  265. package/packages/consent/consent-tools/src/types/errors.ts +14 -0
  266. package/packages/consent/consent-tools/src/types/index.ts +3 -0
  267. package/packages/consent/consent-tools/src/types/settings.ts +121 -0
  268. package/packages/consent/consent-tools/src/types/wrapper.ts +107 -0
  269. package/packages/consent/consent-tools/src/utils/index.ts +4 -0
  270. package/packages/consent/consent-tools/src/utils/pick.ts +18 -0
  271. package/packages/consent/consent-tools/src/utils/pipe.ts +14 -0
  272. package/packages/consent/consent-tools/src/utils/resolve-when.ts +32 -0
  273. package/packages/consent/consent-tools/src/utils/uniq.ts +4 -0
  274. package/packages/consent/consent-tools/tsconfig.build.json +9 -0
  275. package/packages/consent/consent-tools/tsconfig.json +12 -0
  276. package/packages/consent/consent-wrapper-onetrust/.eslintrc.js +7 -0
  277. package/packages/consent/consent-wrapper-onetrust/.lintstagedrc.js +1 -0
  278. package/packages/consent/consent-wrapper-onetrust/LICENSE +45 -0
  279. package/packages/consent/consent-wrapper-onetrust/README.md +125 -0
  280. package/packages/consent/consent-wrapper-onetrust/img/onetrust-cat-id.jpg +0 -0
  281. package/packages/consent/consent-wrapper-onetrust/img/onetrust-popup.jpg +0 -0
  282. package/packages/consent/consent-wrapper-onetrust/jest.config.js +6 -0
  283. package/packages/consent/consent-wrapper-onetrust/jest.setup.js +4 -0
  284. package/packages/consent/consent-wrapper-onetrust/package.json +60 -0
  285. package/packages/consent/consent-wrapper-onetrust/src/domain/__tests__/wrapper.test.ts +151 -0
  286. package/packages/consent/consent-wrapper-onetrust/src/domain/wrapper.ts +61 -0
  287. package/packages/consent/consent-wrapper-onetrust/src/index.ts +6 -0
  288. package/packages/consent/consent-wrapper-onetrust/src/index.umd.ts +11 -0
  289. package/packages/consent/consent-wrapper-onetrust/src/lib/__tests__/onetrust-api.test.ts +181 -0
  290. package/packages/consent/consent-wrapper-onetrust/src/lib/onetrust-api.ts +155 -0
  291. package/packages/consent/consent-wrapper-onetrust/src/lib/validation/index.ts +1 -0
  292. package/packages/consent/consent-wrapper-onetrust/src/lib/validation/onetrust-api-error.ts +11 -0
  293. package/packages/consent/consent-wrapper-onetrust/src/test-helpers/mocks.ts +23 -0
  294. package/packages/consent/consent-wrapper-onetrust/src/test-helpers/onetrust-globals.d.ts +11 -0
  295. package/packages/consent/consent-wrapper-onetrust/src/test-helpers/utils.ts +3 -0
  296. package/packages/consent/consent-wrapper-onetrust/tsconfig.build.json +9 -0
  297. package/packages/consent/consent-wrapper-onetrust/tsconfig.json +11 -0
  298. package/packages/consent/consent-wrapper-onetrust/webpack.config.js +25 -0
  299. package/packages/core/.eslintrc.js +4 -0
  300. package/packages/core/.lintstagedrc.js +1 -0
  301. package/packages/core/LICENSE.MD +45 -0
  302. package/packages/core/README.md +3 -0
  303. package/packages/core/jest.config.js +5 -0
  304. package/packages/core/jest.setup.js +10 -0
  305. package/packages/core/package.json +40 -0
  306. package/packages/core/src/analytics/__tests__/dispatch.test.ts +95 -0
  307. package/packages/core/src/analytics/dispatch.ts +58 -0
  308. package/packages/core/src/analytics/index.ts +11 -0
  309. package/packages/core/src/callback/__tests__/index.test.ts +85 -0
  310. package/packages/core/src/callback/index.ts +51 -0
  311. package/packages/core/src/context/index.ts +123 -0
  312. package/packages/core/src/emitter/__tests__/emitter.test.ts +74 -0
  313. package/packages/core/src/emitter/index.ts +65 -0
  314. package/packages/core/src/emitter/interface.ts +31 -0
  315. package/packages/core/src/events/__tests__/index.test.ts +394 -0
  316. package/packages/core/src/events/index.ts +280 -0
  317. package/packages/core/src/events/interfaces.ts +475 -0
  318. package/packages/core/src/index.ts +19 -0
  319. package/packages/core/src/logger/__tests__/index.test.ts +66 -0
  320. package/packages/core/src/logger/index.ts +74 -0
  321. package/packages/core/src/plugins/index.ts +43 -0
  322. package/packages/core/src/priority-queue/__tests__/backoff.test.ts +23 -0
  323. package/packages/core/src/priority-queue/__tests__/index.test.ts +158 -0
  324. package/packages/core/src/priority-queue/backoff.ts +24 -0
  325. package/packages/core/src/priority-queue/index.ts +103 -0
  326. package/packages/core/src/queue/__tests__/event-queue.test.ts +678 -0
  327. package/packages/core/src/queue/__tests__/extension-flushing.test.ts +416 -0
  328. package/packages/core/src/queue/delivery.ts +73 -0
  329. package/packages/core/src/queue/event-queue.ts +318 -0
  330. package/packages/core/src/stats/__tests__/index.test.ts +103 -0
  331. package/packages/core/src/stats/index.ts +88 -0
  332. package/packages/core/src/task/__tests__/task-group.test.ts +26 -0
  333. package/packages/core/src/task/task-group.ts +31 -0
  334. package/packages/core/src/user/index.ts +7 -0
  335. package/packages/core/src/utils/__tests__/group-by.test.ts +96 -0
  336. package/packages/core/src/utils/__tests__/is-plain-object.test.ts +27 -0
  337. package/packages/core/src/utils/__tests__/is-thenable.test.ts +39 -0
  338. package/packages/core/src/utils/bind-all.ts +19 -0
  339. package/packages/core/src/utils/get-global.ts +17 -0
  340. package/packages/core/src/utils/group-by.ts +30 -0
  341. package/packages/core/src/utils/has-properties.ts +7 -0
  342. package/packages/core/src/utils/is-plain-object.ts +26 -0
  343. package/packages/core/src/utils/is-thenable.ts +9 -0
  344. package/packages/core/src/utils/p-while.ts +12 -0
  345. package/packages/core/src/utils/pick.ts +8 -0
  346. package/packages/core/src/utils/ts-helpers.ts +13 -0
  347. package/packages/core/src/validation/__tests__/assertions.test.ts +155 -0
  348. package/packages/core/src/validation/assertions.ts +72 -0
  349. package/packages/core/src/validation/errors.ts +8 -0
  350. package/packages/core/src/validation/helpers.ts +23 -0
  351. package/packages/core/test-helpers/index.ts +2 -0
  352. package/packages/core/test-helpers/test-ctx.ts +7 -0
  353. package/packages/core/test-helpers/test-event-queue.ts +7 -0
  354. package/packages/core/tsconfig.build.json +9 -0
  355. package/packages/core/tsconfig.json +11 -0
  356. package/packages/node/.eslintrc.js +7 -0
  357. package/packages/node/.lintstagedrc.js +1 -0
  358. package/packages/node/LICENSE +45 -0
  359. package/packages/node/README.md +138 -0
  360. package/packages/node/jest.config.js +5 -0
  361. package/packages/node/jest.setup.js +4 -0
  362. package/packages/node/package.json +50 -0
  363. package/packages/node/scripts/version.sh +11 -0
  364. package/packages/node/src/__tests__/callback.test.ts +47 -0
  365. package/packages/node/src/__tests__/disable.integration.test.ts +42 -0
  366. package/packages/node/src/__tests__/emitter.integration.test.ts +45 -0
  367. package/packages/node/src/__tests__/graceful-shutdown-integration.test.ts +244 -0
  368. package/packages/node/src/__tests__/http-client.integration.test.ts +69 -0
  369. package/packages/node/src/__tests__/http-integration.test.ts +362 -0
  370. package/packages/node/src/__tests__/integration.test.ts +357 -0
  371. package/packages/node/src/__tests__/plugins.test.ts +16 -0
  372. package/packages/node/src/__tests__/settings.test.ts +9 -0
  373. package/packages/node/src/__tests__/test-helpers/assert-shape/http-request-event.ts +13 -0
  374. package/packages/node/src/__tests__/test-helpers/assert-shape/index.ts +2 -0
  375. package/packages/node/src/__tests__/test-helpers/assert-shape/segment-http-api.ts +43 -0
  376. package/packages/node/src/__tests__/test-helpers/create-test-analytics.ts +42 -0
  377. package/packages/node/src/__tests__/test-helpers/factories.ts +17 -0
  378. package/packages/node/src/__tests__/test-helpers/is-valid-date.ts +6 -0
  379. package/packages/node/src/__tests__/test-helpers/resolve-ctx.ts +19 -0
  380. package/packages/node/src/__tests__/test-helpers/resolve-emitter.ts +11 -0
  381. package/packages/node/src/__tests__/test-helpers/sleep.ts +3 -0
  382. package/packages/node/src/__tests__/test-helpers/test-plugin.ts +16 -0
  383. package/packages/node/src/__tests__/typedef-tests.ts +120 -0
  384. package/packages/node/src/app/analytics-node.ts +299 -0
  385. package/packages/node/src/app/context.ts +11 -0
  386. package/packages/node/src/app/dispatch-emit.ts +42 -0
  387. package/packages/node/src/app/emitter.ts +23 -0
  388. package/packages/node/src/app/event-factory.ts +20 -0
  389. package/packages/node/src/app/event-queue.ts +23 -0
  390. package/packages/node/src/app/settings.ts +49 -0
  391. package/packages/node/src/app/types/index.ts +3 -0
  392. package/packages/node/src/app/types/params.ts +76 -0
  393. package/packages/node/src/app/types/plugin.ts +5 -0
  394. package/packages/node/src/app/types/segment-event.ts +7 -0
  395. package/packages/node/src/generated/version.ts +2 -0
  396. package/packages/node/src/index.ts +26 -0
  397. package/packages/node/src/lib/__tests__/abort.test.ts +54 -0
  398. package/packages/node/src/lib/__tests__/create-url.test.ts +35 -0
  399. package/packages/node/src/lib/__tests__/env.test.ts +52 -0
  400. package/packages/node/src/lib/__tests__/get-message-id.test.ts +21 -0
  401. package/packages/node/src/lib/abort.ts +77 -0
  402. package/packages/node/src/lib/base-64-encode.ts +8 -0
  403. package/packages/node/src/lib/create-url.ts +11 -0
  404. package/packages/node/src/lib/env.ts +45 -0
  405. package/packages/node/src/lib/extract-promise-parts.ts +21 -0
  406. package/packages/node/src/lib/fetch.ts +16 -0
  407. package/packages/node/src/lib/get-message-id.ts +10 -0
  408. package/packages/node/src/lib/http-client.ts +95 -0
  409. package/packages/node/src/lib/uuid.ts +1 -0
  410. package/packages/node/src/plugins/segmentio/__tests__/methods.test.ts +223 -0
  411. package/packages/node/src/plugins/segmentio/__tests__/publisher.test.ts +411 -0
  412. package/packages/node/src/plugins/segmentio/context-batch.ts +71 -0
  413. package/packages/node/src/plugins/segmentio/index.ts +66 -0
  414. package/packages/node/src/plugins/segmentio/publisher.ts +265 -0
  415. package/packages/node/tsconfig.build.json +9 -0
  416. package/packages/node/tsconfig.json +10 -0
  417. package/packages/test-helpers/.eslintrc.js +7 -0
  418. package/packages/test-helpers/.lintstagedrc.js +1 -0
  419. package/packages/test-helpers/jest.config.js +3 -0
  420. package/packages/test-helpers/package.json +26 -0
  421. package/packages/test-helpers/src/analytics/cdn-settings-builder.ts +79 -0
  422. package/packages/test-helpers/src/analytics/index.ts +1 -0
  423. package/packages/test-helpers/src/index.ts +2 -0
  424. package/packages/test-helpers/src/utils/index.ts +1 -0
  425. package/packages/test-helpers/src/utils/sleep.ts +4 -0
  426. package/packages/test-helpers/tsconfig.build.json +9 -0
  427. package/packages/test-helpers/tsconfig.json +11 -0
  428. package/tsconfig.json +21 -0
  429. package/turbo.json +39 -0
  430. package/typings/get-monorepo-packages.d.ts +9 -0
  431. package/typings/spawn.d.ts +10 -0
@@ -0,0 +1,138 @@
1
+ # @ht-sdks/events-sdk-js-node
2
+
3
+ https://www.npmjs.com/package/@ht-sdks/events-sdk-js-node
4
+
5
+
6
+ ## Runtime Support
7
+ - Node.js >= 14
8
+ - AWS Lambda
9
+ - Cloudflare Workers
10
+ - Vercel Edge Functions
11
+ - Web Workers (experimental)
12
+
13
+ ## Quick Start
14
+ ### Install library
15
+ ```bash
16
+ # npm
17
+ npm install @ht-sdks/events-sdk-js-node
18
+ # yarn
19
+ yarn add @ht-sdks/events-sdk-js-node
20
+ # pnpm
21
+ pnpm install @ht-sdks/events-sdk-js-node
22
+ ```
23
+
24
+ ### Usage
25
+ Assuming some express-like web framework.
26
+ ```ts
27
+ import { Analytics } from '@ht-sdks/events-sdk-js-node'
28
+ // or, if you use require:
29
+ const { Analytics } = require('@ht-sdks/events-sdk-js-node')
30
+
31
+ // instantiation
32
+ const analytics = new Analytics({ writeKey: '<MY_WRITE_KEY>' })
33
+
34
+ app.post('/login', (req, res) => {
35
+ analytics.identify({
36
+ userId: req.body.userId,
37
+ previousId: req.body.previousId
38
+ })
39
+ res.sendStatus(200)
40
+ })
41
+
42
+ app.post('/cart', (req, res) => {
43
+ analytics.track({
44
+ userId: req.body.userId,
45
+ event: 'Add to cart',
46
+ properties: { productId: '123456' }
47
+ })
48
+ res.sendStatus(201)
49
+ });
50
+ ```
51
+
52
+
53
+ ## Settings & Configuration
54
+
55
+ You can also see the complete list of settings in the [AnalyticsSettings interface](src/app/settings.ts).
56
+
57
+
58
+ ## Usage in non-node runtimes
59
+ ### Usage in AWS Lambda
60
+ - [AWS lambda execution environment](https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtime-environment.html) is challenging for typically non-response-blocking async activites like tracking or logging, since the runtime terminates / freezes after a response is emitted.
61
+
62
+ Here is an example of using analytics.js within a handler:
63
+ ```ts
64
+ const { Analytics } = require('@ht-sdks/events-sdk-js-node');
65
+
66
+ // since analytics has the potential to be stateful if there are any plugins added,
67
+ // to be on the safe side, we should instantiate a new instance of analytics on every request (the cost of instantiation is low).
68
+ const analytics = () => new Analytics({
69
+ maxEventsInBatch: 1,
70
+ writeKey: '<MY_WRITE_KEY>',
71
+ })
72
+ .on('error', console.error);
73
+
74
+ module.exports.handler = async (event) => {
75
+ ...
76
+ // we need to await before returning, otherwise the lambda will exit before sending the request.
77
+ await new Promise((resolve) =>
78
+ analytics().track({ ... }, resolve)
79
+ )
80
+
81
+ ...
82
+ return {
83
+ statusCode: 200,
84
+ };
85
+ ....
86
+ };
87
+ ```
88
+
89
+ ### Usage in Vercel Edge Functions
90
+ ```ts
91
+ import { Analytics } from '@ht-sdks/events-sdk-js-node';
92
+ import { NextRequest, NextResponse } from 'next/server';
93
+
94
+ export const analytics = new Analytics({
95
+ writeKey: '<MY_WRITE_KEY>',
96
+ maxEventsInBatch: 1,
97
+ })
98
+ .on('error', console.error)
99
+
100
+ export const config = {
101
+ runtime: 'edge',
102
+ };
103
+
104
+ export default async (req: NextRequest) => {
105
+ await new Promise((resolve) =>
106
+ analytics.track({ ... }, resolve)
107
+ );
108
+ return NextResponse.json({ ... })
109
+ };
110
+ ```
111
+
112
+ ### Usage in Cloudflare Workers
113
+ ```ts
114
+ import { Analytics, Context } from '@ht-sdks/events-sdk-js-node';
115
+
116
+ export default {
117
+ async fetch(
118
+ request: Request,
119
+ env: Env,
120
+ ctx: ExecutionContext
121
+ ): Promise<Response> {
122
+ const analytics = new Analytics({
123
+ maxEventsInBatch: 1,
124
+ writeKey: '<MY_WRITE_KEY>',
125
+ }).on('error', console.error);
126
+
127
+ await new Promise((resolve, reject) =>
128
+ analytics.track({ ... }, resolve)
129
+ );
130
+
131
+ ...
132
+ return new Response(...)
133
+ },
134
+ };
135
+
136
+ ```
137
+
138
+
@@ -0,0 +1,5 @@
1
+ const { createJestTSConfig } = require('@internal/config')
2
+
3
+ module.exports = createJestTSConfig(__dirname, {
4
+ setupFilesAfterEnv: ['./jest.setup.js'],
5
+ })
@@ -0,0 +1,4 @@
1
+ const fetch = require('node-fetch')
2
+
3
+ // eslint-disable-next-line no-undef
4
+ globalThis.fetch = fetch // polyfill fetch so nock will work correctly on node 18 (https://github.com/nock/nock/issues/2336)
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@ht-sdks/events-sdk-js-node",
3
+ "version": "1.1.2",
4
+ "main": "./dist/cjs/index.js",
5
+ "module": "./dist/esm/index.js",
6
+ "types": "./dist/types/index.d.ts",
7
+ "license": "MIT",
8
+ "repository": {
9
+ "directory": "packages/node",
10
+ "type": "git",
11
+ "url": "https://github.com/ht-sdks/events-sdk-js-mono"
12
+ },
13
+ "files": [
14
+ "dist/",
15
+ "src/",
16
+ "!**/__tests__/**",
17
+ "!*.tsbuildinfo"
18
+ ],
19
+ "engines": {
20
+ "node": ">=14"
21
+ },
22
+ "scripts": {
23
+ ".": "yarn run -T turbo run --filter=@ht-sdks/events-sdk-js-node",
24
+ "test": "yarn jest",
25
+ "lint": "yarn concurrently 'yarn:eslint .' 'yarn:tsc --noEmit'",
26
+ "build": "rm -rf dist && yarn concurrently 'yarn:build:*'",
27
+ "build:cjs": "yarn tsc -p tsconfig.build.json --outDir ./dist/cjs --module commonjs",
28
+ "version": "sh scripts/version.sh",
29
+ "build:esm": "yarn tsc -p tsconfig.build.json",
30
+ "watch": "yarn build:esm --watch",
31
+ "watch:test": "yarn test --watch",
32
+ "tsc": "yarn run -T tsc",
33
+ "eslint": "yarn run -T eslint",
34
+ "concurrently": "yarn run -T concurrently",
35
+ "jest": "yarn run -T jest"
36
+ },
37
+ "dependencies": {
38
+ "@ht-sdks/events-sdk-js-core": "^1.0.0",
39
+ "@lukeed/uuid": "^2.0.0",
40
+ "buffer": "^6.0.3",
41
+ "node-fetch": "^2.6.7",
42
+ "tslib": "^2.4.1"
43
+ },
44
+ "devDependencies": {
45
+ "@internal/config": "0.0.0",
46
+ "@types/node": "^16",
47
+ "axios": "^1.4.0"
48
+ },
49
+ "packageManager": "yarn@3.4.1"
50
+ }
@@ -0,0 +1,11 @@
1
+ #!/bin/sh
2
+ # Generate a version.ts file from the version in the package.json
3
+
4
+ PKG_VERSION=$(node --eval="process.stdout.write(require('./package.json').version)")
5
+
6
+ cat <<EOF >src/generated/version.ts
7
+ // This file is generated.
8
+ export const version = '$PKG_VERSION'
9
+ EOF
10
+
11
+ git add src/generated/version.ts
@@ -0,0 +1,47 @@
1
+ import { createTestAnalytics } from './test-helpers/create-test-analytics'
2
+ import { Context } from '../app/context'
3
+
4
+ describe('Callback behavior', () => {
5
+ it('should handle success', async () => {
6
+ const ajs = createTestAnalytics({
7
+ maxEventsInBatch: 1,
8
+ })
9
+ const ctx = await new Promise<Context>((resolve, reject) =>
10
+ ajs.track(
11
+ {
12
+ anonymousId: 'bar',
13
+ event: 'event name',
14
+ },
15
+ (err, ctx) => {
16
+ if (err) reject('test fail')
17
+ resolve(ctx!)
18
+ }
19
+ )
20
+ )
21
+ expect(ctx.event.event).toBe('event name')
22
+ expect(ctx.event.anonymousId).toBe('bar')
23
+ })
24
+
25
+ it('should handle errors', async () => {
26
+ const ajs = createTestAnalytics(
27
+ {
28
+ maxEventsInBatch: 1,
29
+ },
30
+ { withError: true }
31
+ )
32
+ const [err, ctx] = await new Promise<[any, Context]>((resolve) =>
33
+ ajs.track(
34
+ {
35
+ anonymousId: 'bar',
36
+ event: 'event name',
37
+ },
38
+ (err, ctx) => {
39
+ resolve([err!, ctx!])
40
+ }
41
+ )
42
+ )
43
+ expect(ctx.event.event).toBe('event name')
44
+ expect(ctx.event.anonymousId).toBe('bar')
45
+ expect(err).toEqual(new Error('[404] Not Found'))
46
+ })
47
+ })
@@ -0,0 +1,42 @@
1
+ import {
2
+ createTestAnalytics,
3
+ TestFetchClient,
4
+ } from './test-helpers/create-test-analytics'
5
+
6
+ describe('disable', () => {
7
+ const httpClient = new TestFetchClient()
8
+ const makeReqSpy = jest.spyOn(httpClient, 'makeRequest')
9
+
10
+ it('should not emit an http request if disabled', async () => {
11
+ const analytics = createTestAnalytics({
12
+ disable: true,
13
+ })
14
+ const emitterCb = jest.fn()
15
+ analytics.on('http_request', emitterCb)
16
+ await new Promise((resolve) =>
17
+ analytics.track({ anonymousId: 'foo', event: 'bar' }, resolve)
18
+ )
19
+ expect(emitterCb).not.toBeCalled()
20
+ })
21
+
22
+ it('should call .send if disabled is false', async () => {
23
+ const analytics = createTestAnalytics({
24
+ disable: false,
25
+ httpClient: httpClient,
26
+ })
27
+ await new Promise((resolve) =>
28
+ analytics.track({ anonymousId: 'foo', event: 'bar' }, resolve)
29
+ )
30
+ expect(makeReqSpy).toBeCalledTimes(1)
31
+ })
32
+ it('should not call .send if disabled is true', async () => {
33
+ const analytics = createTestAnalytics({
34
+ disable: true,
35
+ httpClient: httpClient,
36
+ })
37
+ await new Promise((resolve) =>
38
+ analytics.track({ anonymousId: 'foo', event: 'bar' }, resolve)
39
+ )
40
+ expect(makeReqSpy).not.toBeCalled()
41
+ })
42
+ })
@@ -0,0 +1,45 @@
1
+ import { createTestAnalytics } from './test-helpers/create-test-analytics'
2
+ import { assertHttpRequestEmittedEvent } from './test-helpers/assert-shape'
3
+
4
+ describe('http_request', () => {
5
+ it('emits an http_request event if success', async () => {
6
+ const analytics = createTestAnalytics()
7
+ const fn = jest.fn()
8
+ analytics.on('http_request', fn)
9
+ await new Promise((resolve) =>
10
+ analytics.track({ anonymousId: 'foo', event: 'bar' }, resolve)
11
+ )
12
+ expect(fn).toBeCalledTimes(1)
13
+ assertHttpRequestEmittedEvent(fn.mock.lastCall[0])
14
+ })
15
+
16
+ it('emits an http_request event if error', async () => {
17
+ const analytics = createTestAnalytics(
18
+ {
19
+ maxRetries: 0,
20
+ },
21
+ { withError: true }
22
+ )
23
+ const fn = jest.fn()
24
+ analytics.on('http_request', fn)
25
+ await new Promise((resolve) =>
26
+ analytics.track({ anonymousId: 'foo', event: 'bar' }, resolve)
27
+ )
28
+ assertHttpRequestEmittedEvent(fn.mock.lastCall[0])
29
+ })
30
+
31
+ it('if error, emits an http_request event on every retry', async () => {
32
+ const analytics = createTestAnalytics(
33
+ {
34
+ maxRetries: 2,
35
+ },
36
+ { withError: true }
37
+ )
38
+ const fn = jest.fn()
39
+ analytics.on('http_request', fn)
40
+ await new Promise((resolve) =>
41
+ analytics.track({ anonymousId: 'foo', event: 'bar' }, resolve)
42
+ )
43
+ expect(fn).toBeCalledTimes(3)
44
+ })
45
+ })
@@ -0,0 +1,244 @@
1
+ import { TestFetchClient } from './test-helpers/create-test-analytics'
2
+ import { performance as perf } from 'perf_hooks'
3
+ import { Analytics } from '../app/analytics-node'
4
+ import { sleep } from './test-helpers/sleep'
5
+ import { Plugin, HightouchEvent } from '../app/types'
6
+ import { Context } from '../app/context'
7
+
8
+ const testPlugin: Plugin = {
9
+ type: 'after',
10
+ load: () => Promise.resolve(),
11
+ name: 'foo',
12
+ version: 'bar',
13
+ isLoaded: () => true,
14
+ }
15
+
16
+ let testClient: TestFetchClient
17
+
18
+ describe('Ability for users to exit without losing events', () => {
19
+ let ajs!: Analytics
20
+ testClient = new TestFetchClient()
21
+ const makeReqSpy = jest.spyOn(testClient, 'makeRequest')
22
+ beforeEach(async () => {
23
+ ajs = new Analytics({
24
+ writeKey: 'abc123',
25
+ maxEventsInBatch: 1,
26
+ httpClient: testClient,
27
+ })
28
+ })
29
+ const _helpers = {
30
+ getFetchCalls: () =>
31
+ makeReqSpy.mock.calls.map(([{ url, method, data, headers }]) => ({
32
+ url,
33
+ method,
34
+ headers,
35
+ data,
36
+ })),
37
+ makeTrackCall: (analytics = ajs, cb?: (...args: any[]) => void) => {
38
+ analytics.track({ userId: 'foo', event: 'Thing Updated' }, cb)
39
+ },
40
+ }
41
+
42
+ describe('drained emitted event', () => {
43
+ test('emits a drained event if only one event is dispatched', async () => {
44
+ _helpers.makeTrackCall()
45
+ return expect(
46
+ new Promise((resolve) => ajs.once('drained', () => resolve(undefined)))
47
+ ).resolves.toBe(undefined)
48
+ })
49
+
50
+ test('emits a drained event if multiple events are dispatched', async () => {
51
+ let drainedCalls = 0
52
+ ajs.on('drained', () => {
53
+ drainedCalls++
54
+ })
55
+ _helpers.makeTrackCall()
56
+ _helpers.makeTrackCall()
57
+ _helpers.makeTrackCall()
58
+ await sleep(200)
59
+ expect(drainedCalls).toBe(1)
60
+ })
61
+
62
+ test('all callbacks should be called ', async () => {
63
+ const cb = jest.fn()
64
+ ajs.track({ userId: 'foo', event: 'bar' }, cb)
65
+ expect(cb).not.toHaveBeenCalled()
66
+ await ajs.closeAndFlush()
67
+ expect(cb).toBeCalled()
68
+ })
69
+
70
+ test('all async callbacks should be called', async () => {
71
+ const trackCall = new Promise<Context>((resolve) => {
72
+ ajs.track(
73
+ {
74
+ userId: 'abc',
75
+ event: 'def',
76
+ },
77
+ (_, ctx) => sleep(200).then(() => resolve(ctx!))
78
+ )
79
+ })
80
+
81
+ const res = await Promise.race([ajs.closeAndFlush(), trackCall])
82
+ expect(res instanceof Context).toBe(true)
83
+ })
84
+ })
85
+
86
+ describe('.closeAndFlush()', () => {
87
+ test('default timeout should be related to flush interval', () => {
88
+ const flushInterval = 500
89
+ ajs = new Analytics({
90
+ writeKey: 'abc123',
91
+ flushInterval,
92
+ httpClient: testClient,
93
+ })
94
+ const closeAndFlushTimeout = ajs['_closeAndFlushDefaultTimeout']
95
+ expect(closeAndFlushTimeout).toBe(flushInterval * 1.25)
96
+ })
97
+
98
+ test('should force resolve if method call execution time exceeds specified timeout', async () => {
99
+ const TIMEOUT = 300
100
+ await ajs.register({
101
+ ...testPlugin,
102
+ track: async (ctx) => {
103
+ await sleep(1000)
104
+ return ctx
105
+ },
106
+ })
107
+ _helpers.makeTrackCall(ajs)
108
+ const startTime = perf.now()
109
+ await ajs.closeAndFlush({ timeout: TIMEOUT })
110
+ const elapsedTime = Math.round(perf.now() - startTime)
111
+ expect(elapsedTime).toBeLessThanOrEqual(TIMEOUT + 10)
112
+ expect(elapsedTime).toBeGreaterThan(TIMEOUT - 10)
113
+ })
114
+
115
+ test('no new events should be accepted (but existing ones should be flushed)', async () => {
116
+ let trackCallCount = 0
117
+ ajs.on('track', () => {
118
+ // track should only happen after successful dispatch
119
+ trackCallCount += 1
120
+ })
121
+ _helpers.makeTrackCall()
122
+ const closed = ajs.closeAndFlush()
123
+ _helpers.makeTrackCall() // should not trigger
124
+ _helpers.makeTrackCall() // should not trigger
125
+ await closed
126
+ expect(_helpers.getFetchCalls().length).toBe(1)
127
+ expect(trackCallCount).toBe(1)
128
+ })
129
+
130
+ test('any events created after close should be emitted', async () => {
131
+ const events: HightouchEvent[] = []
132
+ ajs.on('call_after_close', (event) => {
133
+ events.push(event)
134
+ })
135
+ _helpers.makeTrackCall()
136
+ const closed = ajs.closeAndFlush()
137
+ _helpers.makeTrackCall() // should be emitted
138
+ _helpers.makeTrackCall() // should be emitted
139
+ expect(events.length).toBe(2)
140
+ expect(events.every((e) => e.type === 'track')).toBeTruthy()
141
+ await closed
142
+ })
143
+
144
+ test('if queue has multiple track events, all of those items should be dispatched, and drain and track events should be emitted', async () => {
145
+ let drainedCalls = 0
146
+ ajs.on('drained', () => {
147
+ drainedCalls++
148
+ })
149
+ let trackCalls = 0
150
+ ajs.on('track', () => {
151
+ trackCalls++
152
+ })
153
+ await ajs.register({
154
+ ...testPlugin,
155
+ track: async (ctx) => {
156
+ await sleep(300)
157
+ return ctx
158
+ },
159
+ })
160
+ _helpers.makeTrackCall()
161
+ _helpers.makeTrackCall()
162
+
163
+ await ajs.closeAndFlush()
164
+
165
+ expect(_helpers.getFetchCalls().length).toBe(2)
166
+
167
+ expect(trackCalls).toBe(2)
168
+
169
+ expect(drainedCalls).toBe(1)
170
+ })
171
+
172
+ test('if no pending events, resolves immediately', async () => {
173
+ const startTime = perf.now()
174
+ await ajs.closeAndFlush()
175
+ const elapsedTime = perf.now() - startTime
176
+ expect(elapsedTime > 0).toBeTruthy()
177
+ expect(elapsedTime).toBeLessThan(20)
178
+ })
179
+
180
+ test('if no pending events, drained should not be emitted an extra time when close is called', async () => {
181
+ let called = false
182
+ ajs.on('drained', () => {
183
+ called = true
184
+ })
185
+ await ajs.closeAndFlush()
186
+ expect(called).toBeFalsy()
187
+ })
188
+
189
+ test('should flush immediately if close is called and there are events in the hightouch.io plugin, but no more are expected', async () => {
190
+ const analytics = new Analytics({
191
+ writeKey: 'foo',
192
+ flushInterval: 10000,
193
+ maxEventsInBatch: 15,
194
+ httpClient: testClient,
195
+ })
196
+ _helpers.makeTrackCall(analytics)
197
+ _helpers.makeTrackCall(analytics)
198
+ await sleep(100)
199
+
200
+ // ensure all track events have reached the hightouch plugin
201
+ expect(analytics['_publisher']['_batch']!.length).toBe(2)
202
+
203
+ const startTime = perf.now()
204
+ await analytics.closeAndFlush()
205
+ const elapsedTime = perf.now() - startTime
206
+ expect(elapsedTime).toBeLessThan(100)
207
+ const calls = _helpers.getFetchCalls()
208
+ expect(calls.length).toBe(1)
209
+ expect(calls[0].data.batch.length).toBe(2)
210
+ })
211
+
212
+ test('should wait to flush if close is called and an event has not made it to the hightouch.io plugin yet', async () => {
213
+ const TRACK_DELAY = 100
214
+ const _testPlugin: Plugin = {
215
+ ...testPlugin,
216
+ track: async (ctx) => {
217
+ await sleep(TRACK_DELAY)
218
+ return ctx
219
+ },
220
+ }
221
+ const analytics = new Analytics({
222
+ writeKey: 'foo',
223
+ flushInterval: 10000,
224
+ maxEventsInBatch: 15,
225
+ httpClient: testClient,
226
+ })
227
+ await analytics.register(_testPlugin)
228
+ _helpers.makeTrackCall(analytics)
229
+ _helpers.makeTrackCall(analytics)
230
+
231
+ // ensure that track events have not reached the hightouch plugin before closeAndFlush is called.
232
+ expect(analytics['_publisher']['_batch']).toBeFalsy()
233
+
234
+ const startTime = perf.now()
235
+ await analytics.closeAndFlush()
236
+ const elapsedTime = perf.now() - startTime
237
+ expect(elapsedTime).toBeGreaterThan(TRACK_DELAY)
238
+ expect(elapsedTime).toBeLessThan(TRACK_DELAY * 2)
239
+ const calls = _helpers.getFetchCalls()
240
+ expect(calls.length).toBe(1)
241
+ expect(calls[0].data.batch.length).toBe(2)
242
+ })
243
+ })
244
+ })
@@ -0,0 +1,69 @@
1
+ import { FetchHTTPClient, HTTPFetchFn } from '..'
2
+ import { AbortSignal as AbortSignalShim } from '../lib/abort'
3
+ import { httpClientOptionsBodyMatcher } from './test-helpers/assert-shape/segment-http-api'
4
+ import { createTestAnalytics } from './test-helpers/create-test-analytics'
5
+ import { createSuccess } from './test-helpers/factories'
6
+
7
+ const testFetch: jest.MockedFn<HTTPFetchFn> = jest
8
+ .fn()
9
+ .mockResolvedValue(createSuccess())
10
+
11
+ let analytics: ReturnType<typeof createTestAnalytics>
12
+
13
+ const helpers = {
14
+ makeTrackCall: () =>
15
+ new Promise((resolve) =>
16
+ analytics.track({ event: 'foo', userId: 'bar' }, resolve)
17
+ ),
18
+ assertFetchCallRequest: (
19
+ ...[url, options]: typeof testFetch['mock']['lastCall']
20
+ ) => {
21
+ expect(url).toBe('https://us-east-1.hightouch-events.com/v1/batch')
22
+ expect(options.headers).toEqual({
23
+ Authorization: 'Basic Zm9vOg==',
24
+ 'Content-Type': 'application/json',
25
+ 'User-Agent': 'analytics-node-next/latest',
26
+ })
27
+ expect(options.method).toBe('POST')
28
+ const getLastBatch = (): object[] => {
29
+ const [, options] = testFetch.mock.lastCall
30
+ const batch = JSON.parse(options.body!).batch
31
+ return batch
32
+ }
33
+ const batch = getLastBatch()
34
+ expect(batch.length).toBe(1)
35
+ expect(batch[0]).toEqual({
36
+ ...httpClientOptionsBodyMatcher,
37
+ timestamp: expect.stringMatching(
38
+ /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/
39
+ ),
40
+ properties: {},
41
+ event: 'foo',
42
+ type: 'track',
43
+ userId: 'bar',
44
+ })
45
+ // @ts-ignore
46
+ expect(options.signal).toBeInstanceOf(
47
+ typeof AbortSignal !== 'undefined' ? AbortSignal : AbortSignalShim
48
+ )
49
+ },
50
+ }
51
+
52
+ describe('httpClient option', () => {
53
+ it('can be a regular custom HTTP client', async () => {
54
+ analytics = createTestAnalytics({
55
+ httpClient: new FetchHTTPClient(testFetch),
56
+ })
57
+ expect(testFetch).toHaveBeenCalledTimes(0)
58
+ await helpers.makeTrackCall()
59
+ expect(testFetch).toHaveBeenCalledTimes(1)
60
+ helpers.assertFetchCallRequest(...testFetch.mock.lastCall)
61
+ })
62
+ it('can be a simple function that matches the fetch interface', async () => {
63
+ analytics = createTestAnalytics({ httpClient: testFetch })
64
+ expect(testFetch).toHaveBeenCalledTimes(0)
65
+ await helpers.makeTrackCall()
66
+ expect(testFetch).toHaveBeenCalledTimes(1)
67
+ helpers.assertFetchCallRequest(...testFetch.mock.lastCall)
68
+ })
69
+ })