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,45 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright © 2023 Hightouch
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
22
+
23
+ ---
24
+
25
+ The MIT License (MIT)
26
+
27
+ Copyright © 2021 Segment
28
+
29
+ Permission is hereby granted, free of charge, to any person obtaining a copy
30
+ of this software and associated documentation files (the "Software"), to deal
31
+ in the Software without restriction, including without limitation the rights
32
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
33
+ copies of the Software, and to permit persons to whom the Software is
34
+ furnished to do so, subject to the following conditions:
35
+
36
+ The above copyright notice and this permission notice shall be included in
37
+ all copies or substantial portions of the Software.
38
+
39
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
40
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
41
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
42
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
43
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
44
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
45
+ THE SOFTWARE.
@@ -0,0 +1,3 @@
1
+ # @ht-sdks/events-sdk-js-core
2
+
3
+ This package represents core 'shared' functionality that is shared by analytics packages. This is not designed to be used directly, but internal to the node and browser packages.
@@ -0,0 +1,5 @@
1
+ const { createJestTSConfig } = require('@internal/config')
2
+
3
+ module.exports = createJestTSConfig(__dirname, {
4
+ projects: ['<rootDir>'],
5
+ })
@@ -0,0 +1,10 @@
1
+ const { TextEncoder, TextDecoder } = require('util')
2
+ const { setImmediate } = require('timers')
3
+
4
+ // fix: "ReferenceError: TextEncoder is not defined" after upgrading JSDOM
5
+ global.TextEncoder = TextEncoder
6
+ global.TextDecoder = TextDecoder
7
+ // fix: jsdom uses setImmediate under the hood for preflight XHR requests,
8
+ // and jest removed setImmediate, so we need to provide it to prevent console
9
+ // logging ReferenceErrors made by integration tests that call Amplitude.
10
+ global.setImmediate = setImmediate
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@ht-sdks/events-sdk-js-core",
3
+ "version": "1.1.0",
4
+ "repository": {
5
+ "type": "git",
6
+ "url": "https://github.com/ht-sdks/events-sdk-js-mono",
7
+ "directory": "packages/core"
8
+ },
9
+ "license": "MIT",
10
+ "main": "./dist/cjs/index.js",
11
+ "module": "./dist/esm/index.js",
12
+ "types": "./dist/types/index.d.ts",
13
+ "files": [
14
+ "dist/",
15
+ "src/",
16
+ "!**/__tests__/**",
17
+ "!*.tsbuildinfo"
18
+ ],
19
+ "sideEffects": false,
20
+ "scripts": {
21
+ ".": "yarn run -T turbo run --filter=@ht-sdks/events-sdk-js-core",
22
+ "test": "yarn jest",
23
+ "lint": "yarn concurrently 'yarn:eslint .' 'yarn:tsc --noEmit'",
24
+ "build": "yarn concurrently 'yarn:build:*'",
25
+ "build:esm": "yarn tsc -p tsconfig.build.json",
26
+ "build:cjs": "yarn tsc -p tsconfig.build.json --outDir ./dist/cjs --module commonjs",
27
+ "watch": "yarn build:esm --watch",
28
+ "watch:test": "yarn test --watch",
29
+ "tsc": "yarn run -T tsc",
30
+ "eslint": "yarn run -T eslint",
31
+ "concurrently": "yarn run -T concurrently",
32
+ "jest": "yarn run -T jest"
33
+ },
34
+ "packageManager": "yarn@3.4.1",
35
+ "dependencies": {
36
+ "@lukeed/uuid": "^2.0.0",
37
+ "dset": "^3.1.2",
38
+ "tslib": "^2.4.1"
39
+ }
40
+ }
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Properly type mocked functions to make it easy to do assertions
3
+ * for example, myModule.mock.calls[0] will have the typed parameters instead of any.
4
+ *
5
+ * TODO: share with rest of project
6
+ */
7
+ type JestMockedFn<Fn> = Fn extends (...args: infer Args) => infer ReturnT
8
+ ? jest.Mock<ReturnT, Args>
9
+ : never
10
+
11
+ const invokeCallback: JestMockedFn<
12
+ typeof import('../../callback')['invokeCallback']
13
+ > = jest.fn()
14
+ jest.mock('../../callback', () => ({
15
+ invokeCallback: invokeCallback,
16
+ }))
17
+
18
+ import { CoreEventQueue } from '../../queue/event-queue'
19
+ import { Emitter } from '../../emitter'
20
+ import { dispatch, getDelay } from '../dispatch'
21
+ import { CoreContext } from '../../context'
22
+ import { TestCtx, TestEventQueue } from '../../../test-helpers'
23
+
24
+ let emitter!: Emitter
25
+ let queue!: CoreEventQueue<CoreContext>
26
+ const dispatchSingleSpy = jest.spyOn(CoreEventQueue.prototype, 'dispatchSingle')
27
+ const dispatchSpy = jest.spyOn(CoreEventQueue.prototype, 'dispatch')
28
+ const screenCtxMatcher = expect.objectContaining<Partial<CoreContext>>({
29
+ event: { type: 'screen' },
30
+ })
31
+
32
+ const screenCtx = new TestCtx({ type: 'screen' })
33
+ describe('Dispatch', () => {
34
+ beforeEach(() => {
35
+ jest.resetAllMocks()
36
+ dispatchSingleSpy.mockImplementationOnce((ctx) => Promise.resolve(ctx))
37
+ invokeCallback.mockImplementationOnce((ctx) => Promise.resolve(ctx))
38
+ dispatchSpy.mockImplementationOnce((ctx) => Promise.resolve(ctx))
39
+ queue = new TestEventQueue()
40
+ queue.isEmpty = jest.fn().mockReturnValue(false)
41
+ emitter = new Emitter()
42
+ })
43
+
44
+ it('should call dispatchSingle correctly if queue is empty', async () => {
45
+ queue.isEmpty = jest.fn().mockReturnValue(true)
46
+ await dispatch(screenCtx, queue, emitter)
47
+ expect(dispatchSingleSpy).toBeCalledWith(screenCtxMatcher)
48
+ expect(dispatchSpy).not.toBeCalled()
49
+ })
50
+
51
+ it('should call dispatch correctly if queue has items', async () => {
52
+ await dispatch(screenCtx, queue, emitter)
53
+ expect(dispatchSpy).toBeCalledWith(screenCtxMatcher)
54
+ expect(dispatchSingleSpy).not.toBeCalled()
55
+ })
56
+
57
+ it('should only call invokeCallback if callback is passed', async () => {
58
+ await dispatch(screenCtx, queue, emitter)
59
+ expect(invokeCallback).not.toBeCalled()
60
+
61
+ const cb = jest.fn()
62
+ await dispatch(screenCtx, queue, emitter, {
63
+ callback: cb,
64
+ })
65
+ expect(invokeCallback).toBeCalledTimes(1)
66
+ })
67
+ it('should call invokeCallback with correct args', async () => {
68
+ const cb = jest.fn()
69
+ await dispatch(screenCtx, queue, emitter, {
70
+ callback: cb,
71
+ })
72
+ expect(dispatchSpy).toBeCalledWith(screenCtxMatcher)
73
+ expect(invokeCallback).toBeCalledTimes(1)
74
+ const [ctx, _cb] = invokeCallback.mock.calls[0]
75
+ expect(ctx).toEqual(screenCtxMatcher)
76
+ expect(_cb).toBe(cb)
77
+ })
78
+ })
79
+
80
+ describe(getDelay, () => {
81
+ it('should calculate the amount of time to delay before invoking the callback', () => {
82
+ const aShortTimeAgo = Date.now() - 200
83
+ const timeout = 5000
84
+ const result = getDelay(aShortTimeAgo, timeout)
85
+ expect(result).toBeLessThanOrEqual(4800)
86
+ expect(result).toBeGreaterThanOrEqual(4790)
87
+ })
88
+
89
+ it('should have a sensible default', () => {
90
+ const aShortTimeAgo = Date.now() - 200
91
+ const result = getDelay(aShortTimeAgo)
92
+ expect(result).toBeLessThanOrEqual(100)
93
+ expect(result).toBeGreaterThanOrEqual(90)
94
+ })
95
+ })
@@ -0,0 +1,58 @@
1
+ import { CoreContext } from '../context'
2
+ import { Callback } from '../events/interfaces'
3
+ import { CoreEventQueue } from '../queue/event-queue'
4
+ import { invokeCallback } from '../callback'
5
+ import { Emitter } from '../emitter'
6
+
7
+ export type DispatchOptions<Ctx extends CoreContext = CoreContext> = {
8
+ timeout?: number
9
+ debug?: boolean
10
+ callback?: Callback<Ctx>
11
+ }
12
+
13
+ /* The amount of time in ms to wait before invoking the callback. */
14
+ export const getDelay = (startTimeInEpochMS: number, timeoutInMS?: number) => {
15
+ const elapsedTime = Date.now() - startTimeInEpochMS
16
+ // increasing the timeout increases the delay by almost the same amount -- this is weird legacy behavior.
17
+ return Math.max((timeoutInMS ?? 300) - elapsedTime, 0)
18
+ }
19
+ /**
20
+ * Push an event into the dispatch queue and invoke any callbacks.
21
+ *
22
+ * @param event - Hightouch event to enqueue.
23
+ * @param queue - Queue to dispatch against.
24
+ * @param emitter - This is typically an instance of "Analytics" -- used for metrics / progress information.
25
+ * @param options
26
+ */
27
+ export async function dispatch<
28
+ Ctx extends CoreContext,
29
+ EQ extends CoreEventQueue<Ctx>
30
+ >(
31
+ ctx: Ctx,
32
+ queue: EQ,
33
+ emitter: Emitter,
34
+ options?: DispatchOptions<Ctx>
35
+ ): Promise<Ctx> {
36
+ emitter.emit('dispatch_start', ctx)
37
+
38
+ const startTime = Date.now()
39
+ let dispatched: Ctx
40
+ if (queue.isEmpty()) {
41
+ dispatched = await queue.dispatchSingle(ctx)
42
+ } else {
43
+ dispatched = await queue.dispatch(ctx)
44
+ }
45
+
46
+ if (options?.callback) {
47
+ dispatched = await invokeCallback(
48
+ dispatched,
49
+ options.callback,
50
+ getDelay(startTime, options.timeout)
51
+ )
52
+ }
53
+ if (options?.debug) {
54
+ dispatched.flush()
55
+ }
56
+
57
+ return dispatched
58
+ }
@@ -0,0 +1,11 @@
1
+ export interface CoreAnalytics {
2
+ track(...args: unknown[]): unknown
3
+ page(...args: unknown[]): unknown
4
+ identify(...args: unknown[]): unknown
5
+ group(...args: unknown[]): unknown
6
+ alias(...args: unknown[]): unknown
7
+ screen(...args: unknown[]): unknown
8
+ register(...plugins: unknown[]): Promise<unknown>
9
+ deregister(...plugins: unknown[]): Promise<unknown>
10
+ readonly VERSION: string
11
+ }
@@ -0,0 +1,85 @@
1
+ import { invokeCallback } from '..'
2
+ import { TestCtx } from '../../../test-helpers'
3
+
4
+ describe(invokeCallback, () => {
5
+ afterEach(() => {
6
+ jest.useRealTimers()
7
+ })
8
+
9
+ it('invokes a callback asynchronously', async () => {
10
+ const ctx = new TestCtx({
11
+ type: 'track',
12
+ })
13
+
14
+ const fn = jest.fn()
15
+ const returned = await invokeCallback(ctx, fn, 0)
16
+
17
+ expect(fn).toHaveBeenCalledWith(ctx)
18
+ expect(returned).toBe(ctx)
19
+ })
20
+
21
+ // Fixes GitHub issue: https://github.com/segmentio/analytics-next/issues/409
22
+ // A.JS classic waited for the timeout/delay before invoking callback,
23
+ // so keep same behavior in A.JS next.
24
+ it('calls the callback after a delay', async () => {
25
+ const ctx = new TestCtx({
26
+ type: 'track',
27
+ })
28
+
29
+ const fn = jest.fn()
30
+ const delay = 100
31
+
32
+ const startTime = Date.now()
33
+ const returned = await invokeCallback(ctx, fn, delay)
34
+ const endTime = Date.now()
35
+
36
+ expect(fn).toHaveBeenCalled()
37
+ expect(endTime - startTime).toBeGreaterThanOrEqual(delay - 1)
38
+ expect(returned).toBe(ctx)
39
+ })
40
+
41
+ it('ignores the callback if it takes too long to resolve', async () => {
42
+ const ctx = new TestCtx({
43
+ type: 'track',
44
+ })
45
+
46
+ const slow = (_ctx: TestCtx): Promise<void> => {
47
+ return new Promise((resolve) => {
48
+ setTimeout(resolve, 1100)
49
+ })
50
+ }
51
+
52
+ const returned = await invokeCallback(ctx, slow, 0)
53
+ expect(returned).toBe(ctx)
54
+
55
+ const logs = returned.logs()
56
+ expect(logs[0].extras).toMatchInlineSnapshot(`
57
+ Object {
58
+ "error": [Error: Promise timed out],
59
+ }
60
+ `)
61
+
62
+ expect(logs[0].level).toEqual('warn')
63
+ })
64
+
65
+ it('does not crash if the callback crashes', async () => {
66
+ const ctx = new TestCtx({
67
+ type: 'track',
68
+ })
69
+
70
+ const boo = (_ctx: TestCtx): Promise<void> => {
71
+ throw new Error('👻 boo!')
72
+ }
73
+
74
+ const returned = await invokeCallback(ctx, boo, 0)
75
+ expect(returned).toBe(ctx)
76
+
77
+ const logs = returned.logs()
78
+ expect(logs[0].extras).toMatchInlineSnapshot(`
79
+ Object {
80
+ "error": [Error: 👻 boo!],
81
+ }
82
+ `)
83
+ expect(logs[0].level).toEqual('warn')
84
+ })
85
+ })
@@ -0,0 +1,51 @@
1
+ import { CoreContext } from '../context'
2
+ import type { Callback } from '../events'
3
+
4
+ export function pTimeout<T>(promise: Promise<T>, timeout: number): Promise<T> {
5
+ return new Promise((resolve, reject) => {
6
+ const timeoutId = setTimeout(() => {
7
+ reject(Error('Promise timed out'))
8
+ }, timeout)
9
+
10
+ promise
11
+ .then((val) => {
12
+ clearTimeout(timeoutId)
13
+ return resolve(val)
14
+ })
15
+ .catch(reject)
16
+ })
17
+ }
18
+
19
+ export function sleep(timeoutInMs: number): Promise<void> {
20
+ return new Promise((resolve) => setTimeout(resolve, timeoutInMs))
21
+ }
22
+
23
+ /**
24
+ * @param ctx
25
+ * @param callback - the function to invoke
26
+ * @param delay - aka "timeout". The amount of time in ms to wait before invoking the callback.
27
+ */
28
+ export function invokeCallback<Ctx extends CoreContext>(
29
+ ctx: Ctx,
30
+ callback: Callback<Ctx>,
31
+ delay: number
32
+ ): Promise<Ctx> {
33
+ const cb = () => {
34
+ try {
35
+ return Promise.resolve(callback(ctx))
36
+ } catch (err) {
37
+ return Promise.reject(err)
38
+ }
39
+ }
40
+
41
+ return (
42
+ sleep(delay)
43
+ // pTimeout ensures that the callback can't cause the context to hang
44
+ .then(() => pTimeout(cb(), 1000))
45
+ .catch((err) => {
46
+ ctx?.log('warn', 'Callback Error', { error: err })
47
+ ctx?.stats.increment('callback_error')
48
+ })
49
+ .then(() => ctx)
50
+ )
51
+ }
@@ -0,0 +1,123 @@
1
+ import { CoreHightouchEvent } from '../events/interfaces'
2
+
3
+ import { v4 as uuid } from '@lukeed/uuid'
4
+ import { dset } from 'dset'
5
+ import { CoreLogger, LogLevel, LogMessage } from '../logger'
6
+ import { CoreStats, CoreMetric, NullStats } from '../stats'
7
+
8
+ export interface SerializedContext {
9
+ id: string
10
+ event: CoreHightouchEvent
11
+ logs: LogMessage[]
12
+ metrics?: CoreMetric[]
13
+ }
14
+
15
+ export interface ContextFailedDelivery {
16
+ reason: unknown
17
+ }
18
+
19
+ export interface CancelationOptions {
20
+ retry?: boolean
21
+ reason?: string
22
+ type?: string
23
+ }
24
+
25
+ export class ContextCancelation {
26
+ retry: boolean
27
+ type: string
28
+ reason?: string
29
+
30
+ constructor(options: CancelationOptions) {
31
+ this.retry = options.retry ?? true
32
+ this.type = options.type ?? 'plugin Error'
33
+ this.reason = options.reason ?? ''
34
+ }
35
+ }
36
+
37
+ export abstract class CoreContext<
38
+ Event extends CoreHightouchEvent = CoreHightouchEvent
39
+ > {
40
+ event: Event
41
+ logger: CoreLogger
42
+ stats: CoreStats
43
+ attempts = 0
44
+
45
+ private _failedDelivery?: ContextFailedDelivery
46
+ private _id: string
47
+
48
+ constructor(
49
+ event: Event,
50
+ id = uuid(),
51
+ stats: CoreStats = new NullStats(),
52
+ logger = new CoreLogger()
53
+ ) {
54
+ this.event = event
55
+ this._id = id
56
+ this.logger = logger
57
+ this.stats = stats
58
+ }
59
+
60
+ static system(): void {
61
+ // This should be overridden by the subclass to return an instance of the subclass.
62
+ }
63
+
64
+ isSame(other: CoreContext): boolean {
65
+ return other.id === this.id
66
+ }
67
+
68
+ cancel(error?: Error | ContextCancelation): never {
69
+ if (error) {
70
+ throw error
71
+ }
72
+
73
+ throw new ContextCancelation({ reason: 'Context Cancel' })
74
+ }
75
+
76
+ log(level: LogLevel, message: string, extras?: object): void {
77
+ this.logger.log(level, message, extras)
78
+ }
79
+
80
+ get id(): string {
81
+ return this._id
82
+ }
83
+
84
+ updateEvent(path: string, val: unknown): Event {
85
+ // Don't allow integrations that are set to false to be overwritten with integration settings.
86
+ if (path.split('.')[0] === 'integrations') {
87
+ const integrationName = path.split('.')[1]
88
+
89
+ if (this.event.integrations?.[integrationName] === false) {
90
+ return this.event
91
+ }
92
+ }
93
+
94
+ dset(this.event, path, val)
95
+ return this.event
96
+ }
97
+
98
+ failedDelivery(): ContextFailedDelivery | undefined {
99
+ return this._failedDelivery
100
+ }
101
+
102
+ setFailedDelivery(options: ContextFailedDelivery) {
103
+ this._failedDelivery = options
104
+ }
105
+
106
+ logs(): LogMessage[] {
107
+ return this.logger.logs
108
+ }
109
+
110
+ flush(): void {
111
+ this.logger.flush()
112
+ this.stats.flush()
113
+ }
114
+
115
+ toJSON(): SerializedContext {
116
+ return {
117
+ id: this._id,
118
+ event: this.event,
119
+ logs: this.logger.logs,
120
+ metrics: this.stats.metrics,
121
+ }
122
+ }
123
+ }
@@ -0,0 +1,74 @@
1
+ import { Emitter } from '../'
2
+
3
+ describe(Emitter, () => {
4
+ it('emits events', () => {
5
+ const em = new Emitter()
6
+
7
+ const fn = jest.fn()
8
+ em.on('test', fn)
9
+ em.emit('test', 'banana')
10
+
11
+ expect(fn).toHaveBeenCalledWith('banana')
12
+ })
13
+
14
+ it('allows for subscribing to events', () => {
15
+ const em = new Emitter()
16
+
17
+ const fn = jest.fn()
18
+ const anotherFn = jest.fn()
19
+
20
+ em.on('test', fn)
21
+ em.on('test', anotherFn)
22
+
23
+ em.emit('test', 'banana', 'phone')
24
+
25
+ expect(fn).toHaveBeenCalledWith('banana', 'phone')
26
+ expect(anotherFn).toHaveBeenCalledWith('banana', 'phone')
27
+ })
28
+
29
+ it('allows for subscribing to the same event multiple times', () => {
30
+ const em = new Emitter()
31
+
32
+ const fn = jest.fn()
33
+
34
+ em.on('test', fn)
35
+ em.emit('test', 'banana')
36
+ em.emit('test', 'phone')
37
+
38
+ expect(fn).toHaveBeenCalledTimes(2)
39
+ expect(fn).toHaveBeenCalledWith('banana')
40
+ expect(fn).toHaveBeenCalledWith('phone')
41
+ })
42
+
43
+ it('allows for subscribers to subscribe only once', () => {
44
+ const em = new Emitter()
45
+
46
+ const fn = jest.fn()
47
+ em.once('test', fn)
48
+
49
+ // 2 emits
50
+ em.emit('test', 'banana')
51
+ em.emit('test', 'phone')
52
+
53
+ expect(fn).toHaveBeenCalledTimes(1)
54
+ expect(fn).toHaveBeenCalledWith('banana')
55
+ })
56
+
57
+ it('allows for unsubscribing', () => {
58
+ const em = new Emitter()
59
+
60
+ const fn = jest.fn()
61
+ em.on('test', fn)
62
+
63
+ // 2 emits
64
+ em.emit('test', 'banana')
65
+ em.emit('test', 'phone')
66
+
67
+ em.off('test', fn)
68
+
69
+ // 3rd emit
70
+ em.emit('test', 'phone')
71
+
72
+ expect(fn).toHaveBeenCalledTimes(2)
73
+ })
74
+ })
@@ -0,0 +1,65 @@
1
+ type EventName = string
2
+ type EventFnArgs = any[]
3
+ type EmitterContract = Record<EventName, EventFnArgs>
4
+
5
+ /**
6
+ * Event Emitter that takes the expected contract as a generic
7
+ * @example
8
+ * ```ts
9
+ * type Contract = {
10
+ * delivery_success: [DeliverySuccessResponse, Metrics],
11
+ * delivery_failure: [DeliveryError]
12
+ * }
13
+ * new Emitter<Contract>()
14
+ * .on('delivery_success', (res, metrics) => ...)
15
+ * .on('delivery_failure', (err) => ...)
16
+ * ```
17
+ */
18
+ export class Emitter<Contract extends EmitterContract = EmitterContract> {
19
+ private callbacks: Partial<Contract> = {}
20
+ on<EventName extends keyof Contract>(
21
+ event: EventName,
22
+ callback: (...args: Contract[EventName]) => void
23
+ ): this {
24
+ if (!this.callbacks[event]) {
25
+ this.callbacks[event] = [callback] as Contract[EventName]
26
+ } else {
27
+ this.callbacks[event]!.push(callback)
28
+ }
29
+ return this
30
+ }
31
+
32
+ once<EventName extends keyof Contract>(
33
+ event: EventName,
34
+ callback: (...args: Contract[EventName]) => void
35
+ ): this {
36
+ const on = (...args: Contract[EventName]): void => {
37
+ this.off(event, on)
38
+ callback.apply(this, args)
39
+ }
40
+
41
+ this.on(event, on)
42
+ return this
43
+ }
44
+
45
+ off<EventName extends keyof Contract>(
46
+ event: EventName,
47
+ callback: (...args: Contract[EventName]) => void
48
+ ): this {
49
+ const fns = this.callbacks[event] ?? []
50
+ const without = fns.filter((fn) => fn !== callback) as Contract[EventName]
51
+ this.callbacks[event] = without
52
+ return this
53
+ }
54
+
55
+ emit<EventName extends keyof Contract>(
56
+ event: EventName,
57
+ ...args: Contract[EventName]
58
+ ): this {
59
+ const callbacks = this.callbacks[event] ?? []
60
+ callbacks.forEach((callback) => {
61
+ callback.apply(this, args)
62
+ })
63
+ return this
64
+ }
65
+ }