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