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.
- package/.editorconfig +10 -0
- package/.eslintrc.isomorphic.js +26 -0
- package/.eslintrc.js +86 -0
- package/.gitattributes +1 -0
- package/.github/workflows/ci.yml +33 -0
- package/.github/workflows/deploy-browser-cdn-candidate.yml +51 -0
- package/.github/workflows/deploy-releases.yml +178 -0
- package/.nvmrc +1 -0
- package/.prettierrc +7 -0
- package/.vscode/extensions.json +3 -0
- package/.vscode/launch.json +81 -0
- package/.vscode/settings.json +41 -0
- package/.yarn/plugins/@yarnpkg/plugin-constraints.cjs +52 -0
- package/.yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs +546 -0
- package/.yarn/plugins/@yarnpkg/plugin-typescript.cjs +9 -0
- package/.yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs +28 -0
- package/.yarn/releases/yarn-3.4.1.cjs +873 -0
- package/.yarnrc.yml +15 -0
- package/jest.config.js +18 -0
- package/package.json +59 -0
- package/packages/browser/.eslintrc.js +9 -0
- package/packages/browser/.lintstagedrc.js +1 -0
- package/packages/browser/ARCHITECTURE.md +48 -0
- package/packages/browser/LICENSE.MD +45 -0
- package/packages/browser/Makefile +64 -0
- package/packages/browser/README.md +227 -0
- package/packages/browser/e2e-tests/local-server.ts +28 -0
- package/packages/browser/e2e-tests/performance/ajs-perf-browser.test.ts +75 -0
- package/packages/browser/jest.config.js +15 -0
- package/packages/browser/jest.setup.js +10 -0
- package/packages/browser/package.json +106 -0
- package/packages/browser/qa/README.md +41 -0
- package/packages/browser/qa/__fixtures__/snippets.ts +148 -0
- package/packages/browser/qa/__tests__/backwards-compatibility.test.ts +180 -0
- package/packages/browser/qa/__tests__/destinations.test.ts +101 -0
- package/packages/browser/qa/__tests__/smoke.test.ts +170 -0
- package/packages/browser/qa/lib/benchmark.ts +36 -0
- package/packages/browser/qa/lib/browser.ts +28 -0
- package/packages/browser/qa/lib/jest-reporter.js +57 -0
- package/packages/browser/qa/lib/runner.ts +142 -0
- package/packages/browser/qa/lib/schema.ts +59 -0
- package/packages/browser/qa/lib/server.ts +54 -0
- package/packages/browser/qa/lib/stats.ts +52 -0
- package/packages/browser/scripts/build-prep.sh +7 -0
- package/packages/browser/scripts/ci.sh +15 -0
- package/packages/browser/scripts/release.js +121 -0
- package/packages/browser/scripts/release.sh +9 -0
- package/packages/browser/scripts/run.sh +8 -0
- package/packages/browser/src/browser/__tests__/analytics-lazy-init.integration.test.ts +51 -0
- package/packages/browser/src/browser/__tests__/analytics-pre-init.integration.test.ts +440 -0
- package/packages/browser/src/browser/__tests__/anon-id-and-reset.integration.test.ts +73 -0
- package/packages/browser/src/browser/__tests__/cdn.test.ts +53 -0
- package/packages/browser/src/browser/__tests__/csp-detection.test.ts +140 -0
- package/packages/browser/src/browser/__tests__/inspector.integration.test.ts +121 -0
- package/packages/browser/src/browser/__tests__/integration.test.ts +1213 -0
- package/packages/browser/src/browser/__tests__/integrations.integration.test.ts +260 -0
- package/packages/browser/src/browser/__tests__/page-enrichment.integration.test.ts +216 -0
- package/packages/browser/src/browser/__tests__/query-string.integration.test.ts +116 -0
- package/packages/browser/src/browser/__tests__/standalone-analytics.test.ts +303 -0
- package/packages/browser/src/browser/__tests__/standalone-errors.test.ts +136 -0
- package/packages/browser/src/browser/__tests__/standalone.test.ts +97 -0
- package/packages/browser/src/browser/__tests__/typedef-tests/analytics-browser.ts +150 -0
- package/packages/browser/src/browser/__tests__/update-cdn-settings.test.ts +71 -0
- package/packages/browser/src/browser/browser-umd.ts +19 -0
- package/packages/browser/src/browser/index.ts +486 -0
- package/packages/browser/src/browser/standalone-analytics.ts +62 -0
- package/packages/browser/src/browser/standalone-interface.ts +11 -0
- package/packages/browser/src/browser/standalone.ts +92 -0
- package/packages/browser/src/core/__tests__/track-form.test.ts +193 -0
- package/packages/browser/src/core/__tests__/track-link.test.ts +252 -0
- package/packages/browser/src/core/analytics/__tests__/integration.test.ts +334 -0
- package/packages/browser/src/core/analytics/__tests__/test-plugins.ts +94 -0
- package/packages/browser/src/core/analytics/index.ts +672 -0
- package/packages/browser/src/core/analytics/interfaces.ts +100 -0
- package/packages/browser/src/core/arguments-resolver/__tests__/index.test.ts +524 -0
- package/packages/browser/src/core/arguments-resolver/index.ts +200 -0
- package/packages/browser/src/core/auto-track.ts +152 -0
- package/packages/browser/src/core/buffer/__tests__/index.test.ts +455 -0
- package/packages/browser/src/core/buffer/index.ts +371 -0
- package/packages/browser/src/core/callback/index.ts +1 -0
- package/packages/browser/src/core/connection/__tests__/index.test.ts +25 -0
- package/packages/browser/src/core/connection/index.ts +13 -0
- package/packages/browser/src/core/constants/index.ts +1 -0
- package/packages/browser/src/core/context/__tests__/index.test.ts +201 -0
- package/packages/browser/src/core/context/index.ts +21 -0
- package/packages/browser/src/core/environment/index.ts +7 -0
- package/packages/browser/src/core/events/__tests__/index.test.ts +450 -0
- package/packages/browser/src/core/events/index.ts +280 -0
- package/packages/browser/src/core/events/interfaces.ts +36 -0
- package/packages/browser/src/core/inspector/index.ts +14 -0
- package/packages/browser/src/core/page/__tests__/index.test.ts +130 -0
- package/packages/browser/src/core/page/add-page-context.ts +33 -0
- package/packages/browser/src/core/page/get-page-context.ts +140 -0
- package/packages/browser/src/core/page/index.ts +2 -0
- package/packages/browser/src/core/plugin/index.ts +12 -0
- package/packages/browser/src/core/query-string/__tests__/gracefulDecodeURIComponent.test.ts +17 -0
- package/packages/browser/src/core/query-string/__tests__/index.test.ts +149 -0
- package/packages/browser/src/core/query-string/__tests__/pickPrefix.test.ts +31 -0
- package/packages/browser/src/core/query-string/__tests__/useQueryString.test.ts +60 -0
- package/packages/browser/src/core/query-string/gracefulDecodeURIComponent.ts +16 -0
- package/packages/browser/src/core/query-string/index.ts +64 -0
- package/packages/browser/src/core/query-string/pickPrefix.ts +20 -0
- package/packages/browser/src/core/queue/__tests__/event-queue.test.ts +82 -0
- package/packages/browser/src/core/queue/event-queue.ts +22 -0
- package/packages/browser/src/core/session/__tests__/index.test.ts +41 -0
- package/packages/browser/src/core/session/index.ts +107 -0
- package/packages/browser/src/core/stats/__tests__/index.test.ts +15 -0
- package/packages/browser/src/core/stats/__tests__/remote-metrics.test.ts +189 -0
- package/packages/browser/src/core/stats/index.ts +15 -0
- package/packages/browser/src/core/stats/remote-metrics.ts +144 -0
- package/packages/browser/src/core/storage/__tests__/cookieStorage.test.ts +58 -0
- package/packages/browser/src/core/storage/__tests__/localStorage.test.ts +70 -0
- package/packages/browser/src/core/storage/__tests__/test-helpers.ts +26 -0
- package/packages/browser/src/core/storage/__tests__/universalStorage.test.ts +167 -0
- package/packages/browser/src/core/storage/cookieStorage.ts +80 -0
- package/packages/browser/src/core/storage/index.ts +64 -0
- package/packages/browser/src/core/storage/localStorage.ts +45 -0
- package/packages/browser/src/core/storage/memoryStorage.ts +22 -0
- package/packages/browser/src/core/storage/settings.ts +23 -0
- package/packages/browser/src/core/storage/types.ts +49 -0
- package/packages/browser/src/core/storage/universalStorage.ts +78 -0
- package/packages/browser/src/core/user/__tests__/index.test.ts +922 -0
- package/packages/browser/src/core/user/__tests__/migrate.test.ts +101 -0
- package/packages/browser/src/core/user/__tests__/session.test.ts +136 -0
- package/packages/browser/src/core/user/__tests__/tld.test.ts +36 -0
- package/packages/browser/src/core/user/index.ts +399 -0
- package/packages/browser/src/core/user/migrate.ts +126 -0
- package/packages/browser/src/core/user/tld.ts +65 -0
- package/packages/browser/src/core/user/vendor/crypto-es/LICENSE +53 -0
- package/packages/browser/src/core/user/vendor/crypto-es/lib/aes.ts +302 -0
- package/packages/browser/src/core/user/vendor/crypto-es/lib/cipher-core.ts +922 -0
- package/packages/browser/src/core/user/vendor/crypto-es/lib/core.ts +806 -0
- package/packages/browser/src/core/user/vendor/crypto-es/lib/enc-base64.ts +110 -0
- package/packages/browser/src/core/user/vendor/crypto-es/lib/evpkdf.ts +110 -0
- package/packages/browser/src/core/user/vendor/crypto-es/lib/md5.ts +238 -0
- package/packages/browser/src/core/user/vendor/readme.md +7 -0
- package/packages/browser/src/generated/__tests__/version.test.ts +18 -0
- package/packages/browser/src/generated/version.ts +2 -0
- package/packages/browser/src/index.ts +13 -0
- package/packages/browser/src/lib/__tests__/embedded-write-key.test.ts +15 -0
- package/packages/browser/src/lib/__tests__/fetch.test.ts +35 -0
- package/packages/browser/src/lib/__tests__/get-process-env.test.ts +5 -0
- package/packages/browser/src/lib/__tests__/group-by.test.ts +96 -0
- package/packages/browser/src/lib/__tests__/is-plan-event-enabled.test.ts +36 -0
- package/packages/browser/src/lib/__tests__/is-thenable.test.ts +39 -0
- package/packages/browser/src/lib/__tests__/merged-options.test.ts +123 -0
- package/packages/browser/src/lib/__tests__/on-page-change.test.ts +74 -0
- package/packages/browser/src/lib/__tests__/parse-cdn.test.ts +88 -0
- package/packages/browser/src/lib/__tests__/pick.test.ts +34 -0
- package/packages/browser/src/lib/__tests__/pick.typedef.ts +39 -0
- package/packages/browser/src/lib/bind-all.ts +19 -0
- package/packages/browser/src/lib/browser-polyfill.ts +23 -0
- package/packages/browser/src/lib/client-hints/__tests__/index.test.ts +66 -0
- package/packages/browser/src/lib/client-hints/index.ts +16 -0
- package/packages/browser/src/lib/client-hints/interfaces.ts +42 -0
- package/packages/browser/src/lib/create-deferred.ts +16 -0
- package/packages/browser/src/lib/csp-detection.ts +8 -0
- package/packages/browser/src/lib/embedded-write-key.ts +24 -0
- package/packages/browser/src/lib/fetch.ts +10 -0
- package/packages/browser/src/lib/get-global.ts +16 -0
- package/packages/browser/src/lib/get-process-env.ts +11 -0
- package/packages/browser/src/lib/global-analytics-helper.ts +31 -0
- package/packages/browser/src/lib/group-by.ts +30 -0
- package/packages/browser/src/lib/is-plan-event-enabled.ts +20 -0
- package/packages/browser/src/lib/is-thenable.ts +9 -0
- package/packages/browser/src/lib/load-script.ts +66 -0
- package/packages/browser/src/lib/merged-options.ts +46 -0
- package/packages/browser/src/lib/on-page-change.ts +29 -0
- package/packages/browser/src/lib/p-while.ts +12 -0
- package/packages/browser/src/lib/parse-cdn.ts +56 -0
- package/packages/browser/src/lib/pick.ts +28 -0
- package/packages/browser/src/lib/priority-queue/__tests__/backoff.test.ts +23 -0
- package/packages/browser/src/lib/priority-queue/__tests__/index.test.ts +158 -0
- package/packages/browser/src/lib/priority-queue/__tests__/persisted.test.ts +228 -0
- package/packages/browser/src/lib/priority-queue/backoff.ts +24 -0
- package/packages/browser/src/lib/priority-queue/index.ts +6 -0
- package/packages/browser/src/lib/priority-queue/persisted.ts +127 -0
- package/packages/browser/src/lib/sleep.ts +4 -0
- package/packages/browser/src/lib/to-facade.ts +53 -0
- package/packages/browser/src/lib/version-type.ts +10 -0
- package/packages/browser/src/node/__tests__/node-integration.test.ts +19 -0
- package/packages/browser/src/node/index.ts +36 -0
- package/packages/browser/src/node/node.browser.ts +7 -0
- package/packages/browser/src/plugins/ajs-destination/__tests__/index.test.ts +834 -0
- package/packages/browser/src/plugins/ajs-destination/index.ts +392 -0
- package/packages/browser/src/plugins/ajs-destination/loader.ts +129 -0
- package/packages/browser/src/plugins/ajs-destination/types.ts +44 -0
- package/packages/browser/src/plugins/ajs-destination/utils.ts +32 -0
- package/packages/browser/src/plugins/analytics-node/__tests__/index.test.ts +69 -0
- package/packages/browser/src/plugins/analytics-node/index.ts +67 -0
- package/packages/browser/src/plugins/env-enrichment/__tests__/index.test.ts +421 -0
- package/packages/browser/src/plugins/env-enrichment/index.ts +208 -0
- package/packages/browser/src/plugins/hightouchio/__tests__/batched-dispatcher.test.ts +299 -0
- package/packages/browser/src/plugins/hightouchio/__tests__/index.test.ts +317 -0
- package/packages/browser/src/plugins/hightouchio/__tests__/normalize.test.ts +181 -0
- package/packages/browser/src/plugins/hightouchio/__tests__/retries.test.ts +82 -0
- package/packages/browser/src/plugins/hightouchio/batched-dispatcher.ts +127 -0
- package/packages/browser/src/plugins/hightouchio/fetch-dispatcher.ts +27 -0
- package/packages/browser/src/plugins/hightouchio/index.ts +147 -0
- package/packages/browser/src/plugins/hightouchio/normalize.ts +71 -0
- package/packages/browser/src/plugins/hightouchio/schedule-flush.ts +58 -0
- package/packages/browser/src/plugins/legacy-video-plugins/__tests__/index.test.ts +48 -0
- package/packages/browser/src/plugins/legacy-video-plugins/index.ts +16 -0
- package/packages/browser/src/plugins/middleware/__tests__/index.test.ts +268 -0
- package/packages/browser/src/plugins/middleware/index.ts +131 -0
- package/packages/browser/src/plugins/remote-loader/__tests__/index.test.ts +943 -0
- package/packages/browser/src/plugins/remote-loader/index.ts +256 -0
- package/packages/browser/src/plugins/remote-middleware/__tests__/index.test.ts +116 -0
- package/packages/browser/src/plugins/remote-middleware/index.ts +44 -0
- package/packages/browser/src/plugins/routing-middleware/__tests__/index.test.ts +64 -0
- package/packages/browser/src/plugins/routing-middleware/index.ts +37 -0
- package/packages/browser/src/plugins/schema-filter/__tests__/index.test.ts +520 -0
- package/packages/browser/src/plugins/schema-filter/index.ts +90 -0
- package/packages/browser/src/plugins/validation/__tests__/index.test.ts +78 -0
- package/packages/browser/src/plugins/validation/index.ts +44 -0
- package/packages/browser/src/test-helpers/browser-storage.ts +75 -0
- package/packages/browser/src/test-helpers/factories.ts +18 -0
- package/packages/browser/src/test-helpers/fetch-parse.ts +8 -0
- package/packages/browser/src/test-helpers/fixtures/cdn-settings.ts +301 -0
- package/packages/browser/src/test-helpers/fixtures/classic-destination.ts +25 -0
- package/packages/browser/src/test-helpers/fixtures/client-hints.ts +28 -0
- package/packages/browser/src/test-helpers/fixtures/create-fetch-method.ts +30 -0
- package/packages/browser/src/test-helpers/fixtures/index.ts +4 -0
- package/packages/browser/src/test-helpers/fixtures/page-context.ts +11 -0
- package/packages/browser/src/test-helpers/test-writekeys.ts +5 -0
- package/packages/browser/src/test-helpers/type-assertions.ts +11 -0
- package/packages/browser/src/tester/__fixtures__/hightouch-snippet.ts +64 -0
- package/packages/browser/src/tester/__fixtures__/index.html +8 -0
- package/packages/browser/src/tester/ajs-perf.ts +30 -0
- package/packages/browser/src/tester/ajs-tester.ts +119 -0
- package/packages/browser/src/tester/server.js +16 -0
- package/packages/browser/tsconfig.build.json +9 -0
- package/packages/browser/tsconfig.json +13 -0
- package/packages/browser/webpack.config.js +106 -0
- package/packages/config/package.json +10 -0
- package/packages/config/src/index.js +4 -0
- package/packages/config/src/jest/config.js +50 -0
- package/packages/config/src/jest/get-module-map.js +34 -0
- package/packages/config/src/lint-staged/config.js +4 -0
- package/packages/config-webpack/package.json +20 -0
- package/packages/config-webpack/webpack.config.common.js +75 -0
- package/packages/consent/consent-tools/.eslintrc.js +7 -0
- package/packages/consent/consent-tools/.lintstagedrc.js +1 -0
- package/packages/consent/consent-tools/LICENSE +45 -0
- package/packages/consent/consent-tools/README.md +104 -0
- package/packages/consent/consent-tools/jest.config.js +6 -0
- package/packages/consent/consent-tools/jest.setup.js +4 -0
- package/packages/consent/consent-tools/package.json +48 -0
- package/packages/consent/consent-tools/src/domain/__tests__/assertions/integrations-assertions.ts +37 -0
- package/packages/consent/consent-tools/src/domain/__tests__/consent-stamping.test.ts +45 -0
- package/packages/consent/consent-tools/src/domain/__tests__/create-wrapper.test.ts +816 -0
- package/packages/consent/consent-tools/src/domain/__tests__/typedef-tests.ts +21 -0
- package/packages/consent/consent-tools/src/domain/consent-changed.ts +51 -0
- package/packages/consent/consent-tools/src/domain/consent-stamping.ts +19 -0
- package/packages/consent/consent-tools/src/domain/create-wrapper.ts +238 -0
- package/packages/consent/consent-tools/src/domain/get-initialized-analytics.ts +25 -0
- package/packages/consent/consent-tools/src/domain/load-cancellation.ts +31 -0
- package/packages/consent/consent-tools/src/domain/validation/__tests__/options-validators.test.ts +77 -0
- package/packages/consent/consent-tools/src/domain/validation/__tests__/validation-error.test.ts +15 -0
- package/packages/consent/consent-tools/src/domain/validation/common-validators.ts +19 -0
- package/packages/consent/consent-tools/src/domain/validation/index.ts +1 -0
- package/packages/consent/consent-tools/src/domain/validation/options-validators.ts +74 -0
- package/packages/consent/consent-tools/src/domain/validation/validation-error.ts +11 -0
- package/packages/consent/consent-tools/src/index.ts +16 -0
- package/packages/consent/consent-tools/src/types/errors.ts +14 -0
- package/packages/consent/consent-tools/src/types/index.ts +3 -0
- package/packages/consent/consent-tools/src/types/settings.ts +121 -0
- package/packages/consent/consent-tools/src/types/wrapper.ts +107 -0
- package/packages/consent/consent-tools/src/utils/index.ts +4 -0
- package/packages/consent/consent-tools/src/utils/pick.ts +18 -0
- package/packages/consent/consent-tools/src/utils/pipe.ts +14 -0
- package/packages/consent/consent-tools/src/utils/resolve-when.ts +32 -0
- package/packages/consent/consent-tools/src/utils/uniq.ts +4 -0
- package/packages/consent/consent-tools/tsconfig.build.json +9 -0
- package/packages/consent/consent-tools/tsconfig.json +12 -0
- package/packages/consent/consent-wrapper-onetrust/.eslintrc.js +7 -0
- package/packages/consent/consent-wrapper-onetrust/.lintstagedrc.js +1 -0
- package/packages/consent/consent-wrapper-onetrust/LICENSE +45 -0
- package/packages/consent/consent-wrapper-onetrust/README.md +125 -0
- package/packages/consent/consent-wrapper-onetrust/img/onetrust-cat-id.jpg +0 -0
- package/packages/consent/consent-wrapper-onetrust/img/onetrust-popup.jpg +0 -0
- package/packages/consent/consent-wrapper-onetrust/jest.config.js +6 -0
- package/packages/consent/consent-wrapper-onetrust/jest.setup.js +4 -0
- package/packages/consent/consent-wrapper-onetrust/package.json +60 -0
- package/packages/consent/consent-wrapper-onetrust/src/domain/__tests__/wrapper.test.ts +151 -0
- package/packages/consent/consent-wrapper-onetrust/src/domain/wrapper.ts +61 -0
- package/packages/consent/consent-wrapper-onetrust/src/index.ts +6 -0
- package/packages/consent/consent-wrapper-onetrust/src/index.umd.ts +11 -0
- package/packages/consent/consent-wrapper-onetrust/src/lib/__tests__/onetrust-api.test.ts +181 -0
- package/packages/consent/consent-wrapper-onetrust/src/lib/onetrust-api.ts +155 -0
- package/packages/consent/consent-wrapper-onetrust/src/lib/validation/index.ts +1 -0
- package/packages/consent/consent-wrapper-onetrust/src/lib/validation/onetrust-api-error.ts +11 -0
- package/packages/consent/consent-wrapper-onetrust/src/test-helpers/mocks.ts +23 -0
- package/packages/consent/consent-wrapper-onetrust/src/test-helpers/onetrust-globals.d.ts +11 -0
- package/packages/consent/consent-wrapper-onetrust/src/test-helpers/utils.ts +3 -0
- package/packages/consent/consent-wrapper-onetrust/tsconfig.build.json +9 -0
- package/packages/consent/consent-wrapper-onetrust/tsconfig.json +11 -0
- package/packages/consent/consent-wrapper-onetrust/webpack.config.js +25 -0
- package/packages/core/.eslintrc.js +4 -0
- package/packages/core/.lintstagedrc.js +1 -0
- package/packages/core/LICENSE.MD +45 -0
- package/packages/core/README.md +3 -0
- package/packages/core/jest.config.js +5 -0
- package/packages/core/jest.setup.js +10 -0
- package/packages/core/package.json +40 -0
- package/packages/core/src/analytics/__tests__/dispatch.test.ts +95 -0
- package/packages/core/src/analytics/dispatch.ts +58 -0
- package/packages/core/src/analytics/index.ts +11 -0
- package/packages/core/src/callback/__tests__/index.test.ts +85 -0
- package/packages/core/src/callback/index.ts +51 -0
- package/packages/core/src/context/index.ts +123 -0
- package/packages/core/src/emitter/__tests__/emitter.test.ts +74 -0
- package/packages/core/src/emitter/index.ts +65 -0
- package/packages/core/src/emitter/interface.ts +31 -0
- package/packages/core/src/events/__tests__/index.test.ts +394 -0
- package/packages/core/src/events/index.ts +280 -0
- package/packages/core/src/events/interfaces.ts +475 -0
- package/packages/core/src/index.ts +19 -0
- package/packages/core/src/logger/__tests__/index.test.ts +66 -0
- package/packages/core/src/logger/index.ts +74 -0
- package/packages/core/src/plugins/index.ts +43 -0
- package/packages/core/src/priority-queue/__tests__/backoff.test.ts +23 -0
- package/packages/core/src/priority-queue/__tests__/index.test.ts +158 -0
- package/packages/core/src/priority-queue/backoff.ts +24 -0
- package/packages/core/src/priority-queue/index.ts +103 -0
- package/packages/core/src/queue/__tests__/event-queue.test.ts +678 -0
- package/packages/core/src/queue/__tests__/extension-flushing.test.ts +416 -0
- package/packages/core/src/queue/delivery.ts +73 -0
- package/packages/core/src/queue/event-queue.ts +318 -0
- package/packages/core/src/stats/__tests__/index.test.ts +103 -0
- package/packages/core/src/stats/index.ts +88 -0
- package/packages/core/src/task/__tests__/task-group.test.ts +26 -0
- package/packages/core/src/task/task-group.ts +31 -0
- package/packages/core/src/user/index.ts +7 -0
- package/packages/core/src/utils/__tests__/group-by.test.ts +96 -0
- package/packages/core/src/utils/__tests__/is-plain-object.test.ts +27 -0
- package/packages/core/src/utils/__tests__/is-thenable.test.ts +39 -0
- package/packages/core/src/utils/bind-all.ts +19 -0
- package/packages/core/src/utils/get-global.ts +17 -0
- package/packages/core/src/utils/group-by.ts +30 -0
- package/packages/core/src/utils/has-properties.ts +7 -0
- package/packages/core/src/utils/is-plain-object.ts +26 -0
- package/packages/core/src/utils/is-thenable.ts +9 -0
- package/packages/core/src/utils/p-while.ts +12 -0
- package/packages/core/src/utils/pick.ts +8 -0
- package/packages/core/src/utils/ts-helpers.ts +13 -0
- package/packages/core/src/validation/__tests__/assertions.test.ts +155 -0
- package/packages/core/src/validation/assertions.ts +72 -0
- package/packages/core/src/validation/errors.ts +8 -0
- package/packages/core/src/validation/helpers.ts +23 -0
- package/packages/core/test-helpers/index.ts +2 -0
- package/packages/core/test-helpers/test-ctx.ts +7 -0
- package/packages/core/test-helpers/test-event-queue.ts +7 -0
- package/packages/core/tsconfig.build.json +9 -0
- package/packages/core/tsconfig.json +11 -0
- package/packages/node/.eslintrc.js +7 -0
- package/packages/node/.lintstagedrc.js +1 -0
- package/packages/node/LICENSE +45 -0
- package/packages/node/README.md +138 -0
- package/packages/node/jest.config.js +5 -0
- package/packages/node/jest.setup.js +4 -0
- package/packages/node/package.json +50 -0
- package/packages/node/scripts/version.sh +11 -0
- package/packages/node/src/__tests__/callback.test.ts +47 -0
- package/packages/node/src/__tests__/disable.integration.test.ts +42 -0
- package/packages/node/src/__tests__/emitter.integration.test.ts +45 -0
- package/packages/node/src/__tests__/graceful-shutdown-integration.test.ts +244 -0
- package/packages/node/src/__tests__/http-client.integration.test.ts +69 -0
- package/packages/node/src/__tests__/http-integration.test.ts +362 -0
- package/packages/node/src/__tests__/integration.test.ts +357 -0
- package/packages/node/src/__tests__/plugins.test.ts +16 -0
- package/packages/node/src/__tests__/settings.test.ts +9 -0
- package/packages/node/src/__tests__/test-helpers/assert-shape/http-request-event.ts +13 -0
- package/packages/node/src/__tests__/test-helpers/assert-shape/index.ts +2 -0
- package/packages/node/src/__tests__/test-helpers/assert-shape/segment-http-api.ts +43 -0
- package/packages/node/src/__tests__/test-helpers/create-test-analytics.ts +42 -0
- package/packages/node/src/__tests__/test-helpers/factories.ts +17 -0
- package/packages/node/src/__tests__/test-helpers/is-valid-date.ts +6 -0
- package/packages/node/src/__tests__/test-helpers/resolve-ctx.ts +19 -0
- package/packages/node/src/__tests__/test-helpers/resolve-emitter.ts +11 -0
- package/packages/node/src/__tests__/test-helpers/sleep.ts +3 -0
- package/packages/node/src/__tests__/test-helpers/test-plugin.ts +16 -0
- package/packages/node/src/__tests__/typedef-tests.ts +120 -0
- package/packages/node/src/app/analytics-node.ts +299 -0
- package/packages/node/src/app/context.ts +11 -0
- package/packages/node/src/app/dispatch-emit.ts +42 -0
- package/packages/node/src/app/emitter.ts +23 -0
- package/packages/node/src/app/event-factory.ts +20 -0
- package/packages/node/src/app/event-queue.ts +23 -0
- package/packages/node/src/app/settings.ts +49 -0
- package/packages/node/src/app/types/index.ts +3 -0
- package/packages/node/src/app/types/params.ts +76 -0
- package/packages/node/src/app/types/plugin.ts +5 -0
- package/packages/node/src/app/types/segment-event.ts +7 -0
- package/packages/node/src/generated/version.ts +2 -0
- package/packages/node/src/index.ts +26 -0
- package/packages/node/src/lib/__tests__/abort.test.ts +54 -0
- package/packages/node/src/lib/__tests__/create-url.test.ts +35 -0
- package/packages/node/src/lib/__tests__/env.test.ts +52 -0
- package/packages/node/src/lib/__tests__/get-message-id.test.ts +21 -0
- package/packages/node/src/lib/abort.ts +77 -0
- package/packages/node/src/lib/base-64-encode.ts +8 -0
- package/packages/node/src/lib/create-url.ts +11 -0
- package/packages/node/src/lib/env.ts +45 -0
- package/packages/node/src/lib/extract-promise-parts.ts +21 -0
- package/packages/node/src/lib/fetch.ts +16 -0
- package/packages/node/src/lib/get-message-id.ts +10 -0
- package/packages/node/src/lib/http-client.ts +95 -0
- package/packages/node/src/lib/uuid.ts +1 -0
- package/packages/node/src/plugins/segmentio/__tests__/methods.test.ts +223 -0
- package/packages/node/src/plugins/segmentio/__tests__/publisher.test.ts +411 -0
- package/packages/node/src/plugins/segmentio/context-batch.ts +71 -0
- package/packages/node/src/plugins/segmentio/index.ts +66 -0
- package/packages/node/src/plugins/segmentio/publisher.ts +265 -0
- package/packages/node/tsconfig.build.json +9 -0
- package/packages/node/tsconfig.json +10 -0
- package/packages/test-helpers/.eslintrc.js +7 -0
- package/packages/test-helpers/.lintstagedrc.js +1 -0
- package/packages/test-helpers/jest.config.js +3 -0
- package/packages/test-helpers/package.json +26 -0
- package/packages/test-helpers/src/analytics/cdn-settings-builder.ts +79 -0
- package/packages/test-helpers/src/analytics/index.ts +1 -0
- package/packages/test-helpers/src/index.ts +2 -0
- package/packages/test-helpers/src/utils/index.ts +1 -0
- package/packages/test-helpers/src/utils/sleep.ts +4 -0
- package/packages/test-helpers/tsconfig.build.json +9 -0
- package/packages/test-helpers/tsconfig.json +11 -0
- package/tsconfig.json +21 -0
- package/turbo.json +39 -0
- package/typings/get-monorepo-packages.d.ts +9 -0
- 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
|
+
}
|
package/packages/consent/consent-tools/src/domain/validation/__tests__/options-validators.test.ts
ADDED
|
@@ -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
|
+
})
|
package/packages/consent/consent-tools/src/domain/validation/__tests__/validation-error.test.ts
ADDED
|
@@ -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
|
+
}
|