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,21 @@
1
+ import type {
2
+ HtEventsSnippet,
3
+ HtEventsBrowser,
4
+ } from '@ht-sdks/events-sdk-js-browser'
5
+ import { createWrapper, AnyAnalytics } from '../../index'
6
+
7
+ type Extends<T, U> = T extends U ? true : false
8
+
9
+ {
10
+ const wrap = createWrapper({ getCategories: () => ({ foo: true }) })
11
+ wrap({} as HtEventsBrowser)
12
+ wrap({} as HtEventsSnippet)
13
+
14
+ // see HtEventsSnippet and HtEventsBrowser extend AnyAnalytics
15
+ const f: Extends<HtEventsSnippet, AnyAnalytics> = true
16
+ const g: Extends<HtEventsBrowser, AnyAnalytics> = true
17
+ console.log(f, g)
18
+
19
+ // should be chainable
20
+ wrap({} as HtEventsBrowser).load({ writeKey: 'foo' })
21
+ }
@@ -0,0 +1,51 @@
1
+ import { AnyAnalytics, Categories } from '../types'
2
+ import { getInitializedAnalytics } from './get-initialized-analytics'
3
+ import { validateCategories } from './validation'
4
+
5
+ /**
6
+ * Dispatch an event that looks like:
7
+ * ```ts
8
+ * {
9
+ * "type": "track",
10
+ * "event": "Hightouch Consent Preference",
11
+ * "context": {
12
+ * "consent": {
13
+ * "categoryPreferences" : {
14
+ * "C0001": true,
15
+ * "C0002": false,
16
+ * }
17
+ * }
18
+ * ...
19
+ * ```
20
+ */
21
+ export const sendConsentChangedEvent = (
22
+ analytics: AnyAnalytics,
23
+ categories: Categories
24
+ ): void => {
25
+ getInitializedAnalytics(analytics).track(
26
+ CONSENT_CHANGED_EVENT,
27
+ undefined,
28
+ createConsentChangedCtxDto(categories)
29
+ )
30
+ }
31
+
32
+ const CONSENT_CHANGED_EVENT = 'Hightouch Consent Preference'
33
+
34
+ const createConsentChangedCtxDto = (categories: Categories) => ({
35
+ consent: {
36
+ categoryPreferences: categories,
37
+ },
38
+ })
39
+
40
+ export const validateAndSendConsentChangedEvent = (
41
+ analytics: AnyAnalytics,
42
+ categories: Categories
43
+ ) => {
44
+ try {
45
+ validateCategories(categories)
46
+ sendConsentChangedEvent(analytics, categories)
47
+ } catch (err) {
48
+ // Not sure if there's a better way to handle this, but this makes testing a bit easier.
49
+ console.error(err)
50
+ }
51
+ }
@@ -0,0 +1,19 @@
1
+ import { AnyAnalytics, Categories } from '../types'
2
+
3
+ type CreateConsentMw = (
4
+ getCategories: () => Promise<Categories>
5
+ ) => AnyAnalytics['addSourceMiddleware']
6
+
7
+ /**
8
+ * Create analytics addSourceMiddleware fn that stamps each event
9
+ */
10
+ export const createConsentStampingMiddleware: CreateConsentMw =
11
+ (getCategories) =>
12
+ async ({ payload, next }) => {
13
+ const categories = await getCategories()
14
+ payload.obj.context.consent = {
15
+ ...payload.obj.context.consent,
16
+ categoryPreferences: categories,
17
+ }
18
+ next(payload)
19
+ }
@@ -0,0 +1,238 @@
1
+ import {
2
+ Categories,
3
+ CreateWrapper,
4
+ AnyAnalytics,
5
+ InitOptions,
6
+ CreateWrapperSettings,
7
+ CDNSettings,
8
+ } from '../types'
9
+ import {
10
+ validateAnalyticsInstance,
11
+ validateCategories,
12
+ validateSettings,
13
+ } from './validation'
14
+ import { createConsentStampingMiddleware } from './consent-stamping'
15
+ import { pipe, pick, uniq } from '../utils'
16
+ import { AbortLoadError, LoadContext } from './load-cancellation'
17
+ import { ValidationError } from './validation/validation-error'
18
+ import { validateAndSendConsentChangedEvent } from './consent-changed'
19
+
20
+ export const createWrapper = <Analytics extends AnyAnalytics>(
21
+ ...[createWrapperOptions]: Parameters<CreateWrapper<Analytics>>
22
+ ): ReturnType<CreateWrapper<Analytics>> => {
23
+ validateSettings(createWrapperOptions)
24
+
25
+ const {
26
+ shouldDisableHightouch,
27
+ shouldDisableConsentRequirement,
28
+ getCategories,
29
+ shouldLoad,
30
+ integrationCategoryMappings,
31
+ shouldEnableIntegration,
32
+ pruneUnmappedCategories,
33
+ registerOnConsentChanged,
34
+ } = createWrapperOptions
35
+
36
+ return (analytics: Analytics) => {
37
+ validateAnalyticsInstance(analytics)
38
+
39
+ // Call this function as early as possible. OnConsentChanged events can happen before .load is called.
40
+ registerOnConsentChanged?.((categories) =>
41
+ // whenever consent changes, dispatch a new event with the latest consent information
42
+ validateAndSendConsentChangedEvent(analytics, categories)
43
+ )
44
+
45
+ const ogLoad = analytics.load
46
+
47
+ const loadWithConsent: AnyAnalytics['load'] = async (
48
+ settings,
49
+ options
50
+ ): Promise<void> => {
51
+ // do not load anything -- hightouch included
52
+ if (await shouldDisableHightouch?.()) {
53
+ return
54
+ }
55
+
56
+ const consentRequirementDisabled =
57
+ await shouldDisableConsentRequirement?.()
58
+ if (consentRequirementDisabled) {
59
+ // ignore consent -- just call analytics.load as usual
60
+ return ogLoad.call(analytics, settings, options)
61
+ }
62
+
63
+ // use these categories to disable/enable the appropriate device mode plugins
64
+ let initialCategories: Categories
65
+ try {
66
+ initialCategories =
67
+ (await shouldLoad?.(new LoadContext())) || (await getCategories())
68
+ } catch (e: unknown) {
69
+ // consumer can call ctx.abort({ loadHightouchNormally: true })
70
+ // to load Segment but disable consent requirement
71
+ if (e instanceof AbortLoadError) {
72
+ if (e.loadHightouchNormally === true) {
73
+ ogLoad.call(analytics, settings, options)
74
+ }
75
+ // do not load anything, but do not log anything either
76
+ // if someone calls ctx.abort(), they are handling the error themselves
77
+ return
78
+ } else {
79
+ throw e
80
+ }
81
+ }
82
+
83
+ validateCategories(initialCategories)
84
+
85
+ const getPrunedCategories = async (
86
+ cdnSettingsP: Promise<CDNSettings>
87
+ ): Promise<Categories> => {
88
+ const cdnSettings = await cdnSettingsP
89
+ // we don't want to send _every_ category to hightouch, only the ones that the user has explicitly configured in their integrations
90
+ let allCategories: string[]
91
+ // We need to get all the unique categories so we can prune the consent object down to only the categories that are configured
92
+ // There can be categories that are not included in any integration in the integrations object (e.g. 2 cloud mode categories), which is why we need a special allCategories array
93
+ if (integrationCategoryMappings) {
94
+ allCategories = uniq(
95
+ Object.values(integrationCategoryMappings).reduce((p, n) =>
96
+ p.concat(n)
97
+ )
98
+ )
99
+ } else {
100
+ allCategories = cdnSettings.consentSettings?.allCategories || []
101
+ }
102
+
103
+ if (!allCategories.length) {
104
+ // No configured integrations found, so no categories will be sent (should not happen unless there's a configuration error)
105
+ throw new ValidationError(
106
+ 'Invariant: No consent categories defined in Segment',
107
+ []
108
+ )
109
+ }
110
+
111
+ const categories = await getCategories()
112
+
113
+ return pick(categories, allCategories)
114
+ }
115
+
116
+ // create getCategories and validate them regardless of whether pruning is turned on or off
117
+ const getValidCategoriesForConsentStamping = pipe(
118
+ pruneUnmappedCategories
119
+ ? getPrunedCategories.bind(
120
+ this,
121
+ new Promise<CDNSettings>((resolve) =>
122
+ analytics.on('initialize', resolve)
123
+ )
124
+ )
125
+ : getCategories,
126
+ async (categories) => {
127
+ validateCategories(await categories)
128
+ return categories
129
+ }
130
+ ) as () => Promise<Categories>
131
+
132
+ // register listener to stamp all events with latest consent information
133
+ analytics.addSourceMiddleware(
134
+ createConsentStampingMiddleware(getValidCategoriesForConsentStamping)
135
+ )
136
+
137
+ const updateCDNSettings: InitOptions['updateCDNSettings'] = (
138
+ cdnSettings
139
+ ) => {
140
+ if (!cdnSettings.remotePlugins) {
141
+ return cdnSettings
142
+ }
143
+
144
+ return disableIntegrations(
145
+ cdnSettings,
146
+ initialCategories,
147
+ integrationCategoryMappings,
148
+ shouldEnableIntegration
149
+ )
150
+ }
151
+
152
+ return ogLoad.call(analytics, settings, {
153
+ ...options,
154
+ updateCDNSettings: pipe(
155
+ updateCDNSettings,
156
+ options?.updateCDNSettings ? options.updateCDNSettings : (f) => f
157
+ ),
158
+ })
159
+ }
160
+ analytics.load = loadWithConsent
161
+ return analytics
162
+ }
163
+ }
164
+
165
+ /**
166
+ * Parse list of categories from `cdnSettings.integration.myIntegration` object
167
+ * @example
168
+ * returns ["Analytics", "Advertising"]
169
+ */
170
+ const getConsentCategories = (integration: unknown): string[] | undefined => {
171
+ if (
172
+ integration &&
173
+ typeof integration === 'object' &&
174
+ 'consentSettings' in integration &&
175
+ typeof integration.consentSettings === 'object' &&
176
+ integration.consentSettings &&
177
+ 'categories' in integration.consentSettings &&
178
+ Array.isArray(integration.consentSettings.categories)
179
+ ) {
180
+ return (integration.consentSettings.categories as string[]) || undefined
181
+ }
182
+
183
+ return undefined
184
+ }
185
+
186
+ const disableIntegrations = (
187
+ cdnSettings: CDNSettings,
188
+ consentedCategories: Categories,
189
+ integrationCategoryMappings: CreateWrapperSettings['integrationCategoryMappings'],
190
+ shouldEnableIntegration: CreateWrapperSettings['shouldEnableIntegration']
191
+ ): CDNSettings => {
192
+ const { remotePlugins, integrations } = cdnSettings
193
+
194
+ const isPluginEnabled = (creationName: string) => {
195
+ const categories = integrationCategoryMappings
196
+ ? // allow hardcoding of consent category mappings for testing (or other reasons)
197
+ integrationCategoryMappings[creationName]
198
+ : getConsentCategories(integrations[creationName])
199
+
200
+ // allow user to customize consent logic if needed
201
+ if (shouldEnableIntegration) {
202
+ return shouldEnableIntegration(categories || [], consentedCategories, {
203
+ creationName,
204
+ })
205
+ }
206
+
207
+ const isMissingCategories = !categories || !categories.length
208
+
209
+ // Enable integration by default if it contains no consent categories data (most likely because consent has not been configured).
210
+ if (isMissingCategories) {
211
+ return true
212
+ }
213
+
214
+ // Enable if all of its consent categories are consented to
215
+ const hasUserConsent = categories.every((c) => consentedCategories[c])
216
+ return hasUserConsent
217
+ }
218
+
219
+ const results = Object.keys(integrations).reduce<CDNSettings>(
220
+ (acc, creationName) => {
221
+ if (!isPluginEnabled(creationName)) {
222
+ // remote disabled action destinations
223
+ acc.remotePlugins =
224
+ acc.remotePlugins &&
225
+ acc.remotePlugins.filter((el) => el.creationName !== creationName)
226
+ // remove disabled classic destinations and locally-installed action destinations
227
+ delete acc.integrations[creationName]
228
+ }
229
+ return acc
230
+ },
231
+ {
232
+ ...cdnSettings,
233
+ remotePlugins,
234
+ integrations: { ...integrations }, // make shallow copy to avoid mutating original
235
+ }
236
+ )
237
+ return results
238
+ }
@@ -0,0 +1,25 @@
1
+ import { AnyAnalytics } from '../types'
2
+
3
+ /**
4
+ * There is a known bug for people who attempt to to wrap the library: the analytics reference does not get updated when the analytics.js library loads.
5
+ * Thus, we need to proxy events to the global reference instead.
6
+ *
7
+ * There is a universal fix here: however, many users may not have updated it:
8
+ * https://github.com/segmentio/snippet/commit/081faba8abab0b2c3ec840b685c4ff6d6cccf79c
9
+ */
10
+ export const getInitializedAnalytics = (
11
+ analytics: AnyAnalytics
12
+ ): AnyAnalytics => {
13
+ const isSnippetUser = Array.isArray(analytics)
14
+ if (isSnippetUser) {
15
+ const opts = (analytics as any)._loadOptions ?? {}
16
+ const globalAnalytics = (window as any)[
17
+ opts?.globalAnalyticsKey ?? 'htevents'
18
+ ]
19
+ if ((globalAnalytics as any).initialized) {
20
+ return globalAnalytics
21
+ }
22
+ }
23
+
24
+ return analytics
25
+ }
@@ -0,0 +1,31 @@
1
+ import { AnalyticsConsentError } from '../types/errors'
2
+ import { ValidationError } from './validation/validation-error'
3
+
4
+ /**
5
+ * Thrown when a load should be cancelled.
6
+ */
7
+ export class AbortLoadError extends AnalyticsConsentError {
8
+ constructor(public loadHightouchNormally: boolean) {
9
+ super('AbortLoadError', '')
10
+ }
11
+ }
12
+
13
+ export interface AbortLoadOptions {
14
+ /**
15
+ * Whether or not to load hightouch.
16
+ * If true -- load hightouch normally (and disable consent requirement.) Wrapper is essentially a no-op
17
+ */
18
+ loadHightouchNormally: boolean
19
+ }
20
+
21
+ export class LoadContext {
22
+ /**
23
+ * Abort the load (this function will always throw)
24
+ */
25
+ abort(options: AbortLoadOptions): never {
26
+ if (typeof options !== 'object') {
27
+ throw new ValidationError('arg should be an object', options)
28
+ }
29
+ throw new AbortLoadError(options.loadHightouchNormally)
30
+ }
31
+ }
@@ -0,0 +1,77 @@
1
+ import { CreateWrapperSettings } from '../../../types'
2
+ import { validateCategories, validateSettings } from '../options-validators'
3
+ import { ValidationError } from '../validation-error'
4
+
5
+ const DEFAULT_OPTIONS: CreateWrapperSettings = {
6
+ getCategories: () => ({}),
7
+ }
8
+
9
+ describe(validateSettings, () => {
10
+ it('should throw if options is not a plain object', () => {
11
+ expect(() => validateSettings(null as any)).toThrow()
12
+ expect(() => validateSettings(undefined as any)).toThrow()
13
+ expect(() => validateSettings('hello' as any)).toThrow()
14
+ })
15
+
16
+ it('should throw an instance of ValidationError', () => {
17
+ expect(() => validateSettings(null as any)).toThrowError(ValidationError)
18
+ })
19
+
20
+ it('should throw with the expected error', () => {
21
+ expect(() =>
22
+ validateSettings(null as any)
23
+ ).toThrowErrorMatchingInlineSnapshot(
24
+ `"[Validation] Options should be an object (Received: null)"`
25
+ )
26
+ })
27
+
28
+ it('should throw if required property(s) are not included', () => {
29
+ expect(() => validateSettings({} as any)).toThrow()
30
+ })
31
+
32
+ it('should throw if getCategories() is not a function', () => {
33
+ expect(() =>
34
+ validateSettings({
35
+ getCategories: {},
36
+ })
37
+ ).toThrow()
38
+ })
39
+
40
+ it('should throw if registerOnChanged() is not a function', () => {
41
+ expect(() =>
42
+ validateSettings({
43
+ ...DEFAULT_OPTIONS,
44
+ registerOnConsentChanged: {} as any,
45
+ })
46
+ ).toThrowErrorMatchingInlineSnapshot(
47
+ `"[Validation] registerOnConsentChanged is not a function (Received: {})"`
48
+ )
49
+ })
50
+ })
51
+
52
+ describe(validateCategories, () => {
53
+ it('should throw if categories is not a plain object', () => {
54
+ expect(() => validateCategories(null)).toThrow()
55
+ expect(() => validateCategories(undefined)).toThrow()
56
+ expect(() => validateCategories('hello')).toThrow()
57
+ })
58
+
59
+ it('should throw an instance of ValidationError', () => {
60
+ expect(() => validateCategories(null)).toThrow(ValidationError)
61
+ })
62
+
63
+ it('should throw with the expected error', () => {
64
+ expect(() => validateCategories(null)).toThrowErrorMatchingInlineSnapshot(
65
+ `"[Validation] Consent Categories should be {[categoryName: string]: boolean} (Received: null)"`
66
+ )
67
+ })
68
+
69
+ it('should throw if categories does not match {categoryName: boolean}', () => {
70
+ expect(() => validateCategories({})).not.toThrow() // if getCategories is empty object, it is the same as 'consent to all categories' if false
71
+ expect(() => validateCategories({ a: true })).not.toThrow()
72
+ expect(() => validateCategories({ a: 'foo' })).toThrow()
73
+ expect(() => validateCategories({ a: 'true' })).toThrow()
74
+ expect(() => validateCategories({ a: true, b: 'foo' })).toThrow()
75
+ expect(() => validateCategories({ a: true, b: 'foo', c: true })).toThrow()
76
+ })
77
+ })
@@ -0,0 +1,15 @@
1
+ import { ValidationError } from '../validation-error'
2
+
3
+ describe(ValidationError, () => {
4
+ it('should have the correct shape', () => {
5
+ const err = new ValidationError('foo', 'bar')
6
+
7
+ expect(err).toBeInstanceOf(Error)
8
+
9
+ expect(err.name).toBe('ValidationError')
10
+
11
+ expect(err.message).toMatchInlineSnapshot(
12
+ `"[Validation] foo (Received: \\"bar\\")"`
13
+ )
14
+ })
15
+ })
@@ -0,0 +1,19 @@
1
+ import { ValidationError } from './validation-error'
2
+
3
+ export function assertIsFunction(
4
+ val: unknown,
5
+ variableName: string
6
+ ): asserts val is Function {
7
+ if (typeof val !== 'function') {
8
+ throw new ValidationError(`${variableName} is not a function`, val)
9
+ }
10
+ }
11
+
12
+ export function assertIsObject(
13
+ val: unknown,
14
+ variableName: string
15
+ ): asserts val is object {
16
+ if (val === null || typeof val !== 'object') {
17
+ throw new ValidationError(`${variableName} is not an object`, val)
18
+ }
19
+ }
@@ -0,0 +1 @@
1
+ export * from './options-validators'
@@ -0,0 +1,74 @@
1
+ import { AnyAnalytics, Categories, CreateWrapperSettings } from '../../types'
2
+ import { assertIsFunction, assertIsObject } from './common-validators'
3
+ import { ValidationError } from './validation-error'
4
+
5
+ export function validateCategories(
6
+ ctgs: unknown
7
+ ): asserts ctgs is NonNullable<Categories> {
8
+ let hasError = true
9
+ if (ctgs && typeof ctgs === 'object' && !Array.isArray(ctgs)) {
10
+ hasError = false
11
+ for (const k in ctgs) {
12
+ if (typeof (ctgs as any)[k] !== 'boolean') {
13
+ hasError = true
14
+ break
15
+ }
16
+ }
17
+ }
18
+ if (hasError) {
19
+ throw new ValidationError(
20
+ `Consent Categories should be {[categoryName: string]: boolean}`,
21
+ ctgs
22
+ )
23
+ }
24
+ }
25
+
26
+ export function validateSettings(options: {
27
+ [k in keyof CreateWrapperSettings]: unknown
28
+ }): asserts options is CreateWrapperSettings {
29
+ if (typeof options !== 'object' || !options) {
30
+ throw new ValidationError('Options should be an object', options)
31
+ }
32
+
33
+ assertIsFunction(options.getCategories, 'getCategories')
34
+
35
+ options.shouldLoad && assertIsFunction(options.shouldLoad, 'shouldLoad')
36
+
37
+ options.shouldDisableConsentRequirement &&
38
+ assertIsFunction(
39
+ options.shouldDisableConsentRequirement,
40
+ 'shouldDisableConsentRequirement'
41
+ )
42
+
43
+ options.shouldEnableIntegration &&
44
+ assertIsFunction(options.shouldEnableIntegration, 'shouldEnableIntegration')
45
+
46
+ options.shouldDisableHightouch &&
47
+ assertIsFunction(options.shouldDisableHightouch, 'shouldDisableHightouch')
48
+
49
+ options.integrationCategoryMappings &&
50
+ assertIsObject(
51
+ options.integrationCategoryMappings,
52
+ 'integrationCategoryMappings'
53
+ )
54
+
55
+ options.registerOnConsentChanged &&
56
+ assertIsFunction(
57
+ options.registerOnConsentChanged,
58
+ 'registerOnConsentChanged'
59
+ )
60
+ }
61
+
62
+ export function validateAnalyticsInstance(
63
+ analytics: unknown
64
+ ): asserts analytics is AnyAnalytics {
65
+ assertIsObject(analytics, 'analytics')
66
+ if (
67
+ 'load' in analytics &&
68
+ 'on' in analytics &&
69
+ 'addSourceMiddleware' in analytics
70
+ ) {
71
+ return
72
+ }
73
+ throw new ValidationError('analytics is not an Analytics instance', analytics)
74
+ }
@@ -0,0 +1,11 @@
1
+ import { AnalyticsConsentError } from '../../types/errors'
2
+
3
+ export class ValidationError extends AnalyticsConsentError {
4
+ constructor(message: string, received?: any) {
5
+ if (arguments.length === 2) {
6
+ // to ensure that explicitly passing undefined as second argument still works
7
+ message += ` (Received: ${JSON.stringify(received)})`
8
+ }
9
+ super('ValidationError', `[Validation] ${message}`)
10
+ }
11
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * This is the public API for this package.
3
+ * We avoid using splat (*) exports so that we can control what is exposed.
4
+ */
5
+ export { createWrapper } from './domain/create-wrapper'
6
+ export { resolveWhen } from './utils'
7
+
8
+ export type {
9
+ Wrapper,
10
+ CreateWrapper,
11
+ CreateWrapperSettings,
12
+ IntegrationCategoryMappings,
13
+ Categories,
14
+ RegisterOnConsentChangedFunction,
15
+ AnyAnalytics,
16
+ } from './types'
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Base Consent Error
3
+ */
4
+ export abstract class AnalyticsConsentError extends Error {
5
+ /**
6
+ *
7
+ * @param name - Pass the name explicitly to work around the limitation that 'name' is automatically set to the parent class.
8
+ * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/extends#using_extends
9
+ * @param message - Error message
10
+ */
11
+ constructor(public name: string, message: string) {
12
+ super(message)
13
+ }
14
+ }
@@ -0,0 +1,3 @@
1
+ export * from './wrapper'
2
+ export * from './settings'
3
+ export * from './errors'